Software APIs
rsa_2048_signature_functest.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
6 #include "sw/device/lib/crypto/drivers/entropy.h"
7 #include "sw/device/lib/crypto/impl/integrity.h"
11 #include "sw/device/lib/testing/profile.h"
12 #include "sw/device/lib/testing/test_framework/check.h"
14 
15 // Module for status messages.
16 #define MODULE_ID MAKE_MODULE_ID('t', 's', 't')
17 
18 enum {
19  kRsa2048NumBytes = 2048 / 8,
20  kRsa2048NumWords = kRsa2048NumBytes / sizeof(uint32_t),
21 };
22 
23 // Note: The private key and valid signatures for this test were generated
24 // out-of-band using the PyCryptodome Python library.
25 
26 // Test RSA-2048 key pair.
27 static uint32_t kTestModulus[kRsa2048NumWords] = {
28  0x40d984b1, 0x3611356d, 0x9eb2f35c, 0x031a892c, 0x16354662, 0x6a260bad,
29  0xb2b807d6, 0xb7de7ccb, 0x278492e0, 0x41adab06, 0x9e60110f, 0x1414eeff,
30  0x8b80e14e, 0x5eb5ae79, 0x0d98fa5b, 0x58bece1f, 0xcf6bdca8, 0x82f5611f,
31  0x351e3869, 0x075005d6, 0xe813fe23, 0xdd967a37, 0x682d1c41, 0x9fdd2d8c,
32  0x21bdd5fc, 0x4fc459c7, 0x508c9293, 0x1f9ac759, 0x55aacb04, 0x58389f05,
33  0x0d0b00fb, 0x59bb4141, 0x68f9e0bf, 0xc2f1a546, 0x0a71ad19, 0x9c400301,
34  0xa4f8ecb9, 0xcdf39538, 0xaabe9cb0, 0xd9f7b2dc, 0x0e8b292d, 0x8ef6c717,
35  0x720e9520, 0xb0c6a23e, 0xda1e92b1, 0x8b6b4800, 0x2f25082b, 0x7f2d6711,
36  0x426fc94f, 0x9926ba5a, 0x89bd4d2b, 0x977718d5, 0x5a8406be, 0x87d090f3,
37  0x639f9975, 0x5948488b, 0x1d3d9cd7, 0x28c7956b, 0xebb97a3e, 0x1edbf4e2,
38  0x105cc797, 0x924ec514, 0x146810df, 0xb1ab4a49,
39 };
40 static uint32_t kTestPrivateExponent[kRsa2048NumWords] = {
41  0x0b19915b, 0xa6a935e6, 0x426b2e10, 0xb4ff0629, 0x7322343b, 0x3f28c8d5,
42  0x190757ce, 0x87409d6b, 0xd88e282b, 0x01c13c2a, 0xebb79189, 0x74cbeab9,
43  0x93de5d54, 0xae1bc80a, 0x083a75f2, 0xd574d229, 0xeb46696e, 0x7648cfb6,
44  0xe7ad1b36, 0xbd0e81b2, 0x19c72703, 0xebea5085, 0xf8c7d152, 0x34dcf84d,
45  0xa437187f, 0x41e4f88e, 0xe4e35f9f, 0xcd8bc6f8, 0x7f98e2f2, 0xffdf75ca,
46  0x3698226e, 0x903f2a56, 0xbf21a6dc, 0x97cbf653, 0xe9d80cb3, 0x55dc1685,
47  0xe0ebae21, 0xc8171e18, 0x8e73d26d, 0xbbdbaac1, 0x886e8007, 0x673c9da4,
48  0xe2cb0698, 0xa9f1ba2d, 0xedab4f0a, 0x197e890c, 0x65e7e736, 0x1de28f24,
49  0x57cf5137, 0x631ff441, 0x22539942, 0xcee3fd41, 0xd22b5f8a, 0x995dd87a,
50  0xcaa6815c, 0x08ca0fd3, 0x8f996093, 0x30b7c446, 0xf69b11f7, 0xa298dd00,
51  0xfd4e8120, 0x059df602, 0x25feb268, 0x0f3f749e,
52 };
53 static uint32_t kTestPublicExponent = 65537;
54 
55 // Message data for testing.
56 static const unsigned char kTestMessage[] = "Test message.";
57 static const size_t kTestMessageLen = sizeof(kTestMessage) - 1;
58 
59 // Valid signature of `kTestMessage` from the test private key, using PKCS#1
60 // v1.5 padding and SHA-256 as the hash function.
61 static const uint32_t kValidSignaturePkcs1v15[kRsa2048NumWords] = {
62  0xab66c6c7, 0x97effc0a, 0x9869cdba, 0x7b6c09fe, 0x2124d28f, 0x793084b3,
63  0x4da24b72, 0x4f6c8659, 0x63e3a27b, 0xbbe8d120, 0x8789190f, 0x1722fe46,
64  0x25573178, 0x3accbdb3, 0x1eb7ca00, 0xe8eb40aa, 0x1d3b21a8, 0x9997925e,
65  0x1793f81d, 0x12728f54, 0x66e40608, 0x4b1057a0, 0xba433eb3, 0x702c73b2,
66  0xa9391740, 0xf838710f, 0xf33cf109, 0x595cee1d, 0x07341be9, 0xcfce52b1,
67  0x5b48ba7a, 0xf70e5a0e, 0xdbb98c42, 0x85fd6979, 0xcdb760fc, 0xd2e09553,
68  0x70bba417, 0x04e52609, 0xc215420e, 0x2407242e, 0x4f19674b, 0x5d996a9d,
69  0xf2fb1d05, 0x88e0fc14, 0xe1a38f0c, 0xd111935d, 0xd23bf5b3, 0xdcd7a882,
70  0x0f242315, 0xd7247d51, 0xc247d6ec, 0xe2492739, 0x3dfb115c, 0x031aea7a,
71  0xcdcb09c0, 0x29318ddb, 0xd0a10dd8, 0x3307018e, 0xe13c5616, 0x98d4db80,
72  0x50692a42, 0x41e94a74, 0x0a6f79eb, 0x1c405c66,
73 };
74 
75 // Valid signature of `kTestMessage` from the test private key, using PSS
76 // padding and SHA-256 as the hash function.
77 static const uint32_t kValidSignaturePss[kRsa2048NumWords] = {
78  0x6203140a, 0xa860e759, 0x65ddb724, 0x2b4eedfa, 0xf11d5e65, 0xa6ab5601,
79  0x14097f2e, 0x56f9dda5, 0xcb43ebcc, 0x7914036d, 0x83e99afd, 0x323187a7,
80  0x6f239172, 0x0fc9f25a, 0xe83555a7, 0xd12997e2, 0x65dcd504, 0x99ebef85,
81  0x4a5f2679, 0xedf106d8, 0x68c21486, 0xeb7edb37, 0x33e22631, 0xf23699ae,
82  0x679b750e, 0xb5c09869, 0x72f7ccd0, 0xef503c8f, 0xa0225545, 0x86554913,
83  0xbce86ec4, 0x75f846d2, 0xf16318a8, 0xbce00097, 0x170a418f, 0x558e2f9f,
84  0xed555d51, 0x061b6074, 0x859c0bb6, 0xb2800a5a, 0x0180afd3, 0x41f0a2d6,
85  0xc75b12ff, 0xaa6179f7, 0x63e71a9a, 0xbdbd759e, 0xe39d7372, 0xa579683f,
86  0x8db987a5, 0x8bd0e702, 0x8b32ed36, 0x988e28ee, 0x21c3402d, 0x48490be0,
87  0xcbfb2e91, 0x1ba04f77, 0x0ca06d1d, 0xcf2a8645, 0xed3f78e4, 0x4483da1d,
88  0x2df279d7, 0xada9475e, 0x6ec0863d, 0x94eb575c,
89 };
90 
91 /**
92  * Helper function to run the RSA-2048 signing routine.
93  *
94  * Packages input into cryptolib-style structs and calls `otcrypto_rsa_sign`
95  * using the constant test private key.
96  *
97  * @param msg Message to sign.
98  * @param msg_len Message length in bytes.
99  * @param padding_mode RSA padding mode.
100  * @param hash_mode Hash function to use.
101  * @param[out] sig Buffer for the generated RSA signature (2048 bits).
102  * @return OK or error.
103  */
104 static status_t run_rsa_2048_sign(const uint8_t *msg, size_t msg_len,
105  otcrypto_rsa_padding_t padding_mode,
106  uint32_t *sig) {
107  otcrypto_key_mode_t key_mode;
108  switch (padding_mode) {
109  case kOtcryptoRsaPaddingPkcs:
110  key_mode = kOtcryptoKeyModeRsaSignPkcs;
111  break;
112  case kOtcryptoRsaPaddingPss:
113  key_mode = kOtcryptoKeyModeRsaSignPss;
114  break;
115  default:
116  return INVALID_ARGUMENT();
117  };
118 
119  // Create two shares for the private exponent (second share is all-zero).
120  otcrypto_const_word32_buf_t d_share0 = {
121  .data = kTestPrivateExponent,
122  .len = ARRAYSIZE(kTestPrivateExponent),
123  };
124  uint32_t share1[ARRAYSIZE(kTestPrivateExponent)] = {0};
125  otcrypto_const_word32_buf_t d_share1 = {
126  .data = share1,
127  .len = ARRAYSIZE(share1),
128  };
129 
130  // Construct the private key.
131  otcrypto_key_config_t private_key_config = {
132  .version = kOtcryptoLibVersion1,
133  .key_mode = key_mode,
134  .key_length = kOtcryptoRsa2048PrivateKeyBytes,
135  .hw_backed = kHardenedBoolFalse,
136  .security_level = kOtcryptoKeySecurityLevelLow,
137  };
138  size_t keyblob_words =
140  uint32_t keyblob[keyblob_words];
141  otcrypto_blinded_key_t private_key = {
142  .config = private_key_config,
143  .keyblob = keyblob,
144  .keyblob_length = kOtcryptoRsa2048PrivateKeyblobBytes,
145  };
146  otcrypto_const_word32_buf_t modulus = {
147  .data = kTestModulus,
148  .len = ARRAYSIZE(kTestModulus),
149  };
150  TRY(otcrypto_rsa_private_key_from_exponents(kOtcryptoRsaSize2048, modulus,
151  kTestPublicExponent, d_share0,
152  d_share1, &private_key));
153 
154  // Hash the message.
155  otcrypto_const_byte_buf_t msg_buf = {.data = msg, .len = msg_len};
156  uint32_t msg_digest_data[kSha256DigestWords];
157  otcrypto_hash_digest_t msg_digest = {
158  .data = msg_digest_data,
159  .len = ARRAYSIZE(msg_digest_data),
160  .mode = kOtcryptoHashModeSha256,
161  };
162  TRY(otcrypto_hash(msg_buf, msg_digest));
163 
164  otcrypto_word32_buf_t sig_buf = {
165  .data = sig,
166  .len = kRsa2048NumWords,
167  };
168  uint64_t t_start = profile_start();
169  TRY(otcrypto_rsa_sign(&private_key, msg_digest, padding_mode, sig_buf));
170  profile_end_and_print(t_start, "RSA signature generation");
171 
172  return OK_STATUS();
173 }
174 
175 /**
176  * Helper function to run the RSA-2048 verification routine.
177  *
178  * Packages input into cryptolib-style structs and calls `otcrypto_rsa_verify`
179  * using the constant test public key. Always uses SHA-256 as the hash
180  * function.
181  *
182  * @param msg Message to verify.
183  * @param msg_len Message length in bytes.
184  * @param sig Signature to verify
185  * @param padding_mode RSA padding mode.
186  * @param[out] verification_result Whether the signature passed verification.
187  * @return OK or error.
188  */
189 static status_t run_rsa_2048_verify(const uint8_t *msg, size_t msg_len,
190  const uint32_t *sig,
191  const otcrypto_rsa_padding_t padding_mode,
192  hardened_bool_t *verification_result) {
193  otcrypto_key_mode_t key_mode;
194  switch (padding_mode) {
195  case kOtcryptoRsaPaddingPkcs:
196  key_mode = kOtcryptoKeyModeRsaSignPkcs;
197  break;
198  case kOtcryptoRsaPaddingPss:
199  key_mode = kOtcryptoKeyModeRsaSignPss;
200  break;
201  default:
202  return INVALID_ARGUMENT();
203  };
204 
205  // Construct the public key.
206  otcrypto_const_word32_buf_t modulus = {
207  .data = kTestModulus,
208  .len = ARRAYSIZE(kTestModulus),
209  };
210  uint32_t public_key_data[ceil_div(kOtcryptoRsa2048PublicKeyBytes,
211  sizeof(uint32_t))];
212  otcrypto_unblinded_key_t public_key = {
213  .key_mode = key_mode,
214  .key_length = kOtcryptoRsa2048PublicKeyBytes,
215  .key = public_key_data,
216  };
217  TRY(otcrypto_rsa_public_key_construct(kOtcryptoRsaSize2048, modulus,
218  kTestPublicExponent, &public_key));
219 
220  // Hash the message.
221  otcrypto_const_byte_buf_t msg_buf = {.data = msg, .len = msg_len};
222  uint32_t msg_digest_data[kSha256DigestWords];
223  otcrypto_hash_digest_t msg_digest = {
224  .data = msg_digest_data,
225  .len = ARRAYSIZE(msg_digest_data),
226  .mode = kOtcryptoHashModeSha256,
227  };
228  TRY(otcrypto_hash(msg_buf, msg_digest));
229 
230  otcrypto_const_word32_buf_t sig_buf = {
231  .data = sig,
232  .len = kRsa2048NumWords,
233  };
234  uint64_t t_start = profile_start();
235  TRY(otcrypto_rsa_verify(&public_key, msg_digest, padding_mode, sig_buf,
236  verification_result));
237  profile_end_and_print(t_start, "RSA verify");
238 
239  return OK_STATUS();
240 }
241 
242 status_t pkcs1v15_sign_test(void) {
243  // Generate a signature using PKCS#1 v1.5 padding and SHA-256 as the hash
244  // function.
245  uint32_t sig[kRsa2048NumWords];
246  TRY(run_rsa_2048_sign(kTestMessage, kTestMessageLen, kOtcryptoRsaPaddingPkcs,
247  sig));
248 
249  // Compare to the expected signature.
250  TRY_CHECK_ARRAYS_EQ(sig, kValidSignaturePkcs1v15,
251  ARRAYSIZE(kValidSignaturePkcs1v15));
252  return OK_STATUS();
253 }
254 
255 status_t pkcs1v15_verify_valid_test(void) {
256  // Try to verify a valid signature.
257  hardened_bool_t verification_result;
258  TRY(run_rsa_2048_verify(kTestMessage, kTestMessageLen,
259  kValidSignaturePkcs1v15, kOtcryptoRsaPaddingPkcs,
260  &verification_result));
261 
262  // Expect the signature to pass verification.
263  TRY_CHECK(verification_result == kHardenedBoolTrue);
264  return OK_STATUS();
265 }
266 
267 status_t pkcs1v15_verify_invalid_test(void) {
268  // Try to verify an invalid signature (wrong padding mode).
269  hardened_bool_t verification_result;
270  TRY(run_rsa_2048_verify(kTestMessage, kTestMessageLen, kValidSignaturePss,
271  kOtcryptoRsaPaddingPkcs, &verification_result));
272 
273  // Expect the signature to fail verification.
274  TRY_CHECK(verification_result == kHardenedBoolFalse);
275  return OK_STATUS();
276 }
277 
278 status_t pss_sign_test(void) {
279  // PSS signatures are not deterministic, so we need to sign-then-verify.
280  uint32_t sig[kRsa2048NumWords];
281  TRY(run_rsa_2048_sign(kTestMessage, kTestMessageLen, kOtcryptoRsaPaddingPss,
282  sig));
283 
284  // Try to verify the signature.
285  hardened_bool_t verification_result;
286  TRY(run_rsa_2048_verify(kTestMessage, kTestMessageLen, sig,
287  kOtcryptoRsaPaddingPss, &verification_result));
288 
289  // Expect the signature to pass verification.
290  TRY_CHECK(verification_result == kHardenedBoolTrue);
291  return OK_STATUS();
292 }
293 
294 status_t pss_verify_valid_test(void) {
295  // Try to verify a valid signature.
296  hardened_bool_t verification_result;
297  TRY(run_rsa_2048_verify(kTestMessage, kTestMessageLen, kValidSignaturePss,
298  kOtcryptoRsaPaddingPss, &verification_result));
299 
300  // Expect the signature to pass verification.
301  TRY_CHECK(verification_result == kHardenedBoolTrue);
302  return OK_STATUS();
303 }
304 
305 status_t pss_verify_invalid_test(void) {
306  // Try to verify an invalid signature (wrong padding mode).
307  hardened_bool_t verification_result;
308  TRY(run_rsa_2048_verify(kTestMessage, kTestMessageLen,
309  kValidSignaturePkcs1v15, kOtcryptoRsaPaddingPss,
310  &verification_result));
311 
312  // Expect the signature to fail verification.
313  TRY_CHECK(verification_result == kHardenedBoolFalse);
314  return OK_STATUS();
315 }
316 
317 OTTF_DEFINE_TEST_CONFIG();
318 
319 bool test_main(void) {
320  status_t test_result = OK_STATUS();
321  CHECK_STATUS_OK(entropy_complex_init());
322  EXECUTE_TEST(test_result, pkcs1v15_sign_test);
323  EXECUTE_TEST(test_result, pkcs1v15_verify_valid_test);
324  EXECUTE_TEST(test_result, pkcs1v15_verify_invalid_test);
325  EXECUTE_TEST(test_result, pss_sign_test);
326  EXECUTE_TEST(test_result, pss_verify_valid_test);
327  EXECUTE_TEST(test_result, pss_verify_invalid_test);
328  return status_ok(test_result);
329 }