blob: de52bab7f3e82b2ea5b54ff32cfff7f9a180f2a8 [file] [log] [blame]
// Copyright Istio 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 util
import (
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"reflect"
"strings"
"testing"
)
const (
csr = `
-----BEGIN CERTIFICATE REQUEST-----
MIIBoTCCAQoCAQAwEzERMA8GA1UEChMISnVqdSBvcmcwgZ8wDQYJKoZIhvcNAQEB
BQADgY0AMIGJAoGBANFf06eqiDx0+qD/xBAR5aMwwgaBOn6TPfSy96vOxLTsfkTg
ir/vb8UG+F5hO6yxF+z2BgzD8LwcbKnxahoPq/aWGLw3Umcqm4wxgWKHxvtYSQDG
w4zpmKOqgkagxbx32JXDlMpi6adUVHNvB838CiUys6IkVB0obGHnre8zmCLdAgMB
AAGgTjBMBgkqhkiG9w0BCQ4xPzA9MDsGA1UdEQQ0MDKGMHNwaWZmZTovL3Rlc3Qu
Y29tL25hbWVzcGFjZS9ucy9zZXJ2aWNlYWNjb3VudC9zYTANBgkqhkiG9w0BAQsF
AAOBgQCw9dL6xRQSjdYKt7exqlTJliuNEhw/xDVGlNUbDZnT0uL3zXI//Z8tsejn
8IFzrDtm0Z2j4BmBzNMvYBKL/4JPZ8DFywOyQqTYnGtHIkt41CNjGfqJRk8pIqVC
hKldzzeCKNgztEvsUKVqltFZ3ZYnkj/8/Cg8zUtTkOhHOjvuig==
-----END CERTIFICATE REQUEST-----`
keyRSA = `
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAw/OBAAhDu58f0HkJlJBtb42Jp9EECC+WYEOVEdM/Y9fqcoSF
b19NxztVqy0r/aW8pCO3DZ2EYIA3Y9pYasDfhsIl9lhQkvEwk/05iL6oNrZ45Bgs
iSK+R5OlO9pXtj6HF948qFTDYbYVqki3rAWSSYeGpQ+/s/xcIIIKH5ozKs7DTqR8
svQ6t7Hxg0vYSUCHfJo25yIvoo8XGZxrFWOZDXfHHC22q8kuuxT82bdQo7KzYhgn
uujyzIZYqgG9BuUmB6UYdvuDRRDz4HDfERSFFxZbTAaMPNgCRvQnkPS0DJO0XZW2
T9m3bQvaqTgFI/capuhhgRcP0UrStJKZO7LVHQIDAQABAoIBAFLw0v2Mgf78j57S
XLfBmlDJfCbIVgiQ+/mrIYH2BLLiRZ5LcZ9+m5FlEBHwgNpQONTROT5OGiYun0No
vFwTX4nOy/rFzvUjmghJ+vxilxjxi6IgiVlSl2/8ksgO12mQdeYob0xg9IJ7bBgz
x2rMwOrWrqtXSzGH9AbehCJ0RowrUUjTujnow8WrDVS0cjPIl9c1eQDIDlHCUskC
iGMYYfJtB1nkdw1Kkp1YVmCYqwzVENi6+Hx66j/oOtGteTelwFmclc7JIK7liKEZ
xnDbgVTkIp9nSszpHStWikwh/srCWI7trC/k0viViZQLOd/64CyJ/sf8uZDzsG7f
hoiK3pECgYEAxF/d7QcDWaXCBkw4yC8ozqp6KTcA8thVuBK0Adtpzuf9t8h+B7V2
wlkSEs4A3YiUnxolEh1XOT+0u3uGfawlhFgXxEEHeBq+Lz6PIbWuVSl4PiWo8vtj
9MoBYRPtJelhHkBfjunqqaFwdRQQvXjmCsQfx4UAhBxdXvc2kTR/y08CgYEA/3K8
DKXldQliScqkG+Acj6nNgugecLYjCHgmAglHX6jwDuTVqNF3cv3DF5bZ4/nIbDsk
WooVhS4AEFYWceqmTveGsJNuDMoRSWNwDFRBu5Iq6LxneKiXp9vuZ4U4xZNejrgx
la7w1hQs92qCloY4Jxw9Ls3zKub4vC26CfJwzdMCgYBGw0T1ZNGQPGruWgkcGeJa
lpPuxiNRXyOEcTjscmRuaqrCzzybCokA/5fDrvgg3Fax/nndTTVhK9O0u457Os1K
I3RtBAHtBbYC0EhDnXR0u7zYqDl5VZ1vWFum38dVIgQdIpVMqn4lIkej6Ncfb7F1
r7bD7umAsbfzwKGpMYHbgQKBgQDL03vzR6hIc71mjffWekOv6lieXKJ1Yw+fIWeK
dmbqEH3EFJnbg5AhRBSYTPj9bICcw7AlQksbonHQlzB/ozEij2V8nZbRQ6b5fQuZ
+t0cUuxEGpkhcLzZ5qZbGbUMCaQIkzaVbiqjVyPuI6Ghg+VoZ6L2JsUh9XyBgqcQ
as/RmwKBgGPB8PHYHyz0km8LxM/GPstcoO4Ls5coS3MX2EBDKGqWOIOtLKz0azc7
R4beF5BJE6ulhLig4fkOWH4CIvw2Y1/22GJE/fYjUTRMD57ZdYuKqSyMNxwqiolw
xGSDfnFvR13RCqeUdlQofVYpolqrSobOyOVfQv2ksnPPsC87NISM
-----END RSA PRIVATE KEY-----`
keyInvalidRSA = `
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----`
keyECDSA = `
-----BEGIN EC PRIVATE KEY-----
MGgCAQEEHBMUyVWFKTW4TwtwCmIAxdpsBFn0MV7tGeSA32CgBwYFK4EEACGhPAM6
AATCkAx7whb2k3xWm+UjlFWFiV11oYmIdYgXqiAQkiz7fEq6QFhsjjCizeGzAlhT
TmngRSxv/dSvGA==
-----END EC PRIVATE KEY-----`
keyInvalidECDSA = `
-----BEGIN EC PRIVATE KEY-----
-----END EC PRIVATE KEY-----`
keyPKCS8RSA = `
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC5iMw+Cvt0ZAnj
l5piKgyoFIlCAD2FeKd0CQaUA9sHk7XuWAXUAHWQrNXRIG/d9uZBedOwFQ/D8GCR
m5uQTTZC/4cww6pXvrVvX3DYe7H3hF8g3cDsHoYuR51LHzFR1lAe/y0XFaRw18Vm
WNFLnUozEeq1nT0CAyw0iXGa22ptZA3M1G9JJjDrENT6adI/N/19XH9fMiQOOOrT
zerC9DRVouXgxDsXUz2H25XT3YWu7nVs/ic57BRc3JU4JfYbVR8Br2+lAgPFvLFs
/HfX2BuvHC64sseIOVfXL7a/EaOVQhD9NKL7K+5faX21JAfN40f+qwfNLJrrUjHu
7UMpZbJVAgMBAAECggEBAJQ6RarfzUuMzRXGvjHlFF2IoqxXUs96uJYMy/OfLPNd
wIEeU/GvOD4Qx3afqqA0LHttIIHSIdlSB2TtZBiih1J5ogGEoWge1geXwalDEckF
OZchc4txS5RX5MPqtNWEGljZV6XUxZ7d1DjThssZa/lnPBRC/kXIUR3cHSYyXFHt
vA4vY4tVmH1TDUY51A64qKO5dg/Jupn1AHVnoU8eGGD31pISmlZdy64rBMdx9Ac5
u30rGP4RWR9YCSZRFtoxL2d0VoEdKAx1qN0/rPYPNUK1EIFO8kW4voNlUfyGDTLX
TdYBX5Stmm3ws6MAoJJKdpBLWmiJgqOjaiYlf/7y+zUCgYEA5mogVNiba2KRP85O
QOH2ugY1dPiiJLm6QTub7Aygy8lc6WQGa2TXBUpqGYp4rs0wjBnkhtIoErZM8cxu
ENj8dGBikfEJq95NcOMx6wsQYKRWX9JwDzNrLyUCtKK+B3kO8daHzHWTPB7mNkHF
Y91PZLmzSCdAsqxI5VHo0mzStMsCgYEAziLizDE4Q+IpNvzpGo+TxOJILTYdf1HC
OdoaWMKU1Hl6TyWGXon0/ZfAI+jxjT9sI4/Slr5ED86FT0iaIOcSgvl8PmbcvMrM
m3Nj/ZVM3EPzo8EW/LNFlZreheIuvuSwUvnzlWaWZdWJ5/z0M7Is05NsF2v5QlON
OVd/b3pVcV8CgYEAhIDTRvepqP9t9/t0FOvdLu0TIMk6tVP5QDo/WGeKsKaDv9O9
vVSoMmqwyS9QZ3WoTWk2ejGwydH8PbEKOrYNt/8VsEelACk+74Q32KrsKCdZZJFn
z9YJ9XqbK7XLAhEj/v8X6QRUP2aljN4V3XAPkCUabIvmMNnSsc2AzkG2ijECgYB6
BtTTo9928A8N6jHj81K6nmmzufFESZX8wUwPd0C7dx4cdE5S8MACzy6DE4bK4tyV
QLKdYgzQfqUUBhqXl7KxrhcKqcHKURNGgsySdSuGyQMV0VxWQ5nRslhAUWDyyFZJ
CIZVzuEBb6OvnWLCp5s5tG+sfdKUnPlhFJbv2y9xaQKBgCp1g3NtljkH1Olk+kFF
LwxpTxIxS/8jZIM6MpfcmLPyZVRrpUORgkphXvLVXub+anNqGbK0Cbc30KQGnFKD
PFsekZAmhgetPqL16MQSEZbXRSnGiklqQtew79S/yQDwZVCer8n1ABp5eZ2wsLgu
92ik2sTgTEhef6AgLeHcT5ne
-----END PRIVATE KEY-----`
keyInvalidPKCS8 = `
-----BEGIN PRIVATE KEY-----
-----END PRIVATE KEY-----`
certRSA = `
-----BEGIN CERTIFICATE-----
MIIC+zCCAeOgAwIBAgIQQ0vFSayWg4FQBBr1EpI5rzANBgkqhkiG9w0BAQsFADAT
MREwDwYDVQQKEwhKdWp1IG9yZzAeFw0xNzAzMTEwNjA0MDJaFw0xODAzMTEwNjA0
MDJaMBMxETAPBgNVBAoTCEp1anUgb3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAw/OBAAhDu58f0HkJlJBtb42Jp9EECC+WYEOVEdM/Y9fqcoSFb19N
xztVqy0r/aW8pCO3DZ2EYIA3Y9pYasDfhsIl9lhQkvEwk/05iL6oNrZ45BgsiSK+
R5OlO9pXtj6HF948qFTDYbYVqki3rAWSSYeGpQ+/s/xcIIIKH5ozKs7DTqR8svQ6
t7Hxg0vYSUCHfJo25yIvoo8XGZxrFWOZDXfHHC22q8kuuxT82bdQo7KzYhgnuujy
zIZYqgG9BuUmB6UYdvuDRRDz4HDfERSFFxZbTAaMPNgCRvQnkPS0DJO0XZW2T9m3
bQvaqTgFI/capuhhgRcP0UrStJKZO7LVHQIDAQABo0swSTAOBgNVHQ8BAf8EBAMC
BaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAUBgNVHREEDTAL
gglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAITDuqOhN1jwiA72qSWzOwuy
bMHPkUTUw2JfICtPS0AlfNNVJXREUi4KoX81ju126PGQeOTApWvS5Kkd6PbNqVH9
g3myAKrkyjewTfFtK5OOOQGzQT6lCEhKdZJusdqfAMl1heFJGnZ6GAi38ftdz2Z8
0LPyyIaVBvexNnTPrqoBqdtWyzjYIdMnsSNWJnldmWjwA76sW+vvlLvTONiT4unM
8ia4GGIw7GK4E/7qxl27q6pXdZkZgG53XItYiUJGAKeBJ2nQfXq0qSmtpHkF17Cu
hw25X3FJpzRq62JxTx5q6+M2c07g4dkbfMDp/TO7vF4SWruU6JBZj5MVDYn4PEA=
-----END CERTIFICATE-----`
certECDSA = `
-----BEGIN CERTIFICATE-----
MIIBSzCB+qADAgECAhAzJszEACNBOHrsfSUJMPsHMAoGCCqGSM49BAMCMAsxCTAH
BgNVBAoTADAeFw0xNzAzMTMwNTE2NThaFw0xNzAzMTMwNTE2NThaMAsxCTAHBgNV
BAoTADBOMBAGByqGSM49AgEGBSuBBAAhAzoABMKQDHvCFvaTfFab5SOUVYWJXXWh
iYh1iBeqIBCSLPt8SrpAWGyOMKLN4bMCWFNOaeBFLG/91K8Yo0swSTAOBgNVHQ8B
Af8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAUBgNV
HREEDTALgglsb2NhbGhvc3QwCgYIKoZIzj0EAwIDQAAwPQIcY8lgBAAtFWtxmk9k
BB6nORpwdv4LVt/BFgLwWQIdAKvHn7cxBJ+aAC25rIumRNKDzP7PkV0HDbxtX+M=
-----END CERTIFICATE-----`
)
func TestParsePemEncodedCertificate(t *testing.T) {
testCases := map[string]struct {
errMsg string
pem string
publicKeyAlgo x509.PublicKeyAlgorithm
}{
"Invalid PEM string": {
errMsg: "invalid PEM encoded certificate",
pem: "invalid pem string",
},
"Invalid certificate string": {
errMsg: "failed to parse X.509 certificate",
pem: keyECDSA,
},
"Parse RSA certificate": {
publicKeyAlgo: x509.RSA,
pem: certRSA,
},
"Parse ECDSA certificate": {
publicKeyAlgo: x509.ECDSA,
pem: certECDSA,
},
}
for id, c := range testCases {
cert, err := ParsePemEncodedCertificate([]byte(c.pem))
if c.errMsg != "" {
if err == nil {
t.Errorf("%s: no error is returned", id)
} else if c.errMsg != err.Error() {
t.Errorf(`%s: Unexpected error message: expected "%s" but got "%s"`, id, c.errMsg, err.Error())
}
} else if cert.PublicKeyAlgorithm != c.publicKeyAlgo {
t.Errorf("%s: Unexpected public key algorithm: want %d but got %d", id, c.publicKeyAlgo, cert.PublicKeyAlgorithm)
}
}
}
func TestParsePemEncodedCSR(t *testing.T) {
testCases := map[string]struct {
algo x509.PublicKeyAlgorithm
errMsg string
pem string
}{
"Invalid PEM string": {
errMsg: "certificate signing request is not properly encoded",
pem: "bad pem string",
},
"Invalid CSR string": {
errMsg: "failed to parse X.509 certificate signing request",
pem: certECDSA,
},
"Parse CSR": {
algo: x509.RSA,
pem: csr,
},
}
for id, c := range testCases {
_, err := ParsePemEncodedCSR([]byte(c.pem))
if c.errMsg != "" {
if err == nil {
t.Errorf(`%s: no error is returned, expected "%s"`, id, c.errMsg)
} else if c.errMsg != err.Error() {
t.Errorf(`%s: Unexpected error message: want "%s" but got "%s"`, id, c.errMsg, err.Error())
}
} else if err != nil {
t.Errorf(`%s: Unexpected error: "%s"`, id, err)
}
}
}
func TestParsePemEncodedKey(t *testing.T) {
testCases := map[string]struct {
pem string
keyType reflect.Type
errMsg string
}{
"Invalid PEM string": {
pem: "Invalid PEM string",
errMsg: "invalid PEM-encoded key",
},
"Invalid PEM block type": {
pem: certRSA,
errMsg: "unsupported PEM block type for a private key: CERTIFICATE",
},
"Parse RSA key": {
pem: keyRSA,
keyType: reflect.TypeOf(&rsa.PrivateKey{}),
},
"Parse invalid RSA key": {
pem: keyInvalidRSA,
errMsg: "failed to parse the RSA private key",
},
"Parse ECDSA key": {
pem: keyECDSA,
keyType: reflect.TypeOf(&ecdsa.PrivateKey{}),
},
"Parse invalid ECDSA key": {
pem: keyInvalidECDSA,
errMsg: "failed to parse the ECDSA private key",
},
"Parse PKCS8 key using RSA algorithm": {
pem: keyPKCS8RSA,
keyType: reflect.TypeOf(&rsa.PrivateKey{}),
},
"Parse invalid PKCS8 key": {
pem: keyInvalidPKCS8,
errMsg: "failed to parse the PKCS8 private key",
},
}
for id, c := range testCases {
key, err := ParsePemEncodedKey([]byte(c.pem))
if c.errMsg != "" {
if err == nil {
t.Errorf(`%s: no error is returned, expected "%s"`, id, c.errMsg)
} else if c.errMsg != err.Error() {
t.Errorf(`%s: Unexpected error message: expected "%s" but got "%s"`, id, c.errMsg, err.Error())
}
} else if err != nil {
t.Errorf(`%s: Unexpected error: "%s"`, id, err)
} else if keyType := reflect.TypeOf(key); keyType != c.keyType {
t.Errorf(`%s: Unmatched key type: expected "%v" but got "%v"`, id, c.keyType, keyType)
}
}
}
func TestGetRSAKeySize(t *testing.T) {
testCases := map[string]struct {
pem string
size int
errMsg string
}{
"Success with RSA key": {
pem: keyRSA,
size: 2048,
},
"Success with PKCS8RSA key": {
pem: keyPKCS8RSA,
size: 2048,
},
"Failure with non-RSA key": {
pem: keyECDSA,
errMsg: "key type is not RSA: *ecdsa.PrivateKey",
},
}
for id, c := range testCases {
key, err := ParsePemEncodedKey([]byte(c.pem))
if err != nil {
t.Errorf("%s: failed to parse the Pem key.", id)
}
size, err := GetRSAKeySize(key)
if c.errMsg != "" {
if err == nil {
t.Errorf(`%s: no error is returned, expected error: "%s"`, id, c.errMsg)
} else if c.errMsg != err.Error() {
t.Errorf(`%s: Unexpected error message: expected "%s" but got "%s"`, id, c.errMsg, err.Error())
}
} else if err != nil {
t.Errorf(`%s: Unexpected error: "%s"`, id, err)
} else if size != c.size {
t.Errorf(`%s: Unmatched key size: expected %v but got "%v"`, id, c.size, size)
}
}
}
func TestIsSupportedECPrivateKey(t *testing.T) {
_, ed25519PrivKey, _ := ed25519.GenerateKey(nil)
ecdsaPrivKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
cases := map[string]struct {
key crypto.PrivateKey
isSupported bool
}{
"ECDSA": {
key: ecdsaPrivKey,
isSupported: true,
},
"ED25519": {
key: ed25519PrivKey,
isSupported: false,
},
}
for id, tc := range cases {
if IsSupportedECPrivateKey(&tc.key) != tc.isSupported {
t.Errorf("%s: does not match expected support level for EC signature algorithms", id)
}
}
}
func TestPemCertBytestoString(t *testing.T) {
// empty check
if len(PemCertBytestoString([]byte{})) != 0 {
t.Errorf("Empty call fails!")
}
certBytes := []byte(certECDSA)
certBytes = AppendCertByte(certBytes, []byte(certRSA))
result := PemCertBytestoString(certBytes)
cert1 := strings.TrimSuffix(strings.TrimPrefix(certECDSA, "\n"), "\n")
cert2 := strings.TrimSuffix(strings.TrimPrefix(certRSA, "\n"), "\n")
if !reflect.DeepEqual(result, []string{cert1, cert2}) {
t.Errorf("Basic comparison fails!")
}
// check only first string passed if second is bogus
certBytes = []byte(certRSA)
certBytes = AppendCertByte(certBytes, []byte("Bogus"))
result = PemCertBytestoString(certBytes)
cert1 = strings.TrimSuffix(strings.TrimPrefix(certRSA, "\n"), "\n")
if !reflect.DeepEqual(result, []string{cert1}) {
t.Errorf("Bogus comparison fails!")
}
}