def test_legacy_non_primary_key_fails(self): builder = keyset_builder.new_keyset_builder() old_template = keyset_builder.legacy_template(jwt.jwt_es256_template()) _ = builder.add_new_key(old_template) current_key_id = builder.add_new_key(jwt.jwt_es256_template()) builder.set_primary_key(current_key_id) handle = builder.keyset_handle() with self.assertRaises(tink.TinkError): handle.primitive(jwt.JwtPublicKeySign) with self.assertRaises(tink.TinkError): handle.public_keyset_handle().primitive(jwt.JwtPublicKeyVerify)
def test_verify_with_other_key_fails(self): handle = tink.new_keyset_handle(jwt.jwt_es256_template()) sign = handle.primitive(jwt.JwtPublicKeySign) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) compact = sign.sign_and_encode(raw_jwt) other_handle = tink.new_keyset_handle(jwt.jwt_es256_template()) other_verify = other_handle.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) with self.assertRaises(tink.TinkError): other_verify.verify_and_decode( compact, jwt.new_validator(expected_issuer='issuer', allow_missing_expiration=True))
class JwtKeyTemplatesTest(parameterized.TestCase): @parameterized.parameters([ ('JWT_HS256', jwt.jwt_hs256_template()), ('JWT_HS384', jwt.jwt_hs384_template()), ('JWT_HS512', jwt.jwt_hs512_template()), ('JWT_ES256', jwt.jwt_es256_template()), ('JWT_ES384', jwt.jwt_es384_template()), ('JWT_ES512', jwt.jwt_es512_template()), ('JWT_RS256_2048_F4', jwt.jwt_rs256_2048_f4_template()), ('JWT_RS256_3072_F4', jwt.jwt_rs256_3072_f4_template()), ('JWT_RS384_3072_F4', jwt.jwt_rs384_3072_f4_template()), ('JWT_RS512_4096_F4', jwt.jwt_rs512_4096_f4_template()), ('JWT_PS256_2048_F4', jwt.jwt_ps256_2048_f4_template()), ('JWT_PS256_3072_F4', jwt.jwt_ps256_3072_f4_template()), ('JWT_PS384_3072_F4', jwt.jwt_ps384_3072_f4_template()), ('JWT_PS512_4096_F4', jwt.jwt_ps512_4096_f4_template()), ]) def test_template(self, template_name, template): self.assertEqual(template, helper.template_from_testdata(template_name, 'jwt')) @parameterized.named_parameters(('0', 0, b'\x00'), ('256', 256, b'\x01\x00'), ('65537', 65537, b'\x01\x00\x01')) def test_num_to_bytes(self, number, expected): self.assertEqual(jwt._jwt_key_templates._num_to_bytes(number), expected)
def test_jwt_public_key_sign_verify(self, lang): private_keyset = testing_servers.new_keyset(lang, jwt.jwt_es256_template()) public_keyset = testing_servers.public_keyset(lang, private_keyset) signer = testing_servers.jwt_public_key_sign(lang, private_keyset) verifier = testing_servers.jwt_public_key_verify(lang, public_keyset) now = datetime.datetime.now(tz=datetime.timezone.utc) token = jwt.new_raw_jwt( issuer='issuer', subject='subject', audiences=['audience1', 'audience2'], jwt_id='jwt_id', expiration=now + datetime.timedelta(seconds=10), custom_claims={'switch': True, 'pi': 3.14159}) compact = signer.sign_and_encode(token) validator = jwt.new_validator( expected_issuer='issuer', expected_audience='audience1', fixed_now=now) verified_jwt = verifier.verify_and_decode(compact, validator) self.assertEqual(verified_jwt.issuer(), 'issuer') self.assertEqual(verified_jwt.subject(), 'subject') self.assertEqual(verified_jwt.jwt_id(), 'jwt_id') self.assertEqual(verified_jwt.custom_claim('switch'), True) self.assertEqual(verified_jwt.custom_claim('pi'), 3.14159) validator2 = jwt.new_validator( expected_audience='wrong_audience', fixed_now=now) with self.assertRaises(tink.TinkError): verifier.verify_and_decode(compact, validator2)
def test_generate_compute_verify_signature(self): keyset_servicer = services.KeysetServicer() jwt_servicer = jwt_service.JwtServicer() template = jwt.jwt_es256_template().SerializeToString() gen_request = testing_api_pb2.KeysetGenerateRequest(template=template) gen_response = keyset_servicer.Generate(gen_request, self._ctx) self.assertEqual(gen_response.WhichOneof('result'), 'keyset') private_keyset = gen_response.keyset comp_request = testing_api_pb2.JwtSignRequest(keyset=private_keyset) comp_request.raw_jwt.issuer.value = 'issuer' comp_request.raw_jwt.subject.value = 'subject' comp_request.raw_jwt.custom_claims['myclaim'].bool_value = True comp_response = jwt_servicer.PublicKeySignAndEncode(comp_request, self._ctx) self.assertEqual(comp_response.WhichOneof('result'), 'signed_compact_jwt') signed_compact_jwt = comp_response.signed_compact_jwt pub_request = testing_api_pb2.KeysetPublicRequest( private_keyset=private_keyset) pub_response = keyset_servicer.Public(pub_request, self._ctx) self.assertEqual(pub_response.WhichOneof('result'), 'public_keyset') public_keyset = pub_response.public_keyset verify_request = testing_api_pb2.JwtVerifyRequest( keyset=public_keyset, signed_compact_jwt=signed_compact_jwt) verify_request.validator.expected_issuer.value = 'issuer' verify_request.validator.expected_subject.value = 'subject' verify_request.validator.allow_missing_expiration = True verify_response = jwt_servicer.PublicKeyVerifyAndDecode( verify_request, self._ctx) self.assertEqual(verify_response.WhichOneof('result'), 'verified_jwt') self.assertEqual(verify_response.verified_jwt.issuer.value, 'issuer')
def test_create_sign_primitive_with_invalid_algorithm_fails(self): handle = tink.new_keyset_handle(jwt.jwt_es256_template()) key = jwt_ecdsa_pb2.JwtEcdsaPrivateKey.FromString( handle._keyset.key[0].key_data.value) key.public_key.algorithm = jwt_ecdsa_pb2.ES_UNKNOWN handle._keyset.key[0].key_data.value = key.SerializeToString() with self.assertRaises(tink.TinkError): handle.primitive(jwt.JwtPublicKeySign)
def test_interesting_error(self): private_handle = tink.new_keyset_handle(jwt.jwt_es256_template()) sign = private_handle.primitive(jwt.JwtPublicKeySign) verify = private_handle.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) compact = sign.sign_and_encode(raw_jwt) with self.assertRaisesRegex(jwt.JwtInvalidError, 'invalid JWT; expected issuer'): verify.verify_and_decode(compact, jwt.new_validator( expected_issuer='unknown', allow_missing_expiration=True))
def test_create_sign_verify(self): handle = tink.new_keyset_handle(jwt.jwt_es256_template()) sign = handle.primitive(jwt.JwtPublicKeySign) verify = handle.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) raw_jwt = jwt.new_raw_jwt( issuer='joe', expiration=DATETIME_2011, custom_claims={'http://example.com/is_root': True}) signed_compact = sign.sign_and_encode(raw_jwt) validator = jwt.new_validator(expected_issuer='joe', fixed_now=DATETIME_1970) verified_jwt = verify.verify_and_decode(signed_compact, validator) self.assertEqual(verified_jwt.issuer(), 'joe') self.assertEqual(verified_jwt.expiration().year, 2011) self.assertCountEqual(verified_jwt.custom_claim_names(), ['http://example.com/is_root']) self.assertTrue( verified_jwt.custom_claim('http://example.com/is_root')) # fails because it is expired with self.assertRaises(tink.TinkError): verify.verify_and_decode( signed_compact, jwt.new_validator(expected_issuer='joe', fixed_now=DATETIME_2020)) # wrong issuer with self.assertRaises(tink.TinkError): verify.verify_and_decode( signed_compact, jwt.new_validator(expected_issuer='jane', fixed_now=DATETIME_1970)) # invalid format with self.assertRaises(tink.TinkError): verify.verify_and_decode(signed_compact + '.123', validator) # invalid character with self.assertRaises(tink.TinkError): verify.verify_and_decode(signed_compact + '?', validator) # modified signature with self.assertRaises(tink.TinkError): verify.verify_and_decode(signed_compact + 'a', validator) # modified header with self.assertRaises(tink.TinkError): verify.verify_and_decode('a' + signed_compact, validator)
def test_create_sign_verify_with_type_header(self): handle = tink.new_keyset_handle(jwt.jwt_es256_template()) sign = handle.primitive(jwt.JwtPublicKeySign) verify = handle.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) raw_jwt = jwt.new_raw_jwt(type_header='typeHeader', issuer='joe', without_expiration=True) signed_compact = sign.sign_and_encode(raw_jwt) validator = jwt.new_validator(expected_type_header='typeHeader', expected_issuer='joe', allow_missing_expiration=True) verified_jwt = verify.verify_and_decode(signed_compact, validator) self.assertEqual(verified_jwt.type_header(), 'typeHeader')
class JwtKeyTemplatesTest(parameterized.TestCase): @parameterized.parameters([ ('JWT_HS256', jwt.jwt_hs256_template()), ('JWT_HS384', jwt.jwt_hs384_template()), ('JWT_HS512', jwt.jwt_hs512_template()), ('JWT_ES256', jwt.jwt_es256_template()), ('JWT_ES384', jwt.jwt_es384_template()), ('JWT_ES512', jwt.jwt_es512_template()), ('JWT_RS256_2048_F4', jwt.jwt_rs256_2048_f4_template()), ('JWT_RS256_3072_F4', jwt.jwt_rs256_3072_f4_template()), ('JWT_RS384_3072_F4', jwt.jwt_rs384_3072_f4_template()), ('JWT_RS512_4096_F4', jwt.jwt_rs512_4096_f4_template()), ('JWT_PS256_2048_F4', jwt.jwt_ps256_2048_f4_template()), ('JWT_PS256_3072_F4', jwt.jwt_ps256_3072_f4_template()), ('JWT_PS384_3072_F4', jwt.jwt_ps384_3072_f4_template()), ('JWT_PS512_4096_F4', jwt.jwt_ps512_4096_f4_template()), ]) def test_template(self, template_name, template): self.assertEqual(template, helper.template_from_testdata(template_name, 'jwt')) @parameterized.named_parameters(('0', 0, b'\x00'), ('256', 256, b'\x01\x00'), ('65537', 65537, b'\x01\x00\x01')) def test_num_to_bytes(self, number, expected): self.assertEqual(jwt._jwt_key_templates._num_to_bytes(number), expected) @parameterized.named_parameters([ ('JWT_HS256', jwt.jwt_hs256_template()), ('JWT_HS384', jwt.jwt_hs384_template()), ('JWT_HS512', jwt.jwt_hs512_template()), ]) def test_mac_success(self, key_template): keyset_handle = tink.new_keyset_handle(key_template) jwt_hmac = keyset_handle.primitive(jwt.JwtMac) token = jwt.new_raw_jwt(issuer='issuer', subject='subject') compact = jwt_hmac.compute_mac_and_encode(token) output_token = jwt_hmac.verify_mac_and_decode(compact, jwt.new_validator()) self.assertEqual(output_token.issuer(), token.issuer()) self.assertEqual(output_token.subject(), token.subject())
def test_jwt_public_key_sign_export_import_verify(self, lang): private_keyset = testing_servers.new_keyset(lang, jwt.jwt_es256_template()) public_keyset = testing_servers.public_keyset(lang, private_keyset) # sign and export public key signer = testing_servers.jwt_public_key_sign(lang, private_keyset) now = datetime.datetime.now(tz=datetime.timezone.utc) token = jwt.new_raw_jwt( jwt_id='jwt_id', expiration=now + datetime.timedelta(seconds=100)) compact = signer.sign_and_encode(token) public_jwk_set = testing_servers.jwk_set_from_keyset(lang, public_keyset) # verify using public_jwk_set imported_public_keyset = testing_servers.jwk_set_to_keyset( lang, public_jwk_set) verifier = testing_servers.jwt_public_key_verify(lang, imported_public_keyset) validator = jwt.new_validator(fixed_now=now) verified_jwt = verifier.verify_and_decode(compact, validator) self.assertEqual(verified_jwt.jwt_id(), 'jwt_id')
signature.signature_key_templates.RSA_SSA_PSS_4096_SHA512_SHA512_64_F4, 'AES_CMAC_PRF': prf.prf_key_templates.AES_CMAC, 'HMAC_PRF_SHA256': prf.prf_key_templates.HMAC_SHA256, 'HMAC_PRF_SHA512': prf.prf_key_templates.HMAC_SHA512, 'HKDF_PRF_SHA256': prf.prf_key_templates.HKDF_SHA256, 'JWT_HS256': jwt.jwt_hs256_template(), 'JWT_HS256_RAW': jwt.raw_jwt_hs256_template(), 'JWT_HS384': jwt.jwt_hs384_template(), 'JWT_HS384_RAW': jwt.raw_jwt_hs384_template(), 'JWT_HS512': jwt.jwt_hs512_template(), 'JWT_HS512_RAW': jwt.raw_jwt_hs512_template(), 'JWT_ES256': jwt.jwt_es256_template(), 'JWT_ES256_RAW': jwt.raw_jwt_es256_template(), 'JWT_ES384': jwt.jwt_es384_template(), 'JWT_ES384_RAW': jwt.raw_jwt_es384_template(), 'JWT_ES512': jwt.jwt_es512_template(), 'JWT_ES512_RAW': jwt.raw_jwt_es512_template(), 'JWT_RS256_2048_F4': jwt.jwt_rs256_2048_f4_template(), 'JWT_RS256_2048_F4_RAW': jwt.raw_jwt_rs256_2048_f4_template(), 'JWT_RS256_3072_F4': jwt.jwt_rs256_3072_f4_template(), 'JWT_RS256_3072_F4_RAW': jwt.raw_jwt_rs256_3072_f4_template(), 'JWT_RS384_3072_F4': jwt.jwt_rs384_3072_f4_template(), 'JWT_RS384_3072_F4_RAW': jwt.raw_jwt_rs384_3072_f4_template(), 'JWT_RS512_4096_F4': jwt.jwt_rs512_4096_f4_template(), 'JWT_RS512_4096_F4_RAW': jwt.raw_jwt_rs512_4096_f4_template(), 'JWT_PS256_2048_F4': jwt.jwt_ps256_2048_f4_template(), 'JWT_PS256_2048_F4_RAW': jwt.raw_jwt_ps256_2048_f4_template(),
class JwtKeyTemplatesTest(parameterized.TestCase): @parameterized.named_parameters([ ('JWT_HS256', jwt.jwt_hs256_template()), ('JWT_HS256_RAW', jwt.raw_jwt_hs256_template()), ('JWT_HS384', jwt.jwt_hs384_template()), ('JWT_HS384_RAW', jwt.raw_jwt_hs384_template()), ('JWT_HS512', jwt.jwt_hs512_template()), ('JWT_HS512_RAW', jwt.raw_jwt_hs512_template()), ]) def test_mac_success(self, key_template): keyset_handle = tink.new_keyset_handle(key_template) jwt_hmac = keyset_handle.primitive(jwt.JwtMac) token = jwt.new_raw_jwt(issuer='issuer', subject='subject', without_expiration=True) compact = jwt_hmac.compute_mac_and_encode(token) output_token = jwt_hmac.verify_mac_and_decode( compact, jwt.new_validator(expected_issuer='issuer', allow_missing_expiration=True)) self.assertEqual(output_token.issuer(), token.issuer()) self.assertEqual(output_token.subject(), token.subject()) @parameterized.named_parameters([ ('JWT_ES256', jwt.jwt_es256_template()), ('JWT_ES256_RAW', jwt.raw_jwt_es256_template()), ('JWT_ES384', jwt.jwt_es384_template()), ('JWT_ES384_RAW', jwt.raw_jwt_es384_template()), ('JWT_ES512', jwt.jwt_es512_template()), ('JWT_ES512_RAW', jwt.raw_jwt_es512_template()), ('JWT_RS256_2048_F4', jwt.jwt_rs256_2048_f4_template()), ('JWT_RS256_2048_F4_RAW', jwt.raw_jwt_rs256_2048_f4_template()), ('JWT_RS256_3072_F4', jwt.jwt_rs256_3072_f4_template()), ('JWT_RS256_3072_F4_RAW', jwt.raw_jwt_rs256_3072_f4_template()), ('JWT_RS384_3072_F4', jwt.jwt_rs384_3072_f4_template()), ('JWT_RS384_3072_F4_RAW', jwt.raw_jwt_rs384_3072_f4_template()), ('JWT_RS512_4096_F4', jwt.jwt_rs512_4096_f4_template()), ('JWT_RS512_4096_F4_RAW', jwt.raw_jwt_rs512_4096_f4_template()), ('JWT_PS256_2048_F4', jwt.jwt_ps256_2048_f4_template()), ('JWT_PS256_2048_F4_RAW', jwt.raw_jwt_ps256_2048_f4_template()), ('JWT_PS256_3072_F4', jwt.jwt_ps256_3072_f4_template()), ('JWT_PS256_3072_F4_RAW', jwt.raw_jwt_ps256_3072_f4_template()), ('JWT_PS384_3072_F4', jwt.jwt_ps384_3072_f4_template()), ('JWT_PS384_3072_F4_RAW', jwt.raw_jwt_ps384_3072_f4_template()), ('JWT_PS512_4096_F4', jwt.jwt_ps512_4096_f4_template()), ('JWT_PS512_4096_F4_RAW', jwt.raw_jwt_ps512_4096_f4_template()), ]) def test_new_keydata_primitive_success(self, template): private_handle = tink.new_keyset_handle(template) sign = private_handle.primitive(jwt.JwtPublicKeySign) verify = private_handle.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) raw_jwt = jwt.new_raw_jwt(issuer='issuer', subject='subject', without_expiration=True) compact = sign.sign_and_encode(raw_jwt) verified_jwt = verify.verify_and_decode( compact, jwt.new_validator(expected_issuer='issuer', allow_missing_expiration=True)) self.assertEqual(verified_jwt.issuer(), 'issuer') self.assertEqual(verified_jwt.subject(), 'subject')
'HKDF_SHA256': prf.prf_key_templates.HKDF_SHA256, 'JWT_HS256': jwt.jwt_hs256_template(), 'JWT_HS256_RAW': jwt.raw_jwt_hs256_template(), 'JWT_HS384': jwt.jwt_hs384_template(), 'JWT_HS384_RAW': jwt.raw_jwt_hs384_template(), 'JWT_HS512': jwt.jwt_hs512_template(), 'JWT_HS512_RAW': jwt.raw_jwt_hs512_template(), 'JWT_ES256': jwt.jwt_es256_template(), 'JWT_ES256_RAW': jwt.raw_jwt_es256_template(), 'JWT_ES384': jwt.jwt_es384_template(), 'JWT_ES384_RAW': jwt.raw_jwt_es384_template(), 'JWT_ES512': jwt.jwt_es512_template(), 'JWT_ES512_RAW': jwt.raw_jwt_es512_template(), 'JWT_RS256_2048_F4': jwt.jwt_rs256_2048_f4_template(), 'JWT_RS256_2048_F4_RAW': jwt.raw_jwt_rs256_2048_f4_template(), 'JWT_RS256_3072_F4':
def test_jwt_mac_from_keyset_without_primary_fails(self): builder = keyset_builder.new_keyset_builder() builder.add_new_key(jwt.jwt_es256_template()) with self.assertRaises(tink.TinkError): builder.keyset_handle()
class JwtSignatureWrapperTest(parameterized.TestCase): def test_interesting_error(self): private_handle = tink.new_keyset_handle(jwt.jwt_es256_template()) sign = private_handle.primitive(jwt.JwtPublicKeySign) verify = private_handle.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) compact = sign.sign_and_encode(raw_jwt) with self.assertRaisesRegex(jwt.JwtInvalidError, 'invalid JWT; expected issuer'): verify.verify_and_decode(compact, jwt.new_validator( expected_issuer='unknown', allow_missing_expiration=True)) @parameterized.parameters([ (jwt.raw_jwt_es256_template(), jwt.raw_jwt_es256_template()), (jwt.raw_jwt_es256_template(), jwt.jwt_es256_template()), (jwt.jwt_es256_template(), jwt.raw_jwt_es256_template()), (jwt.jwt_es256_template(), jwt.jwt_es256_template()), ]) def test_key_rotation(self, old_key_tmpl, new_key_tmpl): builder = keyset_builder.new_keyset_builder() older_key_id = builder.add_new_key(old_key_tmpl) builder.set_primary_key(older_key_id) handle1 = builder.keyset_handle() sign1 = handle1.primitive(jwt.JwtPublicKeySign) verify1 = handle1.public_keyset_handle().primitive(jwt.JwtPublicKeyVerify) newer_key_id = builder.add_new_key(new_key_tmpl) handle2 = builder.keyset_handle() sign2 = handle2.primitive(jwt.JwtPublicKeySign) verify2 = handle2.public_keyset_handle().primitive(jwt.JwtPublicKeyVerify) builder.set_primary_key(newer_key_id) handle3 = builder.keyset_handle() sign3 = handle3.primitive(jwt.JwtPublicKeySign) verify3 = handle3.public_keyset_handle().primitive(jwt.JwtPublicKeyVerify) builder.disable_key(older_key_id) handle4 = builder.keyset_handle() sign4 = handle4.primitive(jwt.JwtPublicKeySign) verify4 = handle4.public_keyset_handle().primitive(jwt.JwtPublicKeyVerify) raw_jwt = jwt.new_raw_jwt(issuer='a', without_expiration=True) validator = jwt.new_validator( expected_issuer='a', allow_missing_expiration=True) self.assertNotEqual(older_key_id, newer_key_id) # 1 uses the older key. So 1, 2 and 3 can verify the signature, but not 4. compact1 = sign1.sign_and_encode(raw_jwt) self.assertEqual( verify1.verify_and_decode(compact1, validator).issuer(), 'a') self.assertEqual( verify2.verify_and_decode(compact1, validator).issuer(), 'a') self.assertEqual( verify3.verify_and_decode(compact1, validator).issuer(), 'a') with self.assertRaises(tink.TinkError): verify4.verify_and_decode(compact1, validator) # 2 uses the older key. So 1, 2 and 3 can verify the signature, but not 4. compact2 = sign2.sign_and_encode(raw_jwt) self.assertEqual( verify1.verify_and_decode(compact2, validator).issuer(), 'a') self.assertEqual( verify2.verify_and_decode(compact2, validator).issuer(), 'a') self.assertEqual( verify3.verify_and_decode(compact2, validator).issuer(), 'a') with self.assertRaises(tink.TinkError): verify4.verify_and_decode(compact2, validator) # 3 uses the newer key. So 2, 3 and 4 can verify the signature, but not 1. compact3 = sign3.sign_and_encode(raw_jwt) with self.assertRaises(tink.TinkError): verify1.verify_and_decode(compact3, validator) self.assertEqual( verify2.verify_and_decode(compact3, validator).issuer(), 'a') self.assertEqual( verify3.verify_and_decode(compact3, validator).issuer(), 'a') self.assertEqual( verify4.verify_and_decode(compact3, validator).issuer(), 'a') # 4 uses the newer key. So 2, 3 and 4 can verify the signature, but not 1. compact4 = sign4.sign_and_encode(raw_jwt) with self.assertRaises(tink.TinkError): verify1.verify_and_decode(compact4, validator) self.assertEqual( verify2.verify_and_decode(compact4, validator).issuer(), 'a') self.assertEqual( verify3.verify_and_decode(compact4, validator).issuer(), 'a') self.assertEqual( verify4.verify_and_decode(compact4, validator).issuer(), 'a') def test_only_tink_output_prefix_type_encodes_a_kid_header(self): handle = tink.new_keyset_handle(jwt.raw_jwt_es256_template()) sign = handle.primitive(jwt.JwtPublicKeySign) verify = handle.public_keyset_handle().primitive(jwt.JwtPublicKeyVerify) tink_handle = _change_output_prefix_to_tink(handle) tink_sign = tink_handle.primitive(jwt.JwtPublicKeySign) tink_verify = tink_handle.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) token = sign.sign_and_encode(raw_jwt) token_with_kid = tink_sign.sign_and_encode(raw_jwt) _, header, _, _ = _jwt_format.split_signed_compact(token) self.assertNotIn('kid', _json_util.json_loads(header)) _, header_with_kid, _, _ = _jwt_format.split_signed_compact(token_with_kid) self.assertIn('kid', _json_util.json_loads(header_with_kid)) validator = jwt.new_validator( expected_issuer='issuer', allow_missing_expiration=True) verify.verify_and_decode(token, validator) tink_verify.verify_and_decode(token_with_kid, validator) other_handle = _change_key_id(tink_handle) other_verify = other_handle.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) verify.verify_and_decode(token_with_kid, validator) # For output prefix type TINK, the kid header is required. with self.assertRaises(tink.TinkError): tink_verify.verify_and_decode(token, validator) # This should fail because value of the kid header is wrong. with self.assertRaises(tink.TinkError): other_verify.verify_and_decode(token_with_kid, validator) @parameterized.named_parameters([ ('JWT_ES256_RAW', jwt.raw_jwt_es256_template()), ('JWT_RS256_RAW', jwt.raw_jwt_rs256_2048_f4_template()), ('JWT_PS256_RAW', jwt.raw_jwt_ps256_3072_f4_template()), ]) def test_raw_key_with_custom_kid_header(self, template): # normal key with output prefix RAW handle = tink.new_keyset_handle(template) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) validator = jwt.new_validator( expected_issuer='issuer', allow_missing_expiration=True) sign = handle.primitive(jwt.JwtPublicKeySign) token = sign.sign_and_encode(raw_jwt) verify = handle.public_keyset_handle().primitive(jwt.JwtPublicKeyVerify) verify.verify_and_decode(token, validator) _, json_header, _, _ = _jwt_format.split_signed_compact(token) self.assertNotIn('kid', _json_util.json_loads(json_header)) # key with a custom_kid set custom_kid_handle = _set_custom_kid(handle, custom_kid=LONG_CUSTOM_KID) custom_kid_sign = custom_kid_handle.primitive(jwt.JwtPublicKeySign) token_with_kid = custom_kid_sign.sign_and_encode(raw_jwt) custom_kid_verify = custom_kid_handle.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) custom_kid_verify.verify_and_decode(token_with_kid, validator) _, header_with_kid, _, _ = _jwt_format.split_signed_compact(token_with_kid) self.assertEqual(_json_util.json_loads(header_with_kid)['kid'], LONG_CUSTOM_KID) # The primitive with a custom_kid set accepts tokens without kid header. custom_kid_verify.verify_and_decode(token, validator) # The primitive without a custom_kid set ignores the kid header. verify.verify_and_decode(token_with_kid, validator) # key with a different custom_kid set other_handle = _set_custom_kid(handle, custom_kid='other kid') other_verify = other_handle.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) # Fails because the kid value do not match. with self.assertRaises(tink.TinkError): other_verify.verify_and_decode(token_with_kid, validator) tink_handle = _change_output_prefix_to_tink(custom_kid_handle) tink_sign = tink_handle.primitive(jwt.JwtPublicKeySign) tink_verify = tink_handle.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) # Having custom_kid set with output prefix TINK is not allowed. with self.assertRaises(tink.TinkError): tink_sign.sign_and_encode(raw_jwt) with self.assertRaises(tink.TinkError): tink_verify.verify_and_decode(token, validator) with self.assertRaises(tink.TinkError): tink_verify.verify_and_decode(token_with_kid, validator) def test_legacy_template_fails(self): template = keyset_builder.legacy_template(jwt.jwt_es256_template()) builder = keyset_builder.new_keyset_builder() key_id = builder.add_new_key(template) builder.set_primary_key(key_id) handle = builder.keyset_handle() with self.assertRaises(tink.TinkError): handle.primitive(jwt.JwtPublicKeySign) with self.assertRaises(tink.TinkError): handle.public_keyset_handle().primitive(jwt.JwtPublicKeyVerify) def test_legacy_non_primary_key_fails(self): builder = keyset_builder.new_keyset_builder() old_template = keyset_builder.legacy_template(jwt.jwt_es256_template()) _ = builder.add_new_key(old_template) current_key_id = builder.add_new_key(jwt.jwt_es256_template()) builder.set_primary_key(current_key_id) handle = builder.keyset_handle() with self.assertRaises(tink.TinkError): handle.primitive(jwt.JwtPublicKeySign) with self.assertRaises(tink.TinkError): handle.public_keyset_handle().primitive(jwt.JwtPublicKeyVerify) def test_jwt_mac_from_keyset_without_primary_fails(self): builder = keyset_builder.new_keyset_builder() builder.add_new_key(jwt.jwt_es256_template()) with self.assertRaises(tink.TinkError): builder.keyset_handle()
class JwtSignatureWrapperTest(parameterized.TestCase): # TODO(juerg): Add tests with TINK templates def test_interesting_error(self): private_handle = tink.new_keyset_handle(jwt.jwt_es256_template()) sign = private_handle.primitive(jwt.JwtPublicKeySign) verify = private_handle.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) compact = sign.sign_and_encode(raw_jwt) with self.assertRaisesRegex(jwt.JwtInvalidError, 'invalid JWT; expected issuer'): verify.verify_and_decode( compact, jwt.new_validator(expected_issuer='unknown', allow_missing_expiration=True)) @parameterized.parameters([ (jwt.jwt_es256_template(), jwt.jwt_es256_template()), (jwt.jwt_es256_template(), jwt_es256_tink_template()), (jwt_es256_tink_template, jwt.jwt_es256_template()), (jwt_es256_tink_template(), jwt_es256_tink_template()), ]) def test_key_rotation(self, old_key_tmpl, new_key_tmpl): old_key_tmpl = jwt.jwt_es256_template() new_key_tmpl = jwt.jwt_es384_template() builder = keyset_builder.new_keyset_builder() older_key_id = builder.add_new_key(old_key_tmpl) builder.set_primary_key(older_key_id) handle1 = builder.keyset_handle() sign1 = handle1.primitive(jwt.JwtPublicKeySign) verify1 = handle1.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) newer_key_id = builder.add_new_key(new_key_tmpl) handle2 = builder.keyset_handle() sign2 = handle2.primitive(jwt.JwtPublicKeySign) verify2 = handle2.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) builder.set_primary_key(newer_key_id) handle3 = builder.keyset_handle() sign3 = handle3.primitive(jwt.JwtPublicKeySign) verify3 = handle3.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) builder.disable_key(older_key_id) handle4 = builder.keyset_handle() sign4 = handle4.primitive(jwt.JwtPublicKeySign) verify4 = handle4.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) raw_jwt = jwt.new_raw_jwt(issuer='a', without_expiration=True) validator = jwt.new_validator(expected_issuer='a', allow_missing_expiration=True) self.assertNotEqual(older_key_id, newer_key_id) # 1 uses the older key. So 1, 2 and 3 can verify the signature, but not 4. compact1 = sign1.sign_and_encode(raw_jwt) self.assertEqual( verify1.verify_and_decode(compact1, validator).issuer(), 'a') self.assertEqual( verify2.verify_and_decode(compact1, validator).issuer(), 'a') self.assertEqual( verify3.verify_and_decode(compact1, validator).issuer(), 'a') with self.assertRaises(tink.TinkError): verify4.verify_and_decode(compact1, validator) # 2 uses the older key. So 1, 2 and 3 can verify the signature, but not 4. compact2 = sign2.sign_and_encode(raw_jwt) self.assertEqual( verify1.verify_and_decode(compact2, validator).issuer(), 'a') self.assertEqual( verify2.verify_and_decode(compact2, validator).issuer(), 'a') self.assertEqual( verify3.verify_and_decode(compact2, validator).issuer(), 'a') with self.assertRaises(tink.TinkError): verify4.verify_and_decode(compact2, validator) # 3 uses the newer key. So 2, 3 and 4 can verify the signature, but not 1. compact3 = sign3.sign_and_encode(raw_jwt) with self.assertRaises(tink.TinkError): verify1.verify_and_decode(compact3, validator) self.assertEqual( verify2.verify_and_decode(compact3, validator).issuer(), 'a') self.assertEqual( verify3.verify_and_decode(compact3, validator).issuer(), 'a') self.assertEqual( verify4.verify_and_decode(compact3, validator).issuer(), 'a') # 4 uses the newer key. So 2, 3 and 4 can verify the signature, but not 1. compact4 = sign4.sign_and_encode(raw_jwt) with self.assertRaises(tink.TinkError): verify1.verify_and_decode(compact4, validator) self.assertEqual( verify2.verify_and_decode(compact4, validator).issuer(), 'a') self.assertEqual( verify3.verify_and_decode(compact4, validator).issuer(), 'a') self.assertEqual( verify4.verify_and_decode(compact4, validator).issuer(), 'a') def test_tink_output_prefix_type_encodes_a_kid_header(self): keyset_handle = tink.new_keyset_handle(jwt_es256_tink_template()) sign = keyset_handle.primitive(jwt.JwtPublicKeySign) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) signed_compact = sign.sign_and_encode(raw_jwt) _, json_header, _, _ = _jwt_format.split_signed_compact(signed_compact) header = _jwt_format.json_loads(json_header) self.assertIn('kid', header) def test_es256_key_with_custom_kid_header(self): keyset_handle = tink.new_keyset_handle(jwt.raw_jwt_es256_template()) # Add a custom kid to the key in keyset_handle value = keyset_handle._keyset.key[0].key_data.value ecdsa_key = jwt_ecdsa_pb2.JwtEcdsaPrivateKey.FromString(value) ecdsa_key.public_key.custom_kid.value = 'my kid' keyset_handle._keyset.key[ 0].key_data.value = ecdsa_key.SerializeToString() sign = keyset_handle.primitive(jwt.JwtPublicKeySign) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) signed_compact = sign.sign_and_encode(raw_jwt) _, json_header, _, _ = _jwt_format.split_signed_compact(signed_compact) header = _jwt_format.json_loads(json_header) self.assertEqual(header['kid'], 'my kid') # Now, change the output prefix type to TINK. This should fail. keyset_handle._keyset.key[0].output_prefix_type = tink_pb2.TINK with self.assertRaises(tink.TinkError): tink_sign = keyset_handle.primitive(jwt.JwtPublicKeySign) tink_sign.sign_and_encode(raw_jwt) def test_rs256_key_with_custom_kid_header(self): keyset_handle = tink.new_keyset_handle( jwt.raw_jwt_rs256_2048_f4_template()) # Add a custom kid to the key in keyset_handle value = keyset_handle._keyset.key[0].key_data.value pkcs1_key = jwt_rsa_ssa_pkcs1_pb2.JwtRsaSsaPkcs1PrivateKey.FromString( value) pkcs1_key.public_key.custom_kid.value = 'my kid' keyset_handle._keyset.key[ 0].key_data.value = pkcs1_key.SerializeToString() sign = keyset_handle.primitive(jwt.JwtPublicKeySign) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) signed_compact = sign.sign_and_encode(raw_jwt) _, json_header, _, _ = _jwt_format.split_signed_compact(signed_compact) header = _jwt_format.json_loads(json_header) self.assertEqual(header['kid'], 'my kid') # Now, change the output prefix type to TINK. This should fail. keyset_handle._keyset.key[0].output_prefix_type = tink_pb2.TINK with self.assertRaises(tink.TinkError): tink_sign = keyset_handle.primitive(jwt.JwtPublicKeySign) tink_sign.sign_and_encode(raw_jwt) def test_ps256_key_with_a_custom_kid_header(self): keyset_handle = tink.new_keyset_handle( jwt.raw_jwt_ps256_2048_f4_template()) # Add a custom kid to the key in keyset_handle value = keyset_handle._keyset.key[0].key_data.value pss_key = jwt_rsa_ssa_pss_pb2.JwtRsaSsaPssPrivateKey.FromString(value) pss_key.public_key.custom_kid.value = 'my kid' keyset_handle._keyset.key[ 0].key_data.value = pss_key.SerializeToString() sign = keyset_handle.primitive(jwt.JwtPublicKeySign) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) signed_compact = sign.sign_and_encode(raw_jwt) _, json_header, _, _ = _jwt_format.split_signed_compact(signed_compact) header = _jwt_format.json_loads(json_header) self.assertEqual(header['kid'], 'my kid') # Now, change the output prefix type to TINK. This should fail. keyset_handle._keyset.key[0].output_prefix_type = tink_pb2.TINK with self.assertRaises(tink.TinkError): tink_sign = keyset_handle.primitive(jwt.JwtPublicKeySign) tink_sign.sign_and_encode(raw_jwt) def test_legacy_template_fails(self): template = _create_jwt_ecdsa_template(jwt_ecdsa_pb2.ES256, tink_pb2.LEGACY) builder = keyset_builder.new_keyset_builder() key_id = builder.add_new_key(template) builder.set_primary_key(key_id) handle = builder.keyset_handle() with self.assertRaises(tink.TinkError): handle.primitive(jwt.JwtPublicKeySign) with self.assertRaises(tink.TinkError): handle.public_keyset_handle().primitive(jwt.JwtPublicKeyVerify) def test_legacy_non_primary_key_fails(self): builder = keyset_builder.new_keyset_builder() old_template = _create_jwt_ecdsa_template(jwt_ecdsa_pb2.ES256, tink_pb2.LEGACY) _ = builder.add_new_key(old_template) current_key_id = builder.add_new_key(jwt.jwt_es256_template()) builder.set_primary_key(current_key_id) handle = builder.keyset_handle() with self.assertRaises(tink.TinkError): handle.primitive(jwt.JwtPublicKeySign) with self.assertRaises(tink.TinkError): handle.public_keyset_handle().primitive(jwt.JwtPublicKeyVerify)
def test_key_rotation(self, old_key_tmpl, new_key_tmpl): old_key_tmpl = jwt.jwt_es256_template() new_key_tmpl = jwt.jwt_es384_template() builder = keyset_builder.new_keyset_builder() older_key_id = builder.add_new_key(old_key_tmpl) builder.set_primary_key(older_key_id) handle1 = builder.keyset_handle() sign1 = handle1.primitive(jwt.JwtPublicKeySign) verify1 = handle1.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) newer_key_id = builder.add_new_key(new_key_tmpl) handle2 = builder.keyset_handle() sign2 = handle2.primitive(jwt.JwtPublicKeySign) verify2 = handle2.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) builder.set_primary_key(newer_key_id) handle3 = builder.keyset_handle() sign3 = handle3.primitive(jwt.JwtPublicKeySign) verify3 = handle3.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) builder.disable_key(older_key_id) handle4 = builder.keyset_handle() sign4 = handle4.primitive(jwt.JwtPublicKeySign) verify4 = handle4.public_keyset_handle().primitive( jwt.JwtPublicKeyVerify) raw_jwt = jwt.new_raw_jwt(issuer='a', without_expiration=True) validator = jwt.new_validator(expected_issuer='a', allow_missing_expiration=True) self.assertNotEqual(older_key_id, newer_key_id) # 1 uses the older key. So 1, 2 and 3 can verify the signature, but not 4. compact1 = sign1.sign_and_encode(raw_jwt) self.assertEqual( verify1.verify_and_decode(compact1, validator).issuer(), 'a') self.assertEqual( verify2.verify_and_decode(compact1, validator).issuer(), 'a') self.assertEqual( verify3.verify_and_decode(compact1, validator).issuer(), 'a') with self.assertRaises(tink.TinkError): verify4.verify_and_decode(compact1, validator) # 2 uses the older key. So 1, 2 and 3 can verify the signature, but not 4. compact2 = sign2.sign_and_encode(raw_jwt) self.assertEqual( verify1.verify_and_decode(compact2, validator).issuer(), 'a') self.assertEqual( verify2.verify_and_decode(compact2, validator).issuer(), 'a') self.assertEqual( verify3.verify_and_decode(compact2, validator).issuer(), 'a') with self.assertRaises(tink.TinkError): verify4.verify_and_decode(compact2, validator) # 3 uses the newer key. So 2, 3 and 4 can verify the signature, but not 1. compact3 = sign3.sign_and_encode(raw_jwt) with self.assertRaises(tink.TinkError): verify1.verify_and_decode(compact3, validator) self.assertEqual( verify2.verify_and_decode(compact3, validator).issuer(), 'a') self.assertEqual( verify3.verify_and_decode(compact3, validator).issuer(), 'a') self.assertEqual( verify4.verify_and_decode(compact3, validator).issuer(), 'a') # 4 uses the newer key. So 2, 3 and 4 can verify the signature, but not 1. compact4 = sign4.sign_and_encode(raw_jwt) with self.assertRaises(tink.TinkError): verify1.verify_and_decode(compact4, validator) self.assertEqual( verify2.verify_and_decode(compact4, validator).issuer(), 'a') self.assertEqual( verify3.verify_and_decode(compact4, validator).issuer(), 'a') self.assertEqual( verify4.verify_and_decode(compact4, validator).issuer(), 'a')