Software APIs
rsa_keygen.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 
5 #include "sw/device/lib/crypto/impl/rsa/rsa_keygen.h"
6 
9 #include "sw/device/lib/crypto/drivers/otbn.h"
10 
11 // Module ID for status codes.
12 #define MODULE_ID MAKE_MODULE_ID('r', 'k', 'g')
13 
14 // Declare the OTBN app.
15 OTBN_DECLARE_APP_SYMBOLS(run_rsa_keygen);
16 static const otbn_app_t kOtbnAppRsaKeygen = OTBN_APP_T_INIT(run_rsa_keygen);
17 
18 // Declare offsets for input and output buffers.
19 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_keygen, mode); // Application mode.
20 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_keygen, rsa_n); // Public exponent n.
21 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_keygen, rsa_d); // Private exponent d.
22 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_keygen, rsa_cofactor); // Cofactor p or q.
23 
24 static const otbn_addr_t kOtbnVarRsaMode =
25  OTBN_ADDR_T_INIT(run_rsa_keygen, mode);
26 static const otbn_addr_t kOtbnVarRsaN = OTBN_ADDR_T_INIT(run_rsa_keygen, rsa_n);
27 static const otbn_addr_t kOtbnVarRsaD = OTBN_ADDR_T_INIT(run_rsa_keygen, rsa_d);
28 static const otbn_addr_t kOtbnVarRsaCofactor =
29  OTBN_ADDR_T_INIT(run_rsa_keygen, rsa_cofactor);
30 
31 // Declare mode constants.
32 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_keygen, MODE_GEN_RSA_2048);
33 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_keygen, MODE_COFACTOR_RSA_2048);
34 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_keygen, MODE_GEN_RSA_3072);
35 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_keygen, MODE_GEN_RSA_4096);
36 static const uint32_t kOtbnRsaModeGen2048 =
37  OTBN_ADDR_T_INIT(run_rsa_keygen, MODE_GEN_RSA_2048);
38 static const uint32_t kOtbnRsaModeCofactor2048 =
39  OTBN_ADDR_T_INIT(run_rsa_keygen, MODE_COFACTOR_RSA_2048);
40 static const uint32_t kOtbnRsaModeGen3072 =
41  OTBN_ADDR_T_INIT(run_rsa_keygen, MODE_GEN_RSA_3072);
42 static const uint32_t kOtbnRsaModeGen4096 =
43  OTBN_ADDR_T_INIT(run_rsa_keygen, MODE_GEN_RSA_4096);
44 
45 enum {
46  /* Fixed public exponent for generated keys. This exponent is 2^16 + 1, also
47  known as "F4" because it's the fourth Fermat number. */
48  kFixedPublicExponent = 65537,
49  /* Number of words used to represent the application mode. */
50  kOtbnRsaModeWords = 1,
51 };
52 
53 /**
54  * Start the OTBN key generation program in random-key mode.
55  *
56  * Cofactor mode should not use this routine, because it wipes DMEM and
57  * cofactor mode requires input data.
58  *
59  * @param mode Mode parameter for keygen.
60  * @return Result of the operation.
61  */
62 static status_t keygen_start(uint32_t mode) {
63  // Load the RSA key generation app. Fails if OTBN is non-idle.
64  HARDENED_TRY(otbn_load_app(kOtbnAppRsaKeygen));
65 
66  // Set mode and start OTBN.
67  HARDENED_TRY(otbn_dmem_write(kOtbnRsaModeWords, &mode, kOtbnVarRsaMode));
68  return otbn_execute();
69 }
70 
71 /**
72  * Finalize a key generation operation (for either mode).
73  *
74  * Checks the application mode against expectations, then reads back the
75  * modulus and private exponent.
76  *
77  * @param exp_mode Application mode to expect.
78  * @param num_words Number of words for modulus and private exponent.
79  * @param[out] n Buffer for the modulus.
80  * @param[out] d Buffer for the private exponent.
81  * @return OK or error.
82  */
83 static status_t keygen_finalize(uint32_t exp_mode, size_t num_words,
84  uint32_t *n, uint32_t *d) {
85  // Spin here waiting for OTBN to complete.
86  HARDENED_TRY(otbn_busy_wait_for_done());
87 
88  // Read the mode from OTBN dmem and panic if it's not as expected.
89  uint32_t act_mode = 0;
90  HARDENED_TRY(otbn_dmem_read(1, kOtbnVarRsaMode, &act_mode));
91  if (act_mode != exp_mode) {
92  return OTCRYPTO_FATAL_ERR;
93  }
94 
95  // Read the public modulus (n) from OTBN dmem.
96  HARDENED_TRY(otbn_dmem_read(num_words, kOtbnVarRsaN, n));
97 
98  // Read the private exponent (d) from OTBN dmem.
99  HARDENED_TRY(otbn_dmem_read(num_words, kOtbnVarRsaD, d));
100 
101  // Wipe DMEM.
102  HARDENED_TRY(otbn_dmem_sec_wipe());
103 
104  return OTCRYPTO_OK;
105 }
106 
107 status_t rsa_keygen_2048_start(void) {
108  return keygen_start(kOtbnRsaModeGen2048);
109 }
110 
111 status_t rsa_keygen_2048_finalize(rsa_2048_public_key_t *public_key,
112  rsa_2048_private_key_t *private_key) {
113  HARDENED_TRY(keygen_finalize(kOtbnRsaModeGen2048, kRsa2048NumWords,
114  private_key->n.data, private_key->d.data));
115 
116  // Copy the modulus to the public key.
117  hardened_memcpy(public_key->n.data, private_key->n.data,
118  ARRAYSIZE(private_key->n.data));
119 
120  // Set the public exponent to F4, the only exponent our key generation
121  // algorithm supports.
122  public_key->e = kFixedPublicExponent;
123 
124  return OTCRYPTO_OK;
125 }
126 
127 status_t rsa_keygen_3072_start(void) {
128  return keygen_start(kOtbnRsaModeGen3072);
129 }
130 
131 status_t rsa_keygen_3072_finalize(rsa_3072_public_key_t *public_key,
132  rsa_3072_private_key_t *private_key) {
133  HARDENED_TRY(keygen_finalize(kOtbnRsaModeGen3072, kRsa3072NumWords,
134  private_key->n.data, private_key->d.data));
135 
136  // Copy the modulus to the public key.
137  hardened_memcpy(public_key->n.data, private_key->n.data,
138  ARRAYSIZE(private_key->n.data));
139 
140  // Set the public exponent to F4, the only exponent our key generation
141  // algorithm supports.
142  public_key->e = kFixedPublicExponent;
143 
144  return OTCRYPTO_OK;
145 }
146 
147 status_t rsa_keygen_4096_start(void) {
148  return keygen_start(kOtbnRsaModeGen4096);
149 }
150 
151 status_t rsa_keygen_4096_finalize(rsa_4096_public_key_t *public_key,
152  rsa_4096_private_key_t *private_key) {
153  HARDENED_TRY(keygen_finalize(kOtbnRsaModeGen4096, kRsa4096NumWords,
154  private_key->n.data, private_key->d.data));
155 
156  // Copy the modulus to the public key.
157  hardened_memcpy(public_key->n.data, private_key->n.data,
158  ARRAYSIZE(private_key->n.data));
159 
160  // Set the public exponent to F4, the only exponent our key generation
161  // algorithm supports.
162  public_key->e = kFixedPublicExponent;
163 
164  return OTCRYPTO_OK;
165 }
166 
167 status_t rsa_keygen_from_cofactor_2048_start(
168  const rsa_2048_public_key_t *public_key,
169  const rsa_2048_cofactor_t *cofactor) {
170  // Only the exponent F4 is supported.
171  if (public_key->e != kFixedPublicExponent) {
172  return OTCRYPTO_BAD_ARGS;
173  }
174 
175  // Load the RSA key generation app. Fails if OTBN is non-idle.
176  HARDENED_TRY(otbn_load_app(kOtbnAppRsaKeygen));
177 
178  // Write the modulus and cofactor into DMEM.
179  HARDENED_TRY(otbn_dmem_write(ARRAYSIZE(public_key->n.data),
180  public_key->n.data, kOtbnVarRsaN));
181  HARDENED_TRY(otbn_dmem_write(ARRAYSIZE(cofactor->data), cofactor->data,
182  kOtbnVarRsaCofactor));
183 
184  // Set mode and start OTBN.
185  uint32_t mode = kOtbnRsaModeCofactor2048;
186  HARDENED_TRY(otbn_dmem_write(kOtbnRsaModeWords, &mode, kOtbnVarRsaMode));
187  return otbn_execute();
188 }
189 
190 status_t rsa_keygen_from_cofactor_2048_finalize(
191  rsa_2048_public_key_t *public_key, rsa_2048_private_key_t *private_key) {
192  HARDENED_TRY(keygen_finalize(kOtbnRsaModeCofactor2048, kRsa2048NumWords,
193  private_key->n.data, private_key->d.data));
194 
195  // Copy the modulus to the public key.
196  hardened_memcpy(public_key->n.data, private_key->n.data,
197  ARRAYSIZE(private_key->n.data));
198 
199  // Set the public exponent to F4, the only exponent our key generation
200  // algorithm supports.
201  public_key->e = kFixedPublicExponent;
202 
203  return OTCRYPTO_OK;
204 }