Software APIs
rsa_3072_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  kRsa3072NumBytes = 3072 / 8,
20  kRsa3072NumWords = kRsa3072NumBytes / 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-3072 key pair:
27 // e = 65537
28 // n =
29 // 0xa60f30a231261907afe74287a90cc23b24ec935f7520180f833bf3261c9f5a53c6057b0be827fc8c8adb26e8a4b442f1075a427b065433ac5b973b2ccc4ee3b8e82d5c810922ea4653cdc14e46dcfa85141f23d07fdec0a90b53c50ad1a7e9984bed7f9edcbafdb26398c69c6b8cfc8e2cd843c33fc8e54284807eb9abca302946b16dd82f8c428bd446f2cbf9d614e637c377b39d0a8e494b2dab398094aee11cf0109bb82214b11988b5df0943554126d660d3ac776aa1ea044e20f7e63fafddecb80bde3a683d64a074ff3e1dfa99ab5c16575dfe37bc5bb1b180434ccc4853b671a05c36a62b22df77e1482def92e576ea64ebf8d88d91fcadfeabc571ebedd8bc920d15ec18e300d4747b8bc3e8e04eb5afd95d6ff662ec62aa54ce8e23dd1beacfdde93cc03d9bdfffd2412d3255bed6946258c90c5fcfd55f1e9c1ce3bcd26c2b1299c298f941f8992318ca24154da24dee956a867b1f16bd0241a25db9c19f8630ca11035b29ea9cddf894ca239b6fe8c2242ceb61422b395248e8eb
30 // d =
31 // 0x2e1fdefed60f0279cfa2b9288c4ca6709e277621d81b2383bf8c79d3b6b48e76e17469429be7eb6eb02d022831837e6a8b83c71e7bda0c864de47a43cdb605ebb8d5ccb16cb3bd85ee4622f0d69f0f98c24789ffa25ce17fb2cd40586a76acdc280ede59666f2c038e4583b933e873c81bedb018be115398bfcc1f26fc700b2393e6b99f884979bc742886cd206695e4824db1647af4d123cb95724f6507277210c31fa1d929e23c74deb3c1b1457a1b4029e0b83ad9ea8cf1bee362a5e8d6fc546a4e705e73b4c9f8f5486c3c4dcc1e3e812025483a0ef65efe857ea81331256f43345142b3cba4cdb00270c27647b3b8d1185826066b83374bb038098a4e152a95830d621c40e752fc2a22a7bd0a88f7a1e86ae8f2bd3bde3d37027fc735a1f8a09cd55ce7738204a3767a15ce0940fe49e5b63c7a23fa15dae580446884981753730bc0944ac3421f557a1f44a1927863c8051c7f4bd88a71c55225b096ecc52df173bf748b23b332bc608702a398f1624a49919be3408341fecaf3cc45d9
32 
33 // Modulus (n) in little-endian form.
34 static uint32_t kTestModulus[kRsa3072NumWords] = {
35  0x5248e8eb, 0x61422b39, 0xc2242ceb, 0x239b6fe8, 0xddf894ca, 0x5b29ea9c,
36  0x30ca1103, 0xb9c19f86, 0x0241a25d, 0x7b1f16bd, 0xee956a86, 0x154da24d,
37  0x2318ca24, 0xf941f899, 0x1299c298, 0xbcd26c2b, 0x1e9c1ce3, 0x5fcfd55f,
38  0x6258c90c, 0x55bed694, 0xd2412d32, 0x3d9bdfff, 0xdde93cc0, 0xdd1beacf,
39  0x54ce8e23, 0x62ec62aa, 0xd95d6ff6, 0xe04eb5af, 0x7b8bc3e8, 0xe300d474,
40  0x0d15ec18, 0xedd8bc92, 0xabc571eb, 0x91fcadfe, 0xebf8d88d, 0xe576ea64,
41  0x482def92, 0x22df77e1, 0x5c36a62b, 0x53b671a0, 0x434ccc48, 0x5bb1b180,
42  0x5dfe37bc, 0xab5c1657, 0x3e1dfa99, 0x64a074ff, 0xde3a683d, 0xddecb80b,
43  0xf7e63faf, 0xea044e20, 0xac776aa1, 0x26d660d3, 0x09435541, 0x1988b5df,
44  0xb82214b1, 0x1cf0109b, 0x8094aee1, 0x4b2dab39, 0x9d0a8e49, 0x37c377b3,
45  0xf9d614e6, 0xd446f2cb, 0x2f8c428b, 0x46b16dd8, 0xabca3029, 0x84807eb9,
46  0x3fc8e542, 0x2cd843c3, 0x6b8cfc8e, 0x6398c69c, 0xdcbafdb2, 0x4bed7f9e,
47  0xd1a7e998, 0x0b53c50a, 0x7fdec0a9, 0x141f23d0, 0x46dcfa85, 0x53cdc14e,
48  0x0922ea46, 0xe82d5c81, 0xcc4ee3b8, 0x5b973b2c, 0x065433ac, 0x075a427b,
49  0xa4b442f1, 0x8adb26e8, 0xe827fc8c, 0xc6057b0b, 0x1c9f5a53, 0x833bf326,
50  0x7520180f, 0x24ec935f, 0xa90cc23b, 0xafe74287, 0x31261907, 0xa60f30a2,
51 };
52 static uint32_t kTestPrivateExponent[kRsa3072NumWords] = {
53  0xf3cc45d9, 0x8341feca, 0x919be340, 0xf1624a49, 0x8702a398, 0xb332bc60,
54  0xbf748b23, 0xc52df173, 0x25b096ec, 0x8a71c552, 0x1c7f4bd8, 0x7863c805,
55  0x1f44a192, 0x421f557a, 0xc0944ac3, 0x1753730b, 0x44688498, 0x15dae580,
56  0x3c7a23fa, 0xfe49e5b6, 0x15ce0940, 0x04a3767a, 0x5ce77382, 0xf8a09cd5,
57  0x7fc735a1, 0xde3d3702, 0xe8f2bd3b, 0xf7a1e86a, 0xa7bd0a88, 0x52fc2a22,
58  0x621c40e7, 0x2a95830d, 0x098a4e15, 0x374bb038, 0x26066b83, 0xb8d11858,
59  0xc27647b3, 0xcdb00270, 0x42b3cba4, 0x6f433451, 0xa8133125, 0x5efe857e,
60  0x483a0ef6, 0x3e812025, 0x3c4dcc1e, 0xf8f5486c, 0x5e73b4c9, 0x546a4e70,
61  0xa5e8d6fc, 0xf1bee362, 0x3ad9ea8c, 0x4029e0b8, 0xb1457a1b, 0x74deb3c1,
62  0xd929e23c, 0x10c31fa1, 0x65072772, 0xcb95724f, 0x7af4d123, 0x824db164,
63  0x206695e4, 0x742886cd, 0x884979bc, 0x93e6b99f, 0xfc700b23, 0xbfcc1f26,
64  0xbe115398, 0x1bedb018, 0x33e873c8, 0x8e4583b9, 0x666f2c03, 0x280ede59,
65  0x6a76acdc, 0xb2cd4058, 0xa25ce17f, 0xc24789ff, 0xd69f0f98, 0xee4622f0,
66  0x6cb3bd85, 0xb8d5ccb1, 0xcdb605eb, 0x4de47a43, 0x7bda0c86, 0x8b83c71e,
67  0x31837e6a, 0xb02d0228, 0x9be7eb6e, 0xe1746942, 0xb6b48e76, 0xbf8c79d3,
68  0xd81b2383, 0x9e277621, 0x8c4ca670, 0xcfa2b928, 0xd60f0279, 0x2e1fdefe,
69 };
70 static uint32_t kTestPublicExponent = 65537;
71 
72 // Message data for testing.
73 static const unsigned char kTestMessage[] = "Test message.";
74 static const size_t kTestMessageLen = sizeof(kTestMessage) - 1;
75 
76 // Valid signature of `kTestMessage` from the test private key, using PKCS#1
77 // v1.5 padding and SHA-512 as the hash function.
78 static const uint32_t kValidSignaturePkcs1v15[kRsa3072NumWords] = {
79  0xb091ff65, 0xd1edc6a5, 0x574498d4, 0x2d6e34d9, 0xb96eb9fe, 0x48194af9,
80  0x8973e3bd, 0x6f66bc1d, 0x55032373, 0x68d5ced7, 0x87998790, 0xe86f7eb1,
81  0x0f07e31b, 0x2842ada5, 0x2af683ab, 0x55245677, 0x4ac777e8, 0x130aa2d6,
82  0x0f7eebb5, 0x9dfa75db, 0x41bbe218, 0xf4f7a2d7, 0xff153220, 0x6e6cd5e8,
83  0xa44fd6b5, 0xfe085392, 0x60e2b298, 0x1c5f74f4, 0x032e2d39, 0xd1c16723,
84  0xa6ae5514, 0x357c60b7, 0x61a51bbc, 0x009391dd, 0x0142d92e, 0xd1593a14,
85  0xbffd75c3, 0x55fdbde2, 0x40533d4b, 0xb423ded9, 0x83106eee, 0x0a6bd1cc,
86  0x9c85a4cb, 0xfa1da7fe, 0x09b79f0c, 0x6ca08324, 0xa3182ce5, 0x9d9ee66d,
87  0x94213c86, 0x9ac854b3, 0x8803ad55, 0xc3ad2e23, 0x7f11620c, 0x56032b2d,
88  0xac4e36be, 0x553b2d2c, 0xc489cec1, 0x40846292, 0x9b4849fd, 0x0d63a0f4,
89  0x27abfa17, 0xec055e10, 0x310e3ef2, 0x953a6701, 0xf844985e, 0x2944b2df,
90  0x37c9097d, 0xcd40700e, 0x57759607, 0xdda27413, 0x77a65ad3, 0x8752df0c,
91  0x50329618, 0x14b74fa7, 0xc9236c54, 0xb8f07265, 0x5b9efc20, 0x15f5f821,
92  0xde9ca767, 0x34bf1a70, 0xca4d5d9c, 0x92725953, 0x998d1231, 0x73bd12aa,
93  0xc222b65f, 0xde00db56, 0xc9e1aaff, 0xb2d32c27, 0x05b93bb4, 0x94b52732,
94  0xbdc53790, 0x92e62a85, 0xc1cb4a8a, 0xff3fe179, 0x565f6d7f, 0x0f784c4a,
95 };
96 
97 // Valid signature of `kTestMessage` from the test private key, using PSS
98 // padding and SHA-512 as the hash function.
99 static const uint32_t kValidSignaturePss[kRsa3072NumWords] = {
100  0xff478de6, 0x9c32afcc, 0x606818a2, 0x10a3510f, 0x474819ee, 0x04be7c07,
101  0xd8bd7511, 0xcf392927, 0x6883efcd, 0x15986843, 0x26e311b9, 0x27d718ac,
102  0xc507b105, 0xfd519ef7, 0x1dd94e1e, 0x4bc8e633, 0x9c4acb4d, 0x21719940,
103  0x7c7b6449, 0x998cd74f, 0xd33c1989, 0x5ef49d96, 0x63e111b0, 0xcca6d7f5,
104  0x75c80acb, 0x07e8907d, 0x3e9d3fcd, 0x493a518e, 0x73aab881, 0xabdc13cc,
105  0x81ed48f2, 0x12395425, 0x7957265f, 0xde23f84b, 0xa7a51962, 0xbceac204,
106  0x1291a9bd, 0x72c83723, 0x9a110ca7, 0x46db7dcc, 0x8af37092, 0x27e9eacd,
107  0xe37be422, 0xeded8b48, 0xdaa20d27, 0xb855507b, 0xe5d45f30, 0x15d6e2e4,
108  0x795c88c2, 0xa7f130c7, 0x973ce990, 0x282625f7, 0x08f2ce39, 0xd8a2b491,
109  0xea037444, 0x41efd30d, 0x44a69d6a, 0xf59709be, 0xc42b92df, 0x516ab280,
110  0xe2f9c7b4, 0xcf3693a8, 0x9b28d5f3, 0x8cbda1ef, 0xa2a05f13, 0x344858e9,
111  0xb8372f6a, 0x4bdc6efd, 0x90ecabab, 0xdb0589e8, 0x1d59f90f, 0x531cf1f2,
112  0x486f3233, 0x6a946ee8, 0x302a6c49, 0x507dda2b, 0x21287d8f, 0x68ec5762,
113  0x81df3cdb, 0x7f0a0851, 0x69f0e825, 0x3bba8632, 0x6a98b6fd, 0xf0bdd53d,
114  0xc9d928a1, 0x6501fded, 0x0e4d8b0b, 0x11ffdc3a, 0xda6a6fa8, 0x567a7e65,
115  0xe2f6c106, 0x4569d9c9, 0x3d69f35e, 0x6d1ebc67, 0x0f4ecb9a, 0x31628ec0,
116 };
117 
118 /**
119  * Helper function to run the RSA-3072 signing routine.
120  *
121  * Packages input into cryptolib-style structs and calls `otcrypto_rsa_sign`
122  * using the constant test private key. Always uses SHA-512 as the hash
123  * function.
124  *
125  * @param msg Message to sign.
126  * @param msg_len Message length in bytes.
127  * @param padding_mode RSA padding mode.
128  * @param[out] sig Buffer for the generated RSA signature (3072 bits).
129  * @return OK or error.
130  */
131 static status_t run_rsa_3072_sign(const uint8_t *msg, size_t msg_len,
132  otcrypto_rsa_padding_t padding_mode,
133  uint32_t *sig) {
134  otcrypto_key_mode_t key_mode;
135  switch (padding_mode) {
136  case kOtcryptoRsaPaddingPkcs:
137  key_mode = kOtcryptoKeyModeRsaSignPkcs;
138  break;
139  case kOtcryptoRsaPaddingPss:
140  key_mode = kOtcryptoKeyModeRsaSignPss;
141  break;
142  default:
143  return INVALID_ARGUMENT();
144  };
145 
146  // Create two shares for the private exponent (second share is all-zero).
147  otcrypto_const_word32_buf_t d_share0 = {
148  .data = kTestPrivateExponent,
149  .len = ARRAYSIZE(kTestPrivateExponent),
150  };
151  uint32_t share1[ARRAYSIZE(kTestPrivateExponent)] = {0};
152  otcrypto_const_word32_buf_t d_share1 = {
153  .data = share1,
154  .len = ARRAYSIZE(share1),
155  };
156 
157  otcrypto_key_config_t private_key_config = {
158  .version = kOtcryptoLibVersion1,
159  .key_mode = key_mode,
160  .key_length = kOtcryptoRsa3072PrivateKeyBytes,
161  .hw_backed = kHardenedBoolFalse,
162  .security_level = kOtcryptoKeySecurityLevelLow,
163  };
164  size_t keyblob_words =
165  ceil_div(kOtcryptoRsa3072PrivateKeyblobBytes, sizeof(uint32_t));
166  uint32_t keyblob[keyblob_words];
167  otcrypto_blinded_key_t private_key = {
168  .config = private_key_config,
169  .keyblob = keyblob,
170  .keyblob_length = kOtcryptoRsa3072PrivateKeyblobBytes,
171  };
172  otcrypto_const_word32_buf_t modulus = {
173  .data = kTestModulus,
174  .len = ARRAYSIZE(kTestModulus),
175  };
176  TRY(otcrypto_rsa_private_key_from_exponents(kOtcryptoRsaSize3072, modulus,
177  kTestPublicExponent, d_share0,
178  d_share1, &private_key));
179 
180  // Hash the message.
181  otcrypto_const_byte_buf_t msg_buf = {.data = msg, .len = msg_len};
182  uint32_t msg_digest_data[kSha512DigestWords];
183  otcrypto_hash_digest_t msg_digest = {
184  .data = msg_digest_data,
185  .len = ARRAYSIZE(msg_digest_data),
186  .mode = kOtcryptoHashModeSha512,
187  };
188  TRY(otcrypto_hash(msg_buf, msg_digest));
189 
190  otcrypto_word32_buf_t sig_buf = {
191  .data = sig,
192  .len = kRsa3072NumWords,
193  };
194 
195  uint64_t t_start = profile_start();
196  TRY(otcrypto_rsa_sign(&private_key, msg_digest, padding_mode, sig_buf));
197  profile_end_and_print(t_start, "RSA signature generation");
198 
199  return OK_STATUS();
200 }
201 
202 /**
203  * Helper function to run the RSA-3072 verification routine.
204  *
205  * Packages input into cryptolib-style structs and calls `otcrypto_rsa_verify`
206  * using the constant test public key. Always uses SHA-512 as the hash
207  * function.
208  *
209  * @param msg Message to verify.
210  * @param msg_len Message length in bytes.
211  * @param sig Signature to verify
212  * @param padding_mode RSA padding mode.
213  * @param[out] verification_result Whether the signature passed verification.
214  * @return OK or error.
215  */
216 static status_t run_rsa_3072_verify(const uint8_t *msg, size_t msg_len,
217  const uint32_t *sig,
218  const otcrypto_rsa_padding_t padding_mode,
219  hardened_bool_t *verification_result) {
220  otcrypto_key_mode_t key_mode;
221  switch (padding_mode) {
222  case kOtcryptoRsaPaddingPkcs:
223  key_mode = kOtcryptoKeyModeRsaSignPkcs;
224  break;
225  case kOtcryptoRsaPaddingPss:
226  key_mode = kOtcryptoKeyModeRsaSignPss;
227  break;
228  default:
229  return INVALID_ARGUMENT();
230  };
231 
232  // Construct the public key.
233  otcrypto_const_word32_buf_t modulus = {
234  .data = kTestModulus,
235  .len = ARRAYSIZE(kTestModulus),
236  };
237  uint32_t public_key_data[ceil_div(kOtcryptoRsa3072PublicKeyBytes,
238  sizeof(uint32_t))];
239  otcrypto_unblinded_key_t public_key = {
240  .key_mode = key_mode,
241  .key_length = kOtcryptoRsa3072PublicKeyBytes,
242  .key = public_key_data,
243  };
244  TRY(otcrypto_rsa_public_key_construct(kOtcryptoRsaSize3072, modulus,
245  kTestPublicExponent, &public_key));
246 
247  // Hash the message.
248  otcrypto_const_byte_buf_t msg_buf = {.data = msg, .len = msg_len};
249  uint32_t msg_digest_data[kSha512DigestWords];
250  otcrypto_hash_digest_t msg_digest = {
251  .data = msg_digest_data,
252  .len = ARRAYSIZE(msg_digest_data),
253  .mode = kOtcryptoHashModeSha512,
254  };
255  TRY(otcrypto_hash(msg_buf, msg_digest));
256 
257  otcrypto_const_word32_buf_t sig_buf = {
258  .data = sig,
259  .len = kRsa3072NumWords,
260  };
261 
262  uint64_t t_start = profile_start();
263  TRY(otcrypto_rsa_verify(&public_key, msg_digest, padding_mode, sig_buf,
264  verification_result));
265  profile_end_and_print(t_start, "RSA verify");
266 
267  return OK_STATUS();
268 }
269 
270 status_t pkcs1v15_sign_test(void) {
271  // Generate a signature using PKCS#1 v1.5 padding and SHA-512 as the hash
272  // function.
273  uint32_t sig[kRsa3072NumWords];
274  TRY(run_rsa_3072_sign(kTestMessage, kTestMessageLen, kOtcryptoRsaPaddingPkcs,
275  sig));
276 
277  // Compare to the expected signature.
278  TRY_CHECK_ARRAYS_EQ(sig, kValidSignaturePkcs1v15,
279  ARRAYSIZE(kValidSignaturePkcs1v15));
280  return OK_STATUS();
281 }
282 
283 status_t pkcs1v15_verify_valid_test(void) {
284  // Try to verify a valid signature.
285  hardened_bool_t verification_result;
286  TRY(run_rsa_3072_verify(kTestMessage, kTestMessageLen,
287  kValidSignaturePkcs1v15, kOtcryptoRsaPaddingPkcs,
288  &verification_result));
289 
290  // Expect the signature to pass verification.
291  TRY_CHECK(verification_result == kHardenedBoolTrue);
292  return OK_STATUS();
293 }
294 
295 status_t pkcs1v15_verify_invalid_test(void) {
296  // Try to verify an invalid signature (wrong padding mode).
297  hardened_bool_t verification_result;
298  TRY(run_rsa_3072_verify(kTestMessage, kTestMessageLen, kValidSignaturePss,
299  kOtcryptoRsaPaddingPkcs, &verification_result));
300 
301  // Expect the signature to fail verification.
302  TRY_CHECK(verification_result == kHardenedBoolFalse);
303  return OK_STATUS();
304 }
305 
306 status_t pss_sign_test(void) {
307  // PSS signatures are not deterministic, so we need to sign-then-verify.
308  uint32_t sig[kRsa3072NumWords];
309  TRY(run_rsa_3072_sign(kTestMessage, kTestMessageLen, kOtcryptoRsaPaddingPss,
310  sig));
311 
312  // Try to verify the signature.
313  hardened_bool_t verification_result;
314  TRY(run_rsa_3072_verify(kTestMessage, kTestMessageLen, sig,
315  kOtcryptoRsaPaddingPss, &verification_result));
316 
317  // Expect the signature to pass verification.
318  TRY_CHECK(verification_result == kHardenedBoolTrue);
319  return OK_STATUS();
320 }
321 
322 status_t pss_verify_valid_test(void) {
323  // Try to verify a valid signature.
324  hardened_bool_t verification_result;
325  TRY(run_rsa_3072_verify(kTestMessage, kTestMessageLen, kValidSignaturePss,
326  kOtcryptoRsaPaddingPss, &verification_result));
327 
328  // Expect the signature to pass verification.
329  TRY_CHECK(verification_result == kHardenedBoolTrue);
330  return OK_STATUS();
331 }
332 
333 status_t pss_verify_invalid_test(void) {
334  // Try to verify an invalid signature (wrong padding mode).
335  hardened_bool_t verification_result;
336  TRY(run_rsa_3072_verify(kTestMessage, kTestMessageLen,
337  kValidSignaturePkcs1v15, kOtcryptoRsaPaddingPss,
338  &verification_result));
339 
340  // Expect the signature to fail verification.
341  TRY_CHECK(verification_result == kHardenedBoolFalse);
342  return OK_STATUS();
343 }
344 
345 OTTF_DEFINE_TEST_CONFIG();
346 
347 bool test_main(void) {
348  status_t test_result = OK_STATUS();
349  CHECK_STATUS_OK(entropy_complex_init());
350  EXECUTE_TEST(test_result, pkcs1v15_sign_test);
351  EXECUTE_TEST(test_result, pkcs1v15_verify_valid_test);
352  EXECUTE_TEST(test_result, pkcs1v15_verify_invalid_test);
353  EXECUTE_TEST(test_result, pss_sign_test);
354  EXECUTE_TEST(test_result, pss_verify_valid_test);
355  EXECUTE_TEST(test_result, pss_verify_invalid_test);
356  return status_ok(test_result);
357 }