Skip to content

Commit

Permalink
Generalize SignedCheckpoint to take arbitrary Notes (#347)
Browse files Browse the repository at this point in the history
* generalize signed checkpoint

Signed-off-by: Asra Ali <asraa@google.com>

* store note as text representation

Signed-off-by: Asra Ali <asraa@google.com>

* cleanup diff

Signed-off-by: Asra Ali <asraa@google.com>

* simplify

Signed-off-by: Asra Ali <asraa@google.com>

* use signer/verifier

Signed-off-by: Asra Ali <asraa@google.com>

* address dan comments

Signed-off-by: Asra Ali <asraa@google.com>
  • Loading branch information
asraa authored Jul 20, 2021
1 parent 12077f5 commit 07c8e8f
Show file tree
Hide file tree
Showing 10 changed files with 490 additions and 295 deletions.
11 changes: 9 additions & 2 deletions cmd/rekor-cli/app/log_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package app

import (
"bytes"
"crypto"
"crypto/x509"
"encoding/hex"
"encoding/pem"
Expand All @@ -35,6 +36,7 @@ import (
"github.com/sigstore/rekor/pkg/generated/client/tlog"
"github.com/sigstore/rekor/pkg/log"
"github.com/sigstore/rekor/pkg/util"
"github.com/sigstore/sigstore/pkg/signature"
)

type logInfoCmdOutput struct {
Expand Down Expand Up @@ -72,7 +74,7 @@ var logInfoCmd = &cobra.Command{

logInfo := result.GetPayload()

sth := util.RekorSTH{}
sth := util.SignedCheckpoint{}
if err := sth.UnmarshalText([]byte(*logInfo.SignedTreeHead)); err != nil {
return nil, err
}
Expand All @@ -97,7 +99,12 @@ var logInfoCmd = &cobra.Command{
return nil, err
}

if !sth.Verify(pub) {
verifier, err := signature.LoadVerifier(pub, crypto.SHA256)
if err != nil {
return nil, err
}

if !sth.Verify(verifier) {
return nil, errors.New("signature on tree head did not verify")
}

Expand Down
6 changes: 3 additions & 3 deletions cmd/rekor-cli/app/state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ import (
"github.com/sigstore/rekor/pkg/util"
)

type persistedState map[string]*util.RekorSTH
type persistedState map[string]*util.SignedCheckpoint

func Dump(url string, sth *util.RekorSTH) error {
func Dump(url string, sth *util.SignedCheckpoint) error {
rekorDir, err := getRekorDir()
if err != nil {
return err
Expand Down Expand Up @@ -67,7 +67,7 @@ func loadStateFile() persistedState {
return result
}

func Load(url string) *util.RekorSTH {
func Load(url string) *util.SignedCheckpoint {
if state := loadStateFile(); state != nil {
return state[url]
}
Expand Down
12 changes: 9 additions & 3 deletions cmd/rekor-server/app/watch.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
genclient "github.com/sigstore/rekor/pkg/generated/client"
"github.com/sigstore/rekor/pkg/log"
"github.com/sigstore/rekor/pkg/util"
"github.com/sigstore/sigstore/pkg/signature"
)

const rekorSthBucketEnv = "REKOR_STH_BUCKET"
Expand Down Expand Up @@ -134,12 +135,17 @@ func doCheck(c *genclient.Rekor, pub crypto.PublicKey) (*SignedAndUnsignedLogRoo
if err != nil {
return nil, errors.Wrap(err, "getting log info")
}
sth := util.RekorSTH{}
sth := util.SignedCheckpoint{}
if err := sth.UnmarshalText([]byte(*li.Payload.SignedTreeHead)); err != nil {
return nil, errors.Wrap(err, "unmarshalling tree head")
}

if !sth.Verify(pub) {
verifier, err := signature.LoadVerifier(pub, crypto.SHA256)
if err != nil {
return nil, err
}

if !sth.Verify(verifier) {
return nil, errors.Wrap(err, "signed tree head failed verification")
}

Expand Down Expand Up @@ -168,5 +174,5 @@ func uploadToBlobStorage(ctx context.Context, bucket *blob.Bucket, lr *SignedAnd

// For JSON marshalling
type SignedAndUnsignedLogRoot struct {
VerifiedLogRoot *util.RekorSTH
VerifiedLogRoot *util.SignedCheckpoint
}
45 changes: 9 additions & 36 deletions pkg/api/tlog.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@
package api

import (
"bytes"
"encoding/base64"
"encoding/binary"
"encoding/hex"
"fmt"
"net/http"
Expand All @@ -27,7 +24,6 @@ import (
"github.com/go-openapi/runtime/middleware"
"github.com/google/trillian/types"
"github.com/spf13/viper"
"golang.org/x/mod/sumdb/note"
"google.golang.org/grpc/codes"

"github.com/sigstore/rekor/pkg/generated/models"
Expand All @@ -54,46 +50,23 @@ func GetLogInfoHandler(params tlog.GetLogInfoParams) middleware.Responder {
hashString := hex.EncodeToString(root.RootHash)
treeSize := int64(root.TreeSize)

sth := util.RekorSTH{
SignedCheckpoint: util.SignedCheckpoint{
Checkpoint: util.Checkpoint{
Ecosystem: "Rekor",
Size: root.TreeSize,
Hash: root.RootHash,
},
},
sth, err := util.CreateSignedCheckpoint(util.Checkpoint{
Ecosystem: "Rekor",
Size: root.TreeSize,
Hash: root.RootHash,
})
if err != nil {
return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("marshalling error: %w", err), sthGenerateError)
}
sth.SetTimestamp(uint64(time.Now().UnixNano()))
// TODO: once api.signer implements crypto.Signer, switch to using Sign() API on Checkpoint
// var opts crypto.SignerOpts
// cs, ok := api.signer.(crypto.Signer)
// if !ok {
// kmsSigner, ok := api.signer.(kms.SignerVerifier)
// if !ok {
// return handleRekorAPIError(params, http.StatusInternalServerError, errors.New("unable to cast to crypto.Signer"), signingError)
// }
// var err error
// cs, opts, err = kmsSigner.CryptoSigner(params.HTTPRequest.Context(), nil)
// if err != nil {
// return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("unable to obtain crypto.Signer: %v", err), signingError)
// }
// }
// sth.Checkpoint.Sign(viper.GetString("rekor_server.hostname"), cs, opts)

// sign the log root ourselves to get the log root signature
cpString, _ := sth.Checkpoint.MarshalText()
sig, err := api.signer.SignMessage(bytes.NewReader(cpString), options.WithContext(params.HTTPRequest.Context()))
_, err = sth.Sign(viper.GetString("rekor_server.hostname"), api.signer, options.WithContext(params.HTTPRequest.Context()))
if err != nil {
return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("signing error: %w", err), signingError)
}

sth.Signatures = append(sth.Signatures, note.Signature{
Name: viper.GetString("rekor_server.hostname"),
Hash: binary.BigEndian.Uint32([]byte(api.pubkeyHash)[0:4]),
Base64: base64.StdEncoding.EncodeToString(sig),
})

scBytes, err := sth.MarshalText()
scBytes, err := sth.SignedNote.MarshalText()
if err != nil {
return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("marshalling error: %w", err), sthGenerateError)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/client/rekor_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,6 @@ func GetRekorClient(rekorServerURL string) (*client.Rekor, error) {
}

registry := strfmt.Default
registry.Add("signedCheckpoint", &util.SignedCheckpoint{}, util.SignedCheckpointValidator)
registry.Add("signedCheckpoint", &util.SignedNote{}, util.SignedCheckpointValidator)
return client.New(rt, registry), nil
}
2 changes: 1 addition & 1 deletion pkg/generated/restapi/configure_rekor_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func configureAPI(api *operations.RekorServerAPI) http.Handler {
api.TimestampGetTimestampResponseHandler = timestamp.GetTimestampResponseHandlerFunc(pkgapi.TimestampResponseHandler)
api.TimestampGetTimestampCertChainHandler = timestamp.GetTimestampCertChainHandlerFunc(pkgapi.GetTimestampCertChainHandler)

api.RegisterFormat("signedCheckpoint", &util.SignedCheckpoint{}, util.SignedCheckpointValidator)
api.RegisterFormat("signedCheckpoint", &util.SignedNote{}, util.SignedCheckpointValidator)

api.PreServerShutdown = func() {}

Expand Down
Loading

0 comments on commit 07c8e8f

Please sign in to comment.