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  }