...

Source file src/github.com/sigstore/rekor/pkg/verify/verify_test.go

Documentation: github.com/sigstore/rekor/pkg/verify

     1  //
     2  // Copyright 2022 The Sigstore Authors.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  package verify
    17  
    18  import (
    19  	"context"
    20  	"crypto/sha256"
    21  	"encoding/hex"
    22  	"testing"
    23  
    24  	"github.com/go-openapi/runtime"
    25  	"github.com/go-openapi/strfmt"
    26  	"github.com/go-openapi/swag"
    27  	"github.com/sigstore/rekor/pkg/generated/client"
    28  	"github.com/sigstore/rekor/pkg/generated/client/tlog"
    29  	"github.com/sigstore/rekor/pkg/generated/models"
    30  	"github.com/sigstore/rekor/pkg/util"
    31  	"github.com/sigstore/sigstore/pkg/signature"
    32  )
    33  
    34  type TlogClient struct {
    35  	Proof   []string
    36  	Root    string
    37  	LogInfo models.LogInfo
    38  }
    39  
    40  func (m *TlogClient) GetLogProof(_ *tlog.GetLogProofParams, _ ...tlog.ClientOption) (*tlog.GetLogProofOK, error) {
    41  	return &tlog.GetLogProofOK{
    42  		Payload: &models.ConsistencyProof{
    43  			Hashes:   m.Proof,
    44  			RootHash: &m.Root,
    45  		}}, nil
    46  }
    47  
    48  func (m *TlogClient) GetLogInfo(_ *tlog.GetLogInfoParams, _ ...tlog.ClientOption) (*tlog.GetLogInfoOK, error) {
    49  	return &tlog.GetLogInfoOK{
    50  		Payload: &m.LogInfo,
    51  	}, nil
    52  }
    53  
    54  // TODO: Implement mock
    55  func (m *TlogClient) SetTransport(_ runtime.ClientTransport) {
    56  }
    57  
    58  func TestConsistency(t *testing.T) {
    59  	root2String := "5be1758dd2228acfaf2546b4b6ce8aa40c82a3748f3dcb550e0d67ba34f02a45"
    60  	root2, _ := hex.DecodeString(root2String)
    61  	root1, _ := hex.DecodeString("59a575f157274702c38de3ab1e1784226f391fb79500ebf9f02b4439fb77574c")
    62  	root0, _ := hex.DecodeString("1a341bc342ff4e567387de9789ab14000b147124317841489172419874198147")
    63  	hashes := []string{"d3be742c8d73e2dd3c5635843e987ad3dfb3837616f412a07bf730c3ad73f5cb"}
    64  	for _, test := range []struct {
    65  		name    string
    66  		oldC    util.Checkpoint
    67  		newC    util.Checkpoint
    68  		Proof   []string
    69  		wantErr bool
    70  	}{
    71  		{
    72  			name: "zero length proof",
    73  			oldC: util.Checkpoint{
    74  				Origin: "test",
    75  				Size:   uint64(2),
    76  				Hash:   root2,
    77  			},
    78  			newC: util.Checkpoint{
    79  				Origin: "test",
    80  				Size:   uint64(2),
    81  				Hash:   root2,
    82  			},
    83  			wantErr: false,
    84  		},
    85  		{
    86  			name: "valid consistency proof",
    87  			oldC: util.Checkpoint{
    88  				Origin: "test",
    89  				Size:   uint64(1),
    90  				Hash:   root1,
    91  			},
    92  			newC: util.Checkpoint{
    93  				Origin: "test",
    94  				Size:   uint64(2),
    95  				Hash:   root2,
    96  			},
    97  			wantErr: false,
    98  		},
    99  		{
   100  			name: "invalid new sth request",
   101  			oldC: util.Checkpoint{
   102  				Origin: "test",
   103  				Size:   uint64(2),
   104  				Hash:   root1,
   105  			},
   106  			newC: util.Checkpoint{
   107  				Origin: "test",
   108  				Size:   uint64(1),
   109  				Hash:   root2,
   110  			},
   111  			wantErr: true,
   112  		},
   113  		{
   114  			name: "invalid consistency proof",
   115  			oldC: util.Checkpoint{
   116  				Origin: "test",
   117  				Size:   uint64(1),
   118  				Hash:   root2,
   119  			},
   120  			newC: util.Checkpoint{
   121  				Origin: "test",
   122  				Size:   uint64(2),
   123  				Hash:   root1,
   124  			},
   125  			wantErr: true,
   126  		},
   127  		{
   128  			name: "invalid consistency - same size",
   129  			oldC: util.Checkpoint{
   130  				Origin: "test",
   131  				Size:   uint64(1),
   132  				Hash:   root1,
   133  			},
   134  			newC: util.Checkpoint{
   135  				Origin: "test",
   136  				Size:   uint64(1),
   137  				Hash:   root2,
   138  			},
   139  			wantErr: true,
   140  		},
   141  		{
   142  			name: "invalid consistency - empty log",
   143  			oldC: util.Checkpoint{
   144  				Origin: "test",
   145  				Size:   uint64(0),
   146  				Hash:   root0,
   147  			},
   148  			newC: util.Checkpoint{
   149  				Origin: "test",
   150  				Size:   uint64(2),
   151  				Hash:   root2,
   152  			},
   153  			wantErr: true,
   154  		},
   155  	} {
   156  		var mClient client.Rekor
   157  		mClient.Tlog = &TlogClient{Proof: hashes, Root: root2String}
   158  
   159  		t.Run(string(test.name), func(t *testing.T) {
   160  
   161  			ctx := context.Background()
   162  			treeID := "123"
   163  			oldSTH, err := util.CreateSignedCheckpoint(test.oldC)
   164  			if err != nil {
   165  				t.Fatalf("creating old checkpoint")
   166  			}
   167  			newSTH, err := util.CreateSignedCheckpoint(test.newC)
   168  			if err != nil {
   169  				t.Fatalf("creating new checkpoint")
   170  			}
   171  
   172  			gotErr := ProveConsistency(ctx, &mClient, oldSTH, newSTH, treeID)
   173  
   174  			if (gotErr != nil) != test.wantErr {
   175  				t.Fatalf("ProveConsistency = %t, wantErr %t", gotErr, test.wantErr)
   176  			}
   177  		})
   178  	}
   179  }
   180  
   181  func TestInclusion(t *testing.T) {
   182  	time := int64(1661794812)
   183  	logID := "1701474e8cb504dbb853a5887bc2cf66936b0f36d2641bfb61f1abae80088e6a"
   184  	for _, test := range []struct {
   185  		name    string
   186  		e       models.LogEntryAnon
   187  		wantErr bool
   188  	}{
   189  		{
   190  			name: "valid inclusion",
   191  			e: models.LogEntryAnon{
   192  				Body:           "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoicmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJlY2RjNTUzNmY3M2JkYWU4ODE2ZjBlYTQwNzI2ZWY1ZTliODEwZDkxNDQ5MzA3NTkwM2JiOTA2MjNkOTdiMWQ4In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FWUNJUUQvUGRQUW1LV0MxKzBCTkVkNWdLdlFHcjF4eGwzaWVVZmZ2M2prMXp6Skt3SWhBTEJqM3hmQXlXeGx6NGpwb0lFSVYxVWZLOXZua1VVT1NvZVp4QlpQSEtQQyIsImZvcm1hdCI6Ing1MDkiLCJwdWJsaWNLZXkiOnsiY29udGVudCI6IkxTMHRMUzFDUlVkSlRpQlFWVUpNU1VNZ1MwVlpMUzB0TFMwS1RVWnJkMFYzV1VoTGIxcEplbW93UTBGUldVbExiMXBKZW1vd1JFRlJZMFJSWjBGRlRVOWpWR1pTUWxNNWFtbFlUVGd4UmxvNFoyMHZNU3R2YldWTmR3cHRiaTh6TkRjdk5UVTJaeTlzY21sVE56SjFUV2haT1V4alZDczFWVW8yWmtkQ1oyeHlOVm80VERCS1RsTjFZWE41WldRNVQzUmhVblozUFQwS0xTMHRMUzFGVGtRZ1VGVkNURWxESUV0RldTMHRMUzB0Q2c9PSJ9fX19",
   193  				IntegratedTime: &time,
   194  				LogID:          &logID,
   195  				LogIndex:       swag.Int64(1),
   196  				Verification: &models.LogEntryAnonVerification{
   197  					InclusionProof: &models.InclusionProof{
   198  						TreeSize: swag.Int64(int64(2)),
   199  						RootHash: swag.String("5be1758dd2228acfaf2546b4b6ce8aa40c82a3748f3dcb550e0d67ba34f02a45"),
   200  						LogIndex: swag.Int64(1),
   201  						Hashes: []string{
   202  							"59a575f157274702c38de3ab1e1784226f391fb79500ebf9f02b4439fb77574c",
   203  						},
   204  					},
   205  					SignedEntryTimestamp: strfmt.Base64("MEUCIHJj8xP+oPTd4BAXhO2lcbRplnKW2FafMiFo0gIDGUcYAiEA80BJ8QikiupGAv3R3dtSvZ1ICsAOQat10cFKPqBkLBM="),
   206  				},
   207  			},
   208  			wantErr: false,
   209  		},
   210  		{
   211  			name: "invalid inclusion - bad body hash",
   212  			e: models.LogEntryAnon{
   213  				Body:           "ayJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoicmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJlY2RjNTUzNmY3M2JkYWU4ODE2ZjBlYTQwNzI2ZWY1ZTliODEwZDkxNDQ5MzA3NTkwM2JiOTA2MjNkOTdiMWQ4In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FWUNJUUQvUGRQUW1LV0MxKzBCTkVkNWdLdlFHcjF4eGwzaWVVZmZ2M2prMXp6Skt3SWhBTEJqM3hmQXlXeGx6NGpwb0lFSVYxVWZLOXZua1VVT1NvZVp4QlpQSEtQQyIsImZvcm1hdCI6Ing1MDkiLCJwdWJsaWNLZXkiOnsiY29udGVudCI6IkxTMHRMUzFDUlVkSlRpQlFWVUpNU1VNZ1MwVlpMUzB0TFMwS1RVWnJkMFYzV1VoTGIxcEplbW93UTBGUldVbExiMXBKZW1vd1JFRlJZMFJSWjBGRlRVOWpWR1pTUWxNNWFtbFlUVGd4UmxvNFoyMHZNU3R2YldWTmR3cHRiaTh6TkRjdk5UVTJaeTlzY21sVE56SjFUV2haT1V4alZDczFWVW8yWmtkQ1oyeHlOVm80VERCS1RsTjFZWE41WldRNVQzUmhVblozUFQwS0xTMHRMUzFGVGtRZ1VGVkNURWxESUV0RldTMHRMUzB0Q2c9PSJ9fX19",
   214  				IntegratedTime: &time,
   215  				LogID:          &logID,
   216  				LogIndex:       swag.Int64(1),
   217  				Verification: &models.LogEntryAnonVerification{
   218  					InclusionProof: &models.InclusionProof{
   219  						TreeSize: swag.Int64(int64(2)),
   220  						RootHash: swag.String("5be1758dd2228acfaf2546b4b6ce8aa40c82a3748f3dcb550e0d67ba34f02a45"),
   221  						LogIndex: swag.Int64(1),
   222  						Hashes: []string{
   223  							"59a575f157274702c38de3ab1e1784226f391fb79500ebf9f02b4439fb77574c",
   224  						},
   225  					},
   226  					SignedEntryTimestamp: strfmt.Base64("MEUCIHJj8xP+oPTd4BAXhO2lcbRplnKW2FafMiFo0gIDGUcYAiEA80BJ8QikiupGAv3R3dtSvZ1ICsAOQat10cFKPqBkLBM="),
   227  				},
   228  			},
   229  			wantErr: true,
   230  		},
   231  	} {
   232  		t.Run(string(test.name), func(t *testing.T) {
   233  			ctx := context.Background()
   234  
   235  			gotErr := VerifyInclusion(ctx, &test.e)
   236  
   237  			if (gotErr != nil) != test.wantErr {
   238  				t.Fatalf("VerifyInclusion = %t, wantErr %t", gotErr, test.wantErr)
   239  			}
   240  		})
   241  	}
   242  }
   243  
   244  func TestCheckpoint(t *testing.T) {
   245  	hostname := "rekor.localhost"
   246  	treeID := int64(123)
   247  	rootHash := sha256.Sum256([]byte{1, 2, 3})
   248  	rootHashString := hex.EncodeToString(rootHash[:])
   249  	treeSize := uint64(42)
   250  	signer, _, err := signature.NewDefaultECDSASignerVerifier()
   251  	if err != nil {
   252  		t.Fatalf("error generating signer: %v", err)
   253  	}
   254  	ctx := context.Background()
   255  	scBytes, err := util.CreateAndSignCheckpoint(ctx, hostname, treeID, treeSize, rootHash[:], signer)
   256  	if err != nil {
   257  		t.Fatalf("error creating signed checkpoint: %v", err)
   258  	}
   259  
   260  	time := int64(1661794812)
   261  	logID := "1701474e8cb504dbb853a5887bc2cf66936b0f36d2641bfb61f1abae80088e6a"
   262  
   263  	for _, test := range []struct {
   264  		name    string
   265  		e       models.LogEntryAnon
   266  		wantErr bool
   267  	}{
   268  		{
   269  			name: "valid checkpoint",
   270  			e: models.LogEntryAnon{
   271  				Body:           "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoicmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJlY2RjNTUzNmY3M2JkYWU4ODE2ZjBlYTQwNzI2ZWY1ZTliODEwZDkxNDQ5MzA3NTkwM2JiOTA2MjNkOTdiMWQ4In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FWUNJUUQvUGRQUW1LV0MxKzBCTkVkNWdLdlFHcjF4eGwzaWVVZmZ2M2prMXp6Skt3SWhBTEJqM3hmQXlXeGx6NGpwb0lFSVYxVWZLOXZua1VVT1NvZVp4QlpQSEtQQyIsImZvcm1hdCI6Ing1MDkiLCJwdWJsaWNLZXkiOnsiY29udGVudCI6IkxTMHRMUzFDUlVkSlRpQlFWVUpNU1VNZ1MwVlpMUzB0TFMwS1RVWnJkMFYzV1VoTGIxcEplbW93UTBGUldVbExiMXBKZW1vd1JFRlJZMFJSWjBGRlRVOWpWR1pTUWxNNWFtbFlUVGd4UmxvNFoyMHZNU3R2YldWTmR3cHRiaTh6TkRjdk5UVTJaeTlzY21sVE56SjFUV2haT1V4alZDczFWVW8yWmtkQ1oyeHlOVm80VERCS1RsTjFZWE41WldRNVQzUmhVblozUFQwS0xTMHRMUzFGVGtRZ1VGVkNURWxESUV0RldTMHRMUzB0Q2c9PSJ9fX19",
   272  				IntegratedTime: &time,
   273  				LogID:          &logID,
   274  				LogIndex:       swag.Int64(1),
   275  				Verification: &models.LogEntryAnonVerification{
   276  					InclusionProof: &models.InclusionProof{
   277  						TreeSize: swag.Int64(int64(2)),
   278  						RootHash: swag.String(rootHashString),
   279  						LogIndex: swag.Int64(1),
   280  						Hashes: []string{
   281  							"59a575f157274702c38de3ab1e1784226f391fb79500ebf9f02b4439fb77574c",
   282  						},
   283  						Checkpoint: swag.String(string(scBytes)),
   284  					},
   285  					SignedEntryTimestamp: strfmt.Base64("MEUCIHJj8xP+oPTd4BAXhO2lcbRplnKW2FafMiFo0gIDGUcYAiEA80BJ8QikiupGAv3R3dtSvZ1ICsAOQat10cFKPqBkLBM="),
   286  				},
   287  			},
   288  			wantErr: false,
   289  		},
   290  		{
   291  			name: "root hash mismatch",
   292  			e: models.LogEntryAnon{
   293  				Body:           "ayJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoicmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJlY2RjNTUzNmY3M2JkYWU4ODE2ZjBlYTQwNzI2ZWY1ZTliODEwZDkxNDQ5MzA3NTkwM2JiOTA2MjNkOTdiMWQ4In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FWUNJUUQvUGRQUW1LV0MxKzBCTkVkNWdLdlFHcjF4eGwzaWVVZmZ2M2prMXp6Skt3SWhBTEJqM3hmQXlXeGx6NGpwb0lFSVYxVWZLOXZua1VVT1NvZVp4QlpQSEtQQyIsImZvcm1hdCI6Ing1MDkiLCJwdWJsaWNLZXkiOnsiY29udGVudCI6IkxTMHRMUzFDUlVkSlRpQlFWVUpNU1VNZ1MwVlpMUzB0TFMwS1RVWnJkMFYzV1VoTGIxcEplbW93UTBGUldVbExiMXBKZW1vd1JFRlJZMFJSWjBGRlRVOWpWR1pTUWxNNWFtbFlUVGd4UmxvNFoyMHZNU3R2YldWTmR3cHRiaTh6TkRjdk5UVTJaeTlzY21sVE56SjFUV2haT1V4alZDczFWVW8yWmtkQ1oyeHlOVm80VERCS1RsTjFZWE41WldRNVQzUmhVblozUFQwS0xTMHRMUzFGVGtRZ1VGVkNURWxESUV0RldTMHRMUzB0Q2c9PSJ9fX19",
   294  				IntegratedTime: &time,
   295  				LogID:          &logID,
   296  				LogIndex:       swag.Int64(1),
   297  				Verification: &models.LogEntryAnonVerification{
   298  					InclusionProof: &models.InclusionProof{
   299  						TreeSize: swag.Int64(int64(2)),
   300  						RootHash: swag.String("5be1758dd2228acfaf2546b4b6ce8aa40c82a3748f3dcb550e0d67ba34f02a45"),
   301  						LogIndex: swag.Int64(1),
   302  						Hashes: []string{
   303  							"59a575f157274702c38de3ab1e1784226f391fb79500ebf9f02b4439fb77574c",
   304  						},
   305  						Checkpoint: swag.String(string(scBytes)),
   306  					},
   307  					SignedEntryTimestamp: strfmt.Base64("MEUCIHJj8xP+oPTd4BAXhO2lcbRplnKW2FafMiFo0gIDGUcYAiEA80BJ8QikiupGAv3R3dtSvZ1ICsAOQat10cFKPqBkLBM="),
   308  				},
   309  			},
   310  			wantErr: true,
   311  		},
   312  	} {
   313  		t.Run(string(test.name), func(t *testing.T) {
   314  			gotErr := VerifyCheckpointSignature(&test.e, signer)
   315  
   316  			if (gotErr != nil) != test.wantErr {
   317  				t.Fatalf("VerifyCheckpointSignature = %t, wantErr %t", gotErr, test.wantErr)
   318  			}
   319  		})
   320  	}
   321  }
   322  

View as plain text