...

Source file src/github.com/sigstore/rekor/pkg/pki/tuf/tuf_test.go

Documentation: github.com/sigstore/rekor/pkg/pki/tuf

     1  //
     2  // Copyright 2021 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 tuf
    17  
    18  import (
    19  	"bytes"
    20  	"crypto/ecdsa"
    21  	"crypto/x509"
    22  	"io"
    23  	"os"
    24  	"reflect"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/sigstore/sigstore/pkg/cryptoutils"
    29  	_ "github.com/theupdateframework/go-tuf/pkg/deprecated/set_ecdsa"
    30  	"github.com/theupdateframework/go-tuf/verify"
    31  )
    32  
    33  func patchIsExpired() func() {
    34  	// Patch out the IsExpired to make the tests stable :)
    35  	old := verify.IsExpired
    36  	verify.IsExpired = func(_ time.Time) bool {
    37  		return false
    38  	}
    39  	return func() {
    40  		verify.IsExpired = old
    41  	}
    42  }
    43  
    44  func TestReadPublicKey(t *testing.T) {
    45  	// Tests reading a valid public key (root.json)
    46  	type test struct {
    47  		caseDesc    string
    48  		inputFile   string
    49  		errorFound  bool
    50  		specVersion string
    51  	}
    52  
    53  	tests := []test{
    54  		{caseDesc: "Unsigned root manifest", inputFile: "testdata/unsigned_root.json", errorFound: true},
    55  		{caseDesc: "Invalid TUF root.json (invalid type)", inputFile: "testdata/timestamp.json", errorFound: true, specVersion: "1.0"},
    56  		{caseDesc: "Valid TUF root.json", inputFile: "testdata/1.root.json", errorFound: false, specVersion: "1.0"},
    57  	}
    58  
    59  	// Patch out the expired function to make tests stable :)
    60  	defer patchIsExpired()()
    61  
    62  	for _, tc := range tests {
    63  		file, err := os.Open(tc.inputFile)
    64  		if err != nil {
    65  			t.Errorf("%v: cannot open %v", tc.caseDesc, tc.inputFile)
    66  		}
    67  
    68  		got, err := NewPublicKey(file)
    69  		if ((got != nil) == tc.errorFound) || ((err != nil) != tc.errorFound) {
    70  			t.Errorf("%v: unexpected result testing %v: %v", tc.caseDesc, tc.inputFile, err)
    71  		}
    72  
    73  		if !tc.errorFound {
    74  			specVersion, err := got.SpecVersion()
    75  			if err != nil {
    76  				t.Errorf("%v: unexpected result testing %v: %v", tc.caseDesc, tc.inputFile, err)
    77  			}
    78  			if specVersion != tc.specVersion {
    79  				t.Errorf("%v: unexpected spec version expected %v, got %v", tc.caseDesc, tc.specVersion, specVersion)
    80  			}
    81  
    82  			identities, err := got.Identities()
    83  			if err != nil {
    84  				t.Errorf("%v: error getting identities for %v: %v", tc.caseDesc, tc.inputFile, err)
    85  			}
    86  			if len(identities) != 7 {
    87  				t.Errorf("%v: expected 7 identities, got: %d", tc.caseDesc, len(identities))
    88  			}
    89  			for _, i := range identities {
    90  				if _, ok := i.Crypto.(*ecdsa.PublicKey); !ok {
    91  					t.Errorf("%v: key was not of type *ecdsa.PublicKey: %v", tc.caseDesc, reflect.TypeOf(i.Crypto))
    92  				}
    93  				key, err := x509.ParsePKIXPublicKey(i.Raw)
    94  				if err != nil {
    95  					t.Fatalf("%v: Raw is not in PKIX format: %v", tc.caseDesc, err)
    96  				}
    97  				if err := cryptoutils.EqualKeys(key, i.Crypto); err != nil {
    98  					t.Errorf("%v: raw key and crypto key not equal: %v", tc.caseDesc, err)
    99  				}
   100  				if len(i.Fingerprint) != 64 {
   101  					t.Errorf("%v: fingerprint is not expected length of 64 (hex 32-byte sha256): %d", tc.caseDesc, len(i.Fingerprint))
   102  				}
   103  			}
   104  		}
   105  	}
   106  }
   107  
   108  func TestReadSignature(t *testing.T) {
   109  	// Tests reading a valid signature (manifest)
   110  	type test struct {
   111  		caseDesc   string
   112  		inputFile  string
   113  		errorFound bool
   114  	}
   115  
   116  	tests := []test{
   117  		{caseDesc: "Not a valid TUF manifest", inputFile: "testdata/bogus.json", errorFound: true},
   118  		{caseDesc: "Valid root.json manifest", inputFile: "testdata/timestamp.json", errorFound: false},
   119  		{caseDesc: "Valid timestamp.json manifest", inputFile: "testdata/1.root.json", errorFound: false},
   120  		{caseDesc: "Valid unsigned root.json manifest", inputFile: "testdata/unsigned_root.json", errorFound: false},
   121  	}
   122  
   123  	for _, tc := range tests {
   124  		file, err := os.Open(tc.inputFile)
   125  		if err != nil {
   126  			t.Errorf("%v: cannot open %v", tc.caseDesc, tc.inputFile)
   127  		}
   128  		if got, err := NewSignature(file); ((got != nil) == tc.errorFound) || ((err != nil) != tc.errorFound) {
   129  			t.Errorf("%v: unexpected result testing %v: %v", tc.caseDesc, tc.inputFile, got)
   130  		}
   131  	}
   132  
   133  }
   134  
   135  func TestCanonicalValue(t *testing.T) {
   136  	// Tests equivalence even with different JSON encodings
   137  	type test struct {
   138  		caseDesc string
   139  		input    string
   140  		output   string
   141  		match    bool
   142  	}
   143  
   144  	var k PublicKey
   145  	if _, err := k.CanonicalValue(); err == nil {
   146  		t.Errorf("CanonicalValue did not error out for uninitialized key")
   147  	}
   148  
   149  	// Patch out the expired function to make tests stable :)
   150  	defer patchIsExpired()()
   151  
   152  	tests := []test{
   153  		{caseDesc: "root", input: "testdata/1.root.json", output: "testdata/reformat.1.root.json", match: true},
   154  	}
   155  
   156  	for _, tc := range tests {
   157  		var inputFile, outputFile io.Reader
   158  		var err error
   159  		inputFile, err = os.Open(tc.input)
   160  		if err != nil {
   161  			t.Errorf("%v: cannot open %v", tc.caseDesc, tc.input)
   162  		}
   163  
   164  		inputKey, err := NewPublicKey(inputFile)
   165  		if err != nil {
   166  			t.Errorf("%v: Error reading input for TestCanonicalValue: %v", tc.caseDesc, err)
   167  		}
   168  
   169  		cvInput, err := inputKey.CanonicalValue()
   170  		if err != nil {
   171  			t.Errorf("%v: Error canonicalizing public key '%v': %v", tc.caseDesc, tc.input, err)
   172  		}
   173  
   174  		outputFile, err = os.Open(tc.output)
   175  		if err != nil {
   176  			t.Errorf("%v: cannot open %v", tc.caseDesc, tc.output)
   177  		}
   178  
   179  		outputKey, err := NewPublicKey(outputFile)
   180  		if err != nil {
   181  			t.Fatalf("%v: Error reading input for TestCanonicalValue: %v", tc.caseDesc, err)
   182  		}
   183  
   184  		cvOutput, err := outputKey.CanonicalValue()
   185  		if err != nil {
   186  			t.Fatalf("%v: Error canonicalizing public key '%v': %v", tc.caseDesc, tc.input, err)
   187  		}
   188  
   189  		if bytes.Equal(cvInput, cvOutput) != tc.match {
   190  			t.Errorf("%v: %v equality of canonical values of %v and %v was expected but not generated", tc.caseDesc, tc.match, tc.input, tc.output)
   191  		}
   192  	}
   193  }
   194  
   195  func TestVerifySignature(t *testing.T) {
   196  	type test struct {
   197  		caseDesc string
   198  		sigFile  string
   199  		keyFile  string
   200  		verified bool
   201  	}
   202  
   203  	tests := []test{
   204  		{caseDesc: "Valid root.json, valid signed timestamp.json", keyFile: "testdata/1.root.json", sigFile: "testdata/timestamp.json", verified: true},
   205  		{caseDesc: "Valid root.json, valid signed root.json", keyFile: "testdata/1.root.json", sigFile: "testdata/1.root.json", verified: true},
   206  		{caseDesc: "Valid root.json, mismatched timestamp.json", keyFile: "testdata/other_root.json", sigFile: "testdata/timestamp.json", verified: false},
   207  		{caseDesc: "Valid root.json, unsigned root.json", keyFile: "testdata/1.root.json", sigFile: "testdata/unsigned_root.json", verified: false},
   208  	}
   209  
   210  	defer patchIsExpired()()
   211  
   212  	for _, tc := range tests {
   213  		keyFile, err := os.Open(tc.keyFile)
   214  		if err != nil {
   215  			t.Errorf("%v: error reading keyfile '%v': %v", tc.caseDesc, tc.keyFile, err)
   216  		}
   217  		k, err := NewPublicKey(keyFile)
   218  		if err != nil {
   219  			t.Errorf("%v: error reading keyfile '%v': %v", tc.caseDesc, tc.keyFile, err)
   220  		}
   221  
   222  		sigFile, err := os.Open(tc.sigFile)
   223  		if err != nil {
   224  			t.Errorf("%v: error reading sigfile '%v': %v", tc.caseDesc, tc.sigFile, err)
   225  		}
   226  		s, err := NewSignature(sigFile)
   227  		if err != nil {
   228  			t.Errorf("%v: error reading sigfile '%v': %v", tc.caseDesc, tc.sigFile, err)
   229  		}
   230  
   231  		if err := s.Verify(nil, k); (err == nil) != tc.verified {
   232  			t.Errorf("%v: unexpected result in verifying sigature: %v", tc.caseDesc, err)
   233  		}
   234  	}
   235  
   236  	emptyKey := PublicKey{}
   237  	emptySig := Signature{}
   238  
   239  	if err := emptySig.Verify(nil, emptyKey); err == nil {
   240  		t.Errorf("expected error when using empty sig to verify")
   241  	}
   242  
   243  	sigFile, _ := os.Open("testdata/timestamp.json")
   244  	validSig, _ := NewSignature(sigFile)
   245  
   246  	if err := validSig.Verify(bytes.NewReader([]byte("irrelevant")), &emptyKey); err == nil {
   247  		t.Errorf("expected error when using empty key to verify")
   248  	}
   249  }
   250  

View as plain text