1
2
3
4
5 package acme
6
7 import (
8 "crypto"
9 "crypto/ecdsa"
10 "crypto/elliptic"
11 "crypto/rsa"
12 "crypto/sha256"
13 "crypto/x509"
14 "encoding/base64"
15 "encoding/json"
16 "encoding/pem"
17 "fmt"
18 "io"
19 "math/big"
20 "testing"
21 )
22
23
24
25
26
27 const (
28
29
30
31
32
33
34
35 testKeyPEM = `
36 -----BEGIN RSA PRIVATE KEY-----
37 MIIEowIBAAKCAQEA4xgZ3eRPkwoRvy7qeRUbmMDe0V+xH9eWLdu0iheeLlrmD2mq
38 WXfP9IeSKApbn34g8TuAS9g5zhq8ELQ3kmjr+KV86GAMgI6VAcGlq3QrzpTCf/30
39 Ab7+zawrfRaFONa1HwEzPY1KHnGVkxJc85gNkwYI9SY2RHXtvln3zs5wITNrdosq
40 EXeaIkVYBEhbhNu54pp3kxo6TuWLi9e6pXeWetEwmlBwtWZlPoib2j3TxLBksKZf
41 oyFyek380mHgJAumQ/I2fjj98/97mk3ihOY4AgVdCDj1z/GCoZkG5Rq7nbCGyosy
42 KWyDX00Zs+nNqVhoLeIvXC4nnWdJMZ6rogxyQQIDAQABAoIBACIEZTOI1Kao9nmV
43 9IeIsuaR1Y61b9neOF/MLmIVIZu+AAJFCMB4Iw11FV6sFodwpEyeZhx2WkpWVN+H
44 r19eGiLX3zsL0DOdqBJoSIHDWCCMxgnYJ6nvS0nRxX3qVrBp8R2g12Ub+gNPbmFm
45 ecf/eeERIVxfifd9VsyRu34eDEvcmKFuLYbElFcPh62xE3x12UZvV/sN7gXbawpP
46 G+w255vbE5MoaKdnnO83cTFlcHvhn24M/78qP7Te5OAeelr1R89kYxQLpuGe4fbS
47 zc6E3ym5Td6urDetGGrSY1Eu10/8sMusX+KNWkm+RsBRbkyKq72ks/qKpOxOa+c6
48 9gm+Y8ECgYEA/iNUyg1ubRdH11p82l8KHtFC1DPE0V1gSZsX29TpM5jS4qv46K+s
49 8Ym1zmrORM8x+cynfPx1VQZQ34EYeCMIX212ryJ+zDATl4NE0I4muMvSiH9vx6Xc
50 7FmhNnaYzPsBL5Tm9nmtQuP09YEn8poiOJFiDs/4olnD5ogA5O4THGkCgYEA5MIL
51 qWYBUuqbEWLRtMruUtpASclrBqNNsJEsMGbeqBJmoMxdHeSZckbLOrqm7GlMyNRJ
52 Ne/5uWRGSzaMYuGmwsPpERzqEvYFnSrpjW5YtXZ+JtxFXNVfm9Z1gLLgvGpOUCIU
53 RbpoDckDe1vgUuk3y5+DjZihs+rqIJ45XzXTzBkCgYBWuf3segruJZy5rEKhTv+o
54 JqeUvRn0jNYYKFpLBeyTVBrbie6GkbUGNIWbrK05pC+c3K9nosvzuRUOQQL1tJbd
55 4gA3oiD9U4bMFNr+BRTHyZ7OQBcIXdz3t1qhuHVKtnngIAN1p25uPlbRFUNpshnt
56 jgeVoHlsBhApcs5DUc+pyQKBgDzeHPg/+g4z+nrPznjKnktRY1W+0El93kgi+J0Q
57 YiJacxBKEGTJ1MKBb8X6sDurcRDm22wMpGfd9I5Cv2v4GsUsF7HD/cx5xdih+G73
58 c4clNj/k0Ff5Nm1izPUno4C+0IOl7br39IPmfpSuR6wH/h6iHQDqIeybjxyKvT1G
59 N0rRAoGBAKGD+4ZI/E1MoJ5CXB8cDDMHagbE3cq/DtmYzE2v1DFpQYu5I4PCm5c7
60 EQeIP6dZtv8IMgtGIb91QX9pXvP0aznzQKwYIA8nZgoENCPfiMTPiEDT9e/0lObO
61 9XWsXpbSTsRPj0sv1rB+UzBJ0PgjK4q2zOF0sNo7b1+6nlM3BWPx
62 -----END RSA PRIVATE KEY-----
63 `
64
65
66 testKeyThumbprint = "6nicxzh6WETQlrvdchkz-U3e3DOQZ4heJKU63rfqMqQ"
67
68
69 testKeyECPEM = `
70 -----BEGIN EC PRIVATE KEY-----
71 MHcCAQEEIK07hGLr0RwyUdYJ8wbIiBS55CjnkMD23DWr+ccnypWLoAoGCCqGSM49
72 AwEHoUQDQgAE5lhEug5xK4xBDZ2nAbaxLtaLiv85bxJ7ePd1dkO23HThqIrvawF5
73 QAaS/RNouybCiRhRjI3EaxLkQwgrCw0gqQ==
74 -----END EC PRIVATE KEY-----
75 `
76
77 testKeyEC384PEM = `
78 -----BEGIN EC PRIVATE KEY-----
79 MIGkAgEBBDAQ4lNtXRORWr1bgKR1CGysr9AJ9SyEk4jiVnlUWWUChmSNL+i9SLSD
80 Oe/naPqXJ6CgBwYFK4EEACKhZANiAAQzKtj+Ms0vHoTX5dzv3/L5YMXOWuI5UKRj
81 JigpahYCqXD2BA1j0E/2xt5vlPf+gm0PL+UHSQsCokGnIGuaHCsJAp3ry0gHQEke
82 WYXapUUFdvaK1R2/2hn5O+eiQM8YzCg=
83 -----END EC PRIVATE KEY-----
84 `
85
86 testKeyEC512PEM = `
87 -----BEGIN EC PRIVATE KEY-----
88 MIHcAgEBBEIBSNZKFcWzXzB/aJClAb305ibalKgtDA7+70eEkdPt28/3LZMM935Z
89 KqYHh/COcxuu3Kt8azRAUz3gyr4zZKhlKUSgBwYFK4EEACOhgYkDgYYABAHUNKbx
90 7JwC7H6pa2sV0tERWhHhB3JmW+OP6SUgMWryvIKajlx73eS24dy4QPGrWO9/ABsD
91 FqcRSkNVTXnIv6+0mAF25knqIBIg5Q8M9BnOu9GGAchcwt3O7RDHmqewnJJDrbjd
92 GGnm6rb+NnWR9DIopM0nKNkToWoF/hzopxu4Ae/GsQ==
93 -----END EC PRIVATE KEY-----
94 `
95
96
97
98 testKeyECPubX = "5lhEug5xK4xBDZ2nAbaxLtaLiv85bxJ7ePd1dkO23HQ"
99 testKeyECPubY = "4aiK72sBeUAGkv0TaLsmwokYUYyNxGsS5EMIKwsNIKk"
100 testKeyEC384PubX = "MyrY_jLNLx6E1-Xc79_y-WDFzlriOVCkYyYoKWoWAqlw9gQNY9BP9sbeb5T3_oJt"
101 testKeyEC384PubY = "Dy_lB0kLAqJBpyBrmhwrCQKd68tIB0BJHlmF2qVFBXb2itUdv9oZ-TvnokDPGMwo"
102 testKeyEC512PubX = "AdQ0pvHsnALsfqlraxXS0RFaEeEHcmZb44_pJSAxavK8gpqOXHvd5Lbh3LhA8atY738AGwMWpxFKQ1VNeci_r7SY"
103 testKeyEC512PubY = "AXbmSeogEiDlDwz0Gc670YYByFzC3c7tEMeap7CckkOtuN0Yaebqtv42dZH0MiikzSco2ROhagX-HOinG7gB78ax"
104
105
106
107 testKeyECThumbprint = "zedj-Bd1Zshp8KLePv2MB-lJ_Hagp7wAwdkA0NUTniU"
108 )
109
110 var (
111 testKey *rsa.PrivateKey
112 testKeyEC *ecdsa.PrivateKey
113 testKeyEC384 *ecdsa.PrivateKey
114 testKeyEC512 *ecdsa.PrivateKey
115 )
116
117 func init() {
118 testKey = parseRSA(testKeyPEM, "testKeyPEM")
119 testKeyEC = parseEC(testKeyECPEM, "testKeyECPEM")
120 testKeyEC384 = parseEC(testKeyEC384PEM, "testKeyEC384PEM")
121 testKeyEC512 = parseEC(testKeyEC512PEM, "testKeyEC512PEM")
122 }
123
124 func decodePEM(s, name string) []byte {
125 d, _ := pem.Decode([]byte(s))
126 if d == nil {
127 panic("no block found in " + name)
128 }
129 return d.Bytes
130 }
131
132 func parseRSA(s, name string) *rsa.PrivateKey {
133 b := decodePEM(s, name)
134 k, err := x509.ParsePKCS1PrivateKey(b)
135 if err != nil {
136 panic(fmt.Sprintf("%s: %v", name, err))
137 }
138 return k
139 }
140
141 func parseEC(s, name string) *ecdsa.PrivateKey {
142 b := decodePEM(s, name)
143 k, err := x509.ParseECPrivateKey(b)
144 if err != nil {
145 panic(fmt.Sprintf("%s: %v", name, err))
146 }
147 return k
148 }
149
150 func TestJWSEncodeJSON(t *testing.T) {
151 claims := struct{ Msg string }{"Hello JWS"}
152
153
154 const (
155
156 protected = "eyJhbGciOiJSUzI1NiIsImp3ayI6eyJlIjoiQVFBQiIsImt0eSI6" +
157 "IlJTQSIsIm4iOiI0eGdaM2VSUGt3b1J2eTdxZVJVYm1NRGUwVi14" +
158 "SDllV0xkdTBpaGVlTGxybUQybXFXWGZQOUllU0tBcGJuMzRnOFR1" +
159 "QVM5ZzV6aHE4RUxRM2ttanItS1Y4NkdBTWdJNlZBY0dscTNRcnpw" +
160 "VENmXzMwQWI3LXphd3JmUmFGT05hMUh3RXpQWTFLSG5HVmt4SmM4" +
161 "NWdOa3dZSTlTWTJSSFh0dmxuM3pzNXdJVE5yZG9zcUVYZWFJa1ZZ" +
162 "QkVoYmhOdTU0cHAza3hvNlR1V0xpOWU2cFhlV2V0RXdtbEJ3dFda" +
163 "bFBvaWIyajNUeExCa3NLWmZveUZ5ZWszODBtSGdKQXVtUV9JMmZq" +
164 "ajk4Xzk3bWszaWhPWTRBZ1ZkQ0RqMXpfR0NvWmtHNVJxN25iQ0d5" +
165 "b3N5S1d5RFgwMFpzLW5OcVZob0xlSXZYQzRubldkSk1aNnJvZ3h5" +
166 "UVEifSwibm9uY2UiOiJub25jZSIsInVybCI6InVybCJ9"
167
168 payload = "eyJNc2ciOiJIZWxsbyBKV1MifQ"
169
170 signature = "YFyl_xz1E7TR-3E1bIuASTr424EgCvBHjt25WUFC2VaDjXYV0Rj_" +
171 "Hd3dJ_2IRqBrXDZZ2n4ZeA_4mm3QFwmwyeDwe2sWElhb82lCZ8iX" +
172 "uFnjeOmSOjx-nWwPa5ibCXzLq13zZ-OBV1Z4oN_TuailQeRoSfA3" +
173 "nO8gG52mv1x2OMQ5MAFtt8jcngBLzts4AyhI6mBJ2w7Yaj3ZCriq" +
174 "DWA3GLFvvHdW1Ba9Z01wtGT2CuZI7DUk_6Qj1b3BkBGcoKur5C9i" +
175 "bUJtCkABwBMvBQNyD3MmXsrRFRTgvVlyU_yMaucYm7nmzEr_2PaQ" +
176 "50rFt_9qOfJ4sfbLtG1Wwae57BQx1g"
177 )
178
179 b, err := jwsEncodeJSON(claims, testKey, noKeyID, "nonce", "url")
180 if err != nil {
181 t.Fatal(err)
182 }
183 var jws struct{ Protected, Payload, Signature string }
184 if err := json.Unmarshal(b, &jws); err != nil {
185 t.Fatal(err)
186 }
187 if jws.Protected != protected {
188 t.Errorf("protected:\n%s\nwant:\n%s", jws.Protected, protected)
189 }
190 if jws.Payload != payload {
191 t.Errorf("payload:\n%s\nwant:\n%s", jws.Payload, payload)
192 }
193 if jws.Signature != signature {
194 t.Errorf("signature:\n%s\nwant:\n%s", jws.Signature, signature)
195 }
196 }
197
198 func TestJWSEncodeNoNonce(t *testing.T) {
199 kid := KeyID("https://example.org/account/1")
200 claims := "RawString"
201 const (
202
203 protected = "eyJhbGciOiJFUzI1NiIsImtpZCI6Imh0dHBzOi8vZXhhbXBsZS5vcmcvYWNjb3VudC8xIiwidXJsIjoidXJsIn0"
204
205 payload = "RawString"
206 )
207
208 b, err := jwsEncodeJSON(claims, testKeyEC, kid, "", "url")
209 if err != nil {
210 t.Fatal(err)
211 }
212 var jws struct{ Protected, Payload, Signature string }
213 if err := json.Unmarshal(b, &jws); err != nil {
214 t.Fatal(err)
215 }
216 if jws.Protected != protected {
217 t.Errorf("protected:\n%s\nwant:\n%s", jws.Protected, protected)
218 }
219 if jws.Payload != payload {
220 t.Errorf("payload:\n%s\nwant:\n%s", jws.Payload, payload)
221 }
222
223 sig, err := base64.RawURLEncoding.DecodeString(jws.Signature)
224 if err != nil {
225 t.Fatalf("jws.Signature: %v", err)
226 }
227 r, s := big.NewInt(0), big.NewInt(0)
228 r.SetBytes(sig[:len(sig)/2])
229 s.SetBytes(sig[len(sig)/2:])
230 h := sha256.Sum256([]byte(protected + "." + payload))
231 if !ecdsa.Verify(testKeyEC.Public().(*ecdsa.PublicKey), h[:], r, s) {
232 t.Error("invalid signature")
233 }
234 }
235
236 func TestJWSEncodeKID(t *testing.T) {
237 kid := KeyID("https://example.org/account/1")
238 claims := struct{ Msg string }{"Hello JWS"}
239
240 const (
241
242 protected = "eyJhbGciOiJFUzI1NiIsImtpZCI6Imh0dHBzOi8vZXhhbXBsZS5" +
243 "vcmcvYWNjb3VudC8xIiwibm9uY2UiOiJub25jZSIsInVybCI6InVybCJ9"
244
245 payload = "eyJNc2ciOiJIZWxsbyBKV1MifQ"
246 )
247
248 b, err := jwsEncodeJSON(claims, testKeyEC, kid, "nonce", "url")
249 if err != nil {
250 t.Fatal(err)
251 }
252 var jws struct{ Protected, Payload, Signature string }
253 if err := json.Unmarshal(b, &jws); err != nil {
254 t.Fatal(err)
255 }
256 if jws.Protected != protected {
257 t.Errorf("protected:\n%s\nwant:\n%s", jws.Protected, protected)
258 }
259 if jws.Payload != payload {
260 t.Errorf("payload:\n%s\nwant:\n%s", jws.Payload, payload)
261 }
262
263 sig, err := base64.RawURLEncoding.DecodeString(jws.Signature)
264 if err != nil {
265 t.Fatalf("jws.Signature: %v", err)
266 }
267 r, s := big.NewInt(0), big.NewInt(0)
268 r.SetBytes(sig[:len(sig)/2])
269 s.SetBytes(sig[len(sig)/2:])
270 h := sha256.Sum256([]byte(protected + "." + payload))
271 if !ecdsa.Verify(testKeyEC.Public().(*ecdsa.PublicKey), h[:], r, s) {
272 t.Error("invalid signature")
273 }
274 }
275
276 func TestJWSEncodeJSONEC(t *testing.T) {
277 tt := []struct {
278 key *ecdsa.PrivateKey
279 x, y string
280 alg, crv string
281 }{
282 {testKeyEC, testKeyECPubX, testKeyECPubY, "ES256", "P-256"},
283 {testKeyEC384, testKeyEC384PubX, testKeyEC384PubY, "ES384", "P-384"},
284 {testKeyEC512, testKeyEC512PubX, testKeyEC512PubY, "ES512", "P-521"},
285 }
286 for i, test := range tt {
287 claims := struct{ Msg string }{"Hello JWS"}
288 b, err := jwsEncodeJSON(claims, test.key, noKeyID, "nonce", "url")
289 if err != nil {
290 t.Errorf("%d: %v", i, err)
291 continue
292 }
293 var jws struct{ Protected, Payload, Signature string }
294 if err := json.Unmarshal(b, &jws); err != nil {
295 t.Errorf("%d: %v", i, err)
296 continue
297 }
298
299 b, err = base64.RawURLEncoding.DecodeString(jws.Protected)
300 if err != nil {
301 t.Errorf("%d: jws.Protected: %v", i, err)
302 }
303 var head struct {
304 Alg string
305 Nonce string
306 URL string `json:"url"`
307 KID string `json:"kid"`
308 JWK struct {
309 Crv string
310 Kty string
311 X string
312 Y string
313 } `json:"jwk"`
314 }
315 if err := json.Unmarshal(b, &head); err != nil {
316 t.Errorf("%d: jws.Protected: %v", i, err)
317 }
318 if head.Alg != test.alg {
319 t.Errorf("%d: head.Alg = %q; want %q", i, head.Alg, test.alg)
320 }
321 if head.Nonce != "nonce" {
322 t.Errorf("%d: head.Nonce = %q; want nonce", i, head.Nonce)
323 }
324 if head.URL != "url" {
325 t.Errorf("%d: head.URL = %q; want 'url'", i, head.URL)
326 }
327 if head.KID != "" {
328
329 t.Errorf("%d: head.KID = %q; want empty", i, head.KID)
330 }
331 if head.JWK.Crv != test.crv {
332 t.Errorf("%d: head.JWK.Crv = %q; want %q", i, head.JWK.Crv, test.crv)
333 }
334 if head.JWK.Kty != "EC" {
335 t.Errorf("%d: head.JWK.Kty = %q; want EC", i, head.JWK.Kty)
336 }
337 if head.JWK.X != test.x {
338 t.Errorf("%d: head.JWK.X = %q; want %q", i, head.JWK.X, test.x)
339 }
340 if head.JWK.Y != test.y {
341 t.Errorf("%d: head.JWK.Y = %q; want %q", i, head.JWK.Y, test.y)
342 }
343 }
344 }
345
346 type customTestSigner struct {
347 sig []byte
348 pub crypto.PublicKey
349 }
350
351 func (s *customTestSigner) Public() crypto.PublicKey { return s.pub }
352 func (s *customTestSigner) Sign(io.Reader, []byte, crypto.SignerOpts) ([]byte, error) {
353 return s.sig, nil
354 }
355
356 func TestJWSEncodeJSONCustom(t *testing.T) {
357 claims := struct{ Msg string }{"hello"}
358 const (
359
360 payload = "eyJNc2ciOiJoZWxsbyJ9"
361
362 testsig = "dGVzdHNpZw"
363
364
365
366 es256stdsig = "MEUCIA7RIVN5Y2xIPC9/FVgH1AKjsigDOvl8fheBmsMWnqZlAiEA" +
367 "xQoH04w8cOXY8S2vCEpUgKZlkMXyk1Cajz9/ioOjVNU"
368
369 es256jwsig = "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw" +
370 "5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q"
371
372
373 es256phead = "eyJhbGciOiJFUzI1NiIsImp3ayI6eyJjcnYiOiJQLTI1NiIsImt0" +
374 "eSI6IkVDIiwieCI6IjVsaEV1ZzV4SzR4QkRaMm5BYmF4THRhTGl2" +
375 "ODVieEo3ZVBkMWRrTzIzSFEiLCJ5IjoiNGFpSzcyc0JlVUFHa3Yw" +
376 "VGFMc213b2tZVVl5TnhHc1M1RU1JS3dzTklLayJ9LCJub25jZSI6" +
377 "Im5vbmNlIiwidXJsIjoidXJsIn0"
378
379
380 rs256phead = "eyJhbGciOiJSUzI1NiIsImp3ayI6eyJlIjoiQVFBQiIsImt0eSI6" +
381 "IlJTQSIsIm4iOiI0eGdaM2VSUGt3b1J2eTdxZVJVYm1NRGUwVi14" +
382 "SDllV0xkdTBpaGVlTGxybUQybXFXWGZQOUllU0tBcGJuMzRnOFR1" +
383 "QVM5ZzV6aHE4RUxRM2ttanItS1Y4NkdBTWdJNlZBY0dscTNRcnpw" +
384 "VENmXzMwQWI3LXphd3JmUmFGT05hMUh3RXpQWTFLSG5HVmt4SmM4" +
385 "NWdOa3dZSTlTWTJSSFh0dmxuM3pzNXdJVE5yZG9zcUVYZWFJa1ZZ" +
386 "QkVoYmhOdTU0cHAza3hvNlR1V0xpOWU2cFhlV2V0RXdtbEJ3dFda" +
387 "bFBvaWIyajNUeExCa3NLWmZveUZ5ZWszODBtSGdKQXVtUV9JMmZq" +
388 "ajk4Xzk3bWszaWhPWTRBZ1ZkQ0RqMXpfR0NvWmtHNVJxN25iQ0d5" +
389 "b3N5S1d5RFgwMFpzLW5OcVZob0xlSXZYQzRubldkSk1aNnJvZ3h5" +
390 "UVEifSwibm9uY2UiOiJub25jZSIsInVybCI6InVybCJ9"
391 )
392
393 tt := []struct {
394 alg, phead string
395 pub crypto.PublicKey
396 stdsig, jwsig string
397 }{
398 {"ES256", es256phead, testKeyEC.Public(), es256stdsig, es256jwsig},
399 {"RS256", rs256phead, testKey.Public(), testsig, testsig},
400 }
401 for _, tc := range tt {
402 tc := tc
403 t.Run(tc.alg, func(t *testing.T) {
404 stdsig, err := base64.RawStdEncoding.DecodeString(tc.stdsig)
405 if err != nil {
406 t.Errorf("couldn't decode test vector: %v", err)
407 }
408 signer := &customTestSigner{
409 sig: stdsig,
410 pub: tc.pub,
411 }
412
413 b, err := jwsEncodeJSON(claims, signer, noKeyID, "nonce", "url")
414 if err != nil {
415 t.Fatal(err)
416 }
417 var j jsonWebSignature
418 if err := json.Unmarshal(b, &j); err != nil {
419 t.Fatal(err)
420 }
421 if j.Protected != tc.phead {
422 t.Errorf("j.Protected = %q\nwant %q", j.Protected, tc.phead)
423 }
424 if j.Payload != payload {
425 t.Errorf("j.Payload = %q\nwant %q", j.Payload, payload)
426 }
427 if j.Sig != tc.jwsig {
428 t.Errorf("j.Sig = %q\nwant %q", j.Sig, tc.jwsig)
429 }
430 })
431 }
432 }
433
434 func TestJWSWithMAC(t *testing.T) {
435
436
437 b64Key := "hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg"
438 rawPayload := []byte("It\xe2\x80\x99s a dangerous business, Frodo, going out your " +
439 "door. You step onto the road, and if you don't keep your feet, " +
440 "there\xe2\x80\x99s no knowing where you might be swept off " +
441 "to.")
442 protected := "eyJhbGciOiJIUzI1NiIsImtpZCI6IjAxOGMwYWU1LTRkOWItNDcxYi1iZmQ2LW" +
443 "VlZjMxNGJjNzAzNyJ9"
444 payload := "SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywg" +
445 "Z29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9h" +
446 "ZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXi" +
447 "gJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9m" +
448 "ZiB0by4"
449 sig := "s0h6KThzkfBBBkLspW1h84VsJZFTsPPqMDA7g1Md7p0"
450
451 key, err := base64.RawURLEncoding.DecodeString(b64Key)
452 if err != nil {
453 t.Fatalf("unable to decode key: %q", b64Key)
454 }
455 got, err := jwsWithMAC(key, "018c0ae5-4d9b-471b-bfd6-eef314bc7037", "", rawPayload)
456 if err != nil {
457 t.Fatalf("jwsWithMAC() = %q", err)
458 }
459 if got.Protected != protected {
460 t.Errorf("got.Protected = %q\nwant %q", got.Protected, protected)
461 }
462 if got.Payload != payload {
463 t.Errorf("got.Payload = %q\nwant %q", got.Payload, payload)
464 }
465 if got.Sig != sig {
466 t.Errorf("got.Signature = %q\nwant %q", got.Sig, sig)
467 }
468 }
469
470 func TestJWSWithMACError(t *testing.T) {
471 p := "{}"
472 if _, err := jwsWithMAC(nil, "", "", []byte(p)); err == nil {
473 t.Errorf("jwsWithMAC(nil, ...) = success; want err")
474 }
475 }
476
477 func TestJWKThumbprintRSA(t *testing.T) {
478
479 const base64N = "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAt" +
480 "VT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn6" +
481 "4tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FD" +
482 "W2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n9" +
483 "1CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINH" +
484 "aQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw"
485 const base64E = "AQAB"
486 const expected = "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs"
487
488 b, err := base64.RawURLEncoding.DecodeString(base64N)
489 if err != nil {
490 t.Fatalf("Error parsing example key N: %v", err)
491 }
492 n := new(big.Int).SetBytes(b)
493
494 b, err = base64.RawURLEncoding.DecodeString(base64E)
495 if err != nil {
496 t.Fatalf("Error parsing example key E: %v", err)
497 }
498 e := new(big.Int).SetBytes(b)
499
500 pub := &rsa.PublicKey{N: n, E: int(e.Uint64())}
501 th, err := JWKThumbprint(pub)
502 if err != nil {
503 t.Error(err)
504 }
505 if th != expected {
506 t.Errorf("thumbprint = %q; want %q", th, expected)
507 }
508 }
509
510 func TestJWKThumbprintEC(t *testing.T) {
511
512
513
514
515 const (
516 base64X = "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9A5RkT" +
517 "KqjqvjyekWF-7ytDyRXYgCF5cj0Kt"
518 base64Y = "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVySsUda" +
519 "QkAgDPrwQrJmbnX9cwlGfP-HqHZR1"
520 expected = "dHri3SADZkrush5HU_50AoRhcKFryN-PI6jPBtPL55M"
521 )
522
523 b, err := base64.RawURLEncoding.DecodeString(base64X)
524 if err != nil {
525 t.Fatalf("Error parsing example key X: %v", err)
526 }
527 x := new(big.Int).SetBytes(b)
528
529 b, err = base64.RawURLEncoding.DecodeString(base64Y)
530 if err != nil {
531 t.Fatalf("Error parsing example key Y: %v", err)
532 }
533 y := new(big.Int).SetBytes(b)
534
535 pub := &ecdsa.PublicKey{Curve: elliptic.P521(), X: x, Y: y}
536 th, err := JWKThumbprint(pub)
537 if err != nil {
538 t.Error(err)
539 }
540 if th != expected {
541 t.Errorf("thumbprint = %q; want %q", th, expected)
542 }
543 }
544
545 func TestJWKThumbprintErrUnsupportedKey(t *testing.T) {
546 _, err := JWKThumbprint(struct{}{})
547 if err != ErrUnsupportedKey {
548 t.Errorf("err = %q; want %q", err, ErrUnsupportedKey)
549 }
550 }
551
View as plain text