...

Source file src/github.com/lestrrat-go/jwx/jwk/ecdsa.go

Documentation: github.com/lestrrat-go/jwx/jwk

     1  package jwk
     2  
     3  import (
     4  	"crypto"
     5  	"crypto/ecdsa"
     6  	"crypto/elliptic"
     7  	"fmt"
     8  	"math/big"
     9  
    10  	"github.com/lestrrat-go/blackmagic"
    11  	"github.com/lestrrat-go/jwx/internal/base64"
    12  	"github.com/lestrrat-go/jwx/internal/ecutil"
    13  	"github.com/lestrrat-go/jwx/jwa"
    14  	"github.com/pkg/errors"
    15  )
    16  
    17  func init() {
    18  	ecutil.RegisterCurve(elliptic.P256(), jwa.P256)
    19  	ecutil.RegisterCurve(elliptic.P384(), jwa.P384)
    20  	ecutil.RegisterCurve(elliptic.P521(), jwa.P521)
    21  }
    22  
    23  func (k *ecdsaPublicKey) FromRaw(rawKey *ecdsa.PublicKey) error {
    24  	k.mu.Lock()
    25  	defer k.mu.Unlock()
    26  
    27  	if rawKey.X == nil {
    28  		return errors.Errorf(`invalid ecdsa.PublicKey`)
    29  	}
    30  
    31  	if rawKey.Y == nil {
    32  		return errors.Errorf(`invalid ecdsa.PublicKey`)
    33  	}
    34  
    35  	xbuf := ecutil.AllocECPointBuffer(rawKey.X, rawKey.Curve)
    36  	ybuf := ecutil.AllocECPointBuffer(rawKey.Y, rawKey.Curve)
    37  	defer ecutil.ReleaseECPointBuffer(xbuf)
    38  	defer ecutil.ReleaseECPointBuffer(ybuf)
    39  
    40  	k.x = make([]byte, len(xbuf))
    41  	copy(k.x, xbuf)
    42  	k.y = make([]byte, len(ybuf))
    43  	copy(k.y, ybuf)
    44  
    45  	var crv jwa.EllipticCurveAlgorithm
    46  	if tmp, ok := ecutil.AlgorithmForCurve(rawKey.Curve); ok {
    47  		crv = tmp
    48  	} else {
    49  		return errors.Errorf(`invalid elliptic curve %s`, rawKey.Curve)
    50  	}
    51  	k.crv = &crv
    52  
    53  	return nil
    54  }
    55  
    56  func (k *ecdsaPrivateKey) FromRaw(rawKey *ecdsa.PrivateKey) error {
    57  	k.mu.Lock()
    58  	defer k.mu.Unlock()
    59  
    60  	if rawKey.PublicKey.X == nil {
    61  		return errors.Errorf(`invalid ecdsa.PrivateKey`)
    62  	}
    63  	if rawKey.PublicKey.Y == nil {
    64  		return errors.Errorf(`invalid ecdsa.PrivateKey`)
    65  	}
    66  	if rawKey.D == nil {
    67  		return errors.Errorf(`invalid ecdsa.PrivateKey`)
    68  	}
    69  
    70  	xbuf := ecutil.AllocECPointBuffer(rawKey.PublicKey.X, rawKey.Curve)
    71  	ybuf := ecutil.AllocECPointBuffer(rawKey.PublicKey.Y, rawKey.Curve)
    72  	dbuf := ecutil.AllocECPointBuffer(rawKey.D, rawKey.Curve)
    73  	defer ecutil.ReleaseECPointBuffer(xbuf)
    74  	defer ecutil.ReleaseECPointBuffer(ybuf)
    75  	defer ecutil.ReleaseECPointBuffer(dbuf)
    76  
    77  	k.x = make([]byte, len(xbuf))
    78  	copy(k.x, xbuf)
    79  	k.y = make([]byte, len(ybuf))
    80  	copy(k.y, ybuf)
    81  	k.d = make([]byte, len(dbuf))
    82  	copy(k.d, dbuf)
    83  
    84  	var crv jwa.EllipticCurveAlgorithm
    85  	if tmp, ok := ecutil.AlgorithmForCurve(rawKey.Curve); ok {
    86  		crv = tmp
    87  	} else {
    88  		return errors.Errorf(`invalid elliptic curve %s`, rawKey.Curve)
    89  	}
    90  	k.crv = &crv
    91  
    92  	return nil
    93  }
    94  
    95  func buildECDSAPublicKey(alg jwa.EllipticCurveAlgorithm, xbuf, ybuf []byte) (*ecdsa.PublicKey, error) {
    96  	var crv elliptic.Curve
    97  	if tmp, ok := ecutil.CurveForAlgorithm(alg); ok {
    98  		crv = tmp
    99  	} else {
   100  		return nil, errors.Errorf(`invalid curve algorithm %s`, alg)
   101  	}
   102  
   103  	var x, y big.Int
   104  	x.SetBytes(xbuf)
   105  	y.SetBytes(ybuf)
   106  
   107  	return &ecdsa.PublicKey{Curve: crv, X: &x, Y: &y}, nil
   108  }
   109  
   110  // Raw returns the EC-DSA public key represented by this JWK
   111  func (k *ecdsaPublicKey) Raw(v interface{}) error {
   112  	k.mu.RLock()
   113  	defer k.mu.RUnlock()
   114  
   115  	pubk, err := buildECDSAPublicKey(k.Crv(), k.x, k.y)
   116  	if err != nil {
   117  		return errors.Wrap(err, `failed to build public key`)
   118  	}
   119  
   120  	return blackmagic.AssignIfCompatible(v, pubk)
   121  }
   122  
   123  func (k *ecdsaPrivateKey) Raw(v interface{}) error {
   124  	k.mu.RLock()
   125  	defer k.mu.RUnlock()
   126  
   127  	pubk, err := buildECDSAPublicKey(k.Crv(), k.x, k.y)
   128  	if err != nil {
   129  		return errors.Wrap(err, `failed to build public key`)
   130  	}
   131  
   132  	var key ecdsa.PrivateKey
   133  	var d big.Int
   134  	d.SetBytes(k.d)
   135  	key.D = &d
   136  	key.PublicKey = *pubk
   137  
   138  	return blackmagic.AssignIfCompatible(v, &key)
   139  }
   140  
   141  func makeECDSAPublicKey(v interface {
   142  	makePairs() []*HeaderPair
   143  }) (Key, error) {
   144  	newKey := NewECDSAPublicKey()
   145  
   146  	// Iterate and copy everything except for the bits that should not be in the public key
   147  	for _, pair := range v.makePairs() {
   148  		switch pair.Key {
   149  		case ECDSADKey:
   150  			continue
   151  		default:
   152  			//nolint:forcetypeassert
   153  			key := pair.Key.(string)
   154  			if err := newKey.Set(key, pair.Value); err != nil {
   155  				return nil, errors.Wrapf(err, `failed to set field %q`, key)
   156  			}
   157  		}
   158  	}
   159  
   160  	return newKey, nil
   161  }
   162  
   163  func (k *ecdsaPrivateKey) PublicKey() (Key, error) {
   164  	return makeECDSAPublicKey(k)
   165  }
   166  
   167  func (k *ecdsaPublicKey) PublicKey() (Key, error) {
   168  	return makeECDSAPublicKey(k)
   169  }
   170  
   171  func ecdsaThumbprint(hash crypto.Hash, crv, x, y string) []byte {
   172  	h := hash.New()
   173  	fmt.Fprint(h, `{"crv":"`)
   174  	fmt.Fprint(h, crv)
   175  	fmt.Fprint(h, `","kty":"EC","x":"`)
   176  	fmt.Fprint(h, x)
   177  	fmt.Fprint(h, `","y":"`)
   178  	fmt.Fprint(h, y)
   179  	fmt.Fprint(h, `"}`)
   180  	return h.Sum(nil)
   181  }
   182  
   183  // Thumbprint returns the JWK thumbprint using the indicated
   184  // hashing algorithm, according to RFC 7638
   185  func (k ecdsaPublicKey) Thumbprint(hash crypto.Hash) ([]byte, error) {
   186  	k.mu.RLock()
   187  	defer k.mu.RUnlock()
   188  
   189  	var key ecdsa.PublicKey
   190  	if err := k.Raw(&key); err != nil {
   191  		return nil, errors.Wrap(err, `failed to materialize ecdsa.PublicKey for thumbprint generation`)
   192  	}
   193  
   194  	xbuf := ecutil.AllocECPointBuffer(key.X, key.Curve)
   195  	ybuf := ecutil.AllocECPointBuffer(key.Y, key.Curve)
   196  	defer ecutil.ReleaseECPointBuffer(xbuf)
   197  	defer ecutil.ReleaseECPointBuffer(ybuf)
   198  
   199  	return ecdsaThumbprint(
   200  		hash,
   201  		key.Curve.Params().Name,
   202  		base64.EncodeToString(xbuf),
   203  		base64.EncodeToString(ybuf),
   204  	), nil
   205  }
   206  
   207  // Thumbprint returns the JWK thumbprint using the indicated
   208  // hashing algorithm, according to RFC 7638
   209  func (k ecdsaPrivateKey) Thumbprint(hash crypto.Hash) ([]byte, error) {
   210  	k.mu.RLock()
   211  	defer k.mu.RUnlock()
   212  
   213  	var key ecdsa.PrivateKey
   214  	if err := k.Raw(&key); err != nil {
   215  		return nil, errors.Wrap(err, `failed to materialize ecdsa.PrivateKey for thumbprint generation`)
   216  	}
   217  
   218  	xbuf := ecutil.AllocECPointBuffer(key.X, key.Curve)
   219  	ybuf := ecutil.AllocECPointBuffer(key.Y, key.Curve)
   220  	defer ecutil.ReleaseECPointBuffer(xbuf)
   221  	defer ecutil.ReleaseECPointBuffer(ybuf)
   222  
   223  	return ecdsaThumbprint(
   224  		hash,
   225  		key.Curve.Params().Name,
   226  		base64.EncodeToString(xbuf),
   227  		base64.EncodeToString(ybuf),
   228  	), nil
   229  }
   230  

View as plain text