ecdsa.go 5.5 KB

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