| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 |
- package jwk
- import (
- "crypto"
- "crypto/ecdsa"
- "crypto/elliptic"
- "encoding/json"
- "fmt"
- "math/big"
- "github.com/lestrrat/go-jwx/internal/base64"
- "github.com/lestrrat/go-jwx/jwa"
- pdebug "github.com/lestrrat/go-pdebug"
- "github.com/pkg/errors"
- )
- func newECDSAPublicKey(key *ecdsa.PublicKey) (*ECDSAPublicKey, error) {
- if key == nil {
- return nil, errors.New(`non-nil ecdsa.PublicKey required`)
- }
- var hdr StandardHeaders
- hdr.Set(KeyTypeKey, jwa.EC)
- return &ECDSAPublicKey{
- headers: &hdr,
- key: key,
- }, nil
- }
- func newECDSAPrivateKey(key *ecdsa.PrivateKey) (*ECDSAPrivateKey, error) {
- if key == nil {
- return nil, errors.New(`non-nil ecdsa.PrivateKey required`)
- }
- var hdr StandardHeaders
- hdr.Set(KeyTypeKey, jwa.EC)
- return &ECDSAPrivateKey{
- headers: &hdr,
- key: key,
- }, nil
- }
- func (k ECDSAPrivateKey) PublicKey() (*ECDSAPublicKey, error) {
- return newECDSAPublicKey(&k.key.PublicKey)
- }
- // Materialize returns the EC-DSA public key represented by this JWK
- func (k ECDSAPublicKey) Materialize() (interface{}, error) {
- return k.key, nil
- }
- func (k ECDSAPublicKey) Curve() jwa.EllipticCurveAlgorithm {
- return jwa.EllipticCurveAlgorithm(k.key.Curve.Params().Name)
- }
- func (k ECDSAPrivateKey) Curve() jwa.EllipticCurveAlgorithm {
- return jwa.EllipticCurveAlgorithm(k.key.PublicKey.Curve.Params().Name)
- }
- func ecdsaThumbprint(hash crypto.Hash, crv, x, y string) []byte {
- h := hash.New()
- fmt.Fprintf(h, `{"crv":"`)
- fmt.Fprintf(h, crv)
- fmt.Fprintf(h, `","kty":"EC","x":"`)
- fmt.Fprintf(h, x)
- fmt.Fprintf(h, `","y":"`)
- fmt.Fprintf(h, y)
- fmt.Fprintf(h, `"}`)
- return h.Sum(nil)
- }
- // Thumbprint returns the JWK thumbprint using the indicated
- // hashing algorithm, according to RFC 7638
- func (k ECDSAPublicKey) Thumbprint(hash crypto.Hash) ([]byte, error) {
- return ecdsaThumbprint(
- hash,
- k.key.Curve.Params().Name,
- base64.EncodeToString(k.key.X.Bytes()),
- base64.EncodeToString(k.key.Y.Bytes()),
- ), nil
- }
- // Thumbprint returns the JWK thumbprint using the indicated
- // hashing algorithm, according to RFC 7638
- func (k ECDSAPrivateKey) Thumbprint(hash crypto.Hash) ([]byte, error) {
- return ecdsaThumbprint(
- hash,
- k.key.Curve.Params().Name,
- base64.EncodeToString(k.key.X.Bytes()),
- base64.EncodeToString(k.key.Y.Bytes()),
- ), nil
- }
- // Materialize returns the EC-DSA private key represented by this JWK
- func (k ECDSAPrivateKey) Materialize() (interface{}, error) {
- return k.key, nil
- }
- func (k ECDSAPublicKey) MarshalJSON() (buf []byte, err error) {
- if pdebug.Enabled {
- g := pdebug.Marker("jwk.ECDSAPublicKey.MarshalJSON").BindError(&err)
- defer g.End()
- }
- m := make(map[string]interface{})
- if err := k.PopulateMap(m); err != nil {
- return nil, errors.Wrap(err, `failed to populate pulibc key values`)
- }
- return json.Marshal(m)
- }
- func (k ECDSAPublicKey) PopulateMap(m map[string]interface{}) (err error) {
- if pdebug.Enabled {
- g := pdebug.Marker("jwk.ECDSAPublicKey.PopulateJSON").BindError(&err)
- defer g.End()
- }
- if err := k.headers.PopulateMap(m); err != nil {
- return errors.Wrap(err, `failed to populate header values`)
- }
- const (
- xKey = `x`
- yKey = `y`
- crvKey = `crv`
- )
- m[xKey] = base64.EncodeToString(k.key.X.Bytes())
- m[yKey] = base64.EncodeToString(k.key.Y.Bytes())
- m[crvKey] = k.key.Curve.Params().Name
- return nil
- }
- func (k ECDSAPrivateKey) MarshalJSON() (buf []byte, err error) {
- if pdebug.Enabled {
- g := pdebug.Marker("jwk.ECDSAPrivateKey.MarshalJSON").BindError(&err)
- defer g.End()
- }
- m := make(map[string]interface{})
- if err := k.PopulateMap(m); err != nil {
- return nil, errors.Wrap(err, `failed to populate pulibc key values`)
- }
- return json.Marshal(m)
- }
- func (k ECDSAPrivateKey) PopulateMap(m map[string]interface{}) (err error) {
- if pdebug.Enabled {
- g := pdebug.Marker("jwk.ECDSAPrivateKey.PopulateJSON").BindError(&err)
- defer g.End()
- }
- if err := k.headers.PopulateMap(m); err != nil {
- return errors.Wrap(err, `failed to populate header values`)
- }
- pubkey, err := newECDSAPublicKey(&k.key.PublicKey)
- if err != nil {
- return errors.Wrap(err, `failed to construct public key from private key`)
- }
- if err := pubkey.PopulateMap(m); err != nil {
- return errors.Wrap(err, `failed to populate public key values`)
- }
- m[`d`] = base64.EncodeToString(k.key.D.Bytes())
- return nil
- }
- func (k *ECDSAPublicKey) UnmarshalJSON(data []byte) (err error) {
- if pdebug.Enabled {
- g := pdebug.Marker("jwk.ECDSAPublicKey.UnmarshalJSON").BindError(&err)
- defer g.End()
- }
- m := map[string]interface{}{}
- if err := json.Unmarshal(data, &m); err != nil {
- return errors.Wrap(err, `failed to unmarshal public key`)
- }
- if err := k.ExtractMap(m); err != nil {
- return errors.Wrap(err, `failed to extract data from map`)
- }
- return nil
- }
- func (k *ECDSAPublicKey) ExtractMap(m map[string]interface{}) (err error) {
- if pdebug.Enabled {
- g := pdebug.Marker("jwk.ECDSAPublicKey.ExtractMap").BindError(&err)
- defer g.End()
- }
- const (
- xKey = `x`
- yKey = `y`
- crvKey = `crv`
- )
- crvname, ok := m[crvKey]
- if !ok {
- return errors.Errorf(`failed to get required key crv`)
- }
- delete(m, crvKey)
- var crv jwa.EllipticCurveAlgorithm
- if err := crv.Accept(crvname); err != nil {
- return errors.Wrap(err, `failed to accept value for crv key`)
- }
- var curve elliptic.Curve
- switch crv {
- case jwa.P256:
- curve = elliptic.P256()
- case jwa.P384:
- curve = elliptic.P384()
- case jwa.P521:
- curve = elliptic.P521()
- default:
- return errors.Errorf(`invalid curve name %s`, crv)
- }
- xbuf, err := getRequiredKey(m, xKey)
- if err != nil {
- return errors.Wrapf(err, `failed to get required key %s`, xKey)
- }
- delete(m, xKey)
- ybuf, err := getRequiredKey(m, yKey)
- if err != nil {
- return errors.Wrapf(err, `failed to get required key %s`, yKey)
- }
- delete(m, yKey)
- var x, y big.Int
- x.SetBytes(xbuf)
- y.SetBytes(ybuf)
- var hdrs StandardHeaders
- if err := hdrs.ExtractMap(m); err != nil {
- return errors.Wrap(err, `failed to extract header values`)
- }
- *k = ECDSAPublicKey{
- headers: &hdrs,
- key: &ecdsa.PublicKey{
- Curve: curve,
- X: &x,
- Y: &y,
- },
- }
- return nil
- }
- func (k *ECDSAPrivateKey) UnmarshalJSON(data []byte) (err error) {
- if pdebug.Enabled {
- g := pdebug.Marker("jwk.ECDSAPrivateKey.UnmarshalJSON").BindError(&err)
- defer g.End()
- }
- m := map[string]interface{}{}
- if err := json.Unmarshal(data, &m); err != nil {
- return errors.Wrap(err, `failed to unmarshal public key`)
- }
- if err := k.ExtractMap(m); err != nil {
- return errors.Wrap(err, `failed to extract data from map`)
- }
- return nil
- }
- func (k *ECDSAPrivateKey) ExtractMap(m map[string]interface{}) (err error) {
- if pdebug.Enabled {
- g := pdebug.Marker("jwk.ECDSAPrivateKey.ExtractMap").BindError(&err)
- defer g.End()
- }
- const (
- dKey = `d`
- )
- dbuf, err := getRequiredKey(m, dKey)
- if err != nil {
- return errors.Wrapf(err, `failed to get required key %s`, dKey)
- }
- delete(m, dKey)
- var pubkey ECDSAPublicKey
- if err := pubkey.ExtractMap(m); err != nil {
- return errors.Wrap(err, `failed to extract public key values`)
- }
- var d big.Int
- d.SetBytes(dbuf)
- *k = ECDSAPrivateKey{
- headers: pubkey.headers,
- key: &ecdsa.PrivateKey{
- PublicKey: *(pubkey.key),
- D: &d,
- },
- }
- pubkey.headers = nil
- return nil
- }
|