From 754d33eb577e35ffc704115e8e188facee49e4ab Mon Sep 17 00:00:00 2001 From: Hayden B Date: Tue, 11 Jan 2022 20:41:11 -0800 Subject: [PATCH] Add support for importing PKCS#8 private keys, and add validation (#1300) This adds support for PKCS#8 encoded private keys, which means we can also import ED25519 keys. I've added tests for PKCS#8 RSA and ECDSA keys too. I also added some validation of keys before importing. For RSA, we will require that the key size be between 2048 and 4096. For ECDSA keys, we will only disallow NIST P-224, since Cosign generates P-256 by default. Other curves are not supported by Go's crypto library. Signed-off-by: Hayden Blauzvern --- pkg/cosign/keys.go | 86 +++++++++++++-- pkg/cosign/keys_test.go | 224 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 288 insertions(+), 22 deletions(-) diff --git a/pkg/cosign/keys.go b/pkg/cosign/keys.go index a4ad1903b6f..f8ba05ce9bc 100644 --- a/pkg/cosign/keys.go +++ b/pkg/cosign/keys.go @@ -18,6 +18,7 @@ package cosign import ( "crypto" "crypto/ecdsa" + "crypto/ed25519" "crypto/elliptic" "crypto/rand" "crypto/rsa" @@ -37,10 +38,14 @@ import ( ) const ( - PrivateKeyPemType = "ENCRYPTED COSIGN PRIVATE KEY" + CosignPrivateKeyPemType = "ENCRYPTED COSIGN PRIVATE KEY" + // PEM-encoded PKCS #1 RSA private key RSAPrivateKeyPemType = "RSA PRIVATE KEY" - ECPrivateKeyPemType = "EC PRIVATE KEY" - BundleKey = static.BundleAnnotationKey + // PEM-encoded ECDSA private key + ECPrivateKeyPemType = "EC PRIVATE KEY" + // PEM-encoded PKCS #8 RSA, ECDSA or ED25519 private key + PrivateKeyPemType = "PRIVATE KEY" + BundleKey = static.BundleAnnotationKey ) type PassFunc func(bool) ([]byte, error) @@ -56,6 +61,35 @@ type KeysBytes struct { password []byte } +// Enforce a minimum and maximum RSA key size. +func validateRsaKey(pk *rsa.PrivateKey) error { + // Key size is the bit length of modulus + keySize := pk.N.BitLen() + if keySize < 2048 { + return fmt.Errorf("rsa key size too small, expected >= 2048") + } + if keySize > 4096 { + return fmt.Errorf("rsa key size too large, expected <= 4096") + } + return nil +} + +// Enforce that the ECDSA key curve is one of: +// * NIST P-256 (secp256r1, prime256v1) +// * NIST P-384 +// * NIST P-521. +// Other EC curves, like secp256k1, are not supported by Go. +func validateEcdsaKey(pk *ecdsa.PrivateKey) error { + switch pk.Curve { + case elliptic.P224(): + return fmt.Errorf("unsupported ec curve, expected NIST P-256, P-384, or P-521") + case elliptic.P256(), elliptic.P384(), elliptic.P521(): + return nil + default: + return fmt.Errorf("unexpected ec curve") + } +} + func GeneratePrivateKey() (*ecdsa.PrivateKey, error) { return ecdsa.GenerateKey(elliptic.P256(), rand.Reader) } @@ -75,15 +109,47 @@ func ImportKeyPair(keyPath string, pf PassFunc) (*KeysBytes, error) { switch p.Type { case RSAPrivateKeyPemType: - pk, err = x509.ParsePKCS1PrivateKey(p.Bytes) + rsaPk, err := x509.ParsePKCS1PrivateKey(p.Bytes) if err != nil { - return nil, fmt.Errorf("parsing error") + return nil, fmt.Errorf("error parsing rsa private key") } - default: - pk, err = x509.ParseECPrivateKey(p.Bytes) + if err = validateRsaKey(rsaPk); err != nil { + return nil, errors.Wrap(err, "error validating rsa key") + } + pk = rsaPk + case ECPrivateKeyPemType: + ecdsaPk, err := x509.ParseECPrivateKey(p.Bytes) if err != nil { - return nil, fmt.Errorf("parsing error") + return nil, fmt.Errorf("error parsing ecdsa private key") } + if err = validateEcdsaKey(ecdsaPk); err != nil { + return nil, errors.Wrap(err, "error validating ecdsa key") + } + pk = ecdsaPk + case PrivateKeyPemType: + pkcs8Pk, err := x509.ParsePKCS8PrivateKey(p.Bytes) + if err != nil { + return nil, fmt.Errorf("error parsing pkcs #8 private key") + } + switch k := pkcs8Pk.(type) { + case *rsa.PrivateKey: + if err = validateRsaKey(k); err != nil { + return nil, errors.Wrap(err, "error validating rsa key") + } + pk = k + case *ecdsa.PrivateKey: + if err = validateEcdsaKey(k); err != nil { + return nil, errors.Wrap(err, "error validating ecdsa key") + } + pk = k + case ed25519.PrivateKey: + // Nothing to validate, since ED25519 supports only one key size. + pk = k + default: + return nil, fmt.Errorf("unexpected private key") + } + default: + return nil, fmt.Errorf("unsupported private key") } return marshalKeyPair(Keys{pk, pk.Public()}, pf) } @@ -107,7 +173,7 @@ func marshalKeyPair(keypair Keys, pf PassFunc) (*KeysBytes, error) { // store in PEM format privBytes := pem.EncodeToMemory(&pem.Block{ Bytes: encBytes, - Type: PrivateKeyPemType, + Type: CosignPrivateKeyPemType, }) // Now do the public key @@ -154,7 +220,7 @@ func LoadPrivateKey(key []byte, pass []byte) (signature.SignerVerifier, error) { if p == nil { return nil, errors.New("invalid pem block") } - if p.Type != PrivateKeyPemType { + if p.Type != CosignPrivateKeyPemType { return nil, fmt.Errorf("unsupported pem type: %s", p.Type) } diff --git a/pkg/cosign/keys_test.go b/pkg/cosign/keys_test.go index 9c7bc136411..95eafea4831 100644 --- a/pkg/cosign/keys_test.go +++ b/pkg/cosign/keys_test.go @@ -53,7 +53,37 @@ pGAaLxggvtvuncMuTrG+cdmsR9SafSFKRS92NCxhOUonQ+NP6mLskIGzJZoQ5JvQ qGzRVIDGbNkrVHM0IsAtHRpC0rYrtZY+9OwiraGcsqUMLwwQdCA= -----END RSA PRIVATE KEY-----` -const invalidrsa = `-----BEGIN PUBLIC KEY----- +// RSA 2048 key encoded with PKCS#8 +const validrsapkcs8 = `-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCwDtRl4McMhk4Q +UD723TzrAlYt59w73Qy6SZJLdaRKLjl0T8NY4NqnscIl/ZFTPh7SwqIF7D33riYB +sp60j6cV7ADh3fiIFtl6hYMAEpgqboJgTSlyeVX2jeyZCg25stv9AtvcT1B5ZVqa ++CY4feeUzp4LbVb4vY0nk1NHP95AJkJdcQaod44NXkc7AVb8h/atWx53AujXQsJY +0t84Z1+WCUhA+2D1ECdGJlkinwy/cBjABKtMe+4jN4z9vRXnIqHn8gpTsoBqSWRP +Ua2aNQzho/JnbDSWDu8Jzs+75llwzGxKFEIsAVpB5v63ir5lVejgf2Bs2JSCfn0W +BSqdxaLXAgMBAAECggEAUwEK3mVVMvB3CXXr2ZOAzwOxAb+Ys5iKEaHyGSWDqX2V +lOKuJM8OB5XlBOhBhc951L/yh3xT0twGCzLdZB9+FPXJjLOMIw0yx3L+yh/6Ibcs +PJ7kdZYDE1TiQVzeD7jlwqmAYqP6OuGwD/QCgQvLDPtEw/pu0KL9U7U/xA22iOM4 +MpbCZgQUBYvIikUgUBnhxtq9CXf9+NZOKGrLUV7zNn2Abqyw5047hDpBRejfiOIw +a6oO3UykJyEKv4P6DmCSIZyBUbgeo+jvJ/4FsGYvCSqIYCdtvOaHqHI5w5cwgUy5 +hwLuqXNG4X/sqqmvqICVB2efK+vrGmGiUFizkWDjsQKBgQDi4mbKNsa1sDMS/F4W +fx0kNlriPGAlS5+I1RgGXOh3sQ3D2hi2hDKym3KlPVXMmDBH+FqHt83uPXXSEpTo +d6jCyprw0kBgmfZCnWrWEMY1KGHPsPDO+Vx7nsrpgPA9EpftXibgTu1wQqNR+NOE +RwweniZhqOjGkjMZagMvS701UwKBgQDGpq3c9SRPJT6TD77akfrWs2nKjXsD9xzP +1mjXVN+ft6Om5olSANrH8nRsbND4BfYMfDbm/LscjM/qZ8ueC/KRZZEBoB9qy7R9 +76JbqvCctFLorTy6RNIYno0JS5tivU93SOKDv1V/eXuZb3BVyixyhIaCjjjjnE7u +AP195YIH7QKBgElHVGm1XWKrQSO9rOnZLmFWyO3PEEKbdTBtmu/bLB4Ualy6YUb5 +1aIIQPQLpl2JPfbQyPSSsgljgl1SMRQQKcqYQ4jKb46Dy5ziWPJAwrPCkizRekVv +Fqa6t9DJG06uZbF9ulKyS0/5xeQg2LgddlWhQMZEFsKjz6tCqTqqXLcPAoGBAIBY +FCCb6XeREpqlI6PHiQ7KH+GUAxSOxXiqiFYHKevhE8SzUak/kBp61SlwLJryDwQG +BNq8Eo/hkjtaED3ubivuOP+Z2nJ/Zf+voXAkQwybnK1jr8aQzETHu0t0I9JpiTwC +RQblyXFwpaB+VU+4LXtXkCgthyfXR0+SKDT84UQJAoGAPxwl93a6voIoTmuT1WJn +RdInSOS8J/13xjhlTHwpWBbUVVZDZyM+vGit0e3cTBSoDnF4/axKVF9veN3GF0RY +doAvTv0rhEQ8VmRQY9cZsaPMVg0q9UcSLLel9lJRRcEXa7v2aUpTNXVtar9csphX +5ybCksQRTS2adHuIdOa111g= +-----END PRIVATE KEY-----` + +const invalidrsawithpubkey = `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx5piWVlE62NnZ0UzJ8Z6 oKiKOC4dbOZ1HsNhIRtqkM+Oq4G+25yq6P+0JU/Qvr9veOGEb3R/J9u8JBo+hv2i 5X8OtgvP2V2pi6f1s6vK7L0+6uRb4YTT/UdMshaVf97MgEqbq41Jf/cuvh+3AV0t @@ -63,6 +93,88 @@ ddS0yb19ShSuW3PPRadruBM1mq15js9GfagPxDS75Imcs+fA62lWvHxEujTGjYHx awIDAQAB -----END PUBLIC KEY-----` +// RSA key with size 1024 +const invalidrsasmallkey = `-----BEGIN RSA PRIVATE KEY----- +MIICWwIBAAKBgQCYm7UwrM1fEsB+pOagKMRy1G9sX3A9MbC+a/G/jI+AERiNhCxa +dQUnicqs1ct78mTSH15+MJa39tYhwwh2yePUMAzP4yeiFluCAjxl8MQOqg2Q0i2+ +juF72HekB1RoXj5To7j9iYL71F3+A7C+ewvMRDQZ6wsJladiM3xbx3swhwIDAQAB +AoGAKstvUgkDRmfxxxHjAoKsJC9iV5ej1+U5VQzcLAT0sMsagYTRE0TBf0bqqPED +MOzWTP4y91wUx93WSn1wwC75TjaRQ8YS9u8lFN/7ANo7zEucCSMlomEJgdvURmpS +JwsEyx03W+VCPTIz1WNFG04ICnLQvimOihU6nanDE8t4UoECQQDKFpLsipARIgVs +Zr+V7CgN33O7sduaZvakq9ymgHqd5L1B+USglCVXBCYUPTombT9Li8ecDZk69e6I +aWm1Pb9hAkEAwVHyTzI3Lu4LCx/T6mTOaJR1ads6XlFqTKUNBLd+PeL89cJhnigO +Ad0faD4hW61IF0lHjPemLo3c6nGeNPOA5wJAIHLNdpOtHEMlMcmxu4XmzItzjtC5 +HSqpMbmyvT1l8tJWnTBEF7CR6k3tO1S1cJQcFKpGC8WXNANnIJokcgiPIQJAJBNs +yoaucZ2OhgbsfwNM2YtK1fRJUiyTT7ZFVaoAbwAbAKnDmcYTxxlCsStXAkq191J/ +fbkBVBK5NS76vRrr5QJAGdcfJrnB9UIJQrTrXZWYSGCqkKSHhSrI4bLxrG2I+KlR +yAA/xDHlrlrCK260XFCi47rpAowtLwB1JbUwGr6x0Q== +-----END RSA PRIVATE KEY-----` + +// RSA key with size 5120 +const invalidrsalargekey = `-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY-----` + const invalidkey = `-----BEGIN PGP PRIVATE KEY BLOCK----- Version: BCPG C# v1.6.1.0 @@ -95,12 +207,52 @@ hfOiWo/4tMCN8XJpe0L+99ubcnHjQR7C8htFB4DnIA8KhMBSDdF/Vgp97g== =8+cN -----END PGP PRIVATE KEY BLOCK-----` -const validec = `-----BEGIN EC PRIVATE KEY----- +// Valid NIST P-256 key +const validecp256 = `-----BEGIN EC PRIVATE KEY----- MHcCAQEEIIGhcmCI5F7BPMH4r3pWCpQdAsveErdU5DjvVQerErJuoAoGCCqGSM49 AwEHoUQDQgAE+9E3Qe+h25ofmz3Uo2T004Dfy49iX06MMbxf9rsGmLkOPrS0KYDl 1QMfFuSbrtf8wTWNT9HNxrW/Foz39mDhHw== -----END EC PRIVATE KEY-----` +// Valid NIST P-384 key +const validecp384 = `-----BEGIN EC PRIVATE KEY----- +MIGkAgEBBDDWIebxSdyJVber6J/l5MKnD0+VU0b7fcjY/RbIxuIsHLVIvwJrSohY +r3gJ/iJmIKGgBwYFK4EEACKhZANiAAQeoKZkkc1GafmIgp1tbNbMBjr2EdvX2dtT +lGhzHJgE0YB6TavazcYH1iOBNmX7/pInCopiyWbjF/5olrRKJMG6DQz80td++fYf +O4tr+Z3nyUgRGmf/fqYA4PSN30CuOMU= +-----END EC PRIVATE KEY-----` + +// Valid NIST P-521 key +const validecp521 = `-----BEGIN EC PRIVATE KEY----- +MIHcAgEBBEIA3JhHw1bhJyNnK80SPnvuIY9h++IaEhZcHR7SDHzMnFf72O5fF/RI +c+Dbd9lTfrP3Oy9BOC1opvXHvr5tqzV0MregBwYFK4EEACOhgYkDgYYABAALA20e +WqTf2chokKaCmxfnhs1lW70/J8slBzKBG6x3OjJX+yrpkDqe8zpkN08E+RZA8RSE +9TqbcXVHGtR6tj0IMgEFmybW+efJr4nz/iBvchGeIg1HtOX5V97z0bmwsCgQCD8L +4cNcYkeNJazrzzXte5Y5DK4Vm8QE4Jkux6FCw19QhQ== +-----END EC PRIVATE KEY-----` + +// Valid NIST P-256 key encoded with PKCS#8 +const validecpkcs8 = `-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgmKnLL81dCEYc6Spq +rFukFeTnU5JjtXfeNHAXJj3hYTahRANCAATjp4/Z4tUbZwUdId07GQeUdwLll4Br +YLP25Fk+mBY2G0lyKqjqLG5hxhimbEJH6j+lzg5tcYpQgzXtOJ66Zi0N +-----END PRIVATE KEY-----` + +// We consider NIST P-224 below our standard. +const invalidecp224 = `-----BEGIN EC PRIVATE KEY----- +MGgCAQEEHNpr8qVw+OcDrk/2aSqCGkWFKIjJSH0smeuloomgBwYFK4EEACGhPAM6 +AARL+L9osuD8BYNr/aCkJiDHfDhxosXNOkcml4XPsnN88EjUqI2J7lMqmea5guwr +eu5jUfVoZzti6A== +-----END EC PRIVATE KEY-----` + +// Go crypto library does not support non-NIST curves. +const invalidecunsupported = `-----BEGIN EC PRIVATE KEY----- +MHQCAQEEIJ6iubjORxWrzL3Z0i30s80TuLD+N6YTYVk49nzl+O1eoAcGBSuBBAAK +oUQDQgAEBadoFlV8pUuQ+WvRapCRJRGYk34h2nYkXW0BPdaCiPiEHawiVq9XXwG9 +BuLB48bb77i0pTkVEefOuiNrbdBibw== +-----END EC PRIVATE KEY-----` + +// PKCS#8 ED25519 key const ed25519key = `-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEIALEbo1EFnWFqBK/wC+hhypG/8hXEerwdNetAoFoFVdv -----END PRIVATE KEY-----` @@ -144,30 +296,74 @@ func TestImportPrivateKey(t *testing.T) { pemData string expected error }{ + // RSA tests { fileName: "validrsa.key", pemData: validrsa, expected: nil, }, { - fileName: "invalidrsa.key", - pemData: invalidrsa, - expected: errors.New("parsing error"), + fileName: "validrsapkcs8.key", + pemData: validrsapkcs8, + expected: nil, }, { - fileName: "invalidkey.key", - pemData: invalidkey, - expected: errors.New("invalid pem block"), + fileName: "invalidrsawithpubkey.key", + pemData: invalidrsawithpubkey, + expected: errors.New("unsupported private key"), + }, + { + fileName: "invalidrsasmallkey.key", + pemData: invalidrsasmallkey, + expected: errors.New("error validating rsa key: rsa key size too small, expected >= 2048"), }, { - fileName: "validec.key", - pemData: validec, + fileName: "invalidrsalargekey.key", + pemData: invalidrsalargekey, + expected: errors.New("error validating rsa key: rsa key size too large, expected <= 4096"), + }, + // EC tests + { + fileName: "validecp256.key", + pemData: validecp256, + expected: nil, + }, + { + fileName: "validecp384.key", + pemData: validecp384, + expected: nil, + }, + { + fileName: "validecp521.key", + pemData: validecp521, + expected: nil, + }, + { + fileName: "validecpkcs8.key", + pemData: validecpkcs8, expected: nil, }, + { + fileName: "invalidecp224.key", + pemData: invalidecp224, + expected: errors.New("error validating ecdsa key: unsupported ec curve, expected NIST P-256, P-384, or P-521"), + }, + { + fileName: "invalidecunsupported.key", + pemData: invalidecunsupported, + expected: errors.New("error parsing ecdsa private key"), + }, + // ED25519 tests { fileName: "ed25519.key", pemData: ed25519key, - expected: errors.New("parsing error"), + expected: nil, + }, + // Additional tests + { + fileName: "invalidkey.key", + pemData: invalidkey, + expected: errors.New("invalid pem block"), }, } td := t.TempDir() @@ -180,7 +376,11 @@ func TestImportPrivateKey(t *testing.T) { t.Fatal(err) } _, err = ImportKeyPair(f, pass("hello")) - require.Equal(t, tc.expected, err) + if err == nil || tc.expected == nil { + require.Equal(t, tc.expected, err) + } else { + require.Equal(t, tc.expected.Error(), err.Error()) + } }) } }