xref: /aosp_15_r20/external/tink/testing/cross_language/key_version_test.py (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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