• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2023 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
15from typing import List, Tuple
16
17from absl.testing import absltest
18from absl.testing import parameterized
19
20import tink
21from tink import signature
22
23from tink.proto import common_pb2
24from tink.proto import rsa_ssa_pkcs1_pb2
25from tink.proto import tink_pb2
26import tink_config
27from util import testing_servers
28
29# 2048-bit modulus of the first test vector in
30# https://github.com/google/wycheproof/blob/master/testvectors/rsa_pkcs1_2048_test.json
31# This modulus uses the minimal two's-complement big-endian encoding, that's
32# why it starts with a zero and has a leading 0 byte and has 257 bytes.
33MODULUS_BYTES = bytes.fromhex(
34    '00b3510a2bcd4ce644c5b594ae5059e12b2f054b658d5da5959a2fdf1871b808'
35    'bc3df3e628d2792e51aad5c124b43bda453dca5cde4bcf28e7bd4effba0cb4b7'
36    '42bbb6d5a013cb63d1aa3a89e02627ef5398b52c0cfd97d208abeb8d7c9bce0b'
37    'beb019a86ddb589beb29a5b74bf861075c677c81d430f030c265247af9d3c914'
38    '0ccb65309d07e0adc1efd15cf17e7b055d7da3868e4648cc3a180f0ee7f8e1e7'
39    'b18098a3391b4ce7161e98d57af8a947e201a463e2d6bbca8059e5706e9dfed8'
40    'f4856465ffa712ed1aa18e888d12dc6aa09ce95ecfca83cc5b0b15db09c8647f'
41    '5d524c0f2e7620a3416b9623cadc0f097af573261c98c8400aa12af38e43cad84d'
42)
43
44# Same as MODULUS_BYTES, but with the least significant byte set to 0.
45# Hence this modulus has 256 as a factor.
46WEIRD_MODULUS_BYTES = bytes.fromhex(
47    '00b3510a2bcd4ce644c5b594ae5059e12b2f054b658d5da5959a2fdf1871b808'
48    'bc3df3e628d2792e51aad5c124b43bda453dca5cde4bcf28e7bd4effba0cb4b7'
49    '42bbb6d5a013cb63d1aa3a89e02627ef5398b52c0cfd97d208abeb8d7c9bce0b'
50    'beb019a86ddb589beb29a5b74bf861075c677c81d430f030c265247af9d3c914'
51    '0ccb65309d07e0adc1efd15cf17e7b055d7da3868e4648cc3a180f0ee7f8e1e7'
52    'b18098a3391b4ce7161e98d57af8a947e201a463e2d6bbca8059e5706e9dfed8'
53    'f4856465ffa712ed1aa18e888d12dc6aa09ce95ecfca83cc5b0b15db09c8647f'
54    '5d524c0f2e7620a3416b9623cadc0f097af573261c98c8400aa12af38e43cad800'
55)
56
57# Same as MODULUS_BYTES, but with the most significant bit set to 0, and
58# the 2nd most significant bit set to 1. So this modulus has 2047 bits.
59SHORT_MODULUS_BYTES = bytes.fromhex(
60    '0073510a2bcd4ce644c5b594ae5059e12b2f054b658d5da5959a2fdf1871b808'
61    'bc3df3e628d2792e51aad5c124b43bda453dca5cde4bcf28e7bd4effba0cb4b7'
62    '42bbb6d5a013cb63d1aa3a89e02627ef5398b52c0cfd97d208abeb8d7c9bce0b'
63    'beb019a86ddb589beb29a5b74bf861075c677c81d430f030c265247af9d3c914'
64    '0ccb65309d07e0adc1efd15cf17e7b055d7da3868e4648cc3a180f0ee7f8e1e7'
65    'b18098a3391b4ce7161e98d57af8a947e201a463e2d6bbca8059e5706e9dfed8'
66    'f4856465ffa712ed1aa18e888d12dc6aa09ce95ecfca83cc5b0b15db09c8647f'
67    '5d524c0f2e7620a3416b9623cadc0f097af573261c98c8400aa12af38e43cad84d'
68)
69
70# big-endian encoding of 4th Fermat number F4 = 65537 = 2^16 + 1
71F4_BYTES = bytes.fromhex('010001')
72
73RSA_SSA_PKCS1_PUBLIC_KEY_TYPE_URL = (
74    'type.googleapis.com/google.crypto.tink.RsaSsaPkcs1PublicKey'
75)
76
77
78def setUpModule():
79  signature.register()
80  testing_servers.start('aes_ctr_hmac_streaming_key_test')
81
82
83def tearDownModule():
84  testing_servers.stop()
85
86
87def public_key_to_keyset(
88    public_key: rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey,
89    output_prefix_type: tink_pb2.OutputPrefixType,
90) -> tink_pb2.Keyset:
91  """Embeds a RsaSsaPkcs1PrivateKey with the output_prefix_type in a keyset."""
92  return tink_pb2.Keyset(
93      primary_key_id=1234,
94      key=[
95          tink_pb2.Keyset.Key(
96              key_data=tink_pb2.KeyData(
97                  type_url=RSA_SSA_PKCS1_PUBLIC_KEY_TYPE_URL,
98                  value=public_key.SerializeToString(),
99                  key_material_type=tink_pb2.KeyData.ASYMMETRIC_PUBLIC,
100              ),
101              output_prefix_type=output_prefix_type,
102              status=tink_pb2.KeyStatusType.ENABLED,
103              key_id=1234,
104          )
105      ],
106  )
107
108
109def valid_public_keys() -> (
110    List[Tuple[str, rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey]]
111):
112  return [
113      (
114          '2048-bit public key with SHA256',
115          rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey(
116              version=0,
117              n=MODULUS_BYTES,
118              e=F4_BYTES,
119              params=rsa_ssa_pkcs1_pb2.RsaSsaPkcs1Params(
120                  hash_type=common_pb2.HashType.SHA256
121              ),
122          ),
123      ),
124      (
125          '2048-bit public key with SHA384',
126          rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey(
127              version=0,
128              n=MODULUS_BYTES,
129              e=F4_BYTES,
130              params=rsa_ssa_pkcs1_pb2.RsaSsaPkcs1Params(
131                  hash_type=common_pb2.HashType.SHA384
132              ),
133          ),
134      ),
135      (
136          '2048-bit public key with SHA512',
137          rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey(
138              version=0,
139              n=MODULUS_BYTES,
140              e=F4_BYTES,
141              params=rsa_ssa_pkcs1_pb2.RsaSsaPkcs1Params(
142                  hash_type=common_pb2.HashType.SHA512
143              ),
144          ),
145      ),
146      (
147          '2048-bit public key with SHA1',
148          rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey(
149              version=0,
150              n=MODULUS_BYTES,
151              e=F4_BYTES,
152              params=rsa_ssa_pkcs1_pb2.RsaSsaPkcs1Params(
153                  hash_type=common_pb2.HashType.SHA256
154              ),
155          ),
156      ),
157      (
158          '2048-bit public key with e=2^16+3',
159          rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey(
160              version=0,
161              n=MODULUS_BYTES,
162              e=bytes.fromhex('010003'),
163              params=rsa_ssa_pkcs1_pb2.RsaSsaPkcs1Params(
164                  hash_type=common_pb2.HashType.SHA256
165              ),
166          ),
167      ),
168      (
169          '2048-bit public key with e=2^32-1',
170          rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey(
171              version=0,
172              n=MODULUS_BYTES,
173              e=bytes.fromhex('ffffffff'),
174              params=rsa_ssa_pkcs1_pb2.RsaSsaPkcs1Params(
175                  hash_type=common_pb2.HashType.SHA256
176              ),
177          ),
178      ),
179      (
180          '2048-bit public key with many leading zeros in the modulus',
181          rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey(
182              version=0,
183              n=bytes.fromhex('00000000') + MODULUS_BYTES,
184              e=F4_BYTES,
185              params=rsa_ssa_pkcs1_pb2.RsaSsaPkcs1Params(
186                  hash_type=common_pb2.HashType.SHA256
187              ),
188          ),
189      ),
190      (
191          '2048-bit public key without any leading zeros in the modulus',
192          rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey(
193              version=0,
194              n=MODULUS_BYTES[1:],
195              e=F4_BYTES,
196              params=rsa_ssa_pkcs1_pb2.RsaSsaPkcs1Params(
197                  hash_type=common_pb2.HashType.SHA256
198              ),
199          ),
200      ),
201      (
202          '2048-bit public key with modulus divisible by 256',
203          rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey(
204              version=0,
205              n=WEIRD_MODULUS_BYTES,
206              e=F4_BYTES,
207              params=rsa_ssa_pkcs1_pb2.RsaSsaPkcs1Params(
208                  hash_type=common_pb2.HashType.SHA256
209              ),
210          ),
211      ),
212  ]
213
214
215def invalid_public_keys() -> (
216    List[Tuple[str, rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey]]
217):
218  return [
219      (
220          '2048-bit public key with SHA224',
221          rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey(
222              version=0,
223              n=MODULUS_BYTES,
224              e=F4_BYTES,
225              params=rsa_ssa_pkcs1_pb2.RsaSsaPkcs1Params(
226                  hash_type=common_pb2.HashType.SHA224
227              ),
228          ),
229      ),
230      (
231          '2048-bit public key with small e',
232          rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey(
233              version=0,
234              n=MODULUS_BYTES,
235              e=bytes.fromhex('03'),
236              params=rsa_ssa_pkcs1_pb2.RsaSsaPkcs1Params(
237                  hash_type=common_pb2.HashType.SHA1
238              ),
239          ),
240      ),
241      (
242          '2048-bit public key with 2^16-1',
243          rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey(
244              version=0,
245              n=MODULUS_BYTES,
246              e=bytes.fromhex('00ffff'),
247              params=rsa_ssa_pkcs1_pb2.RsaSsaPkcs1Params(
248                  hash_type=common_pb2.HashType.SHA1
249              ),
250          ),
251      ),
252      (
253          '2048-bit public key with an invalid e',
254          rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey(
255              version=0,
256              n=MODULUS_BYTES,
257              # This e is even, which is invalid since e must be co-prime
258              # with p-1 and q-1, which both are also even.
259              e=bytes.fromhex('010002'),
260              params=rsa_ssa_pkcs1_pb2.RsaSsaPkcs1Params(
261                  hash_type=common_pb2.HashType.SHA256
262              ),
263          ),
264      ),
265      (
266          '2048-bit public key with e=2^32+1',
267          rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey(
268              version=0,
269              n=MODULUS_BYTES,
270              # BoringSSL (which gets used in C++, Python and Go) rejects values
271              # for e with more than 32 bits.
272              e=bytes.fromhex('0100000001'),
273              params=rsa_ssa_pkcs1_pb2.RsaSsaPkcs1Params(
274                  hash_type=common_pb2.HashType.SHA256
275              ),
276          ),
277      ),
278      (
279          '2047-bit public key',
280          rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey(
281              version=0,
282              n=SHORT_MODULUS_BYTES,
283              e=F4_BYTES,
284              params=rsa_ssa_pkcs1_pb2.RsaSsaPkcs1Params(
285                  hash_type=common_pb2.HashType.SHA256
286              ),
287          ),
288      ),
289      (
290          '2048-bit public key with version 1',
291          rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey(
292              version=1,
293              n=MODULUS_BYTES,
294              e=F4_BYTES,
295              params=rsa_ssa_pkcs1_pb2.RsaSsaPkcs1Params(
296                  hash_type=common_pb2.HashType.SHA256
297              ),
298          ),
299      ),
300  ]
301
302
303def valid_key_testcases():
304  for lang in tink_config.supported_languages_for_key_type(
305      'RsaSsaPkcs1PublicKey'
306  ):
307    for key_desc, key in valid_public_keys():
308      if lang == 'go' and (
309          key_desc == '2048-bit public key with e=2^16+3'
310          or key_desc == '2048-bit public key with e=2^32-1'
311      ):
312        # Go only accepts e = F4 = 2^16 + 1 = 65537. See also b/274605582.
313        continue
314      yield ('%s: %s' % (key_desc, lang), lang, key)
315
316
317def invalid_key_testcases():
318  for lang in tink_config.supported_languages_for_key_type(
319      'RsaSsaPkcs1PublicKey'
320  ):
321    for key_desc, key in invalid_public_keys():
322      if lang == 'java' and key_desc == '2048-bit public key with e=2^32+1':
323        # Java accepts large values for e. See also b/274605582.
324        continue
325      yield ('%s: %s' % (key_desc, lang), lang, key)
326
327
328class RsaSsaPkcs1PublicKeyTest(parameterized.TestCase):
329  """Tests specific for keys of type RsaSsaPkcs1PublicKey."""
330
331  @parameterized.named_parameters(valid_key_testcases())
332  def test_create_signature_verify_with_valid_key_success(
333      self, lang: str, key: rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey
334  ):
335    keyset = public_key_to_keyset(key, tink_pb2.OutputPrefixType.TINK)
336    testing_servers.remote_primitive(
337        lang, keyset.SerializeToString(), signature.PublicKeyVerify
338    )
339
340  @parameterized.named_parameters(invalid_key_testcases())
341  def test_create_signature_verify_with_invalid_key_fails(
342      self, lang: str, key: rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey
343  ):
344    keyset = public_key_to_keyset(key, tink_pb2.OutputPrefixType.TINK)
345    with self.assertRaises(tink.TinkError):
346      testing_servers.remote_primitive(
347          lang, keyset.SerializeToString(), signature.PublicKeyVerify
348      )
349
350  def test_golang_rejects_f4_plus_2(self):
351    """See also b/274605582."""
352    key = rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey(
353        version=0,
354        n=MODULUS_BYTES,
355        e=bytes.fromhex('010003'),
356        params=rsa_ssa_pkcs1_pb2.RsaSsaPkcs1Params(
357            hash_type=common_pb2.HashType.SHA256
358        ),
359    )
360    keyset = public_key_to_keyset(key, tink_pb2.OutputPrefixType.TINK)
361    with self.assertRaises(tink.TinkError):
362      testing_servers.remote_primitive(
363          'go', keyset.SerializeToString(), signature.PublicKeyVerify
364      )
365
366  def test_java_accepts_large_e(self):
367    """See also b/274605582."""
368    key = rsa_ssa_pkcs1_pb2.RsaSsaPkcs1PublicKey(
369        version=0,
370        n=MODULUS_BYTES,
371        # 2^32 + 1
372        e=bytes.fromhex('0100000001'),
373        params=rsa_ssa_pkcs1_pb2.RsaSsaPkcs1Params(
374            hash_type=common_pb2.HashType.SHA256
375        ),
376    )
377    keyset = public_key_to_keyset(key, tink_pb2.OutputPrefixType.TINK)
378    testing_servers.remote_primitive(
379        'java', keyset.SerializeToString(), signature.PublicKeyVerify
380    )
381
382
383if __name__ == '__main__':
384  absltest.main()
385