...

Source file src/k8s.io/client-go/util/keyutil/key.go

Documentation: k8s.io/client-go/util/keyutil

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

View as plain text