Software APIs
rsa_3072_verify.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_3072_verify.h"
6 
10 #include "sw/device/lib/crypto/drivers/otbn.h"
11 #include "sw/device/lib/crypto/impl/status.h"
13 
15 
16 // Module ID for status codes.
17 #define MODULE_ID MAKE_MODULE_ID('r', '3', 'v')
18 
19 OTBN_DECLARE_APP_SYMBOLS(run_rsa_verify_3072); // The OTBN RSA-3072 app.
20 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_verify_3072,
21  mode); // Mode (constants or modexp).
22 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_verify_3072,
23  out_buf); // Output buffer (message).
24 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_verify_3072, in_mod); // The RSA modulus (n).
25 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_verify_3072, in_buf); // The signature (s).
26 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_verify_3072,
27  rr); // The Montgomery constant R^2.
28 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_verify_3072,
29  m0inv); // The Montgomery constant m0_inv.
30 
31 static const otbn_app_t kOtbnAppRsa = OTBN_APP_T_INIT(run_rsa_verify_3072);
32 static const otbn_addr_t kOtbnVarRsaMode =
33  OTBN_ADDR_T_INIT(run_rsa_verify_3072, mode);
34 static const otbn_addr_t kOtbnVarRsaOutBuf =
35  OTBN_ADDR_T_INIT(run_rsa_verify_3072, out_buf);
36 static const otbn_addr_t kOtbnVarRsaInMod =
37  OTBN_ADDR_T_INIT(run_rsa_verify_3072, in_mod);
38 static const otbn_addr_t kOtbnVarRsaInBuf =
39  OTBN_ADDR_T_INIT(run_rsa_verify_3072, in_buf);
40 static const otbn_addr_t kOtbnVarRsaRR =
41  OTBN_ADDR_T_INIT(run_rsa_verify_3072, rr);
42 static const otbn_addr_t kOtbnVarRsaM0Inv =
43  OTBN_ADDR_T_INIT(run_rsa_verify_3072, m0inv);
44 
45 /* Mode is represented by a single word: 1=constant computation, 2=modexp */
46 static const uint32_t kOtbnRsaModeNumWords = 1;
47 static const uint32_t kOtbnRsaModeConstants = 1;
48 static const uint32_t kOtbnRsaModeModexp = 2;
49 
50 status_t rsa_3072_encode_sha256(const uint8_t *msg, size_t msgLen,
51  rsa_3072_int_t *result) {
52  if (msg == NULL && msgLen != 0) {
53  return OTCRYPTO_BAD_ARGS;
54  }
55 
56  // Message encoding as described in RFC 8017, Section 9.2. The encoded
57  // message is:
58  //
59  // EM = 0x00 || 0x01 || PS || 0x00 || T,
60  //
61  // where PS is padding made of enough 0xff bytes to meet the desired
62  // message length emLen (emLen = 384 bytes for RSA-3072), and T is the DER
63  // encoding of the digest. For SHA-256,
64  //
65  // T = (0x)30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || H,
66  //
67  // where H is the 256-bit message digest from SHA-256.
68  //
69  // Note that the RFC document is using a big-endian representation; here we
70  // are using little-endian, so the bytes are reversed.
71 
72  // Initially set all bits of the result; we will change the ones that are not
73  // part of PS.
74  memset(result->data, 0xff, sizeof(result->data));
75 
76  // Set 0x00 || 0x01 bytes at most significant end
77  result->data[kRsa3072NumWords - 1] = 0x0001ffff;
78 
79  // Hash message.
80  otcrypto_const_byte_buf_t msg_buf = {
81  .data = msg,
82  .len = msgLen,
83  };
84  uint32_t digest_buf[kSha256DigestWords];
85  otcrypto_hash_digest_t digest = {
86  .mode = kOtcryptoHashModeSha256,
87  .data = digest_buf,
88  .len = kSha256DigestWords,
89  };
90  TRY(otcrypto_hash(msg_buf, digest));
91 
92  // Copy the message digest into the least significant end of the result,
93  // reversing the order of bytes to get little-endian form.
94  for (size_t i = 0; i < kHmacSha256DigestWords; i++) {
95  result->data[i] =
96  __builtin_bswap32(digest.data[kHmacSha256DigestWords - 1 - i]);
97  }
98 
99  // Set remainder of 0x00 || T section
100  result->data[kHmacSha256DigestWords] = 0x05000420;
101  result->data[kHmacSha256DigestWords + 1] = 0x03040201;
102  result->data[kHmacSha256DigestWords + 2] = 0x86480165;
103  result->data[kHmacSha256DigestWords + 3] = 0x0d060960;
104  result->data[kHmacSha256DigestWords + 4] = 0x00303130;
105 
106  return OTCRYPTO_OK;
107 }
108 
109 /**
110  * Copies a 3072-bit number from the CPU memory to OTBN data memory.
111  *
112  * @param otbn The OTBN context object.
113  * @param src Source of the data to copy.
114  * @param dst Address of the destination in OTBN's data memory.
115  * @return The result of the operation.
116  */
117 status_t write_rsa_3072_int_to_otbn(const rsa_3072_int_t *src,
118  otbn_addr_t dst) {
119  return otbn_dmem_write(kRsa3072NumWords, src->data, dst);
120 }
121 
122 /**
123  * Copies a 3072-bit number from OTBN data memory to CPU memory.
124  *
125  * @param otbn The OTBN context object.
126  * @param src The address in OTBN data memory to copy from.
127  * @param dst The destination of the copied data in main memory (preallocated).
128  * @return The result of the operation.
129  */
130 status_t read_rsa_3072_int_from_otbn(otbn_addr_t src, rsa_3072_int_t *dst) {
131  return otbn_dmem_read(kRsa3072NumWords, src, dst->data);
132 }
133 
134 status_t rsa_3072_compute_constants(const rsa_3072_public_key_t *public_key,
135  rsa_3072_constants_t *result) {
136  // Load the RSA app. Fails if OTBN is non-idle.
137  HARDENED_TRY(otbn_load_app(kOtbnAppRsa));
138 
139  // Set mode to compute constants.
140  HARDENED_TRY(otbn_dmem_write(kOtbnRsaModeNumWords, &kOtbnRsaModeConstants,
141  kOtbnVarRsaMode));
142 
143  // Set the modulus (n).
144  HARDENED_TRY(write_rsa_3072_int_to_otbn(&public_key->n, kOtbnVarRsaInMod));
145 
146  // Start the OTBN routine.
147  HARDENED_TRY(otbn_execute());
148 
149  // Spin here waiting for OTBN to complete.
150  HARDENED_TRY(otbn_busy_wait_for_done());
151 
152  // Read constant rr out of DMEM.
153  HARDENED_TRY(read_rsa_3072_int_from_otbn(kOtbnVarRsaRR, &result->rr));
154 
155  // Read constant m0_inv out of DMEM.
156  HARDENED_TRY(
157  otbn_dmem_read(kOtbnWideWordNumWords, kOtbnVarRsaM0Inv, result->m0_inv));
158 
159  return OTCRYPTO_OK;
160 }
161 
162 status_t rsa_3072_verify_start(const rsa_3072_int_t *signature,
163  const rsa_3072_public_key_t *public_key,
164  const rsa_3072_constants_t *constants) {
165  // Only the F4 modulus is supported.
166  if (public_key->e != 65537) {
167  return OTCRYPTO_BAD_ARGS;
168  }
169 
170  // Reject the signature if it is too large (n <= sig): RFC 8017, section
171  // 5.2.2, step 1.
172  if (memrcmp(public_key->n.data, signature->data, kRsa3072NumBytes) <= 0) {
173  return OTCRYPTO_BAD_ARGS;
174  }
175 
176  // Load the RSA app. Fails if OTBN is non-idle.
177  HARDENED_TRY(otbn_load_app(kOtbnAppRsa));
178 
179  // Set mode to perform modular exponentiation.
180  HARDENED_TRY(otbn_dmem_write(kOtbnRsaModeNumWords, &kOtbnRsaModeModexp,
181  kOtbnVarRsaMode));
182 
183  // Set the modulus (n).
184  HARDENED_TRY(write_rsa_3072_int_to_otbn(&public_key->n, kOtbnVarRsaInMod));
185 
186  // Set the signature.
187  HARDENED_TRY(write_rsa_3072_int_to_otbn(signature, kOtbnVarRsaInBuf));
188 
189  // Set the precomputed constant R^2.
190  HARDENED_TRY(write_rsa_3072_int_to_otbn(&constants->rr, kOtbnVarRsaRR));
191 
192  // Set the precomputed constant m0_inv.
193  HARDENED_TRY(otbn_dmem_write(kOtbnWideWordNumWords, constants->m0_inv,
194  kOtbnVarRsaM0Inv));
195 
196  // Start the OTBN routine.
197  HARDENED_TRY(otbn_execute());
198 
199  return OTCRYPTO_OK;
200 }
201 
202 status_t rsa_3072_verify_finalize(const rsa_3072_int_t *message,
203  hardened_bool_t *result) {
204  // Initially set the result to false in case of early returns due to invalid
205  // arguments.
206  *result = kHardenedBoolFalse;
207 
208  // Spin here waiting for OTBN to complete.
209  HARDENED_TRY(otbn_busy_wait_for_done());
210 
211  // Read recovered message out of OTBN dmem.
212  rsa_3072_int_t recoveredMessage;
213  HARDENED_TRY(
214  read_rsa_3072_int_from_otbn(kOtbnVarRsaOutBuf, &recoveredMessage));
215 
216  // TODO: harden this memory comparison
217  // Check if recovered message matches expectation
218  *result = kHardenedBoolTrue;
219  for (int i = 0; i < kRsa3072NumWords; i++) {
220  if (recoveredMessage.data[i] != message->data[i]) {
221  *result = kHardenedBoolFalse;
222  }
223  }
224 
225  return OTCRYPTO_OK;
226 }
227 
228 status_t rsa_3072_verify(const rsa_3072_int_t *signature,
229  const rsa_3072_int_t *message,
230  const rsa_3072_public_key_t *public_key,
231  const rsa_3072_constants_t *constants,
232  hardened_bool_t *result) {
233  // Initially set the result to false in case of early returns due to invalid
234  // arguments.
235  *result = kHardenedBoolFalse;
236 
237  // Initiate OTBN signature verification.
238  HARDENED_TRY(rsa_3072_verify_start(signature, public_key, constants));
239 
240  // Wait for OTBN operations to complete and signature to be verified.
241  return rsa_3072_verify_finalize(message, result);
242 }