diff --git a/pkg/serviceaccount/jwt.go b/pkg/serviceaccount/jwt.go index ad53a1802a5..b277fca1e8c 100644 --- a/pkg/serviceaccount/jwt.go +++ b/pkg/serviceaccount/jwt.go @@ -73,11 +73,25 @@ func ReadPrivateKey(file string) (interface{}, error) { // ReadPrivateKeyFromPEM is a helper function for reading a private key from a PEM-encoded file func ReadPrivateKeyFromPEM(data []byte) (interface{}, error) { - if key, err := jwt.ParseRSAPrivateKeyFromPEM(data); err == nil { - return key, nil - } - if key, err := jwt.ParseECPrivateKeyFromPEM(data); err == nil { - return key, nil + var block *pem.Block + for { + // read the next block + block, data = pem.Decode(data) + if block == nil { + break + } + + // get PEM bytes for just this block + blockData := pem.EncodeToMemory(block) + if key, err := jwt.ParseRSAPrivateKeyFromPEM(blockData); err == nil { + return key, nil + } + if key, err := jwt.ParseECPrivateKeyFromPEM(blockData); err == nil { + return key, nil + } + + // tolerate non-key PEM blocks for compatibility with things like "EC PARAMETERS" blocks + // originally, only the first PEM block was parsed and expected to be a key block } return nil, fmt.Errorf("data does not contain a valid RSA or ECDSA private key") } diff --git a/pkg/serviceaccount/jwt_test.go b/pkg/serviceaccount/jwt_test.go index 7908114fa26..8213e737aca 100644 --- a/pkg/serviceaccount/jwt_test.go +++ b/pkg/serviceaccount/jwt_test.go @@ -81,6 +81,17 @@ X024wzbiw1q07jFCyfQmODzURAx1VNT7QVUMdz/N8vy47/H40AZJ -----END RSA PRIVATE KEY----- ` +// openssl ecparam -name prime256v1 -genkey -out ecdsa256params.pem +const ecdsaPrivateKeyWithParams = `-----BEGIN EC PARAMETERS----- +BggqhkjOPQMBBw== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIJ9LWDj3ZWe9CksPV7mZjD2dYXG9icfzxadCRwd3vr1toAoGCCqGSM49 +AwEHoUQDQgAEaLNEpzbaaNTCkKjBVj7sxpfJ1ifJQGNvcck4nrzcwFRuujwVDDJh +95iIGwKCQeSg+yhdN6Q/p2XaxNIZlYmUhg== +-----END EC PRIVATE KEY----- +` + // openssl ecparam -name prime256v1 -genkey -noout -out ecdsa256.pem const ecdsaPrivateKey = `-----BEGIN EC PRIVATE KEY----- MHcCAQEEIEZmTmUhuanLjPA2CLquXivuwBDHTt5XYwgIr/kA1LtRoAoGCCqGSM49 @@ -110,6 +121,10 @@ func TestReadPrivateKey(t *testing.T) { } defer os.Remove(f.Name()) + if _, err := serviceaccount.ReadPrivateKey(f.Name()); err == nil { + t.Fatalf("Expected error reading key from empty file, got none") + } + if err := ioutil.WriteFile(f.Name(), []byte(rsaPrivateKey), os.FileMode(0600)); err != nil { t.Fatalf("error writing private key to tmpfile: %v", err) } @@ -123,6 +138,13 @@ func TestReadPrivateKey(t *testing.T) { if _, err := serviceaccount.ReadPrivateKey(f.Name()); err != nil { t.Fatalf("error reading private ECDSA key: %v", err) } + + if err := ioutil.WriteFile(f.Name(), []byte(ecdsaPrivateKeyWithParams), os.FileMode(0600)); err != nil { + t.Fatalf("error writing private key to tmpfile: %v", err) + } + if _, err := serviceaccount.ReadPrivateKey(f.Name()); err != nil { + t.Fatalf("error reading private ECDSA key with params: %v", err) + } } func TestReadPublicKeys(t *testing.T) { @@ -132,6 +154,10 @@ func TestReadPublicKeys(t *testing.T) { } defer os.Remove(f.Name()) + if _, err := serviceaccount.ReadPublicKeys(f.Name()); err == nil { + t.Fatalf("Expected error reading keys from empty file, got none") + } + if err := ioutil.WriteFile(f.Name(), []byte(rsaPublicKey), os.FileMode(0600)); err != nil { t.Fatalf("error writing public key to tmpfile: %v", err) }