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