// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////////// package jwt import ( "fmt" "testing" "time" "google.golang.org/protobuf/proto" "github.com/google/tink/go/core/registry" jepb "github.com/google/tink/go/proto/jwt_ecdsa_go_proto" ) const testECDSAVerifierKeyType = "type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey" func TestECDSAVerifierNotImplemented(t *testing.T) { km, err := registry.GetKeyManager(testECDSAVerifierKeyType) if err != nil { t.Fatalf("registry.GetKeyManager(%q) err = %v, want nil", testECDSAVerifierKeyType, err) } if _, err := km.NewKey(nil); err != errECDSAVerifierNotImplemented { t.Fatalf("km.NewKey() err = %v, want %v", err, errECDSAVerifierNotImplemented) } if _, err := km.NewKeyData(nil); err != errECDSAVerifierNotImplemented { t.Fatalf("km.NewKeyData() err = %v, want %v", err, errECDSAVerifierNotImplemented) } } func TestECDSAVerifierDoesSupport(t *testing.T) { km, err := registry.GetKeyManager(testECDSAVerifierKeyType) if err != nil { t.Fatalf("registry.GetKeyManager(%q) err = %v, want nil", testECDSAVerifierKeyType, err) } if !km.DoesSupport(testECDSAVerifierKeyType) { t.Errorf("km.DoesSupport(%q) = false, want true", testECDSAVerifierKeyType) } if km.DoesSupport("not.the.actual.key.type") { t.Errorf("km.DoesSupport('not.the.actual.key.type') = true, want false") } } func TestECDSAVerifierTypeURL(t *testing.T) { km, err := registry.GetKeyManager(testECDSAVerifierKeyType) if err != nil { t.Fatalf("registry.GetKeyManager(%q) err = %v, want nil", testECDSAVerifierKeyType, err) } if km.TypeURL() != testECDSAVerifierKeyType { t.Errorf("km.TypeURL() = %q, want %q", km.TypeURL(), testECDSAVerifierKeyType) } } func TestECDSAVerifierPrimitiveWithNilKey(t *testing.T) { km, err := registry.GetKeyManager(testECDSAVerifierKeyType) if err != nil { t.Fatalf("registry.GetKeyManager(%q) err = %v, want nil", testECDSAVerifierKeyType, err) } if _, err := km.Primitive(nil); err == nil { t.Errorf("km.Primitive(nil) err = nil, want error") } } func createECDSAPublicKey(algorithm jepb.JwtEcdsaAlgorithm, kid *string, version uint32) (*jepb.JwtEcdsaPublicKey, error) { // Public key from: https://datatracker.ietf.org/doc/html/rfc7515#appendix-A.3 x, err := base64Decode("f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU") if err != nil { return nil, fmt.Errorf("base64 decoding x coordinate of public key: %v", err) } y, err := base64Decode("x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0") if err != nil { return nil, fmt.Errorf("base64 decoding y coordinate of public key: %v", err) } var customKID *jepb.JwtEcdsaPublicKey_CustomKid = nil if kid != nil { customKID = &jepb.JwtEcdsaPublicKey_CustomKid{Value: *kid} } return &jepb.JwtEcdsaPublicKey{ Version: version, Algorithm: algorithm, X: x, Y: y, CustomKid: customKID, }, nil } func createECDSASerializedPublicKey(algorithm jepb.JwtEcdsaAlgorithm, kid *string, version uint32) ([]byte, error) { pubKey, err := createECDSAPublicKey(algorithm, kid, version) if err != nil { return nil, err } return proto.Marshal(pubKey) } func TestECDSAVerifierPrimitiveInvalidKeyVersion(t *testing.T) { km, err := registry.GetKeyManager(testECDSAVerifierKeyType) if err != nil { t.Fatalf("registry.GetKeyManager(%q) err = %v, want nil", testECDSAVerifierKeyType, err) } var invalidKeyVersion uint32 = 1 serializedPubKey, err := createECDSASerializedPublicKey(jepb.JwtEcdsaAlgorithm_ES384, nil, invalidKeyVersion) if err != nil { t.Fatal(err) } if _, err := km.Primitive(serializedPubKey); err == nil { t.Errorf("km.Primitive() err = nil, want error") } } func TestECDSAVerifierPrimitiveWithInvalidAlgorithm(t *testing.T) { km, err := registry.GetKeyManager(testECDSAVerifierKeyType) if err != nil { t.Fatalf("registry.GetKeyManager(%q) err = %v, want nil", testECDSAVerifierKeyType, err) } serializedPubKey, err := createECDSASerializedPublicKey(jepb.JwtEcdsaAlgorithm_ES_UNKNOWN, nil /*=kid*/, 0 /*=version*/) if err != nil { t.Fatal(err) } if _, err := km.Primitive(serializedPubKey); err == nil { t.Errorf("km.Primitive() err = nil, want error") } } func TestECDSAVerifierPrimitiveVerifyFixedToken(t *testing.T) { km, err := registry.GetKeyManager(testECDSAVerifierKeyType) if err != nil { t.Fatalf("registry.GetKeyManager(%q) err = %v, want nil", testECDSAVerifierKeyType, err) } serializedPubKey, err := createECDSASerializedPublicKey(jepb.JwtEcdsaAlgorithm_ES256, nil /*=kid*/, 0 /*=version*/) if err != nil { t.Fatal(err) } v, err := km.Primitive(serializedPubKey) if err != nil { t.Fatalf("km.Primitive() err = %v, want nil", err) } verifier, ok := v.(*verifierWithKID) if !ok { t.Fatalf("primitive is not a JWT Verifier") } // compact from https://datatracker.ietf.org/doc/html/rfc7515#appendix-A.3 compact := "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q" opts := &ValidatorOpts{ ExpectedIssuer: refString("joe"), FixedNow: time.Unix(12345, 0), } validator, err := NewValidator(opts) if err != nil { t.Fatalf("creating JWTValidator: %v", err) } // verification succeeds because token was valid valid on January 1, 1970 UTC. if _, err := verifier.VerifyAndDecodeWithKID(compact, validator, nil); err != nil { t.Errorf("verifier.VerifyAndDecodeWithKID(kid = nil) err = %v, want nil", err) } // verification with KID fails because token contains no KID. if _, err := verifier.VerifyAndDecodeWithKID(compact, validator, refString("1234")); err == nil { t.Errorf("verifier.VerifyAndDecodeWithKID(kid = '1234') err = nil, want error") } } func TestECDSAVerifierPrimitiveFixedTokenWithKID(t *testing.T) { km, err := registry.GetKeyManager(testECDSAVerifierKeyType) if err != nil { t.Fatalf("registry.GetKeyManager(%q) err = %v, want nil", testECDSAVerifierKeyType, err) } serializedPubKey, err := createECDSASerializedPublicKey(jepb.JwtEcdsaAlgorithm_ES256, refString("1234"), 0 /*=version*/) if err != nil { t.Fatal(err) } v, err := km.Primitive(serializedPubKey) if err != nil { t.Fatalf("km.Primitive() err = %v, want nil", err) } verifier, ok := v.(*verifierWithKID) if !ok { t.Fatalf("primitive is not a JWT Verifier") } // compact is the claim set '{}' with header '{"alg":"ES256", "kid":"1234"}' // signed with private key as specified in https://datatracker.ietf.org/doc/html/rfc7515#appendix-A.3 compact := "eyJhbGciOiJFUzI1NiIsImtpZCI6IjEyMzQifQ.e30.3jdIhPC4qfXrzE8ds6tyrLoqqmwfXX-CyfP9YG0k_LFeuF5wYPsmgPeUthMFfvPIN63zQ9i-I5BQLJVwaRTTdw" validator, err := NewValidator(&ValidatorOpts{AllowMissingExpiration: true}) if err != nil { t.Fatalf("creating JWTValidator: %v", err) } if _, err := verifier.VerifyAndDecodeWithKID(compact, validator, nil); err != nil { t.Errorf("verifier.VerifyAndDecodeWithKID(kid = nil) err = %v, want nil ", err) } if _, err := verifier.VerifyAndDecodeWithKID(compact, validator, refString("1234")); err == nil { t.Errorf("verifier.VerifyAndDecodeWithKID(kid = 1234) err = nil, want error ") } }