forked from toolshed/abra
		
	
		
			
				
	
	
		
			429 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			429 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package libtrust
 | |
| 
 | |
| import (
 | |
| 	"crypto"
 | |
| 	"crypto/ecdsa"
 | |
| 	"crypto/elliptic"
 | |
| 	"crypto/rand"
 | |
| 	"crypto/x509"
 | |
| 	"encoding/json"
 | |
| 	"encoding/pem"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"math/big"
 | |
| )
 | |
| 
 | |
| /*
 | |
|  * EC DSA PUBLIC KEY
 | |
|  */
 | |
| 
 | |
| // ecPublicKey implements a libtrust.PublicKey using elliptic curve digital
 | |
| // signature algorithms.
 | |
| type ecPublicKey struct {
 | |
| 	*ecdsa.PublicKey
 | |
| 	curveName          string
 | |
| 	signatureAlgorithm *signatureAlgorithm
 | |
| 	extended           map[string]interface{}
 | |
| }
 | |
| 
 | |
| func fromECPublicKey(cryptoPublicKey *ecdsa.PublicKey) (*ecPublicKey, error) {
 | |
| 	curve := cryptoPublicKey.Curve
 | |
| 
 | |
| 	switch {
 | |
| 	case curve == elliptic.P256():
 | |
| 		return &ecPublicKey{cryptoPublicKey, "P-256", es256, map[string]interface{}{}}, nil
 | |
| 	case curve == elliptic.P384():
 | |
| 		return &ecPublicKey{cryptoPublicKey, "P-384", es384, map[string]interface{}{}}, nil
 | |
| 	case curve == elliptic.P521():
 | |
| 		return &ecPublicKey{cryptoPublicKey, "P-521", es512, map[string]interface{}{}}, nil
 | |
| 	default:
 | |
| 		return nil, errors.New("unsupported elliptic curve")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // KeyType returns the key type for elliptic curve keys, i.e., "EC".
 | |
| func (k *ecPublicKey) KeyType() string {
 | |
| 	return "EC"
 | |
| }
 | |
| 
 | |
| // CurveName returns the elliptic curve identifier.
 | |
| // Possible values are "P-256", "P-384", and "P-521".
 | |
| func (k *ecPublicKey) CurveName() string {
 | |
| 	return k.curveName
 | |
| }
 | |
| 
 | |
| // KeyID returns a distinct identifier which is unique to this Public Key.
 | |
| func (k *ecPublicKey) KeyID() string {
 | |
| 	return keyIDFromCryptoKey(k)
 | |
| }
 | |
| 
 | |
| func (k *ecPublicKey) String() string {
 | |
| 	return fmt.Sprintf("EC Public Key <%s>", k.KeyID())
 | |
| }
 | |
| 
 | |
| // Verify verifyies the signature of the data in the io.Reader using this
 | |
| // PublicKey. 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.
 | |
| func (k *ecPublicKey) Verify(data io.Reader, alg string, signature []byte) error {
 | |
| 	// For EC keys there is only one supported signature algorithm depending
 | |
| 	// on the curve parameters.
 | |
| 	if k.signatureAlgorithm.HeaderParam() != alg {
 | |
| 		return fmt.Errorf("unable to verify signature: EC Public Key with curve %q does not support signature algorithm %q", k.curveName, alg)
 | |
| 	}
 | |
| 
 | |
| 	// signature is the concatenation of (r, s), base64Url encoded.
 | |
| 	sigLength := len(signature)
 | |
| 	expectedOctetLength := 2 * ((k.Params().BitSize + 7) >> 3)
 | |
| 	if sigLength != expectedOctetLength {
 | |
| 		return fmt.Errorf("signature length is %d octets long, should be %d", sigLength, expectedOctetLength)
 | |
| 	}
 | |
| 
 | |
| 	rBytes, sBytes := signature[:sigLength/2], signature[sigLength/2:]
 | |
| 	r := new(big.Int).SetBytes(rBytes)
 | |
| 	s := new(big.Int).SetBytes(sBytes)
 | |
| 
 | |
| 	hasher := k.signatureAlgorithm.HashID().New()
 | |
| 	_, err := io.Copy(hasher, data)
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("error reading data to sign: %s", err)
 | |
| 	}
 | |
| 	hash := hasher.Sum(nil)
 | |
| 
 | |
| 	if !ecdsa.Verify(k.PublicKey, hash, r, s) {
 | |
| 		return errors.New("invalid signature")
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // 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
 | |
| func (k *ecPublicKey) CryptoPublicKey() crypto.PublicKey {
 | |
| 	return k.PublicKey
 | |
| }
 | |
| 
 | |
| func (k *ecPublicKey) toMap() map[string]interface{} {
 | |
| 	jwk := make(map[string]interface{})
 | |
| 	for k, v := range k.extended {
 | |
| 		jwk[k] = v
 | |
| 	}
 | |
| 	jwk["kty"] = k.KeyType()
 | |
| 	jwk["kid"] = k.KeyID()
 | |
| 	jwk["crv"] = k.CurveName()
 | |
| 
 | |
| 	xBytes := k.X.Bytes()
 | |
| 	yBytes := k.Y.Bytes()
 | |
| 	octetLength := (k.Params().BitSize + 7) >> 3
 | |
| 	// MUST include leading zeros in the output so that x, y are each
 | |
| 	// *octetLength* bytes long.
 | |
| 	xBuf := make([]byte, octetLength-len(xBytes), octetLength)
 | |
| 	yBuf := make([]byte, octetLength-len(yBytes), octetLength)
 | |
| 	xBuf = append(xBuf, xBytes...)
 | |
| 	yBuf = append(yBuf, yBytes...)
 | |
| 
 | |
| 	jwk["x"] = joseBase64UrlEncode(xBuf)
 | |
| 	jwk["y"] = joseBase64UrlEncode(yBuf)
 | |
| 
 | |
| 	return jwk
 | |
| }
 | |
| 
 | |
| // MarshalJSON serializes this Public Key using the JWK JSON serialization format for
 | |
| // elliptic curve keys.
 | |
| func (k *ecPublicKey) MarshalJSON() (data []byte, err error) {
 | |
| 	return json.Marshal(k.toMap())
 | |
| }
 | |
| 
 | |
| // PEMBlock serializes this Public Key to DER-encoded PKIX format.
 | |
| func (k *ecPublicKey) PEMBlock() (*pem.Block, error) {
 | |
| 	derBytes, err := x509.MarshalPKIXPublicKey(k.PublicKey)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("unable to serialize EC PublicKey to DER-encoded PKIX format: %s", err)
 | |
| 	}
 | |
| 	k.extended["kid"] = k.KeyID() // For display purposes.
 | |
| 	return createPemBlock("PUBLIC KEY", derBytes, k.extended)
 | |
| }
 | |
| 
 | |
| func (k *ecPublicKey) AddExtendedField(field string, value interface{}) {
 | |
| 	k.extended[field] = value
 | |
| }
 | |
| 
 | |
| func (k *ecPublicKey) GetExtendedField(field string) interface{} {
 | |
| 	v, ok := k.extended[field]
 | |
| 	if !ok {
 | |
| 		return nil
 | |
| 	}
 | |
| 	return v
 | |
| }
 | |
| 
 | |
| func ecPublicKeyFromMap(jwk map[string]interface{}) (*ecPublicKey, error) {
 | |
| 	// JWK key type (kty) has already been determined to be "EC".
 | |
| 	// Need to extract 'crv', 'x', 'y', and 'kid' and check for
 | |
| 	// consistency.
 | |
| 
 | |
| 	// Get the curve identifier value.
 | |
| 	crv, err := stringFromMap(jwk, "crv")
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("JWK EC Public Key curve identifier: %s", err)
 | |
| 	}
 | |
| 
 | |
| 	var (
 | |
| 		curve  elliptic.Curve
 | |
| 		sigAlg *signatureAlgorithm
 | |
| 	)
 | |
| 
 | |
| 	switch {
 | |
| 	case crv == "P-256":
 | |
| 		curve = elliptic.P256()
 | |
| 		sigAlg = es256
 | |
| 	case crv == "P-384":
 | |
| 		curve = elliptic.P384()
 | |
| 		sigAlg = es384
 | |
| 	case crv == "P-521":
 | |
| 		curve = elliptic.P521()
 | |
| 		sigAlg = es512
 | |
| 	default:
 | |
| 		return nil, fmt.Errorf("JWK EC Public Key curve identifier not supported: %q\n", crv)
 | |
| 	}
 | |
| 
 | |
| 	// Get the X and Y coordinates for the public key point.
 | |
| 	xB64Url, err := stringFromMap(jwk, "x")
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("JWK EC Public Key x-coordinate: %s", err)
 | |
| 	}
 | |
| 	x, err := parseECCoordinate(xB64Url, curve)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("JWK EC Public Key x-coordinate: %s", err)
 | |
| 	}
 | |
| 
 | |
| 	yB64Url, err := stringFromMap(jwk, "y")
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("JWK EC Public Key y-coordinate: %s", err)
 | |
| 	}
 | |
| 	y, err := parseECCoordinate(yB64Url, curve)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("JWK EC Public Key y-coordinate: %s", err)
 | |
| 	}
 | |
| 
 | |
| 	key := &ecPublicKey{
 | |
| 		PublicKey: &ecdsa.PublicKey{Curve: curve, X: x, Y: y},
 | |
| 		curveName: crv, signatureAlgorithm: sigAlg,
 | |
| 	}
 | |
| 
 | |
| 	// Key ID is optional too, but if it exists, it should match the key.
 | |
| 	_, ok := jwk["kid"]
 | |
| 	if ok {
 | |
| 		kid, err := stringFromMap(jwk, "kid")
 | |
| 		if err != nil {
 | |
| 			return nil, fmt.Errorf("JWK EC Public Key ID: %s", err)
 | |
| 		}
 | |
| 		if kid != key.KeyID() {
 | |
| 			return nil, fmt.Errorf("JWK EC Public Key ID does not match: %s", kid)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	key.extended = jwk
 | |
| 
 | |
| 	return key, nil
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * EC DSA PRIVATE KEY
 | |
|  */
 | |
| 
 | |
| // ecPrivateKey implements a JWK Private Key using elliptic curve digital signature
 | |
| // algorithms.
 | |
| type ecPrivateKey struct {
 | |
| 	ecPublicKey
 | |
| 	*ecdsa.PrivateKey
 | |
| }
 | |
| 
 | |
| func fromECPrivateKey(cryptoPrivateKey *ecdsa.PrivateKey) (*ecPrivateKey, error) {
 | |
| 	publicKey, err := fromECPublicKey(&cryptoPrivateKey.PublicKey)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return &ecPrivateKey{*publicKey, cryptoPrivateKey}, nil
 | |
| }
 | |
| 
 | |
| // PublicKey returns the Public Key data associated with this Private Key.
 | |
| func (k *ecPrivateKey) PublicKey() PublicKey {
 | |
| 	return &k.ecPublicKey
 | |
| }
 | |
| 
 | |
| func (k *ecPrivateKey) String() string {
 | |
| 	return fmt.Sprintf("EC Private Key <%s>", k.KeyID())
 | |
| }
 | |
| 
 | |
| // Sign signs the data read from the io.Reader using a signature algorithm supported
 | |
| // by the elliptic curve 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 the name of the JWK signature algorithm used, e.g.,
 | |
| // "ES256", "ES384", "ES512".
 | |
| func (k *ecPrivateKey) Sign(data io.Reader, hashID crypto.Hash) (signature []byte, alg string, err error) {
 | |
| 	// Generate a signature of the data using the internal alg.
 | |
| 	// The given hashId is only a suggestion, and since EC keys only support
 | |
| 	// on signature/hash algorithm given the curve name, we disregard it for
 | |
| 	// the elliptic curve JWK signature implementation.
 | |
| 	hasher := k.signatureAlgorithm.HashID().New()
 | |
| 	_, err = io.Copy(hasher, data)
 | |
| 	if err != nil {
 | |
| 		return nil, "", fmt.Errorf("error reading data to sign: %s", err)
 | |
| 	}
 | |
| 	hash := hasher.Sum(nil)
 | |
| 
 | |
| 	r, s, err := ecdsa.Sign(rand.Reader, k.PrivateKey, hash)
 | |
| 	if err != nil {
 | |
| 		return nil, "", fmt.Errorf("error producing signature: %s", err)
 | |
| 	}
 | |
| 	rBytes, sBytes := r.Bytes(), s.Bytes()
 | |
| 	octetLength := (k.ecPublicKey.Params().BitSize + 7) >> 3
 | |
| 	// MUST include leading zeros in the output
 | |
| 	rBuf := make([]byte, octetLength-len(rBytes), octetLength)
 | |
| 	sBuf := make([]byte, octetLength-len(sBytes), octetLength)
 | |
| 
 | |
| 	rBuf = append(rBuf, rBytes...)
 | |
| 	sBuf = append(sBuf, sBytes...)
 | |
| 
 | |
| 	signature = append(rBuf, sBuf...)
 | |
| 	alg = k.signatureAlgorithm.HeaderParam()
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // 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
 | |
| func (k *ecPrivateKey) CryptoPrivateKey() crypto.PrivateKey {
 | |
| 	return k.PrivateKey
 | |
| }
 | |
| 
 | |
| func (k *ecPrivateKey) toMap() map[string]interface{} {
 | |
| 	jwk := k.ecPublicKey.toMap()
 | |
| 
 | |
| 	dBytes := k.D.Bytes()
 | |
| 	// The length of this octet string MUST be ceiling(log-base-2(n)/8)
 | |
| 	// octets (where n is the order of the curve). This is because the private
 | |
| 	// key d must be in the interval [1, n-1] so the bitlength of d should be
 | |
| 	// no larger than the bitlength of n-1. The easiest way to find the octet
 | |
| 	// length is to take bitlength(n-1), add 7 to force a carry, and shift this
 | |
| 	// bit sequence right by 3, which is essentially dividing by 8 and adding
 | |
| 	// 1 if there is any remainder. Thus, the private key value d should be
 | |
| 	// output to (bitlength(n-1)+7)>>3 octets.
 | |
| 	n := k.ecPublicKey.Params().N
 | |
| 	octetLength := (new(big.Int).Sub(n, big.NewInt(1)).BitLen() + 7) >> 3
 | |
| 	// Create a buffer with the necessary zero-padding.
 | |
| 	dBuf := make([]byte, octetLength-len(dBytes), octetLength)
 | |
| 	dBuf = append(dBuf, dBytes...)
 | |
| 
 | |
| 	jwk["d"] = joseBase64UrlEncode(dBuf)
 | |
| 
 | |
| 	return jwk
 | |
| }
 | |
| 
 | |
| // MarshalJSON serializes this Private Key using the JWK JSON serialization format for
 | |
| // elliptic curve keys.
 | |
| func (k *ecPrivateKey) MarshalJSON() (data []byte, err error) {
 | |
| 	return json.Marshal(k.toMap())
 | |
| }
 | |
| 
 | |
| // PEMBlock serializes this Private Key to DER-encoded PKIX format.
 | |
| func (k *ecPrivateKey) PEMBlock() (*pem.Block, error) {
 | |
| 	derBytes, err := x509.MarshalECPrivateKey(k.PrivateKey)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("unable to serialize EC PrivateKey to DER-encoded PKIX format: %s", err)
 | |
| 	}
 | |
| 	k.extended["keyID"] = k.KeyID() // For display purposes.
 | |
| 	return createPemBlock("EC PRIVATE KEY", derBytes, k.extended)
 | |
| }
 | |
| 
 | |
| func ecPrivateKeyFromMap(jwk map[string]interface{}) (*ecPrivateKey, error) {
 | |
| 	dB64Url, err := stringFromMap(jwk, "d")
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("JWK EC Private Key: %s", err)
 | |
| 	}
 | |
| 
 | |
| 	// JWK key type (kty) has already been determined to be "EC".
 | |
| 	// Need to extract the public key information, then extract the private
 | |
| 	// key value 'd'.
 | |
| 	publicKey, err := ecPublicKeyFromMap(jwk)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	d, err := parseECPrivateParam(dB64Url, publicKey.Curve)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("JWK EC Private Key d-param: %s", err)
 | |
| 	}
 | |
| 
 | |
| 	key := &ecPrivateKey{
 | |
| 		ecPublicKey: *publicKey,
 | |
| 		PrivateKey: &ecdsa.PrivateKey{
 | |
| 			PublicKey: *publicKey.PublicKey,
 | |
| 			D:         d,
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	return key, nil
 | |
| }
 | |
| 
 | |
| /*
 | |
|  *	Key Generation Functions.
 | |
|  */
 | |
| 
 | |
| func generateECPrivateKey(curve elliptic.Curve) (k *ecPrivateKey, err error) {
 | |
| 	k = new(ecPrivateKey)
 | |
| 	k.PrivateKey, err = ecdsa.GenerateKey(curve, rand.Reader)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	k.ecPublicKey.PublicKey = &k.PrivateKey.PublicKey
 | |
| 	k.extended = make(map[string]interface{})
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // GenerateECP256PrivateKey generates a key pair using elliptic curve P-256.
 | |
| func GenerateECP256PrivateKey() (PrivateKey, error) {
 | |
| 	k, err := generateECPrivateKey(elliptic.P256())
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("error generating EC P-256 key: %s", err)
 | |
| 	}
 | |
| 
 | |
| 	k.curveName = "P-256"
 | |
| 	k.signatureAlgorithm = es256
 | |
| 
 | |
| 	return k, nil
 | |
| }
 | |
| 
 | |
| // GenerateECP384PrivateKey generates a key pair using elliptic curve P-384.
 | |
| func GenerateECP384PrivateKey() (PrivateKey, error) {
 | |
| 	k, err := generateECPrivateKey(elliptic.P384())
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("error generating EC P-384 key: %s", err)
 | |
| 	}
 | |
| 
 | |
| 	k.curveName = "P-384"
 | |
| 	k.signatureAlgorithm = es384
 | |
| 
 | |
| 	return k, nil
 | |
| }
 | |
| 
 | |
| // GenerateECP521PrivateKey generates aß key pair using elliptic curve P-521.
 | |
| func GenerateECP521PrivateKey() (PrivateKey, error) {
 | |
| 	k, err := generateECPrivateKey(elliptic.P521())
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("error generating EC P-521 key: %s", err)
 | |
| 	}
 | |
| 
 | |
| 	k.curveName = "P-521"
 | |
| 	k.signatureAlgorithm = es512
 | |
| 
 | |
| 	return k, nil
 | |
| }
 |