github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/pkg/usertokens/pkitokens/publickeys.go (about) 1 package pkitokens 2 3 import ( 4 "crypto" 5 "crypto/ecdsa" 6 "crypto/rsa" 7 "crypto/x509" 8 "encoding/pem" 9 "fmt" 10 ) 11 12 // parsePublicKeysFromPEM reads all public keys from PEMs that are either 13 // in a "PUBLIC KEY", "RSA PUBLIC KEY" or "CERTIFICATE" type PEM and 14 // returns them in an array. Only RSA and ECDSA keys are taken into account. 15 // NOTE: pay attention to the special return logic! 16 // 17 // The return logic is as follows: 18 // if no keys could be found or parsed: nil, err 19 // if no errors were found at all: keys, nil 20 // if some keys could be parsed, but others failed: keys, err 21 // 22 func parsePublicKeysFromPEM(bytesPEM []byte) ([]crypto.PublicKey, error) { 23 keys := make([]crypto.PublicKey, 0, 1) 24 rest := bytesPEM 25 var errs []error 26 for { 27 var block *pem.Block 28 block, rest = pem.Decode(rest) 29 if block == nil { 30 break 31 } 32 switch block.Type { 33 case "CERTIFICATE": 34 cert, err := x509.ParseCertificate(block.Bytes) 35 if err != nil { 36 errs = append(errs, err) 37 continue 38 } 39 if !isSupportedPublicKeyType(cert.PublicKey) { 40 errs = append(errs, fmt.Errorf("unsupported key type %T", cert.PublicKey)) 41 continue 42 } 43 keys = append(keys, cert.PublicKey) 44 case "PUBLIC KEY": 45 pub, err := x509.ParsePKIXPublicKey(block.Bytes) 46 if err != nil { 47 errs = append(errs, err) 48 continue 49 } 50 if !isSupportedPublicKeyType(pub) { 51 errs = append(errs, fmt.Errorf("unsupported key type %T", pub)) 52 continue 53 } 54 keys = append(keys, pub) 55 case "RSA PUBLIC KEY": 56 pub, err := x509.ParsePKCS1PublicKey(block.Bytes) 57 if err != nil { 58 errs = append(errs, err) 59 continue 60 } 61 if !isSupportedPublicKeyType(pub) { 62 errs = append(errs, fmt.Errorf("unsupported key type %T", pub)) 63 continue 64 } 65 keys = append(keys, pub) 66 default: 67 // invalid type, read the next entry 68 errs = append(errs, fmt.Errorf("unsupported PEM type %s", block.Type)) 69 continue 70 } 71 } 72 73 // create detailed error 74 var detailedErrors string 75 for i, err := range errs { 76 detailedErrors += err.Error() 77 if i+1 < len(errs) { 78 detailedErrors += "; " 79 } 80 } 81 82 // if no keys at all were found, be specific about this 83 if len(keys) == 0 { 84 return nil, fmt.Errorf("no valid certificates or public keys found (errors: [%s])", detailedErrors) 85 } 86 87 // if some errors were encountered, but we have some keys, return both 88 if len(keys) > 0 && len(errs) > 0 { 89 return keys, fmt.Errorf("[%s]", detailedErrors) 90 } 91 92 // if all went well, return keys, but no error 93 return keys, nil 94 } 95 96 // isSupportedPublicKeyType returns true if `key` is an RSA or ECDSA public key 97 func isSupportedPublicKeyType(key crypto.PublicKey) bool { 98 return isRSAPublicKey(key) || isECDSAPublicKey(key) 99 } 100 101 func isRSAPublicKey(key crypto.PublicKey) bool { 102 _, ok := key.(*rsa.PublicKey) 103 return ok 104 } 105 106 func isECDSAPublicKey(key crypto.PublicKey) bool { 107 _, ok := key.(*ecdsa.PublicKey) 108 return ok 109 }