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