diff --git a/pkg/serviceaccount/BUILD b/pkg/serviceaccount/BUILD index f56e4a0b331..2ad4f902241 100644 --- a/pkg/serviceaccount/BUILD +++ b/pkg/serviceaccount/BUILD @@ -23,6 +23,7 @@ go_library( "//vendor:k8s.io/apiserver/pkg/authentication/authenticator", "//vendor:k8s.io/apiserver/pkg/authentication/serviceaccount", "//vendor:k8s.io/apiserver/pkg/authentication/user", + "//vendor:k8s.io/client-go/util/cert", ], ) @@ -38,6 +39,7 @@ go_test( "//pkg/serviceaccount:go_default_library", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apiserver/pkg/authentication/serviceaccount", + "//vendor:k8s.io/client-go/util/cert", ], ) diff --git a/pkg/serviceaccount/jwt.go b/pkg/serviceaccount/jwt.go index b277fca1e8c..38c063253bf 100644 --- a/pkg/serviceaccount/jwt.go +++ b/pkg/serviceaccount/jwt.go @@ -29,6 +29,7 @@ import ( "k8s.io/apiserver/pkg/authentication/authenticator" apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount" "k8s.io/apiserver/pkg/authentication/user" + "k8s.io/client-go/util/cert" "k8s.io/kubernetes/pkg/api/v1" jwt "github.com/dgrijalva/jwt-go" @@ -64,38 +65,13 @@ func ReadPrivateKey(file string) (interface{}, error) { if err != nil { return nil, err } - key, err := ReadPrivateKeyFromPEM(data) + key, err := cert.ParsePrivateKeyPEM(data) if err != nil { return nil, fmt.Errorf("error reading private key file %s: %v", file, err) } return key, nil } -// ReadPrivateKeyFromPEM is a helper function for reading a private key from a PEM-encoded file -func ReadPrivateKeyFromPEM(data []byte) (interface{}, error) { - 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") -} - // ReadPublicKeys is a helper function for reading an array of rsa.PublicKey or ecdsa.PublicKey from a PEM-encoded file. // Reads public keys from both public and private key files. func ReadPublicKeys(file string) ([]interface{}, error) { diff --git a/pkg/serviceaccount/jwt_test.go b/pkg/serviceaccount/jwt_test.go index 8213e737aca..d1a308b14d7 100644 --- a/pkg/serviceaccount/jwt_test.go +++ b/pkg/serviceaccount/jwt_test.go @@ -24,6 +24,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount" + "k8s.io/client-go/util/cert" "k8s.io/kubernetes/pkg/api/v1" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake" @@ -106,7 +107,7 @@ X2i8uIp/C/ASqiIGUeeKQtX0/IR3qCXyThP/dbCiHrF3v1cuhBOHY8CLVg== -----END PUBLIC KEY-----` func getPrivateKey(data string) interface{} { - key, _ := serviceaccount.ReadPrivateKeyFromPEM([]byte(data)) + key, _ := cert.ParsePrivateKeyPEM([]byte(data)) return key } diff --git a/staging/src/k8s.io/client-go/util/cert/pem.go b/staging/src/k8s.io/client-go/util/cert/pem.go index 59e602d2f1c..e0b46d88a79 100644 --- a/staging/src/k8s.io/client-go/util/cert/pem.go +++ b/staging/src/k8s.io/client-go/util/cert/pem.go @@ -56,23 +56,39 @@ func EncodeCertPEM(cert *x509.Certificate) []byte { } // ParsePrivateKeyPEM returns a private key parsed from a PEM block in the supplied data. -// Recognizes PEM blocks for "EC PRIVATE KEY" and "RSA PRIVATE KEY" +// Recognizes PEM blocks for "EC PRIVATE KEY", "RSA PRIVATE KEY", or "PRIVATE KEY" func ParsePrivateKeyPEM(keyData []byte) (interface{}, error) { + var privateKeyPemBlock *pem.Block for { - var privateKeyPemBlock *pem.Block privateKeyPemBlock, keyData = pem.Decode(keyData) if privateKeyPemBlock == nil { - // we read all the PEM blocks and didn't recognize one - return nil, fmt.Errorf("no private key PEM block found") + break } switch privateKeyPemBlock.Type { case "EC PRIVATE KEY": - return x509.ParseECPrivateKey(privateKeyPemBlock.Bytes) + // ECDSA Private Key in ASN.1 format + if key, err := x509.ParseECPrivateKey(privateKeyPemBlock.Bytes); err == nil { + return key, nil + } case "RSA PRIVATE KEY": - return x509.ParsePKCS1PrivateKey(privateKeyPemBlock.Bytes) + // RSA Private Key in PKCS#1 format + if key, err := x509.ParsePKCS1PrivateKey(privateKeyPemBlock.Bytes); err == nil { + return key, nil + } + case "PRIVATE KEY": + // RSA or ECDSA Private Key in unencrypted PKCS#8 format + if key, err := x509.ParsePKCS8PrivateKey(privateKeyPemBlock.Bytes); 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 } + + // we read all the PEM blocks and didn't recognize one + return nil, fmt.Errorf("data does not contain a valid RSA or ECDSA private key") } // ParseCertsPEM returns the x509.Certificates contained in the given PEM-encoded byte array