Software APIs
rsa_4096_keygen_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/otbn.h"
7 #include "sw/device/lib/crypto/impl/rsa/rsa_datatypes.h"
12 #include "sw/device/lib/testing/entropy_testutils.h"
13 #include "sw/device/lib/testing/test_framework/check.h"
15 
16 // Module for status messages.
17 #define MODULE_ID MAKE_MODULE_ID('t', 's', 't')
18 
19 // Message data for testing.
20 static const unsigned char kTestMessage[] = "Test message.";
21 static const size_t kTestMessageLen = sizeof(kTestMessage) - 1;
22 
23 // RSA key mode for testing.
24 static const otcrypto_key_mode_t kTestKeyMode = kOtcryptoKeyModeRsaSignPkcs;
25 
26 status_t keygen_then_sign_test(void) {
27  // Allocate buffer for the public key.
28  uint32_t public_key_data[ceil_div(kOtcryptoRsa4096PublicKeyBytes,
29  sizeof(uint32_t))];
30  memset(public_key_data, 0, sizeof(public_key_data));
31  otcrypto_unblinded_key_t public_key = {
32  .key_mode = kTestKeyMode,
33  .key_length = kOtcryptoRsa4096PublicKeyBytes,
34  .key = public_key_data,
35  };
36 
37  // Allocate buffers for the private key.
38  size_t keyblob_words =
39  ceil_div(kOtcryptoRsa4096PrivateKeyblobBytes, sizeof(uint32_t));
40  uint32_t keyblob[keyblob_words];
41  memset(keyblob, 0, sizeof(keyblob));
42  otcrypto_blinded_key_t private_key = {
43  .config =
44  {
45  .version = kOtcryptoLibVersion1,
46  .key_mode = kTestKeyMode,
47  .key_length = kOtcryptoRsa4096PrivateKeyBytes,
48  .hw_backed = kHardenedBoolFalse,
49  .security_level = kOtcryptoKeySecurityLevelLow,
50  },
51  .keyblob_length = kOtcryptoRsa4096PrivateKeyblobBytes,
52  .keyblob = keyblob,
53  };
54 
55  // Generate the key pair.
56  LOG_INFO("Starting keypair generation...");
57  TRY(otcrypto_rsa_keygen(kOtcryptoRsaSize4096, &public_key, &private_key));
58  LOG_INFO("Keypair generation complete.");
59  LOG_INFO("OTBN instruction count: %u", otbn_instruction_count_get());
60 
61  // Interpret public key using internal RSA datatype.
62  TRY_CHECK(public_key.key_length == sizeof(rsa_4096_public_key_t));
63  rsa_4096_public_key_t *pk = (rsa_4096_public_key_t *)public_key.key;
64 
65  // Interpret private key using internal RSA datatype.
66  TRY_CHECK(private_key.keyblob_length == sizeof(rsa_4096_private_key_t));
67  rsa_4096_private_key_t *sk = (rsa_4096_private_key_t *)private_key.keyblob;
68 
69  // Check that the key uses the F4 exponent.
70  TRY_CHECK(pk->e == 65537);
71 
72  // Check that the moduli match.
73  TRY_CHECK(ARRAYSIZE(pk->n.data) == ARRAYSIZE(sk->n.data));
74  TRY_CHECK_ARRAYS_EQ(pk->n.data, sk->n.data, ARRAYSIZE(pk->n.data));
75 
76  // Check that d is at least 2^(len(n) / 2) (this is a FIPS requirement) by
77  // ensuring that the most significant half is nonzero.
78  bool d_large_enough = false;
79  for (size_t i = kRsa4096NumWords / 2; i < kRsa4096NumWords; i++) {
80  if (sk->d.data[i] != 0) {
81  d_large_enough = true;
82  }
83  }
84  TRY_CHECK(d_large_enough);
85 
86  // Hash the message.
87  otcrypto_const_byte_buf_t msg_buf = {
88  .len = kTestMessageLen,
89  .data = kTestMessage,
90  };
91  uint32_t msg_digest_data[kSha512DigestWords];
92  otcrypto_hash_digest_t msg_digest = {
93  .data = msg_digest_data,
94  .len = ARRAYSIZE(msg_digest_data),
95  .mode = kOtcryptoHashModeSha512,
96  };
97  TRY(otcrypto_hash(msg_buf, msg_digest));
98 
99  uint32_t sig[kRsa4096NumWords];
100  otcrypto_word32_buf_t sig_buf = {
101  .data = sig,
102  .len = kRsa4096NumWords,
103  };
104  otcrypto_const_word32_buf_t const_sig_buf = {
105  .data = sig,
106  .len = kRsa4096NumWords,
107  };
108 
109  // Generate a signature.
110  LOG_INFO("Starting signature generation...");
111  TRY(otcrypto_rsa_sign(&private_key, msg_digest, kOtcryptoRsaPaddingPkcs,
112  sig_buf));
113  LOG_INFO("Signature generation complete.");
114  LOG_INFO("OTBN instruction count: %u", otbn_instruction_count_get());
115 
116  // Try to verify the signature. If something is wrong with the key (nonprime
117  // p and q, incorrect d), then this is likely to fail.
118  LOG_INFO("Starting signature verification...");
119  hardened_bool_t verification_result;
120  TRY(otcrypto_rsa_verify(&public_key, msg_digest, kOtcryptoRsaPaddingPkcs,
121  const_sig_buf, &verification_result));
122  LOG_INFO("Signature verification complete.");
123  LOG_INFO("OTBN instruction count: %u", otbn_instruction_count_get());
124 
125  // Expect the signature to pass verification.
126  TRY_CHECK(verification_result == kHardenedBoolTrue);
127  return OK_STATUS();
128 }
129 
130 OTTF_DEFINE_TEST_CONFIG();
131 
132 bool test_main(void) {
133  CHECK_STATUS_OK(entropy_testutils_auto_mode_init());
134 
135  status_t test_result = OK_STATUS();
136  EXECUTE_TEST(test_result, keygen_then_sign_test);
137  return status_ok(test_result);
138 }