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"""Cross-language tests for Public-Key Signatures.""" 15 16from typing import Iterable, Tuple 17 18from absl.testing import absltest 19from absl.testing import parameterized 20 21import tink 22from tink import signature 23 24from tink.proto import tink_pb2 25from tink.testing import keyset_builder 26from util import testing_servers 27from util import utilities 28 29SUPPORTED_LANGUAGES = (testing_servers 30 .SUPPORTED_LANGUAGES_BY_PRIMITIVE['signature']) 31 32 33def setUpModule(): 34 signature.register() 35 testing_servers.start('signature') 36 37 38def tearDownModule(): 39 testing_servers.stop() 40 41 42class SignatureTest(parameterized.TestCase): 43 44 @parameterized.parameters( 45 utilities.tinkey_template_names_for(signature.PublicKeySign)) 46 def test_sign_verify(self, key_template_name): 47 supported_langs = utilities.SUPPORTED_LANGUAGES_BY_TEMPLATE_NAME[ 48 key_template_name] 49 self.assertNotEmpty(supported_langs) 50 key_template = utilities.KEY_TEMPLATE[key_template_name] 51 # Take the first supported language to generate the private keyset. 52 private_keyset = testing_servers.new_keyset(supported_langs[0], 53 key_template) 54 supported_signers = {} 55 for lang in supported_langs: 56 supported_signers[lang] = testing_servers.remote_primitive( 57 lang, private_keyset, signature.PublicKeySign) 58 public_keyset = testing_servers.public_keyset('java', private_keyset) 59 supported_verifiers = {} 60 for lang in supported_verifiers: 61 supported_verifiers[lang] = testing_servers.remote_primitive( 62 lang, public_keyset, signature.PublicKeyVerify) 63 for lang, signer in supported_signers.items(): 64 message = ( 65 b'A message to be signed using key_template %s in %s.' 66 % (key_template_name.encode('utf8'), lang.encode('utf8'))) 67 sign = signer.sign(message) 68 for _, verifier in supported_verifiers.items(): 69 self.assertIsNone(verifier.verify(sign, message)) 70 71# If the implementations work fine for keysets with single keys, then key 72# rotation should work if the primitive wrapper is implemented correctly. 73# The wrapper does not depend on the key type, so it should be fine to always 74# test with the same key type. The wrapper needs to treat keys with output 75# prefix RAW and LEGACY differently, so we also test templates with these 76# prefixes. 77KEY_ROTATION_TEMPLATES = [ 78 signature.signature_key_templates.ECDSA_P256, 79 keyset_builder.raw_template(signature.signature_key_templates.ECDSA_P256), 80 keyset_builder.legacy_template(signature.signature_key_templates.ECDSA_P256) 81] 82 83 84def key_rotation_test_cases( 85) -> Iterable[Tuple[str, str, tink_pb2.KeyTemplate, tink_pb2.KeyTemplate]]: 86 for enc_lang in SUPPORTED_LANGUAGES: 87 for dec_lang in SUPPORTED_LANGUAGES: 88 for old_key_tmpl in KEY_ROTATION_TEMPLATES: 89 for new_key_tmpl in KEY_ROTATION_TEMPLATES: 90 yield (enc_lang, dec_lang, old_key_tmpl, new_key_tmpl) 91 92 93class SignatureKeyRotationTest(parameterized.TestCase): 94 95 @parameterized.parameters(key_rotation_test_cases()) 96 def test_key_rotation(self, enc_lang, dec_lang, old_key_tmpl, new_key_tmpl): 97 # Do a key rotation from an old key generated from old_key_tmpl to a new 98 # key generated from new_key_tmpl. Encryption and decryption are done 99 # in languages enc_lang and dec_lang. 100 builder = keyset_builder.new_keyset_builder() 101 older_key_id = builder.add_new_key(old_key_tmpl) 102 builder.set_primary_key(older_key_id) 103 sign1 = testing_servers.remote_primitive(enc_lang, builder.keyset(), 104 signature.PublicKeySign) 105 verify1 = testing_servers.remote_primitive(dec_lang, 106 builder.public_keyset(), 107 signature.PublicKeyVerify) 108 newer_key_id = builder.add_new_key(new_key_tmpl) 109 sign2 = testing_servers.remote_primitive(enc_lang, builder.keyset(), 110 signature.PublicKeySign) 111 verify2 = testing_servers.remote_primitive(dec_lang, 112 builder.public_keyset(), 113 signature.PublicKeyVerify) 114 115 builder.set_primary_key(newer_key_id) 116 sign3 = testing_servers.remote_primitive(enc_lang, builder.keyset(), 117 signature.PublicKeySign) 118 verify3 = testing_servers.remote_primitive(dec_lang, 119 builder.public_keyset(), 120 signature.PublicKeyVerify) 121 122 builder.disable_key(older_key_id) 123 sign4 = testing_servers.remote_primitive(enc_lang, builder.keyset(), 124 signature.PublicKeySign) 125 verify4 = testing_servers.remote_primitive(dec_lang, 126 builder.public_keyset(), 127 signature.PublicKeyVerify) 128 self.assertNotEqual(older_key_id, newer_key_id) 129 130 # 1 signs with the older key. So 1, 2 and 3 can verify it, but not 4. 131 data_signature1 = sign1.sign(b'data') 132 verify1.verify(data_signature1, b'data') 133 verify2.verify(data_signature1, b'data') 134 verify3.verify(data_signature1, b'data') 135 with self.assertRaises(tink.TinkError): 136 verify4.verify(data_signature1, b'data') 137 138 # 2 signs with the older key. So 1, 2 and 3 can verify it, but not 4. 139 data_signature2 = sign2.sign(b'data') 140 verify1.verify(data_signature2, b'data') 141 verify2.verify(data_signature2, b'data') 142 verify3.verify(data_signature2, b'data') 143 with self.assertRaises(tink.TinkError): 144 verify4.verify(data_signature2, b'data') 145 146 # 3 signs with the newer key. So 2, 3 and 4 can verify it, but not 1. 147 data_signature3 = sign3.sign(b'data') 148 with self.assertRaises(tink.TinkError): 149 verify1.verify(data_signature3, b'data') 150 verify2.verify(data_signature3, b'data') 151 verify3.verify(data_signature3, b'data') 152 verify4.verify(data_signature3, b'data') 153 154 # 4 signs with the newer key. So 2, 3 and 4 can verify it, but not 1. 155 data_signature4 = sign4.sign(b'data') 156 with self.assertRaises(tink.TinkError): 157 verify1.verify(data_signature4, b'data') 158 verify2.verify(data_signature4, b'data') 159 verify3.verify(data_signature4, b'data') 160 verify4.verify(data_signature4, b'data') 161 162if __name__ == '__main__': 163 absltest.main() 164