xref: /aosp_15_r20/external/tink/go/jwt/jwt_signer_verifier_factory_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_test
18
19import (
20	"crypto/ecdsa"
21	"crypto/elliptic"
22	"crypto/rand"
23	"fmt"
24	"testing"
25
26	"google.golang.org/protobuf/proto"
27	"github.com/google/tink/go/jwt"
28	"github.com/google/tink/go/keyset"
29	"github.com/google/tink/go/signature"
30	"github.com/google/tink/go/testkeyset"
31	"github.com/google/tink/go/testutil"
32	jepb "github.com/google/tink/go/proto/jwt_ecdsa_go_proto"
33	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
34)
35
36func TestSignerVerifierFactoryWithInvalidPrimitiveSetType(t *testing.T) {
37	kh, err := keyset.NewHandle(signature.ECDSAP256KeyTemplate())
38	if err != nil {
39		t.Fatalf("failed to build *keyset.Handle: %s", err)
40	}
41	if _, err := jwt.NewSigner(kh); err == nil {
42		t.Errorf("jwt.NewSigner() err = nil, want error")
43	}
44	if _, err := jwt.NewVerifier(kh); err == nil {
45		t.Errorf("jwt.NewVerifier() err = nil, want error")
46	}
47}
48
49func TestSignerVerifierFactoryNilKeyset(t *testing.T) {
50	if _, err := jwt.NewSigner(nil); err == nil {
51		t.Errorf("jwt.NewSigner(nil) err = nil, want error")
52	}
53	if _, err := jwt.NewVerifier(nil); err == nil {
54		t.Errorf("jwt.NewVerifier(nil) err = nil, want error")
55	}
56}
57
58func createJWTECDSAKey(kid *string) (*jepb.JwtEcdsaPrivateKey, error) {
59	k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
60	if err != nil {
61		return nil, fmt.Errorf("ecdsa.GenerateKey(curve=P256): %v", err)
62	}
63	var customKID *jepb.JwtEcdsaPublicKey_CustomKid = nil
64	if kid != nil {
65		customKID = &jepb.JwtEcdsaPublicKey_CustomKid{Value: *kid}
66	}
67	return &jepb.JwtEcdsaPrivateKey{
68		Version: 0,
69		PublicKey: &jepb.JwtEcdsaPublicKey{
70			Version:   0,
71			Algorithm: jepb.JwtEcdsaAlgorithm_ES256,
72			X:         k.X.Bytes(),
73			Y:         k.Y.Bytes(),
74			CustomKid: customKID,
75		},
76		KeyValue: k.D.Bytes(),
77	}, nil
78}
79
80func createKeyData(privKey *jepb.JwtEcdsaPrivateKey) (*tinkpb.KeyData, error) {
81	serializedPrivKey, err := proto.Marshal(privKey)
82	if err != nil {
83		return nil, fmt.Errorf("serializing private key proto: %v", err)
84	}
85	return &tinkpb.KeyData{
86		TypeUrl:         "type.googleapis.com/google.crypto.tink.JwtEcdsaPrivateKey",
87		Value:           serializedPrivKey,
88		KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PRIVATE,
89	}, nil
90}
91
92func createKeysetHandles(privKey *tinkpb.KeyData, outputPrefixType tinkpb.OutputPrefixType) (*keyset.Handle, *keyset.Handle, error) {
93	k := testutil.NewKey(privKey, tinkpb.KeyStatusType_ENABLED, 1 /*=keyID*/, outputPrefixType)
94	privKeyHandle, err := testkeyset.NewHandle(testutil.NewKeyset(k.KeyId, []*tinkpb.Keyset_Key{k}))
95	if err != nil {
96		return nil, nil, fmt.Errorf("creating keyset handle for private key: %v", err)
97	}
98	pubKeyHandle, err := privKeyHandle.Public()
99	if err != nil {
100		return nil, nil, fmt.Errorf("creating keyset handle for public key: %v", err)
101	}
102	return privKeyHandle, pubKeyHandle, nil
103}
104
105func createKeyHandlesFromKey(t *testing.T, privKey *jepb.JwtEcdsaPrivateKey, outputPrefixType tinkpb.OutputPrefixType) (*keyset.Handle, *keyset.Handle) {
106	privKeyData, err := createKeyData(privKey)
107	if err != nil {
108		t.Fatal(err)
109	}
110	privKeyHandle, pubKeyHandle, err := createKeysetHandles(privKeyData, outputPrefixType)
111	if err != nil {
112		t.Fatal(err)
113	}
114	return privKeyHandle, pubKeyHandle
115}
116
117func createKeyAndKeyHandles(t *testing.T, kid *string, outputPrefixType tinkpb.OutputPrefixType) (*jepb.JwtEcdsaPrivateKey, *keyset.Handle, *keyset.Handle) {
118	privKey, err := createJWTECDSAKey(kid)
119	if err != nil {
120		t.Fatal(err)
121	}
122	privKeyHandle, pubKeyHandle := createKeyHandlesFromKey(t, privKey, outputPrefixType)
123	return privKey, privKeyHandle, pubKeyHandle
124}
125
126func TestFactoryVerifyWithDifferentKeyFails(t *testing.T) {
127	_, privKeyHandle, pubKeyHandle := createKeyAndKeyHandles(t, nil /*=kid*/, tinkpb.OutputPrefixType_TINK)
128
129	signer, err := jwt.NewSigner(privKeyHandle)
130	if err != nil {
131		t.Fatalf("jwt.NewSigner() err = %v, want nil", err)
132	}
133	verifier, err := jwt.NewVerifier(pubKeyHandle)
134	if err != nil {
135		t.Fatalf("jwt.NewVerifier() err = %v, want nil", err)
136	}
137
138	rawJWT, err := jwt.NewRawJWT(&jwt.RawJWTOptions{WithoutExpiration: true, Audiences: []string{"tink-audience"}})
139	if err != nil {
140		t.Fatalf("jwt.NewRawJWT() err = %v, want nil", err)
141	}
142	validator, err := jwt.NewValidator(&jwt.ValidatorOpts{AllowMissingExpiration: true, ExpectedAudience: refString("tink-audience")})
143	if err != nil {
144		t.Fatalf("jwt.NewValidator() err = %v, want nil", err)
145	}
146	compact, err := signer.SignAndEncode(rawJWT)
147	if err != nil {
148		t.Errorf("signer.SignAndEncode() err = %v, want nil", err)
149	}
150	if _, err := verifier.VerifyAndDecode(compact, validator); err != nil {
151		t.Errorf("verifier.VerifyAndDecode() err = %v, want nil", err)
152	}
153
154	// verification with different key fails
155	_, _, pubKeyHandle = createKeyAndKeyHandles(t, nil /*=kid*/, tinkpb.OutputPrefixType_TINK)
156	verifier, err = jwt.NewVerifier(pubKeyHandle)
157	if err != nil {
158		t.Fatalf("jwt.NewVerifier() err = %v, want nil", err)
159	}
160	if _, err := verifier.VerifyAndDecode(compact, validator); err == nil {
161		t.Errorf("verifier.VerifyAndDecode() err = nil, want error")
162	}
163}
164
165func TestFactorySignWithTinkAndCustomKIDFails(t *testing.T) {
166	_, privKeyHandle, _ := createKeyAndKeyHandles(t, refString("customKID"), tinkpb.OutputPrefixType_TINK)
167	signer, err := jwt.NewSigner(privKeyHandle)
168	if err != nil {
169		t.Fatalf("jwt.NewSigner() err = %v, want nil", err)
170	}
171	rawJWT, err := jwt.NewRawJWT(&jwt.RawJWTOptions{WithoutExpiration: true})
172	if err != nil {
173		t.Fatalf("jwt.NewRawJWT() err = %v, want nil", err)
174	}
175	if _, err := signer.SignAndEncode(rawJWT); err == nil {
176		t.Errorf("signer.SignAndEncode() err = nil, want error")
177	}
178}
179
180type signerVerifierFactoryKIDTestCase struct {
181	tag                  string
182	signerOutputPrefix   tinkpb.OutputPrefixType
183	signerKID            *string
184	verifierOutputPrefix tinkpb.OutputPrefixType
185	verifierKID          *string
186}
187
188func TestFactorySignVerifyWithKIDFailure(t *testing.T) {
189	rawJWT, err := jwt.NewRawJWT(&jwt.RawJWTOptions{WithoutExpiration: true})
190	if err != nil {
191		t.Fatalf("jwt.NewRawJWT() err = %v, want nil", err)
192	}
193	validator, err := jwt.NewValidator(&jwt.ValidatorOpts{AllowMissingExpiration: true})
194	if err != nil {
195		t.Fatalf("jwt.NewValidator() err = %v, want nil", err)
196	}
197	for _, tc := range []signerVerifierFactoryKIDTestCase{
198		{
199			tag:                  "raw output prefix and different custom kid",
200			signerOutputPrefix:   tinkpb.OutputPrefixType_RAW,
201			signerKID:            refString("customKID"),
202			verifierOutputPrefix: tinkpb.OutputPrefixType_RAW,
203			verifierKID:          refString("OtherCustomKID"),
204		},
205		{
206			tag:                  "verifier with tink output prefix and custom kid when token has no kid",
207			signerOutputPrefix:   tinkpb.OutputPrefixType_RAW,
208			signerKID:            nil,
209			verifierOutputPrefix: tinkpb.OutputPrefixType_TINK,
210			verifierKID:          refString("customKID"),
211		},
212		{
213			tag:                  "verifier with tink output prefix and custom kid when token has kid",
214			signerOutputPrefix:   tinkpb.OutputPrefixType_RAW,
215			signerKID:            refString("customKID"),
216			verifierOutputPrefix: tinkpb.OutputPrefixType_TINK,
217			verifierKID:          refString("customKid"),
218		},
219		{
220			tag:                  "token with fixed kid and verifier with tink output prefix",
221			signerOutputPrefix:   tinkpb.OutputPrefixType_RAW,
222			signerKID:            refString("customKID"),
223			verifierOutputPrefix: tinkpb.OutputPrefixType_TINK,
224			verifierKID:          nil,
225		},
226		{
227			tag:                  "token missing kid in header when verifier has tink output prefix",
228			signerOutputPrefix:   tinkpb.OutputPrefixType_RAW,
229			signerKID:            nil,
230			verifierOutputPrefix: tinkpb.OutputPrefixType_TINK,
231			verifierKID:          nil,
232		},
233	} {
234		t.Run(tc.tag, func(t *testing.T) {
235			key, privKeyHandle, _ := createKeyAndKeyHandles(t, tc.signerKID, tc.signerOutputPrefix)
236			signer, err := jwt.NewSigner(privKeyHandle)
237			if err != nil {
238				t.Fatalf("jwt.NewSigner() err = %v, want nil", err)
239			}
240			compact, err := signer.SignAndEncode(rawJWT)
241			if err != nil {
242				t.Errorf("signer.SignAndEncode() err = %v, want nil", err)
243			}
244
245			key.PublicKey.CustomKid = nil
246			if tc.verifierKID != nil {
247				key.PublicKey.CustomKid = &jepb.JwtEcdsaPublicKey_CustomKid{Value: *tc.verifierKID}
248			}
249			_, pubKeyHandle := createKeyHandlesFromKey(t, key, tc.verifierOutputPrefix)
250			verifier, err := jwt.NewVerifier(pubKeyHandle)
251			if err != nil {
252				t.Fatalf("jwt.NewVerifier() err = %v, want nil", err)
253			}
254			if _, err := verifier.VerifyAndDecode(compact, validator); err == nil {
255				t.Errorf("verifier.VerifyAndDecode() err = nil, want error")
256			}
257		})
258	}
259}
260
261func TestVerifyAndDecodeReturnsValidationError(t *testing.T) {
262	_, privateHandle, publicHandle := createKeyAndKeyHandles(t, nil /*=kid*/, tinkpb.OutputPrefixType_TINK)
263	signer, err := jwt.NewSigner(privateHandle)
264	if err != nil {
265		t.Fatalf("jwt.NewSigner() err = %v, want nil", err)
266	}
267	verifier, err := jwt.NewVerifier(publicHandle)
268	if err != nil {
269		t.Fatalf("jwt.NewVerifier() err = %v, want nil", err)
270	}
271
272	audience := "audience"
273	rawJWT, err := jwt.NewRawJWT(&jwt.RawJWTOptions{Audience: &audience, WithoutExpiration: true})
274	if err != nil {
275		t.Fatalf("jwt.NewRawJWT() err = %v, want nil", err)
276	}
277
278	compact, err := signer.SignAndEncode(rawJWT)
279	if err != nil {
280		t.Errorf("signer.SignAndEncode() err = %v, want nil", err)
281	}
282
283	otherAudience := "otherAudience"
284	validator, err := jwt.NewValidator(
285		&jwt.ValidatorOpts{ExpectedAudience: &otherAudience, AllowMissingExpiration: true})
286	if err != nil {
287		t.Fatalf("jwt.NewValidator() err = %v, want nil", err)
288	}
289	_, err = verifier.VerifyAndDecode(compact, validator)
290	wantErr := "validating audience claim: otherAudience not found"
291	if err == nil {
292		t.Errorf("verifier.VerifyAndDecode() err = nil, want %q", wantErr)
293	}
294	if err.Error() != wantErr {
295		t.Errorf("verifier.VerifyAndDecode() err = %q, want %q", err.Error(), wantErr)
296	}
297}
298
299func TestFactorySignVerifyWithKIDSuccess(t *testing.T) {
300	rawJWT, err := jwt.NewRawJWT(&jwt.RawJWTOptions{WithoutExpiration: true})
301	if err != nil {
302		t.Fatalf("jwt.NewRawJWT() err = %v, want nil", err)
303	}
304	validator, err := jwt.NewValidator(&jwt.ValidatorOpts{AllowMissingExpiration: true})
305	if err != nil {
306		t.Fatalf("jwt.NewValidator() err = %v, want nil", err)
307	}
308	for _, tc := range []signerVerifierFactoryKIDTestCase{
309		{
310			tag:                "signer verifier without custom kid and with raw output prefix",
311			signerOutputPrefix: tinkpb.OutputPrefixType_RAW,
312			signerKID:          nil,
313
314			verifierOutputPrefix: tinkpb.OutputPrefixType_RAW,
315			verifierKID:          nil,
316		},
317		{
318			tag:                  "signer with custom kid verifier without custom kid and raw output prefixes",
319			signerOutputPrefix:   tinkpb.OutputPrefixType_RAW,
320			signerKID:            refString("customKID"),
321			verifierOutputPrefix: tinkpb.OutputPrefixType_RAW,
322			verifierKID:          nil,
323		},
324		{
325			tag:                  "signer and verifier same custom kid and raw output prefix",
326			signerOutputPrefix:   tinkpb.OutputPrefixType_RAW,
327			signerKID:            refString("customKID"),
328			verifierOutputPrefix: tinkpb.OutputPrefixType_RAW,
329			verifierKID:          refString("customKID"),
330		},
331		{
332			tag:                  "signer and verifier with tink output prefix and no custom kid",
333			signerOutputPrefix:   tinkpb.OutputPrefixType_TINK,
334			signerKID:            nil,
335			verifierOutputPrefix: tinkpb.OutputPrefixType_TINK,
336			verifierKID:          nil,
337		},
338		{
339			tag:                  "signer with tink output prefix verifier with raw output prefix",
340			signerOutputPrefix:   tinkpb.OutputPrefixType_TINK,
341			signerKID:            nil,
342			verifierOutputPrefix: tinkpb.OutputPrefixType_RAW,
343			verifierKID:          nil,
344		},
345		{
346			tag:                  "token missing kid in header when verifier has custom kid",
347			signerOutputPrefix:   tinkpb.OutputPrefixType_RAW,
348			signerKID:            nil,
349			verifierOutputPrefix: tinkpb.OutputPrefixType_RAW,
350			verifierKID:          refString("customKID"),
351		},
352	} {
353		t.Run(tc.tag, func(t *testing.T) {
354			key, privKeyHandle, _ := createKeyAndKeyHandles(t, tc.signerKID, tc.signerOutputPrefix)
355			signer, err := jwt.NewSigner(privKeyHandle)
356			if err != nil {
357				t.Fatalf("jwt.NewSigner() err = %v, want nil", err)
358			}
359			compact, err := signer.SignAndEncode(rawJWT)
360			if err != nil {
361				t.Errorf("signer.SignAndEncode() err = %v, want nil", err)
362			}
363
364			key.GetPublicKey().CustomKid = nil
365			if tc.verifierKID != nil {
366				key.GetPublicKey().CustomKid = &jepb.JwtEcdsaPublicKey_CustomKid{Value: *tc.verifierKID}
367			}
368			_, pubKeyHandle := createKeyHandlesFromKey(t, key, tc.verifierOutputPrefix)
369			verifier, err := jwt.NewVerifier(pubKeyHandle)
370			if err != nil {
371				t.Fatalf("jwt.NewVerifier() err = %v, want nil", err)
372			}
373			if _, err := verifier.VerifyAndDecode(compact, validator); err != nil {
374				t.Errorf("verifier.VerifyAndDecode() err = %v, want nil", err)
375			}
376		})
377	}
378}
379