xref: /aosp_15_r20/external/tink/go/jwt/jwt_signer_verifier_kid_test.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1// Copyright 2022 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15////////////////////////////////////////////////////////////////////////////////
16
17package jwt
18
19import (
20	"fmt"
21	"testing"
22	"time"
23
24	"github.com/google/tink/go/signature/subtle"
25	"github.com/google/tink/go/tink"
26)
27
28func createTinkECVerifier() (tink.Verifier, error) {
29	// Public key from: https://datatracker.ietf.org/doc/html/rfc7515#appendix-A.3
30	x, err := base64Decode("f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU")
31	if err != nil {
32		return nil, fmt.Errorf("base64 decoding x coordinate of public key: %v", err)
33	}
34	y, err := base64Decode("x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0")
35	if err != nil {
36		return nil, fmt.Errorf("base64 decoding y coordinate of public key: %v", err)
37	}
38	tv, err := subtle.NewECDSAVerifier("SHA256", "NIST_P256", "IEEE_P1363", x, y)
39	if err != nil {
40		return nil, fmt.Errorf("subtle.NewECDSAVerifier() err = %v, want nil", err)
41	}
42	return tv, nil
43}
44
45func createTinkECSigner() (tink.Signer, error) {
46	// Private key from: https://datatracker.ietf.org/doc/html/rfc7515#appendix-A.3
47	k, err := base64Decode("jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI")
48	if err != nil {
49		return nil, fmt.Errorf("base64 decoding private key: %v", err)
50	}
51	ts, err := subtle.NewECDSASigner("SHA256", "NIST_P256", "IEEE_P1363", k)
52	if err != nil {
53		return nil, fmt.Errorf("subtle.NewECDSASigner() err = %v, want nil", err)
54	}
55	return ts, nil
56}
57
58func createESVerifier(kid *string) (*verifierWithKID, error) {
59	tv, err := createTinkECVerifier()
60	if err != nil {
61		return nil, err
62	}
63	v, err := newVerifierWithKID(tv, "ES256", kid)
64	if err != nil {
65		return nil, fmt.Errorf("newVerifierWithKID(algorithm = 'ES256') err = %v, want nil", err)
66	}
67	return v, nil
68}
69
70func createESSigner(kid *string) (*signerWithKID, error) {
71	ts, err := createTinkECSigner()
72	if err != nil {
73		return nil, err
74	}
75	s, err := newSignerWithKID(ts, "ES256", kid)
76	if err != nil {
77		return nil, fmt.Errorf("newSignerWithKID(algorithm = 'ES256') err = %v, want nil", err)
78	}
79	return s, nil
80}
81
82func TestVerifierWithFixedToken(t *testing.T) {
83	// compact from: https://datatracker.ietf.org/doc/html/rfc7515#appendix-A.3
84	compact := "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q"
85	v, err := createESVerifier(nil)
86	if err != nil {
87		t.Fatal(err)
88	}
89	validator, err := NewValidator(&ValidatorOpts{ExpectedIssuer: refString("joe"), FixedNow: time.Unix(1300819300, 0)})
90	if err != nil {
91		t.Fatalf("NewValidator() err = %v, want nil", err)
92	}
93	verified, err := v.VerifyAndDecodeWithKID(compact, validator, nil)
94	if err != nil {
95		t.Errorf("VerifyAndDecodeWithKID() err = %v, want nil", err)
96	}
97	issuer, err := verified.Issuer()
98	if err != nil {
99		t.Errorf("verified.Issuer() err = %v, want nil", err)
100	}
101	if issuer != "joe" {
102		t.Errorf("verified.Issuer() = %q, want joe", issuer)
103	}
104	expiration, err := verified.ExpiresAt()
105	if err != nil {
106		t.Errorf("verified.ExpiresAt() err = %v, want nil", err)
107	}
108	wantExp := time.Unix(1300819380, 0)
109	if !expiration.Equal(wantExp) {
110		t.Errorf("verified.ExpiresAt() = %q, want %q", expiration, wantExp)
111	}
112	boolClaim, err := verified.BooleanClaim("http://example.com/is_root")
113	if err != nil {
114		t.Errorf("verified.BooleanClaim('http://example.com/is_root') err = %v, want nil", err)
115	}
116	if boolClaim != true {
117		t.Errorf("verified.BooleanClaim('http://example.com/is_root') = %v, want false", boolClaim)
118	}
119}
120
121func TestCreateSignValidateToken(t *testing.T) {
122	rawJWT, err := NewRawJWT(&RawJWTOptions{TypeHeader: refString("JWT"), WithoutExpiration: true})
123	if err != nil {
124		t.Fatalf("NewRawJWT() err = %v, want nil", err)
125	}
126	validator, err := NewValidator(&ValidatorOpts{ExpectedTypeHeader: refString("JWT"), AllowMissingExpiration: true})
127	if err != nil {
128		t.Fatalf("NewValidator() err = %v, want nil", err)
129	}
130	s, err := createESSigner(nil)
131	if err != nil {
132		t.Fatal(err)
133	}
134	v, err := createESVerifier(nil)
135	if err != nil {
136		t.Fatal(err)
137	}
138
139	compact, err := s.SignAndEncodeWithKID(rawJWT, nil)
140	if err != nil {
141		t.Fatalf("s.SignAndEncodeWithKID() err = %v, want nil", err)
142	}
143	verified, err := v.VerifyAndDecodeWithKID(compact, validator, nil)
144	if err != nil {
145		t.Fatalf("v.VerifyAndDecodeWithKID() err = %v, want nil", err)
146	}
147	typeHeader, err := verified.TypeHeader()
148	if err != nil {
149		t.Errorf("verified.TypeHeader() err = %v, want nil", err)
150	}
151	if typeHeader != "JWT" {
152		t.Errorf("verified.TypeHeader() = %q, want 'JWT'", typeHeader)
153	}
154}
155
156func TestSignerWithTinkAndCustomKIDFails(t *testing.T) {
157	rawJWT, err := NewRawJWT(&RawJWTOptions{TypeHeader: refString("JWT"), WithoutExpiration: true})
158	if err != nil {
159		t.Fatalf("NewRawJWT() err = %v, want nil", err)
160	}
161	s, err := createESSigner(refString("1234"))
162	if err != nil {
163		t.Fatal(err)
164	}
165	if _, err := s.SignAndEncodeWithKID(rawJWT, refString("123")); err == nil {
166		t.Errorf("s.SignAndEncodeWithKID(kid = 123) err = nil, want error")
167	}
168}
169
170type signerVerifierKIDTestCase struct {
171	tag               string
172	signerCustomKID   *string
173	verifierCustomKID *string
174	// calculated from the Tink Key ID.
175	signerKID *string
176	// calculated from the Tink Key ID.
177	verifierKID *string
178}
179
180func TestSignVerifyWithKID(t *testing.T) {
181	rawJWT, err := NewRawJWT(&RawJWTOptions{TypeHeader: refString("JWT"), WithoutExpiration: true})
182	if err != nil {
183		t.Fatalf("NewRawJWT() err = %v, want nil", err)
184	}
185	validator, err := NewValidator(&ValidatorOpts{ExpectedTypeHeader: refString("JWT"), AllowMissingExpiration: true})
186	if err != nil {
187		t.Fatalf("NewValidator() err = %v, want nil", err)
188	}
189	for _, tc := range []signerVerifierKIDTestCase{
190		{
191			tag:               "verifier with custom kid matches kid in header generated with custom kid",
192			signerCustomKID:   refString("1234"),
193			verifierCustomKID: refString("1234"),
194		},
195		{
196			tag:             "verifier with tink kid matches kid in header generated with custom kid",
197			signerCustomKID: refString("1234"),
198			verifierKID:     refString("1234"),
199		},
200		{
201			tag:         "verifier with tink kid matches kid in header generated with tink kid",
202			signerKID:   refString("1234"),
203			verifierKID: refString("1234"),
204		},
205		{
206			tag:       "no kid in verifier ignores kid when present in header",
207			signerKID: refString("1234"),
208		},
209		{
210			tag:               "verifier with custom kid ignores when no kid present in header",
211			verifierCustomKID: refString("1234"),
212		},
213	} {
214		t.Run(tc.tag, func(t *testing.T) {
215			s, err := createESSigner(tc.signerCustomKID)
216			if err != nil {
217				t.Fatal(err)
218			}
219			v, err := createESVerifier(tc.verifierCustomKID)
220			if err != nil {
221				t.Fatal(err)
222			}
223			compact, err := s.SignAndEncodeWithKID(rawJWT, tc.signerKID)
224			if err != nil {
225				t.Fatalf("s.SignAndEncodeWithKID(kid = %v) err = %v, want nil", tc.signerKID, err)
226			}
227			verified, err := v.VerifyAndDecodeWithKID(compact, validator, tc.verifierKID)
228			if err != nil {
229				t.Fatalf("s.VerifyAndDecodeWithKID(kid = %v) err = %v, want nil", tc.verifierKID, err)
230			}
231			typeHeader, err := verified.TypeHeader()
232			if err != nil {
233				t.Errorf("verified.TypeHeader() err = %v, want nil", err)
234			}
235			if typeHeader != "JWT" {
236				t.Errorf("verified.TypeHeader() = %q, want 'JWT'", typeHeader)
237			}
238		})
239	}
240}
241
242func TestSignVerifyWithKIDFailure(t *testing.T) {
243	rawJWT, err := NewRawJWT(&RawJWTOptions{TypeHeader: refString("JWT"), WithoutExpiration: true})
244	if err != nil {
245		t.Fatalf("NewRawJWT() err = %v, want nil", err)
246	}
247	validator, err := NewValidator(&ValidatorOpts{ExpectedTypeHeader: refString("JWT"), AllowMissingExpiration: true})
248	if err != nil {
249		t.Fatalf("NewValidator() err = %v, want nil", err)
250	}
251	for _, tc := range []signerVerifierKIDTestCase{
252		{
253			tag:               "verifier with custom kid different from header generated with custom kid",
254			signerCustomKID:   refString("1234"),
255			verifierCustomKID: refString("123"),
256		},
257		{
258			tag:               "verifier with custom kid different from header generated with tink kid",
259			signerKID:         refString("5678"),
260			verifierCustomKID: refString("1234"),
261		},
262		{
263			tag:               "verifier with both tink and custom kid",
264			verifierCustomKID: refString("1234"),
265			verifierKID:       refString("1234"),
266		},
267		{
268			tag:         "verifier with tink kid and token without kid in header",
269			verifierKID: refString("1234"),
270		},
271	} {
272		t.Run(tc.tag, func(t *testing.T) {
273			s, err := createESSigner(tc.signerCustomKID)
274			if err != nil {
275				t.Fatal(err)
276			}
277			v, err := createESVerifier(tc.verifierCustomKID)
278			if err != nil {
279				t.Fatal(err)
280			}
281			compact, err := s.SignAndEncodeWithKID(rawJWT, tc.signerKID)
282			if err != nil {
283				t.Fatalf("s.SignAndEncodeWithKID(kid = %v) err = %v, want nil", tc.signerKID, err)
284			}
285			if _, err := v.VerifyAndDecodeWithKID(compact, validator, tc.verifierKID); err == nil {
286				t.Fatalf("s.VerifyAndDecodeWithKID(kid = %v) err = nil, want error", tc.verifierKID)
287			}
288		})
289	}
290}
291
292func TestVerifierModifiedCompact(t *testing.T) {
293	rawJWT, err := NewRawJWT(&RawJWTOptions{TypeHeader: refString("JWT"), WithoutExpiration: true})
294	if err != nil {
295		t.Fatalf("NewRawJWT() err = %v, want nil", err)
296	}
297	validator, err := NewValidator(&ValidatorOpts{ExpectedTypeHeader: refString("JWT"), AllowMissingExpiration: true})
298	if err != nil {
299		t.Fatalf("NewValidator() err = %v, want nil", err)
300	}
301	s, err := createESSigner(nil)
302	if err != nil {
303		t.Fatal(err)
304	}
305	v, err := createESVerifier(nil)
306	if err != nil {
307		t.Fatal(err)
308	}
309	compact, err := s.SignAndEncodeWithKID(rawJWT, nil)
310	if err != nil {
311		t.Fatalf("s.SignAndEncodeWithKID() err = %v, want nil", err)
312	}
313	if _, err := v.VerifyAndDecodeWithKID(compact, validator, nil); err != nil {
314		t.Errorf("VerifyAndDecodeWithKID() err = %v, want nil", err)
315	}
316	for _, invalid := range []string{
317		compact + "x",
318		compact + " ",
319		"x" + compact,
320		" " + compact,
321	} {
322		if _, err := v.VerifyAndDecodeWithKID(invalid, validator, nil); err == nil {
323			t.Errorf("VerifyAndDecodeWithKID() err = nil, want error")
324		}
325	}
326}
327
328func TestVerifierInvalidInputs(t *testing.T) {
329	validator, err := NewValidator(&ValidatorOpts{AllowMissingExpiration: true})
330	if err != nil {
331		t.Fatalf("NewValidator() err = %v, want nil", err)
332	}
333	v, err := createESVerifier(nil)
334	if err != nil {
335		t.Fatal(err)
336	}
337	for _, invalid := range []string{
338		"eyJhbGciOiJUzI1NiJ9.e30.YWJj.",
339		"eyJhbGciOiJUzI1NiJ9?.e30.YWJj",
340		"eyJhbGciOiJUzI1NiJ9.e30?.YWJj",
341		"eyJhbGciOiJUzI1NiJ9.e30.YWJj?",
342		"eyJhbGciOiJUzI1NiJ9.YWJj",
343	} {
344		if _, err := v.VerifyAndDecodeWithKID(invalid, validator, nil); err == nil {
345			t.Errorf("v.VerifyAndDecodeWithKID(compact = %q) err = nil, want error", invalid)
346		}
347	}
348}
349
350func TestNewSignerWithNilTinkSignerFails(t *testing.T) {
351	if _, err := newSignerWithKID(nil, "ES256", nil); err == nil {
352		t.Errorf("newSignerWithKID(nil, 'ES256', nil) err = nil, want error")
353	}
354}
355
356func TestNewVerifierWithNilTinkVerifierFails(t *testing.T) {
357	if _, err := newVerifierWithKID(nil, "ES256", nil); err == nil {
358		t.Errorf("newVerifierWithKID(nil, 'ES256', nil) err = nil, want error")
359	}
360}
361