From e7b377aa4a7d659286a0c8fdfce7639734455578 Mon Sep 17 00:00:00 2001 From: Hayden B Date: Mon, 7 Aug 2023 09:21:38 -0700 Subject: [PATCH] Refactor Identities API (#1611) * Refactor Identities API Instead of providing raw strings that are up to the client to determine how to parse, return typed structs. Encoded keys are included and should be parsed based on the returned type. Signed-off-by: Hayden Blauzvern * Remove debug statement Signed-off-by: Hayden Blauzvern --------- Signed-off-by: Hayden Blauzvern --- pkg/pki/identity/identity.go | 25 ++++ pkg/pki/minisign/minisign.go | 5 +- pkg/pki/minisign/minisign_test.go | 28 +++- pkg/pki/pgp/pgp.go | 9 +- pkg/pki/pgp/pgp_test.go | 6 +- pkg/pki/pkcs7/pkcs7.go | 17 +-- pkg/pki/pkcs7/pkcs7_test.go | 37 +++-- pkg/pki/pki.go | 5 +- pkg/pki/ssh/ssh.go | 20 +-- pkg/pki/ssh/ssh_test.go | 34 +++-- pkg/pki/tuf/testdata/1.root.json | 170 +++++++++++++--------- pkg/pki/tuf/testdata/reformat.1.root.json | 2 +- pkg/pki/tuf/testdata/timestamp.json | 45 ++---- pkg/pki/tuf/tuf.go | 51 ++++++- pkg/pki/tuf/tuf_test.go | 22 ++- pkg/pki/x509/x509.go | 15 +- pkg/pki/x509/x509_test.go | 60 ++++++-- pkg/types/cose/v0.0.1/entry_test.go | 3 +- 18 files changed, 343 insertions(+), 211 deletions(-) create mode 100644 pkg/pki/identity/identity.go diff --git a/pkg/pki/identity/identity.go b/pkg/pki/identity/identity.go new file mode 100644 index 000000000..0527af7ab --- /dev/null +++ b/pkg/pki/identity/identity.go @@ -0,0 +1,25 @@ +// Copyright 2023 The Sigstore Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package identity + +type Identity struct { + // Types include: *rsa.PublicKey, *ecdsa.PublicKey, ed25519.Publickey, + // *x509.Certificate, openpgp.EntityList, *minisign.PublicKey, ssh.PublicKey + Crypto any + // Based on type of Crypto. Possible values include: PEM-encoded public key, + // PEM-encoded certificate, canonicalized PGP public key, encoded Minisign + // public key, encoded SSH public key + Raw []byte +} diff --git a/pkg/pki/minisign/minisign.go b/pkg/pki/minisign/minisign.go index 0bcb02fa8..94e7161d7 100644 --- a/pkg/pki/minisign/minisign.go +++ b/pkg/pki/minisign/minisign.go @@ -23,6 +23,7 @@ import ( "strings" minisign "github.com/jedisct1/go-minisign" + "github.com/sigstore/rekor/pkg/pki/identity" sigsig "github.com/sigstore/sigstore/pkg/signature" "golang.org/x/crypto/blake2b" ) @@ -184,11 +185,11 @@ func (k PublicKey) Subjects() []string { } // Identities implements the pki.PublicKey interface -func (k PublicKey) Identities() ([]string, error) { +func (k PublicKey) Identities() ([]identity.Identity, error) { // returns base64-encoded key (sig alg, key ID, and public key) key, err := k.CanonicalValue() if err != nil { return nil, err } - return []string{string(key)}, nil + return []identity.Identity{{Crypto: k.key, Raw: key}}, nil } diff --git a/pkg/pki/minisign/minisign_test.go b/pkg/pki/minisign/minisign_test.go index c91db0274..fda36b6f4 100644 --- a/pkg/pki/minisign/minisign_test.go +++ b/pkg/pki/minisign/minisign_test.go @@ -24,6 +24,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" + minisign "github.com/jedisct1/go-minisign" "go.uber.org/goleak" ) @@ -64,6 +65,20 @@ func TestReadPublicKey(t *testing.T) { if !bytes.Equal(rawGot.key.PublicKey[:], rawBytes) { t.Errorf("expected parsed keys to be equal, %v != %v", rawGot.key.PublicKey, rawBytes) } + ids, err := rawGot.Identities() + if err != nil { + t.Fatalf("unexpected error getting identities: %v", err) + } + if _, ok := ids[0].Crypto.(*minisign.PublicKey); !ok { + t.Fatalf("key is of unexpected type, expected *minisign.PublicKey, got %v", reflect.TypeOf(ids[0].Crypto)) + } + val, err := rawGot.CanonicalValue() + if err != nil { + t.Fatalf("error canonicalizing key: %v", err) + } + if !reflect.DeepEqual(val, ids[0].Raw) { + t.Errorf("raw key and canonical value are not equal") + } }) } } @@ -293,10 +308,17 @@ func TestCanonicalValuePublicKey(t *testing.T) { // Identities should be equal to the canonical value for minisign ids, err := outputKey.Identities() if err != nil { - t.Errorf("unexpected error getting identities: %v", err) + t.Fatalf("unexpected error getting identities: %v", err) + } + if _, ok := ids[0].Crypto.(*minisign.PublicKey); !ok { + t.Fatalf("key is of unexpected type, expected *minisign.PublicKey, got %v", reflect.TypeOf(ids[0].Crypto)) + } + val, err := outputKey.CanonicalValue() + if err != nil { + t.Fatalf("error canonicalizing key: %v", err) } - if !reflect.DeepEqual([]string{string(cvOutput)}, ids) { - t.Errorf("identities and canonical value are not equal") + if !reflect.DeepEqual(val, ids[0].Raw) { + t.Errorf("raw key and canonical value are not equal") } } } diff --git a/pkg/pki/pgp/pgp.go b/pkg/pki/pgp/pgp.go index aee7fa14b..bd5608196 100644 --- a/pkg/pki/pgp/pgp.go +++ b/pkg/pki/pgp/pgp.go @@ -31,6 +31,7 @@ import ( "golang.org/x/crypto/openpgp/armor" //nolint:staticcheck "golang.org/x/crypto/openpgp/packet" //nolint:staticcheck + "github.com/sigstore/rekor/pkg/pki/identity" sigsig "github.com/sigstore/sigstore/pkg/signature" ) @@ -305,14 +306,10 @@ func (k PublicKey) Subjects() []string { } // Identities implements the pki.PublicKey interface -func (k PublicKey) Identities() ([]string, error) { - // returns the email addresses and armored public key - var identities []string - identities = append(identities, k.Subjects()...) +func (k PublicKey) Identities() ([]identity.Identity, error) { key, err := k.CanonicalValue() if err != nil { return nil, err } - identities = append(identities, string(key)) - return identities, nil + return []identity.Identity{{Crypto: k.key, Raw: key}}, nil } diff --git a/pkg/pki/pgp/pgp_test.go b/pkg/pki/pgp/pgp_test.go index 20362f7bd..19fe7da11 100644 --- a/pkg/pki/pgp/pgp_test.go +++ b/pkg/pki/pgp/pgp_test.go @@ -27,6 +27,7 @@ import ( "sort" "testing" + "github.com/sigstore/rekor/pkg/pki/identity" "go.uber.org/goleak" ) @@ -387,9 +388,8 @@ func TestEmailAddresses(t *testing.T) { t.Errorf("%v: Error getting subjects from keys length, got %v, expected %v", tc.caseDesc, len(subjects), len(tc.subjects)) } - expectedIDs := tc.subjects - key, _ := inputKey.CanonicalValue() - expectedIDs = append(expectedIDs, string(key)) + keyVal, _ := inputKey.CanonicalValue() + expectedIDs := []identity.Identity{{Crypto: inputKey.key, Raw: keyVal}} ids, err := inputKey.Identities() if err != nil { t.Fatalf("unexpected error getting identities: %v", err) diff --git a/pkg/pki/pkcs7/pkcs7.go b/pkg/pki/pkcs7/pkcs7.go index 8694844da..00a5c1243 100644 --- a/pkg/pki/pkcs7/pkcs7.go +++ b/pkg/pki/pkcs7/pkcs7.go @@ -28,6 +28,7 @@ import ( "strings" "github.com/sassoftware/relic/lib/pkcs7" + "github.com/sigstore/rekor/pkg/pki/identity" "github.com/sigstore/sigstore/pkg/cryptoutils" sigsig "github.com/sigstore/sigstore/pkg/signature" ) @@ -224,24 +225,18 @@ func (k PublicKey) Subjects() []string { } // Identities implements the pki.PublicKey interface -func (k PublicKey) Identities() ([]string, error) { - var identities []string - +func (k PublicKey) Identities() ([]identity.Identity, error) { // pkcs7 structure may contain both a key and certificate chain pemCert, err := cryptoutils.MarshalCertificateToPEM(k.certs[0]) if err != nil { return nil, err } - identities = append(identities, string(pemCert)) pemKey, err := cryptoutils.MarshalPublicKeyToPEM(k.key) if err != nil { return nil, err } - identities = append(identities, string(pemKey)) - - // Subjects come from the certificate Subject and SANs - // SANs could include an email, IP address, DNS name, URI, or any other value in the SAN - identities = append(identities, k.Subjects()...) - - return identities, nil + return []identity.Identity{ + {Crypto: k.certs[0], Raw: pemCert}, + {Crypto: k.key, Raw: pemKey}, + }, nil } diff --git a/pkg/pki/pkcs7/pkcs7_test.go b/pkg/pki/pkcs7/pkcs7_test.go index 333c4654e..0adfe0c76 100644 --- a/pkg/pki/pkcs7/pkcs7_test.go +++ b/pkg/pki/pkcs7/pkcs7_test.go @@ -28,6 +28,7 @@ import ( "testing" "github.com/sassoftware/relic/lib/pkcs7" + "github.com/sigstore/rekor/pkg/pki/identity" "github.com/sigstore/rekor/pkg/pki/x509/testutils" "github.com/sigstore/sigstore/pkg/cryptoutils" ) @@ -470,12 +471,12 @@ A6ydFG8HXGWcnVVIVQ== { name: "email in subject", pkcs7: pkcsPEMEmail, - identities: []string{pkcsEmailCert, pkcsPEMEmailKey, "test@rekor.dev"}, + identities: []string{pkcsEmailCert, pkcsPEMEmailKey}, }, { name: "email and URI in subject alternative name", pkcs7: string(pkcs7bytes), - identities: []string{string(leafCertPEM), string(leafPEM), "subject@example.com", "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v1.1.1"}, + identities: []string{string(leafCertPEM), string(leafPEM)}, }, } @@ -485,23 +486,33 @@ A6ydFG8HXGWcnVVIVQ== if err != nil { t.Fatal(err) } - identities, err := pub.Identities() + ids, err := pub.Identities() if err != nil { t.Fatalf("unexpected error getting identities: %v", err) } + if len(ids) != 2 { + t.Fatalf("expected 2 identities, got %d", len(ids)) + } - if len(identities) == len(tt.identities) { - if len(identities) > 0 { - sort.Strings(identities) - sort.Strings(tt.identities) - if !reflect.DeepEqual(identities, tt.identities) { - t.Errorf("%v: Error getting identities from keys, got %v, expected %v", tt.name, identities, tt.identities) - } - } - } else { - t.Errorf("%v: Error getting identities from keys, got %v, expected %v", tt.name, identities, tt.identities) + // compare certificate + cert, _ := cryptoutils.UnmarshalCertificatesFromPEM([]byte(tt.identities[0])) + expectedID := identity.Identity{Crypto: cert[0], Raw: []byte(tt.identities[0])} + if !ids[0].Crypto.(*x509.Certificate).Equal(expectedID.Crypto.(*x509.Certificate)) { + t.Errorf("certificates did not match") + } + if !reflect.DeepEqual(ids[0].Raw, expectedID.Raw) { + t.Errorf("raw identities did not match, expected %v, got %v", ids[0].Raw, string(expectedID.Raw)) } + // compare public key + key, _ := cryptoutils.UnmarshalPEMToPublicKey([]byte(tt.identities[1])) + expectedID = identity.Identity{Crypto: key, Raw: []byte(tt.identities[1])} + if err := cryptoutils.EqualKeys(expectedID.Crypto, ids[1].Crypto); err != nil { + t.Errorf("%v: public keys did not match: %v", tt.name, err) + } + if !reflect.DeepEqual(ids[1].Raw, expectedID.Raw) { + t.Errorf("%v: raw identities did not match", tt.name) + } }) } } diff --git a/pkg/pki/pki.go b/pkg/pki/pki.go index fc60ac691..19688bd1b 100644 --- a/pkg/pki/pki.go +++ b/pkg/pki/pki.go @@ -18,6 +18,7 @@ package pki import ( "io" + "github.com/sigstore/rekor/pkg/pki/identity" sigsig "github.com/sigstore/sigstore/pkg/signature" ) @@ -28,8 +29,8 @@ type PublicKey interface { // also return Subject URIs present in public keys. EmailAddresses() []string Subjects() []string - // Identities returns PEM-encoded public keys and subjects from either certificate or PGP keys - Identities() ([]string, error) + // Identities returns a list of typed keys and certificates. + Identities() ([]identity.Identity, error) } // Signature Generic object representing a signature (regardless of format & algorithm) diff --git a/pkg/pki/ssh/ssh.go b/pkg/pki/ssh/ssh.go index 30f84ba23..449bda6be 100644 --- a/pkg/pki/ssh/ssh.go +++ b/pkg/pki/ssh/ssh.go @@ -22,6 +22,7 @@ import ( "net/http" "github.com/asaskevich/govalidator" + "github.com/sigstore/rekor/pkg/pki/identity" sigsig "github.com/sigstore/sigstore/pkg/signature" "golang.org/x/crypto/ssh" ) @@ -108,25 +109,20 @@ func (k PublicKey) CanonicalValue() ([]byte, error) { // EmailAddresses implements the pki.PublicKey interface func (k PublicKey) EmailAddresses() []string { + if govalidator.IsEmail(k.comment) { + return []string{k.comment} + } return nil } // Subjects implements the pki.PublicKey interface func (k PublicKey) Subjects() []string { - return nil + return k.EmailAddresses() } // Identities implements the pki.PublicKey interface -func (k PublicKey) Identities() ([]string, error) { - var identities []string - +func (k PublicKey) Identities() ([]identity.Identity, error) { // an authorized key format - authorizedKey := string(bytes.TrimSpace(ssh.MarshalAuthorizedKey(k.key))) - identities = append(identities, authorizedKey) - - if govalidator.IsEmail(k.comment) { - identities = append(identities, k.comment) - } - - return identities, nil + authorizedKey := bytes.TrimSpace(ssh.MarshalAuthorizedKey(k.key)) + return []identity.Identity{{Crypto: k.key, Raw: authorizedKey}}, nil } diff --git a/pkg/pki/ssh/ssh_test.go b/pkg/pki/ssh/ssh_test.go index 104ec8ec2..456378887 100644 --- a/pkg/pki/ssh/ssh_test.go +++ b/pkg/pki/ssh/ssh_test.go @@ -17,32 +17,44 @@ package ssh import ( "math/rand" "reflect" - "sort" "strings" "testing" + + "github.com/sigstore/rekor/pkg/pki/identity" + "golang.org/x/crypto/ssh" ) func TestIdentities(t *testing.T) { // from ssh_e2e_test.go publicKey := "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDXofkiahE7uavjWvxnwkUF27qMgz7pdTwzSv0XzVG6EtirOv3PDWct4YKoXE9c0EqbxnIfYEKwEextdvB7zkgwczdJSHxf/18jQumLn/FuoCmugVSk1H5Qli/qzwBpaTnOk3WuakGuoYUl8ZAokKKgOKLA0aZJ1WRQ2ZCZggA3EkwNZiY17y9Q6HqdgQcH6XN8aAMADNVJdMAJb33hSRJjjsAPTmzBTishP8lYDoGRSsSE7/8XRBCEV5E4I8mI9GElcZwV/1KJx98mpH8QvMzXM1idFcwPRtt1NTAOshwgUU0Fu1x8lU5RQIa6ZKW36qNQLvLxy/BscC7B/mdLptoDs/ot9NimUXZcgCR1a2Q3o7Wi6jIgcgJcyV10Nba81ol4RdN4qPHnVZIzuo+dBkqwG3CMtB4Rj84+Qi+7zyU01hIPreoxQDXaayiGPBUUIiAlW9gsiuRWJzNnu3cvuWDLVfQIkjh7Wug58z+v2NOJ7IMdyERillhzDcvVHaq14+U= test@rekor.dev" + expectedKey, _, _, _, _ := ssh.ParseAuthorizedKey([]byte(publicKey)) pub, err := NewPublicKey(strings.NewReader(publicKey)) if err != nil { t.Fatal(err) } - identities, err := pub.Identities() - if err != nil { - t.Fatalf("unexpected error getting identities: %v", err) + if !reflect.DeepEqual(pub.EmailAddresses(), []string{"test@rekor.dev"}) { + t.Fatalf("expected email address, got %v", pub.EmailAddresses()) + } + if !reflect.DeepEqual(pub.Subjects(), []string{"test@rekor.dev"}) { + t.Fatalf("expected email address as subject, got %v", pub.Subjects()) } - expectedIDs := []string{"test@rekor.dev", - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDXofkiahE7uavjWvxnwkUF27qMgz7pdTwzSv0XzVG6EtirOv3PDWct4YKoXE9c0EqbxnIfYEKwEextdvB7zkgwczdJSHxf/18jQumLn/FuoCmugVSk1H5Qli/qzwBpaTnOk3WuakGuoYUl8ZAokKKgOKLA0aZJ1WRQ2ZCZggA3EkwNZiY17y9Q6HqdgQcH6XN8aAMADNVJdMAJb33hSRJjjsAPTmzBTishP8lYDoGRSsSE7/8XRBCEV5E4I8mI9GElcZwV/1KJx98mpH8QvMzXM1idFcwPRtt1NTAOshwgUU0Fu1x8lU5RQIa6ZKW36qNQLvLxy/BscC7B/mdLptoDs/ot9NimUXZcgCR1a2Q3o7Wi6jIgcgJcyV10Nba81ol4RdN4qPHnVZIzuo+dBkqwG3CMtB4Rj84+Qi+7zyU01hIPreoxQDXaayiGPBUUIiAlW9gsiuRWJzNnu3cvuWDLVfQIkjh7Wug58z+v2NOJ7IMdyERillhzDcvVHaq14+U="} - - sort.Strings(identities) - sort.Strings(expectedIDs) - if !reflect.DeepEqual(identities, expectedIDs) { - t.Errorf("err getting identities from keys, got %v, expected %v", identities, expectedIDs) + keyVal := "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDXofkiahE7uavjWvxnwkUF27qMgz7pdTwzSv0XzVG6EtirOv3PDWct4YKoXE9c0EqbxnIfYEKwEextdvB7zkgwczdJSHxf/18jQumLn/FuoCmugVSk1H5Qli/qzwBpaTnOk3WuakGuoYUl8ZAokKKgOKLA0aZJ1WRQ2ZCZggA3EkwNZiY17y9Q6HqdgQcH6XN8aAMADNVJdMAJb33hSRJjjsAPTmzBTishP8lYDoGRSsSE7/8XRBCEV5E4I8mI9GElcZwV/1KJx98mpH8QvMzXM1idFcwPRtt1NTAOshwgUU0Fu1x8lU5RQIa6ZKW36qNQLvLxy/BscC7B/mdLptoDs/ot9NimUXZcgCR1a2Q3o7Wi6jIgcgJcyV10Nba81ol4RdN4qPHnVZIzuo+dBkqwG3CMtB4Rj84+Qi+7zyU01hIPreoxQDXaayiGPBUUIiAlW9gsiuRWJzNnu3cvuWDLVfQIkjh7Wug58z+v2NOJ7IMdyERillhzDcvVHaq14+U=" + expectedID := identity.Identity{Crypto: expectedKey, Raw: []byte(keyVal)} + ids, err := pub.Identities() + if err != nil { + t.Fatal(err) + } + if len(ids) != 1 { + t.Errorf("too many identities, expected 1, got %v", len(ids)) + } + if !reflect.DeepEqual(ids[0].Crypto.(ssh.PublicKey).Marshal(), expectedID.Crypto.(ssh.PublicKey).Marshal()) { + t.Errorf("certificates did not match") + } + if !reflect.DeepEqual(ids[0].Raw, expectedID.Raw) { + t.Errorf("raw identities did not match, expected %v, got %v", string(ids[0].Raw), string(expectedID.Raw)) } } diff --git a/pkg/pki/tuf/testdata/1.root.json b/pkg/pki/tuf/testdata/1.root.json index d2ddcab9d..7719fb590 100644 --- a/pkg/pki/tuf/testdata/1.root.json +++ b/pkg/pki/tuf/testdata/1.root.json @@ -1,130 +1,156 @@ { - "signatures": [ - { - "keyid": "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97", - "sig": "30450221008a35d51da0f845301a5eac98ad0df00a934f59b709c1eaf81c86be734d9356f80220742942325599749800f52675f6efe124345980a2a636c0dc76f9caf9fc3123b0" - }, - { - "keyid": "bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62", - "sig": "3045022100ef9157ece2a09baec1eab80adfc00b04da20b1f9a0d1b47c5dabc4506719ef2c022074f72acd57398e4ddc8c2a5040df902961e9615dca48f3fbe38cbb506e500066" - }, - { - "keyid": "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b", - "sig": "30450220420fdc9a09cd069b8b15fd8db9cedf7d0dee75871bd1cfee77c926d4120a770002210097553b5ad0d6b4a13902ed37509638bb63a9009f78230cd56c802909ffbfead7" - }, - { - "keyid": "f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb", - "sig": "304502202aaf32e66f90752f658672b085ecfe45cc1ad31ee6cf5c9ad05f3267685f8d88022100b5df02acdaa371123db9d7a42219553fe079b230b168833e951be7ee56ded347" - }, - { - "keyid": "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209", - "sig": "304402205d420c7d05c58980c1c9f7d221f53b5334aae27a447d2a91c2ceddd685269749022039ec83e51f8e1779d7f0142dfa4a5bbecfe327fc0b91b7416090fea2416fd53a" - } - ], "signed": { "_type": "root", - "consistent_snapshot": false, - "expires": "2021-12-18T13:28:12.99008-06:00", + "spec_version": "1.0", + "version": 5, + "expires": "2023-04-18T18:13:43Z", "keys": { - "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97": { + "25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99": { + "keytype": "ecdsa-sha2-nistp256", + "scheme": "ecdsa-sha2-nistp256", "keyid_hash_algorithms": [ "sha256", "sha512" ], - "keytype": "ecdsa-sha2-nistp256", "keyval": { - "public": "04cbc5cab2684160323c25cd06c3307178a6b1d1c9b949328453ae473c5ba7527e35b13f298b41633382241f3fd8526c262d43b45adee5c618fa0642c82b8a9803" - }, - "scheme": "ecdsa-sha2-nistp256" + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEXsz3SZXFb8jMV42j6pJlyjbjR8K\nN3Bwocexq6LMIb5qsWKOQvLN16NUefLc4HswOoumRsVVaajSpQS6fobkRw==\n-----END PUBLIC KEY-----\n" + } }, - "bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62": { + "2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de": { + "keytype": "ecdsa-sha2-nistp256", + "scheme": "ecdsa-sha2-nistp256", "keyid_hash_algorithms": [ "sha256", "sha512" ], - "keytype": "ecdsa-sha2-nistp256", "keyval": { - "public": "04a71aacd835dc170ba6db3fa33a1a33dee751d4f8b0217b805b9bd3242921ee93672fdcfd840576c5bb0dc0ed815edf394c1ee48c2b5e02485e59bfc512f3adc7" - }, - "scheme": "ecdsa-sha2-nistp256" + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0ghrh92Lw1Yr3idGV5WqCtMDB8Cx\n+D8hdC4w2ZLNIplVRoVGLskYa3gheMyOjiJ8kPi15aQ2//7P+oj7UvJPGw==\n-----END PUBLIC KEY-----\n" + } }, - "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b": { + "45b283825eb184cabd582eb17b74fc8ed404f68cf452acabdad2ed6f90ce216b": { + "keytype": "ecdsa-sha2-nistp256", + "scheme": "ecdsa-sha2-nistp256", "keyid_hash_algorithms": [ "sha256", "sha512" ], - "keytype": "ecdsa-sha2-nistp256", "keyval": { - "public": "04117b33dd265715bf23315e368faa499728db8d1f0a377070a1c7b1aba2cc21be6ab1628e42f2cdd7a35479f2dce07b303a8ba646c55569a8d2a504ba7e86e447" - }, - "scheme": "ecdsa-sha2-nistp256" + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELrWvNt94v4R085ELeeCMxHp7PldF\n0/T1GxukUh2ODuggLGJE0pc1e8CSBf6CS91Fwo9FUOuRsjBUld+VqSyCdQ==\n-----END PUBLIC KEY-----\n" + } }, - "f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb": { + "7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b": { + "keytype": "ecdsa-sha2-nistp256", + "scheme": "ecdsa-sha2-nistp256", "keyid_hash_algorithms": [ "sha256", "sha512" ], + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEinikSsAQmYkNeH5eYq/CnIzLaacO\nxlSaawQDOwqKy/tCqxq5xxPSJc21K4WIhs9GyOkKfzueY3GILzcMJZ4cWw==\n-----END PUBLIC KEY-----\n" + } + }, + "e1863ba02070322ebc626dcecf9d881a3a38c35c3b41a83765b6ad6c37eaec2a": { "keytype": "ecdsa-sha2-nistp256", + "scheme": "ecdsa-sha2-nistp256", + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], "keyval": { - "public": "04cc1cd53a61c23e88cc54b488dfae168a257c34fac3e88811c55962b24cffbfecb724447999c54670e365883716302e49da57c79a33cd3e16f81fbc66f0bcdf48" - }, - "scheme": "ecdsa-sha2-nistp256" + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWRiGr5+j+3J5SsH+Ztr5nE2H2wO7\nBV+nO3s93gLca18qTOzHY1oWyAGDykMSsGTUBSt9D+An0KfKsD2mfSM42Q==\n-----END PUBLIC KEY-----\n" + } }, - "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209": { + "f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f": { + "keytype": "ecdsa-sha2-nistp256", + "scheme": "ecdsa-sha2-nistp256", "keyid_hash_algorithms": [ "sha256", "sha512" ], + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzBzVOmHCPojMVLSI364WiiV8NPrD\n6IgRxVliskz/v+y3JER5mcVGcONliDcWMC5J2lfHmjPNPhb4H7xm8LzfSA==\n-----END PUBLIC KEY-----\n" + } + }, + "ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c": { "keytype": "ecdsa-sha2-nistp256", + "scheme": "ecdsa-sha2-nistp256", + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], "keyval": { - "public": "048a78a44ac01099890d787e5e62afc29c8ccb69a70ec6549a6b04033b0a8acbfb42ab1ab9c713d225cdb52b858886cf46c8e90a7f3b9e6371882f370c259e1c5b" - }, - "scheme": "ecdsa-sha2-nistp256" + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEy8XKsmhBYDI8Jc0GwzBxeKax0cm5\nSTKEU65HPFunUn41sT8pi0FjM4IkHz/YUmwmLUO0Wt7lxhj6BkLIK4qYAw==\n-----END PUBLIC KEY-----\n" + } } }, "roles": { "root": { "keyids": [ - "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97", - "bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62", - "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b", - "f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb", - "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209" + "ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c", + "25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99", + "f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f", + "7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b", + "2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de" ], "threshold": 3 }, "snapshot": { "keyids": [ - "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97", - "bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62", - "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b", - "f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb", - "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209" + "45b283825eb184cabd582eb17b74fc8ed404f68cf452acabdad2ed6f90ce216b" ], - "threshold": 3 + "threshold": 1 }, "targets": { "keyids": [ - "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97", - "bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62", - "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b", - "f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb", - "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209" + "ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c", + "25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99", + "f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f", + "7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b", + "2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de" ], "threshold": 3 }, "timestamp": { "keyids": [ - "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97", - "bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62", - "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b", - "f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb", - "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209" + "e1863ba02070322ebc626dcecf9d881a3a38c35c3b41a83765b6ad6c37eaec2a" ], - "threshold": 3 + "threshold": 1 } }, - "spec_version": "1.0", - "version": 1 - } + "consistent_snapshot": true + }, + "signatures": [ + { + "keyid": "ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c", + "sig": "3045022100fc1c2be509ce50ea917bbad1d9efe9d96c8c2ebea04af2717aa3d9c6fe617a75022012eef282a19f2d8bd4818aa333ef48a06489f49d4d34a20b8fe8fc867bb25a7a" + }, + { + "keyid": "25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99", + "sig": "30450221008a4392ae5057fc00778b651e61fea244766a4ae58db84d9f1d3810720ab0f3b702207c49e59e8031318caf02252ecea1281cecc1e5986c309a9cef61f455ecf7165d" + }, + { + "keyid": "7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b", + "sig": "3046022100da1b8dc5d53aaffbbfac98de3e23ee2d2ad3446a7bed09fac0f88bae19be2587022100b681c046afc3919097dfe794e0d819be891e2e850aade315bec06b0c4dea221b" + }, + { + "keyid": "2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de", + "sig": "3046022100b534e0030e1b271133ecfbdf3ba9fbf3becb3689abea079a2150afbb63cdb7c70221008c39a718fd9495f249b4ab8788d5b9dc269f0868dbe38b272f48207359d3ded9" + }, + { + "keyid": "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97", + "sig": "3045022100fc1c2be509ce50ea917bbad1d9efe9d96c8c2ebea04af2717aa3d9c6fe617a75022012eef282a19f2d8bd4818aa333ef48a06489f49d4d34a20b8fe8fc867bb25a7a" + }, + { + "keyid": "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b", + "sig": "30450221008a4392ae5057fc00778b651e61fea244766a4ae58db84d9f1d3810720ab0f3b702207c49e59e8031318caf02252ecea1281cecc1e5986c309a9cef61f455ecf7165d" + }, + { + "keyid": "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209", + "sig": "3046022100da1b8dc5d53aaffbbfac98de3e23ee2d2ad3446a7bed09fac0f88bae19be2587022100b681c046afc3919097dfe794e0d819be891e2e850aade315bec06b0c4dea221b" + }, + { + "keyid": "75e867ab10e121fdef32094af634707f43ddd79c6bab8ad6c5ab9f03f4ea8c90", + "sig": "3046022100b534e0030e1b271133ecfbdf3ba9fbf3becb3689abea079a2150afbb63cdb7c70221008c39a718fd9495f249b4ab8788d5b9dc269f0868dbe38b272f48207359d3ded9" + } + ] } diff --git a/pkg/pki/tuf/testdata/reformat.1.root.json b/pkg/pki/tuf/testdata/reformat.1.root.json index e482e1157..4737c4f10 100644 --- a/pkg/pki/tuf/testdata/reformat.1.root.json +++ b/pkg/pki/tuf/testdata/reformat.1.root.json @@ -1 +1 @@ -{"signatures":[{"keyid":"2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97","sig":"30450221008a35d51da0f845301a5eac98ad0df00a934f59b709c1eaf81c86be734d9356f80220742942325599749800f52675f6efe124345980a2a636c0dc76f9caf9fc3123b0"},{"keyid":"bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62","sig":"3045022100ef9157ece2a09baec1eab80adfc00b04da20b1f9a0d1b47c5dabc4506719ef2c022074f72acd57398e4ddc8c2a5040df902961e9615dca48f3fbe38cbb506e500066"},{"keyid":"eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b","sig":"30450220420fdc9a09cd069b8b15fd8db9cedf7d0dee75871bd1cfee77c926d4120a770002210097553b5ad0d6b4a13902ed37509638bb63a9009f78230cd56c802909ffbfead7"},{"keyid":"f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb","sig":"304502202aaf32e66f90752f658672b085ecfe45cc1ad31ee6cf5c9ad05f3267685f8d88022100b5df02acdaa371123db9d7a42219553fe079b230b168833e951be7ee56ded347"},{"keyid":"f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209","sig":"304402205d420c7d05c58980c1c9f7d221f53b5334aae27a447d2a91c2ceddd685269749022039ec83e51f8e1779d7f0142dfa4a5bbecfe327fc0b91b7416090fea2416fd53a"}],"signed":{"_type":"root","consistent_snapshot":false,"expires":"2021-12-18T13:28:12.99008-06:00","keys":{"2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97":{"keyid_hash_algorithms":["sha256","sha512"],"keytype":"ecdsa-sha2-nistp256","keyval":{"public":"04cbc5cab2684160323c25cd06c3307178a6b1d1c9b949328453ae473c5ba7527e35b13f298b41633382241f3fd8526c262d43b45adee5c618fa0642c82b8a9803"},"scheme":"ecdsa-sha2-nistp256"},"bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62":{"keyid_hash_algorithms":["sha256","sha512"],"keytype":"ecdsa-sha2-nistp256","keyval":{"public":"04a71aacd835dc170ba6db3fa33a1a33dee751d4f8b0217b805b9bd3242921ee93672fdcfd840576c5bb0dc0ed815edf394c1ee48c2b5e02485e59bfc512f3adc7"},"scheme":"ecdsa-sha2-nistp256"},"eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b":{"keyid_hash_algorithms":["sha256","sha512"],"keytype":"ecdsa-sha2-nistp256","keyval":{"public":"04117b33dd265715bf23315e368faa499728db8d1f0a377070a1c7b1aba2cc21be6ab1628e42f2cdd7a35479f2dce07b303a8ba646c55569a8d2a504ba7e86e447"},"scheme":"ecdsa-sha2-nistp256"},"f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb":{"keyid_hash_algorithms":["sha256","sha512"],"keytype":"ecdsa-sha2-nistp256","keyval":{"public":"04cc1cd53a61c23e88cc54b488dfae168a257c34fac3e88811c55962b24cffbfecb724447999c54670e365883716302e49da57c79a33cd3e16f81fbc66f0bcdf48"},"scheme":"ecdsa-sha2-nistp256"},"f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209":{"keyid_hash_algorithms":["sha256","sha512"],"keytype":"ecdsa-sha2-nistp256","keyval":{"public":"048a78a44ac01099890d787e5e62afc29c8ccb69a70ec6549a6b04033b0a8acbfb42ab1ab9c713d225cdb52b858886cf46c8e90a7f3b9e6371882f370c259e1c5b"},"scheme":"ecdsa-sha2-nistp256"}},"roles":{"root":{"keyids":["2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97","bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62","eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b","f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb","f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209"],"threshold":3},"snapshot":{"keyids":["2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97","bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62","eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b","f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb","f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209"],"threshold":3},"targets":{"keyids":["2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97","bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62","eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b","f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb","f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209"],"threshold":3},"timestamp":{"keyids":["2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97","bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62","eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b","f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb","f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209"],"threshold":3}},"spec_version":"1.0","version":1}} \ No newline at end of file +{"signed":{"_type":"root","spec_version":"1.0","version":5,"expires":"2023-04-18T18:13:43Z","keys":{"25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEXsz3SZXFb8jMV42j6pJlyjbjR8K\nN3Bwocexq6LMIb5qsWKOQvLN16NUefLc4HswOoumRsVVaajSpQS6fobkRw==\n-----END PUBLIC KEY-----\n"}},"2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0ghrh92Lw1Yr3idGV5WqCtMDB8Cx\n+D8hdC4w2ZLNIplVRoVGLskYa3gheMyOjiJ8kPi15aQ2//7P+oj7UvJPGw==\n-----END PUBLIC KEY-----\n"}},"45b283825eb184cabd582eb17b74fc8ed404f68cf452acabdad2ed6f90ce216b":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELrWvNt94v4R085ELeeCMxHp7PldF\n0/T1GxukUh2ODuggLGJE0pc1e8CSBf6CS91Fwo9FUOuRsjBUld+VqSyCdQ==\n-----END PUBLIC KEY-----\n"}},"7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEinikSsAQmYkNeH5eYq/CnIzLaacO\nxlSaawQDOwqKy/tCqxq5xxPSJc21K4WIhs9GyOkKfzueY3GILzcMJZ4cWw==\n-----END PUBLIC KEY-----\n"}},"e1863ba02070322ebc626dcecf9d881a3a38c35c3b41a83765b6ad6c37eaec2a":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWRiGr5+j+3J5SsH+Ztr5nE2H2wO7\nBV+nO3s93gLca18qTOzHY1oWyAGDykMSsGTUBSt9D+An0KfKsD2mfSM42Q==\n-----END PUBLIC KEY-----\n"}},"f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzBzVOmHCPojMVLSI364WiiV8NPrD\n6IgRxVliskz/v+y3JER5mcVGcONliDcWMC5J2lfHmjPNPhb4H7xm8LzfSA==\n-----END PUBLIC KEY-----\n"}},"ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEy8XKsmhBYDI8Jc0GwzBxeKax0cm5\nSTKEU65HPFunUn41sT8pi0FjM4IkHz/YUmwmLUO0Wt7lxhj6BkLIK4qYAw==\n-----END PUBLIC KEY-----\n"}}},"roles":{"root":{"keyids":["ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c","25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99","f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f","7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b","2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de"],"threshold":3},"snapshot":{"keyids":["45b283825eb184cabd582eb17b74fc8ed404f68cf452acabdad2ed6f90ce216b"],"threshold":1},"targets":{"keyids":["ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c","25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99","f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f","7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b","2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de"],"threshold":3},"timestamp":{"keyids":["e1863ba02070322ebc626dcecf9d881a3a38c35c3b41a83765b6ad6c37eaec2a"],"threshold":1}},"consistent_snapshot":true},"signatures":[{"keyid":"ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c","sig":"3045022100fc1c2be509ce50ea917bbad1d9efe9d96c8c2ebea04af2717aa3d9c6fe617a75022012eef282a19f2d8bd4818aa333ef48a06489f49d4d34a20b8fe8fc867bb25a7a"},{"keyid":"25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99","sig":"30450221008a4392ae5057fc00778b651e61fea244766a4ae58db84d9f1d3810720ab0f3b702207c49e59e8031318caf02252ecea1281cecc1e5986c309a9cef61f455ecf7165d"},{"keyid":"7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b","sig":"3046022100da1b8dc5d53aaffbbfac98de3e23ee2d2ad3446a7bed09fac0f88bae19be2587022100b681c046afc3919097dfe794e0d819be891e2e850aade315bec06b0c4dea221b"},{"keyid":"2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de","sig":"3046022100b534e0030e1b271133ecfbdf3ba9fbf3becb3689abea079a2150afbb63cdb7c70221008c39a718fd9495f249b4ab8788d5b9dc269f0868dbe38b272f48207359d3ded9"},{"keyid":"2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97","sig":"3045022100fc1c2be509ce50ea917bbad1d9efe9d96c8c2ebea04af2717aa3d9c6fe617a75022012eef282a19f2d8bd4818aa333ef48a06489f49d4d34a20b8fe8fc867bb25a7a"},{"keyid":"eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b","sig":"30450221008a4392ae5057fc00778b651e61fea244766a4ae58db84d9f1d3810720ab0f3b702207c49e59e8031318caf02252ecea1281cecc1e5986c309a9cef61f455ecf7165d"},{"keyid":"f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209","sig":"3046022100da1b8dc5d53aaffbbfac98de3e23ee2d2ad3446a7bed09fac0f88bae19be2587022100b681c046afc3919097dfe794e0d819be891e2e850aade315bec06b0c4dea221b"},{"keyid":"75e867ab10e121fdef32094af634707f43ddd79c6bab8ad6c5ab9f03f4ea8c90","sig":"3046022100b534e0030e1b271133ecfbdf3ba9fbf3becb3689abea079a2150afbb63cdb7c70221008c39a718fd9495f249b4ab8788d5b9dc269f0868dbe38b272f48207359d3ded9"}]} \ No newline at end of file diff --git a/pkg/pki/tuf/testdata/timestamp.json b/pkg/pki/tuf/testdata/timestamp.json index 5bea8900a..3ff09fe94 100644 --- a/pkg/pki/tuf/testdata/timestamp.json +++ b/pkg/pki/tuf/testdata/timestamp.json @@ -1,39 +1,24 @@ { - "signatures": [ - { - "keyid": "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97", - "sig": "3044022079252576532ed5ed4a19e4135997d89172101ed745a4489be6b20d04d483bbcc0220515119aab690033dc1e1650f08995dc839dcd161cab3898db0749063ca32dc86" - }, - { - "keyid": "bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62", - "sig": "3045022100c5216dd17d381c951b5174f8ee2157b315d1f26247e7f9e49c42cf975dfcf49b022048fb1751a86fddedc21129e94a3e7e0efeeb93f1238fad6636bbf0c0d39543e8" - }, - { - "keyid": "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b", - "sig": "3045022042c6b4003deee27db7db6f5aebb29ac89625fd7389dfff434fa93c65cf8aed5f022100fe6cbd036b5fce1169d7392ecfaf76e01f05fdc6c81cf9bae8c9227fc09c65d9" - }, - { - "keyid": "f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb", - "sig": "3045022100bc431b7315c2aa657418835005692021de7496bbc7c1a2fedf2aafe8d861ca5402200cbca80a4555d8236265e1b746743532894b46257c450ff8706d0e50e659978c" - }, - { - "keyid": "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209", - "sig": "3046022100c09aea2f05e94a656bd70379340c7b5f09b24bbd20adf4855be3783d7ce39482022100da93a8a1577599979d38bfc44016bde5838d9548797fc9e960780276855bbcf9" - } - ], "signed": { "_type": "timestamp", - "expires": "2021-12-18T13:28:12.99008-06:00", + "spec_version": "1.0", + "version": 53, + "expires": "2022-11-03T21:10:23Z", "meta": { "snapshot.json": { + "length": 1973, "hashes": { - "sha512": "9103503c18f7da2098dce04892948ad240c1b9965048c4ab4da0c32248f3491652d91d76fe9022be2cf15a99e68b3a3ddd1034e5293c8aac86d0446c4354716d" + "sha256": "d1eea940c4e3fff8a3ae5932a38ca35fdd789e1a85d4919f3316efd879c0e0ed", + "sha512": "d0848c412728e5db9ad0713d3d1c319f7cc2bde67082da95f79f740ef26e1fee91a32b1eb948b47bb2c06b71557f60e61605e512e40dd4b25c907ac3f4ca6e91" }, - "length": 1849, - "version": 1 + "version": 53 } - }, - "spec_version": "1.0", - "version": 1 - } + } + }, + "signatures": [ + { + "keyid": "e1863ba02070322ebc626dcecf9d881a3a38c35c3b41a83765b6ad6c37eaec2a", + "sig": "304502202bb5ce4034ea4be68a9a6c9af77b48911294f1492d7add5a763a5a77bc863f27022100d4ab20ffa8790e6a28e7f1e66495e1fc5242bed0f5222312e76ec60235270df2" + } + ] } diff --git a/pkg/pki/tuf/tuf.go b/pkg/pki/tuf/tuf.go index 7da68e2e4..7c61e776f 100644 --- a/pkg/pki/tuf/tuf.go +++ b/pkg/pki/tuf/tuf.go @@ -16,14 +16,18 @@ package tuf import ( + "crypto/x509" "encoding/json" "fmt" "io" "time" "github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer" + "github.com/sigstore/rekor/pkg/pki/identity" + "github.com/sigstore/sigstore/pkg/cryptoutils" sigsig "github.com/sigstore/sigstore/pkg/signature" "github.com/theupdateframework/go-tuf/data" + "github.com/theupdateframework/go-tuf/pkg/keys" "github.com/theupdateframework/go-tuf/verify" ) @@ -168,14 +172,51 @@ func (k PublicKey) Subjects() []string { } // Identities implements the pki.PublicKey interface -func (k PublicKey) Identities() ([]string, error) { +func (k PublicKey) Identities() ([]identity.Identity, error) { root := &data.Root{} if err := json.Unmarshal(k.root.Signed, root); err != nil { return nil, err } - identity, err := json.Marshal(root.Keys) - if err != nil { - return nil, err + var ids []identity.Identity + for _, k := range root.Keys { + verifier, err := keys.GetVerifier(k) + if err != nil { + return nil, err + } + switch k.Type { + // RSA and ECDSA keys are PKIX-encoded without PEM header for the Verifier type + case data.KeyTypeRSASSA_PSS_SHA256: + fallthrough + // TODO: Update to constants once go-tuf is updated to 0.6.0 (need PR #508) + case "ecdsa-sha2-nistp256": + fallthrough + case "ecdsa": + pub, err := x509.ParsePKIXPublicKey([]byte(verifier.Public())) + if err != nil { + return nil, err + } + pemKey, err := cryptoutils.MarshalPublicKeyToPEM(pub) + if err != nil { + return nil, err + } + ids = append(ids, identity.Identity{ + Crypto: pub, + Raw: pemKey, + }) + case data.KeyTypeEd25519: + // key is stored as a 32-byte string + pub := []byte(verifier.Public()) + pemKey, err := cryptoutils.MarshalPublicKeyToPEM(pub) + if err != nil { + return nil, err + } + ids = append(ids, identity.Identity{ + Crypto: pub, + Raw: pemKey, + }) + default: + return nil, fmt.Errorf("unsupported key type: %v", k.Type) + } } - return []string{string(identity)}, nil + return ids, nil } diff --git a/pkg/pki/tuf/tuf_test.go b/pkg/pki/tuf/tuf_test.go index b87f181bc..d7d318cba 100644 --- a/pkg/pki/tuf/tuf_test.go +++ b/pkg/pki/tuf/tuf_test.go @@ -17,13 +17,13 @@ package tuf import ( "bytes" - "encoding/json" + "crypto/ecdsa" "io" "os" + "reflect" "testing" "time" - "github.com/theupdateframework/go-tuf/data" _ "github.com/theupdateframework/go-tuf/pkg/deprecated/set_ecdsa" "github.com/theupdateframework/go-tuf/verify" ) @@ -81,15 +81,13 @@ func TestReadPublicKey(t *testing.T) { if err != nil { t.Errorf("%v: error getting identities for %v: %v", tc.caseDesc, tc.inputFile, err) } - if len(identities) != 1 { - t.Errorf("%v: expected 1 identity, got: %d", tc.caseDesc, len(identities)) + if len(identities) != 7 { + t.Errorf("%v: expected 7 identities, got: %d", tc.caseDesc, len(identities)) } - var keys map[string]*data.PublicKey - if err := json.Unmarshal([]byte(identities[0]), &keys); err != nil { - t.Fatal(err) - } - if len(keys) != 5 { - t.Errorf("%v: expected 5 keys, got %d", tc.caseDesc, len(keys)) + for _, i := range identities { + if _, ok := i.Crypto.(*ecdsa.PublicKey); !ok { + t.Errorf("%v: key was not of type *ecdsa.PublicKey: %v", tc.caseDesc, reflect.TypeOf(i.Crypto)) + } } } } @@ -168,12 +166,12 @@ func TestCanonicalValue(t *testing.T) { outputKey, err := NewPublicKey(outputFile) if err != nil { - t.Errorf("%v: Error reading input for TestCanonicalValue: %v", tc.caseDesc, err) + t.Fatalf("%v: Error reading input for TestCanonicalValue: %v", tc.caseDesc, err) } cvOutput, err := outputKey.CanonicalValue() if err != nil { - t.Errorf("%v: Error canonicalizing public key '%v': %v", tc.caseDesc, tc.input, err) + t.Fatalf("%v: Error canonicalizing public key '%v': %v", tc.caseDesc, tc.input, err) } if bytes.Equal(cvInput, cvOutput) != tc.match { diff --git a/pkg/pki/x509/x509.go b/pkg/pki/x509/x509.go index 9624981a1..f66633591 100644 --- a/pkg/pki/x509/x509.go +++ b/pkg/pki/x509/x509.go @@ -27,6 +27,7 @@ import ( "strings" validator "github.com/go-playground/validator/v10" + "github.com/sigstore/rekor/pkg/pki/identity" "github.com/sigstore/sigstore/pkg/cryptoutils" sigsig "github.com/sigstore/sigstore/pkg/signature" ) @@ -222,14 +223,14 @@ func (k PublicKey) Subjects() []string { } // Identities implements the pki.PublicKey interface -func (k PublicKey) Identities() ([]string, error) { +func (k PublicKey) Identities() ([]identity.Identity, error) { // k contains either a key, a cert, or a list of certs if k.key != nil { pem, err := cryptoutils.MarshalPublicKeyToPEM(k.key) if err != nil { return nil, err } - return []string{string(pem)}, nil + return []identity.Identity{{Crypto: k.key, Raw: pem}}, nil } var cert *x509.Certificate @@ -242,19 +243,11 @@ func (k PublicKey) Identities() ([]string, error) { return nil, errors.New("no key, certificate or certificate chain provided") } - var identities []string pemCert, err := cryptoutils.MarshalCertificateToPEM(cert) if err != nil { return nil, err } - identities = append(identities, string(pemCert)) - pemKey, err := cryptoutils.MarshalPublicKeyToPEM(cert.PublicKey) - if err != nil { - return nil, err - } - identities = append(identities, string(pemKey)) - identities = append(identities, cryptoutils.GetSubjectAlternateNames(cert)...) - return identities, nil + return []identity.Identity{{Crypto: cert, Raw: pemCert}}, nil } func verifyCertChain(certChain []*x509.Certificate) error { diff --git a/pkg/pki/x509/x509_test.go b/pkg/pki/x509/x509_test.go index 525099257..2c5c78495 100644 --- a/pkg/pki/x509/x509_test.go +++ b/pkg/pki/x509/x509_test.go @@ -19,13 +19,15 @@ import ( "bytes" "crypto" "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" "crypto/x509" "net/url" "reflect" - "sort" "strings" "testing" + "github.com/sigstore/rekor/pkg/pki/identity" "github.com/sigstore/rekor/pkg/pki/x509/testutils" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" @@ -163,6 +165,38 @@ func TestSignature_Verify(t *testing.T) { if err := canonicalSig.Verify(bytes.NewReader(data), pub); err != nil { t.Errorf("Signature.Verify() error = %v", err) } + + pubKey, _ := cryptoutils.UnmarshalPEMToPublicKey([]byte(tt.pub)) + expectedID := identity.Identity{Crypto: pubKey, Raw: []byte(tt.pub)} + ids, err := pub.Identities() + if err != nil { + t.Fatal(err) + } + if len(ids) != 1 { + t.Errorf("%v: too many identities, expected 1, got %v", tt.name, len(ids)) + } + switch v := ids[0].Crypto.(type) { + case *rsa.PublicKey: + if tt.name != "rsa" { + t.Fatalf("unexpected key, expected RSA, got %v", reflect.TypeOf(v)) + } + case *ecdsa.PublicKey: + if tt.name != "ec" { + t.Fatalf("unexpected key, expected RSA, got %v", reflect.TypeOf(v)) + } + case ed25519.PublicKey: + if tt.name != "ed25519" { + t.Fatalf("unexpected key, expected RSA, got %v", reflect.TypeOf(v)) + } + default: + t.Fatalf("unexpected key type, got %v", reflect.TypeOf(v)) + } + if err := cryptoutils.EqualKeys(expectedID.Crypto, ids[0].Crypto); err != nil { + t.Errorf("%v: public keys did not match: %v", tt.name, err) + } + if !reflect.DeepEqual(ids[0].Raw, expectedID.Raw) { + t.Errorf("%v: raw identities did not match, expected %v, got %v", tt.name, tt.pub, string(expectedID.Raw)) + } }) } } @@ -208,15 +242,6 @@ func TestSignature_VerifyFail(t *testing.T) { if err := s.Verify(bytes.NewReader(data), pub); err == nil { t.Error("Signature.Verify() expected error!") } - - expectedIDs := []string{tt.pub} - ids, err := pub.Identities() - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(expectedIDs, ids) { - t.Errorf("%v: identities did not match, expected %v, got %v", tt.name, expectedIDs, ids) - } }) } } @@ -226,7 +251,6 @@ func TestPublicKeyWithCertChain(t *testing.T) { subCert, subKey, _ := testutils.GenerateSubordinateCa(rootCert, rootKey) url, _ := url.Parse("https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v1.1.1") leafCert, leafKey, _ := testutils.GenerateLeafCert("subject@example.com", "oidc-issuer", url, subCert, subKey) - leafPEM, _ := cryptoutils.MarshalPublicKeyToPEM(leafKey.Public()) leafCertPEM, _ := cryptoutils.MarshalCertificateToPEM(leafCert) pemCertChain, err := cryptoutils.MarshalCertificatesToPEM([]*x509.Certificate{leafCert, subCert, rootCert}) @@ -256,15 +280,19 @@ func TestPublicKeyWithCertChain(t *testing.T) { t.Fatalf("expected matching subjects, expected %v, got %v", expectedSubjects, pub.Subjects()) } - expectedIDs := []string{string(leafCertPEM), string(leafPEM), "subject@example.com", url.String()} + expectedID := identity.Identity{Crypto: leafCert, Raw: leafCertPEM} ids, err := pub.Identities() if err != nil { t.Fatal(err) } - sort.Strings(ids) - sort.Strings(expectedIDs) - if !reflect.DeepEqual(expectedIDs, ids) { - t.Fatalf("identities do not match, expected %v, got %v", []string{}, ids) + if len(ids) != 1 { + t.Errorf("too many identities, expected 1, got %v", len(ids)) + } + if !ids[0].Crypto.(*x509.Certificate).Equal(expectedID.Crypto.(*x509.Certificate)) { + t.Errorf("certificates did not match") + } + if !reflect.DeepEqual(ids[0].Raw, expectedID.Raw) { + t.Errorf("raw identities did not match, expected %v, got %v", ids[0].Raw, string(expectedID.Raw)) } canonicalValue, err := pub.CanonicalValue() diff --git a/pkg/types/cose/v0.0.1/entry_test.go b/pkg/types/cose/v0.0.1/entry_test.go index 0aed90df9..f6b7a4107 100644 --- a/pkg/types/cose/v0.0.1/entry_test.go +++ b/pkg/types/cose/v0.0.1/entry_test.go @@ -34,6 +34,7 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/pki/identity" sigx509 "github.com/sigstore/rekor/pkg/pki/x509" "github.com/sigstore/rekor/pkg/types" "github.com/spf13/viper" @@ -90,7 +91,7 @@ func (t testPublicKey) Subjects() []string { return nil } -func (t testPublicKey) Identities() ([]string, error) { +func (t testPublicKey) Identities() ([]identity.Identity, error) { return nil, nil }