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 18 19import ( 20 "fmt" 21 "testing" 22 "time" 23 24 "github.com/google/tink/go/signature/subtle" 25 "github.com/google/tink/go/tink" 26) 27 28func createTinkECVerifier() (tink.Verifier, error) { 29 // Public key from: https://datatracker.ietf.org/doc/html/rfc7515#appendix-A.3 30 x, err := base64Decode("f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU") 31 if err != nil { 32 return nil, fmt.Errorf("base64 decoding x coordinate of public key: %v", err) 33 } 34 y, err := base64Decode("x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0") 35 if err != nil { 36 return nil, fmt.Errorf("base64 decoding y coordinate of public key: %v", err) 37 } 38 tv, err := subtle.NewECDSAVerifier("SHA256", "NIST_P256", "IEEE_P1363", x, y) 39 if err != nil { 40 return nil, fmt.Errorf("subtle.NewECDSAVerifier() err = %v, want nil", err) 41 } 42 return tv, nil 43} 44 45func createTinkECSigner() (tink.Signer, error) { 46 // Private key from: https://datatracker.ietf.org/doc/html/rfc7515#appendix-A.3 47 k, err := base64Decode("jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI") 48 if err != nil { 49 return nil, fmt.Errorf("base64 decoding private key: %v", err) 50 } 51 ts, err := subtle.NewECDSASigner("SHA256", "NIST_P256", "IEEE_P1363", k) 52 if err != nil { 53 return nil, fmt.Errorf("subtle.NewECDSASigner() err = %v, want nil", err) 54 } 55 return ts, nil 56} 57 58func createESVerifier(kid *string) (*verifierWithKID, error) { 59 tv, err := createTinkECVerifier() 60 if err != nil { 61 return nil, err 62 } 63 v, err := newVerifierWithKID(tv, "ES256", kid) 64 if err != nil { 65 return nil, fmt.Errorf("newVerifierWithKID(algorithm = 'ES256') err = %v, want nil", err) 66 } 67 return v, nil 68} 69 70func createESSigner(kid *string) (*signerWithKID, error) { 71 ts, err := createTinkECSigner() 72 if err != nil { 73 return nil, err 74 } 75 s, err := newSignerWithKID(ts, "ES256", kid) 76 if err != nil { 77 return nil, fmt.Errorf("newSignerWithKID(algorithm = 'ES256') err = %v, want nil", err) 78 } 79 return s, nil 80} 81 82func TestVerifierWithFixedToken(t *testing.T) { 83 // compact from: https://datatracker.ietf.org/doc/html/rfc7515#appendix-A.3 84 compact := "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q" 85 v, err := createESVerifier(nil) 86 if err != nil { 87 t.Fatal(err) 88 } 89 validator, err := NewValidator(&ValidatorOpts{ExpectedIssuer: refString("joe"), FixedNow: time.Unix(1300819300, 0)}) 90 if err != nil { 91 t.Fatalf("NewValidator() err = %v, want nil", err) 92 } 93 verified, err := v.VerifyAndDecodeWithKID(compact, validator, nil) 94 if err != nil { 95 t.Errorf("VerifyAndDecodeWithKID() err = %v, want nil", err) 96 } 97 issuer, err := verified.Issuer() 98 if err != nil { 99 t.Errorf("verified.Issuer() err = %v, want nil", err) 100 } 101 if issuer != "joe" { 102 t.Errorf("verified.Issuer() = %q, want joe", issuer) 103 } 104 expiration, err := verified.ExpiresAt() 105 if err != nil { 106 t.Errorf("verified.ExpiresAt() err = %v, want nil", err) 107 } 108 wantExp := time.Unix(1300819380, 0) 109 if !expiration.Equal(wantExp) { 110 t.Errorf("verified.ExpiresAt() = %q, want %q", expiration, wantExp) 111 } 112 boolClaim, err := verified.BooleanClaim("http://example.com/is_root") 113 if err != nil { 114 t.Errorf("verified.BooleanClaim('http://example.com/is_root') err = %v, want nil", err) 115 } 116 if boolClaim != true { 117 t.Errorf("verified.BooleanClaim('http://example.com/is_root') = %v, want false", boolClaim) 118 } 119} 120 121func TestCreateSignValidateToken(t *testing.T) { 122 rawJWT, err := NewRawJWT(&RawJWTOptions{TypeHeader: refString("JWT"), WithoutExpiration: true}) 123 if err != nil { 124 t.Fatalf("NewRawJWT() err = %v, want nil", err) 125 } 126 validator, err := NewValidator(&ValidatorOpts{ExpectedTypeHeader: refString("JWT"), AllowMissingExpiration: true}) 127 if err != nil { 128 t.Fatalf("NewValidator() err = %v, want nil", err) 129 } 130 s, err := createESSigner(nil) 131 if err != nil { 132 t.Fatal(err) 133 } 134 v, err := createESVerifier(nil) 135 if err != nil { 136 t.Fatal(err) 137 } 138 139 compact, err := s.SignAndEncodeWithKID(rawJWT, nil) 140 if err != nil { 141 t.Fatalf("s.SignAndEncodeWithKID() err = %v, want nil", err) 142 } 143 verified, err := v.VerifyAndDecodeWithKID(compact, validator, nil) 144 if err != nil { 145 t.Fatalf("v.VerifyAndDecodeWithKID() err = %v, want nil", err) 146 } 147 typeHeader, err := verified.TypeHeader() 148 if err != nil { 149 t.Errorf("verified.TypeHeader() err = %v, want nil", err) 150 } 151 if typeHeader != "JWT" { 152 t.Errorf("verified.TypeHeader() = %q, want 'JWT'", typeHeader) 153 } 154} 155 156func TestSignerWithTinkAndCustomKIDFails(t *testing.T) { 157 rawJWT, err := NewRawJWT(&RawJWTOptions{TypeHeader: refString("JWT"), WithoutExpiration: true}) 158 if err != nil { 159 t.Fatalf("NewRawJWT() err = %v, want nil", err) 160 } 161 s, err := createESSigner(refString("1234")) 162 if err != nil { 163 t.Fatal(err) 164 } 165 if _, err := s.SignAndEncodeWithKID(rawJWT, refString("123")); err == nil { 166 t.Errorf("s.SignAndEncodeWithKID(kid = 123) err = nil, want error") 167 } 168} 169 170type signerVerifierKIDTestCase struct { 171 tag string 172 signerCustomKID *string 173 verifierCustomKID *string 174 // calculated from the Tink Key ID. 175 signerKID *string 176 // calculated from the Tink Key ID. 177 verifierKID *string 178} 179 180func TestSignVerifyWithKID(t *testing.T) { 181 rawJWT, err := NewRawJWT(&RawJWTOptions{TypeHeader: refString("JWT"), WithoutExpiration: true}) 182 if err != nil { 183 t.Fatalf("NewRawJWT() err = %v, want nil", err) 184 } 185 validator, err := NewValidator(&ValidatorOpts{ExpectedTypeHeader: refString("JWT"), AllowMissingExpiration: true}) 186 if err != nil { 187 t.Fatalf("NewValidator() err = %v, want nil", err) 188 } 189 for _, tc := range []signerVerifierKIDTestCase{ 190 { 191 tag: "verifier with custom kid matches kid in header generated with custom kid", 192 signerCustomKID: refString("1234"), 193 verifierCustomKID: refString("1234"), 194 }, 195 { 196 tag: "verifier with tink kid matches kid in header generated with custom kid", 197 signerCustomKID: refString("1234"), 198 verifierKID: refString("1234"), 199 }, 200 { 201 tag: "verifier with tink kid matches kid in header generated with tink kid", 202 signerKID: refString("1234"), 203 verifierKID: refString("1234"), 204 }, 205 { 206 tag: "no kid in verifier ignores kid when present in header", 207 signerKID: refString("1234"), 208 }, 209 { 210 tag: "verifier with custom kid ignores when no kid present in header", 211 verifierCustomKID: refString("1234"), 212 }, 213 } { 214 t.Run(tc.tag, func(t *testing.T) { 215 s, err := createESSigner(tc.signerCustomKID) 216 if err != nil { 217 t.Fatal(err) 218 } 219 v, err := createESVerifier(tc.verifierCustomKID) 220 if err != nil { 221 t.Fatal(err) 222 } 223 compact, err := s.SignAndEncodeWithKID(rawJWT, tc.signerKID) 224 if err != nil { 225 t.Fatalf("s.SignAndEncodeWithKID(kid = %v) err = %v, want nil", tc.signerKID, err) 226 } 227 verified, err := v.VerifyAndDecodeWithKID(compact, validator, tc.verifierKID) 228 if err != nil { 229 t.Fatalf("s.VerifyAndDecodeWithKID(kid = %v) err = %v, want nil", tc.verifierKID, err) 230 } 231 typeHeader, err := verified.TypeHeader() 232 if err != nil { 233 t.Errorf("verified.TypeHeader() err = %v, want nil", err) 234 } 235 if typeHeader != "JWT" { 236 t.Errorf("verified.TypeHeader() = %q, want 'JWT'", typeHeader) 237 } 238 }) 239 } 240} 241 242func TestSignVerifyWithKIDFailure(t *testing.T) { 243 rawJWT, err := NewRawJWT(&RawJWTOptions{TypeHeader: refString("JWT"), WithoutExpiration: true}) 244 if err != nil { 245 t.Fatalf("NewRawJWT() err = %v, want nil", err) 246 } 247 validator, err := NewValidator(&ValidatorOpts{ExpectedTypeHeader: refString("JWT"), AllowMissingExpiration: true}) 248 if err != nil { 249 t.Fatalf("NewValidator() err = %v, want nil", err) 250 } 251 for _, tc := range []signerVerifierKIDTestCase{ 252 { 253 tag: "verifier with custom kid different from header generated with custom kid", 254 signerCustomKID: refString("1234"), 255 verifierCustomKID: refString("123"), 256 }, 257 { 258 tag: "verifier with custom kid different from header generated with tink kid", 259 signerKID: refString("5678"), 260 verifierCustomKID: refString("1234"), 261 }, 262 { 263 tag: "verifier with both tink and custom kid", 264 verifierCustomKID: refString("1234"), 265 verifierKID: refString("1234"), 266 }, 267 { 268 tag: "verifier with tink kid and token without kid in header", 269 verifierKID: refString("1234"), 270 }, 271 } { 272 t.Run(tc.tag, func(t *testing.T) { 273 s, err := createESSigner(tc.signerCustomKID) 274 if err != nil { 275 t.Fatal(err) 276 } 277 v, err := createESVerifier(tc.verifierCustomKID) 278 if err != nil { 279 t.Fatal(err) 280 } 281 compact, err := s.SignAndEncodeWithKID(rawJWT, tc.signerKID) 282 if err != nil { 283 t.Fatalf("s.SignAndEncodeWithKID(kid = %v) err = %v, want nil", tc.signerKID, err) 284 } 285 if _, err := v.VerifyAndDecodeWithKID(compact, validator, tc.verifierKID); err == nil { 286 t.Fatalf("s.VerifyAndDecodeWithKID(kid = %v) err = nil, want error", tc.verifierKID) 287 } 288 }) 289 } 290} 291 292func TestVerifierModifiedCompact(t *testing.T) { 293 rawJWT, err := NewRawJWT(&RawJWTOptions{TypeHeader: refString("JWT"), WithoutExpiration: true}) 294 if err != nil { 295 t.Fatalf("NewRawJWT() err = %v, want nil", err) 296 } 297 validator, err := NewValidator(&ValidatorOpts{ExpectedTypeHeader: refString("JWT"), AllowMissingExpiration: true}) 298 if err != nil { 299 t.Fatalf("NewValidator() err = %v, want nil", err) 300 } 301 s, err := createESSigner(nil) 302 if err != nil { 303 t.Fatal(err) 304 } 305 v, err := createESVerifier(nil) 306 if err != nil { 307 t.Fatal(err) 308 } 309 compact, err := s.SignAndEncodeWithKID(rawJWT, nil) 310 if err != nil { 311 t.Fatalf("s.SignAndEncodeWithKID() err = %v, want nil", err) 312 } 313 if _, err := v.VerifyAndDecodeWithKID(compact, validator, nil); err != nil { 314 t.Errorf("VerifyAndDecodeWithKID() err = %v, want nil", err) 315 } 316 for _, invalid := range []string{ 317 compact + "x", 318 compact + " ", 319 "x" + compact, 320 " " + compact, 321 } { 322 if _, err := v.VerifyAndDecodeWithKID(invalid, validator, nil); err == nil { 323 t.Errorf("VerifyAndDecodeWithKID() err = nil, want error") 324 } 325 } 326} 327 328func TestVerifierInvalidInputs(t *testing.T) { 329 validator, err := NewValidator(&ValidatorOpts{AllowMissingExpiration: true}) 330 if err != nil { 331 t.Fatalf("NewValidator() err = %v, want nil", err) 332 } 333 v, err := createESVerifier(nil) 334 if err != nil { 335 t.Fatal(err) 336 } 337 for _, invalid := range []string{ 338 "eyJhbGciOiJUzI1NiJ9.e30.YWJj.", 339 "eyJhbGciOiJUzI1NiJ9?.e30.YWJj", 340 "eyJhbGciOiJUzI1NiJ9.e30?.YWJj", 341 "eyJhbGciOiJUzI1NiJ9.e30.YWJj?", 342 "eyJhbGciOiJUzI1NiJ9.YWJj", 343 } { 344 if _, err := v.VerifyAndDecodeWithKID(invalid, validator, nil); err == nil { 345 t.Errorf("v.VerifyAndDecodeWithKID(compact = %q) err = nil, want error", invalid) 346 } 347 } 348} 349 350func TestNewSignerWithNilTinkSignerFails(t *testing.T) { 351 if _, err := newSignerWithKID(nil, "ES256", nil); err == nil { 352 t.Errorf("newSignerWithKID(nil, 'ES256', nil) err = nil, want error") 353 } 354} 355 356func TestNewVerifierWithNilTinkVerifierFails(t *testing.T) { 357 if _, err := newVerifierWithKID(nil, "ES256", nil); err == nil { 358 t.Errorf("newVerifierWithKID(nil, 'ES256', nil) err = nil, want error") 359 } 360} 361