mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 13:50:01 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			254 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			254 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package libtrust
 | |
| 
 | |
| import (
 | |
| 	"crypto"
 | |
| 	"crypto/ecdsa"
 | |
| 	"crypto/rsa"
 | |
| 	"crypto/x509"
 | |
| 	"encoding/json"
 | |
| 	"encoding/pem"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| )
 | |
| 
 | |
| // PublicKey is a generic interface for a Public Key.
 | |
| type PublicKey interface {
 | |
| 	// KeyType returns the key type for this key. For elliptic curve keys,
 | |
| 	// this value should be "EC". For RSA keys, this value should be "RSA".
 | |
| 	KeyType() string
 | |
| 	// KeyID returns a distinct identifier which is unique to this Public Key.
 | |
| 	// The format generated by this library is a base32 encoding of a 240 bit
 | |
| 	// hash of the public key data divided into 12 groups like so:
 | |
| 	//    ABCD:EFGH:IJKL:MNOP:QRST:UVWX:YZ23:4567:ABCD:EFGH:IJKL:MNOP
 | |
| 	KeyID() string
 | |
| 	// Verify verifyies the signature of the data in the io.Reader using this
 | |
| 	// Public Key. The alg parameter should identify the digital signature
 | |
| 	// algorithm which was used to produce the signature and should be
 | |
| 	// supported by this public key. Returns a nil error if the signature
 | |
| 	// is valid.
 | |
| 	Verify(data io.Reader, alg string, signature []byte) error
 | |
| 	// CryptoPublicKey returns the internal object which can be used as a
 | |
| 	// crypto.PublicKey for use with other standard library operations. The type
 | |
| 	// is either *rsa.PublicKey or *ecdsa.PublicKey
 | |
| 	CryptoPublicKey() crypto.PublicKey
 | |
| 	// These public keys can be serialized to the standard JSON encoding for
 | |
| 	// JSON Web Keys. See section 6 of the IETF draft RFC for JOSE JSON Web
 | |
| 	// Algorithms.
 | |
| 	MarshalJSON() ([]byte, error)
 | |
| 	// These keys can also be serialized to the standard PEM encoding.
 | |
| 	PEMBlock() (*pem.Block, error)
 | |
| 	// The string representation of a key is its key type and ID.
 | |
| 	String() string
 | |
| 	AddExtendedField(string, interface{})
 | |
| 	GetExtendedField(string) interface{}
 | |
| }
 | |
| 
 | |
| // PrivateKey is a generic interface for a Private Key.
 | |
| type PrivateKey interface {
 | |
| 	// A PrivateKey contains all fields and methods of a PublicKey of the
 | |
| 	// same type. The MarshalJSON method also outputs the private key as a
 | |
| 	// JSON Web Key, and the PEMBlock method outputs the private key as a
 | |
| 	// PEM block.
 | |
| 	PublicKey
 | |
| 	// PublicKey returns the PublicKey associated with this PrivateKey.
 | |
| 	PublicKey() PublicKey
 | |
| 	// Sign signs the data read from the io.Reader using a signature algorithm
 | |
| 	// supported by the private key. If the specified hashing algorithm is
 | |
| 	// supported by this key, that hash function is used to generate the
 | |
| 	// signature otherwise the the default hashing algorithm for this key is
 | |
| 	// used. Returns the signature and identifier of the algorithm used.
 | |
| 	Sign(data io.Reader, hashID crypto.Hash) (signature []byte, alg string, err error)
 | |
| 	// CryptoPrivateKey returns the internal object which can be used as a
 | |
| 	// crypto.PublicKey for use with other standard library operations. The
 | |
| 	// type is either *rsa.PublicKey or *ecdsa.PublicKey
 | |
| 	CryptoPrivateKey() crypto.PrivateKey
 | |
| }
 | |
| 
 | |
| // FromCryptoPublicKey returns a libtrust PublicKey representation of the given
 | |
| // *ecdsa.PublicKey or *rsa.PublicKey. Returns a non-nil error when the given
 | |
| // key is of an unsupported type.
 | |
| func FromCryptoPublicKey(cryptoPublicKey crypto.PublicKey) (PublicKey, error) {
 | |
| 	switch cryptoPublicKey := cryptoPublicKey.(type) {
 | |
| 	case *ecdsa.PublicKey:
 | |
| 		return fromECPublicKey(cryptoPublicKey)
 | |
| 	case *rsa.PublicKey:
 | |
| 		return fromRSAPublicKey(cryptoPublicKey), nil
 | |
| 	default:
 | |
| 		return nil, fmt.Errorf("public key type %T is not supported", cryptoPublicKey)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // FromCryptoPrivateKey returns a libtrust PrivateKey representation of the given
 | |
| // *ecdsa.PrivateKey or *rsa.PrivateKey. Returns a non-nil error when the given
 | |
| // key is of an unsupported type.
 | |
| func FromCryptoPrivateKey(cryptoPrivateKey crypto.PrivateKey) (PrivateKey, error) {
 | |
| 	switch cryptoPrivateKey := cryptoPrivateKey.(type) {
 | |
| 	case *ecdsa.PrivateKey:
 | |
| 		return fromECPrivateKey(cryptoPrivateKey)
 | |
| 	case *rsa.PrivateKey:
 | |
| 		return fromRSAPrivateKey(cryptoPrivateKey), nil
 | |
| 	default:
 | |
| 		return nil, fmt.Errorf("private key type %T is not supported", cryptoPrivateKey)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // UnmarshalPublicKeyPEM parses the PEM encoded data and returns a libtrust
 | |
| // PublicKey or an error if there is a problem with the encoding.
 | |
| func UnmarshalPublicKeyPEM(data []byte) (PublicKey, error) {
 | |
| 	pemBlock, _ := pem.Decode(data)
 | |
| 	if pemBlock == nil {
 | |
| 		return nil, errors.New("unable to find PEM encoded data")
 | |
| 	} else if pemBlock.Type != "PUBLIC KEY" {
 | |
| 		return nil, fmt.Errorf("unable to get PublicKey from PEM type: %s", pemBlock.Type)
 | |
| 	}
 | |
| 
 | |
| 	return pubKeyFromPEMBlock(pemBlock)
 | |
| }
 | |
| 
 | |
| // UnmarshalPublicKeyPEMBundle parses the PEM encoded data as a bundle of
 | |
| // PEM blocks appended one after the other and returns a slice of PublicKey
 | |
| // objects that it finds.
 | |
| func UnmarshalPublicKeyPEMBundle(data []byte) ([]PublicKey, error) {
 | |
| 	pubKeys := []PublicKey{}
 | |
| 
 | |
| 	for {
 | |
| 		var pemBlock *pem.Block
 | |
| 		pemBlock, data = pem.Decode(data)
 | |
| 		if pemBlock == nil {
 | |
| 			break
 | |
| 		} else if pemBlock.Type != "PUBLIC KEY" {
 | |
| 			return nil, fmt.Errorf("unable to get PublicKey from PEM type: %s", pemBlock.Type)
 | |
| 		}
 | |
| 
 | |
| 		pubKey, err := pubKeyFromPEMBlock(pemBlock)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 
 | |
| 		pubKeys = append(pubKeys, pubKey)
 | |
| 	}
 | |
| 
 | |
| 	return pubKeys, nil
 | |
| }
 | |
| 
 | |
| // UnmarshalPrivateKeyPEM parses the PEM encoded data and returns a libtrust
 | |
| // PrivateKey or an error if there is a problem with the encoding.
 | |
| func UnmarshalPrivateKeyPEM(data []byte) (PrivateKey, error) {
 | |
| 	pemBlock, _ := pem.Decode(data)
 | |
| 	if pemBlock == nil {
 | |
| 		return nil, errors.New("unable to find PEM encoded data")
 | |
| 	}
 | |
| 
 | |
| 	var key PrivateKey
 | |
| 
 | |
| 	switch {
 | |
| 	case pemBlock.Type == "RSA PRIVATE KEY":
 | |
| 		rsaPrivateKey, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes)
 | |
| 		if err != nil {
 | |
| 			return nil, fmt.Errorf("unable to decode RSA Private Key PEM data: %s", err)
 | |
| 		}
 | |
| 		key = fromRSAPrivateKey(rsaPrivateKey)
 | |
| 	case pemBlock.Type == "EC PRIVATE KEY":
 | |
| 		ecPrivateKey, err := x509.ParseECPrivateKey(pemBlock.Bytes)
 | |
| 		if err != nil {
 | |
| 			return nil, fmt.Errorf("unable to decode EC Private Key PEM data: %s", err)
 | |
| 		}
 | |
| 		key, err = fromECPrivateKey(ecPrivateKey)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 	default:
 | |
| 		return nil, fmt.Errorf("unable to get PrivateKey from PEM type: %s", pemBlock.Type)
 | |
| 	}
 | |
| 
 | |
| 	addPEMHeadersToKey(pemBlock, key.PublicKey())
 | |
| 
 | |
| 	return key, nil
 | |
| }
 | |
| 
 | |
| // UnmarshalPublicKeyJWK unmarshals the given JSON Web Key into a generic
 | |
| // Public Key to be used with libtrust.
 | |
| func UnmarshalPublicKeyJWK(data []byte) (PublicKey, error) {
 | |
| 	jwk := make(map[string]interface{})
 | |
| 
 | |
| 	err := json.Unmarshal(data, &jwk)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf(
 | |
| 			"decoding JWK Public Key JSON data: %s\n", err,
 | |
| 		)
 | |
| 	}
 | |
| 
 | |
| 	// Get the Key Type value.
 | |
| 	kty, err := stringFromMap(jwk, "kty")
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("JWK Public Key type: %s", err)
 | |
| 	}
 | |
| 
 | |
| 	switch {
 | |
| 	case kty == "EC":
 | |
| 		// Call out to unmarshal EC public key.
 | |
| 		return ecPublicKeyFromMap(jwk)
 | |
| 	case kty == "RSA":
 | |
| 		// Call out to unmarshal RSA public key.
 | |
| 		return rsaPublicKeyFromMap(jwk)
 | |
| 	default:
 | |
| 		return nil, fmt.Errorf(
 | |
| 			"JWK Public Key type not supported: %q\n", kty,
 | |
| 		)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // UnmarshalPublicKeyJWKSet parses the JSON encoded data as a JSON Web Key Set
 | |
| // and returns a slice of Public Key objects.
 | |
| func UnmarshalPublicKeyJWKSet(data []byte) ([]PublicKey, error) {
 | |
| 	rawKeys, err := loadJSONKeySetRaw(data)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	pubKeys := make([]PublicKey, 0, len(rawKeys))
 | |
| 
 | |
| 	for _, rawKey := range rawKeys {
 | |
| 		pubKey, err := UnmarshalPublicKeyJWK(rawKey)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		pubKeys = append(pubKeys, pubKey)
 | |
| 	}
 | |
| 
 | |
| 	return pubKeys, nil
 | |
| }
 | |
| 
 | |
| // UnmarshalPrivateKeyJWK unmarshals the given JSON Web Key into a generic
 | |
| // Private Key to be used with libtrust.
 | |
| func UnmarshalPrivateKeyJWK(data []byte) (PrivateKey, error) {
 | |
| 	jwk := make(map[string]interface{})
 | |
| 
 | |
| 	err := json.Unmarshal(data, &jwk)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf(
 | |
| 			"decoding JWK Private Key JSON data: %s\n", err,
 | |
| 		)
 | |
| 	}
 | |
| 
 | |
| 	// Get the Key Type value.
 | |
| 	kty, err := stringFromMap(jwk, "kty")
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("JWK Private Key type: %s", err)
 | |
| 	}
 | |
| 
 | |
| 	switch {
 | |
| 	case kty == "EC":
 | |
| 		// Call out to unmarshal EC private key.
 | |
| 		return ecPrivateKeyFromMap(jwk)
 | |
| 	case kty == "RSA":
 | |
| 		// Call out to unmarshal RSA private key.
 | |
| 		return rsaPrivateKeyFromMap(jwk)
 | |
| 	default:
 | |
| 		return nil, fmt.Errorf(
 | |
| 			"JWK Private Key type not supported: %q\n", kty,
 | |
| 		)
 | |
| 	}
 | |
| }
 |