k8s.io/client-go@v0.31.1/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 "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 }