From 5cb0be9a3ffe70fbe487b40236dfa35b3ba1f864 Mon Sep 17 00:00:00 2001 From: Dan Lorenc Date: Mon, 27 Dec 2021 10:53:49 -0600 Subject: [PATCH] Enable parsing of incomplete minisign keys, to enable re-indexing. Without this we can't properly re-run IndexKeys() on the log data because old minisign keys were stripped to no longer contain the KeyID or Algorithm field. Signed-off-by: Dan Lorenc --- pkg/pki/minisign/minisign.go | 29 ++++++++++---- pkg/pki/minisign/minisign_test.go | 64 ++++++++++++++++++++++++------- 2 files changed, 72 insertions(+), 21 deletions(-) diff --git a/pkg/pki/minisign/minisign.go b/pkg/pki/minisign/minisign.go index 995a18c7a..3b210b1ec 100644 --- a/pkg/pki/minisign/minisign.go +++ b/pkg/pki/minisign/minisign.go @@ -121,17 +121,30 @@ func NewPublicKey(r io.Reader) (*PublicKey, error) { inputString := inputBuffer.String() + // There are three ways a minisign key can be stored. + // 1. The entire text key + // 2. A base64 encoded string + // 3. A legacy format we stored of just the key material (no key ID or Algorithm) due to bug fixed in https://github.com/sigstore/rekor/pull/562 key, err := minisign.DecodePublicKey(inputString) - if err != nil { - // try as a standalone base64 string - key, err = minisign.NewPublicKey(inputString) - if err != nil { - return nil, fmt.Errorf("unable to read minisign public key: %w", err) - } + if err == nil { + k.key = &key + return &k, nil + } + key, err = minisign.NewPublicKey(inputString) + if err == nil { + k.key = &key + return &k, nil } - k.key = &key - return &k, nil + if len(inputString) == 32 { + k.key = &minisign.PublicKey{ + SignatureAlgorithm: [2]byte{'E', 'd'}, + KeyId: [8]byte{}, + } + copy(k.key.PublicKey[:], inputBuffer.Bytes()) + return &k, nil + } + return nil, fmt.Errorf("unable to read minisign public key: %w", err) } // CanonicalValue implements the pki.PublicKey interface diff --git a/pkg/pki/minisign/minisign_test.go b/pkg/pki/minisign/minisign_test.go index 15706158b..40d38a8b6 100644 --- a/pkg/pki/minisign/minisign_test.go +++ b/pkg/pki/minisign/minisign_test.go @@ -32,26 +32,64 @@ func TestMain(m *testing.M) { func TestReadPublicKey(t *testing.T) { type test struct { - caseDesc string - inputFile string - errorFound bool + caseDesc string + inputFile string } tests := []test{ - {caseDesc: "Not a valid public key file", inputFile: "testdata/hello_world.txt.minisig", errorFound: true}, - {caseDesc: "Valid public key (minisign)", inputFile: "testdata/minisign.pub", errorFound: false}, - {caseDesc: "Valid public key (signify)", inputFile: "testdata/signify.pub", errorFound: false}, + {caseDesc: "Valid public key (minisign)", inputFile: "testdata/minisign.pub"}, + {caseDesc: "Valid public key (signify)", inputFile: "testdata/signify.pub"}, } for _, tc := range tests { - file, err := os.Open(tc.inputFile) - if err != nil { - t.Errorf("%v: cannot open %v", tc.caseDesc, tc.inputFile) - } + t.Run(tc.caseDesc, func(t *testing.T) { + file, err := os.Open(tc.inputFile) + if err != nil { + t.Fatalf("%v: cannot open %v", tc.caseDesc, tc.inputFile) + } - if got, err := NewPublicKey(file); ((got != nil) == tc.errorFound) || ((err != nil) != tc.errorFound) { - t.Errorf("%v: unexpected result testing %v: %v", tc.caseDesc, tc.inputFile, err) - } + got, err := NewPublicKey(file) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + + // Try to send just the raw public key bytes too + rawBytes := got.key.PublicKey[:] + + rawGot, err := NewPublicKey(bytes.NewReader(rawBytes)) + if err != nil { + t.Fatalf("unexpected error re-parsing public key: %v", err) + } + if !bytes.Equal(rawGot.key.PublicKey[:], rawBytes) { + t.Errorf("expected parsed keys to be equal, %v != %v", rawGot.key.PublicKey, rawBytes) + } + }) + } +} + +func TestReadPublicKeyErr(t *testing.T) { + type test struct { + caseDesc string + inputFile string + } + + tests := []test{ + {caseDesc: "Not a valid public key file", inputFile: "testdata/hello_world.txt.minisig"}, + {caseDesc: "Wrong length", inputFile: "testdata/hello_world.txt"}, + } + + for _, tc := range tests { + t.Run(tc.caseDesc, func(t *testing.T) { + file, err := os.Open(tc.inputFile) + if err != nil { + t.Fatalf("%v: cannot open %v", tc.caseDesc, tc.inputFile) + } + + got, err := NewPublicKey(file) + if err == nil { + t.Errorf("error expected, got nil error and %v", got) + } + }) } }