| /* |
| Copyright 2014 The Kubernetes 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 cert |
| |
| import ( |
| "crypto/ecdsa" |
| "crypto/rsa" |
| "crypto/x509" |
| "encoding/pem" |
| "errors" |
| "fmt" |
| ) |
| |
| const ( |
| // ECPrivateKeyBlockType is a possible value for pem.Block.Type. |
| ECPrivateKeyBlockType = "EC PRIVATE KEY" |
| // RSAPrivateKeyBlockType is a possible value for pem.Block.Type. |
| RSAPrivateKeyBlockType = "RSA PRIVATE KEY" |
| // PrivateKeyBlockType is a possible value for pem.Block.Type. |
| PrivateKeyBlockType = "PRIVATE KEY" |
| // PublicKeyBlockType is a possible value for pem.Block.Type. |
| PublicKeyBlockType = "PUBLIC KEY" |
| // CertificateBlockType is a possible value for pem.Block.Type. |
| CertificateBlockType = "CERTIFICATE" |
| // CertificateRequestBlockType is a possible value for pem.Block.Type. |
| CertificateRequestBlockType = "CERTIFICATE REQUEST" |
| ) |
| |
| // EncodePublicKeyPEM returns PEM-encoded public data |
| func EncodePublicKeyPEM(key *rsa.PublicKey) ([]byte, error) { |
| der, err := x509.MarshalPKIXPublicKey(key) |
| if err != nil { |
| return []byte{}, err |
| } |
| block := pem.Block{ |
| Type: PublicKeyBlockType, |
| Bytes: der, |
| } |
| return pem.EncodeToMemory(&block), nil |
| } |
| |
| // EncodePrivateKeyPEM returns PEM-encoded private key data |
| func EncodePrivateKeyPEM(key *rsa.PrivateKey) []byte { |
| block := pem.Block{ |
| Type: RSAPrivateKeyBlockType, |
| Bytes: x509.MarshalPKCS1PrivateKey(key), |
| } |
| return pem.EncodeToMemory(&block) |
| } |
| |
| // EncodeCertPEM returns PEM-endcoded certificate data |
| func EncodeCertPEM(cert *x509.Certificate) []byte { |
| block := pem.Block{ |
| Type: CertificateBlockType, |
| Bytes: cert.Raw, |
| } |
| return pem.EncodeToMemory(&block) |
| } |
| |
| // ParsePrivateKeyPEM returns a private key parsed from a PEM block in the supplied data. |
| // Recognizes PEM blocks for "EC PRIVATE KEY", "RSA PRIVATE KEY", or "PRIVATE KEY" |
| func ParsePrivateKeyPEM(keyData []byte) (interface{}, error) { |
| var privateKeyPemBlock *pem.Block |
| for { |
| privateKeyPemBlock, keyData = pem.Decode(keyData) |
| if privateKeyPemBlock == nil { |
| break |
| } |
| |
| switch privateKeyPemBlock.Type { |
| case ECPrivateKeyBlockType: |
| // ECDSA Private Key in ASN.1 format |
| if key, err := x509.ParseECPrivateKey(privateKeyPemBlock.Bytes); err == nil { |
| return key, nil |
| } |
| case RSAPrivateKeyBlockType: |
| // RSA Private Key in PKCS#1 format |
| if key, err := x509.ParsePKCS1PrivateKey(privateKeyPemBlock.Bytes); err == nil { |
| return key, nil |
| } |
| case PrivateKeyBlockType: |
| // 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") |
| } |
| |
| // ParsePublicKeysPEM is a helper function for reading an array of rsa.PublicKey or ecdsa.PublicKey from a PEM-encoded byte array. |
| // Reads public keys from both public and private key files. |
| func ParsePublicKeysPEM(keyData []byte) ([]interface{}, error) { |
| var block *pem.Block |
| keys := []interface{}{} |
| for { |
| // read the next block |
| block, keyData = pem.Decode(keyData) |
| if block == nil { |
| break |
| } |
| |
| // test block against parsing functions |
| if privateKey, err := parseRSAPrivateKey(block.Bytes); err == nil { |
| keys = append(keys, &privateKey.PublicKey) |
| continue |
| } |
| if publicKey, err := parseRSAPublicKey(block.Bytes); err == nil { |
| keys = append(keys, publicKey) |
| continue |
| } |
| if privateKey, err := parseECPrivateKey(block.Bytes); err == nil { |
| keys = append(keys, &privateKey.PublicKey) |
| continue |
| } |
| if publicKey, err := parseECPublicKey(block.Bytes); err == nil { |
| keys = append(keys, publicKey) |
| continue |
| } |
| |
| // tolerate non-key PEM blocks for backwards compatibility |
| // originally, only the first PEM block was parsed and expected to be a key block |
| } |
| |
| if len(keys) == 0 { |
| return nil, fmt.Errorf("data does not contain any valid RSA or ECDSA public keys") |
| } |
| return keys, nil |
| } |
| |
| // ParseCertsPEM returns the x509.Certificates contained in the given PEM-encoded byte array |
| // Returns an error if a certificate could not be parsed, or if the data does not contain any certificates |
| func ParseCertsPEM(pemCerts []byte) ([]*x509.Certificate, error) { |
| ok := false |
| certs := []*x509.Certificate{} |
| for len(pemCerts) > 0 { |
| var block *pem.Block |
| block, pemCerts = pem.Decode(pemCerts) |
| if block == nil { |
| break |
| } |
| // Only use PEM "CERTIFICATE" blocks without extra headers |
| if block.Type != CertificateBlockType || len(block.Headers) != 0 { |
| continue |
| } |
| |
| cert, err := x509.ParseCertificate(block.Bytes) |
| if err != nil { |
| return certs, err |
| } |
| |
| certs = append(certs, cert) |
| ok = true |
| } |
| |
| if !ok { |
| return certs, errors.New("data does not contain any valid RSA or ECDSA certificates") |
| } |
| return certs, nil |
| } |
| |
| // parseRSAPublicKey parses a single RSA public key from the provided data |
| func parseRSAPublicKey(data []byte) (*rsa.PublicKey, error) { |
| var err error |
| |
| // Parse the key |
| var parsedKey interface{} |
| if parsedKey, err = x509.ParsePKIXPublicKey(data); err != nil { |
| if cert, err := x509.ParseCertificate(data); err == nil { |
| parsedKey = cert.PublicKey |
| } else { |
| return nil, err |
| } |
| } |
| |
| // Test if parsed key is an RSA Public Key |
| var pubKey *rsa.PublicKey |
| var ok bool |
| if pubKey, ok = parsedKey.(*rsa.PublicKey); !ok { |
| return nil, fmt.Errorf("data doesn't contain valid RSA Public Key") |
| } |
| |
| return pubKey, nil |
| } |
| |
| // parseRSAPrivateKey parses a single RSA private key from the provided data |
| func parseRSAPrivateKey(data []byte) (*rsa.PrivateKey, error) { |
| var err error |
| |
| // Parse the key |
| var parsedKey interface{} |
| if parsedKey, err = x509.ParsePKCS1PrivateKey(data); err != nil { |
| if parsedKey, err = x509.ParsePKCS8PrivateKey(data); err != nil { |
| return nil, err |
| } |
| } |
| |
| // Test if parsed key is an RSA Private Key |
| var privKey *rsa.PrivateKey |
| var ok bool |
| if privKey, ok = parsedKey.(*rsa.PrivateKey); !ok { |
| return nil, fmt.Errorf("data doesn't contain valid RSA Private Key") |
| } |
| |
| return privKey, nil |
| } |
| |
| // parseECPublicKey parses a single ECDSA public key from the provided data |
| func parseECPublicKey(data []byte) (*ecdsa.PublicKey, error) { |
| var err error |
| |
| // Parse the key |
| var parsedKey interface{} |
| if parsedKey, err = x509.ParsePKIXPublicKey(data); err != nil { |
| if cert, err := x509.ParseCertificate(data); err == nil { |
| parsedKey = cert.PublicKey |
| } else { |
| return nil, err |
| } |
| } |
| |
| // Test if parsed key is an ECDSA Public Key |
| var pubKey *ecdsa.PublicKey |
| var ok bool |
| if pubKey, ok = parsedKey.(*ecdsa.PublicKey); !ok { |
| return nil, fmt.Errorf("data doesn't contain valid ECDSA Public Key") |
| } |
| |
| return pubKey, nil |
| } |
| |
| // parseECPrivateKey parses a single ECDSA private key from the provided data |
| func parseECPrivateKey(data []byte) (*ecdsa.PrivateKey, error) { |
| var err error |
| |
| // Parse the key |
| var parsedKey interface{} |
| if parsedKey, err = x509.ParseECPrivateKey(data); err != nil { |
| return nil, err |
| } |
| |
| // Test if parsed key is an ECDSA Private Key |
| var privKey *ecdsa.PrivateKey |
| var ok bool |
| if privKey, ok = parsedKey.(*ecdsa.PrivateKey); !ok { |
| return nil, fmt.Errorf("data doesn't contain valid ECDSA Private Key") |
| } |
| |
| return privKey, nil |
| } |