您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. // Copyright 2015 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package acme
  5. import (
  6. "crypto"
  7. "crypto/ecdsa"
  8. "crypto/rand"
  9. "crypto/rsa"
  10. "crypto/sha256"
  11. _ "crypto/sha512" // need for EC keys
  12. "encoding/base64"
  13. "encoding/json"
  14. "fmt"
  15. "math/big"
  16. )
  17. // jwsEncodeJSON signs claimset using provided key and a nonce.
  18. // The result is serialized in JSON format.
  19. // See https://tools.ietf.org/html/rfc7515#section-7.
  20. func jwsEncodeJSON(claimset interface{}, key crypto.Signer, nonce string) ([]byte, error) {
  21. jwk, err := jwkEncode(key.Public())
  22. if err != nil {
  23. return nil, err
  24. }
  25. alg, sha := jwsHasher(key.Public())
  26. if alg == "" || !sha.Available() {
  27. return nil, ErrUnsupportedKey
  28. }
  29. phead := fmt.Sprintf(`{"alg":%q,"jwk":%s,"nonce":%q}`, alg, jwk, nonce)
  30. phead = base64.RawURLEncoding.EncodeToString([]byte(phead))
  31. cs, err := json.Marshal(claimset)
  32. if err != nil {
  33. return nil, err
  34. }
  35. payload := base64.RawURLEncoding.EncodeToString(cs)
  36. hash := sha.New()
  37. hash.Write([]byte(phead + "." + payload))
  38. sig, err := jwsSign(key, sha, hash.Sum(nil))
  39. if err != nil {
  40. return nil, err
  41. }
  42. enc := struct {
  43. Protected string `json:"protected"`
  44. Payload string `json:"payload"`
  45. Sig string `json:"signature"`
  46. }{
  47. Protected: phead,
  48. Payload: payload,
  49. Sig: base64.RawURLEncoding.EncodeToString(sig),
  50. }
  51. return json.Marshal(&enc)
  52. }
  53. // jwkEncode encodes public part of an RSA or ECDSA key into a JWK.
  54. // The result is also suitable for creating a JWK thumbprint.
  55. // https://tools.ietf.org/html/rfc7517
  56. func jwkEncode(pub crypto.PublicKey) (string, error) {
  57. switch pub := pub.(type) {
  58. case *rsa.PublicKey:
  59. // https://tools.ietf.org/html/rfc7518#section-6.3.1
  60. n := pub.N
  61. e := big.NewInt(int64(pub.E))
  62. // Field order is important.
  63. // See https://tools.ietf.org/html/rfc7638#section-3.3 for details.
  64. return fmt.Sprintf(`{"e":"%s","kty":"RSA","n":"%s"}`,
  65. base64.RawURLEncoding.EncodeToString(e.Bytes()),
  66. base64.RawURLEncoding.EncodeToString(n.Bytes()),
  67. ), nil
  68. case *ecdsa.PublicKey:
  69. // https://tools.ietf.org/html/rfc7518#section-6.2.1
  70. p := pub.Curve.Params()
  71. n := p.BitSize / 8
  72. if p.BitSize%8 != 0 {
  73. n++
  74. }
  75. x := pub.X.Bytes()
  76. if n > len(x) {
  77. x = append(make([]byte, n-len(x)), x...)
  78. }
  79. y := pub.Y.Bytes()
  80. if n > len(y) {
  81. y = append(make([]byte, n-len(y)), y...)
  82. }
  83. // Field order is important.
  84. // See https://tools.ietf.org/html/rfc7638#section-3.3 for details.
  85. return fmt.Sprintf(`{"crv":"%s","kty":"EC","x":"%s","y":"%s"}`,
  86. p.Name,
  87. base64.RawURLEncoding.EncodeToString(x),
  88. base64.RawURLEncoding.EncodeToString(y),
  89. ), nil
  90. }
  91. return "", ErrUnsupportedKey
  92. }
  93. // jwsSign signs the digest using the given key.
  94. // The hash is unused for ECDSA keys.
  95. //
  96. // Note: non-stdlib crypto.Signer implementations are expected to return
  97. // the signature in the format as specified in RFC7518.
  98. // See https://tools.ietf.org/html/rfc7518 for more details.
  99. func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) {
  100. if key, ok := key.(*ecdsa.PrivateKey); ok {
  101. // The key.Sign method of ecdsa returns ASN1-encoded signature.
  102. // So, we use the package Sign function instead
  103. // to get R and S values directly and format the result accordingly.
  104. r, s, err := ecdsa.Sign(rand.Reader, key, digest)
  105. if err != nil {
  106. return nil, err
  107. }
  108. rb, sb := r.Bytes(), s.Bytes()
  109. size := key.Params().BitSize / 8
  110. if size%8 > 0 {
  111. size++
  112. }
  113. sig := make([]byte, size*2)
  114. copy(sig[size-len(rb):], rb)
  115. copy(sig[size*2-len(sb):], sb)
  116. return sig, nil
  117. }
  118. return key.Sign(rand.Reader, digest, hash)
  119. }
  120. // jwsHasher indicates suitable JWS algorithm name and a hash function
  121. // to use for signing a digest with the provided key.
  122. // It returns ("", 0) if the key is not supported.
  123. func jwsHasher(pub crypto.PublicKey) (string, crypto.Hash) {
  124. switch pub := pub.(type) {
  125. case *rsa.PublicKey:
  126. return "RS256", crypto.SHA256
  127. case *ecdsa.PublicKey:
  128. switch pub.Params().Name {
  129. case "P-256":
  130. return "ES256", crypto.SHA256
  131. case "P-384":
  132. return "ES384", crypto.SHA384
  133. case "P-521":
  134. return "ES512", crypto.SHA512
  135. }
  136. }
  137. return "", 0
  138. }
  139. // JWKThumbprint creates a JWK thumbprint out of pub
  140. // as specified in https://tools.ietf.org/html/rfc7638.
  141. func JWKThumbprint(pub crypto.PublicKey) (string, error) {
  142. jwk, err := jwkEncode(pub)
  143. if err != nil {
  144. return "", err
  145. }
  146. b := sha256.Sum256([]byte(jwk))
  147. return base64.RawURLEncoding.EncodeToString(b[:]), nil
  148. }