k8s.io/client-go@v0.22.2/util/keyutil/key.go (about)

     1  /*
     2  Copyright 2018 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // Package keyutil contains utilities for managing public/private key pairs.
    18  package keyutil
    19  
    20  import (
    21  	"crypto"
    22  	"crypto/ecdsa"
    23  	"crypto/elliptic"
    24  	cryptorand "crypto/rand"
    25  	"crypto/rsa"
    26  	"crypto/x509"
    27  	"encoding/pem"
    28  	"fmt"
    29  	"io/ioutil"
    30  	"os"
    31  	"path/filepath"
    32  )
    33  
    34  const (
    35  	// ECPrivateKeyBlockType is a possible value for pem.Block.Type.
    36  	ECPrivateKeyBlockType = "EC PRIVATE KEY"
    37  	// RSAPrivateKeyBlockType is a possible value for pem.Block.Type.
    38  	RSAPrivateKeyBlockType = "RSA PRIVATE KEY"
    39  	// PrivateKeyBlockType is a possible value for pem.Block.Type.
    40  	PrivateKeyBlockType = "PRIVATE KEY"
    41  	// PublicKeyBlockType is a possible value for pem.Block.Type.
    42  	PublicKeyBlockType = "PUBLIC KEY"
    43  )
    44  
    45  // MakeEllipticPrivateKeyPEM creates an ECDSA private key
    46  func MakeEllipticPrivateKeyPEM() ([]byte, error) {
    47  	privateKey, err := ecdsa.GenerateKey(elliptic.P256(), cryptorand.Reader)
    48  	if err != nil {
    49  		return nil, err
    50  	}
    51  
    52  	derBytes, err := x509.MarshalECPrivateKey(privateKey)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	privateKeyPemBlock := &pem.Block{
    58  		Type:  ECPrivateKeyBlockType,
    59  		Bytes: derBytes,
    60  	}
    61  	return pem.EncodeToMemory(privateKeyPemBlock), nil
    62  }
    63  
    64  // WriteKey writes the pem-encoded key data to keyPath.
    65  // The key file will be created with file mode 0600.
    66  // If the key file already exists, it will be overwritten.
    67  // The parent directory of the keyPath will be created as needed with file mode 0755.
    68  func WriteKey(keyPath string, data []byte) error {
    69  	if err := os.MkdirAll(filepath.Dir(keyPath), os.FileMode(0755)); err != nil {
    70  		return err
    71  	}
    72  	return ioutil.WriteFile(keyPath, data, os.FileMode(0600))
    73  }
    74  
    75  // LoadOrGenerateKeyFile looks for a key in the file at the given path. If it
    76  // can't find one, it will generate a new key and store it there.
    77  func LoadOrGenerateKeyFile(keyPath string) (data []byte, wasGenerated bool, err error) {
    78  	loadedData, err := ioutil.ReadFile(keyPath)
    79  	// Call verifyKeyData to ensure the file wasn't empty/corrupt.
    80  	if err == nil && verifyKeyData(loadedData) {
    81  		return loadedData, false, err
    82  	}
    83  	if !os.IsNotExist(err) {
    84  		return nil, false, fmt.Errorf("error loading key from %s: %v", keyPath, err)
    85  	}
    86  
    87  	generatedData, err := MakeEllipticPrivateKeyPEM()
    88  	if err != nil {
    89  		return nil, false, fmt.Errorf("error generating key: %v", err)
    90  	}
    91  	if err := WriteKey(keyPath, generatedData); err != nil {
    92  		return nil, false, fmt.Errorf("error writing key to %s: %v", keyPath, err)
    93  	}
    94  	return generatedData, true, nil
    95  }
    96  
    97  // MarshalPrivateKeyToPEM converts a known private key type of RSA or ECDSA to
    98  // a PEM encoded block or returns an error.
    99  func MarshalPrivateKeyToPEM(privateKey crypto.PrivateKey) ([]byte, error) {
   100  	switch t := privateKey.(type) {
   101  	case *ecdsa.PrivateKey:
   102  		derBytes, err := x509.MarshalECPrivateKey(t)
   103  		if err != nil {
   104  			return nil, err
   105  		}
   106  		block := &pem.Block{
   107  			Type:  ECPrivateKeyBlockType,
   108  			Bytes: derBytes,
   109  		}
   110  		return pem.EncodeToMemory(block), nil
   111  	case *rsa.PrivateKey:
   112  		block := &pem.Block{
   113  			Type:  RSAPrivateKeyBlockType,
   114  			Bytes: x509.MarshalPKCS1PrivateKey(t),
   115  		}
   116  		return pem.EncodeToMemory(block), nil
   117  	default:
   118  		return nil, fmt.Errorf("private key is not a recognized type: %T", privateKey)
   119  	}
   120  }
   121  
   122  // PrivateKeyFromFile returns the private key in rsa.PrivateKey or ecdsa.PrivateKey format from a given PEM-encoded file.
   123  // Returns an error if the file could not be read or if the private key could not be parsed.
   124  func PrivateKeyFromFile(file string) (interface{}, error) {
   125  	data, err := ioutil.ReadFile(file)
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  	key, err := ParsePrivateKeyPEM(data)
   130  	if err != nil {
   131  		return nil, fmt.Errorf("error reading private key file %s: %v", file, err)
   132  	}
   133  	return key, nil
   134  }
   135  
   136  // PublicKeysFromFile returns the public keys in rsa.PublicKey or ecdsa.PublicKey format from a given PEM-encoded file.
   137  // Reads public keys from both public and private key files.
   138  func PublicKeysFromFile(file string) ([]interface{}, error) {
   139  	data, err := ioutil.ReadFile(file)
   140  	if err != nil {
   141  		return nil, err
   142  	}
   143  	keys, err := ParsePublicKeysPEM(data)
   144  	if err != nil {
   145  		return nil, fmt.Errorf("error reading public key file %s: %v", file, err)
   146  	}
   147  	return keys, nil
   148  }
   149  
   150  // verifyKeyData returns true if the provided data appears to be a valid private key.
   151  func verifyKeyData(data []byte) bool {
   152  	if len(data) == 0 {
   153  		return false
   154  	}
   155  	_, err := ParsePrivateKeyPEM(data)
   156  	return err == nil
   157  }
   158  
   159  // ParsePrivateKeyPEM returns a private key parsed from a PEM block in the supplied data.
   160  // Recognizes PEM blocks for "EC PRIVATE KEY", "RSA PRIVATE KEY", or "PRIVATE KEY"
   161  func ParsePrivateKeyPEM(keyData []byte) (interface{}, error) {
   162  	var privateKeyPemBlock *pem.Block
   163  	for {
   164  		privateKeyPemBlock, keyData = pem.Decode(keyData)
   165  		if privateKeyPemBlock == nil {
   166  			break
   167  		}
   168  
   169  		switch privateKeyPemBlock.Type {
   170  		case ECPrivateKeyBlockType:
   171  			// ECDSA Private Key in ASN.1 format
   172  			if key, err := x509.ParseECPrivateKey(privateKeyPemBlock.Bytes); err == nil {
   173  				return key, nil
   174  			}
   175  		case RSAPrivateKeyBlockType:
   176  			// RSA Private Key in PKCS#1 format
   177  			if key, err := x509.ParsePKCS1PrivateKey(privateKeyPemBlock.Bytes); err == nil {
   178  				return key, nil
   179  			}
   180  		case PrivateKeyBlockType:
   181  			// RSA or ECDSA Private Key in unencrypted PKCS#8 format
   182  			if key, err := x509.ParsePKCS8PrivateKey(privateKeyPemBlock.Bytes); err == nil {
   183  				return key, nil
   184  			}
   185  		}
   186  
   187  		// tolerate non-key PEM blocks for compatibility with things like "EC PARAMETERS" blocks
   188  		// originally, only the first PEM block was parsed and expected to be a key block
   189  	}
   190  
   191  	// we read all the PEM blocks and didn't recognize one
   192  	return nil, fmt.Errorf("data does not contain a valid RSA or ECDSA private key")
   193  }
   194  
   195  // ParsePublicKeysPEM is a helper function for reading an array of rsa.PublicKey or ecdsa.PublicKey from a PEM-encoded byte array.
   196  // Reads public keys from both public and private key files.
   197  func ParsePublicKeysPEM(keyData []byte) ([]interface{}, error) {
   198  	var block *pem.Block
   199  	keys := []interface{}{}
   200  	for {
   201  		// read the next block
   202  		block, keyData = pem.Decode(keyData)
   203  		if block == nil {
   204  			break
   205  		}
   206  
   207  		// test block against parsing functions
   208  		if privateKey, err := parseRSAPrivateKey(block.Bytes); err == nil {
   209  			keys = append(keys, &privateKey.PublicKey)
   210  			continue
   211  		}
   212  		if publicKey, err := parseRSAPublicKey(block.Bytes); err == nil {
   213  			keys = append(keys, publicKey)
   214  			continue
   215  		}
   216  		if privateKey, err := parseECPrivateKey(block.Bytes); err == nil {
   217  			keys = append(keys, &privateKey.PublicKey)
   218  			continue
   219  		}
   220  		if publicKey, err := parseECPublicKey(block.Bytes); err == nil {
   221  			keys = append(keys, publicKey)
   222  			continue
   223  		}
   224  
   225  		// tolerate non-key PEM blocks for backwards compatibility
   226  		// originally, only the first PEM block was parsed and expected to be a key block
   227  	}
   228  
   229  	if len(keys) == 0 {
   230  		return nil, fmt.Errorf("data does not contain any valid RSA or ECDSA public keys")
   231  	}
   232  	return keys, nil
   233  }
   234  
   235  // parseRSAPublicKey parses a single RSA public key from the provided data
   236  func parseRSAPublicKey(data []byte) (*rsa.PublicKey, error) {
   237  	var err error
   238  
   239  	// Parse the key
   240  	var parsedKey interface{}
   241  	if parsedKey, err = x509.ParsePKIXPublicKey(data); err != nil {
   242  		if cert, err := x509.ParseCertificate(data); err == nil {
   243  			parsedKey = cert.PublicKey
   244  		} else {
   245  			return nil, err
   246  		}
   247  	}
   248  
   249  	// Test if parsed key is an RSA Public Key
   250  	var pubKey *rsa.PublicKey
   251  	var ok bool
   252  	if pubKey, ok = parsedKey.(*rsa.PublicKey); !ok {
   253  		return nil, fmt.Errorf("data doesn't contain valid RSA Public Key")
   254  	}
   255  
   256  	return pubKey, nil
   257  }
   258  
   259  // parseRSAPrivateKey parses a single RSA private key from the provided data
   260  func parseRSAPrivateKey(data []byte) (*rsa.PrivateKey, error) {
   261  	var err error
   262  
   263  	// Parse the key
   264  	var parsedKey interface{}
   265  	if parsedKey, err = x509.ParsePKCS1PrivateKey(data); err != nil {
   266  		if parsedKey, err = x509.ParsePKCS8PrivateKey(data); err != nil {
   267  			return nil, err
   268  		}
   269  	}
   270  
   271  	// Test if parsed key is an RSA Private Key
   272  	var privKey *rsa.PrivateKey
   273  	var ok bool
   274  	if privKey, ok = parsedKey.(*rsa.PrivateKey); !ok {
   275  		return nil, fmt.Errorf("data doesn't contain valid RSA Private Key")
   276  	}
   277  
   278  	return privKey, nil
   279  }
   280  
   281  // parseECPublicKey parses a single ECDSA public key from the provided data
   282  func parseECPublicKey(data []byte) (*ecdsa.PublicKey, error) {
   283  	var err error
   284  
   285  	// Parse the key
   286  	var parsedKey interface{}
   287  	if parsedKey, err = x509.ParsePKIXPublicKey(data); err != nil {
   288  		if cert, err := x509.ParseCertificate(data); err == nil {
   289  			parsedKey = cert.PublicKey
   290  		} else {
   291  			return nil, err
   292  		}
   293  	}
   294  
   295  	// Test if parsed key is an ECDSA Public Key
   296  	var pubKey *ecdsa.PublicKey
   297  	var ok bool
   298  	if pubKey, ok = parsedKey.(*ecdsa.PublicKey); !ok {
   299  		return nil, fmt.Errorf("data doesn't contain valid ECDSA Public Key")
   300  	}
   301  
   302  	return pubKey, nil
   303  }
   304  
   305  // parseECPrivateKey parses a single ECDSA private key from the provided data
   306  func parseECPrivateKey(data []byte) (*ecdsa.PrivateKey, error) {
   307  	var err error
   308  
   309  	// Parse the key
   310  	var parsedKey interface{}
   311  	if parsedKey, err = x509.ParseECPrivateKey(data); err != nil {
   312  		return nil, err
   313  	}
   314  
   315  	// Test if parsed key is an ECDSA Private Key
   316  	var privKey *ecdsa.PrivateKey
   317  	var ok bool
   318  	if privKey, ok = parsedKey.(*ecdsa.PrivateKey); !ok {
   319  		return nil, fmt.Errorf("data doesn't contain valid ECDSA Private Key")
   320  	}
   321  
   322  	return privKey, nil
   323  }