Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

267 linhas
8.7 KiB

  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/ecdsa"
  7. "crypto/elliptic"
  8. "crypto/rsa"
  9. "crypto/x509"
  10. "encoding/base64"
  11. "encoding/json"
  12. "encoding/pem"
  13. "math/big"
  14. "testing"
  15. )
  16. const testKeyPEM = `
  17. -----BEGIN RSA PRIVATE KEY-----
  18. MIIEowIBAAKCAQEA4xgZ3eRPkwoRvy7qeRUbmMDe0V+xH9eWLdu0iheeLlrmD2mq
  19. WXfP9IeSKApbn34g8TuAS9g5zhq8ELQ3kmjr+KV86GAMgI6VAcGlq3QrzpTCf/30
  20. Ab7+zawrfRaFONa1HwEzPY1KHnGVkxJc85gNkwYI9SY2RHXtvln3zs5wITNrdosq
  21. EXeaIkVYBEhbhNu54pp3kxo6TuWLi9e6pXeWetEwmlBwtWZlPoib2j3TxLBksKZf
  22. oyFyek380mHgJAumQ/I2fjj98/97mk3ihOY4AgVdCDj1z/GCoZkG5Rq7nbCGyosy
  23. KWyDX00Zs+nNqVhoLeIvXC4nnWdJMZ6rogxyQQIDAQABAoIBACIEZTOI1Kao9nmV
  24. 9IeIsuaR1Y61b9neOF/MLmIVIZu+AAJFCMB4Iw11FV6sFodwpEyeZhx2WkpWVN+H
  25. r19eGiLX3zsL0DOdqBJoSIHDWCCMxgnYJ6nvS0nRxX3qVrBp8R2g12Ub+gNPbmFm
  26. ecf/eeERIVxfifd9VsyRu34eDEvcmKFuLYbElFcPh62xE3x12UZvV/sN7gXbawpP
  27. G+w255vbE5MoaKdnnO83cTFlcHvhn24M/78qP7Te5OAeelr1R89kYxQLpuGe4fbS
  28. zc6E3ym5Td6urDetGGrSY1Eu10/8sMusX+KNWkm+RsBRbkyKq72ks/qKpOxOa+c6
  29. 9gm+Y8ECgYEA/iNUyg1ubRdH11p82l8KHtFC1DPE0V1gSZsX29TpM5jS4qv46K+s
  30. 8Ym1zmrORM8x+cynfPx1VQZQ34EYeCMIX212ryJ+zDATl4NE0I4muMvSiH9vx6Xc
  31. 7FmhNnaYzPsBL5Tm9nmtQuP09YEn8poiOJFiDs/4olnD5ogA5O4THGkCgYEA5MIL
  32. qWYBUuqbEWLRtMruUtpASclrBqNNsJEsMGbeqBJmoMxdHeSZckbLOrqm7GlMyNRJ
  33. Ne/5uWRGSzaMYuGmwsPpERzqEvYFnSrpjW5YtXZ+JtxFXNVfm9Z1gLLgvGpOUCIU
  34. RbpoDckDe1vgUuk3y5+DjZihs+rqIJ45XzXTzBkCgYBWuf3segruJZy5rEKhTv+o
  35. JqeUvRn0jNYYKFpLBeyTVBrbie6GkbUGNIWbrK05pC+c3K9nosvzuRUOQQL1tJbd
  36. 4gA3oiD9U4bMFNr+BRTHyZ7OQBcIXdz3t1qhuHVKtnngIAN1p25uPlbRFUNpshnt
  37. jgeVoHlsBhApcs5DUc+pyQKBgDzeHPg/+g4z+nrPznjKnktRY1W+0El93kgi+J0Q
  38. YiJacxBKEGTJ1MKBb8X6sDurcRDm22wMpGfd9I5Cv2v4GsUsF7HD/cx5xdih+G73
  39. c4clNj/k0Ff5Nm1izPUno4C+0IOl7br39IPmfpSuR6wH/h6iHQDqIeybjxyKvT1G
  40. N0rRAoGBAKGD+4ZI/E1MoJ5CXB8cDDMHagbE3cq/DtmYzE2v1DFpQYu5I4PCm5c7
  41. EQeIP6dZtv8IMgtGIb91QX9pXvP0aznzQKwYIA8nZgoENCPfiMTPiEDT9e/0lObO
  42. 9XWsXpbSTsRPj0sv1rB+UzBJ0PgjK4q2zOF0sNo7b1+6nlM3BWPx
  43. -----END RSA PRIVATE KEY-----
  44. `
  45. // This thumbprint is for the testKey defined above.
  46. const testKeyThumbprint = "6nicxzh6WETQlrvdchkz-U3e3DOQZ4heJKU63rfqMqQ"
  47. const (
  48. // openssl ecparam -name secp256k1 -genkey -noout
  49. testKeyECPEM = `
  50. -----BEGIN EC PRIVATE KEY-----
  51. MHcCAQEEIK07hGLr0RwyUdYJ8wbIiBS55CjnkMD23DWr+ccnypWLoAoGCCqGSM49
  52. AwEHoUQDQgAE5lhEug5xK4xBDZ2nAbaxLtaLiv85bxJ7ePd1dkO23HThqIrvawF5
  53. QAaS/RNouybCiRhRjI3EaxLkQwgrCw0gqQ==
  54. -----END EC PRIVATE KEY-----
  55. `
  56. // 1. opnessl ec -in key.pem -noout -text
  57. // 2. remove first byte, 04 (the header); the rest is X and Y
  58. // 3. covert each with: echo <val> | xxd -r -p | base64 | tr -d '=' | tr '/+' '_-'
  59. testKeyECPubX = "5lhEug5xK4xBDZ2nAbaxLtaLiv85bxJ7ePd1dkO23HQ"
  60. testKeyECPubY = "4aiK72sBeUAGkv0TaLsmwokYUYyNxGsS5EMIKwsNIKk"
  61. // echo -n '{"crv":"P-256","kty":"EC","x":"<testKeyECPubX>","y":"<testKeyECPubY>"}' | \
  62. // openssl dgst -binary -sha256 | base64 | tr -d '=' | tr '/+' '_-'
  63. testKeyECThumbprint = "zedj-Bd1Zshp8KLePv2MB-lJ_Hagp7wAwdkA0NUTniU"
  64. )
  65. var (
  66. testKey *rsa.PrivateKey
  67. testKeyEC *ecdsa.PrivateKey
  68. )
  69. func init() {
  70. d, _ := pem.Decode([]byte(testKeyPEM))
  71. if d == nil {
  72. panic("no block found in testKeyPEM")
  73. }
  74. var err error
  75. testKey, err = x509.ParsePKCS1PrivateKey(d.Bytes)
  76. if err != nil {
  77. panic(err.Error())
  78. }
  79. if d, _ = pem.Decode([]byte(testKeyECPEM)); d == nil {
  80. panic("no block found in testKeyECPEM")
  81. }
  82. testKeyEC, err = x509.ParseECPrivateKey(d.Bytes)
  83. if err != nil {
  84. panic(err.Error())
  85. }
  86. }
  87. func TestJWSEncodeJSON(t *testing.T) {
  88. claims := struct{ Msg string }{"Hello JWS"}
  89. // JWS signed with testKey and "nonce" as the nonce value
  90. // JSON-serialized JWS fields are split for easier testing
  91. const (
  92. // {"alg":"RS256","jwk":{"e":"AQAB","kty":"RSA","n":"..."},"nonce":"nonce"}
  93. protected = "eyJhbGciOiJSUzI1NiIsImp3ayI6eyJlIjoiQVFBQiIsImt0eSI6" +
  94. "IlJTQSIsIm4iOiI0eGdaM2VSUGt3b1J2eTdxZVJVYm1NRGUwVi14" +
  95. "SDllV0xkdTBpaGVlTGxybUQybXFXWGZQOUllU0tBcGJuMzRnOFR1" +
  96. "QVM5ZzV6aHE4RUxRM2ttanItS1Y4NkdBTWdJNlZBY0dscTNRcnpw" +
  97. "VENmXzMwQWI3LXphd3JmUmFGT05hMUh3RXpQWTFLSG5HVmt4SmM4" +
  98. "NWdOa3dZSTlTWTJSSFh0dmxuM3pzNXdJVE5yZG9zcUVYZWFJa1ZZ" +
  99. "QkVoYmhOdTU0cHAza3hvNlR1V0xpOWU2cFhlV2V0RXdtbEJ3dFda" +
  100. "bFBvaWIyajNUeExCa3NLWmZveUZ5ZWszODBtSGdKQXVtUV9JMmZq" +
  101. "ajk4Xzk3bWszaWhPWTRBZ1ZkQ0RqMXpfR0NvWmtHNVJxN25iQ0d5" +
  102. "b3N5S1d5RFgwMFpzLW5OcVZob0xlSXZYQzRubldkSk1aNnJvZ3h5" +
  103. "UVEifSwibm9uY2UiOiJub25jZSJ9"
  104. // {"Msg":"Hello JWS"}
  105. payload = "eyJNc2ciOiJIZWxsbyBKV1MifQ"
  106. signature = "eAGUikStX_UxyiFhxSLMyuyBcIB80GeBkFROCpap2sW3EmkU_ggF" +
  107. "knaQzxrTfItICSAXsCLIquZ5BbrSWA_4vdEYrwWtdUj7NqFKjHRa" +
  108. "zpLHcoR7r1rEHvkoP1xj49lS5fc3Wjjq8JUhffkhGbWZ8ZVkgPdC" +
  109. "4tMBWiQDoth-x8jELP_3LYOB_ScUXi2mETBawLgOT2K8rA0Vbbmx" +
  110. "hWNlOWuUf-8hL5YX4IOEwsS8JK_TrTq5Zc9My0zHJmaieqDV0UlP" +
  111. "k0onFjPFkGm7MrPSgd0MqRG-4vSAg2O4hDo7rKv4n8POjjXlNQvM" +
  112. "9IPLr8qZ7usYBKhEGwX3yq_eicAwBw"
  113. )
  114. b, err := jwsEncodeJSON(claims, testKey, "nonce")
  115. if err != nil {
  116. t.Fatal(err)
  117. }
  118. var jws struct{ Protected, Payload, Signature string }
  119. if err := json.Unmarshal(b, &jws); err != nil {
  120. t.Fatal(err)
  121. }
  122. if jws.Protected != protected {
  123. t.Errorf("protected:\n%s\nwant:\n%s", jws.Protected, protected)
  124. }
  125. if jws.Payload != payload {
  126. t.Errorf("payload:\n%s\nwant:\n%s", jws.Payload, payload)
  127. }
  128. if jws.Signature != signature {
  129. t.Errorf("signature:\n%s\nwant:\n%s", jws.Signature, signature)
  130. }
  131. }
  132. func TestJWSEncodeJSONEC(t *testing.T) {
  133. claims := struct{ Msg string }{"Hello JWS"}
  134. b, err := jwsEncodeJSON(claims, testKeyEC, "nonce")
  135. if err != nil {
  136. t.Fatal(err)
  137. }
  138. var jws struct{ Protected, Payload, Signature string }
  139. if err := json.Unmarshal(b, &jws); err != nil {
  140. t.Fatal(err)
  141. }
  142. if b, err = base64.RawURLEncoding.DecodeString(jws.Protected); err != nil {
  143. t.Fatalf("jws.Protected: %v", err)
  144. }
  145. var head struct {
  146. Alg string
  147. Nonce string
  148. JWK struct {
  149. Crv string
  150. Kty string
  151. X string
  152. Y string
  153. } `json:"jwk"`
  154. }
  155. if err := json.Unmarshal(b, &head); err != nil {
  156. t.Fatalf("jws.Protected: %v", err)
  157. }
  158. if head.Alg != "ES256" {
  159. t.Errorf("head.Alg = %q; want ES256", head.Alg)
  160. }
  161. if head.Nonce != "nonce" {
  162. t.Errorf("head.Nonce = %q; want nonce", head.Nonce)
  163. }
  164. if head.JWK.Crv != "P-256" {
  165. t.Errorf("head.JWK.Crv = %q; want P-256", head.JWK.Crv)
  166. }
  167. if head.JWK.Kty != "EC" {
  168. t.Errorf("head.JWK.Kty = %q; want EC", head.JWK.Kty)
  169. }
  170. if head.JWK.X != testKeyECPubX {
  171. t.Errorf("head.JWK.X = %q; want %q", head.JWK.X, testKeyECPubX)
  172. }
  173. if head.JWK.Y != testKeyECPubY {
  174. t.Errorf("head.JWK.Y = %q; want %q", head.JWK.Y, testKeyECPubY)
  175. }
  176. }
  177. func TestJWKThumbprintRSA(t *testing.T) {
  178. // Key example from RFC 7638
  179. const base64N = "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAt" +
  180. "VT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn6" +
  181. "4tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FD" +
  182. "W2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n9" +
  183. "1CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINH" +
  184. "aQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw"
  185. const base64E = "AQAB"
  186. const expected = "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs"
  187. b, err := base64.RawURLEncoding.DecodeString(base64N)
  188. if err != nil {
  189. t.Fatalf("Error parsing example key N: %v", err)
  190. }
  191. n := new(big.Int).SetBytes(b)
  192. b, err = base64.RawURLEncoding.DecodeString(base64E)
  193. if err != nil {
  194. t.Fatalf("Error parsing example key E: %v", err)
  195. }
  196. e := new(big.Int).SetBytes(b)
  197. pub := &rsa.PublicKey{N: n, E: int(e.Uint64())}
  198. th, err := JWKThumbprint(pub)
  199. if err != nil {
  200. t.Error(err)
  201. }
  202. if th != expected {
  203. t.Errorf("thumbprint = %q; want %q", th, expected)
  204. }
  205. }
  206. func TestJWKThumbprintEC(t *testing.T) {
  207. // Key example from RFC 7520
  208. // expected was computed with
  209. // echo -n '{"crv":"P-521","kty":"EC","x":"<base64X>","y":"<base64Y>"}' | \
  210. // openssl dgst -binary -sha256 | \
  211. // base64 | \
  212. // tr -d '=' | tr '/+' '_-'
  213. const (
  214. base64X = "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9A5RkT" +
  215. "KqjqvjyekWF-7ytDyRXYgCF5cj0Kt"
  216. base64Y = "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVySsUda" +
  217. "QkAgDPrwQrJmbnX9cwlGfP-HqHZR1"
  218. expected = "dHri3SADZkrush5HU_50AoRhcKFryN-PI6jPBtPL55M"
  219. )
  220. b, err := base64.RawURLEncoding.DecodeString(base64X)
  221. if err != nil {
  222. t.Fatalf("Error parsing example key X: %v", err)
  223. }
  224. x := new(big.Int).SetBytes(b)
  225. b, err = base64.RawURLEncoding.DecodeString(base64Y)
  226. if err != nil {
  227. t.Fatalf("Error parsing example key Y: %v", err)
  228. }
  229. y := new(big.Int).SetBytes(b)
  230. pub := &ecdsa.PublicKey{Curve: elliptic.P521(), X: x, Y: y}
  231. th, err := JWKThumbprint(pub)
  232. if err != nil {
  233. t.Error(err)
  234. }
  235. if th != expected {
  236. t.Errorf("thumbprint = %q; want %q", th, expected)
  237. }
  238. }
  239. func TestJWKThumbprintErrUnsupportedKey(t *testing.T) {
  240. _, err := JWKThumbprint(struct{}{})
  241. if err != ErrUnsupportedKey {
  242. t.Errorf("err = %q; want %q", err, ErrUnsupportedKey)
  243. }
  244. }