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 }