xref: /aosp_15_r20/external/tink/testing/cross_language/signature_test.py (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1*e7b1675dSTing-Kang Chang# Copyright 2020 Google LLC
2*e7b1675dSTing-Kang Chang#
3*e7b1675dSTing-Kang Chang# Licensed under the Apache License, Version 2.0 (the "License");
4*e7b1675dSTing-Kang Chang# you may not use this file except in compliance with the License.
5*e7b1675dSTing-Kang Chang# You may obtain a copy of the License at
6*e7b1675dSTing-Kang Chang#
7*e7b1675dSTing-Kang Chang#      http://www.apache.org/licenses/LICENSE-2.0
8*e7b1675dSTing-Kang Chang#
9*e7b1675dSTing-Kang Chang# Unless required by applicable law or agreed to in writing, software
10*e7b1675dSTing-Kang Chang# distributed under the License is distributed on an "AS IS" BASIS,
11*e7b1675dSTing-Kang Chang# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e7b1675dSTing-Kang Chang# See the License for the specific language governing permissions and
13*e7b1675dSTing-Kang Chang# limitations under the License.
14*e7b1675dSTing-Kang Chang"""Cross-language tests for Public-Key Signatures."""
15*e7b1675dSTing-Kang Chang
16*e7b1675dSTing-Kang Changfrom typing import Iterable, Tuple
17*e7b1675dSTing-Kang Chang
18*e7b1675dSTing-Kang Changfrom absl.testing import absltest
19*e7b1675dSTing-Kang Changfrom absl.testing import parameterized
20*e7b1675dSTing-Kang Chang
21*e7b1675dSTing-Kang Changimport tink
22*e7b1675dSTing-Kang Changfrom tink import signature
23*e7b1675dSTing-Kang Chang
24*e7b1675dSTing-Kang Changfrom tink.proto import tink_pb2
25*e7b1675dSTing-Kang Changfrom tink.testing import keyset_builder
26*e7b1675dSTing-Kang Changfrom util import testing_servers
27*e7b1675dSTing-Kang Changfrom util import utilities
28*e7b1675dSTing-Kang Chang
29*e7b1675dSTing-Kang ChangSUPPORTED_LANGUAGES = (testing_servers
30*e7b1675dSTing-Kang Chang                       .SUPPORTED_LANGUAGES_BY_PRIMITIVE['signature'])
31*e7b1675dSTing-Kang Chang
32*e7b1675dSTing-Kang Chang
33*e7b1675dSTing-Kang Changdef setUpModule():
34*e7b1675dSTing-Kang Chang  signature.register()
35*e7b1675dSTing-Kang Chang  testing_servers.start('signature')
36*e7b1675dSTing-Kang Chang
37*e7b1675dSTing-Kang Chang
38*e7b1675dSTing-Kang Changdef tearDownModule():
39*e7b1675dSTing-Kang Chang  testing_servers.stop()
40*e7b1675dSTing-Kang Chang
41*e7b1675dSTing-Kang Chang
42*e7b1675dSTing-Kang Changclass SignatureTest(parameterized.TestCase):
43*e7b1675dSTing-Kang Chang
44*e7b1675dSTing-Kang Chang  @parameterized.parameters(
45*e7b1675dSTing-Kang Chang      utilities.tinkey_template_names_for(signature.PublicKeySign))
46*e7b1675dSTing-Kang Chang  def test_sign_verify(self, key_template_name):
47*e7b1675dSTing-Kang Chang    supported_langs = utilities.SUPPORTED_LANGUAGES_BY_TEMPLATE_NAME[
48*e7b1675dSTing-Kang Chang        key_template_name]
49*e7b1675dSTing-Kang Chang    self.assertNotEmpty(supported_langs)
50*e7b1675dSTing-Kang Chang    key_template = utilities.KEY_TEMPLATE[key_template_name]
51*e7b1675dSTing-Kang Chang    # Take the first supported language to generate the private keyset.
52*e7b1675dSTing-Kang Chang    private_keyset = testing_servers.new_keyset(supported_langs[0],
53*e7b1675dSTing-Kang Chang                                                key_template)
54*e7b1675dSTing-Kang Chang    supported_signers = {}
55*e7b1675dSTing-Kang Chang    for lang in supported_langs:
56*e7b1675dSTing-Kang Chang      supported_signers[lang] = testing_servers.remote_primitive(
57*e7b1675dSTing-Kang Chang          lang, private_keyset, signature.PublicKeySign)
58*e7b1675dSTing-Kang Chang    public_keyset = testing_servers.public_keyset('java', private_keyset)
59*e7b1675dSTing-Kang Chang    supported_verifiers = {}
60*e7b1675dSTing-Kang Chang    for lang in supported_verifiers:
61*e7b1675dSTing-Kang Chang      supported_verifiers[lang] = testing_servers.remote_primitive(
62*e7b1675dSTing-Kang Chang          lang, public_keyset, signature.PublicKeyVerify)
63*e7b1675dSTing-Kang Chang    for lang, signer in supported_signers.items():
64*e7b1675dSTing-Kang Chang      message = (
65*e7b1675dSTing-Kang Chang          b'A message to be signed using key_template %s in %s.'
66*e7b1675dSTing-Kang Chang          % (key_template_name.encode('utf8'), lang.encode('utf8')))
67*e7b1675dSTing-Kang Chang      sign = signer.sign(message)
68*e7b1675dSTing-Kang Chang      for _, verifier in supported_verifiers.items():
69*e7b1675dSTing-Kang Chang        self.assertIsNone(verifier.verify(sign, message))
70*e7b1675dSTing-Kang Chang
71*e7b1675dSTing-Kang Chang# If the implementations work fine for keysets with single keys, then key
72*e7b1675dSTing-Kang Chang# rotation should work if the primitive wrapper is implemented correctly.
73*e7b1675dSTing-Kang Chang# The wrapper does not depend on the key type, so it should be fine to always
74*e7b1675dSTing-Kang Chang# test with the same key type. The wrapper needs to treat keys with output
75*e7b1675dSTing-Kang Chang# prefix RAW and LEGACY differently, so we also test templates with these
76*e7b1675dSTing-Kang Chang# prefixes.
77*e7b1675dSTing-Kang ChangKEY_ROTATION_TEMPLATES = [
78*e7b1675dSTing-Kang Chang    signature.signature_key_templates.ECDSA_P256,
79*e7b1675dSTing-Kang Chang    keyset_builder.raw_template(signature.signature_key_templates.ECDSA_P256),
80*e7b1675dSTing-Kang Chang    keyset_builder.legacy_template(signature.signature_key_templates.ECDSA_P256)
81*e7b1675dSTing-Kang Chang]
82*e7b1675dSTing-Kang Chang
83*e7b1675dSTing-Kang Chang
84*e7b1675dSTing-Kang Changdef key_rotation_test_cases(
85*e7b1675dSTing-Kang Chang) -> Iterable[Tuple[str, str, tink_pb2.KeyTemplate, tink_pb2.KeyTemplate]]:
86*e7b1675dSTing-Kang Chang  for enc_lang in SUPPORTED_LANGUAGES:
87*e7b1675dSTing-Kang Chang    for dec_lang in SUPPORTED_LANGUAGES:
88*e7b1675dSTing-Kang Chang      for old_key_tmpl in KEY_ROTATION_TEMPLATES:
89*e7b1675dSTing-Kang Chang        for new_key_tmpl in KEY_ROTATION_TEMPLATES:
90*e7b1675dSTing-Kang Chang          yield (enc_lang, dec_lang, old_key_tmpl, new_key_tmpl)
91*e7b1675dSTing-Kang Chang
92*e7b1675dSTing-Kang Chang
93*e7b1675dSTing-Kang Changclass SignatureKeyRotationTest(parameterized.TestCase):
94*e7b1675dSTing-Kang Chang
95*e7b1675dSTing-Kang Chang  @parameterized.parameters(key_rotation_test_cases())
96*e7b1675dSTing-Kang Chang  def test_key_rotation(self, enc_lang, dec_lang, old_key_tmpl, new_key_tmpl):
97*e7b1675dSTing-Kang Chang    # Do a key rotation from an old key generated from old_key_tmpl to a new
98*e7b1675dSTing-Kang Chang    # key generated from new_key_tmpl. Encryption and decryption are done
99*e7b1675dSTing-Kang Chang    # in languages enc_lang and dec_lang.
100*e7b1675dSTing-Kang Chang    builder = keyset_builder.new_keyset_builder()
101*e7b1675dSTing-Kang Chang    older_key_id = builder.add_new_key(old_key_tmpl)
102*e7b1675dSTing-Kang Chang    builder.set_primary_key(older_key_id)
103*e7b1675dSTing-Kang Chang    sign1 = testing_servers.remote_primitive(enc_lang, builder.keyset(),
104*e7b1675dSTing-Kang Chang                                             signature.PublicKeySign)
105*e7b1675dSTing-Kang Chang    verify1 = testing_servers.remote_primitive(dec_lang,
106*e7b1675dSTing-Kang Chang                                               builder.public_keyset(),
107*e7b1675dSTing-Kang Chang                                               signature.PublicKeyVerify)
108*e7b1675dSTing-Kang Chang    newer_key_id = builder.add_new_key(new_key_tmpl)
109*e7b1675dSTing-Kang Chang    sign2 = testing_servers.remote_primitive(enc_lang, builder.keyset(),
110*e7b1675dSTing-Kang Chang                                             signature.PublicKeySign)
111*e7b1675dSTing-Kang Chang    verify2 = testing_servers.remote_primitive(dec_lang,
112*e7b1675dSTing-Kang Chang                                               builder.public_keyset(),
113*e7b1675dSTing-Kang Chang                                               signature.PublicKeyVerify)
114*e7b1675dSTing-Kang Chang
115*e7b1675dSTing-Kang Chang    builder.set_primary_key(newer_key_id)
116*e7b1675dSTing-Kang Chang    sign3 = testing_servers.remote_primitive(enc_lang, builder.keyset(),
117*e7b1675dSTing-Kang Chang                                             signature.PublicKeySign)
118*e7b1675dSTing-Kang Chang    verify3 = testing_servers.remote_primitive(dec_lang,
119*e7b1675dSTing-Kang Chang                                               builder.public_keyset(),
120*e7b1675dSTing-Kang Chang                                               signature.PublicKeyVerify)
121*e7b1675dSTing-Kang Chang
122*e7b1675dSTing-Kang Chang    builder.disable_key(older_key_id)
123*e7b1675dSTing-Kang Chang    sign4 = testing_servers.remote_primitive(enc_lang, builder.keyset(),
124*e7b1675dSTing-Kang Chang                                             signature.PublicKeySign)
125*e7b1675dSTing-Kang Chang    verify4 = testing_servers.remote_primitive(dec_lang,
126*e7b1675dSTing-Kang Chang                                               builder.public_keyset(),
127*e7b1675dSTing-Kang Chang                                               signature.PublicKeyVerify)
128*e7b1675dSTing-Kang Chang    self.assertNotEqual(older_key_id, newer_key_id)
129*e7b1675dSTing-Kang Chang
130*e7b1675dSTing-Kang Chang    # 1 signs with the older key. So 1, 2 and 3 can verify it, but not 4.
131*e7b1675dSTing-Kang Chang    data_signature1 = sign1.sign(b'data')
132*e7b1675dSTing-Kang Chang    verify1.verify(data_signature1, b'data')
133*e7b1675dSTing-Kang Chang    verify2.verify(data_signature1, b'data')
134*e7b1675dSTing-Kang Chang    verify3.verify(data_signature1, b'data')
135*e7b1675dSTing-Kang Chang    with self.assertRaises(tink.TinkError):
136*e7b1675dSTing-Kang Chang      verify4.verify(data_signature1, b'data')
137*e7b1675dSTing-Kang Chang
138*e7b1675dSTing-Kang Chang    # 2 signs with the older key. So 1, 2 and 3 can verify it, but not 4.
139*e7b1675dSTing-Kang Chang    data_signature2 = sign2.sign(b'data')
140*e7b1675dSTing-Kang Chang    verify1.verify(data_signature2, b'data')
141*e7b1675dSTing-Kang Chang    verify2.verify(data_signature2, b'data')
142*e7b1675dSTing-Kang Chang    verify3.verify(data_signature2, b'data')
143*e7b1675dSTing-Kang Chang    with self.assertRaises(tink.TinkError):
144*e7b1675dSTing-Kang Chang      verify4.verify(data_signature2, b'data')
145*e7b1675dSTing-Kang Chang
146*e7b1675dSTing-Kang Chang    # 3 signs with the newer key. So 2, 3 and 4 can verify it, but not 1.
147*e7b1675dSTing-Kang Chang    data_signature3 = sign3.sign(b'data')
148*e7b1675dSTing-Kang Chang    with self.assertRaises(tink.TinkError):
149*e7b1675dSTing-Kang Chang      verify1.verify(data_signature3, b'data')
150*e7b1675dSTing-Kang Chang    verify2.verify(data_signature3, b'data')
151*e7b1675dSTing-Kang Chang    verify3.verify(data_signature3, b'data')
152*e7b1675dSTing-Kang Chang    verify4.verify(data_signature3, b'data')
153*e7b1675dSTing-Kang Chang
154*e7b1675dSTing-Kang Chang    # 4 signs with the newer key. So 2, 3 and 4 can verify it, but not 1.
155*e7b1675dSTing-Kang Chang    data_signature4 = sign4.sign(b'data')
156*e7b1675dSTing-Kang Chang    with self.assertRaises(tink.TinkError):
157*e7b1675dSTing-Kang Chang      verify1.verify(data_signature4, b'data')
158*e7b1675dSTing-Kang Chang    verify2.verify(data_signature4, b'data')
159*e7b1675dSTing-Kang Chang    verify3.verify(data_signature4, b'data')
160*e7b1675dSTing-Kang Chang    verify4.verify(data_signature4, b'data')
161*e7b1675dSTing-Kang Chang
162*e7b1675dSTing-Kang Changif __name__ == '__main__':
163*e7b1675dSTing-Kang Chang  absltest.main()
164