def test_only_tink_output_prefix_type_encodes_a_kid_header(self): handle = tink.new_keyset_handle(jwt.raw_jwt_hs256_template()) jwt_mac = handle.primitive(jwt.JwtMac) tink_handle = _change_output_prefix_to_tink(handle) tink_jwt_mac = tink_handle.primitive(jwt.JwtMac) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) token = jwt_mac.compute_mac_and_encode(raw_jwt) token_with_kid = tink_jwt_mac.compute_mac_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) jwt_mac.verify_mac_and_decode(token, validator) tink_jwt_mac.verify_mac_and_decode(token_with_kid, validator) # With output prefix type RAW, a kid header is ignored jwt_mac.verify_mac_and_decode(token_with_kid, validator) # With output prefix type TINK, a kid header is required. with self.assertRaises(tink.TinkError): tink_jwt_mac.verify_mac_and_decode(token, validator) other_handle = _change_key_id(tink_handle) other_jwt_mac = other_handle.primitive(jwt.JwtMac) # A token with a wrong kid is rejected, even if the signature is ok. with self.assertRaises(tink.TinkError): other_jwt_mac.verify_mac_and_decode(token_with_kid, validator)
def test_legacy_key_fails(self): template = keyset_builder.legacy_template(jwt.raw_jwt_hs256_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.JwtMac)
def test_raw_output_prefix_type_encodes_a_custom_kid_header(self): # normal HMAC jwt_mac with output prefix RAW handle = tink.new_keyset_handle(jwt.raw_jwt_hs256_template()) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) validator = jwt.new_validator(expected_issuer='issuer', allow_missing_expiration=True) jwt_mac = handle.primitive(jwt.JwtMac) token = jwt_mac.compute_mac_and_encode(raw_jwt) jwt_mac.verify_mac_and_decode(token, validator) _, json_header, _, _ = _jwt_format.split_signed_compact(token) self.assertNotIn('kid', _json_util.json_loads(json_header)) # HMAC jwt_mac with a custom_kid set custom_kid_handle = _set_custom_kid(handle, custom_kid='my kid') custom_kid_jwt_mac = custom_kid_handle.primitive(jwt.JwtMac) token_with_kid = custom_kid_jwt_mac.compute_mac_and_encode(raw_jwt) custom_kid_jwt_mac.verify_mac_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'], 'my kid') # Even when custom_kid is set, its not required to be set in the header. custom_kid_jwt_mac.verify_mac_and_decode(token, validator) # An additional kid header is ignored. jwt_mac.verify_mac_and_decode(token_with_kid, validator) other_handle = _set_custom_kid(handle, custom_kid='other kid') other_jwt_mac = other_handle.primitive(jwt.JwtMac) with self.assertRaises(tink.TinkError): # The custom_kid does not match the kid header. other_jwt_mac.verify_mac_and_decode(token_with_kid, validator) tink_handle = _change_output_prefix_to_tink(custom_kid_handle) tink_jwt_mac = tink_handle.primitive(jwt.JwtMac) # having custom_kid set with output prefix TINK is not allowed with self.assertRaises(tink.TinkError): tink_jwt_mac.compute_mac_and_encode(raw_jwt) with self.assertRaises(tink.TinkError): tink_jwt_mac.verify_mac_and_decode(token, validator) with self.assertRaises(tink.TinkError): tink_jwt_mac.verify_mac_and_decode(token_with_kid, validator)
def test_raw_output_prefix_type_encodes_a_custom_kid_header(self): keyset_handle = tink.new_keyset_handle(jwt.raw_jwt_hs256_template()) # Add a custom kid to the key in keyset_handle value = keyset_handle._keyset.key[0].key_data.value hmac_key = jwt_hmac_pb2.JwtHmacKey.FromString(value) hmac_key.custom_kid.value = 'my kid' keyset_handle._keyset.key[ 0].key_data.value = hmac_key.SerializeToString() jwt_mac = keyset_handle.primitive(jwt.JwtMac) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) signed_compact = jwt_mac.compute_mac_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_jwt_mac = keyset_handle.primitive(jwt.JwtMac) tink_jwt_mac.compute_mac_and_encode(raw_jwt)
'RSA_SSA_PKCS1_4096_SHA512_F4': signature.signature_key_templates.RSA_SSA_PKCS1_4096_SHA512_F4, 'RSA_SSA_PSS_3072_SHA256_SHA256_32_F4': signature.signature_key_templates.RSA_SSA_PSS_3072_SHA256_SHA256_32_F4, 'RSA_SSA_PSS_4096_SHA512_SHA512_64_F4': 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(),
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')
'RSA_SSA_PSS_3072_SHA256_SHA256_32_F4': signature.signature_key_templates.RSA_SSA_PSS_3072_SHA256_SHA256_32_F4, 'RSA_SSA_PSS_4096_SHA512_SHA512_64_F4': signature.signature_key_templates.RSA_SSA_PSS_4096_SHA512_SHA512_64_F4, 'AES_CMAC_PRF': prf.prf_key_templates.AES_CMAC, 'HMAC_SHA256_PRF': prf.prf_key_templates.HMAC_SHA256, 'HMAC_SHA512_PRF': prf.prf_key_templates.HMAC_SHA512, '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':
class JwtHmacKeyManagerTest(parameterized.TestCase): def test_basic(self): key_manager = _jwt_hmac_key_manager.MacCcToPyJwtMacKeyManager() self.assertEqual(key_manager.primitive_class(), _jwt_mac.JwtMacInternal) self.assertEqual(key_manager.key_type(), 'type.googleapis.com/google.crypto.tink.JwtHmacKey') @parameterized.named_parameters([ ('JWT_HS256', jwt.raw_jwt_hs256_template()), ('JWT_HS384', jwt.raw_jwt_hs384_template()), ('JWT_HS512', jwt.raw_jwt_hs512_template()), ]) def test_new_keydata_primitive_success(self, template): key_manager = _jwt_hmac_key_manager.MacCcToPyJwtMacKeyManager() key_data = key_manager.new_key_data(template) jwt_hmac = key_manager.primitive(key_data) raw_jwt = jwt.new_raw_jwt( type_header='typeHeader', issuer='issuer', without_expiration=True) validator = jwt.new_validator( expected_type_header='typeHeader', expected_issuer='issuer', allow_missing_expiration=True, fixed_now=DATETIME_1970) token_with_kid = jwt_hmac.compute_mac_and_encode_with_kid( raw_jwt, kid='kid-123') token_without_kid = jwt_hmac.compute_mac_and_encode_with_kid( raw_jwt, kid=None) # Verification of a token with a kid only fails if the wrong kid is passed. verified_jwt = jwt_hmac.verify_mac_and_decode_with_kid( token_with_kid, validator, kid='kid-123') self.assertEqual(verified_jwt.type_header(), 'typeHeader') self.assertEqual(verified_jwt.issuer(), 'issuer') jwt_hmac.verify_mac_and_decode_with_kid(token_with_kid, validator, kid=None) with self.assertRaises(tink.TinkError): jwt_hmac.verify_mac_and_decode_with_kid( token_with_kid, validator, kid='other-kid') # A token without kid is only valid if no kid is passed. jwt_hmac.verify_mac_and_decode_with_kid( token_without_kid, validator, kid=None) with self.assertRaises(tink.TinkError): jwt_hmac.verify_mac_and_decode_with_kid( token_without_kid, validator, kid='kid-123') def test_fixed_signed_compact(self): signed_compact = ( 'eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleH' 'AiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.' 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk') jwt_hmac = create_fixed_jwt_hmac() verified_jwt = jwt_hmac.verify_mac_and_decode_with_kid( signed_compact, jwt.new_validator( expected_type_header='JWT', expected_issuer='joe', fixed_now=DATETIME_1970), kid=None) 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')) self.assertTrue(verified_jwt.type_header(), 'JWT') # fails because it is expired with self.assertRaises(tink.TinkError): jwt_hmac.verify_mac_and_decode_with_kid( signed_compact, jwt.new_validator(fixed_now=DATETIME_2020), kid=None) # fails with wrong issuer with self.assertRaises(tink.TinkError): jwt_hmac.verify_mac_and_decode_with_kid( signed_compact, jwt.new_validator(expected_issuer='jane', fixed_now=DATETIME_1970), kid=None) def test_weird_tokens_with_valid_macs(self): jwt_hmac = create_fixed_jwt_hmac() validator = jwt.new_validator( expected_issuer='joe', allow_missing_expiration=True) cc_mac = _cc_mac() # Normal token. valid_token = gen_token('{"alg":"HS256"}', '{"iss":"joe"}') verified = jwt_hmac.verify_mac_and_decode_with_kid( valid_token, validator, kid=None) self.assertEqual(verified.issuer(), 'joe') # Token with unknown header is valid. token_with_unknown_header = gen_token( '{"unknown_header":"123","alg":"HS256"}', '{"iss":"joe"}') verified2 = jwt_hmac.verify_mac_and_decode_with_kid( token_with_unknown_header, validator, kid=None) self.assertEqual(verified2.issuer(), 'joe') # Token with unknown kid is valid, since primitives with output prefix type # RAW ignore kid headers. token_with_unknown_kid = gen_token('{"kid":"unknown","alg":"HS256"}', '{"iss":"joe"}') verified2 = jwt_hmac.verify_mac_and_decode_with_kid( token_with_unknown_kid, validator, kid=None) self.assertEqual(verified2.issuer(), 'joe') # Token with invalid alg header alg_invalid = gen_token('{"alg":"HS384"}', '{"iss":"joe"}') with self.assertRaises(tink.TinkError): jwt_hmac.verify_mac_and_decode_with_kid(alg_invalid, validator, kid=None) # Token with empty header empty_header = gen_token('{}', '{"iss":"joe"}') with self.assertRaises(tink.TinkError): jwt_hmac.verify_mac_and_decode_with_kid(empty_header, validator, kid=None) # Token header is not valid JSON header_invalid = gen_token('{"alg":"HS256"', '{"iss":"joe"}') with self.assertRaises(tink.TinkError): jwt_hmac.verify_mac_and_decode_with_kid( header_invalid, validator, kid=None) # Token payload is not valid JSON payload_invalid = gen_token('{"alg":"HS256"}', '{"iss":"joe"') with self.assertRaises(tink.TinkError): jwt_hmac.verify_mac_and_decode_with_kid( payload_invalid, validator, kid=None) # Token with whitespace in header JSON string is valid. whitespace_in_header = gen_token(' {"alg": \n "HS256"} \n ', '{"iss":"joe" }') verified_jwt = jwt_hmac.verify_mac_and_decode_with_kid( whitespace_in_header, validator, kid=None) self.assertEqual(verified_jwt.issuer(), 'joe') # Token with whitespace in payload JSON string is valid. whitespace_in_payload = gen_token('{"alg":"HS256"}', ' {"iss": \n"joe" } \n') verified_jwt = jwt_hmac.verify_mac_and_decode_with_kid( whitespace_in_payload, validator, kid=None) self.assertEqual(verified_jwt.issuer(), 'joe') # Token with whitespace in base64-encoded header is invalid. with_whitespace_in_encoding = ( _jwt_format.encode_header('{"alg":"HS256"}') + b' .' + _jwt_format.encode_payload('{"iss":"joe"}')) token_with_whitespace_in_encoding = _jwt_format.create_signed_compact( with_whitespace_in_encoding, cc_mac.compute_mac(with_whitespace_in_encoding)) with self.assertRaises(tink.TinkError): jwt_hmac.verify_mac_and_decode_with_kid( token_with_whitespace_in_encoding, validator, kid=None) # Token with invalid character is invalid. with_invalid_char = ( _jwt_format.encode_header('{"alg":"HS256"}') + b'.?' + _jwt_format.encode_payload('{"iss":"joe"}')) token_with_invalid_char = _jwt_format.create_signed_compact( with_invalid_char, cc_mac.compute_mac(with_invalid_char)) with self.assertRaises(tink.TinkError): jwt_hmac.verify_mac_and_decode_with_kid( token_with_invalid_char, validator, kid=None) # Token with additional '.' is invalid. with_dot = ( _jwt_format.encode_header('{"alg":"HS256"}') + b'.' + _jwt_format.encode_payload('{"iss":"joe"}') + b'.') token_with_dot = _jwt_format.create_signed_compact( with_dot, cc_mac.compute_mac(with_dot)) with self.assertRaises(tink.TinkError): jwt_hmac.verify_mac_and_decode_with_kid( token_with_dot, validator, kid=None) # num_recursions has been chosen such that parsing of this token fails # in all languages. We want to make sure that the algorithm does not # hang or crash in this case, but only returns a parsing error. num_recursions = 10000 rec_payload = ('{"a":' * num_recursions) + '""' + ('}' * num_recursions) rec_token = gen_token('{"alg":"HS256"}', rec_payload) with self.assertRaises(tink.TinkError): jwt_hmac.verify_mac_and_decode_with_kid( rec_token, validator=jwt.new_validator(allow_missing_expiration=True), kid=None) # test wrong types with self.assertRaises(tink.TinkError): jwt_hmac.verify_mac_and_decode_with_kid( cast(str, None), validator, kid=None) with self.assertRaises(tink.TinkError): jwt_hmac.verify_mac_and_decode_with_kid( cast(str, 123), validator, kid=None) with self.assertRaises(tink.TinkError): valid_token_bytes = valid_token.encode('utf8') jwt_hmac.verify_mac_and_decode_with_kid( cast(str, valid_token_bytes), validator, kid=None) @parameterized.named_parameters([ ('modified_signature', ('eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleH' 'AiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.' 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXi')), ('modified_payload', ('eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLCJleHAiOj' 'EzMDA4MTkzODEsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.' 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk')), ('modified_header', ('eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleH' 'AiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.' 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk')), ('extra .', 'eyJhbGciOiJIUzI1NiJ9.e30.abc.'), ('invalid_header_encoding', 'eyJhbGciOiJIUzI1NiJ9?.e30.abc'), ('invalid_payload_encoding', 'eyJhbGciOiJIUzI1NiJ9.e30?.abc'), ('invalid_mac_encoding', 'eyJhbGciOiJIUzI1NiJ9.e30.abc?'), ('no_mac', 'eyJhbGciOiJIUzI1NiJ9.e30'), ]) def test_invalid_signed_compact(self, invalid_signed_compact): jwt_hmac = create_fixed_jwt_hmac() validator = jwt.new_validator( expected_issuer='joe', allow_missing_expiration=True, fixed_now=DATETIME_1970) with self.assertRaises(tink.TinkError): jwt_hmac.verify_mac_and_decode_with_kid( invalid_signed_compact, validator, kid=None)
class JwtMacWrapperTest(parameterized.TestCase): @parameterized.parameters([ (jwt.raw_jwt_hs256_template(), jwt.raw_jwt_hs256_template()), (jwt.raw_jwt_hs256_template(), jwt.jwt_hs256_template()), (jwt.jwt_hs256_template(), jwt.raw_jwt_hs256_template()), (jwt.jwt_hs256_template(), jwt.jwt_hs256_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) jwtmac1 = builder.keyset_handle().primitive(jwt.JwtMac) newer_key_id = builder.add_new_key(new_key_tmpl) jwtmac2 = builder.keyset_handle().primitive(jwt.JwtMac) builder.set_primary_key(newer_key_id) jwtmac3 = builder.keyset_handle().primitive(jwt.JwtMac) builder.disable_key(older_key_id) jwtmac4 = builder.keyset_handle().primitive(jwt.JwtMac) 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 mac, but not 4. compact1 = jwtmac1.compute_mac_and_encode(raw_jwt) self.assertEqual( jwtmac1.verify_mac_and_decode(compact1, validator).issuer(), 'a') self.assertEqual( jwtmac2.verify_mac_and_decode(compact1, validator).issuer(), 'a') self.assertEqual( jwtmac3.verify_mac_and_decode(compact1, validator).issuer(), 'a') with self.assertRaises(tink.TinkError): jwtmac4.verify_mac_and_decode(compact1, validator) # 2 uses the older key. So 1, 2 and 3 can verify the mac, but not 4. compact2 = jwtmac2.compute_mac_and_encode(raw_jwt) self.assertEqual( jwtmac1.verify_mac_and_decode(compact2, validator).issuer(), 'a') self.assertEqual( jwtmac2.verify_mac_and_decode(compact2, validator).issuer(), 'a') self.assertEqual( jwtmac3.verify_mac_and_decode(compact2, validator).issuer(), 'a') with self.assertRaises(tink.TinkError): jwtmac4.verify_mac_and_decode(compact2, validator) # 3 uses the newer key. So 2, 3 and 4 can verify the mac, but not 1. compact3 = jwtmac3.compute_mac_and_encode(raw_jwt) with self.assertRaises(tink.TinkError): jwtmac1.verify_mac_and_decode(compact3, validator) self.assertEqual( jwtmac2.verify_mac_and_decode(compact3, validator).issuer(), 'a') self.assertEqual( jwtmac3.verify_mac_and_decode(compact3, validator).issuer(), 'a') self.assertEqual( jwtmac4.verify_mac_and_decode(compact3, validator).issuer(), 'a') # 4 uses the newer key. So 2, 3 and 4 can verify the mac, but not 1. compact4 = jwtmac4.compute_mac_and_encode(raw_jwt) with self.assertRaises(tink.TinkError): jwtmac1.verify_mac_and_decode(compact4, validator) self.assertEqual( jwtmac2.verify_mac_and_decode(compact4, validator).issuer(), 'a') self.assertEqual( jwtmac3.verify_mac_and_decode(compact4, validator).issuer(), 'a') self.assertEqual( jwtmac4.verify_mac_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_hs256_template()) jwt_mac = handle.primitive(jwt.JwtMac) tink_handle = _change_output_prefix_to_tink(handle) tink_jwt_mac = tink_handle.primitive(jwt.JwtMac) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) token = jwt_mac.compute_mac_and_encode(raw_jwt) token_with_kid = tink_jwt_mac.compute_mac_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) jwt_mac.verify_mac_and_decode(token, validator) tink_jwt_mac.verify_mac_and_decode(token_with_kid, validator) # With output prefix type RAW, a kid header is ignored jwt_mac.verify_mac_and_decode(token_with_kid, validator) # With output prefix type TINK, a kid header is required. with self.assertRaises(tink.TinkError): tink_jwt_mac.verify_mac_and_decode(token, validator) other_handle = _change_key_id(tink_handle) other_jwt_mac = other_handle.primitive(jwt.JwtMac) # A token with a wrong kid is rejected, even if the signature is ok. with self.assertRaises(tink.TinkError): other_jwt_mac.verify_mac_and_decode(token_with_kid, validator) def test_raw_output_prefix_type_encodes_a_custom_kid_header(self): # normal HMAC jwt_mac with output prefix RAW handle = tink.new_keyset_handle(jwt.raw_jwt_hs256_template()) raw_jwt = jwt.new_raw_jwt(issuer='issuer', without_expiration=True) validator = jwt.new_validator(expected_issuer='issuer', allow_missing_expiration=True) jwt_mac = handle.primitive(jwt.JwtMac) token = jwt_mac.compute_mac_and_encode(raw_jwt) jwt_mac.verify_mac_and_decode(token, validator) _, json_header, _, _ = _jwt_format.split_signed_compact(token) self.assertNotIn('kid', _json_util.json_loads(json_header)) # HMAC jwt_mac with a custom_kid set custom_kid_handle = _set_custom_kid(handle, custom_kid='my kid') custom_kid_jwt_mac = custom_kid_handle.primitive(jwt.JwtMac) token_with_kid = custom_kid_jwt_mac.compute_mac_and_encode(raw_jwt) custom_kid_jwt_mac.verify_mac_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'], 'my kid') # Even when custom_kid is set, its not required to be set in the header. custom_kid_jwt_mac.verify_mac_and_decode(token, validator) # An additional kid header is ignored. jwt_mac.verify_mac_and_decode(token_with_kid, validator) other_handle = _set_custom_kid(handle, custom_kid='other kid') other_jwt_mac = other_handle.primitive(jwt.JwtMac) with self.assertRaises(tink.TinkError): # The custom_kid does not match the kid header. other_jwt_mac.verify_mac_and_decode(token_with_kid, validator) tink_handle = _change_output_prefix_to_tink(custom_kid_handle) tink_jwt_mac = tink_handle.primitive(jwt.JwtMac) # having custom_kid set with output prefix TINK is not allowed with self.assertRaises(tink.TinkError): tink_jwt_mac.compute_mac_and_encode(raw_jwt) with self.assertRaises(tink.TinkError): tink_jwt_mac.verify_mac_and_decode(token, validator) with self.assertRaises(tink.TinkError): tink_jwt_mac.verify_mac_and_decode(token_with_kid, validator) def test_legacy_key_fails(self): template = keyset_builder.legacy_template(jwt.raw_jwt_hs256_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.JwtMac) def test_legacy_non_primary_key_fails(self): builder = keyset_builder.new_keyset_builder() old_template = keyset_builder.legacy_template( jwt.raw_jwt_hs256_template()) _ = builder.add_new_key(old_template) current_key_id = builder.add_new_key(jwt.jwt_hs256_template()) builder.set_primary_key(current_key_id) handle = builder.keyset_handle() with self.assertRaises(tink.TinkError): handle.primitive(jwt.JwtMac) def test_jwt_mac_from_keyset_without_primary_fails(self): builder = keyset_builder.new_keyset_builder() builder.add_new_key(jwt.raw_jwt_hs256_template()) with self.assertRaises(tink.TinkError): builder.keyset_handle()
def test_jwt_mac_from_keyset_without_primary_fails(self): builder = keyset_builder.new_keyset_builder() builder.add_new_key(jwt.raw_jwt_hs256_template()) with self.assertRaises(tink.TinkError): builder.keyset_handle()