Software APIs
rsa_signature.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_signature.h"
6 
10 #include "sw/device/lib/crypto/drivers/entropy.h"
11 #include "sw/device/lib/crypto/impl/rsa/rsa_modexp.h"
12 #include "sw/device/lib/crypto/impl/rsa/rsa_padding.h"
14 
15 // Module ID for status codes.
16 #define MODULE_ID MAKE_MODULE_ID('r', 's', 'v')
17 
18 /**
19  * Ensure that the digest type matches the length and is supported.
20  *
21  * Accepts only SHA-2 and SHA-3 family hash functions (XOFs such as SHAKE are
22  * not currently supported for RSA). Returns an error if the digest type is
23  * unsupported or the digest buffer is the wrong length.
24  *
25  * @param digest Message digest to check.
26  * @return Result of the operation (OK or BAD_ARGS).
27  */
29 static status_t digest_check(const otcrypto_hash_digest_t digest) {
30  size_t num_words = 0;
31  switch (digest.mode) {
32  case kOtcryptoHashModeSha3_224:
33  num_words = 224 / 32;
34  break;
35  case kOtcryptoHashModeSha256:
37  case kOtcryptoHashModeSha3_256:
38  num_words = 256 / 32;
39  break;
40  case kOtcryptoHashModeSha384:
42  case kOtcryptoHashModeSha3_384:
43  num_words = 384 / 32;
44  break;
45  case kOtcryptoHashModeSha512:
47  case kOtcryptoHashModeSha3_512:
48  num_words = 512 / 32;
49  break;
50  default:
51  return OTCRYPTO_BAD_ARGS;
52  }
53  HARDENED_CHECK_GT(num_words, 0);
54 
55  if (num_words != digest.len) {
56  return OTCRYPTO_BAD_ARGS;
57  }
58  return OTCRYPTO_OK;
59 }
60 
61 /**
62  * Encode the message with the provided padding mode and hash function.
63  *
64  * @param message_digest Message digest to encode.
65  * @param padding_mode Signature padding mode.
66  * @param encoded_message_len Encoded message length in 32-bit words.
67  * @param[out] encoded_message Encoded message.
68  * @return Result of the operation (OK or error).
69  */
71 static status_t message_encode(const otcrypto_hash_digest_t message_digest,
72  const rsa_signature_padding_t padding_mode,
73  size_t encoded_message_len,
74  uint32_t *encoded_message) {
75  // Check that the digest length is OK.
76  HARDENED_TRY(digest_check(message_digest));
77 
78  switch (padding_mode) {
79  case kRsaSignaturePaddingPkcs1v15:
80  return rsa_padding_pkcs1v15_encode(message_digest, encoded_message_len,
81  encoded_message);
82  case kRsaSignaturePaddingPss: {
83  // Generate a random salt value whose length matches the digest length.
84  uint32_t salt[message_digest.len];
85  HARDENED_TRY(entropy_complex_check());
86  HARDENED_TRY(entropy_csrng_uninstantiate());
87  HARDENED_TRY(entropy_csrng_instantiate(
88  /*disable_trng_input=*/kHardenedBoolFalse, &kEntropyEmptySeed));
89  HARDENED_TRY(entropy_csrng_generate(&kEntropyEmptySeed, salt,
90  ARRAYSIZE(salt),
91  /*fips_check=*/kHardenedBoolTrue));
92  HARDENED_TRY(entropy_csrng_uninstantiate());
93  return rsa_padding_pss_encode(message_digest, salt, ARRAYSIZE(salt),
94  encoded_message_len, encoded_message);
95  }
96  default:
97  // Unrecognized padding mode.
98  return OTCRYPTO_BAD_ARGS;
99  }
100 
101  // Unreachable.
102  HARDENED_TRAP();
103  return OTCRYPTO_FATAL_ERR;
104 }
105 
106 /**
107  * Check if the encoded message represents the message.
108  *
109  * If the encoded message does not match the message, this function will return
110  * an OK status and write `kHardenedBoolFalse` into the result buffer. The
111  * caller should not interpret an OK status as a match between the encoded and
112  * raw messages, since the status return value is reserved for operational or
113  * logical error codes.
114  *
115  * @param message_digest Message digest to verify.
116  * @param padding_mode Signature padding mode.
117  * @param encoded_message Encoded message.
118  * @param encoded_message_len Encoded message length in 32-bit words.
119  * @param[out] result True if the check passed.
120  * @return Result of the operation (OK or error).
121  */
123 static status_t encoded_message_verify(
124  const otcrypto_hash_digest_t message_digest,
125  const rsa_signature_padding_t padding_mode, uint32_t *encoded_message,
126  const size_t encoded_message_len, hardened_bool_t *result) {
127  // Check that the digest length is OK.
128  HARDENED_TRY(digest_check(message_digest));
129 
130  switch (padding_mode) {
131  case kRsaSignaturePaddingPkcs1v15:
132  return rsa_padding_pkcs1v15_verify(message_digest, encoded_message,
133  encoded_message_len, result);
134  case kRsaSignaturePaddingPss:
135  return rsa_padding_pss_verify(message_digest, encoded_message,
136  encoded_message_len, result);
137  default:
138  // Unrecognized padding mode.
139  return OTCRYPTO_BAD_ARGS;
140  }
141 
142  // Unreachable.
143  HARDENED_TRAP();
144  return OTCRYPTO_FATAL_ERR;
145 }
146 
147 status_t rsa_signature_generate_2048_start(
148  const rsa_2048_private_key_t *private_key,
149  const otcrypto_hash_digest_t message_digest,
150  const rsa_signature_padding_t padding_mode) {
151  // Encode the message.
152  rsa_2048_int_t encoded_message;
153  HARDENED_TRY(message_encode(message_digest, padding_mode,
154  ARRAYSIZE(encoded_message.data),
155  encoded_message.data));
156 
157  // Start computing (encoded_message ^ d) mod n.
158  return rsa_modexp_consttime_2048_start(&encoded_message, &private_key->d,
159  &private_key->n);
160 }
161 
162 status_t rsa_signature_generate_2048_finalize(rsa_2048_int_t *signature) {
163  return rsa_modexp_2048_finalize(signature);
164 }
165 
166 status_t rsa_signature_verify_2048_start(
167  const rsa_2048_public_key_t *public_key, const rsa_2048_int_t *signature) {
168  // Start computing (sig ^ e) mod n with a variable-time exponentiation.
169  return rsa_modexp_vartime_2048_start(signature, public_key->e,
170  &public_key->n);
171 }
172 
173 status_t rsa_signature_verify_finalize(
174  const otcrypto_hash_digest_t message_digest,
175  const rsa_signature_padding_t padding_mode,
176  hardened_bool_t *verification_result) {
177  // Wait for OTBN to complete and get the size for the last RSA operation.
178  size_t num_words;
179  HARDENED_TRY(rsa_modexp_wait(&num_words));
180 
181  // Call the appropriate `finalize()` operation to get the recovered encoded
182  // message.
183  switch (num_words) {
184  case kRsa2048NumWords: {
185  rsa_2048_int_t recovered_message;
186  HARDENED_TRY(rsa_modexp_2048_finalize(&recovered_message));
187  return encoded_message_verify(
188  message_digest, padding_mode, recovered_message.data,
189  ARRAYSIZE(recovered_message.data), verification_result);
190  }
191  case kRsa3072NumWords: {
192  rsa_3072_int_t recovered_message;
193  HARDENED_TRY(rsa_modexp_3072_finalize(&recovered_message));
194  return encoded_message_verify(
195  message_digest, padding_mode, recovered_message.data,
196  ARRAYSIZE(recovered_message.data), verification_result);
197  }
198  case kRsa4096NumWords: {
199  rsa_4096_int_t recovered_message;
200  HARDENED_TRY(rsa_modexp_4096_finalize(&recovered_message));
201  return encoded_message_verify(
202  message_digest, padding_mode, recovered_message.data,
203  ARRAYSIZE(recovered_message.data), verification_result);
204  }
205  default:
206  // Unexpected number of words; should never get here.
207  return OTCRYPTO_FATAL_ERR;
208  }
209 
210  // Should be unreachable.
211  HARDENED_TRAP();
212  return OTCRYPTO_FATAL_ERR;
213 }
214 
215 status_t rsa_signature_generate_3072_start(
216  const rsa_3072_private_key_t *private_key,
217  const otcrypto_hash_digest_t message_digest,
218  const rsa_signature_padding_t padding_mode) {
219  // Encode the message.
220  rsa_3072_int_t encoded_message;
221  HARDENED_TRY(message_encode(message_digest, padding_mode,
222  ARRAYSIZE(encoded_message.data),
223  encoded_message.data));
224 
225  // Start computing (encoded_message ^ d) mod n.
226  return rsa_modexp_consttime_3072_start(&encoded_message, &private_key->d,
227  &private_key->n);
228 }
229 
230 status_t rsa_signature_generate_3072_finalize(rsa_3072_int_t *signature) {
231  return rsa_modexp_3072_finalize(signature);
232 }
233 
234 status_t rsa_signature_verify_3072_start(
235  const rsa_3072_public_key_t *public_key, const rsa_3072_int_t *signature) {
236  // Start computing (sig ^ e) mod n with a variable-time exponentiation.
237  return rsa_modexp_vartime_3072_start(signature, public_key->e,
238  &public_key->n);
239 }
240 
241 status_t rsa_signature_generate_4096_start(
242  const rsa_4096_private_key_t *private_key,
243  const otcrypto_hash_digest_t message_digest,
244  const rsa_signature_padding_t padding_mode) {
245  // Encode the message.
246  rsa_4096_int_t encoded_message;
247  HARDENED_TRY(message_encode(message_digest, padding_mode,
248  ARRAYSIZE(encoded_message.data),
249  encoded_message.data));
250 
251  // Start computing (encoded_message ^ d) mod n.
252  return rsa_modexp_consttime_4096_start(&encoded_message, &private_key->d,
253  &private_key->n);
254 }
255 
256 status_t rsa_signature_generate_4096_finalize(rsa_4096_int_t *signature) {
257  return rsa_modexp_4096_finalize(signature);
258 }
259 
260 status_t rsa_signature_verify_4096_start(
261  const rsa_4096_public_key_t *public_key, const rsa_4096_int_t *signature) {
262  // Start computing (sig ^ e) mod n with a variable-time exponentiation.
263  return rsa_modexp_vartime_4096_start(signature, public_key->e,
264  &public_key->n);
265 }