1/*-
2 * Copyright 2014 Square Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package jose
18
19import (
20	"bytes"
21	"crypto"
22	"crypto/ecdsa"
23	"crypto/elliptic"
24	"crypto/rsa"
25	"crypto/x509"
26	"encoding/hex"
27	"math/big"
28	"reflect"
29	"strings"
30	"testing"
31
32	"github.com/stretchr/testify/assert"
33	"golang.org/x/crypto/ed25519"
34
35	"gopkg.in/square/go-jose.v2/json"
36)
37
38// Test chain of two X.509 certificates
39var testCertificates, _ = x509.ParseCertificates(fromBase64Bytes(`
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`))
79
80func TestCurveSize(t *testing.T) {
81	size256 := curveSize(elliptic.P256())
82	size384 := curveSize(elliptic.P384())
83	size521 := curveSize(elliptic.P521())
84	if size256 != 32 {
85		t.Error("P-256 have 32 bytes")
86	}
87	if size384 != 48 {
88		t.Error("P-384 have 48 bytes")
89	}
90	if size521 != 66 {
91		t.Error("P-521 have 66 bytes")
92	}
93}
94
95func TestRoundtripRsaPrivate(t *testing.T) {
96	jwk, err := fromRsaPrivateKey(rsaTestKey)
97	if err != nil {
98		t.Error("problem constructing JWK from rsa key", err)
99	}
100
101	rsa2, err := jwk.rsaPrivateKey()
102	if err != nil {
103		t.Error("problem converting RSA private -> JWK", err)
104	}
105
106	if rsa2.N.Cmp(rsaTestKey.N) != 0 {
107		t.Error("RSA private N mismatch")
108	}
109	if rsa2.E != rsaTestKey.E {
110		t.Error("RSA private E mismatch")
111	}
112	if rsa2.D.Cmp(rsaTestKey.D) != 0 {
113		t.Error("RSA private D mismatch")
114	}
115	if len(rsa2.Primes) != 2 {
116		t.Error("RSA private roundtrip expected two primes")
117	}
118	if rsa2.Primes[0].Cmp(rsaTestKey.Primes[0]) != 0 {
119		t.Error("RSA private P mismatch")
120	}
121	if rsa2.Primes[1].Cmp(rsaTestKey.Primes[1]) != 0 {
122		t.Error("RSA private Q mismatch")
123	}
124}
125
126func TestRoundtripRsaPrivatePrecomputed(t *testing.T) {
127	// Isolate a shallow copy of the rsaTestKey to avoid polluting it with Precompute
128	localKey := &(*rsaTestKey)
129	localKey.Precompute()
130
131	jwk, err := fromRsaPrivateKey(localKey)
132	if err != nil {
133		t.Error("problem constructing JWK from rsa key", err)
134	}
135
136	rsa2, err := jwk.rsaPrivateKey()
137	if err != nil {
138		t.Error("problem converting RSA private -> JWK", err)
139	}
140
141	if rsa2.Precomputed.Dp == nil {
142		t.Error("RSA private Dp nil")
143	}
144	if rsa2.Precomputed.Dq == nil {
145		t.Error("RSA private Dq nil")
146	}
147	if rsa2.Precomputed.Qinv == nil {
148		t.Error("RSA private Qinv nil")
149	}
150
151	if rsa2.Precomputed.Dp.Cmp(localKey.Precomputed.Dp) != 0 {
152		t.Error("RSA private Dp mismatch")
153	}
154	if rsa2.Precomputed.Dq.Cmp(localKey.Precomputed.Dq) != 0 {
155		t.Error("RSA private Dq mismatch")
156	}
157	if rsa2.Precomputed.Qinv.Cmp(localKey.Precomputed.Qinv) != 0 {
158		t.Error("RSA private Qinv mismatch")
159	}
160}
161
162func TestRsaPrivateInsufficientPrimes(t *testing.T) {
163	brokenRsaPrivateKey := rsa.PrivateKey{
164		PublicKey: rsa.PublicKey{
165			N: rsaTestKey.N,
166			E: rsaTestKey.E,
167		},
168		D:      rsaTestKey.D,
169		Primes: []*big.Int{rsaTestKey.Primes[0]},
170	}
171
172	_, err := fromRsaPrivateKey(&brokenRsaPrivateKey)
173	if err != ErrUnsupportedKeyType {
174		t.Error("expected unsupported key type error, got", err)
175	}
176}
177
178func TestRsaPrivateExcessPrimes(t *testing.T) {
179	brokenRsaPrivateKey := rsa.PrivateKey{
180		PublicKey: rsa.PublicKey{
181			N: rsaTestKey.N,
182			E: rsaTestKey.E,
183		},
184		D: rsaTestKey.D,
185		Primes: []*big.Int{
186			rsaTestKey.Primes[0],
187			rsaTestKey.Primes[1],
188			big.NewInt(3),
189		},
190	}
191
192	_, err := fromRsaPrivateKey(&brokenRsaPrivateKey)
193	if err != ErrUnsupportedKeyType {
194		t.Error("expected unsupported key type error, got", err)
195	}
196}
197
198func TestRoundtripEcPublic(t *testing.T) {
199	for i, ecTestKey := range []*ecdsa.PrivateKey{ecTestKey256, ecTestKey384, ecTestKey521} {
200		jwk, err := fromEcPublicKey(&ecTestKey.PublicKey)
201
202		ec2, err := jwk.ecPublicKey()
203		if err != nil {
204			t.Error("problem converting ECDSA private -> JWK", i, err)
205		}
206
207		if !reflect.DeepEqual(ec2.Curve, ecTestKey.Curve) {
208			t.Error("ECDSA private curve mismatch", i)
209		}
210		if ec2.X.Cmp(ecTestKey.X) != 0 {
211			t.Error("ECDSA X mismatch", i)
212		}
213		if ec2.Y.Cmp(ecTestKey.Y) != 0 {
214			t.Error("ECDSA Y mismatch", i)
215		}
216	}
217}
218
219func TestRoundtripEcPrivate(t *testing.T) {
220	for i, ecTestKey := range []*ecdsa.PrivateKey{ecTestKey256, ecTestKey384, ecTestKey521} {
221		jwk, err := fromEcPrivateKey(ecTestKey)
222
223		ec2, err := jwk.ecPrivateKey()
224		if err != nil {
225			t.Fatalf("problem converting ECDSA private -> JWK for %#v: %s", ecTestKey, err)
226		}
227
228		if !reflect.DeepEqual(ec2.Curve, ecTestKey.Curve) {
229			t.Error("ECDSA private curve mismatch", i)
230		}
231		if ec2.X.Cmp(ecTestKey.X) != 0 {
232			t.Error("ECDSA X mismatch", i)
233		}
234		if ec2.Y.Cmp(ecTestKey.Y) != 0 {
235			t.Error("ECDSA Y mismatch", i)
236		}
237		if ec2.D.Cmp(ecTestKey.D) != 0 {
238			t.Error("ECDSA D mismatch", i)
239		}
240	}
241}
242
243func TestRoundtripX5C(t *testing.T) {
244	jwk := JSONWebKey{
245		Key:          rsaTestKey,
246		KeyID:        "bar",
247		Algorithm:    "foo",
248		Certificates: testCertificates,
249	}
250
251	jsonbar, err := jwk.MarshalJSON()
252	if err != nil {
253		t.Error("problem marshaling", err)
254	}
255
256	var jwk2 JSONWebKey
257	err = jwk2.UnmarshalJSON(jsonbar)
258	if err != nil {
259		t.Fatal("problem unmarshalling", err)
260	}
261
262	if !reflect.DeepEqual(testCertificates, jwk2.Certificates) {
263		t.Error("Certificates not equal", jwk.Certificates, jwk2.Certificates)
264	}
265
266	jsonbar2, err := jwk2.MarshalJSON()
267	if err != nil {
268		t.Error("problem marshaling", err)
269	}
270	if !bytes.Equal(jsonbar, jsonbar2) {
271		t.Error("roundtrip should not lose information")
272	}
273}
274
275func TestMarshalUnmarshal(t *testing.T) {
276	kid := "DEADBEEF"
277
278	for i, key := range []interface{}{ecTestKey256, ecTestKey384, ecTestKey521, rsaTestKey, ed25519PrivateKey} {
279		for _, use := range []string{"", "sig", "enc"} {
280			jwk := JSONWebKey{Key: key, KeyID: kid, Algorithm: "foo"}
281			if use != "" {
282				jwk.Use = use
283			}
284
285			jsonbar, err := jwk.MarshalJSON()
286			if err != nil {
287				t.Error("problem marshaling", i, err)
288			}
289
290			var jwk2 JSONWebKey
291			err = jwk2.UnmarshalJSON(jsonbar)
292			if err != nil {
293				t.Fatal("problem unmarshalling", i, err)
294			}
295
296			jsonbar2, err := jwk2.MarshalJSON()
297			if err != nil {
298				t.Fatal("problem marshaling", i, err)
299			}
300
301			if !bytes.Equal(jsonbar, jsonbar2) {
302				t.Error("roundtrip should not lose information", i)
303			}
304			if jwk2.KeyID != kid {
305				t.Error("kid did not roundtrip JSON marshalling", i)
306			}
307
308			if jwk2.Algorithm != "foo" {
309				t.Error("alg did not roundtrip JSON marshalling", i)
310			}
311
312			if jwk2.Use != use {
313				t.Error("use did not roundtrip JSON marshalling", i)
314			}
315		}
316	}
317}
318
319func TestMarshalNonPointer(t *testing.T) {
320	type EmbedsKey struct {
321		Key JSONWebKey
322	}
323
324	keyJSON := []byte(`{
325		"e": "AQAB",
326		"kty": "RSA",
327		"n": "vd7rZIoTLEe-z1_8G1FcXSw9CQFEJgV4g9V277sER7yx5Qjz_Pkf2YVth6wwwFJEmzc0hoKY-MMYFNwBE4hQHw"
328	}`)
329	var parsedKey JSONWebKey
330	err := json.Unmarshal(keyJSON, &parsedKey)
331	if err != nil {
332		t.Errorf("Error unmarshalling key: %v", err)
333		return
334	}
335	ek := EmbedsKey{
336		Key: parsedKey,
337	}
338	out, err := json.Marshal(ek)
339	if err != nil {
340		t.Errorf("Error marshalling JSON: %v", err)
341		return
342	}
343	expected := "{\"Key\":{\"kty\":\"RSA\",\"n\":\"vd7rZIoTLEe-z1_8G1FcXSw9CQFEJgV4g9V277sER7yx5Qjz_Pkf2YVth6wwwFJEmzc0hoKY-MMYFNwBE4hQHw\",\"e\":\"AQAB\"}}"
344	if string(out) != expected {
345		t.Error("Failed to marshal embedded non-pointer JWK properly:", string(out))
346	}
347}
348
349func TestMarshalUnmarshalInvalid(t *testing.T) {
350	// Make an invalid curve coordinate by creating a byte array that is one
351	// byte too large, and setting the first byte to 1 (otherwise it's just zero).
352	invalidCoord := make([]byte, curveSize(ecTestKey256.Curve)+1)
353	invalidCoord[0] = 1
354
355	keys := []interface{}{
356		// Empty keys
357		&rsa.PrivateKey{},
358		&ecdsa.PrivateKey{},
359		// Invalid keys
360		&ecdsa.PrivateKey{
361			PublicKey: ecdsa.PublicKey{
362				// Missing values in pub key
363				Curve: elliptic.P256(),
364			},
365		},
366		&ecdsa.PrivateKey{
367			PublicKey: ecdsa.PublicKey{
368				// Invalid curve
369				Curve: nil,
370				X:     ecTestKey256.X,
371				Y:     ecTestKey256.Y,
372			},
373		},
374		&ecdsa.PrivateKey{
375			// Valid pub key, but missing priv key values
376			PublicKey: ecTestKey256.PublicKey,
377		},
378		&ecdsa.PrivateKey{
379			// Invalid pub key, values too large
380			PublicKey: ecdsa.PublicKey{
381				Curve: ecTestKey256.Curve,
382				X:     big.NewInt(0).SetBytes(invalidCoord),
383				Y:     big.NewInt(0).SetBytes(invalidCoord),
384			},
385			D: ecTestKey256.D,
386		},
387		nil,
388	}
389
390	for i, key := range keys {
391		jwk := JSONWebKey{Key: key}
392		_, err := jwk.MarshalJSON()
393		if err == nil {
394			t.Error("managed to serialize invalid key", i)
395		}
396	}
397}
398
399func TestWebKeyVectorsInvalid(t *testing.T) {
400	keys := []string{
401		// Invalid JSON
402		"{X",
403		// Empty key
404		"{}",
405		// Invalid RSA keys
406		`{"kty":"RSA"}`,
407		`{"kty":"RSA","e":""}`,
408		`{"kty":"RSA","e":"XXXX"}`,
409		`{"kty":"RSA","d":"XXXX"}`,
410		// Invalid EC keys
411		`{"kty":"EC","crv":"ABC"}`,
412		`{"kty":"EC","crv":"P-256"}`,
413		`{"kty":"EC","crv":"P-256","d":"XXX"}`,
414		`{"kty":"EC","crv":"ABC","d":"dGVzdA","x":"dGVzdA"}`,
415		`{"kty":"EC","crv":"P-256","d":"dGVzdA","x":"dGVzdA"}`,
416	}
417
418	for _, key := range keys {
419		var jwk2 JSONWebKey
420		err := jwk2.UnmarshalJSON([]byte(key))
421		if err == nil {
422			t.Error("managed to parse invalid key:", key)
423		}
424	}
425}
426
427// Test vectors from RFC 7520
428var cookbookJWKs = []string{
429	// EC Public
430	stripWhitespace(`{
431     "kty": "EC",
432     "kid": "bilbo.baggins@hobbiton.example",
433     "use": "sig",
434     "crv": "P-521",
435     "x": "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9
436         A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt",
437     "y": "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVy
438         SsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1"
439   }`),
440
441	//ED Private
442	stripWhitespace(`{
443     "kty": "OKP",
444     "crv": "Ed25519",
445     "x": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo",
446     "d": "nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A"
447   }`),
448
449	// EC Private
450	stripWhitespace(`{
451     "kty": "EC",
452     "kid": "bilbo.baggins@hobbiton.example",
453     "use": "sig",
454     "crv": "P-521",
455     "x": "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9
456           A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt",
457     "y": "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVy
458           SsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1",
459     "d": "AAhRON2r9cqXX1hg-RoI6R1tX5p2rUAYdmpHZoC1XNM56KtscrX6zb
460           KipQrCW9CGZH3T4ubpnoTKLDYJ_fF3_rJt"
461   }`),
462
463	// RSA Public
464	stripWhitespace(`{
465     "kty": "RSA",
466     "kid": "bilbo.baggins@hobbiton.example",
467     "use": "sig",
468     "n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT
469         -O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqV
470         wGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-
471         oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde
472         3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuC
473         LqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5g
474         HdrNP5zw",
475     "e": "AQAB"
476   }`),
477
478	// RSA Private
479	stripWhitespace(`{"kty":"RSA",
480      "kid":"juliet@capulet.lit",
481      "use":"enc",
482      "n":"t6Q8PWSi1dkJj9hTP8hNYFlvadM7DflW9mWepOJhJ66w7nyoK1gPNqFMSQRy
483           O125Gp-TEkodhWr0iujjHVx7BcV0llS4w5ACGgPrcAd6ZcSR0-Iqom-QFcNP
484           8Sjg086MwoqQU_LYywlAGZ21WSdS_PERyGFiNnj3QQlO8Yns5jCtLCRwLHL0
485           Pb1fEv45AuRIuUfVcPySBWYnDyGxvjYGDSM-AqWS9zIQ2ZilgT-GqUmipg0X
486           OC0Cc20rgLe2ymLHjpHciCKVAbY5-L32-lSeZO-Os6U15_aXrk9Gw8cPUaX1
487           _I8sLGuSiVdt3C_Fn2PZ3Z8i744FPFGGcG1qs2Wz-Q",
488      "e":"AQAB",
489      "d":"GRtbIQmhOZtyszfgKdg4u_N-R_mZGU_9k7JQ_jn1DnfTuMdSNprTeaSTyWfS
490           NkuaAwnOEbIQVy1IQbWVV25NY3ybc_IhUJtfri7bAXYEReWaCl3hdlPKXy9U
491           vqPYGR0kIXTQRqns-dVJ7jahlI7LyckrpTmrM8dWBo4_PMaenNnPiQgO0xnu
492           ToxutRZJfJvG4Ox4ka3GORQd9CsCZ2vsUDmsXOfUENOyMqADC6p1M3h33tsu
493           rY15k9qMSpG9OX_IJAXmxzAh_tWiZOwk2K4yxH9tS3Lq1yX8C1EWmeRDkK2a
494           hecG85-oLKQt5VEpWHKmjOi_gJSdSgqcN96X52esAQ",
495      "p":"2rnSOV4hKSN8sS4CgcQHFbs08XboFDqKum3sc4h3GRxrTmQdl1ZK9uw-PIHf
496           QP0FkxXVrx-WE-ZEbrqivH_2iCLUS7wAl6XvARt1KkIaUxPPSYB9yk31s0Q8
497           UK96E3_OrADAYtAJs-M3JxCLfNgqh56HDnETTQhH3rCT5T3yJws",
498      "q":"1u_RiFDP7LBYh3N4GXLT9OpSKYP0uQZyiaZwBtOCBNJgQxaj10RWjsZu0c6I
499           edis4S7B_coSKB0Kj9PaPaBzg-IySRvvcQuPamQu66riMhjVtG6TlV8CLCYK
500           rYl52ziqK0E_ym2QnkwsUX7eYTB7LbAHRK9GqocDE5B0f808I4s",
501      "dp":"KkMTWqBUefVwZ2_Dbj1pPQqyHSHjj90L5x_MOzqYAJMcLMZtbUtwKqvVDq3
502           tbEo3ZIcohbDtt6SbfmWzggabpQxNxuBpoOOf_a_HgMXK_lhqigI4y_kqS1w
503           Y52IwjUn5rgRrJ-yYo1h41KR-vz2pYhEAeYrhttWtxVqLCRViD6c",
504      "dq":"AvfS0-gRxvn0bwJoMSnFxYcK1WnuEjQFluMGfwGitQBWtfZ1Er7t1xDkbN9
505           GQTB9yqpDoYaN06H7CFtrkxhJIBQaj6nkF5KKS3TQtQ5qCzkOkmxIe3KRbBy
506           mXxkb5qwUpX5ELD5xFc6FeiafWYY63TmmEAu_lRFCOJ3xDea-ots",
507      "qi":"lSQi-w9CpyUReMErP1RsBLk7wNtOvs5EQpPqmuMvqW57NBUczScEoPwmUqq
508           abu9V0-Py4dQ57_bapoKRu1R90bvuFnU63SHWEFglZQvJDMeAvmj4sm-Fp0o
509           Yu_neotgQ0hzbI5gry7ajdYy9-2lNx_76aBZoOUu9HCJ-UsfSOI8"}`),
510
511	// X.509 Certificate Chain
512	stripWhitespace(`{"kty":"RSA",
513      "use":"sig",
514      "kid":"1b94c",
515      "n":"vrjOfz9Ccdgx5nQudyhdoR17V-IubWMeOZCwX_jj0hgAsz2J_pqYW08
516           PLbK_PdiVGKPrqzmDIsLI7sA25VEnHU1uCLNwBuUiCO11_-7dYbsr4iJmG0Q
517           u2j8DsVyT1azpJC_NG84Ty5KKthuCaPod7iI7w0LK9orSMhBEwwZDCxTWq4a
518           YWAchc8t-emd9qOvWtVMDC2BXksRngh6X5bUYLy6AyHKvj-nUy1wgzjYQDwH
519           MTplCoLtU-o-8SNnZ1tmRoGE9uJkBLdh5gFENabWnU5m1ZqZPdwS-qo-meMv
520           VfJb6jJVWRpl2SUtCnYG2C32qvbWbjZ_jBPD5eunqsIo1vQ",
521      "e":"AQAB",
522      "x5c":
523           ["MIIDQjCCAiqgAwIBAgIGATz/FuLiMA0GCSqGSIb3DQEBBQUAMGIxCzAJB
524           gNVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYD
525           VQQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1
526           wYmVsbDAeFw0xMzAyMjEyMzI5MTVaFw0xODA4MTQyMjI5MTVaMGIxCzAJBg
527           NVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYDV
528           QQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1w
529           YmVsbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL64zn8/QnH
530           YMeZ0LncoXaEde1fiLm1jHjmQsF/449IYALM9if6amFtPDy2yvz3YlRij66
531           s5gyLCyO7ANuVRJx1NbgizcAblIgjtdf/u3WG7K+IiZhtELto/A7Fck9Ws6
532           SQvzRvOE8uSirYbgmj6He4iO8NCyvaK0jIQRMMGQwsU1quGmFgHIXPLfnpn
533           fajr1rVTAwtgV5LEZ4Iel+W1GC8ugMhyr4/p1MtcIM42EA8BzE6ZQqC7VPq
534           PvEjZ2dbZkaBhPbiZAS3YeYBRDWm1p1OZtWamT3cEvqqPpnjL1XyW+oyVVk
535           aZdklLQp2Btgt9qr21m42f4wTw+Xrp6rCKNb0CAwEAATANBgkqhkiG9w0BA
536           QUFAAOCAQEAh8zGlfSlcI0o3rYDPBB07aXNswb4ECNIKG0CETTUxmXl9KUL
537           +9gGlqCz5iWLOgWsnrcKcY0vXPG9J1r9AqBNTqNgHq2G03X09266X5CpOe1
538           zFo+Owb1zxtp3PehFdfQJ610CDLEaS9V9Rqp17hCyybEpOGVwe8fnk+fbEL
539           2Bo3UPGrpsHzUoaGpDftmWssZkhpBJKVMJyf/RuP2SmmaIzmnw9JiSlYhzo
540           4tpzd5rFXhjRbg4zW9C+2qok+2+qDM1iJ684gPHMIY8aLWrdgQTxkumGmTq
541           gawR+N5MDtdPTEQ0XfIBc2cJEUyMTY5MPvACWpkA6SdS4xSvdXK3IVfOWA=="]}`),
542}
543
544// SHA-256 thumbprints of the above keys, hex-encoded
545var cookbookJWKThumbprints = []string{
546	"747ae2dd2003664aeeb21e4753fe7402846170a16bc8df8f23a8cf06d3cbe793",
547	"f6934029a341ddf81dceb753e91d17efe16664f40d9f4ed84bc5ea87e111f29d",
548	"747ae2dd2003664aeeb21e4753fe7402846170a16bc8df8f23a8cf06d3cbe793",
549	"f63838e96077ad1fc01c3f8405774dedc0641f558ebb4b40dccf5f9b6d66a932",
550	"0fc478f8579325fcee0d4cbc6d9d1ce21730a6e97e435d6008fb379b0ebe47d4",
551	"0ddb05bfedbec2070fa037324ba397396561d3425d6d69245570c261dc49dee3",
552}
553
554func TestWebKeyVectorsValid(t *testing.T) {
555	for _, key := range cookbookJWKs {
556		var jwk2 JSONWebKey
557		err := jwk2.UnmarshalJSON([]byte(key))
558		if err != nil {
559			t.Error("unable to parse valid key:", key, err)
560		}
561	}
562}
563
564func TestEd25519Serialization(t *testing.T) {
565	jwk := JSONWebKey{
566		Key: ed25519PrivateKey,
567	}
568	serialized, _ := json.Marshal(jwk)
569
570	var jwk2 JSONWebKey
571	json.Unmarshal(serialized, &jwk2)
572
573	assert.True(t, bytes.Equal(
574		[]byte(jwk.Key.(ed25519.PrivateKey).Public().(ed25519.PublicKey)),
575		[]byte(jwk2.Key.(ed25519.PrivateKey).Public().(ed25519.PublicKey))))
576}
577
578func TestThumbprint(t *testing.T) {
579	for i, key := range cookbookJWKs {
580		var jwk2 JSONWebKey
581		err := jwk2.UnmarshalJSON([]byte(key))
582		if err != nil {
583			t.Error("unable to parse valid key:", key, err)
584		}
585
586		tp, err := jwk2.Thumbprint(crypto.SHA256)
587		if err != nil {
588			t.Error("unable to compute thumbprint:", key, err)
589		}
590
591		tpHex := hex.EncodeToString(tp)
592		if cookbookJWKThumbprints[i] != tpHex {
593			t.Error("incorrect thumbprint:", i, cookbookJWKThumbprints[i], tpHex)
594		}
595	}
596}
597
598func TestMarshalUnmarshalJWKSet(t *testing.T) {
599	jwk1 := JSONWebKey{Key: rsaTestKey, KeyID: "ABCDEFG", Algorithm: "foo"}
600	jwk2 := JSONWebKey{Key: rsaTestKey, KeyID: "GFEDCBA", Algorithm: "foo"}
601	var set JSONWebKeySet
602	set.Keys = append(set.Keys, jwk1)
603	set.Keys = append(set.Keys, jwk2)
604
605	jsonbar, err := json.Marshal(&set)
606	if err != nil {
607		t.Error("problem marshalling set", err)
608	}
609	var set2 JSONWebKeySet
610	err = json.Unmarshal(jsonbar, &set2)
611	if err != nil {
612		t.Fatal("problem unmarshalling set", err)
613	}
614	jsonbar2, err := json.Marshal(&set2)
615	if err != nil {
616		t.Fatal("problem marshalling set", err)
617	}
618	if !bytes.Equal(jsonbar, jsonbar2) {
619		t.Error("roundtrip should not lose information")
620	}
621}
622
623func TestJWKSetKey(t *testing.T) {
624	jwk1 := JSONWebKey{Key: rsaTestKey, KeyID: "ABCDEFG", Algorithm: "foo"}
625	jwk2 := JSONWebKey{Key: rsaTestKey, KeyID: "GFEDCBA", Algorithm: "foo"}
626	var set JSONWebKeySet
627	set.Keys = append(set.Keys, jwk1)
628	set.Keys = append(set.Keys, jwk2)
629	k := set.Key("ABCDEFG")
630	if len(k) != 1 {
631		t.Errorf("method should return slice with one key not %d", len(k))
632	}
633	if k[0].KeyID != "ABCDEFG" {
634		t.Error("method should return key with ID ABCDEFG")
635	}
636}
637
638func TestJWKSymmetricKey(t *testing.T) {
639	sample1 := `{"kty":"oct","alg":"A128KW","k":"GawgguFyGrWKav7AX4VKUg"}`
640	sample2 := `{"kty":"oct","k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow","kid":"HMAC key used in JWS spec Appendix A.1 example"}`
641
642	var jwk1 JSONWebKey
643	json.Unmarshal([]byte(sample1), &jwk1)
644
645	if jwk1.Algorithm != "A128KW" {
646		t.Errorf("expected Algorithm to be A128KW, but was '%s'", jwk1.Algorithm)
647	}
648	expected1 := fromHexBytes("19ac2082e1721ab58a6afec05f854a52")
649	if !bytes.Equal(jwk1.Key.([]byte), expected1) {
650		t.Errorf("expected Key to be '%s', but was '%s'", hex.EncodeToString(expected1), hex.EncodeToString(jwk1.Key.([]byte)))
651	}
652
653	var jwk2 JSONWebKey
654	json.Unmarshal([]byte(sample2), &jwk2)
655
656	if jwk2.KeyID != "HMAC key used in JWS spec Appendix A.1 example" {
657		t.Errorf("expected KeyID to be 'HMAC key used in JWS spec Appendix A.1 example', but was '%s'", jwk2.KeyID)
658	}
659	expected2 := fromHexBytes(`
660    0323354b2b0fa5bc837e0665777ba68f5ab328e6f054c928a90f84b2d2502ebf
661    d3fb5a92d20647ef968ab4c377623d223d2e2172052e4f08c0cd9af567d080a3`)
662	if !bytes.Equal(jwk2.Key.([]byte), expected2) {
663		t.Errorf("expected Key to be '%s', but was '%s'", hex.EncodeToString(expected2), hex.EncodeToString(jwk2.Key.([]byte)))
664	}
665}
666
667func TestJWKSymmetricRoundtrip(t *testing.T) {
668	jwk1 := JSONWebKey{Key: []byte{1, 2, 3, 4}}
669	marshaled, err := jwk1.MarshalJSON()
670	if err != nil {
671		t.Error("failed to marshal valid JWK object", err)
672	}
673
674	var jwk2 JSONWebKey
675	err = jwk2.UnmarshalJSON(marshaled)
676	if err != nil {
677		t.Error("failed to unmarshal valid JWK object", err)
678	}
679
680	if !bytes.Equal(jwk1.Key.([]byte), jwk2.Key.([]byte)) {
681		t.Error("round-trip of symmetric JWK gave different raw keys")
682	}
683}
684
685func TestJWKSymmetricInvalid(t *testing.T) {
686	invalid := JSONWebKey{}
687	_, err := invalid.MarshalJSON()
688	if err == nil {
689		t.Error("excepted error on marshaling invalid symmetric JWK object")
690	}
691
692	var jwk JSONWebKey
693	err = jwk.UnmarshalJSON([]byte(`{"kty":"oct"}`))
694	if err == nil {
695		t.Error("excepted error on unmarshaling invalid symmetric JWK object")
696	}
697}
698
699func TestJWKIsPublic(t *testing.T) {
700	bigInt := big.NewInt(0)
701	eccPub := ecdsa.PublicKey{elliptic.P256(), bigInt, bigInt}
702	rsaPub := rsa.PublicKey{bigInt, 1}
703
704	cases := []struct {
705		key              interface{}
706		expectedIsPublic bool
707	}{
708		{&eccPub, true},
709		{&ecdsa.PrivateKey{eccPub, bigInt}, false},
710		{&rsaPub, true},
711		{&rsa.PrivateKey{rsaPub, bigInt, []*big.Int{bigInt, bigInt}, rsa.PrecomputedValues{}}, false},
712		{ed25519PublicKey, true},
713		{ed25519PrivateKey, false},
714	}
715
716	for _, tc := range cases {
717		k := &JSONWebKey{Key: tc.key}
718		if public := k.IsPublic(); public != tc.expectedIsPublic {
719			t.Errorf("expected IsPublic to return %t, got %t", tc.expectedIsPublic, public)
720		}
721	}
722}
723
724func TestJWKValid(t *testing.T) {
725	bigInt := big.NewInt(0)
726	eccPub := ecdsa.PublicKey{elliptic.P256(), bigInt, bigInt}
727	rsaPub := rsa.PublicKey{bigInt, 1}
728	edPubEmpty := ed25519.PublicKey([]byte{})
729	edPrivEmpty := ed25519.PublicKey([]byte{})
730
731	cases := []struct {
732		key              interface{}
733		expectedValidity bool
734	}{
735		{nil, false},
736		{&ecdsa.PublicKey{}, false},
737		{&eccPub, true},
738		{&ecdsa.PrivateKey{}, false},
739		{&ecdsa.PrivateKey{eccPub, bigInt}, true},
740		{&rsa.PublicKey{}, false},
741		{&rsaPub, true},
742		{&rsa.PrivateKey{}, false},
743		{&rsa.PrivateKey{rsaPub, bigInt, []*big.Int{bigInt, bigInt}, rsa.PrecomputedValues{}}, true},
744		{ed25519PublicKey, true},
745		{ed25519PrivateKey, true},
746		{edPubEmpty, false},
747		{edPrivEmpty, false},
748	}
749
750	for _, tc := range cases {
751		k := &JSONWebKey{Key: tc.key}
752		valid := k.Valid()
753		if valid != tc.expectedValidity {
754			t.Errorf("expected Valid to return %t, got %t", tc.expectedValidity, valid)
755		}
756		if valid {
757			wasPublic := k.IsPublic()
758			p := k.Public() // all aforemention keys are asymmetric
759			if !p.Valid() {
760				t.Errorf("unable to derive public key from valid asymmetric key")
761			}
762			if wasPublic != k.IsPublic() {
763				t.Errorf("original key was touched during public key derivation")
764			}
765		}
766	}
767}
768
769func TestJWKBufferSizeCheck(t *testing.T) {
770	key := `{
771		"kty":"EC",
772		"crv":"P-256",
773		"x":"m9GSmJ5iGmAYlMlaOJGSFN_CjN9cIn8GGYExP-C0FBiIXlWTNvGN38R9WdrHcppfsKF0FXMOMyutpHIRaiMxYSA",
774		"y":"ZaPcRZ3q_7T3h-Gwz2i-T2JjJXfj6YVGgKHcFz5zqmg"}`
775	var jwk JSONWebKey
776	jwk.UnmarshalJSON([]byte(key))
777	jwk.Valid() // true
778	// panic: square/go-jose: invalid call to newFixedSizeBuffer (len(data) > length)
779	// github.com/square/go-jose.newFixedSizeBuffer(0xc420014557, 0x41, 0x41, 0x20, 0x0)
780	jwk.Thumbprint(crypto.SHA256)
781}
782
783func TestJWKPaddingPrivateX(t *testing.T) {
784	key := `{
785    "kty": "EC",
786    "crv": "P-256",
787    "x": "nPTIABcDASY6FNGSNfHCB51tY7qChtgzeVazOtLrwQ",
788    "y": "vEEs4V0egJkNyM2Q4pp001zu14VcpQ0_Ei8xOOPxKZs",
789    "d": "nIVCvMR2wkLmeGJErOpI23VDHl2s3JwGdbzKy0odir0"
790  }`
791	var jwk JSONWebKey
792	err := jwk.UnmarshalJSON([]byte(key))
793	if err == nil {
794		t.Errorf("Expected key with short x to fail unmarshalling")
795	}
796	if !strings.Contains(err.Error(), "wrong length for x") {
797		t.Errorf("Wrong error for short x, got %q", err)
798	}
799	if jwk.Valid() {
800		t.Errorf("Expected key to be invalid, but it was valid.")
801	}
802}
803
804func TestJWKPaddingPrivateY(t *testing.T) {
805	key := `{
806    "kty": "EC",
807    "crv": "P-256",
808    "x": "vEEs4V0egJkNyM2Q4pp001zu14VcpQ0_Ei8xOOPxKZs",
809    "y": "nPTIABcDASY6FNGSNfHCB51tY7qChtgzeVazOtLrwQ",
810    "d": "nIVCvMR2wkLmeGJErOpI23VDHl2s3JwGdbzKy0odir0"
811  }`
812	var jwk JSONWebKey
813	err := jwk.UnmarshalJSON([]byte(key))
814	if err == nil {
815		t.Errorf("Expected key with short x to fail unmarshalling")
816	}
817	if !strings.Contains(err.Error(), "wrong length for y") {
818		t.Errorf("Wrong error for short y, got %q", err)
819	}
820	if jwk.Valid() {
821		t.Errorf("Expected key to be invalid, but it was valid.")
822	}
823}
824
825func TestJWKPaddingPrivateD(t *testing.T) {
826	key := `{
827    "kty": "EC",
828    "crv": "P-256",
829    "x": "vEEs4V0egJkNyM2Q4pp001zu14VcpQ0_Ei8xOOPxKZs",
830    "y": "qnPTIABcDASY6FNGSNfHCB51tY7qChtgzeVazOtLrwQ",
831    "d": "IVCvMR2wkLmeGJErOpI23VDHl2s3JwGdbzKy0odir0"
832  }`
833	var jwk JSONWebKey
834	err := jwk.UnmarshalJSON([]byte(key))
835	if err == nil {
836		t.Errorf("Expected key with short x to fail unmarshalling")
837	}
838	if !strings.Contains(err.Error(), "wrong length for d") {
839		t.Errorf("Wrong error for short d, got %q", err)
840	}
841	if jwk.Valid() {
842		t.Errorf("Expected key to be invalid, but it was valid.")
843	}
844}
845
846func TestJWKPaddingX(t *testing.T) {
847	key := `{
848    "kty": "EC",
849    "crv": "P-256",
850    "x": "nPTIABcDASY6FNGSNfHCB51tY7qChtgzeVazOtLrwQ",
851    "y": "vEEs4V0egJkNyM2Q4pp001zu14VcpQ0_Ei8xOOPxKZs"
852  }`
853	var jwk JSONWebKey
854	err := jwk.UnmarshalJSON([]byte(key))
855	if err == nil {
856		t.Errorf("Expected key with short x to fail unmarshalling")
857	}
858	if !strings.Contains(err.Error(), "wrong length for x") {
859		t.Errorf("Wrong error for short x, got %q", err)
860	}
861	if jwk.Valid() {
862		t.Errorf("Expected key to be invalid, but it was valid.")
863	}
864}
865
866func TestJWKPaddingY(t *testing.T) {
867	key := `{
868    "kty": "EC",
869    "crv": "P-256",
870    "x": "vEEs4V0egJkNyM2Q4pp001zu14VcpQ0_Ei8xOOPxKZs",
871    "y": "nPTIABcDASY6FNGSNfHCB51tY7qChtgzeVazOtLrwQ"
872  }`
873	var jwk JSONWebKey
874	err := jwk.UnmarshalJSON([]byte(key))
875	if err == nil {
876		t.Errorf("Expected key with short y to fail unmarshalling")
877	}
878	if !strings.Contains(err.Error(), "wrong length for y") {
879		t.Errorf("Wrong error for short y, got %q", err)
880	}
881	if jwk.Valid() {
882		t.Errorf("Expected key to be invalid, but it was valid.")
883	}
884}
885