xref: /aosp_15_r20/external/tink/testing/go/jwt_service_test.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1*e7b1675dSTing-Kang Chang// Copyright 2022 Google LLC
2*e7b1675dSTing-Kang Chang//
3*e7b1675dSTing-Kang Chang// Licensed under the Apache License, Version 2.0 (the "License");
4*e7b1675dSTing-Kang Chang// you may not use this file except in compliance with the License.
5*e7b1675dSTing-Kang Chang// You may obtain a copy of the License at
6*e7b1675dSTing-Kang Chang//
7*e7b1675dSTing-Kang Chang//     http://www.apache.org/licenses/LICENSE-2.0
8*e7b1675dSTing-Kang Chang//
9*e7b1675dSTing-Kang Chang// Unless required by applicable law or agreed to in writing, software
10*e7b1675dSTing-Kang Chang// distributed under the License is distributed on an "AS IS" BASIS,
11*e7b1675dSTing-Kang Chang// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e7b1675dSTing-Kang Chang// See the License for the specific language governing permissions and
13*e7b1675dSTing-Kang Chang// limitations under the License.
14*e7b1675dSTing-Kang Chang//
15*e7b1675dSTing-Kang Chang///////////////////////////////////////////////////////////////////////////////
16*e7b1675dSTing-Kang Chang
17*e7b1675dSTing-Kang Changpackage services_test
18*e7b1675dSTing-Kang Chang
19*e7b1675dSTing-Kang Changimport (
20*e7b1675dSTing-Kang Chang	"context"
21*e7b1675dSTing-Kang Chang	"errors"
22*e7b1675dSTing-Kang Chang	"fmt"
23*e7b1675dSTing-Kang Chang	"testing"
24*e7b1675dSTing-Kang Chang
25*e7b1675dSTing-Kang Chang	dpb "google.golang.org/protobuf/types/known/durationpb"
26*e7b1675dSTing-Kang Chang	spb "google.golang.org/protobuf/types/known/structpb"
27*e7b1675dSTing-Kang Chang	tpb "google.golang.org/protobuf/types/known/timestamppb"
28*e7b1675dSTing-Kang Chang	wpb "google.golang.org/protobuf/types/known/wrapperspb"
29*e7b1675dSTing-Kang Chang	"github.com/google/go-cmp/cmp"
30*e7b1675dSTing-Kang Chang	"google.golang.org/protobuf/proto"
31*e7b1675dSTing-Kang Chang	"google.golang.org/protobuf/testing/protocmp"
32*e7b1675dSTing-Kang Chang	"github.com/google/tink/go/aead"
33*e7b1675dSTing-Kang Chang	"github.com/google/tink/go/jwt"
34*e7b1675dSTing-Kang Chang	"github.com/google/tink/go/signature"
35*e7b1675dSTing-Kang Chang	"github.com/google/tink/testing/go/services"
36*e7b1675dSTing-Kang Chang	pb "github.com/google/tink/testing/go/protos/testing_api_go_grpc"
37*e7b1675dSTing-Kang Chang)
38*e7b1675dSTing-Kang Chang
39*e7b1675dSTing-Kang Changfunc verifiedJWTFromResponse(response *pb.JwtVerifyResponse) (*pb.JwtToken, error) {
40*e7b1675dSTing-Kang Chang	switch r := response.Result.(type) {
41*e7b1675dSTing-Kang Chang	case *pb.JwtVerifyResponse_VerifiedJwt:
42*e7b1675dSTing-Kang Chang		return r.VerifiedJwt, nil
43*e7b1675dSTing-Kang Chang	case *pb.JwtVerifyResponse_Err:
44*e7b1675dSTing-Kang Chang		return nil, errors.New(r.Err)
45*e7b1675dSTing-Kang Chang	default:
46*e7b1675dSTing-Kang Chang		return nil, fmt.Errorf("response.Result has unexpected type %T", r)
47*e7b1675dSTing-Kang Chang	}
48*e7b1675dSTing-Kang Chang}
49*e7b1675dSTing-Kang Chang
50*e7b1675dSTing-Kang Changfunc signedCompactJWTFromResponse(response *pb.JwtSignResponse) (string, error) {
51*e7b1675dSTing-Kang Chang	switch r := response.Result.(type) {
52*e7b1675dSTing-Kang Chang	case *pb.JwtSignResponse_SignedCompactJwt:
53*e7b1675dSTing-Kang Chang		return r.SignedCompactJwt, nil
54*e7b1675dSTing-Kang Chang	case *pb.JwtSignResponse_Err:
55*e7b1675dSTing-Kang Chang		return "", errors.New(r.Err)
56*e7b1675dSTing-Kang Chang	default:
57*e7b1675dSTing-Kang Chang		return "", fmt.Errorf("response.Result has unexpected type %T", r)
58*e7b1675dSTing-Kang Chang	}
59*e7b1675dSTing-Kang Chang}
60*e7b1675dSTing-Kang Chang
61*e7b1675dSTing-Kang Changfunc jwkSetFromResponse(response *pb.JwtToJwkSetResponse) (string, error) {
62*e7b1675dSTing-Kang Chang	switch r := response.Result.(type) {
63*e7b1675dSTing-Kang Chang	case *pb.JwtToJwkSetResponse_JwkSet:
64*e7b1675dSTing-Kang Chang		return r.JwkSet, nil
65*e7b1675dSTing-Kang Chang	case *pb.JwtToJwkSetResponse_Err:
66*e7b1675dSTing-Kang Chang		return "", errors.New(r.Err)
67*e7b1675dSTing-Kang Chang	default:
68*e7b1675dSTing-Kang Chang		return "", fmt.Errorf("response.Result has unexpected type %T", r)
69*e7b1675dSTing-Kang Chang	}
70*e7b1675dSTing-Kang Chang}
71*e7b1675dSTing-Kang Chang
72*e7b1675dSTing-Kang Changfunc keysetFromResponse(response *pb.JwtFromJwkSetResponse) ([]byte, error) {
73*e7b1675dSTing-Kang Chang	switch r := response.Result.(type) {
74*e7b1675dSTing-Kang Chang	case *pb.JwtFromJwkSetResponse_Keyset:
75*e7b1675dSTing-Kang Chang		return r.Keyset, nil
76*e7b1675dSTing-Kang Chang	case *pb.JwtFromJwkSetResponse_Err:
77*e7b1675dSTing-Kang Chang		return nil, errors.New(r.Err)
78*e7b1675dSTing-Kang Chang	default:
79*e7b1675dSTing-Kang Chang		return nil, fmt.Errorf("response.Result has unexpected type %T", r)
80*e7b1675dSTing-Kang Chang	}
81*e7b1675dSTing-Kang Chang}
82*e7b1675dSTing-Kang Chang
83*e7b1675dSTing-Kang Changtype jwtTestCase struct {
84*e7b1675dSTing-Kang Chang	tag       string
85*e7b1675dSTing-Kang Chang	rawJWT    *pb.JwtToken
86*e7b1675dSTing-Kang Chang	validator *pb.JwtValidator
87*e7b1675dSTing-Kang Chang}
88*e7b1675dSTing-Kang Chang
89*e7b1675dSTing-Kang Changfunc TestJWTComputeInvalidJWT(t *testing.T) {
90*e7b1675dSTing-Kang Chang	for _, tc := range []jwtTestCase{
91*e7b1675dSTing-Kang Chang		{
92*e7b1675dSTing-Kang Chang			tag:    "nil rawJWT",
93*e7b1675dSTing-Kang Chang			rawJWT: nil,
94*e7b1675dSTing-Kang Chang		},
95*e7b1675dSTing-Kang Chang		{
96*e7b1675dSTing-Kang Chang			tag: "invalid json array string",
97*e7b1675dSTing-Kang Chang			rawJWT: &pb.JwtToken{
98*e7b1675dSTing-Kang Chang				CustomClaims: map[string]*pb.JwtClaimValue{
99*e7b1675dSTing-Kang Chang					"cc-array": &pb.JwtClaimValue{Kind: &pb.JwtClaimValue_JsonArrayValue{JsonArrayValue: "{35}"}},
100*e7b1675dSTing-Kang Chang				},
101*e7b1675dSTing-Kang Chang			},
102*e7b1675dSTing-Kang Chang		},
103*e7b1675dSTing-Kang Chang		{
104*e7b1675dSTing-Kang Chang			tag: "invalid json object string",
105*e7b1675dSTing-Kang Chang			rawJWT: &pb.JwtToken{
106*e7b1675dSTing-Kang Chang				CustomClaims: map[string]*pb.JwtClaimValue{
107*e7b1675dSTing-Kang Chang					"cc-object": &pb.JwtClaimValue{Kind: &pb.JwtClaimValue_JsonObjectValue{JsonObjectValue: `["o":"a"]`}},
108*e7b1675dSTing-Kang Chang				},
109*e7b1675dSTing-Kang Chang			},
110*e7b1675dSTing-Kang Chang		},
111*e7b1675dSTing-Kang Chang	} {
112*e7b1675dSTing-Kang Chang		t.Run(tc.tag, func(t *testing.T) {
113*e7b1675dSTing-Kang Chang			keysetService := &services.KeysetService{}
114*e7b1675dSTing-Kang Chang			jwtService := &services.JWTService{}
115*e7b1675dSTing-Kang Chang			ctx := context.Background()
116*e7b1675dSTing-Kang Chang			template, err := proto.Marshal(jwt.HS256Template())
117*e7b1675dSTing-Kang Chang			if err != nil {
118*e7b1675dSTing-Kang Chang				t.Fatalf("proto.Marshal(jwt.HS256Template()) failed: %v", err)
119*e7b1675dSTing-Kang Chang			}
120*e7b1675dSTing-Kang Chang			keyset, err := genKeyset(ctx, keysetService, template)
121*e7b1675dSTing-Kang Chang			if err != nil {
122*e7b1675dSTing-Kang Chang				t.Fatalf("genKeyset failed: %v", err)
123*e7b1675dSTing-Kang Chang			}
124*e7b1675dSTing-Kang Chang			signResponse, err := jwtService.ComputeMacAndEncode(ctx, &pb.JwtSignRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: keyset}, RawJwt: tc.rawJWT})
125*e7b1675dSTing-Kang Chang			if err != nil {
126*e7b1675dSTing-Kang Chang				t.Fatalf("jwtService.ComputeMacAndEncode() err = %v, want nil", err)
127*e7b1675dSTing-Kang Chang			}
128*e7b1675dSTing-Kang Chang			if _, err := signedCompactJWTFromResponse(signResponse); err == nil {
129*e7b1675dSTing-Kang Chang				t.Fatalf("JwtSignResponse: error = nil, want error")
130*e7b1675dSTing-Kang Chang			}
131*e7b1675dSTing-Kang Chang		})
132*e7b1675dSTing-Kang Chang	}
133*e7b1675dSTing-Kang Chang}
134*e7b1675dSTing-Kang Chang
135*e7b1675dSTing-Kang Changfunc TestSuccessfulJwtMacCreation(t *testing.T) {
136*e7b1675dSTing-Kang Chang	keysetService := &services.KeysetService{}
137*e7b1675dSTing-Kang Chang	jwtService := &services.JWTService{}
138*e7b1675dSTing-Kang Chang	ctx := context.Background()
139*e7b1675dSTing-Kang Chang
140*e7b1675dSTing-Kang Chang	template, err := proto.Marshal(jwt.HS256Template())
141*e7b1675dSTing-Kang Chang	if err != nil {
142*e7b1675dSTing-Kang Chang		t.Fatalf("proto.Marshal(jwt.HS256Template()) failed: %v, want nil", err)
143*e7b1675dSTing-Kang Chang	}
144*e7b1675dSTing-Kang Chang
145*e7b1675dSTing-Kang Chang	keyset, err := genKeyset(ctx, keysetService, template)
146*e7b1675dSTing-Kang Chang	if err != nil {
147*e7b1675dSTing-Kang Chang		t.Fatalf("genKeyset failed: %v", err)
148*e7b1675dSTing-Kang Chang	}
149*e7b1675dSTing-Kang Chang
150*e7b1675dSTing-Kang Chang	result, err := jwtService.CreateJwtMac(ctx, &pb.CreationRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: keyset}})
151*e7b1675dSTing-Kang Chang	if err != nil {
152*e7b1675dSTing-Kang Chang		t.Fatalf("CreateJwtMac with good keyset failed with gRPC error: %v, want nil", err)
153*e7b1675dSTing-Kang Chang	}
154*e7b1675dSTing-Kang Chang	if result.GetErr() != "" {
155*e7b1675dSTing-Kang Chang		t.Fatalf("CreateJwtMac with good keyset failed with result.GetErr() = %q, want empty string", result.GetErr())
156*e7b1675dSTing-Kang Chang	}
157*e7b1675dSTing-Kang Chang}
158*e7b1675dSTing-Kang Chang
159*e7b1675dSTing-Kang Changfunc TestFailingJwtMacCreation(t *testing.T) {
160*e7b1675dSTing-Kang Chang	keysetService := &services.KeysetService{}
161*e7b1675dSTing-Kang Chang	jwtService := &services.JWTService{}
162*e7b1675dSTing-Kang Chang	ctx := context.Background()
163*e7b1675dSTing-Kang Chang
164*e7b1675dSTing-Kang Chang	// We use signature keys -- then we cannot create a JwtMac
165*e7b1675dSTing-Kang Chang	template, err := proto.Marshal(aead.AES128GCMKeyTemplate())
166*e7b1675dSTing-Kang Chang	if err != nil {
167*e7b1675dSTing-Kang Chang		t.Fatalf("proto.Marshal(signature.ECDSAP256KeyTemplate()) failed: %v", err)
168*e7b1675dSTing-Kang Chang	}
169*e7b1675dSTing-Kang Chang
170*e7b1675dSTing-Kang Chang	badKeyset, err := genKeyset(ctx, keysetService, template)
171*e7b1675dSTing-Kang Chang	if err != nil {
172*e7b1675dSTing-Kang Chang		t.Fatalf("genKeyset failed: %v", err)
173*e7b1675dSTing-Kang Chang	}
174*e7b1675dSTing-Kang Chang
175*e7b1675dSTing-Kang Chang	result, err := jwtService.CreateJwtMac(ctx, &pb.CreationRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: badKeyset}})
176*e7b1675dSTing-Kang Chang	if err != nil {
177*e7b1675dSTing-Kang Chang		t.Fatalf("CreateJwtMac with bad keyset failed with gRPC error: %v", err)
178*e7b1675dSTing-Kang Chang	}
179*e7b1675dSTing-Kang Chang	if result.GetErr() == "" {
180*e7b1675dSTing-Kang Chang		t.Fatalf("result.GetErr() of bad keyset after CreateJwtMac is empty, want not empty")
181*e7b1675dSTing-Kang Chang	}
182*e7b1675dSTing-Kang Chang}
183*e7b1675dSTing-Kang Chang
184*e7b1675dSTing-Kang Changfunc TestJWTComputeMACWithInvalidKeysetFails(t *testing.T) {
185*e7b1675dSTing-Kang Chang	keysetService := &services.KeysetService{}
186*e7b1675dSTing-Kang Chang	jwtService := &services.JWTService{}
187*e7b1675dSTing-Kang Chang	ctx := context.Background()
188*e7b1675dSTing-Kang Chang	template, err := proto.Marshal(aead.AES256GCMKeyTemplate())
189*e7b1675dSTing-Kang Chang	if err != nil {
190*e7b1675dSTing-Kang Chang		t.Fatalf("proto.Marshal(jwt.AES256GCMKeyTemplate()) failed: %v", err)
191*e7b1675dSTing-Kang Chang	}
192*e7b1675dSTing-Kang Chang	keyset, err := genKeyset(ctx, keysetService, template)
193*e7b1675dSTing-Kang Chang	if err != nil {
194*e7b1675dSTing-Kang Chang		t.Fatalf("genKeyset failed: %v", err)
195*e7b1675dSTing-Kang Chang	}
196*e7b1675dSTing-Kang Chang	rawJWT := &pb.JwtToken{
197*e7b1675dSTing-Kang Chang		TypeHeader: &wpb.StringValue{Value: "JWT"},
198*e7b1675dSTing-Kang Chang		Issuer:     &wpb.StringValue{Value: "issuer"},
199*e7b1675dSTing-Kang Chang	}
200*e7b1675dSTing-Kang Chang	signResponse, err := jwtService.ComputeMacAndEncode(ctx, &pb.JwtSignRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: keyset}, RawJwt: rawJWT})
201*e7b1675dSTing-Kang Chang	if err != nil {
202*e7b1675dSTing-Kang Chang		t.Fatalf("jwtService.ComputeMacAndEncode() err = %v, want nil", err)
203*e7b1675dSTing-Kang Chang	}
204*e7b1675dSTing-Kang Chang	if _, err := signedCompactJWTFromResponse(signResponse); err == nil {
205*e7b1675dSTing-Kang Chang		t.Fatalf("JwtSignResponse: error = nil, want error")
206*e7b1675dSTing-Kang Chang	}
207*e7b1675dSTing-Kang Chang}
208*e7b1675dSTing-Kang Chang
209*e7b1675dSTing-Kang Changfunc TestJWTComputeAndVerifyMac(t *testing.T) {
210*e7b1675dSTing-Kang Chang	for _, tc := range []jwtTestCase{
211*e7b1675dSTing-Kang Chang		{
212*e7b1675dSTing-Kang Chang			tag: "all claims and custom claims",
213*e7b1675dSTing-Kang Chang			rawJWT: &pb.JwtToken{
214*e7b1675dSTing-Kang Chang				TypeHeader: &wpb.StringValue{Value: "JWT"},
215*e7b1675dSTing-Kang Chang				Issuer:     &wpb.StringValue{Value: "issuer"},
216*e7b1675dSTing-Kang Chang				Subject:    &wpb.StringValue{Value: "subject"},
217*e7b1675dSTing-Kang Chang				JwtId:      &wpb.StringValue{Value: "tink"},
218*e7b1675dSTing-Kang Chang				Audiences:  []string{"audience"},
219*e7b1675dSTing-Kang Chang				Expiration: &tpb.Timestamp{Seconds: 123456},
220*e7b1675dSTing-Kang Chang				NotBefore:  &tpb.Timestamp{Seconds: 12345},
221*e7b1675dSTing-Kang Chang				IssuedAt:   &tpb.Timestamp{Seconds: 1234},
222*e7b1675dSTing-Kang Chang				CustomClaims: map[string]*pb.JwtClaimValue{
223*e7b1675dSTing-Kang Chang					"cc-null":   &pb.JwtClaimValue{Kind: &pb.JwtClaimValue_NullValue{}},
224*e7b1675dSTing-Kang Chang					"cc-num":    &pb.JwtClaimValue{Kind: &pb.JwtClaimValue_NumberValue{NumberValue: 5.67}},
225*e7b1675dSTing-Kang Chang					"cc-bool":   &pb.JwtClaimValue{Kind: &pb.JwtClaimValue_BoolValue{BoolValue: true}},
226*e7b1675dSTing-Kang Chang					"cc-string": &pb.JwtClaimValue{Kind: &pb.JwtClaimValue_StringValue{StringValue: "foo bar"}},
227*e7b1675dSTing-Kang Chang					"cc-array":  &pb.JwtClaimValue{Kind: &pb.JwtClaimValue_JsonArrayValue{JsonArrayValue: "[35]"}},
228*e7b1675dSTing-Kang Chang					"cc-object": &pb.JwtClaimValue{Kind: &pb.JwtClaimValue_JsonObjectValue{JsonObjectValue: `{"key":"val"}`}},
229*e7b1675dSTing-Kang Chang				},
230*e7b1675dSTing-Kang Chang			},
231*e7b1675dSTing-Kang Chang			validator: &pb.JwtValidator{
232*e7b1675dSTing-Kang Chang				ExpectedTypeHeader: &wpb.StringValue{Value: "JWT"},
233*e7b1675dSTing-Kang Chang				ExpectedIssuer:     &wpb.StringValue{Value: "issuer"},
234*e7b1675dSTing-Kang Chang				ExpectedAudience:   &wpb.StringValue{Value: "audience"},
235*e7b1675dSTing-Kang Chang				Now:                &tpb.Timestamp{Seconds: 12345},
236*e7b1675dSTing-Kang Chang				ClockSkew:          &dpb.Duration{Seconds: 0},
237*e7b1675dSTing-Kang Chang			},
238*e7b1675dSTing-Kang Chang		},
239*e7b1675dSTing-Kang Chang		{
240*e7b1675dSTing-Kang Chang			tag: "without custom claims",
241*e7b1675dSTing-Kang Chang			rawJWT: &pb.JwtToken{
242*e7b1675dSTing-Kang Chang				TypeHeader: &wpb.StringValue{Value: "JWT"},
243*e7b1675dSTing-Kang Chang				Issuer:     &wpb.StringValue{Value: "issuer"},
244*e7b1675dSTing-Kang Chang				Subject:    &wpb.StringValue{Value: "subject"},
245*e7b1675dSTing-Kang Chang				Audiences:  []string{"audience"},
246*e7b1675dSTing-Kang Chang			},
247*e7b1675dSTing-Kang Chang			validator: &pb.JwtValidator{
248*e7b1675dSTing-Kang Chang				ExpectedTypeHeader:     &wpb.StringValue{Value: "JWT"},
249*e7b1675dSTing-Kang Chang				ExpectedIssuer:         &wpb.StringValue{Value: "issuer"},
250*e7b1675dSTing-Kang Chang				ExpectedAudience:       &wpb.StringValue{Value: "audience"},
251*e7b1675dSTing-Kang Chang				AllowMissingExpiration: true,
252*e7b1675dSTing-Kang Chang			},
253*e7b1675dSTing-Kang Chang		},
254*e7b1675dSTing-Kang Chang		{
255*e7b1675dSTing-Kang Chang			tag: "without expiration",
256*e7b1675dSTing-Kang Chang			rawJWT: &pb.JwtToken{
257*e7b1675dSTing-Kang Chang				Subject: &wpb.StringValue{Value: "subject"},
258*e7b1675dSTing-Kang Chang			},
259*e7b1675dSTing-Kang Chang			validator: &pb.JwtValidator{
260*e7b1675dSTing-Kang Chang				AllowMissingExpiration: true,
261*e7b1675dSTing-Kang Chang			},
262*e7b1675dSTing-Kang Chang		},
263*e7b1675dSTing-Kang Chang		{
264*e7b1675dSTing-Kang Chang			tag: "clock skew",
265*e7b1675dSTing-Kang Chang			rawJWT: &pb.JwtToken{
266*e7b1675dSTing-Kang Chang				Expiration: &tpb.Timestamp{Seconds: 1234},
267*e7b1675dSTing-Kang Chang			},
268*e7b1675dSTing-Kang Chang			validator: &pb.JwtValidator{
269*e7b1675dSTing-Kang Chang				Now:       &tpb.Timestamp{Seconds: 1235},
270*e7b1675dSTing-Kang Chang				ClockSkew: &dpb.Duration{Seconds: 2},
271*e7b1675dSTing-Kang Chang			},
272*e7b1675dSTing-Kang Chang		},
273*e7b1675dSTing-Kang Chang	} {
274*e7b1675dSTing-Kang Chang		t.Run(tc.tag, func(t *testing.T) {
275*e7b1675dSTing-Kang Chang			keysetService := &services.KeysetService{}
276*e7b1675dSTing-Kang Chang			jwtService := &services.JWTService{}
277*e7b1675dSTing-Kang Chang			ctx := context.Background()
278*e7b1675dSTing-Kang Chang			template, err := proto.Marshal(jwt.HS256Template())
279*e7b1675dSTing-Kang Chang			if err != nil {
280*e7b1675dSTing-Kang Chang				t.Fatalf("proto.Marshal(jwt.HS256Template()) failed: %v", err)
281*e7b1675dSTing-Kang Chang			}
282*e7b1675dSTing-Kang Chang			keyset, err := genKeyset(ctx, keysetService, template)
283*e7b1675dSTing-Kang Chang			if err != nil {
284*e7b1675dSTing-Kang Chang				t.Fatalf("genKeyset failed: %v", err)
285*e7b1675dSTing-Kang Chang			}
286*e7b1675dSTing-Kang Chang
287*e7b1675dSTing-Kang Chang			signResponse, err := jwtService.ComputeMacAndEncode(ctx, &pb.JwtSignRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: keyset}, RawJwt: tc.rawJWT})
288*e7b1675dSTing-Kang Chang			if err != nil {
289*e7b1675dSTing-Kang Chang				t.Fatalf("jwtService.ComputeMacAndEncode() err = %v, want nil", err)
290*e7b1675dSTing-Kang Chang			}
291*e7b1675dSTing-Kang Chang			compact, err := signedCompactJWTFromResponse(signResponse)
292*e7b1675dSTing-Kang Chang			if err != nil {
293*e7b1675dSTing-Kang Chang				t.Fatalf("JwtSignResponse_Err: %v", err)
294*e7b1675dSTing-Kang Chang			}
295*e7b1675dSTing-Kang Chang			verifyResponse, err := jwtService.VerifyMacAndDecode(ctx, &pb.JwtVerifyRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: keyset}, SignedCompactJwt: compact, Validator: tc.validator})
296*e7b1675dSTing-Kang Chang			if err != nil {
297*e7b1675dSTing-Kang Chang				t.Fatalf("jwtService.VerifyMacAndDecode() err = %v, want nil", err)
298*e7b1675dSTing-Kang Chang			}
299*e7b1675dSTing-Kang Chang			verifiedJWT, err := verifiedJWTFromResponse(verifyResponse)
300*e7b1675dSTing-Kang Chang			if err != nil {
301*e7b1675dSTing-Kang Chang				t.Fatalf("JwtVerifyResponse_Err: %v", err)
302*e7b1675dSTing-Kang Chang			}
303*e7b1675dSTing-Kang Chang			if !cmp.Equal(verifiedJWT, tc.rawJWT, protocmp.Transform()) {
304*e7b1675dSTing-Kang Chang				t.Errorf("verifiedJWT doesn't match expected value: (+ got, - want) %v", cmp.Diff(verifiedJWT, tc.rawJWT, protocmp.Transform()))
305*e7b1675dSTing-Kang Chang			}
306*e7b1675dSTing-Kang Chang		})
307*e7b1675dSTing-Kang Chang	}
308*e7b1675dSTing-Kang Chang}
309*e7b1675dSTing-Kang Chang
310*e7b1675dSTing-Kang Changfunc TestJWTVerifyMACFailures(t *testing.T) {
311*e7b1675dSTing-Kang Chang	keysetService := &services.KeysetService{}
312*e7b1675dSTing-Kang Chang	jwtService := &services.JWTService{}
313*e7b1675dSTing-Kang Chang	ctx := context.Background()
314*e7b1675dSTing-Kang Chang	template, err := proto.Marshal(jwt.HS256Template())
315*e7b1675dSTing-Kang Chang	if err != nil {
316*e7b1675dSTing-Kang Chang		t.Fatalf("proto.Marshal(jwt.HS256Template()) failed: %v", err)
317*e7b1675dSTing-Kang Chang	}
318*e7b1675dSTing-Kang Chang	keyset, err := genKeyset(ctx, keysetService, template)
319*e7b1675dSTing-Kang Chang	if err != nil {
320*e7b1675dSTing-Kang Chang		t.Fatalf("genKeyset failed: %v", err)
321*e7b1675dSTing-Kang Chang	}
322*e7b1675dSTing-Kang Chang	rawJWT := &pb.JwtToken{
323*e7b1675dSTing-Kang Chang		TypeHeader: &wpb.StringValue{Value: "JWT"},
324*e7b1675dSTing-Kang Chang		Expiration: &tpb.Timestamp{Seconds: 123456},
325*e7b1675dSTing-Kang Chang		NotBefore:  &tpb.Timestamp{Seconds: 12345},
326*e7b1675dSTing-Kang Chang		IssuedAt:   &tpb.Timestamp{Seconds: 1234},
327*e7b1675dSTing-Kang Chang	}
328*e7b1675dSTing-Kang Chang	signResponse, err := jwtService.ComputeMacAndEncode(ctx, &pb.JwtSignRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: keyset}, RawJwt: rawJWT})
329*e7b1675dSTing-Kang Chang	if err != nil {
330*e7b1675dSTing-Kang Chang		t.Fatalf("jwtService.ComputeMacAndEncode() err = %v, want nil", err)
331*e7b1675dSTing-Kang Chang	}
332*e7b1675dSTing-Kang Chang	compact, err := signedCompactJWTFromResponse(signResponse)
333*e7b1675dSTing-Kang Chang	if err != nil {
334*e7b1675dSTing-Kang Chang		t.Fatalf("JwtSignResponse_Err: %v", err)
335*e7b1675dSTing-Kang Chang	}
336*e7b1675dSTing-Kang Chang	validator := &pb.JwtValidator{
337*e7b1675dSTing-Kang Chang		ExpectedTypeHeader: &wpb.StringValue{Value: "JWT"},
338*e7b1675dSTing-Kang Chang		Now:                &tpb.Timestamp{Seconds: 12345},
339*e7b1675dSTing-Kang Chang	}
340*e7b1675dSTing-Kang Chang	verifyResponse, err := jwtService.VerifyMacAndDecode(ctx, &pb.JwtVerifyRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: keyset}, SignedCompactJwt: compact, Validator: validator})
341*e7b1675dSTing-Kang Chang	if err != nil {
342*e7b1675dSTing-Kang Chang		t.Fatalf("jwtService.VerifyMacAndDecode() err = %v, want nil", err)
343*e7b1675dSTing-Kang Chang	}
344*e7b1675dSTing-Kang Chang	if _, err := verifiedJWTFromResponse(verifyResponse); err != nil {
345*e7b1675dSTing-Kang Chang		t.Fatalf("JwtVerifyResponse_Err: %v", err)
346*e7b1675dSTing-Kang Chang	}
347*e7b1675dSTing-Kang Chang	for _, tc := range []jwtTestCase{
348*e7b1675dSTing-Kang Chang		{
349*e7b1675dSTing-Kang Chang			tag: "unexpected type header",
350*e7b1675dSTing-Kang Chang			validator: &pb.JwtValidator{
351*e7b1675dSTing-Kang Chang				ExpectedTypeHeader: &wpb.StringValue{Value: "unexpected"},
352*e7b1675dSTing-Kang Chang				Now:                &tpb.Timestamp{Seconds: 12345},
353*e7b1675dSTing-Kang Chang			},
354*e7b1675dSTing-Kang Chang		},
355*e7b1675dSTing-Kang Chang		{
356*e7b1675dSTing-Kang Chang			tag: "expired token",
357*e7b1675dSTing-Kang Chang			validator: &pb.JwtValidator{
358*e7b1675dSTing-Kang Chang				ExpectedTypeHeader: &wpb.StringValue{Value: "JWT"},
359*e7b1675dSTing-Kang Chang				Now:                &tpb.Timestamp{Seconds: 999999999999},
360*e7b1675dSTing-Kang Chang			},
361*e7b1675dSTing-Kang Chang		},
362*e7b1675dSTing-Kang Chang		{
363*e7b1675dSTing-Kang Chang			tag: "expect issued in the past",
364*e7b1675dSTing-Kang Chang			validator: &pb.JwtValidator{
365*e7b1675dSTing-Kang Chang				ExpectedTypeHeader:    &wpb.StringValue{Value: "JWT"},
366*e7b1675dSTing-Kang Chang				Now:                   &tpb.Timestamp{Seconds: 1233},
367*e7b1675dSTing-Kang Chang				ExpectIssuedInThePast: true,
368*e7b1675dSTing-Kang Chang			},
369*e7b1675dSTing-Kang Chang		},
370*e7b1675dSTing-Kang Chang	} {
371*e7b1675dSTing-Kang Chang		t.Run(tc.tag, func(t *testing.T) {
372*e7b1675dSTing-Kang Chang			verifyResponse, err := jwtService.VerifyMacAndDecode(ctx, &pb.JwtVerifyRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: keyset}, SignedCompactJwt: compact, Validator: tc.validator})
373*e7b1675dSTing-Kang Chang			if err != nil {
374*e7b1675dSTing-Kang Chang				t.Fatalf("jwtService.VerifyMacAndDecode() err = %v, want nil", err)
375*e7b1675dSTing-Kang Chang			}
376*e7b1675dSTing-Kang Chang			if _, err := verifiedJWTFromResponse(verifyResponse); err == nil {
377*e7b1675dSTing-Kang Chang				t.Fatalf("JwtVerifyResponse_Err: nil, want error")
378*e7b1675dSTing-Kang Chang			}
379*e7b1675dSTing-Kang Chang		})
380*e7b1675dSTing-Kang Chang	}
381*e7b1675dSTing-Kang Chang}
382*e7b1675dSTing-Kang Chang
383*e7b1675dSTing-Kang Changfunc TestSuccessfulJwtSignVerifyCreation(t *testing.T) {
384*e7b1675dSTing-Kang Chang	keysetService := &services.KeysetService{}
385*e7b1675dSTing-Kang Chang	jwtService := &services.JWTService{}
386*e7b1675dSTing-Kang Chang	ctx := context.Background()
387*e7b1675dSTing-Kang Chang
388*e7b1675dSTing-Kang Chang	template, err := proto.Marshal(jwt.ES256Template())
389*e7b1675dSTing-Kang Chang	if err != nil {
390*e7b1675dSTing-Kang Chang		t.Fatalf("proto.Marshal(hybrid.ES256Template()) failed: %v", err)
391*e7b1675dSTing-Kang Chang	}
392*e7b1675dSTing-Kang Chang
393*e7b1675dSTing-Kang Chang	privateKeyset, err := genKeyset(ctx, keysetService, template)
394*e7b1675dSTing-Kang Chang	if err != nil {
395*e7b1675dSTing-Kang Chang		t.Fatalf("genKeyset failed: %v", err)
396*e7b1675dSTing-Kang Chang	}
397*e7b1675dSTing-Kang Chang
398*e7b1675dSTing-Kang Chang	result, err := jwtService.CreateJwtPublicKeySign(ctx, &pb.CreationRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: privateKeyset}})
399*e7b1675dSTing-Kang Chang	if err != nil {
400*e7b1675dSTing-Kang Chang		t.Fatalf("CreateJwtPublicKeySign with good keyset failed with gRPC error: %v, want nil", err)
401*e7b1675dSTing-Kang Chang	}
402*e7b1675dSTing-Kang Chang	if result.GetErr() != "" {
403*e7b1675dSTing-Kang Chang		t.Fatalf("CreateJwtPublicKeySign with good keyset failed with result.GetErr() = %q, want empty string", result.GetErr())
404*e7b1675dSTing-Kang Chang	}
405*e7b1675dSTing-Kang Chang}
406*e7b1675dSTing-Kang Chang
407*e7b1675dSTing-Kang Changfunc TestSuccessfulJwtVerifyCreation(t *testing.T) {
408*e7b1675dSTing-Kang Chang	keysetService := &services.KeysetService{}
409*e7b1675dSTing-Kang Chang	jwtService := &services.JWTService{}
410*e7b1675dSTing-Kang Chang	ctx := context.Background()
411*e7b1675dSTing-Kang Chang
412*e7b1675dSTing-Kang Chang	template, err := proto.Marshal(jwt.ES256Template())
413*e7b1675dSTing-Kang Chang	if err != nil {
414*e7b1675dSTing-Kang Chang		t.Fatalf("proto.Marshal(hybrid.ES256Template()) failed: %v", err)
415*e7b1675dSTing-Kang Chang	}
416*e7b1675dSTing-Kang Chang
417*e7b1675dSTing-Kang Chang	privateKeyset, err := genKeyset(ctx, keysetService, template)
418*e7b1675dSTing-Kang Chang	if err != nil {
419*e7b1675dSTing-Kang Chang		t.Fatalf("genKeyset failed: %v", err)
420*e7b1675dSTing-Kang Chang	}
421*e7b1675dSTing-Kang Chang	publicKeyset, err := pubKeyset(ctx, keysetService, privateKeyset)
422*e7b1675dSTing-Kang Chang	if err != nil {
423*e7b1675dSTing-Kang Chang		t.Fatalf("pubKeyset failed: %v", err)
424*e7b1675dSTing-Kang Chang	}
425*e7b1675dSTing-Kang Chang
426*e7b1675dSTing-Kang Chang	result, err := jwtService.CreateJwtPublicKeyVerify(ctx, &pb.CreationRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: publicKeyset}})
427*e7b1675dSTing-Kang Chang	if err != nil {
428*e7b1675dSTing-Kang Chang		t.Fatalf("CreateJwtPublicKeyVerify with good keyset failed with gRPC error: %v", err)
429*e7b1675dSTing-Kang Chang	}
430*e7b1675dSTing-Kang Chang	if result.GetErr() != "" {
431*e7b1675dSTing-Kang Chang		t.Fatalf("CreateJwtPublicKeyVerify with good keyset failed with result.GetErr() = %q, want empty string", result.GetErr())
432*e7b1675dSTing-Kang Chang	}
433*e7b1675dSTing-Kang Chang}
434*e7b1675dSTing-Kang Chang
435*e7b1675dSTing-Kang Changfunc TestFailingJwtSignCreation(t *testing.T) {
436*e7b1675dSTing-Kang Chang	keysetService := &services.KeysetService{}
437*e7b1675dSTing-Kang Chang	jwtService := &services.JWTService{}
438*e7b1675dSTing-Kang Chang	ctx := context.Background()
439*e7b1675dSTing-Kang Chang
440*e7b1675dSTing-Kang Chang	// We use signature keys -- then we cannot create a hybrid encrypt
441*e7b1675dSTing-Kang Chang	template, err := proto.Marshal(signature.ECDSAP256KeyTemplate())
442*e7b1675dSTing-Kang Chang	if err != nil {
443*e7b1675dSTing-Kang Chang		t.Fatalf("proto.Marshal(signature.ECDSAP256KeyTemplate()) failed: %v", err)
444*e7b1675dSTing-Kang Chang	}
445*e7b1675dSTing-Kang Chang
446*e7b1675dSTing-Kang Chang	privateKeyset, err := genKeyset(ctx, keysetService, template)
447*e7b1675dSTing-Kang Chang	if err != nil {
448*e7b1675dSTing-Kang Chang		t.Fatalf("genKeyset failed: %v", err)
449*e7b1675dSTing-Kang Chang	}
450*e7b1675dSTing-Kang Chang
451*e7b1675dSTing-Kang Chang	result, err := jwtService.CreateJwtPublicKeySign(ctx, &pb.CreationRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: privateKeyset}})
452*e7b1675dSTing-Kang Chang	if err != nil {
453*e7b1675dSTing-Kang Chang		t.Fatalf("CreateJwtPublicKeySign with bad keyset failed with gRPC error: %v", err)
454*e7b1675dSTing-Kang Chang	}
455*e7b1675dSTing-Kang Chang	if result.GetErr() == "" {
456*e7b1675dSTing-Kang Chang		t.Fatalf("CreateJwtPublicKeySign with bad keyset succeeded")
457*e7b1675dSTing-Kang Chang	}
458*e7b1675dSTing-Kang Chang}
459*e7b1675dSTing-Kang Chang
460*e7b1675dSTing-Kang Changfunc TestFailingJwtVerifyCreation(t *testing.T) {
461*e7b1675dSTing-Kang Chang	keysetService := &services.KeysetService{}
462*e7b1675dSTing-Kang Chang	jwtService := &services.JWTService{}
463*e7b1675dSTing-Kang Chang	ctx := context.Background()
464*e7b1675dSTing-Kang Chang
465*e7b1675dSTing-Kang Chang	// We use signature keys -- then we cannot create a hybrid encrypt
466*e7b1675dSTing-Kang Chang	template, err := proto.Marshal(signature.ECDSAP256KeyTemplate())
467*e7b1675dSTing-Kang Chang	if err != nil {
468*e7b1675dSTing-Kang Chang		t.Fatalf("proto.Marshal(signature.ECDSAP256KeyTemplate()) failed: %v", err)
469*e7b1675dSTing-Kang Chang	}
470*e7b1675dSTing-Kang Chang
471*e7b1675dSTing-Kang Chang	privateKeyset, err := genKeyset(ctx, keysetService, template)
472*e7b1675dSTing-Kang Chang	if err != nil {
473*e7b1675dSTing-Kang Chang		t.Fatalf("genKeyset failed: %v", err)
474*e7b1675dSTing-Kang Chang	}
475*e7b1675dSTing-Kang Chang	publicKeyset, err := pubKeyset(ctx, keysetService, privateKeyset)
476*e7b1675dSTing-Kang Chang	if err != nil {
477*e7b1675dSTing-Kang Chang		t.Fatalf("pubKeyset failed: %v", err)
478*e7b1675dSTing-Kang Chang	}
479*e7b1675dSTing-Kang Chang
480*e7b1675dSTing-Kang Chang	result, err := jwtService.CreateJwtPublicKeyVerify(ctx, &pb.CreationRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: publicKeyset}})
481*e7b1675dSTing-Kang Chang	if err != nil {
482*e7b1675dSTing-Kang Chang		t.Fatalf("CreateJwtPublicKeyVerify with good keyset failed with gRPC error: %v", err)
483*e7b1675dSTing-Kang Chang	}
484*e7b1675dSTing-Kang Chang	if result.GetErr() == "" {
485*e7b1675dSTing-Kang Chang		t.Fatalf("CreateJwtPublicKeyVerify with bad keyset succeeded")
486*e7b1675dSTing-Kang Chang	}
487*e7b1675dSTing-Kang Chang}
488*e7b1675dSTing-Kang Chang
489*e7b1675dSTing-Kang Changfunc TestJWTPublicKeySignWithInvalidKeysetFails(t *testing.T) {
490*e7b1675dSTing-Kang Chang	keysetService := &services.KeysetService{}
491*e7b1675dSTing-Kang Chang	jwtService := &services.JWTService{}
492*e7b1675dSTing-Kang Chang
493*e7b1675dSTing-Kang Chang	ctx := context.Background()
494*e7b1675dSTing-Kang Chang	template, err := proto.Marshal(aead.AES256GCMKeyTemplate())
495*e7b1675dSTing-Kang Chang	if err != nil {
496*e7b1675dSTing-Kang Chang		t.Fatalf("proto.Marshal(aead.AES256GCMKeyTemplate()) failed: %v", err)
497*e7b1675dSTing-Kang Chang	}
498*e7b1675dSTing-Kang Chang	privateKeyset, err := genKeyset(ctx, keysetService, template)
499*e7b1675dSTing-Kang Chang	if err != nil {
500*e7b1675dSTing-Kang Chang		t.Fatalf("genKeyset failed: %v", err)
501*e7b1675dSTing-Kang Chang	}
502*e7b1675dSTing-Kang Chang	rawJWT := &pb.JwtToken{
503*e7b1675dSTing-Kang Chang		Subject: &wpb.StringValue{Value: "tink-subject"},
504*e7b1675dSTing-Kang Chang	}
505*e7b1675dSTing-Kang Chang	signResponse, err := jwtService.PublicKeySignAndEncode(ctx, &pb.JwtSignRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: privateKeyset}, RawJwt: rawJWT})
506*e7b1675dSTing-Kang Chang	if err != nil {
507*e7b1675dSTing-Kang Chang		t.Fatalf("jwtService.PublicKeySignAndEncode() err = %v", err)
508*e7b1675dSTing-Kang Chang	}
509*e7b1675dSTing-Kang Chang	if _, err := signedCompactJWTFromResponse(signResponse); err == nil {
510*e7b1675dSTing-Kang Chang		t.Fatalf("JwtSignResponse_Err: nil want error")
511*e7b1675dSTing-Kang Chang	}
512*e7b1675dSTing-Kang Chang}
513*e7b1675dSTing-Kang Chang
514*e7b1675dSTing-Kang Changfunc TestJWTPublicKeySignInvalidTokenFails(t *testing.T) {
515*e7b1675dSTing-Kang Chang	keysetService := &services.KeysetService{}
516*e7b1675dSTing-Kang Chang	jwtService := &services.JWTService{}
517*e7b1675dSTing-Kang Chang
518*e7b1675dSTing-Kang Chang	ctx := context.Background()
519*e7b1675dSTing-Kang Chang	template, err := proto.Marshal(jwt.ES256Template())
520*e7b1675dSTing-Kang Chang	if err != nil {
521*e7b1675dSTing-Kang Chang		t.Fatalf("proto.Marshal(jwt.ES256Template()) failed: %v", err)
522*e7b1675dSTing-Kang Chang	}
523*e7b1675dSTing-Kang Chang	privateKeyset, err := genKeyset(ctx, keysetService, template)
524*e7b1675dSTing-Kang Chang	if err != nil {
525*e7b1675dSTing-Kang Chang		t.Fatalf("genKeyset failed: %v", err)
526*e7b1675dSTing-Kang Chang	}
527*e7b1675dSTing-Kang Chang	for _, tc := range []jwtTestCase{
528*e7b1675dSTing-Kang Chang		{
529*e7b1675dSTing-Kang Chang			tag:    "nil rawJWT",
530*e7b1675dSTing-Kang Chang			rawJWT: nil,
531*e7b1675dSTing-Kang Chang		},
532*e7b1675dSTing-Kang Chang		{
533*e7b1675dSTing-Kang Chang			tag: "invalid json array string",
534*e7b1675dSTing-Kang Chang			rawJWT: &pb.JwtToken{
535*e7b1675dSTing-Kang Chang				CustomClaims: map[string]*pb.JwtClaimValue{
536*e7b1675dSTing-Kang Chang					"cc-array": &pb.JwtClaimValue{Kind: &pb.JwtClaimValue_JsonArrayValue{JsonArrayValue: "{35}"}},
537*e7b1675dSTing-Kang Chang				},
538*e7b1675dSTing-Kang Chang			},
539*e7b1675dSTing-Kang Chang		},
540*e7b1675dSTing-Kang Chang		{
541*e7b1675dSTing-Kang Chang			tag: "invalid json object string",
542*e7b1675dSTing-Kang Chang			rawJWT: &pb.JwtToken{
543*e7b1675dSTing-Kang Chang				CustomClaims: map[string]*pb.JwtClaimValue{
544*e7b1675dSTing-Kang Chang					"cc-object": &pb.JwtClaimValue{Kind: &pb.JwtClaimValue_JsonObjectValue{JsonObjectValue: `["o":"a"]`}},
545*e7b1675dSTing-Kang Chang				},
546*e7b1675dSTing-Kang Chang			},
547*e7b1675dSTing-Kang Chang		},
548*e7b1675dSTing-Kang Chang	} {
549*e7b1675dSTing-Kang Chang		t.Run(tc.tag, func(t *testing.T) {
550*e7b1675dSTing-Kang Chang			signResponse, err := jwtService.PublicKeySignAndEncode(ctx, &pb.JwtSignRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: privateKeyset}, RawJwt: tc.rawJWT})
551*e7b1675dSTing-Kang Chang			if err != nil {
552*e7b1675dSTing-Kang Chang				t.Fatalf("jwtService.PublicKeySignAndEncode() err = %v", err)
553*e7b1675dSTing-Kang Chang			}
554*e7b1675dSTing-Kang Chang			if _, err := signedCompactJWTFromResponse(signResponse); err == nil {
555*e7b1675dSTing-Kang Chang				t.Fatalf("JwtSignResponse_Err: nil want error")
556*e7b1675dSTing-Kang Chang			}
557*e7b1675dSTing-Kang Chang		})
558*e7b1675dSTing-Kang Chang	}
559*e7b1675dSTing-Kang Chang}
560*e7b1675dSTing-Kang Chang
561*e7b1675dSTing-Kang Changfunc TestJWTPublicKeyVerifyFails(t *testing.T) {
562*e7b1675dSTing-Kang Chang	keysetService := &services.KeysetService{}
563*e7b1675dSTing-Kang Chang	jwtService := &services.JWTService{}
564*e7b1675dSTing-Kang Chang
565*e7b1675dSTing-Kang Chang	ctx := context.Background()
566*e7b1675dSTing-Kang Chang	template, err := proto.Marshal(jwt.ES256Template())
567*e7b1675dSTing-Kang Chang	if err != nil {
568*e7b1675dSTing-Kang Chang		t.Fatalf("proto.Marshal(jwt.ES256Template()) failed: %v", err)
569*e7b1675dSTing-Kang Chang	}
570*e7b1675dSTing-Kang Chang	privateKeyset, err := genKeyset(ctx, keysetService, template)
571*e7b1675dSTing-Kang Chang	if err != nil {
572*e7b1675dSTing-Kang Chang		t.Fatalf("genKeyset failed: %v", err)
573*e7b1675dSTing-Kang Chang	}
574*e7b1675dSTing-Kang Chang	publicKeyset, err := pubKeyset(ctx, keysetService, privateKeyset)
575*e7b1675dSTing-Kang Chang	if err != nil {
576*e7b1675dSTing-Kang Chang		t.Fatalf("pubKeyset failed: %v", err)
577*e7b1675dSTing-Kang Chang	}
578*e7b1675dSTing-Kang Chang	rawJWT := &pb.JwtToken{
579*e7b1675dSTing-Kang Chang		Subject: &wpb.StringValue{Value: "tink-subject"},
580*e7b1675dSTing-Kang Chang	}
581*e7b1675dSTing-Kang Chang	signResponse, err := jwtService.PublicKeySignAndEncode(ctx, &pb.JwtSignRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: privateKeyset}, RawJwt: rawJWT})
582*e7b1675dSTing-Kang Chang	if err != nil {
583*e7b1675dSTing-Kang Chang		t.Fatalf("jwtService.PublicKeySignAndEncode() err = %v", err)
584*e7b1675dSTing-Kang Chang	}
585*e7b1675dSTing-Kang Chang	compact, err := signedCompactJWTFromResponse(signResponse)
586*e7b1675dSTing-Kang Chang	if err != nil {
587*e7b1675dSTing-Kang Chang		t.Fatalf("JwtSignResponse_Err failed: %v", err)
588*e7b1675dSTing-Kang Chang	}
589*e7b1675dSTing-Kang Chang	validator := &pb.JwtValidator{
590*e7b1675dSTing-Kang Chang		ExpectedTypeHeader: &wpb.StringValue{Value: "JWT"},
591*e7b1675dSTing-Kang Chang	}
592*e7b1675dSTing-Kang Chang	verifyResponse, err := jwtService.PublicKeyVerifyAndDecode(ctx, &pb.JwtVerifyRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: publicKeyset}, SignedCompactJwt: compact, Validator: validator})
593*e7b1675dSTing-Kang Chang	if err != nil {
594*e7b1675dSTing-Kang Chang		t.Fatalf("jwtVerifySignature failed: %v", err)
595*e7b1675dSTing-Kang Chang	}
596*e7b1675dSTing-Kang Chang	if _, err := verifiedJWTFromResponse(verifyResponse); err == nil {
597*e7b1675dSTing-Kang Chang		t.Fatalf("JwtVerifyResponse_Err: nil want error")
598*e7b1675dSTing-Kang Chang	}
599*e7b1675dSTing-Kang Chang}
600*e7b1675dSTing-Kang Chang
601*e7b1675dSTing-Kang Changfunc TestJWTPublicKeySignAndEncodeVerifyAndDecode(t *testing.T) {
602*e7b1675dSTing-Kang Chang	keysetService := &services.KeysetService{}
603*e7b1675dSTing-Kang Chang	jwtService := &services.JWTService{}
604*e7b1675dSTing-Kang Chang
605*e7b1675dSTing-Kang Chang	ctx := context.Background()
606*e7b1675dSTing-Kang Chang	template, err := proto.Marshal(jwt.ES256Template())
607*e7b1675dSTing-Kang Chang	if err != nil {
608*e7b1675dSTing-Kang Chang		t.Fatalf("proto.Marshal(jwt.ES256Template()) failed: %v", err)
609*e7b1675dSTing-Kang Chang	}
610*e7b1675dSTing-Kang Chang	privateKeyset, err := genKeyset(ctx, keysetService, template)
611*e7b1675dSTing-Kang Chang	if err != nil {
612*e7b1675dSTing-Kang Chang		t.Fatalf("genKeyset failed: %v", err)
613*e7b1675dSTing-Kang Chang	}
614*e7b1675dSTing-Kang Chang	publicKeyset, err := pubKeyset(ctx, keysetService, privateKeyset)
615*e7b1675dSTing-Kang Chang	if err != nil {
616*e7b1675dSTing-Kang Chang		t.Fatalf("pubKeyset failed: %v", err)
617*e7b1675dSTing-Kang Chang	}
618*e7b1675dSTing-Kang Chang	rawJWT := &pb.JwtToken{
619*e7b1675dSTing-Kang Chang		Subject: &wpb.StringValue{Value: "tink-subject"},
620*e7b1675dSTing-Kang Chang	}
621*e7b1675dSTing-Kang Chang	signResponse, err := jwtService.PublicKeySignAndEncode(ctx, &pb.JwtSignRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: privateKeyset}, RawJwt: rawJWT})
622*e7b1675dSTing-Kang Chang	if err != nil {
623*e7b1675dSTing-Kang Chang		t.Fatalf("jwtService.PublicKeySignAndEncode() err = %v", err)
624*e7b1675dSTing-Kang Chang	}
625*e7b1675dSTing-Kang Chang	compact, err := signedCompactJWTFromResponse(signResponse)
626*e7b1675dSTing-Kang Chang	if err != nil {
627*e7b1675dSTing-Kang Chang		t.Fatalf("JwtSignResponse_Err failed: %v", err)
628*e7b1675dSTing-Kang Chang	}
629*e7b1675dSTing-Kang Chang	validator := &pb.JwtValidator{
630*e7b1675dSTing-Kang Chang		AllowMissingExpiration: true,
631*e7b1675dSTing-Kang Chang	}
632*e7b1675dSTing-Kang Chang	verifyResponse, err := jwtService.PublicKeyVerifyAndDecode(ctx, &pb.JwtVerifyRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: publicKeyset}, SignedCompactJwt: compact, Validator: validator})
633*e7b1675dSTing-Kang Chang	if err != nil {
634*e7b1675dSTing-Kang Chang		t.Fatalf("jwtVerifySignature failed: %v", err)
635*e7b1675dSTing-Kang Chang	}
636*e7b1675dSTing-Kang Chang	verifiedJWT, err := verifiedJWTFromResponse(verifyResponse)
637*e7b1675dSTing-Kang Chang	if err != nil {
638*e7b1675dSTing-Kang Chang		t.Fatalf("JwtVerifyResponse_Err: %v", err)
639*e7b1675dSTing-Kang Chang	}
640*e7b1675dSTing-Kang Chang	if !cmp.Equal(verifiedJWT, rawJWT, protocmp.Transform()) {
641*e7b1675dSTing-Kang Chang		t.Errorf("verifiedJWT doesn't match expected value: (+ got, - want) %v", cmp.Diff(verifiedJWT, rawJWT, protocmp.Transform()))
642*e7b1675dSTing-Kang Chang	}
643*e7b1675dSTing-Kang Chang}
644*e7b1675dSTing-Kang Chang
645*e7b1675dSTing-Kang Changfunc TestToJwkSetWithPrivateKeyFails(t *testing.T) {
646*e7b1675dSTing-Kang Chang	keysetService := &services.KeysetService{}
647*e7b1675dSTing-Kang Chang	jwtService := &services.JWTService{}
648*e7b1675dSTing-Kang Chang
649*e7b1675dSTing-Kang Chang	ctx := context.Background()
650*e7b1675dSTing-Kang Chang	template, err := proto.Marshal(jwt.ES256Template())
651*e7b1675dSTing-Kang Chang	if err != nil {
652*e7b1675dSTing-Kang Chang		t.Fatalf("proto.Marshal(jwt.ES256Template()) failed: %v", err)
653*e7b1675dSTing-Kang Chang	}
654*e7b1675dSTing-Kang Chang	privateKeyset, err := genKeyset(ctx, keysetService, template)
655*e7b1675dSTing-Kang Chang	if err != nil {
656*e7b1675dSTing-Kang Chang		t.Fatalf("genKeyset failed: %v", err)
657*e7b1675dSTing-Kang Chang	}
658*e7b1675dSTing-Kang Chang	toJWKResponse, err := jwtService.ToJwkSet(ctx, &pb.JwtToJwkSetRequest{Keyset: privateKeyset})
659*e7b1675dSTing-Kang Chang	if err != nil {
660*e7b1675dSTing-Kang Chang		t.Fatalf("jwtService.ToJwkSet() err = %v, want nil", err)
661*e7b1675dSTing-Kang Chang	}
662*e7b1675dSTing-Kang Chang	if _, err := jwkSetFromResponse(toJWKResponse); err == nil {
663*e7b1675dSTing-Kang Chang		t.Fatalf("JwtToJwkSetResponse_Err: = nil, want error")
664*e7b1675dSTing-Kang Chang	}
665*e7b1675dSTing-Kang Chang}
666*e7b1675dSTing-Kang Chang
667*e7b1675dSTing-Kang Changfunc TestFromJwkSetPrivateKeyFails(t *testing.T) {
668*e7b1675dSTing-Kang Chang	jwtService := &services.JWTService{}
669*e7b1675dSTing-Kang Chang	ctx := context.Background()
670*e7b1675dSTing-Kang Chang	jwkES256PublicKey := `{
671*e7b1675dSTing-Kang Chang	  "keys":[{
672*e7b1675dSTing-Kang Chang	  "kty":"EC",
673*e7b1675dSTing-Kang Chang	  "crv":"P-256",
674*e7b1675dSTing-Kang Chang	  "x":"wO6uIxh8SkKOO8VjZXNRTteRcwCPE4_4JElKyaa0fcQ",
675*e7b1675dSTing-Kang Chang	  "y":"7oRiYhnmkP6nqrdXWgtsWUWq5uFRLJkhyVFiWPRB278",
676*e7b1675dSTing-Kang Chang		"d":"8oRinhnmkYjkqrdXWgtsWUWq5uFRLJkhyVFiWPRB278",
677*e7b1675dSTing-Kang Chang	  "use":"sig","alg":"ES256","key_ops":["verify"],
678*e7b1675dSTing-Kang Chang	  "kid":"EhuduQ"}]
679*e7b1675dSTing-Kang Chang	}`
680*e7b1675dSTing-Kang Chang	fromJWKResponse, err := jwtService.FromJwkSet(ctx, &pb.JwtFromJwkSetRequest{JwkSet: jwkES256PublicKey})
681*e7b1675dSTing-Kang Chang	if err != nil {
682*e7b1675dSTing-Kang Chang		t.Fatalf("jwtService.FromJwkSet() err = %v, want nil", err)
683*e7b1675dSTing-Kang Chang	}
684*e7b1675dSTing-Kang Chang	if _, err := keysetFromResponse(fromJWKResponse); err == nil {
685*e7b1675dSTing-Kang Chang		t.Fatalf("JwtFromJwkSetResponse_Err = nil, want error")
686*e7b1675dSTing-Kang Chang	}
687*e7b1675dSTing-Kang Chang}
688*e7b1675dSTing-Kang Chang
689*e7b1675dSTing-Kang Changfunc TestFromJwkToJwkSet(t *testing.T) {
690*e7b1675dSTing-Kang Chang	jwtService := &services.JWTService{}
691*e7b1675dSTing-Kang Chang	ctx := context.Background()
692*e7b1675dSTing-Kang Chang	jwkES256PublicKey := `{
693*e7b1675dSTing-Kang Chang	  "keys":[{
694*e7b1675dSTing-Kang Chang	  "kty":"EC",
695*e7b1675dSTing-Kang Chang	  "crv":"P-256",
696*e7b1675dSTing-Kang Chang	  "x":"wO6uIxh8SkKOO8VjZXNRTteRcwCPE4_4JElKyaa0fcQ",
697*e7b1675dSTing-Kang Chang	  "y":"7oRiYhnmkP6nqrdXWgtsWUWq5uFRLJkhyVFiWPRB278",
698*e7b1675dSTing-Kang Chang	  "use":"sig","alg":"ES256","key_ops":["verify"],
699*e7b1675dSTing-Kang Chang	  "kid":"EhuduQ"}]
700*e7b1675dSTing-Kang Chang	}`
701*e7b1675dSTing-Kang Chang	fromJWKResponse, err := jwtService.FromJwkSet(ctx, &pb.JwtFromJwkSetRequest{JwkSet: jwkES256PublicKey})
702*e7b1675dSTing-Kang Chang	if err != nil {
703*e7b1675dSTing-Kang Chang		t.Fatalf("jwtService.FromJwkSet() err = %v, want nil", err)
704*e7b1675dSTing-Kang Chang	}
705*e7b1675dSTing-Kang Chang	ks, err := keysetFromResponse(fromJWKResponse)
706*e7b1675dSTing-Kang Chang	if err != nil {
707*e7b1675dSTing-Kang Chang		t.Fatalf("JwtFromJwkSetResponse_Err: = %v, want nil", err)
708*e7b1675dSTing-Kang Chang	}
709*e7b1675dSTing-Kang Chang	toJWKResponse, err := jwtService.ToJwkSet(ctx, &pb.JwtToJwkSetRequest{Keyset: ks})
710*e7b1675dSTing-Kang Chang	if err != nil {
711*e7b1675dSTing-Kang Chang		t.Fatalf("jwtService.ToJwkSet() err = %v, want nil", err)
712*e7b1675dSTing-Kang Chang	}
713*e7b1675dSTing-Kang Chang	jwkSet, err := jwkSetFromResponse(toJWKResponse)
714*e7b1675dSTing-Kang Chang	if err != nil {
715*e7b1675dSTing-Kang Chang		t.Fatalf("JwtToJwkSetResponse_Err: = %v, want nil", err)
716*e7b1675dSTing-Kang Chang	}
717*e7b1675dSTing-Kang Chang	got := &spb.Struct{}
718*e7b1675dSTing-Kang Chang	if err := got.UnmarshalJSON([]byte(jwkSet)); err != nil {
719*e7b1675dSTing-Kang Chang		t.Fatalf("got.UnmarshalJSON() err = %v, want nil", err)
720*e7b1675dSTing-Kang Chang	}
721*e7b1675dSTing-Kang Chang	want := &spb.Struct{}
722*e7b1675dSTing-Kang Chang	if err := want.UnmarshalJSON([]byte(jwkES256PublicKey)); err != nil {
723*e7b1675dSTing-Kang Chang		t.Fatalf("want.UnmarshalJSON() err = %v, want nil", err)
724*e7b1675dSTing-Kang Chang	}
725*e7b1675dSTing-Kang Chang	if !cmp.Equal(want, got, protocmp.Transform()) {
726*e7b1675dSTing-Kang Chang		t.Errorf("mismatch in jwk sets: diff (-want,+got): %v", cmp.Diff(want, got, protocmp.Transform()))
727*e7b1675dSTing-Kang Chang	}
728*e7b1675dSTing-Kang Chang}
729