blob: 300e27f3dc0a48fce37adec0fc8b4a2dab9c7223 [file] [log] [blame]
// 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 ")
}
}