Skip to content

Commit

Permalink
feat: add verification functions
Browse files Browse the repository at this point in the history
Signed-off-by: Asra Ali <asraa@google.com>

lint and comment

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

update

Signed-off-by: Asra Ali <asraa@google.com>
  • Loading branch information
asraa committed Aug 18, 2022
1 parent 9e65c7f commit 970fc7f
Show file tree
Hide file tree
Showing 3 changed files with 223 additions and 71 deletions.
66 changes: 16 additions & 50 deletions cmd/rekor-cli/app/log_info.go
Expand Up @@ -16,10 +16,9 @@
package app

import (
"bytes"
"context"
"crypto"
"crypto/x509"
"encoding/hex"
"encoding/pem"
"errors"
"fmt"
Expand All @@ -28,10 +27,10 @@ import (
"github.com/go-openapi/swag"
rclient "github.com/sigstore/rekor/pkg/generated/client"
"github.com/sigstore/rekor/pkg/generated/models"

"github.com/sigstore/rekor/pkg/verify"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/transparency-dev/merkle/proof"
"github.com/transparency-dev/merkle/rfc6962"

"github.com/sigstore/rekor/cmd/rekor-cli/app/format"
"github.com/sigstore/rekor/cmd/rekor-cli/app/state"
Expand Down Expand Up @@ -70,6 +69,7 @@ var logInfoCmd = &cobra.Command{
Long: `Prints info about the transparency log`,
Run: format.WrapCmd(func(args []string) (interface{}, error) {
serverURL := viper.GetString("rekor_server")
ctx := context.Background()
rekorClient, err := client.GetRekorClient(serverURL, client.WithUserAgent(UserAgent()))
if err != nil {
return nil, err
Expand All @@ -85,7 +85,7 @@ var logInfoCmd = &cobra.Command{
logInfo := result.GetPayload()

// Verify inactive shards
if err := verifyInactiveTrees(rekorClient, serverURL, logInfo.InactiveShards); err != nil {
if err := verifyInactiveTrees(ctx, rekorClient, serverURL, logInfo.InactiveShards); err != nil {
return nil, err
}

Expand All @@ -97,7 +97,7 @@ var logInfoCmd = &cobra.Command{
}
treeID := swag.StringValue(logInfo.TreeID)

if err := verifyTree(rekorClient, signedTreeHead, serverURL, treeID); err != nil {
if err := verifyTree(ctx, rekorClient, signedTreeHead, serverURL, treeID); err != nil {
return nil, err
}

Expand All @@ -112,23 +112,23 @@ var logInfoCmd = &cobra.Command{
}),
}

func verifyInactiveTrees(rekorClient *rclient.Rekor, serverURL string, inactiveShards []*models.InactiveShardLogInfo) error {
func verifyInactiveTrees(ctx context.Context, rekorClient *rclient.Rekor, serverURL string, inactiveShards []*models.InactiveShardLogInfo) error {
if inactiveShards == nil {
return nil
}
log.CliLogger.Infof("Validating inactive shards...")
for _, shard := range inactiveShards {
signedTreeHead := swag.StringValue(shard.SignedTreeHead)
treeID := swag.StringValue(shard.TreeID)
if err := verifyTree(rekorClient, signedTreeHead, serverURL, treeID); err != nil {
if err := verifyTree(ctx, rekorClient, signedTreeHead, serverURL, treeID); err != nil {
return fmt.Errorf("verifying inactive shard with ID %s: %w", treeID, err)
}
}
log.CliLogger.Infof("Successfully validated inactive shards")
return nil
}

func verifyTree(rekorClient *rclient.Rekor, signedTreeHead, serverURL, treeID string) error {
func verifyTree(ctx context.Context, rekorClient *rclient.Rekor, signedTreeHead, serverURL, treeID string) error {
oldState := state.Load(serverURL)
if treeID != "" {
oldState = state.Load(treeID)
Expand All @@ -145,8 +145,13 @@ func verifyTree(rekorClient *rclient.Rekor, signedTreeHead, serverURL, treeID st
return errors.New("signature on tree head did not verify")
}

if err := proveConsistency(rekorClient, oldState, sth, treeID); err != nil {
return err
if oldState != nil {
if err := verify.ProveConsistency(ctx, rekorClient, oldState.Hash,
int64(oldState.Size), sth, treeID); err != nil {
return err
}
} else {
log.CliLogger.Infof("No previous log state stored, unable to prove consistency")
}

if viper.GetBool("store_tree_state") {
Expand All @@ -162,45 +167,6 @@ func verifyTree(rekorClient *rclient.Rekor, signedTreeHead, serverURL, treeID st
return nil
}

func proveConsistency(rekorClient *rclient.Rekor, oldState *util.SignedCheckpoint, sth util.SignedCheckpoint, treeID string) error {
if oldState == nil {
log.CliLogger.Infof("No previous log state stored, unable to prove consistency")
return nil
}
persistedSize := oldState.Size
switch {
case persistedSize < sth.Size:
log.CliLogger.Infof("Found previous log state, proving consistency between %d and %d", oldState.Size, sth.Size)
params := tlog.NewGetLogProofParams()
firstSize := int64(persistedSize)
params.FirstSize = &firstSize
params.LastSize = int64(sth.Size)
params.TreeID = &treeID
logProof, err := rekorClient.Tlog.GetLogProof(params)
if err != nil {
return err
}
hashes := [][]byte{}
for _, h := range logProof.Payload.Hashes {
b, _ := hex.DecodeString(h)
hashes = append(hashes, b)
}
if err := proof.VerifyConsistency(rfc6962.DefaultHasher, persistedSize, sth.Size, hashes, oldState.Hash,
sth.Hash); err != nil {
return err
}
log.CliLogger.Infof("Consistency proof valid!")
case persistedSize == sth.Size:
if !bytes.Equal(oldState.Hash, sth.Hash) {
return errors.New("root hash returned from server does not match previously persisted state")
}
log.CliLogger.Infof("Persisted log state matches the current state of the log")
default:
return fmt.Errorf("current size of tree reported from server %d is less than previously persisted state %d", sth.Size, persistedSize)
}
return nil
}

func loadVerifier(rekorClient *rclient.Rekor) (signature.Verifier, error) {
publicKey := viper.GetString("rekor_server_public_key")
if publicKey == "" {
Expand Down
32 changes: 11 additions & 21 deletions cmd/rekor-cli/app/verify.go
Expand Up @@ -16,17 +16,14 @@
package app

import (
"bytes"
"context"
"encoding/base64"
"encoding/hex"
"fmt"
"math/bits"
"strconv"

"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/transparency-dev/merkle/proof"
"github.com/transparency-dev/merkle/rfc6962"

"github.com/sigstore/rekor/cmd/rekor-cli/app/format"
Expand All @@ -36,6 +33,7 @@ import (
"github.com/sigstore/rekor/pkg/log"
"github.com/sigstore/rekor/pkg/sharding"
"github.com/sigstore/rekor/pkg/types"
"github.com/sigstore/rekor/pkg/verify"
)

type verifyCmdOutput struct {
Expand Down Expand Up @@ -88,6 +86,7 @@ var verifyCmd = &cobra.Command{
return nil
},
Run: format.WrapCmd(func(args []string) (interface{}, error) {
ctx := context.Background()
rekorClient, err := client.GetRekorClient(viper.GetString("rekor_server"), client.WithUserAgent(UserAgent()))
if err != nil {
return nil, err
Expand Down Expand Up @@ -139,7 +138,7 @@ var verifyCmd = &cobra.Command{
logEntry := resp.Payload[0]

var o *verifyCmdOutput
var entryBytes []byte
var entry models.LogEntryAnon
for k, v := range logEntry {
o = &verifyCmdOutput{
RootHash: *v.Verification.InclusionProof.RootHash,
Expand All @@ -148,10 +147,7 @@ var verifyCmd = &cobra.Command{
Size: *v.Verification.InclusionProof.TreeSize,
Hashes: v.Verification.InclusionProof.Hashes,
}
entryBytes, err = base64.StdEncoding.DecodeString(v.Body.(string))
if err != nil {
return nil, err
}
entry = v
}

if viper.IsSet("uuid") {
Expand All @@ -164,23 +160,17 @@ var verifyCmd = &cobra.Command{
}
}

// Note: the returned entry UUID is the UUID (not include the Tree ID)
leafHash, _ := hex.DecodeString(o.EntryUUID)
if !bytes.Equal(rfc6962.DefaultHasher.HashLeaf(entryBytes), leafHash) {
return nil, fmt.Errorf("computed leaf hash did not match entry UUID")
// Get Rekor Pub
// TODO(asraa): Replace with sigstore's GetRekorPubs to use TUF.
verifier, err := loadVerifier(rekorClient)
if err != nil {
return nil, err
}

hashes := [][]byte{}
for _, h := range o.Hashes {
hb, _ := hex.DecodeString(h)
hashes = append(hashes, hb)
if err := verify.VerifyLogEntry(ctx, rekorClient, &entry, verifier); err != nil {
return nil, fmt.Errorf("validating entry: %w", err)
}

rootHash, _ := hex.DecodeString(o.RootHash)

if err := proof.VerifyInclusion(rfc6962.DefaultHasher, uint64(o.Index), uint64(o.Size), leafHash, hashes, rootHash); err != nil {
return nil, err
}
return o, err
}),
}
Expand Down

0 comments on commit 970fc7f

Please sign in to comment.