From 7b37b9a416db316c28b586f739f8542b26245908 Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Mon, 3 Oct 2022 14:42:21 -0500 Subject: [PATCH 1/2] verify: verify checkpoint signature Signed-off-by: Asra Ali --- pkg/verify/verify.go | 9 +++++ pkg/verify/verify_test.go | 82 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/pkg/verify/verify.go b/pkg/verify/verify.go index d01dad8e8..c5b42ac9b 100644 --- a/pkg/verify/verify.go +++ b/pkg/verify/verify.go @@ -119,6 +119,15 @@ func VerifyCheckpointSignature(e *models.LogEntryAnon, verifier signature.Verifi if !sth.Verify(verifier) { return errors.New("signature on checkpoint did not verify") } + rootHash, err := hex.DecodeString(*e.Verification.InclusionProof.RootHash) + if err != nil { + return err + } + if bytes.EqualFold(rootHash, sth.Hash) { + return fmt.Errorf("proof root hash does not match signed tree head, expected %s got %s", + *e.Verification.InclusionProof.RootHash, + sth.Hash) + } return nil } diff --git a/pkg/verify/verify_test.go b/pkg/verify/verify_test.go index 41cbea77f..a14c12897 100644 --- a/pkg/verify/verify_test.go +++ b/pkg/verify/verify_test.go @@ -17,16 +17,19 @@ package verify import ( "context" + "crypto/sha256" "encoding/hex" "testing" "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" + "github.com/google/trillian/types" "github.com/sigstore/rekor/pkg/generated/client" "github.com/sigstore/rekor/pkg/generated/client/tlog" "github.com/sigstore/rekor/pkg/generated/models" "github.com/sigstore/rekor/pkg/util" + "github.com/sigstore/sigstore/pkg/signature" ) type TlogClient struct { @@ -223,3 +226,82 @@ func TestInclusion(t *testing.T) { }) } } + +func TestCheckpoint(t *testing.T) { + hostname := "rekor.localhost" + treeID := int64(123) + rootHash := sha256.Sum256([]byte{1, 2, 3}) + rootHashString := hex.EncodeToString(rootHash[:]) + treeSize := uint64(42) + signer, _, err := signature.NewDefaultECDSASignerVerifier() + if err != nil { + t.Fatalf("error generating signer: %v", err) + } + ctx := context.Background() + scBytes, err := util.CreateAndSignCheckpoint(ctx, hostname, treeID, &types.LogRootV1{TreeSize: treeSize, RootHash: rootHash[:]}, signer) + if err != nil { + t.Fatalf("error creating signed checkpoint: %v", err) + } + + time := int64(1661794812) + logID := "1701474e8cb504dbb853a5887bc2cf66936b0f36d2641bfb61f1abae80088e6a" + + for _, test := range []struct { + name string + e models.LogEntryAnon + wantErr bool + }{ + { + name: "valid checkpoint", + e: models.LogEntryAnon{ + Body: "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoicmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJlY2RjNTUzNmY3M2JkYWU4ODE2ZjBlYTQwNzI2ZWY1ZTliODEwZDkxNDQ5MzA3NTkwM2JiOTA2MjNkOTdiMWQ4In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FWUNJUUQvUGRQUW1LV0MxKzBCTkVkNWdLdlFHcjF4eGwzaWVVZmZ2M2prMXp6Skt3SWhBTEJqM3hmQXlXeGx6NGpwb0lFSVYxVWZLOXZua1VVT1NvZVp4QlpQSEtQQyIsImZvcm1hdCI6Ing1MDkiLCJwdWJsaWNLZXkiOnsiY29udGVudCI6IkxTMHRMUzFDUlVkSlRpQlFWVUpNU1VNZ1MwVlpMUzB0TFMwS1RVWnJkMFYzV1VoTGIxcEplbW93UTBGUldVbExiMXBKZW1vd1JFRlJZMFJSWjBGRlRVOWpWR1pTUWxNNWFtbFlUVGd4UmxvNFoyMHZNU3R2YldWTmR3cHRiaTh6TkRjdk5UVTJaeTlzY21sVE56SjFUV2haT1V4alZDczFWVW8yWmtkQ1oyeHlOVm80VERCS1RsTjFZWE41WldRNVQzUmhVblozUFQwS0xTMHRMUzFGVGtRZ1VGVkNURWxESUV0RldTMHRMUzB0Q2c9PSJ9fX19", + IntegratedTime: &time, + LogID: &logID, + LogIndex: swag.Int64(1), + Verification: &models.LogEntryAnonVerification{ + InclusionProof: &models.InclusionProof{ + TreeSize: swag.Int64(int64(2)), + RootHash: swag.String("5be1758dd2228acfaf2546b4b6ce8aa40c82a3748f3dcb550e0d67ba34f02a45"), + LogIndex: swag.Int64(1), + Hashes: []string{ + "59a575f157274702c38de3ab1e1784226f391fb79500ebf9f02b4439fb77574c", + }, + Checkpoint: swag.String(string(scBytes)), + }, + SignedEntryTimestamp: strfmt.Base64("MEUCIHJj8xP+oPTd4BAXhO2lcbRplnKW2FafMiFo0gIDGUcYAiEA80BJ8QikiupGAv3R3dtSvZ1ICsAOQat10cFKPqBkLBM="), + }, + }, + wantErr: false, + }, + { + name: "root hash mismatch", + e: models.LogEntryAnon{ + Body: "ayJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoicmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJlY2RjNTUzNmY3M2JkYWU4ODE2ZjBlYTQwNzI2ZWY1ZTliODEwZDkxNDQ5MzA3NTkwM2JiOTA2MjNkOTdiMWQ4In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FWUNJUUQvUGRQUW1LV0MxKzBCTkVkNWdLdlFHcjF4eGwzaWVVZmZ2M2prMXp6Skt3SWhBTEJqM3hmQXlXeGx6NGpwb0lFSVYxVWZLOXZua1VVT1NvZVp4QlpQSEtQQyIsImZvcm1hdCI6Ing1MDkiLCJwdWJsaWNLZXkiOnsiY29udGVudCI6IkxTMHRMUzFDUlVkSlRpQlFWVUpNU1VNZ1MwVlpMUzB0TFMwS1RVWnJkMFYzV1VoTGIxcEplbW93UTBGUldVbExiMXBKZW1vd1JFRlJZMFJSWjBGRlRVOWpWR1pTUWxNNWFtbFlUVGd4UmxvNFoyMHZNU3R2YldWTmR3cHRiaTh6TkRjdk5UVTJaeTlzY21sVE56SjFUV2haT1V4alZDczFWVW8yWmtkQ1oyeHlOVm80VERCS1RsTjFZWE41WldRNVQzUmhVblozUFQwS0xTMHRMUzFGVGtRZ1VGVkNURWxESUV0RldTMHRMUzB0Q2c9PSJ9fX19", + IntegratedTime: &time, + LogID: &logID, + LogIndex: swag.Int64(1), + Verification: &models.LogEntryAnonVerification{ + InclusionProof: &models.InclusionProof{ + TreeSize: swag.Int64(int64(2)), + RootHash: swag.String(rootHashString), + LogIndex: swag.Int64(1), + Hashes: []string{ + "59a575f157274702c38de3ab1e1784226f391fb79500ebf9f02b4439fb77574c", + }, + Checkpoint: swag.String(string(scBytes)), + }, + SignedEntryTimestamp: strfmt.Base64("MEUCIHJj8xP+oPTd4BAXhO2lcbRplnKW2FafMiFo0gIDGUcYAiEA80BJ8QikiupGAv3R3dtSvZ1ICsAOQat10cFKPqBkLBM="), + }, + }, + wantErr: true, + }, + } { + t.Run(string(test.name), func(t *testing.T) { + gotErr := VerifyCheckpointSignature(&test.e, signer) + + if (gotErr != nil) != test.wantErr { + t.Fatalf("VerifyCheckpointSignature = %t, wantErr %t", gotErr, test.wantErr) + } + }) + } +} From d3c134d60822da9f835b871dca4b3b0b172d2b78 Mon Sep 17 00:00:00 2001 From: Asra Ali Date: Mon, 3 Oct 2022 15:14:01 -0500 Subject: [PATCH 2/2] fix not Signed-off-by: Asra Ali fix Signed-off-by: Asra Ali --- pkg/verify/verify.go | 7 ++++--- pkg/verify/verify_test.go | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pkg/verify/verify.go b/pkg/verify/verify.go index c5b42ac9b..94908c00d 100644 --- a/pkg/verify/verify.go +++ b/pkg/verify/verify.go @@ -121,12 +121,13 @@ func VerifyCheckpointSignature(e *models.LogEntryAnon, verifier signature.Verifi } rootHash, err := hex.DecodeString(*e.Verification.InclusionProof.RootHash) if err != nil { - return err + return errors.New("decoding inclusion proof root has") } - if bytes.EqualFold(rootHash, sth.Hash) { + + if !bytes.EqualFold(rootHash, sth.Hash) { return fmt.Errorf("proof root hash does not match signed tree head, expected %s got %s", *e.Verification.InclusionProof.RootHash, - sth.Hash) + hex.EncodeToString(sth.Hash)) } return nil } diff --git a/pkg/verify/verify_test.go b/pkg/verify/verify_test.go index a14c12897..dd7b1ac61 100644 --- a/pkg/verify/verify_test.go +++ b/pkg/verify/verify_test.go @@ -261,7 +261,7 @@ func TestCheckpoint(t *testing.T) { Verification: &models.LogEntryAnonVerification{ InclusionProof: &models.InclusionProof{ TreeSize: swag.Int64(int64(2)), - RootHash: swag.String("5be1758dd2228acfaf2546b4b6ce8aa40c82a3748f3dcb550e0d67ba34f02a45"), + RootHash: swag.String(rootHashString), LogIndex: swag.Int64(1), Hashes: []string{ "59a575f157274702c38de3ab1e1784226f391fb79500ebf9f02b4439fb77574c", @@ -283,7 +283,7 @@ func TestCheckpoint(t *testing.T) { Verification: &models.LogEntryAnonVerification{ InclusionProof: &models.InclusionProof{ TreeSize: swag.Int64(int64(2)), - RootHash: swag.String(rootHashString), + RootHash: swag.String("5be1758dd2228acfaf2546b4b6ce8aa40c82a3748f3dcb550e0d67ba34f02a45"), LogIndex: swag.Int64(1), Hashes: []string{ "59a575f157274702c38de3ab1e1784226f391fb79500ebf9f02b4439fb77574c",