github.com/in-toto/in-toto-golang@v0.9.1-0.20240517212500-990269f763cf/in_toto/keylib_test.go (about) 1 package in_toto 2 3 import ( 4 "crypto/x509" 5 "errors" 6 "os" 7 "testing" 8 9 "github.com/stretchr/testify/assert" 10 ) 11 12 // TestLoadKey makes sure, that our LoadKey function loads keys correctly 13 // and that the key IDs of private and public key match. 14 func TestLoadKey(t *testing.T) { 15 validTables := []struct { 16 name string 17 path string 18 scheme string 19 hashAlgorithms []string 20 expectedKeyID string 21 }{ 22 {"rsa public key", "alice.pub", "rsassa-pss-sha256", []string{"sha256", "sha512"}, "70ca5750c2eda80b18f41f4ec5f92146789b5d68dd09577be422a0159bd13680"}, 23 {"rsa private key", "dan", "rsassa-pss-sha256", []string{"sha256", "sha512"}, "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401"}, 24 {"rsa public key", "dan.pub", "rsassa-pss-sha256", []string{"sha256", "sha512"}, "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401"}, 25 {"ed25519 private key", "carol", "ed25519", []string{"sha256", "sha512"}, "be6371bc627318218191ce0780fd3183cce6c36da02938a477d2e4dfae1804a6"}, 26 {"ed25519 public key", "carol.pub", "ed25519", []string{"sha256", "sha512"}, "be6371bc627318218191ce0780fd3183cce6c36da02938a477d2e4dfae1804a6"}, 27 {"ecdsa private key (P521)", "frank", "ecdsa-sha2-nistp521", []string{"sha256", "sha512"}, "434cf7c5b168f6ea4c7e6e67afa74a02625310530f1664f761637bdc7ad8f8df"}, 28 {"ecdsa public key (P521)", "frank.pub", "ecdsa-sha2-nistp521", []string{"sha256", "sha512"}, "434cf7c5b168f6ea4c7e6e67afa74a02625310530f1664f761637bdc7ad8f8df"}, 29 {"ecdsa private key (P384)", "grace", "ecdsa-sha2-nistp384", []string{"sha256", "sha512"}, "a5522ebccd492f64e6ec0bbcb5eb782708f6e26709a3712e64fff108b98e5142"}, 30 {"ecdsa public key (P384)", "grace.pub", "ecdsa-sha2-nistp384", []string{"sha256", "sha512"}, "a5522ebccd492f64e6ec0bbcb5eb782708f6e26709a3712e64fff108b98e5142"}, 31 {"ecdsa private key (P224)", "heidi", "ecdsa-sha2-nistp224", []string{"sha256", "sha512"}, "fae849ef9247cc7d19ebd33ab63b5d18a31357508fd82d8ad2aad6fdcc584bd7"}, 32 {"ecdsa public key (P224)", "heidi.pub", "ecdsa-sha2-nistp224", []string{"sha256", "sha512"}, "fae849ef9247cc7d19ebd33ab63b5d18a31357508fd82d8ad2aad6fdcc584bd7"}, 33 {"rsa public key from certificate", "example.com.write-code.cert.pem", "rsassa-pss-sha256", []string{"sha256", "sha512"}, "4979dea7a8467cbe0299693703b81d490854143b859a469ec0f6349e7bdf582a"}, 34 } 35 for _, table := range validTables { 36 var key Key 37 err := key.LoadKey(table.path, table.scheme, table.hashAlgorithms) 38 if err != nil { 39 t.Errorf("failed key.LoadKey() for %s %s. Error: %s", table.name, table.path, err) 40 } 41 if table.expectedKeyID != key.KeyID { 42 t.Errorf("keyID for %s %s does not match expected keyID: %s. Got keyID: %s", table.name, table.path, table.expectedKeyID, key.KeyID) 43 } 44 } 45 } 46 47 // TestLoadKeyDefaults makes sure our function loads keys correctly 48 // with the expected default schemes 49 func TestLoadKeyDefaults(t *testing.T) { 50 validTables := []struct { 51 name string 52 path string 53 expectedKeyID string 54 expectedScheme string 55 }{ 56 {"rsa public key", "alice.pub", "70ca5750c2eda80b18f41f4ec5f92146789b5d68dd09577be422a0159bd13680", rsassapsssha256Scheme}, 57 {"rsa private key", "dan", "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401", rsassapsssha256Scheme}, 58 {"rsa public key", "dan.pub", "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401", rsassapsssha256Scheme}, 59 {"ed25519 private key", "carol", "be6371bc627318218191ce0780fd3183cce6c36da02938a477d2e4dfae1804a6", ed25519Scheme}, 60 {"ed25519 public key", "carol.pub", "be6371bc627318218191ce0780fd3183cce6c36da02938a477d2e4dfae1804a6", ed25519Scheme}, 61 {"ecdsa private key (P521)", "frank", "0ab02fd8a1195d902d4e71df38123be0d3fa9ea45ebc6e1246d8e82179acb6dd", ecdsaSha2nistp256}, 62 {"ecdsa public key (P521)", "frank.pub", "0ab02fd8a1195d902d4e71df38123be0d3fa9ea45ebc6e1246d8e82179acb6dd", ecdsaSha2nistp256}, 63 {"ecdsa private key (P384)", "grace", "a5fe82bffd11c43cd25b41b427496dea8eb61505bfa11907a6a565ebb00fa323", ecdsaSha2nistp256}, 64 {"ecdsa public key (P384)", "grace.pub", "a5fe82bffd11c43cd25b41b427496dea8eb61505bfa11907a6a565ebb00fa323", ecdsaSha2nistp256}, 65 {"ecdsa private key (P224)", "heidi", "337f2a2bed46e863a68f17ae0e3e96756eca87c38080d872c5824493cec1ce1a", ecdsaSha2nistp256}, 66 {"ecdsa public key (P224)", "heidi.pub", "337f2a2bed46e863a68f17ae0e3e96756eca87c38080d872c5824493cec1ce1a", ecdsaSha2nistp256}, 67 {"rsa public key from certificate", "example.com.write-code.cert.pem", "4979dea7a8467cbe0299693703b81d490854143b859a469ec0f6349e7bdf582a", rsassapsssha256Scheme}, 68 } 69 for _, table := range validTables { 70 var key Key 71 err := key.LoadKeyDefaults(table.path) 72 if err != nil { 73 t.Errorf("failed key.LoadKeyDefaults() for %s %s. Error: %s", table.name, table.path, err) 74 } 75 if table.expectedKeyID != key.KeyID { 76 t.Errorf("keyID for %s %s does not match expected keyID: %s. Got keyID: %s", table.name, table.path, table.expectedKeyID, key.KeyID) 77 } 78 if table.expectedScheme != key.Scheme { 79 t.Errorf("scheme for %s %s does not match expected scheme: %s. Got scheme %s", table.name, table.path, table.expectedScheme, key.Scheme) 80 } 81 } 82 } 83 84 // TestLoadKeyReader makes sure, that our LoadKeyReader function loads keys correctly 85 // and that the key IDs of private and public key match. 86 func TestLoadKeyReader(t *testing.T) { 87 var key Key 88 if err := key.LoadKeyReader(nil, "ed25519", []string{"sha256", "sha512"}); err != ErrNoPEMBlock { 89 t.Errorf("unexpected error loading key: %s", err) 90 } 91 } 92 93 // TestLoadKeyErrors tests the LoadKey functions for the most popular errors: 94 // 95 // - os.ErrNotExist (triggered, when the file does not exist) 96 // - ErrNoPEMBlock (for example if the passed file is not a PEM block) 97 // - ErrFailedPEMParsing (for example if we pass an EC key, instead a key in PKCS8 format) 98 func TestLoadKeyErrors(t *testing.T) { 99 invalidTables := []struct { 100 name string 101 path string 102 scheme string 103 hashAlgorithms []string 104 err error 105 }{ 106 {"not existing file", "inToToRocks", "rsassa-pss-sha256", []string{"sha256", "sha512"}, os.ErrNotExist}, 107 {"existing, but invalid file", "demo.layout", "ecdsa-sha2-nistp521", []string{"sha512"}, ErrNoPEMBlock}, 108 {"EC private key file", "erin", "ecdsa-sha2-nistp521", []string{"sha256", "sha512"}, ErrFailedPEMParsing}, 109 {"valid ed25519 private key, but invalid scheme", "carol", "", []string{"sha256"}, ErrEmptyKeyField}, 110 {"valid ed25519 public key, but invalid scheme", "carol.pub", "", []string{"sha256"}, ErrEmptyKeyField}, 111 {"valid rsa private key, but invalid scheme", "dan", "rsassa-psa-sha256", nil, ErrSchemeKeyTypeMismatch}, 112 {"valid rsa public key, but invalid scheme", "dan.pub", "rsassa-psa-sha256", nil, ErrSchemeKeyTypeMismatch}, 113 {"valid ecdsa private key, but invalid scheme", "frank", "ecdsa-sha-nistp256", nil, ErrSchemeKeyTypeMismatch}, 114 {"valid ecdsa public key, but invalid scheme", "frank.pub", "ecdsa-sha-nistp256", nil, ErrSchemeKeyTypeMismatch}, 115 } 116 117 for _, table := range invalidTables { 118 var key Key 119 err := key.LoadKey(table.path, table.scheme, table.hashAlgorithms) 120 if !errors.Is(err, table.err) { 121 t.Errorf("failed LoadKey() for %s %s, got error: %s. Should have: %s", table.name, table.path, err, table.err) 122 } 123 } 124 } 125 126 // TestLoadKeyDefaultsErrors tests the LoadKeyDefaults functions for the most popular errors: 127 // 128 // - os.ErrNotExist (triggered, when the file does not exist) 129 // - ErrNoPEMBlock (for example if the passed file is not a PEM block) 130 // - ErrFailedPEMParsing (for example if we pass an EC key, instead a key in PKCS8 format) 131 func TestLoadKeyDefaultsErrors(t *testing.T) { 132 invalidTables := []struct { 133 name string 134 path string 135 err error 136 }{ 137 {"not existing file", "inToToRocks", os.ErrNotExist}, 138 {"existing, but invalid file", "demo.layout", ErrNoPEMBlock}, 139 {"EC private key file", "erin", ErrFailedPEMParsing}, 140 } 141 142 for _, table := range invalidTables { 143 var key Key 144 err := key.LoadKeyDefaults(table.path) 145 if !errors.Is(err, table.err) { 146 t.Errorf("failed LoadKeyDefaults() for %s %s, got error: %s. Should have: %s", table.name, table.path, err, table.err) 147 } 148 } 149 } 150 151 func TestSetKeyComponentsErrors(t *testing.T) { 152 invalidTables := []struct { 153 name string 154 pubkeyBytes []byte 155 privateKeyBytes []byte 156 keyType string 157 scheme string 158 KeyIDHashAlgorithms []string 159 err error 160 }{ 161 {"test invalid key type", []byte{}, []byte{}, "yolo", "ed25519", []string{"sha512"}, ErrUnsupportedKeyType}, 162 {"invalid scheme", []byte("393e671b200f964c49083d34a867f5d989ec1c69df7b66758fe471c8591b139c"), []byte{}, "ed25519", "", []string{"sha256"}, ErrEmptyKeyField}, 163 } 164 165 for _, table := range invalidTables { 166 var key Key 167 err := key.setKeyComponents(table.pubkeyBytes, table.privateKeyBytes, table.keyType, table.scheme, table.KeyIDHashAlgorithms) 168 if !errors.Is(err, table.err) { 169 t.Errorf("'%s' failed, should have: '%s', got: '%s'", table.name, ErrUnsupportedKeyType, err) 170 } 171 } 172 } 173 174 func TestVerifyCertificateTrust(t *testing.T) { 175 var rootKey, intermediateKey, leafKey Key 176 err := rootKey.LoadKeyDefaults("root.cert.pem") 177 assert.Nil(t, err, "unexpected error loading root") 178 err = intermediateKey.LoadKeyDefaults("example.com.intermediate.cert.pem") 179 assert.Nil(t, err, "unexpected error loading intermediate") 180 err = leafKey.LoadKeyDefaults("example.com.write-code.cert.pem") 181 assert.Nil(t, err, "unexpected error loading leaf") 182 183 rootPool := x509.NewCertPool() 184 ok := rootPool.AppendCertsFromPEM([]byte(rootKey.KeyVal.Certificate)) 185 assert.True(t, ok, "unexpected error adding cert to root pool") 186 intermediatePool := x509.NewCertPool() 187 ok = intermediatePool.AppendCertsFromPEM([]byte(intermediateKey.KeyVal.Certificate)) 188 assert.True(t, ok, "unexpected error adding cert to root pool") 189 190 _, possibleLeafCert, err := decodeAndParse([]byte(leafKey.KeyVal.Certificate)) 191 assert.Nil(t, err, "unexpected error parsing leaf certificate") 192 leafCert, ok := possibleLeafCert.(*x509.Certificate) 193 assert.True(t, ok, "parseKey didn't return a x509 certificate") 194 195 // Test the happy path 196 _, err = VerifyCertificateTrust(leafCert, rootPool, intermediatePool) 197 assert.Nil(t, err, "unexpected error verifying trust") 198 199 // Test with no intermediate connecting the leaf to the root 200 _, err = VerifyCertificateTrust(leafCert, rootPool, x509.NewCertPool()) 201 assert.NotNil(t, err, "expected error with missing intermediate") 202 203 // Test with no root 204 _, err = VerifyCertificateTrust(leafCert, x509.NewCertPool(), intermediatePool) 205 assert.NotNil(t, err, "expected error with missing root") 206 }