forked from toolshed/abra
		
	
		
			
				
	
	
		
			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,
 | 
						|
		)
 | 
						|
	}
 | 
						|
}
 |