1# Copyright 2020 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"""Tests that keys with higher version numbers are rejected.""" 15 16from typing import Iterable 17 18from absl.testing import absltest 19from absl.testing import parameterized 20 21import tink 22from tink import aead 23from tink import daead 24from tink import mac 25from tink import prf 26 27from tink.proto import aes_cmac_pb2 28from tink.proto import aes_cmac_prf_pb2 29from tink.proto import aes_ctr_hmac_aead_pb2 30from tink.proto import aes_eax_pb2 31from tink.proto import aes_gcm_pb2 32from tink.proto import aes_gcm_siv_pb2 33from tink.proto import aes_siv_pb2 34from tink.proto import chacha20_poly1305_pb2 35from tink.proto import hkdf_prf_pb2 36from tink.proto import hmac_pb2 37from tink.proto import hmac_prf_pb2 38from tink.proto import kms_aead_pb2 39from tink.proto import kms_envelope_pb2 40from tink.proto import tink_pb2 41from tink.proto import xchacha20_poly1305_pb2 42 43import tink_config 44from util import testing_servers 45from util import utilities 46 47 48KEY_TYPE_TO_PROTO_CLASS = { 49 'AesEaxKey': aes_eax_pb2.AesEaxKey, 50 'AesGcmKey': aes_gcm_pb2.AesGcmKey, 51 'AesGcmSivKey': aes_gcm_siv_pb2.AesGcmSivKey, 52 'AesCtrHmacAeadKey': aes_ctr_hmac_aead_pb2.AesCtrHmacAeadKey, 53 'ChaCha20Poly1305Key': chacha20_poly1305_pb2.ChaCha20Poly1305Key, 54 'XChaCha20Poly1305Key': xchacha20_poly1305_pb2.XChaCha20Poly1305Key, 55 'KmsAeadKey': kms_aead_pb2.KmsAeadKey, 56 'KmsEnvelopeAeadKey': kms_envelope_pb2.KmsEnvelopeAeadKey, 57 'AesCmacKey': aes_cmac_pb2.AesCmacKey, 58 'HmacKey': hmac_pb2.HmacKey, 59 'AesCmacPrfKey': aes_cmac_prf_pb2.AesCmacPrfKey, 60 'HmacPrfKey': hmac_prf_pb2.HmacPrfKey, 61 'HkdfPrfKey': hkdf_prf_pb2.HkdfPrfKey, 62 'AesSivKey': aes_siv_pb2.AesSivKey, 63} 64 65 66def gen_inc_versions(keyset): 67 """Parses keyset and generates modified keyset with incremented version.""" 68 keyset_proto = tink_pb2.Keyset.FromString(keyset) 69 for key in keyset_proto.key: 70 key_type = tink_config.key_type_from_type_url(key.key_data.type_url) 71 key_class = KEY_TYPE_TO_PROTO_CLASS[key_type] 72 73 default_val = key.key_data.value 74 75 key_proto = key_class.FromString(default_val) 76 key_proto.version = key_proto.version + 1 77 key.key_data.value = key_proto.SerializeToString() 78 yield keyset_proto.SerializeToString() 79 80 if key_type == 'AesCtrHmacAeadKey': 81 key_proto1 = aes_ctr_hmac_aead_pb2.AesCtrHmacAeadKey.FromString( 82 default_val) 83 key_proto1.aes_ctr_key.version = key_proto1.aes_ctr_key.version + 1 84 key.key_data.value = key_proto1.SerializeToString() 85 yield keyset_proto.SerializeToString() 86 87 key_proto2 = aes_ctr_hmac_aead_pb2.AesCtrHmacAeadKey.FromString( 88 default_val) 89 key_proto2.hmac_key.version = key_proto2.hmac_key.version + 1 90 key.key_data.value = key_proto2.SerializeToString() 91 yield keyset_proto.SerializeToString() 92 93 key.key_data.value = default_val 94 95 96def test_cases(key_types: Iterable[str]): 97 for key_type in key_types: 98 for key_template_name in utilities.KEY_TEMPLATE_NAMES[key_type]: 99 for lang in tink_config.supported_languages_for_key_type(key_type): 100 yield (key_template_name, lang) 101 102 103def setUpModule(): 104 aead.register() 105 mac.register() 106 daead.register() 107 prf.register() 108 testing_servers.start('key_version') 109 110 111def tearDownModule(): 112 testing_servers.stop() 113 114 115class KeyVersionTest(parameterized.TestCase): 116 """These tests verify that keys with an unknown version are rejected. 117 118 The tests first try out the unmodified key to make sure that it works. This is 119 done to make sure that the failure of the modified key is really due to the 120 incremented version. 121 """ 122 123 @parameterized.parameters( 124 test_cases(tink_config.key_types_for_primitive(aead.Aead))) 125 def test_inc_version_aead(self, key_template_name, lang): 126 """Increments the key version by one and checks they can't be used.""" 127 template = utilities.KEY_TEMPLATE[key_template_name] 128 keyset = testing_servers.new_keyset(lang, template) 129 _ = testing_servers.remote_primitive(lang, keyset, 130 aead.Aead).encrypt(b'foo', b'bar') 131 for keyset1 in gen_inc_versions(keyset): 132 with self.assertRaises(tink.TinkError): 133 _ = testing_servers.remote_primitive(lang, keyset1, aead.Aead) 134 135 @parameterized.parameters( 136 test_cases(tink_config.key_types_for_primitive(daead.DeterministicAead))) 137 def test_inc_version_daead(self, key_template_name, lang): 138 """Increments the key version by one and checks they can't be used.""" 139 template = utilities.KEY_TEMPLATE[key_template_name] 140 keyset = testing_servers.new_keyset(lang, template) 141 p = testing_servers.remote_primitive(lang, keyset, daead.DeterministicAead) 142 _ = p.encrypt_deterministically(b'foo', b'bar') 143 for keyset1 in gen_inc_versions(keyset): 144 with self.assertRaises(tink.TinkError): 145 _ = testing_servers.remote_primitive(lang, keyset1, 146 daead.DeterministicAead) 147 148 @parameterized.parameters( 149 test_cases(tink_config.key_types_for_primitive(mac.Mac))) 150 def test_inc_version_mac(self, key_template_name, lang): 151 """Increments the key version by one and checks they can't be used.""" 152 template = utilities.KEY_TEMPLATE[key_template_name] 153 keyset = testing_servers.new_keyset(lang, template) 154 _ = testing_servers.remote_primitive(lang, keyset, mac.Mac) 155 for keyset1 in gen_inc_versions(keyset): 156 with self.assertRaises(tink.TinkError): 157 _ = testing_servers.remote_primitive(lang, keyset1, mac.Mac) 158 159 @parameterized.parameters( 160 test_cases(tink_config.key_types_for_primitive(prf.PrfSet))) 161 def test_inc_version_prf(self, key_template_name, lang): 162 """Increments the key version by one and checks they can't be used.""" 163 template = utilities.KEY_TEMPLATE[key_template_name] 164 keyset = testing_servers.new_keyset(lang, template) 165 prf_set = testing_servers.remote_primitive(lang, keyset, prf.PrfSet) 166 _ = prf_set.primary().compute(b'foo', 16) 167 for keyset1 in gen_inc_versions(keyset): 168 with self.assertRaises(tink.TinkError): 169 _ = testing_servers.remote_primitive(lang, keyset1, prf.PrfSet) 170 171 172if __name__ == '__main__': 173 absltest.main() 174