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/sha1"
26	"crypto/sha256"
27	"crypto/x509"
28	"encoding/hex"
29	"math/big"
30	"reflect"
31	"strings"
32	"testing"
33
34	"github.com/google/go-cmp/cmp"
35	"github.com/stretchr/testify/assert"
36	"github.com/stretchr/testify/require"
37
38	"golang.org/x/crypto/ed25519"
39
40	"gopkg.in/square/go-jose.v2/json"
41)
42
43// Test chain of two X.509 certificates
44var testCertificates, _ = x509.ParseCertificates(fromBase64Bytes(`
45MIIDfDCCAmSgAwIBAgIJANWAkzF7PA8/MA0GCSqGSIb3DQEBCwUAMFUxCzAJ
46BgNVBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4G
47A1UECxMHZXhhbXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1sZWFmMB4XDTE2MDYx
48MDIyMTQxMVoXDTIzMDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNV
49BAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUw
50EwYDVQQDEwxleGFtcGxlLWxlYWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
51ggEKAoIBAQC7stSvfQyGuHw3v34fisqIdDXberrFoFk9ht/WdXgYzX2uLNKd
52sR/J5sbWSl8K/5djpzj31eIzqU69w8v7SChM5x9bouDsABHz3kZucx5cSafE
53gJojysBkcrq3VY+aJanzbL+qErYX+lhRpPcZK6JMWIwar8Y3B2la4yWwieec
54w2/WfEVvG0M/DOYKnR8QHFsfl3US1dnBM84czKPyt9r40gDk2XiH/lGts5a9
554rAGvbr8IMCtq0mA5aH3Fx3mDSi3+4MZwygCAHrF5O5iSV9rEI+m2+7j2S+j
56HDUnvV+nqcpb9m6ENECnYX8FD2KcqlOjTmw8smDy09N2Np6i464lAgMBAAGj
57TzBNMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAsBgNVHREEJTAj
58hwR/AAABhxAAAAAAAAAAAAAAAAAAAAABgglsb2NhbGhvc3QwDQYJKoZIhvcN
59AQELBQADggEBAGM4aa/qrURUweZBIwZYv8O9b2+r4l0HjGAh982/B9sMlM05
60kojyDCUGvj86z18Lm8mKr4/y+i0nJ+vDIksEvfDuzw5ALAXGcBzPJKtICUf7
61LstA/n9NNpshWz0kld9ylnB5mbUzSFDncVyeXkEf5sGQXdIIZT9ChRBoiloS
62aa7dvBVCcsX1LGP2LWqKtD+7nUnw5qCwtyAVT8pthEUxFTpywoiJS5ZdzeEx
638MNGvUeLFj2kleqPF78EioEQlSOxViCuctEtnQuPcDLHNFr10byTZY9roObi
64qdsJLMVvb2XliJjAqaPa9AkYwGE6xHw2ispwg64Rse0+AtKups19WIUwggNT
65MIICO6ADAgECAgkAqD4tCWKt9/AwDQYJKoZIhvcNAQELBQAwVTELMAkGA1UE
66BhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQL
67EwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLXJvb3QwHhcNMTYwNjEwMjIx
68NDExWhcNMjMwNDE1MjIxNDExWjBVMQswCQYDVQQGEwJVUzELMAkGA1UECBMC
69Q0ExEDAOBgNVBAoTB2NlcnRpZ28xEDAOBgNVBAsTB2V4YW1wbGUxFTATBgNV
70BAMTDGV4YW1wbGUtcm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
71ggEBAMo4ShKI2MxDz/NQVxBbz0tbD5R5NcobA0NKkaPKLyMEpnWVY9ucyauM
72joNn1F568cfOoF0pm3700U8UTPt2MMxEHIi4mFG/OF8UF+Voh1J42Tb42lRo
73W5RRR3ogh4+7QB1G94nxkYddHAJ4QMhUJlLigFg8c6Ff/MxYODy9I7ilLFOM
74Zzsjx8fFpRKRXNQFt471P/V4WTSba7GzdTOJRyTZf/xipF36n8RoEQPvyde8
75pEAsCC4oDOrEiCTdxw8rRJVAU0Wr55XX+qjxyi55C6oykIC/BWR+lUqGd7IL
76Y2Uyt/OVxllt8b+KuVKNCfn4TFlfgizLWkJRs6JV9KuwJ20CAwEAAaMmMCQw
77DgYDVR0PAQH/BAQDAgIEMBIGA1UdEwEB/wQIMAYBAf8CAQAwDQYJKoZIhvcN
78AQELBQADggEBAIsQlTrm9NT6gts0cs4JHp8AutuMrvGyLpIUOlJcEybvgxaz
79LebIMGZek5w3yEJiCyCK9RdNDP3Kdc/+nM6PhvzfPOVo58+0tMCYyEpZVXhD
80zmasNDP4fMbiUpczvx5OwPw/KuhwD+1ITuZUQnQlqXgTYoj9n39+qlgUsHos
81WXHmfzd6Fcz96ADSXg54IL2cEoJ41Q3ewhA7zmWWPLMAl21aex2haiAmzqqN
82xXyfZTnGNnE3lkV1yVguOrqDZyMRdcxDFvxvtmEeMtYV2Mc/zlS9ccrcOkrc
83mZSDxthLu3UMl98NA2NrCGWwzJwpk36vQ0PRSbibsCMarFspP8zbIoU=`))
84
85func TestCurveSize(t *testing.T) {
86	size256 := curveSize(elliptic.P256())
87	size384 := curveSize(elliptic.P384())
88	size521 := curveSize(elliptic.P521())
89	if size256 != 32 {
90		t.Error("P-256 have 32 bytes")
91	}
92	if size384 != 48 {
93		t.Error("P-384 have 48 bytes")
94	}
95	if size521 != 66 {
96		t.Error("P-521 have 66 bytes")
97	}
98}
99
100func TestRoundtripRsaPrivate(t *testing.T) {
101	jwk, err := fromRsaPrivateKey(rsaTestKey)
102	if err != nil {
103		t.Error("problem constructing JWK from rsa key", err)
104	}
105
106	rsa2, err := jwk.rsaPrivateKey()
107	if err != nil {
108		t.Error("problem converting RSA private -> JWK", err)
109	}
110
111	if rsa2.N.Cmp(rsaTestKey.N) != 0 {
112		t.Error("RSA private N mismatch")
113	}
114	if rsa2.E != rsaTestKey.E {
115		t.Error("RSA private E mismatch")
116	}
117	if rsa2.D.Cmp(rsaTestKey.D) != 0 {
118		t.Error("RSA private D mismatch")
119	}
120	if len(rsa2.Primes) != 2 {
121		t.Error("RSA private roundtrip expected two primes")
122	}
123	if rsa2.Primes[0].Cmp(rsaTestKey.Primes[0]) != 0 {
124		t.Error("RSA private P mismatch")
125	}
126	if rsa2.Primes[1].Cmp(rsaTestKey.Primes[1]) != 0 {
127		t.Error("RSA private Q mismatch")
128	}
129}
130
131func TestRoundtripRsaPrivatePrecomputed(t *testing.T) {
132	// Isolate a shallow copy of the rsaTestKey to avoid polluting it with Precompute
133	localKey := &(*rsaTestKey)
134	localKey.Precompute()
135
136	jwk, err := fromRsaPrivateKey(localKey)
137	if err != nil {
138		t.Error("problem constructing JWK from rsa key", err)
139	}
140
141	rsa2, err := jwk.rsaPrivateKey()
142	if err != nil {
143		t.Error("problem converting RSA private -> JWK", err)
144	}
145
146	if rsa2.Precomputed.Dp == nil {
147		t.Error("RSA private Dp nil")
148	}
149	if rsa2.Precomputed.Dq == nil {
150		t.Error("RSA private Dq nil")
151	}
152	if rsa2.Precomputed.Qinv == nil {
153		t.Error("RSA private Qinv nil")
154	}
155
156	if rsa2.Precomputed.Dp.Cmp(localKey.Precomputed.Dp) != 0 {
157		t.Error("RSA private Dp mismatch")
158	}
159	if rsa2.Precomputed.Dq.Cmp(localKey.Precomputed.Dq) != 0 {
160		t.Error("RSA private Dq mismatch")
161	}
162	if rsa2.Precomputed.Qinv.Cmp(localKey.Precomputed.Qinv) != 0 {
163		t.Error("RSA private Qinv mismatch")
164	}
165}
166
167func TestRsaPrivateInsufficientPrimes(t *testing.T) {
168	brokenRsaPrivateKey := rsa.PrivateKey{
169		PublicKey: rsa.PublicKey{
170			N: rsaTestKey.N,
171			E: rsaTestKey.E,
172		},
173		D:      rsaTestKey.D,
174		Primes: []*big.Int{rsaTestKey.Primes[0]},
175	}
176
177	_, err := fromRsaPrivateKey(&brokenRsaPrivateKey)
178	if err != ErrUnsupportedKeyType {
179		t.Error("expected unsupported key type error, got", err)
180	}
181}
182
183func TestRsaPrivateExcessPrimes(t *testing.T) {
184	brokenRsaPrivateKey := rsa.PrivateKey{
185		PublicKey: rsa.PublicKey{
186			N: rsaTestKey.N,
187			E: rsaTestKey.E,
188		},
189		D: rsaTestKey.D,
190		Primes: []*big.Int{
191			rsaTestKey.Primes[0],
192			rsaTestKey.Primes[1],
193			big.NewInt(3),
194		},
195	}
196
197	_, err := fromRsaPrivateKey(&brokenRsaPrivateKey)
198	if err != ErrUnsupportedKeyType {
199		t.Error("expected unsupported key type error, got", err)
200	}
201}
202
203func TestRoundtripEcPublic(t *testing.T) {
204	for i, ecTestKey := range []*ecdsa.PrivateKey{ecTestKey256, ecTestKey384, ecTestKey521} {
205		jwk, err := fromEcPublicKey(&ecTestKey.PublicKey)
206
207		ec2, err := jwk.ecPublicKey()
208		if err != nil {
209			t.Error("problem converting ECDSA private -> JWK", i, err)
210		}
211
212		if !reflect.DeepEqual(ec2.Curve, ecTestKey.Curve) {
213			t.Error("ECDSA private curve mismatch", i)
214		}
215		if ec2.X.Cmp(ecTestKey.X) != 0 {
216			t.Error("ECDSA X mismatch", i)
217		}
218		if ec2.Y.Cmp(ecTestKey.Y) != 0 {
219			t.Error("ECDSA Y mismatch", i)
220		}
221	}
222}
223
224func TestRoundtripEcPrivate(t *testing.T) {
225	for i, ecTestKey := range []*ecdsa.PrivateKey{ecTestKey256, ecTestKey384, ecTestKey521} {
226		jwk, err := fromEcPrivateKey(ecTestKey)
227
228		ec2, err := jwk.ecPrivateKey()
229		if err != nil {
230			t.Fatalf("problem converting ECDSA private -> JWK for %#v: %s", ecTestKey, err)
231		}
232
233		if !reflect.DeepEqual(ec2.Curve, ecTestKey.Curve) {
234			t.Error("ECDSA private curve mismatch", i)
235		}
236		if ec2.X.Cmp(ecTestKey.X) != 0 {
237			t.Error("ECDSA X mismatch", i)
238		}
239		if ec2.Y.Cmp(ecTestKey.Y) != 0 {
240			t.Error("ECDSA Y mismatch", i)
241		}
242		if ec2.D.Cmp(ecTestKey.D) != 0 {
243			t.Error("ECDSA D mismatch", i)
244		}
245	}
246}
247
248func TestRoundtripX509(t *testing.T) {
249	x5tSHA1 := sha1.Sum(testCertificates[0].Raw)
250	x5tSHA256 := sha256.Sum256(testCertificates[0].Raw)
251
252	cases := []struct {
253		name string
254		jwk  JSONWebKey
255	}{
256		{
257			name: "all fields",
258			jwk: JSONWebKey{
259				Key:                         testCertificates[0].PublicKey,
260				KeyID:                       "bar",
261				Algorithm:                   "foo",
262				Certificates:                testCertificates,
263				CertificateThumbprintSHA1:   x5tSHA1[:],
264				CertificateThumbprintSHA256: x5tSHA256[:],
265			},
266		},
267		{
268			name: "no optional x5ts",
269			jwk: JSONWebKey{
270				Key:          testCertificates[0].PublicKey,
271				KeyID:        "bar",
272				Algorithm:    "foo",
273				Certificates: testCertificates,
274			},
275		},
276		{
277			name: "no x5t",
278			jwk: JSONWebKey{
279				Key:                         testCertificates[0].PublicKey,
280				KeyID:                       "bar",
281				Algorithm:                   "foo",
282				Certificates:                testCertificates,
283				CertificateThumbprintSHA256: x5tSHA256[:],
284			},
285		},
286		{
287			name: "no x5t#S256",
288			jwk: JSONWebKey{
289				Key:                       testCertificates[0].PublicKey,
290				KeyID:                     "bar",
291				Algorithm:                 "foo",
292				Certificates:              testCertificates,
293				CertificateThumbprintSHA1: x5tSHA1[:],
294			},
295		},
296	}
297
298	for _, c := range cases {
299		t.Run(c.name, func(t *testing.T) {
300			jsonbar, err := c.jwk.MarshalJSON()
301			require.NoError(t, err)
302
303			var jwk2 JSONWebKey
304			err = jwk2.UnmarshalJSON(jsonbar)
305			require.NoError(t, err)
306
307			if !reflect.DeepEqual(testCertificates, jwk2.Certificates) {
308				t.Error("Certificates not equal", c.jwk.Certificates, jwk2.Certificates)
309			}
310
311			jsonbar2, err := jwk2.MarshalJSON()
312			require.NoError(t, err)
313
314			require.Empty(t, cmp.Diff(jsonbar, jsonbar2))
315			if !bytes.Equal(jsonbar, jsonbar2) {
316				t.Error("roundtrip should not lose information")
317			}
318		})
319	}
320}
321
322func TestRoundtripX509Hex(t *testing.T) {
323	var hexJWK = `{
324   "kty":"RSA",
325   "kid":"bar",
326   "alg":"foo",
327   "n":"u7LUr30Mhrh8N79-H4rKiHQ123q6xaBZPYbf1nV4GM19rizSnbEfyebG1kpfCv-XY6c499XiM6lOvcPL-0goTOcfW6Lg7AAR895GbnMeXEmnxICaI8rAZHK6t1WPmiWp82y_qhK2F_pYUaT3GSuiTFiMGq_GNwdpWuMlsInnnMNv1nxFbxtDPwzmCp0fEBxbH5d1EtXZwTPOHMyj8rfa-NIA5Nl4h_5RrbOWveKwBr26_CDAratJgOWh9xcd5g0ot_uDGcMoAgB6xeTuYklfaxCPptvu49kvoxw1J71fp6nKW_ZuhDRAp2F_BQ9inKpTo05sPLJg8tPTdjaeouOuJQ",
328   "e":"AQAB",
329   "x5c":[
330      "MIIDfDCCAmSgAwIBAgIJANWAkzF7PA8/MA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4GA1UECxMHZXhhbXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1sZWFmMB4XDTE2MDYxMDIyMTQxMVoXDTIzMDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLWxlYWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7stSvfQyGuHw3v34fisqIdDXberrFoFk9ht/WdXgYzX2uLNKdsR/J5sbWSl8K/5djpzj31eIzqU69w8v7SChM5x9bouDsABHz3kZucx5cSafEgJojysBkcrq3VY+aJanzbL+qErYX+lhRpPcZK6JMWIwar8Y3B2la4yWwieecw2/WfEVvG0M/DOYKnR8QHFsfl3US1dnBM84czKPyt9r40gDk2XiH/lGts5a94rAGvbr8IMCtq0mA5aH3Fx3mDSi3+4MZwygCAHrF5O5iSV9rEI+m2+7j2S+jHDUnvV+nqcpb9m6ENECnYX8FD2KcqlOjTmw8smDy09N2Np6i464lAgMBAAGjTzBNMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAsBgNVHREEJTAjhwR/AAABhxAAAAAAAAAAAAAAAAAAAAABgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAGM4aa/qrURUweZBIwZYv8O9b2+r4l0HjGAh982/B9sMlM05kojyDCUGvj86z18Lm8mKr4/y+i0nJ+vDIksEvfDuzw5ALAXGcBzPJKtICUf7LstA/n9NNpshWz0kld9ylnB5mbUzSFDncVyeXkEf5sGQXdIIZT9ChRBoiloSaa7dvBVCcsX1LGP2LWqKtD+7nUnw5qCwtyAVT8pthEUxFTpywoiJS5ZdzeEx8MNGvUeLFj2kleqPF78EioEQlSOxViCuctEtnQuPcDLHNFr10byTZY9roObiqdsJLMVvb2XliJjAqaPa9AkYwGE6xHw2ispwg64Rse0+AtKups19WIU=",
331      "MIIDUzCCAjugAwIBAgIJAKg+LQlirffwMA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4GA1UECxMHZXhhbXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1yb290MB4XDTE2MDYxMDIyMTQxMVoXDTIzMDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLXJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKOEoSiNjMQ8/zUFcQW89LWw+UeTXKGwNDSpGjyi8jBKZ1lWPbnMmrjI6DZ9ReevHHzqBdKZt+9NFPFEz7djDMRByIuJhRvzhfFBflaIdSeNk2+NpUaFuUUUd6IIePu0AdRveJ8ZGHXRwCeEDIVCZS4oBYPHOhX/zMWDg8vSO4pSxTjGc7I8fHxaUSkVzUBbeO9T/1eFk0m2uxs3UziUck2X/8YqRd+p/EaBED78nXvKRALAguKAzqxIgk3ccPK0SVQFNFq+eV1/qo8coueQuqMpCAvwVkfpVKhneyC2NlMrfzlcZZbfG/irlSjQn5+ExZX4Isy1pCUbOiVfSrsCdtAgMBAAGjJjAkMA4GA1UdDwEB/wQEAwICBDASBgNVHRMBAf8ECDAGAQH/AgEAMA0GCSqGSIb3DQEBCwUAA4IBAQCLEJU65vTU+oLbNHLOCR6fALrbjK7xsi6SFDpSXBMm74MWsy3myDBmXpOcN8hCYgsgivUXTQz9ynXP/pzOj4b83zzlaOfPtLTAmMhKWVV4Q85mrDQz+HzG4lKXM78eTsD8PyrocA/tSE7mVEJ0Jal4E2KI/Z9/fqpYFLB6LFlx5n83ehXM/egA0l4OeCC9nBKCeNUN3sIQO85lljyzAJdtWnsdoWogJs6qjcV8n2U5xjZxN5ZFdclYLjq6g2cjEXXMQxb8b7ZhHjLWFdjHP85UvXHK3DpK3JmUg8bYS7t1DJffDQNjawhlsMycKZN+r0ND0Um4m7AjGqxbKT/M2yKF"
332	],
333	"x5t": "MDYxMjU0ZmRmNzIwZjJjMGU0YmQzZjMzMzlhMmZlNTM1MGExNWRlMQ",
334	"x5t#S256": "MjAzMjRhNGI5MmYxMjI2OGVmOWFlMDI1ZmQ1Yzc5ZDE1OGZmNzQ1NzQwMDkyMTk2ZTgzNTNjMDAzMTUxNzUxMQ"
335}`
336
337	// json output
338	var output = `{
339	"kty":"RSA",
340	"kid":"bar",
341	"alg":"foo",
342	"n":"u7LUr30Mhrh8N79-H4rKiHQ123q6xaBZPYbf1nV4GM19rizSnbEfyebG1kpfCv-XY6c499XiM6lOvcPL-0goTOcfW6Lg7AAR895GbnMeXEmnxICaI8rAZHK6t1WPmiWp82y_qhK2F_pYUaT3GSuiTFiMGq_GNwdpWuMlsInnnMNv1nxFbxtDPwzmCp0fEBxbH5d1EtXZwTPOHMyj8rfa-NIA5Nl4h_5RrbOWveKwBr26_CDAratJgOWh9xcd5g0ot_uDGcMoAgB6xeTuYklfaxCPptvu49kvoxw1J71fp6nKW_ZuhDRAp2F_BQ9inKpTo05sPLJg8tPTdjaeouOuJQ",
343	"e":"AQAB",
344	"x5c":[
345		"MIIDfDCCAmSgAwIBAgIJANWAkzF7PA8/MA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4GA1UECxMHZXhhbXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1sZWFmMB4XDTE2MDYxMDIyMTQxMVoXDTIzMDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLWxlYWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7stSvfQyGuHw3v34fisqIdDXberrFoFk9ht/WdXgYzX2uLNKdsR/J5sbWSl8K/5djpzj31eIzqU69w8v7SChM5x9bouDsABHz3kZucx5cSafEgJojysBkcrq3VY+aJanzbL+qErYX+lhRpPcZK6JMWIwar8Y3B2la4yWwieecw2/WfEVvG0M/DOYKnR8QHFsfl3US1dnBM84czKPyt9r40gDk2XiH/lGts5a94rAGvbr8IMCtq0mA5aH3Fx3mDSi3+4MZwygCAHrF5O5iSV9rEI+m2+7j2S+jHDUnvV+nqcpb9m6ENECnYX8FD2KcqlOjTmw8smDy09N2Np6i464lAgMBAAGjTzBNMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAsBgNVHREEJTAjhwR/AAABhxAAAAAAAAAAAAAAAAAAAAABgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAGM4aa/qrURUweZBIwZYv8O9b2+r4l0HjGAh982/B9sMlM05kojyDCUGvj86z18Lm8mKr4/y+i0nJ+vDIksEvfDuzw5ALAXGcBzPJKtICUf7LstA/n9NNpshWz0kld9ylnB5mbUzSFDncVyeXkEf5sGQXdIIZT9ChRBoiloSaa7dvBVCcsX1LGP2LWqKtD+7nUnw5qCwtyAVT8pthEUxFTpywoiJS5ZdzeEx8MNGvUeLFj2kleqPF78EioEQlSOxViCuctEtnQuPcDLHNFr10byTZY9roObiqdsJLMVvb2XliJjAqaPa9AkYwGE6xHw2ispwg64Rse0+AtKups19WIU=",
346		"MIIDUzCCAjugAwIBAgIJAKg+LQlirffwMA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4GA1UECxMHZXhhbXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1yb290MB4XDTE2MDYxMDIyMTQxMVoXDTIzMDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLXJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKOEoSiNjMQ8/zUFcQW89LWw+UeTXKGwNDSpGjyi8jBKZ1lWPbnMmrjI6DZ9ReevHHzqBdKZt+9NFPFEz7djDMRByIuJhRvzhfFBflaIdSeNk2+NpUaFuUUUd6IIePu0AdRveJ8ZGHXRwCeEDIVCZS4oBYPHOhX/zMWDg8vSO4pSxTjGc7I8fHxaUSkVzUBbeO9T/1eFk0m2uxs3UziUck2X/8YqRd+p/EaBED78nXvKRALAguKAzqxIgk3ccPK0SVQFNFq+eV1/qo8coueQuqMpCAvwVkfpVKhneyC2NlMrfzlcZZbfG/irlSjQn5+ExZX4Isy1pCUbOiVfSrsCdtAgMBAAGjJjAkMA4GA1UdDwEB/wQEAwICBDASBgNVHRMBAf8ECDAGAQH/AgEAMA0GCSqGSIb3DQEBCwUAA4IBAQCLEJU65vTU+oLbNHLOCR6fALrbjK7xsi6SFDpSXBMm74MWsy3myDBmXpOcN8hCYgsgivUXTQz9ynXP/pzOj4b83zzlaOfPtLTAmMhKWVV4Q85mrDQz+HzG4lKXM78eTsD8PyrocA/tSE7mVEJ0Jal4E2KI/Z9/fqpYFLB6LFlx5n83ehXM/egA0l4OeCC9nBKCeNUN3sIQO85lljyzAJdtWnsdoWogJs6qjcV8n2U5xjZxN5ZFdclYLjq6g2cjEXXMQxb8b7ZhHjLWFdjHP85UvXHK3DpK3JmUg8bYS7t1DJffDQNjawhlsMycKZN+r0ND0Um4m7AjGqxbKT/M2yKF"
347	],
348	"x5t":"BhJU_fcg8sDkvT8zOaL-U1ChXeE",
349	"x5t#S256":"IDJKS5LxImjvmuAl_Vx50Vj_dFdACSGW6DU8ADFRdRE"
350	}`
351
352	var jwk2 JSONWebKey
353	err := jwk2.UnmarshalJSON([]byte(hexJWK))
354	require.NoError(t, err)
355
356	js, err := jwk2.MarshalJSON()
357	require.NoError(t, err)
358
359	var j1, j2 map[string]interface{}
360	require.NoError(t, json.Unmarshal(js, &j1))
361	require.NoError(t, json.Unmarshal([]byte(output), &j2))
362	require.Empty(t, cmp.Diff(j1, j2))
363}
364
365func TestInvalidThumbprintsX509(t *testing.T) {
366	// Too short
367	jwk := JSONWebKey{
368		Key:                         rsaTestKey,
369		KeyID:                       "bar",
370		Algorithm:                   "foo",
371		Certificates:                testCertificates,
372		CertificateThumbprintSHA1:   []byte{0x01}, // invalid length
373		CertificateThumbprintSHA256: []byte{0x02}, // invalid length
374	}
375
376	_, err := jwk.MarshalJSON()
377	if err == nil {
378		t.Error("should not marshal JWK with too short thumbprints")
379	}
380
381	// Mismatched (leaf has different sum)
382	sha1sum := sha1.Sum(nil)
383	jwk.CertificateThumbprintSHA1 = sha1sum[:]
384	sha256sum := sha256.Sum256(nil)
385	jwk.CertificateThumbprintSHA256 = sha256sum[:]
386
387	_, err = jwk.MarshalJSON()
388	if err == nil {
389		t.Error("should not marshal JWK with mismatched thumbprints")
390	}
391
392	// Too short
393	shortThumbprints := []byte(`{
394  "kty": "RSA",
395  "kid": "bar",
396  "alg": "foo",
397  "n": "wN3v274Fr7grvZdXirEGkHlhYKh72gP-46MxQilMgANi6EaX2m0mYiMC60X1UmOhQNoVW0ItthMME-CGh7haA_Jeou_L6-EVOz-7lGu_J06VRl-mgkQZO0sYSkRY8Rsu7TW-pgnWWwZjSdgxN2gq7DvjjC4RLroV94Lgrb2Qwx6J5bZNOfj3pHmEWZ_eRFEH73Ct5RxwUKtNKx_XAmodZn9oFXBlN7F2Js-4DO-8UgbS7ALkTmhDzClT1GPfdLMusmXw4BXyV72vBOWrbUTdwk4pG8ahPQ0cGQ1ubaAmro_k3Bxg06voWPhXx7ALrpzmZCzr6YY-c5Y5rku4qXh-HQ",
398  "e": "AQAB",
399  "d": "RRM3xMvZ3YVopQ5_G_0rDLNsXOH6-apUr9LS4Y9JBtAvrGEcIe7VwHApq3ny0v870a5J19Vr6boIqVXQ2Or90kwL-O9JacHDiOTamd29KKbMb9fyGtWo88OBf5fbAv9pXyvQjEcZrqArD1eOyPlV5iXM6XfWT5X2KB-HuLIcFsVJSEb0yw943dEhZKkv2fySlVtKEhji2CfkMWP438G8auxwFPNIXmuvA1xvcAepOiI9I1Wy17txLOQg8MYBl98F7mxPUMpL3jm8-CSuxpknucFuFIrqIsbGmukSNp14APcu7bN0cJW5uVW-XtGbuioJkPjU2YJgfhIeMI8kuny5QQ",
400  "p": "yRNzbsreZK9MqJgbVsbl7SX2MyyJW_JnFKGdyrXzMqCtzRS7XJ9L3SwdDG_ERgSCkT9PP2dax9fS7RghHNJIU_NlPnJqzBPvPyzbjho7hcGYGDU2UO8E3SBP1WKm1SnlYhm1uHwrHudAO0D5jhVYQfRwem-zX3QibrsxEyxSELM",
401  "q": "9Yx0zzrhSxdE8ubryZfOyOw6cSbUdyCMgY3IFmEdb_UDZOQNMDCFj2RS1g6yFGKuaFqnL9ZRnmprikf20w-mu-LtLU_l0eK4U7pbAoB--pxFP_O6Yk3ZBu_YJ3FpimyX1v4OVZT-JOU_caKiTrPnlw3P7KbEc9iu_bOc8dE-_e8",
402  "dp": "GwiFbXDS44B58vS4QDtvcCm5Zvnm4bi-SRTNbRJ3Rug5Vagi5Hn6LhsfMKvaHHvAvhxf4CtaFiIbFos28HQJC1he1T12xEct1DWIsxstw3bapu6IhesMoVoVwZ-IxIHkeALy3oG7HmWCyjSbGJIgEoX1lVBtMjkf4_lAyM4dnmc",
403  "dq": "XYtXyMbOo3PG8Z6lfxRVU9gi346CbKu6u3RPIK94rnkyBNKYb55ck2cN47yPfRKnDNxUSvYj--zg8To_PuL8iyGFZ7jDffUYcdVR7J8VQNYdz6JDhEXSA0GGIGilY3XBVsdMoK_1Lgsj41-o48DH3pUFfEuAFf4blE1D4h_sFoM",
404  "qi": "CN3q5TMZO06DlK4onrJ687bPp2GE-fynd7ADPdf1ek3cXbeaFApVNp4w-i8zr7IVugQohn01i_jnkymw4UN-acoIzX2sGYhgDm6le1jyfv28bQ_Z5hT0rFNlPfGyK0kkPYUTxZ4ZCKpCYJT9C1nH58Yu4xFk4VR1zhULegjCCd4",
405  "x5c": [
406    "MIIDfDCCAmSgAwIBAgIJANWAkzF7PA8/MA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4GA1UECxMHZXhhbXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1sZWFmMB4XDTE2MDYxMDIyMTQxMVoXDTIzMDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLWxlYWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7stSvfQyGuHw3v34fisqIdDXberrFoFk9ht/WdXgYzX2uLNKdsR/J5sbWSl8K/5djpzj31eIzqU69w8v7SChM5x9bouDsABHz3kZucx5cSafEgJojysBkcrq3VY+aJanzbL+qErYX+lhRpPcZK6JMWIwar8Y3B2la4yWwieecw2/WfEVvG0M/DOYKnR8QHFsfl3US1dnBM84czKPyt9r40gDk2XiH/lGts5a94rAGvbr8IMCtq0mA5aH3Fx3mDSi3+4MZwygCAHrF5O5iSV9rEI+m2+7j2S+jHDUnvV+nqcpb9m6ENECnYX8FD2KcqlOjTmw8smDy09N2Np6i464lAgMBAAGjTzBNMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAsBgNVHREEJTAjhwR/AAABhxAAAAAAAAAAAAAAAAAAAAABgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAGM4aa/qrURUweZBIwZYv8O9b2+r4l0HjGAh982/B9sMlM05kojyDCUGvj86z18Lm8mKr4/y+i0nJ+vDIksEvfDuzw5ALAXGcBzPJKtICUf7LstA/n9NNpshWz0kld9ylnB5mbUzSFDncVyeXkEf5sGQXdIIZT9ChRBoiloSaa7dvBVCcsX1LGP2LWqKtD+7nUnw5qCwtyAVT8pthEUxFTpywoiJS5ZdzeEx8MNGvUeLFj2kleqPF78EioEQlSOxViCuctEtnQuPcDLHNFr10byTZY9roObiqdsJLMVvb2XliJjAqaPa9AkYwGE6xHw2ispwg64Rse0+AtKups19WIU="
407  ],
408  "x5t": "BhJU_fcg8sDkvT8zOaL-U1C",
409  "x5t#S256": "IDJKS5LxImjvmuAl_Vx50Vj_dFdACSGW6DU8ADF"
410}`)
411
412	// Mismatched (leaf has different sum)
413	mismatchedThumbprints := []byte(`{
414  "kty": "RSA",
415  "kid": "bar",
416  "alg": "foo",
417  "n": "wN3v274Fr7grvZdXirEGkHlhYKh72gP-46MxQilMgANi6EaX2m0mYiMC60X1UmOhQNoVW0ItthMME-CGh7haA_Jeou_L6-EVOz-7lGu_J06VRl-mgkQZO0sYSkRY8Rsu7TW-pgnWWwZjSdgxN2gq7DvjjC4RLroV94Lgrb2Qwx6J5bZNOfj3pHmEWZ_eRFEH73Ct5RxwUKtNKx_XAmodZn9oFXBlN7F2Js-4DO-8UgbS7ALkTmhDzClT1GPfdLMusmXw4BXyV72vBOWrbUTdwk4pG8ahPQ0cGQ1ubaAmro_k3Bxg06voWPhXx7ALrpzmZCzr6YY-c5Y5rku4qXh-HQ",
418  "e": "AQAB",
419  "d": "RRM3xMvZ3YVopQ5_G_0rDLNsXOH6-apUr9LS4Y9JBtAvrGEcIe7VwHApq3ny0v870a5J19Vr6boIqVXQ2Or90kwL-O9JacHDiOTamd29KKbMb9fyGtWo88OBf5fbAv9pXyvQjEcZrqArD1eOyPlV5iXM6XfWT5X2KB-HuLIcFsVJSEb0yw943dEhZKkv2fySlVtKEhji2CfkMWP438G8auxwFPNIXmuvA1xvcAepOiI9I1Wy17txLOQg8MYBl98F7mxPUMpL3jm8-CSuxpknucFuFIrqIsbGmukSNp14APcu7bN0cJW5uVW-XtGbuioJkPjU2YJgfhIeMI8kuny5QQ",
420  "p": "yRNzbsreZK9MqJgbVsbl7SX2MyyJW_JnFKGdyrXzMqCtzRS7XJ9L3SwdDG_ERgSCkT9PP2dax9fS7RghHNJIU_NlPnJqzBPvPyzbjho7hcGYGDU2UO8E3SBP1WKm1SnlYhm1uHwrHudAO0D5jhVYQfRwem-zX3QibrsxEyxSELM",
421  "q": "9Yx0zzrhSxdE8ubryZfOyOw6cSbUdyCMgY3IFmEdb_UDZOQNMDCFj2RS1g6yFGKuaFqnL9ZRnmprikf20w-mu-LtLU_l0eK4U7pbAoB--pxFP_O6Yk3ZBu_YJ3FpimyX1v4OVZT-JOU_caKiTrPnlw3P7KbEc9iu_bOc8dE-_e8",
422  "dp": "GwiFbXDS44B58vS4QDtvcCm5Zvnm4bi-SRTNbRJ3Rug5Vagi5Hn6LhsfMKvaHHvAvhxf4CtaFiIbFos28HQJC1he1T12xEct1DWIsxstw3bapu6IhesMoVoVwZ-IxIHkeALy3oG7HmWCyjSbGJIgEoX1lVBtMjkf4_lAyM4dnmc",
423  "dq": "XYtXyMbOo3PG8Z6lfxRVU9gi346CbKu6u3RPIK94rnkyBNKYb55ck2cN47yPfRKnDNxUSvYj--zg8To_PuL8iyGFZ7jDffUYcdVR7J8VQNYdz6JDhEXSA0GGIGilY3XBVsdMoK_1Lgsj41-o48DH3pUFfEuAFf4blE1D4h_sFoM",
424  "qi": "CN3q5TMZO06DlK4onrJ687bPp2GE-fynd7ADPdf1ek3cXbeaFApVNp4w-i8zr7IVugQohn01i_jnkymw4UN-acoIzX2sGYhgDm6le1jyfv28bQ_Z5hT0rFNlPfGyK0kkPYUTxZ4ZCKpCYJT9C1nH58Yu4xFk4VR1zhULegjCCd4",
425  "x5c": [
426    "MIIDfDCCAmSgAwIBAgIJANWAkzF7PA8/MA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4GA1UECxMHZXhhbXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1sZWFmMB4XDTE2MDYxMDIyMTQxMVoXDTIzMDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLWxlYWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7stSvfQyGuHw3v34fisqIdDXberrFoFk9ht/WdXgYzX2uLNKdsR/J5sbWSl8K/5djpzj31eIzqU69w8v7SChM5x9bouDsABHz3kZucx5cSafEgJojysBkcrq3VY+aJanzbL+qErYX+lhRpPcZK6JMWIwar8Y3B2la4yWwieecw2/WfEVvG0M/DOYKnR8QHFsfl3US1dnBM84czKPyt9r40gDk2XiH/lGts5a94rAGvbr8IMCtq0mA5aH3Fx3mDSi3+4MZwygCAHrF5O5iSV9rEI+m2+7j2S+jHDUnvV+nqcpb9m6ENECnYX8FD2KcqlOjTmw8smDy09N2Np6i464lAgMBAAGjTzBNMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAsBgNVHREEJTAjhwR/AAABhxAAAAAAAAAAAAAAAAAAAAABgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAGM4aa/qrURUweZBIwZYv8O9b2+r4l0HjGAh982/B9sMlM05kojyDCUGvj86z18Lm8mKr4/y+i0nJ+vDIksEvfDuzw5ALAXGcBzPJKtICUf7LstA/n9NNpshWz0kld9ylnB5mbUzSFDncVyeXkEf5sGQXdIIZT9ChRBoiloSaa7dvBVCcsX1LGP2LWqKtD+7nUnw5qCwtyAVT8pthEUxFTpywoiJS5ZdzeEx8MNGvUeLFj2kleqPF78EioEQlSOxViCuctEtnQuPcDLHNFr10byTZY9roObiqdsJLMVvb2XliJjAqaPa9AkYwGE6xHw2ispwg64Rse0+AtKups19WIU="
427  ],
428  "x5t": "BhJU_fcg8sDkvT8zOaL-U1ChXeX",
429  "x5t#S256": "IDJKS5LxImjvmuAl_Vx50Vj_dFdACSGW6DU8ADFRdRX"
430}`)
431
432	var jwk2 JSONWebKey
433	err = jwk2.UnmarshalJSON(mismatchedThumbprints)
434	if err == nil {
435		t.Error("should not unmarshal JWK with mismatched thumbprints")
436	}
437
438	err = jwk2.UnmarshalJSON(shortThumbprints)
439	if err == nil {
440		t.Error("should not unmarshal JWK with too short thumbprints")
441	}
442}
443
444func TestKeyMismatchX509(t *testing.T) {
445	x5tSHA1 := sha1.Sum(testCertificates[0].Raw)
446	x5tSHA256 := sha256.Sum256(testCertificates[0].Raw)
447
448	jwk := JSONWebKey{
449		KeyID:                       "bar",
450		Algorithm:                   "foo",
451		Certificates:                testCertificates,
452		CertificateThumbprintSHA1:   x5tSHA1[:],
453		CertificateThumbprintSHA256: x5tSHA256[:],
454	}
455
456	for _, key := range []interface{}{
457		// None of these keys should match what's in the cert, so parsing should always fail.
458		ecTestKey256,
459		ecTestKey256.Public(),
460		ecTestKey384,
461		ecTestKey384.Public(),
462		ecTestKey521,
463		ecTestKey521.Public(),
464		rsaTestKey,
465		rsaTestKey.Public(),
466		ed25519PrivateKey,
467		ed25519PrivateKey.Public(),
468	} {
469		jwk.Key = key
470		raw, _ := jwk.MarshalJSON()
471
472		var jwk2 JSONWebKey
473		err := jwk2.UnmarshalJSON(raw)
474		if err == nil {
475			t.Error("should not unmarshal JWK with key/cert mismatch")
476		}
477	}
478}
479
480func TestMarshalUnmarshal(t *testing.T) {
481	kid := "DEADBEEF"
482
483	for i, key := range []interface{}{
484		ecTestKey256,
485		ecTestKey256.Public(),
486		ecTestKey384,
487		ecTestKey384.Public(),
488		ecTestKey521,
489		ecTestKey521.Public(),
490		rsaTestKey,
491		rsaTestKey.Public(),
492		ed25519PrivateKey,
493		ed25519PrivateKey.Public(),
494	} {
495		for _, use := range []string{"", "sig", "enc"} {
496			jwk := JSONWebKey{Key: key, KeyID: kid, Algorithm: "foo"}
497			if use != "" {
498				jwk.Use = use
499			}
500
501			jsonbar, err := jwk.MarshalJSON()
502			if err != nil {
503				t.Error("problem marshaling", i, err)
504			}
505
506			var jwk2 JSONWebKey
507			err = jwk2.UnmarshalJSON(jsonbar)
508			if err != nil {
509				t.Fatal("problem unmarshalling", i, err)
510			}
511
512			jsonbar2, err := jwk2.MarshalJSON()
513			if err != nil {
514				t.Fatal("problem marshaling", i, err)
515			}
516
517			if !bytes.Equal(jsonbar, jsonbar2) {
518				t.Error("roundtrip should not lose information", i)
519			}
520			if jwk2.KeyID != kid {
521				t.Error("kid did not roundtrip JSON marshalling", i)
522			}
523
524			if jwk2.Algorithm != "foo" {
525				t.Error("alg did not roundtrip JSON marshalling", i)
526			}
527
528			if jwk2.Use != use {
529				t.Error("use did not roundtrip JSON marshalling", i)
530			}
531		}
532	}
533}
534
535func TestMarshalNonPointer(t *testing.T) {
536	type EmbedsKey struct {
537		Key JSONWebKey
538	}
539
540	keyJSON := []byte(`{
541		"e": "AQAB",
542		"kty": "RSA",
543		"n": "vd7rZIoTLEe-z1_8G1FcXSw9CQFEJgV4g9V277sER7yx5Qjz_Pkf2YVth6wwwFJEmzc0hoKY-MMYFNwBE4hQHw"
544	}`)
545	var parsedKey JSONWebKey
546	err := json.Unmarshal(keyJSON, &parsedKey)
547	if err != nil {
548		t.Errorf("Error unmarshalling key: %v", err)
549		return
550	}
551	ek := EmbedsKey{
552		Key: parsedKey,
553	}
554	out, err := json.Marshal(ek)
555	if err != nil {
556		t.Errorf("Error marshalling JSON: %v", err)
557		return
558	}
559	expected := "{\"Key\":{\"kty\":\"RSA\",\"n\":\"vd7rZIoTLEe-z1_8G1FcXSw9CQFEJgV4g9V277sER7yx5Qjz_Pkf2YVth6wwwFJEmzc0hoKY-MMYFNwBE4hQHw\",\"e\":\"AQAB\"}}"
560	if string(out) != expected {
561		t.Error("Failed to marshal embedded non-pointer JWK properly:", string(out))
562	}
563}
564
565func TestMarshalUnmarshalInvalid(t *testing.T) {
566	// Make an invalid curve coordinate by creating a byte array that is one
567	// byte too large, and setting the first byte to 1 (otherwise it's just zero).
568	invalidCoord := make([]byte, curveSize(ecTestKey256.Curve)+1)
569	invalidCoord[0] = 1
570
571	keys := []interface{}{
572		// Empty keys
573		&rsa.PrivateKey{},
574		&ecdsa.PrivateKey{},
575		// Invalid keys
576		&ecdsa.PrivateKey{
577			PublicKey: ecdsa.PublicKey{
578				// Missing values in pub key
579				Curve: elliptic.P256(),
580			},
581		},
582		&ecdsa.PrivateKey{
583			PublicKey: ecdsa.PublicKey{
584				// Invalid curve
585				Curve: nil,
586				X:     ecTestKey256.X,
587				Y:     ecTestKey256.Y,
588			},
589		},
590		&ecdsa.PrivateKey{
591			// Valid pub key, but missing priv key values
592			PublicKey: ecTestKey256.PublicKey,
593		},
594		&ecdsa.PrivateKey{
595			// Invalid pub key, values too large
596			PublicKey: ecdsa.PublicKey{
597				Curve: ecTestKey256.Curve,
598				X:     big.NewInt(0).SetBytes(invalidCoord),
599				Y:     big.NewInt(0).SetBytes(invalidCoord),
600			},
601			D: ecTestKey256.D,
602		},
603		nil,
604	}
605
606	for i, key := range keys {
607		jwk := JSONWebKey{Key: key}
608		_, err := jwk.MarshalJSON()
609		if err == nil {
610			t.Error("managed to serialize invalid key", i)
611		}
612	}
613}
614
615func TestWebKeyVectorsInvalid(t *testing.T) {
616	keys := []string{
617		// Invalid JSON
618		"{X",
619		// Empty key
620		"{}",
621		// Invalid RSA keys
622		`{"kty":"RSA"}`,
623		`{"kty":"RSA","e":""}`,
624		`{"kty":"RSA","e":"XXXX"}`,
625		`{"kty":"RSA","d":"XXXX"}`,
626		// Invalid EC keys
627		`{"kty":"EC","crv":"ABC"}`,
628		`{"kty":"EC","crv":"P-256"}`,
629		`{"kty":"EC","crv":"P-256","d":"XXX"}`,
630		`{"kty":"EC","crv":"ABC","d":"dGVzdA","x":"dGVzdA"}`,
631		`{"kty":"EC","crv":"P-256","d":"dGVzdA","x":"dGVzdA"}`,
632	}
633
634	for _, key := range keys {
635		var jwk2 JSONWebKey
636		err := jwk2.UnmarshalJSON([]byte(key))
637		if err == nil {
638			t.Error("managed to parse invalid key:", key)
639		}
640	}
641}
642
643// Test vectors from RFC 7520
644var cookbookJWKs = []string{
645	// EC Public
646	stripWhitespace(`{
647     "kty": "EC",
648     "kid": "bilbo.baggins@hobbiton.example",
649     "use": "sig",
650     "crv": "P-521",
651     "x": "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9
652         A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt",
653     "y": "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVy
654         SsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1"
655   }`),
656
657	//ED Private
658	stripWhitespace(`{
659     "kty": "OKP",
660     "crv": "Ed25519",
661     "x": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo",
662     "d": "nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A"
663   }`),
664
665	// EC Private
666	stripWhitespace(`{
667     "kty": "EC",
668     "kid": "bilbo.baggins@hobbiton.example",
669     "use": "sig",
670     "crv": "P-521",
671     "x": "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9
672           A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt",
673     "y": "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVy
674           SsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1",
675     "d": "AAhRON2r9cqXX1hg-RoI6R1tX5p2rUAYdmpHZoC1XNM56KtscrX6zb
676           KipQrCW9CGZH3T4ubpnoTKLDYJ_fF3_rJt"
677   }`),
678
679	// RSA Public
680	stripWhitespace(`{
681     "kty": "RSA",
682     "kid": "bilbo.baggins@hobbiton.example",
683     "use": "sig",
684     "n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT
685         -O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqV
686         wGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-
687         oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde
688         3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuC
689         LqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5g
690         HdrNP5zw",
691     "e": "AQAB"
692   }`),
693
694	// RSA Private
695	stripWhitespace(`{"kty":"RSA",
696      "kid":"juliet@capulet.lit",
697      "use":"enc",
698      "n":"t6Q8PWSi1dkJj9hTP8hNYFlvadM7DflW9mWepOJhJ66w7nyoK1gPNqFMSQRy
699           O125Gp-TEkodhWr0iujjHVx7BcV0llS4w5ACGgPrcAd6ZcSR0-Iqom-QFcNP
700           8Sjg086MwoqQU_LYywlAGZ21WSdS_PERyGFiNnj3QQlO8Yns5jCtLCRwLHL0
701           Pb1fEv45AuRIuUfVcPySBWYnDyGxvjYGDSM-AqWS9zIQ2ZilgT-GqUmipg0X
702           OC0Cc20rgLe2ymLHjpHciCKVAbY5-L32-lSeZO-Os6U15_aXrk9Gw8cPUaX1
703           _I8sLGuSiVdt3C_Fn2PZ3Z8i744FPFGGcG1qs2Wz-Q",
704      "e":"AQAB",
705      "d":"GRtbIQmhOZtyszfgKdg4u_N-R_mZGU_9k7JQ_jn1DnfTuMdSNprTeaSTyWfS
706           NkuaAwnOEbIQVy1IQbWVV25NY3ybc_IhUJtfri7bAXYEReWaCl3hdlPKXy9U
707           vqPYGR0kIXTQRqns-dVJ7jahlI7LyckrpTmrM8dWBo4_PMaenNnPiQgO0xnu
708           ToxutRZJfJvG4Ox4ka3GORQd9CsCZ2vsUDmsXOfUENOyMqADC6p1M3h33tsu
709           rY15k9qMSpG9OX_IJAXmxzAh_tWiZOwk2K4yxH9tS3Lq1yX8C1EWmeRDkK2a
710           hecG85-oLKQt5VEpWHKmjOi_gJSdSgqcN96X52esAQ",
711      "p":"2rnSOV4hKSN8sS4CgcQHFbs08XboFDqKum3sc4h3GRxrTmQdl1ZK9uw-PIHf
712           QP0FkxXVrx-WE-ZEbrqivH_2iCLUS7wAl6XvARt1KkIaUxPPSYB9yk31s0Q8
713           UK96E3_OrADAYtAJs-M3JxCLfNgqh56HDnETTQhH3rCT5T3yJws",
714      "q":"1u_RiFDP7LBYh3N4GXLT9OpSKYP0uQZyiaZwBtOCBNJgQxaj10RWjsZu0c6I
715           edis4S7B_coSKB0Kj9PaPaBzg-IySRvvcQuPamQu66riMhjVtG6TlV8CLCYK
716           rYl52ziqK0E_ym2QnkwsUX7eYTB7LbAHRK9GqocDE5B0f808I4s",
717      "dp":"KkMTWqBUefVwZ2_Dbj1pPQqyHSHjj90L5x_MOzqYAJMcLMZtbUtwKqvVDq3
718           tbEo3ZIcohbDtt6SbfmWzggabpQxNxuBpoOOf_a_HgMXK_lhqigI4y_kqS1w
719           Y52IwjUn5rgRrJ-yYo1h41KR-vz2pYhEAeYrhttWtxVqLCRViD6c",
720      "dq":"AvfS0-gRxvn0bwJoMSnFxYcK1WnuEjQFluMGfwGitQBWtfZ1Er7t1xDkbN9
721           GQTB9yqpDoYaN06H7CFtrkxhJIBQaj6nkF5KKS3TQtQ5qCzkOkmxIe3KRbBy
722           mXxkb5qwUpX5ELD5xFc6FeiafWYY63TmmEAu_lRFCOJ3xDea-ots",
723      "qi":"lSQi-w9CpyUReMErP1RsBLk7wNtOvs5EQpPqmuMvqW57NBUczScEoPwmUqq
724           abu9V0-Py4dQ57_bapoKRu1R90bvuFnU63SHWEFglZQvJDMeAvmj4sm-Fp0o
725           Yu_neotgQ0hzbI5gry7ajdYy9-2lNx_76aBZoOUu9HCJ-UsfSOI8"}`),
726
727	// X.509 Certificate Chain
728	stripWhitespace(`{"kty":"RSA",
729      "use":"sig",
730      "kid":"1b94c",
731      "n":"vrjOfz9Ccdgx5nQudyhdoR17V-IubWMeOZCwX_jj0hgAsz2J_pqYW08
732           PLbK_PdiVGKPrqzmDIsLI7sA25VEnHU1uCLNwBuUiCO11_-7dYbsr4iJmG0Q
733           u2j8DsVyT1azpJC_NG84Ty5KKthuCaPod7iI7w0LK9orSMhBEwwZDCxTWq4a
734           YWAchc8t-emd9qOvWtVMDC2BXksRngh6X5bUYLy6AyHKvj-nUy1wgzjYQDwH
735           MTplCoLtU-o-8SNnZ1tmRoGE9uJkBLdh5gFENabWnU5m1ZqZPdwS-qo-meMv
736           VfJb6jJVWRpl2SUtCnYG2C32qvbWbjZ_jBPD5eunqsIo1vQ",
737      "e":"AQAB",
738      "x5c":
739           ["MIIDQjCCAiqgAwIBAgIGATz/FuLiMA0GCSqGSIb3DQEBBQUAMGIxCzAJB
740           gNVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYD
741           VQQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1
742           wYmVsbDAeFw0xMzAyMjEyMzI5MTVaFw0xODA4MTQyMjI5MTVaMGIxCzAJBg
743           NVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYDV
744           QQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1w
745           YmVsbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL64zn8/QnH
746           YMeZ0LncoXaEde1fiLm1jHjmQsF/449IYALM9if6amFtPDy2yvz3YlRij66
747           s5gyLCyO7ANuVRJx1NbgizcAblIgjtdf/u3WG7K+IiZhtELto/A7Fck9Ws6
748           SQvzRvOE8uSirYbgmj6He4iO8NCyvaK0jIQRMMGQwsU1quGmFgHIXPLfnpn
749           fajr1rVTAwtgV5LEZ4Iel+W1GC8ugMhyr4/p1MtcIM42EA8BzE6ZQqC7VPq
750           PvEjZ2dbZkaBhPbiZAS3YeYBRDWm1p1OZtWamT3cEvqqPpnjL1XyW+oyVVk
751           aZdklLQp2Btgt9qr21m42f4wTw+Xrp6rCKNb0CAwEAATANBgkqhkiG9w0BA
752           QUFAAOCAQEAh8zGlfSlcI0o3rYDPBB07aXNswb4ECNIKG0CETTUxmXl9KUL
753           +9gGlqCz5iWLOgWsnrcKcY0vXPG9J1r9AqBNTqNgHq2G03X09266X5CpOe1
754           zFo+Owb1zxtp3PehFdfQJ610CDLEaS9V9Rqp17hCyybEpOGVwe8fnk+fbEL
755           2Bo3UPGrpsHzUoaGpDftmWssZkhpBJKVMJyf/RuP2SmmaIzmnw9JiSlYhzo
756           4tpzd5rFXhjRbg4zW9C+2qok+2+qDM1iJ684gPHMIY8aLWrdgQTxkumGmTq
757           gawR+N5MDtdPTEQ0XfIBc2cJEUyMTY5MPvACWpkA6SdS4xSvdXK3IVfOWA=="]}`),
758}
759
760// SHA-256 thumbprints of the above keys, hex-encoded
761var cookbookJWKThumbprints = []string{
762	"747ae2dd2003664aeeb21e4753fe7402846170a16bc8df8f23a8cf06d3cbe793",
763	"f6934029a341ddf81dceb753e91d17efe16664f40d9f4ed84bc5ea87e111f29d",
764	"747ae2dd2003664aeeb21e4753fe7402846170a16bc8df8f23a8cf06d3cbe793",
765	"f63838e96077ad1fc01c3f8405774dedc0641f558ebb4b40dccf5f9b6d66a932",
766	"0fc478f8579325fcee0d4cbc6d9d1ce21730a6e97e435d6008fb379b0ebe47d4",
767	"0ddb05bfedbec2070fa037324ba397396561d3425d6d69245570c261dc49dee3",
768}
769
770func TestWebKeyVectorsValid(t *testing.T) {
771	for _, key := range cookbookJWKs {
772		var jwk2 JSONWebKey
773		err := jwk2.UnmarshalJSON([]byte(key))
774		if err != nil {
775			t.Error("unable to parse valid key:", key, err)
776		}
777	}
778}
779
780func TestEd25519Serialization(t *testing.T) {
781	jwk := JSONWebKey{
782		Key: ed25519PrivateKey,
783	}
784	serialized, _ := json.Marshal(jwk)
785
786	var jwk2 JSONWebKey
787	json.Unmarshal(serialized, &jwk2)
788
789	assert.True(t, bytes.Equal(
790		[]byte(jwk.Key.(ed25519.PrivateKey).Public().(ed25519.PublicKey)),
791		[]byte(jwk2.Key.(ed25519.PrivateKey).Public().(ed25519.PublicKey))))
792}
793
794func TestThumbprint(t *testing.T) {
795	for i, key := range cookbookJWKs {
796		var jwk2 JSONWebKey
797		err := jwk2.UnmarshalJSON([]byte(key))
798		if err != nil {
799			t.Error("unable to parse valid key:", key, err)
800		}
801
802		tp, err := jwk2.Thumbprint(crypto.SHA256)
803		if err != nil {
804			t.Error("unable to compute thumbprint:", key, err)
805		}
806
807		tpHex := hex.EncodeToString(tp)
808		if cookbookJWKThumbprints[i] != tpHex {
809			t.Error("incorrect thumbprint:", i, cookbookJWKThumbprints[i], tpHex)
810		}
811	}
812}
813
814func TestMarshalUnmarshalJWKSet(t *testing.T) {
815	jwk1 := JSONWebKey{Key: rsaTestKey, KeyID: "ABCDEFG", Algorithm: "foo"}
816	jwk2 := JSONWebKey{Key: rsaTestKey, KeyID: "GFEDCBA", Algorithm: "foo"}
817	var set JSONWebKeySet
818	set.Keys = append(set.Keys, jwk1)
819	set.Keys = append(set.Keys, jwk2)
820
821	jsonbar, err := json.Marshal(&set)
822	if err != nil {
823		t.Error("problem marshalling set", err)
824	}
825	var set2 JSONWebKeySet
826	err = json.Unmarshal(jsonbar, &set2)
827	if err != nil {
828		t.Fatal("problem unmarshalling set", err)
829	}
830	jsonbar2, err := json.Marshal(&set2)
831	if err != nil {
832		t.Fatal("problem marshalling set", err)
833	}
834	if !bytes.Equal(jsonbar, jsonbar2) {
835		t.Error("roundtrip should not lose information")
836	}
837}
838
839func TestJWKSetKey(t *testing.T) {
840	jwk1 := JSONWebKey{Key: rsaTestKey, KeyID: "ABCDEFG", Algorithm: "foo"}
841	jwk2 := JSONWebKey{Key: rsaTestKey, KeyID: "GFEDCBA", Algorithm: "foo"}
842	var set JSONWebKeySet
843	set.Keys = append(set.Keys, jwk1)
844	set.Keys = append(set.Keys, jwk2)
845	k := set.Key("ABCDEFG")
846	if len(k) != 1 {
847		t.Errorf("method should return slice with one key not %d", len(k))
848	}
849	if k[0].KeyID != "ABCDEFG" {
850		t.Error("method should return key with ID ABCDEFG")
851	}
852}
853
854func TestJWKSymmetricKey(t *testing.T) {
855	sample1 := `{"kty":"oct","alg":"A128KW","k":"GawgguFyGrWKav7AX4VKUg"}`
856	sample2 := `{"kty":"oct","k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow","kid":"HMAC key used in JWS spec Appendix A.1 example"}`
857
858	var jwk1 JSONWebKey
859	json.Unmarshal([]byte(sample1), &jwk1)
860
861	if jwk1.Algorithm != "A128KW" {
862		t.Errorf("expected Algorithm to be A128KW, but was '%s'", jwk1.Algorithm)
863	}
864	expected1 := fromHexBytes("19ac2082e1721ab58a6afec05f854a52")
865	if !bytes.Equal(jwk1.Key.([]byte), expected1) {
866		t.Errorf("expected Key to be '%s', but was '%s'", hex.EncodeToString(expected1), hex.EncodeToString(jwk1.Key.([]byte)))
867	}
868
869	var jwk2 JSONWebKey
870	json.Unmarshal([]byte(sample2), &jwk2)
871
872	if jwk2.KeyID != "HMAC key used in JWS spec Appendix A.1 example" {
873		t.Errorf("expected KeyID to be 'HMAC key used in JWS spec Appendix A.1 example', but was '%s'", jwk2.KeyID)
874	}
875	expected2 := fromHexBytes(`
876    0323354b2b0fa5bc837e0665777ba68f5ab328e6f054c928a90f84b2d2502ebf
877    d3fb5a92d20647ef968ab4c377623d223d2e2172052e4f08c0cd9af567d080a3`)
878	if !bytes.Equal(jwk2.Key.([]byte), expected2) {
879		t.Errorf("expected Key to be '%s', but was '%s'", hex.EncodeToString(expected2), hex.EncodeToString(jwk2.Key.([]byte)))
880	}
881}
882
883func TestJWKSymmetricRoundtrip(t *testing.T) {
884	jwk1 := JSONWebKey{Key: []byte{1, 2, 3, 4}}
885	marshaled, err := jwk1.MarshalJSON()
886	if err != nil {
887		t.Error("failed to marshal valid JWK object", err)
888	}
889
890	var jwk2 JSONWebKey
891	err = jwk2.UnmarshalJSON(marshaled)
892	if err != nil {
893		t.Error("failed to unmarshal valid JWK object", err)
894	}
895
896	if !bytes.Equal(jwk1.Key.([]byte), jwk2.Key.([]byte)) {
897		t.Error("round-trip of symmetric JWK gave different raw keys")
898	}
899}
900
901func TestJWKSymmetricInvalid(t *testing.T) {
902	invalid := JSONWebKey{}
903	_, err := invalid.MarshalJSON()
904	if err == nil {
905		t.Error("excepted error on marshaling invalid symmetric JWK object")
906	}
907
908	var jwk JSONWebKey
909	err = jwk.UnmarshalJSON([]byte(`{"kty":"oct"}`))
910	if err == nil {
911		t.Error("excepted error on unmarshaling invalid symmetric JWK object")
912	}
913}
914
915func TestJWKIsPublic(t *testing.T) {
916	bigInt := big.NewInt(0)
917	eccPub := ecdsa.PublicKey{elliptic.P256(), bigInt, bigInt}
918	rsaPub := rsa.PublicKey{bigInt, 1}
919
920	cases := []struct {
921		key              interface{}
922		expectedIsPublic bool
923	}{
924		{&eccPub, true},
925		{&ecdsa.PrivateKey{eccPub, bigInt}, false},
926		{&rsaPub, true},
927		{&rsa.PrivateKey{rsaPub, bigInt, []*big.Int{bigInt, bigInt}, rsa.PrecomputedValues{}}, false},
928		{ed25519PublicKey, true},
929		{ed25519PrivateKey, false},
930	}
931
932	for _, tc := range cases {
933		k := &JSONWebKey{Key: tc.key}
934		if public := k.IsPublic(); public != tc.expectedIsPublic {
935			t.Errorf("expected IsPublic to return %t, got %t", tc.expectedIsPublic, public)
936		}
937	}
938}
939
940func TestJWKValid(t *testing.T) {
941	bigInt := big.NewInt(0)
942	eccPub := ecdsa.PublicKey{elliptic.P256(), bigInt, bigInt}
943	rsaPub := rsa.PublicKey{bigInt, 1}
944	edPubEmpty := ed25519.PublicKey([]byte{})
945	edPrivEmpty := ed25519.PublicKey([]byte{})
946
947	cases := []struct {
948		key              interface{}
949		expectedValidity bool
950	}{
951		{nil, false},
952		{&ecdsa.PublicKey{}, false},
953		{&eccPub, true},
954		{&ecdsa.PrivateKey{}, false},
955		{&ecdsa.PrivateKey{eccPub, bigInt}, true},
956		{&rsa.PublicKey{}, false},
957		{&rsaPub, true},
958		{&rsa.PrivateKey{}, false},
959		{&rsa.PrivateKey{rsaPub, bigInt, []*big.Int{bigInt, bigInt}, rsa.PrecomputedValues{}}, true},
960		{ed25519PublicKey, true},
961		{ed25519PrivateKey, true},
962		{edPubEmpty, false},
963		{edPrivEmpty, false},
964	}
965
966	for _, tc := range cases {
967		k := &JSONWebKey{Key: tc.key}
968		valid := k.Valid()
969		if valid != tc.expectedValidity {
970			t.Errorf("expected Valid to return %t, got %t", tc.expectedValidity, valid)
971		}
972		if valid {
973			wasPublic := k.IsPublic()
974			p := k.Public() // all aforemention keys are asymmetric
975			if !p.Valid() {
976				t.Errorf("unable to derive public key from valid asymmetric key")
977			}
978			if wasPublic != k.IsPublic() {
979				t.Errorf("original key was touched during public key derivation")
980			}
981		}
982	}
983}
984
985func TestJWKBufferSizeCheck(t *testing.T) {
986	key := `{
987		"kty":"EC",
988		"crv":"P-256",
989		"x":"m9GSmJ5iGmAYlMlaOJGSFN_CjN9cIn8GGYExP-C0FBiIXlWTNvGN38R9WdrHcppfsKF0FXMOMyutpHIRaiMxYSA",
990		"y":"ZaPcRZ3q_7T3h-Gwz2i-T2JjJXfj6YVGgKHcFz5zqmg"}`
991	var jwk JSONWebKey
992	jwk.UnmarshalJSON([]byte(key))
993	jwk.Valid() // true
994	// panic: square/go-jose: invalid call to newFixedSizeBuffer (len(data) > length)
995	// github.com/square/go-jose.newFixedSizeBuffer(0xc420014557, 0x41, 0x41, 0x20, 0x0)
996	jwk.Thumbprint(crypto.SHA256)
997}
998
999func TestJWKPaddingPrivateX(t *testing.T) {
1000	key := `{
1001    "kty": "EC",
1002    "crv": "P-256",
1003    "x": "nPTIABcDASY6FNGSNfHCB51tY7qChtgzeVazOtLrwQ",
1004    "y": "vEEs4V0egJkNyM2Q4pp001zu14VcpQ0_Ei8xOOPxKZs",
1005    "d": "nIVCvMR2wkLmeGJErOpI23VDHl2s3JwGdbzKy0odir0"
1006  }`
1007	var jwk JSONWebKey
1008	err := jwk.UnmarshalJSON([]byte(key))
1009	if err == nil {
1010		t.Errorf("Expected key with short x to fail unmarshalling")
1011	}
1012	if !strings.Contains(err.Error(), "wrong length for x") {
1013		t.Errorf("Wrong error for short x, got %q", err)
1014	}
1015	if jwk.Valid() {
1016		t.Errorf("Expected key to be invalid, but it was valid.")
1017	}
1018}
1019
1020func TestJWKPaddingPrivateY(t *testing.T) {
1021	key := `{
1022    "kty": "EC",
1023    "crv": "P-256",
1024    "x": "vEEs4V0egJkNyM2Q4pp001zu14VcpQ0_Ei8xOOPxKZs",
1025    "y": "nPTIABcDASY6FNGSNfHCB51tY7qChtgzeVazOtLrwQ",
1026    "d": "nIVCvMR2wkLmeGJErOpI23VDHl2s3JwGdbzKy0odir0"
1027  }`
1028	var jwk JSONWebKey
1029	err := jwk.UnmarshalJSON([]byte(key))
1030	if err == nil {
1031		t.Errorf("Expected key with short x to fail unmarshalling")
1032	}
1033	if !strings.Contains(err.Error(), "wrong length for y") {
1034		t.Errorf("Wrong error for short y, got %q", err)
1035	}
1036	if jwk.Valid() {
1037		t.Errorf("Expected key to be invalid, but it was valid.")
1038	}
1039}
1040
1041func TestJWKPaddingPrivateD(t *testing.T) {
1042	key := `{
1043    "kty": "EC",
1044    "crv": "P-256",
1045    "x": "vEEs4V0egJkNyM2Q4pp001zu14VcpQ0_Ei8xOOPxKZs",
1046    "y": "qnPTIABcDASY6FNGSNfHCB51tY7qChtgzeVazOtLrwQ",
1047    "d": "IVCvMR2wkLmeGJErOpI23VDHl2s3JwGdbzKy0odir0"
1048  }`
1049	var jwk JSONWebKey
1050	err := jwk.UnmarshalJSON([]byte(key))
1051	if err == nil {
1052		t.Errorf("Expected key with short x to fail unmarshalling")
1053	}
1054	if !strings.Contains(err.Error(), "wrong length for d") {
1055		t.Errorf("Wrong error for short d, got %q", err)
1056	}
1057	if jwk.Valid() {
1058		t.Errorf("Expected key to be invalid, but it was valid.")
1059	}
1060}
1061
1062func TestJWKPaddingX(t *testing.T) {
1063	key := `{
1064    "kty": "EC",
1065    "crv": "P-256",
1066    "x": "nPTIABcDASY6FNGSNfHCB51tY7qChtgzeVazOtLrwQ",
1067    "y": "vEEs4V0egJkNyM2Q4pp001zu14VcpQ0_Ei8xOOPxKZs"
1068  }`
1069	var jwk JSONWebKey
1070	err := jwk.UnmarshalJSON([]byte(key))
1071	if err == nil {
1072		t.Errorf("Expected key with short x to fail unmarshalling")
1073	}
1074	if !strings.Contains(err.Error(), "wrong length for x") {
1075		t.Errorf("Wrong error for short x, got %q", err)
1076	}
1077	if jwk.Valid() {
1078		t.Errorf("Expected key to be invalid, but it was valid.")
1079	}
1080}
1081
1082func TestJWKPaddingY(t *testing.T) {
1083	key := `{
1084    "kty": "EC",
1085    "crv": "P-256",
1086    "x": "vEEs4V0egJkNyM2Q4pp001zu14VcpQ0_Ei8xOOPxKZs",
1087    "y": "nPTIABcDASY6FNGSNfHCB51tY7qChtgzeVazOtLrwQ"
1088  }`
1089	var jwk JSONWebKey
1090	err := jwk.UnmarshalJSON([]byte(key))
1091	if err == nil {
1092		t.Errorf("Expected key with short y to fail unmarshalling")
1093	}
1094	if !strings.Contains(err.Error(), "wrong length for y") {
1095		t.Errorf("Wrong error for short y, got %q", err)
1096	}
1097	if jwk.Valid() {
1098		t.Errorf("Expected key to be invalid, but it was valid.")
1099	}
1100}
1101