Software APIs
otbn_sca.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/tests/penetrationtests/firmware/sca/otbn_sca.h"
6 
7 #include "ecc256_keygen_sca.h"
10 #include "sw/device/lib/base/status.h"
11 #include "sw/device/lib/crypto/drivers/keymgr.h"
12 #include "sw/device/lib/crypto/impl/keyblob.h"
13 #include "sw/device/lib/crypto/impl/status.h"
16 #include "sw/device/lib/testing/entropy_testutils.h"
17 #include "sw/device/lib/testing/keymgr_testutils.h"
18 #include "sw/device/lib/testing/test_framework/ottf_test_config.h"
19 #include "sw/device/lib/testing/test_framework/ujson_ottf.h"
20 #include "sw/device/lib/ujson/ujson.h"
21 #include "sw/device/sca/lib/prng.h"
22 #include "sw/device/tests/penetrationtests/firmware/lib/pentest_lib.h"
23 #include "sw/device/tests/penetrationtests/json/otbn_sca_commands.h"
24 
26 #include "otbn_regs.h" // Generated.
27 
28 static dif_otbn_t otbn;
29 static dif_keymgr_t keymgr;
30 static dif_kmac_t kmac;
31 
32 enum {
33  kKeySideloadNumIt = 16,
34  /**
35  * Number of bytes for ECDSA P-256 private keys, message digests, and point
36  * coordinates.
37  */
38  kEcc256NumBytes = 256 / 8,
39  /**
40  * Number of 32b words for ECDSA P-256 private keys, message digests, and
41  * point coordinates.
42  */
43  kEcc256NumWords = kEcc256NumBytes / sizeof(uint32_t),
44  /**
45  * Max number of traces per batch.
46  */
47  kNumBatchOpsMax = 256,
48 };
49 
50 // Data structs for key sideloading test.
51 OTBN_DECLARE_APP_SYMBOLS(otbn_key_sideload_sca);
52 OTBN_DECLARE_SYMBOL_ADDR(otbn_key_sideload_sca, k_s0_l);
53 OTBN_DECLARE_SYMBOL_ADDR(otbn_key_sideload_sca, k_s0_h);
54 OTBN_DECLARE_SYMBOL_ADDR(otbn_key_sideload_sca, k_s1_l);
55 OTBN_DECLARE_SYMBOL_ADDR(otbn_key_sideload_sca, k_s1_h);
56 OTBN_DECLARE_SYMBOL_ADDR(otbn_key_sideload_sca, k_l);
57 OTBN_DECLARE_SYMBOL_ADDR(otbn_key_sideload_sca, k_h);
58 const otbn_app_t kOtbnAppKeySideloadSca =
59  OTBN_APP_T_INIT(otbn_key_sideload_sca);
60 static const otbn_addr_t kOtbnAppKeySideloadks0l =
61  OTBN_ADDR_T_INIT(otbn_key_sideload_sca, k_s0_l);
62 static const otbn_addr_t kOtbnAppKeySideloadks0h =
63  OTBN_ADDR_T_INIT(otbn_key_sideload_sca, k_s0_h);
64 static const otbn_addr_t kOtbnAppKeySideloadks1l =
65  OTBN_ADDR_T_INIT(otbn_key_sideload_sca, k_s1_l);
66 static const otbn_addr_t kOtbnAppKeySideloadks1h =
67  OTBN_ADDR_T_INIT(otbn_key_sideload_sca, k_s1_h);
68 static const otbn_addr_t kOtbnAppKeySideloadkl =
69  OTBN_ADDR_T_INIT(otbn_key_sideload_sca, k_l);
70 static const otbn_addr_t kOtbnAppKeySideloadkh =
71  OTBN_ADDR_T_INIT(otbn_key_sideload_sca, k_h);
72 
73 // RSA OTBN App.
75 OTBN_DECLARE_SYMBOL_ADDR(rsa, mode);
76 OTBN_DECLARE_SYMBOL_ADDR(rsa, n_limbs);
77 OTBN_DECLARE_SYMBOL_ADDR(rsa, inout);
78 OTBN_DECLARE_SYMBOL_ADDR(rsa, modulus);
79 OTBN_DECLARE_SYMBOL_ADDR(rsa, exp);
80 
81 static const otbn_app_t kOtbnAppRsa = OTBN_APP_T_INIT(rsa);
82 static const otbn_addr_t kOtbnVarRsaMode = OTBN_ADDR_T_INIT(rsa, mode);
83 static const otbn_addr_t kOtbnVarRsaNLimbs = OTBN_ADDR_T_INIT(rsa, n_limbs);
84 static const otbn_addr_t kOtbnVarRsaInOut = OTBN_ADDR_T_INIT(rsa, inout);
85 static const otbn_addr_t kOtbnVarRsaModulus = OTBN_ADDR_T_INIT(rsa, modulus);
86 static const otbn_addr_t kOtbnVarRsaExp = OTBN_ADDR_T_INIT(rsa, exp);
87 
88 // p256_ecdsa_sca has randomization removed.
89 OTBN_DECLARE_APP_SYMBOLS(p256_ecdsa_sca);
90 
91 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, mode);
92 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, msg);
93 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, r);
94 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, s);
95 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, x);
96 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, y);
97 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, d0);
98 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, d1);
99 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, k0);
100 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, k1);
101 OTBN_DECLARE_SYMBOL_ADDR(p256_ecdsa_sca, x_r);
102 
103 static const otbn_app_t kOtbnAppP256Ecdsa = OTBN_APP_T_INIT(p256_ecdsa_sca);
104 
105 static const otbn_addr_t kOtbnVarMode = OTBN_ADDR_T_INIT(p256_ecdsa_sca, mode);
106 static const otbn_addr_t kOtbnVarMsg = OTBN_ADDR_T_INIT(p256_ecdsa_sca, msg);
107 static const otbn_addr_t kOtbnVarR = OTBN_ADDR_T_INIT(p256_ecdsa_sca, r);
108 static const otbn_addr_t kOtbnVarS = OTBN_ADDR_T_INIT(p256_ecdsa_sca, s);
109 static const otbn_addr_t kOtbnVarD0 = OTBN_ADDR_T_INIT(p256_ecdsa_sca, d0);
110 static const otbn_addr_t kOtbnVarD1 = OTBN_ADDR_T_INIT(p256_ecdsa_sca, d1);
111 static const otbn_addr_t kOtbnVarK0 = OTBN_ADDR_T_INIT(p256_ecdsa_sca, k0);
112 static const otbn_addr_t kOtbnVarK1 = OTBN_ADDR_T_INIT(p256_ecdsa_sca, k1);
113 
114 /**
115  * Clears the OTBN DMEM and IMEM.
116  *
117  * @returns OK or error.
118  */
119 static status_t clear_otbn(void) {
120  // Clear OTBN memory.
121  TRY(otbn_dmem_sec_wipe());
122  TRY(otbn_imem_sec_wipe());
123 
124  return OK_STATUS();
125 }
126 
127 /**
128  * Generate masked shared.
129  *
130  * If mask_en is set, generate a random share.
131  * If mask_en is not set, set share to 0.
132  *
133  * @param dest_array Destination array.
134  * @param mask_en Masking enabled or disabled.
135  * @param len Length of the array.
136  */
137 void gen_mask_data(uint32_t *dest_array, bool mask_en, size_t len) {
138  if (mask_en) {
139  for (size_t j = 0; j < len; ++j) {
140  dest_array[j] = prng_rand_uint32();
141  }
142  } else {
143  memset(dest_array, 0, len * sizeof(dest_array[0]));
144  }
145 }
146 
147 /**
148  * Generate a FvsR data set.
149  *
150  * If fixed is set, copy src_fixed_array into dest_array.
151  * If fixed is not set, generate random data.
152  *
153  * @param dest_array Destination array.
154  * @param fixed Fixed or random set.
155  * @param src_fixed_array Source fixed array.
156  * @param len Length of the array.
157  */
158 void gen_fvsr_data(uint32_t *dest_array, bool fixed, uint32_t *src_fixed_array,
159  size_t len) {
160  if (fixed) {
161  memcpy(dest_array, src_fixed_array, len * sizeof(src_fixed_array[0]));
162  } else {
163  for (size_t j = 0; j < len; ++j) {
164  dest_array[j] = prng_rand_uint32();
165  }
166  }
167 }
168 
169 /**
170  * Signs a message with ECDSA using the P-256 curve.
171  *
172  * R = k*G
173  * r = x-coordinate of R
174  * s = k^(-1)(msg + r*d) mod n
175  *
176  * @param otbn_ctx The OTBN context object.
177  * @param msg The message to sign, msg (32B).
178  * @param private_key_d The private key, d (32B).
179  * @param k The ephemeral key, k (random scalar) (32B).
180  * @param[out] signature_r Signature component r (the x-coordinate of R).
181  * Provide a pre-allocated 32B buffer.
182  * @param[out] signature_s Signature component s (the proof).
183  * Provide a pre-allocated 32B buffer.
184  */
185 static status_t p256_ecdsa_sign(const uint32_t *msg,
186  const uint32_t *private_key_d,
187  uint32_t *signature_r, uint32_t *signature_s,
188  const uint32_t *k) {
189  uint32_t mode = 1; // mode 1 => sign
190  // Send operation mode to OTBN
191  TRY(otbn_dmem_write(/*num_words=*/1, &mode, kOtbnVarMode));
192  // Send Msg to OTBN
193  TRY(otbn_dmem_write(kEcc256NumWords, msg, kOtbnVarMsg));
194  // Send two shares of private_key_d to OTBN
195  TRY(otbn_dmem_write(kEcc256NumWords, private_key_d, kOtbnVarD0));
196  TRY(otbn_dmem_write(kEcc256NumWords, private_key_d + kEcc256NumWords,
197  kOtbnVarD1));
198  // Send two shares of secret_k to OTBN
199  TRY(otbn_dmem_write(kEcc256NumWords, k, kOtbnVarK0));
200  TRY(otbn_dmem_write(kEcc256NumWords, k + kEcc256NumWords, kOtbnVarK1));
201 
202  // Start OTBN execution
203  pentest_set_trigger_high();
204  // Give the trigger time to rise.
205  asm volatile(NOP30);
206  otbn_execute();
207  otbn_busy_wait_for_done();
208  pentest_set_trigger_low();
209 
210  // Read the results back (sig_r, sig_s)
211  TRY(otbn_dmem_read(kEcc256NumWords, kOtbnVarR, signature_r));
212  TRY(otbn_dmem_read(kEcc256NumWords, kOtbnVarS, signature_s));
213 
214  return OK_STATUS();
215 }
216 
217 status_t handle_otbn_sca_ecdsa_p256_sign(ujson_t *uj) {
218  // Get masks off or on.
219  penetrationtest_otbn_sca_en_masks_t uj_data_masks;
220 
221  // Get message and key.
222  penetrationtest_otbn_sca_ecdsa_p256_sign_t uj_data;
223  TRY(ujson_deserialize_penetrationtest_otbn_sca_ecdsa_p256_sign_t(uj,
224  &uj_data));
225 
226  // Set of share d1 for masking.
227  uint32_t ecc256_private_key_d1[kEcc256NumWords];
228  memset(ecc256_private_key_d1, 0, sizeof(ecc256_private_key_d1));
229  // If masking is activated, generate random share d1.
230  if (uj_data_masks.en_masks) {
231  for (size_t j = 0; j < kEcc256NumWords; j++) {
232  ecc256_private_key_d1[j] = prng_rand_uint32();
233  }
234  }
235 
236  // Set of share k1 for masking.
237  uint32_t ecc256_secret_k1[kEcc256NumWords];
238  memset(ecc256_secret_k1, 0, sizeof(ecc256_secret_k1));
239  // If masking is activated, generate random share d1.
240  if (uj_data_masks.en_masks) {
241  for (size_t j = 0; j < kEcc256NumWords; j++) {
242  ecc256_secret_k1[j] = prng_rand_uint32();
243  }
244  }
245 
246  // Combine D0 and D1 into the private key.
247  uint32_t ecc256_private_key_d[2 * kEcc256NumWords];
248  memset(ecc256_private_key_d, 0, sizeof(ecc256_private_key_d));
249  memcpy(ecc256_private_key_d, uj_data.d0, sizeof(uj_data.d0));
250  memcpy(ecc256_private_key_d + kEcc256NumWords, ecc256_private_key_d1,
251  sizeof(ecc256_private_key_d1));
252 
253  // Combine K0 and K1 into the secret key.
254  uint32_t ecc256_secret_k[2 * kEcc256NumWords];
255  memset(ecc256_secret_k, 0, sizeof(ecc256_secret_k));
256  memcpy(ecc256_secret_k, uj_data.k0, sizeof(uj_data.k0));
257  memcpy(ecc256_secret_k + kEcc256NumWords, ecc256_secret_k1,
258  sizeof(ecc256_secret_k1));
259 
260  otbn_load_app(kOtbnAppP256Ecdsa);
261 
262  // Signature output.
263  uint32_t ecc256_signature_r[kEcc256NumWords];
264  uint32_t ecc256_signature_s[kEcc256NumWords];
265 
266  // Start the operation.
267  p256_ecdsa_sign(uj_data.msg, ecc256_private_key_d, ecc256_signature_r,
268  ecc256_signature_s, ecc256_secret_k);
269 
270  // Send back signature to host.
271  penetrationtest_otbn_sca_ecdsa_p256_signature_t uj_output;
272  memcpy(uj_output.r, ecc256_signature_r, sizeof(ecc256_signature_r));
273  memcpy(uj_output.s, ecc256_signature_s, sizeof(ecc256_signature_s));
274  RESP_OK(ujson_serialize_penetrationtest_otbn_sca_ecdsa_p256_signature_t, uj,
275  &uj_output);
276 
277  // Clear OTBN memory
278  TRY(clear_otbn());
279 
280  return OK_STATUS();
281 }
282 
283 status_t handle_otbn_sca_ecdsa_p256_sign_batch(ujson_t *uj) {
284  // Get number of traces.
285  penetrationtest_otbn_sca_num_traces_t uj_data_num_traces;
286  TRY(ujson_deserialize_penetrationtest_otbn_sca_num_traces_t(
287  uj, &uj_data_num_traces));
288 
289  if (uj_data_num_traces.num_traces > kNumBatchOpsMax) {
290  return OUT_OF_RANGE();
291  }
292 
293  // Get masks off or on.
294  penetrationtest_otbn_sca_en_masks_t uj_data_masks;
295  TRY(ujson_deserialize_penetrationtest_otbn_sca_en_masks_t(uj,
296  &uj_data_masks));
297 
298  // Create random message, k, and d.
299  uint32_t ecc256_message_batch[kNumBatchOpsMax][kEcc256NumWords];
300 
301  uint32_t ecc256_private_key_d0_batch[kNumBatchOpsMax][kEcc256NumWords];
302  uint32_t ecc256_private_key_d1_batch[kNumBatchOpsMax][kEcc256NumWords];
303  uint32_t ecc256_private_key_d_batch[kNumBatchOpsMax][2 * kEcc256NumWords];
304 
305  uint32_t ecc256_secret_key_k0_batch[kNumBatchOpsMax][kEcc256NumWords];
306  uint32_t ecc256_secret_key_k1_batch[kNumBatchOpsMax][kEcc256NumWords];
307  uint32_t ecc256_secret_key_k_batch[kNumBatchOpsMax][2 * kEcc256NumWords];
308 
309  // Generate the FvsR data set.
310  for (size_t i = 0; i < uj_data_num_traces.num_traces; ++i) {
311  // Generate random message.
312  gen_fvsr_data(ecc256_message_batch[i], false, NULL, kEcc256NumWords);
313 
314  // Set random private key d0.
315  gen_fvsr_data(ecc256_private_key_d0_batch[i], false, NULL, kEcc256NumWords);
316 
317  // When masks are on, set random private key d1. If masks are off, set to 0.
318  gen_mask_data(ecc256_private_key_d1_batch[i], uj_data_masks.en_masks,
319  kEcc256NumWords);
320 
321  // Combine both shares d0 and d1 to d.
322  memcpy(ecc256_private_key_d_batch[i], ecc256_private_key_d0_batch[i],
323  sizeof(ecc256_private_key_d0_batch[i]));
324  memcpy(ecc256_private_key_d_batch[i] + kEcc256NumWords,
325  ecc256_private_key_d1_batch[i],
326  sizeof(ecc256_private_key_d1_batch[i]));
327 
328  // Set random secret key k0.
329  gen_fvsr_data(ecc256_secret_key_k0_batch[i], false, NULL, kEcc256NumWords);
330 
331  // When masks are on, set random secret key k1. If masks are off, set to 0.
332  gen_mask_data(ecc256_secret_key_k1_batch[i], uj_data_masks.en_masks,
333  kEcc256NumWords);
334 
335  // Combine both shares k0 and k1 to k.
336  memcpy(ecc256_secret_key_k_batch[i], ecc256_secret_key_k0_batch[i],
337  sizeof(ecc256_secret_key_k0_batch[i]));
338  memcpy(ecc256_secret_key_k_batch[i] + kEcc256NumWords,
339  ecc256_secret_key_k1_batch[i],
340  sizeof(ecc256_secret_key_k1_batch[i]));
341  }
342 
343  // Last signature output.
344  uint32_t ecc256_signature_r[kEcc256NumWords];
345  uint32_t ecc256_signature_s[kEcc256NumWords];
346  // Run num_traces ECDSA operations.
347  for (size_t i = 0; i < uj_data_num_traces.num_traces; ++i) {
348  otbn_load_app(kOtbnAppP256Ecdsa);
349 
350  // Start the operation.
351  p256_ecdsa_sign(ecc256_message_batch[i], ecc256_private_key_d_batch[i],
352  ecc256_signature_r, ecc256_signature_s,
353  ecc256_secret_key_k_batch[i]);
354  }
355 
356  // Send back the last signature to host.
357  penetrationtest_otbn_sca_ecdsa_p256_signature_t uj_output;
358  memcpy(uj_output.r, ecc256_signature_r, sizeof(ecc256_signature_r));
359  memcpy(uj_output.s, ecc256_signature_s, sizeof(ecc256_signature_s));
360  RESP_OK(ujson_serialize_penetrationtest_otbn_sca_ecdsa_p256_signature_t, uj,
361  &uj_output);
362 
363  // Clear OTBN memory
364  TRY(clear_otbn());
365 
366  return OK_STATUS();
367 }
368 
369 status_t handle_otbn_sca_ecdsa_p256_sign_fvsr_batch(ujson_t *uj) {
370  // Get number of traces.
371  penetrationtest_otbn_sca_num_traces_t uj_data_num_traces;
372  TRY(ujson_deserialize_penetrationtest_otbn_sca_num_traces_t(
373  uj, &uj_data_num_traces));
374 
375  if (uj_data_num_traces.num_traces > kNumBatchOpsMax) {
376  return OUT_OF_RANGE();
377  }
378 
379  // Get masks off or on.
380  penetrationtest_otbn_sca_en_masks_t uj_data_masks;
381  TRY(ujson_deserialize_penetrationtest_otbn_sca_en_masks_t(uj,
382  &uj_data_masks));
383 
384  // Get fixed message and key.
385  penetrationtest_otbn_sca_ecdsa_p256_sign_t uj_data;
386  TRY(ujson_deserialize_penetrationtest_otbn_sca_ecdsa_p256_sign_t(uj,
387  &uj_data));
388 
389  uint32_t ecc256_message_batch[kNumBatchOpsMax][kEcc256NumWords];
390 
391  uint32_t ecc256_private_key_d0_batch[kNumBatchOpsMax][kEcc256NumWords];
392  uint32_t ecc256_private_key_d1_batch[kNumBatchOpsMax][kEcc256NumWords];
393  uint32_t ecc256_private_key_d_batch[kNumBatchOpsMax][2 * kEcc256NumWords];
394 
395  uint32_t ecc256_secret_key_k0_batch[kNumBatchOpsMax][kEcc256NumWords];
396  uint32_t ecc256_secret_key_k1_batch[kNumBatchOpsMax][kEcc256NumWords];
397  uint32_t ecc256_secret_key_k_batch[kNumBatchOpsMax][2 * kEcc256NumWords];
398 
399  // Generate the FvsR data set. For each trace, message, k, and d is either set
400  // to fixed received from the host over uJSON or random.
401  bool run_fixed = true;
402  for (size_t i = 0; i < uj_data_num_traces.num_traces; ++i) {
403  // Set message.
404  gen_fvsr_data(ecc256_message_batch[i], run_fixed, uj_data.msg,
405  kEcc256NumWords);
406 
407  // If the run is fixed, take the private key received over uJSON. Else,
408  // generate a random private key.
409  gen_fvsr_data(ecc256_private_key_d0_batch[i], run_fixed, uj_data.d0,
410  kEcc256NumWords);
411 
412  // When masks are on, set fixed or random private key d1. If masks are off,
413  // set to 0.
414  gen_mask_data(ecc256_private_key_d1_batch[i], uj_data_masks.en_masks,
415  kEcc256NumWords);
416 
417  // Combine both shares
418  memcpy(ecc256_private_key_d_batch[i], ecc256_private_key_d0_batch[i],
419  sizeof(ecc256_private_key_d0_batch[i]));
420  memcpy(ecc256_private_key_d_batch[i] + kEcc256NumWords,
421  ecc256_private_key_d1_batch[i],
422  sizeof(ecc256_private_key_d1_batch[i]));
423 
424  // Set random secret key k0.
425  // If the run is fixed, take the private key received over uJSON. Else,
426  // generate a random private key.
427  gen_fvsr_data(ecc256_secret_key_k0_batch[i], run_fixed, uj_data.k0,
428  kEcc256NumWords);
429 
430  // When masks are on, set random secret key k1. If masks are off, set to 0.
431  gen_mask_data(ecc256_secret_key_k1_batch[i], uj_data_masks.en_masks,
432  kEcc256NumWords);
433 
434  // Combine both shares k0 and k1 to k.
435  memcpy(ecc256_secret_key_k_batch[i], ecc256_secret_key_k0_batch[i],
436  sizeof(ecc256_secret_key_k0_batch[i]));
437  memcpy(ecc256_secret_key_k_batch[i] + kEcc256NumWords,
438  ecc256_secret_key_k1_batch[i],
439  sizeof(ecc256_secret_key_k1_batch[i]));
440 
441  run_fixed = prng_rand_uint32() & 0x1;
442  }
443 
444  // Last signature output.
445  uint32_t ecc256_signature_r[kEcc256NumWords];
446  uint32_t ecc256_signature_s[kEcc256NumWords];
447  // Run num_traces ECDSA operations.
448  for (size_t i = 0; i < uj_data_num_traces.num_traces; ++i) {
449  otbn_load_app(kOtbnAppP256Ecdsa);
450 
451  // Start the operation.
452  p256_ecdsa_sign(uj_data.msg, ecc256_private_key_d_batch[i],
453  ecc256_signature_r, ecc256_signature_s,
454  ecc256_secret_key_k_batch[i]);
455  }
456 
457  // Send back the last signature to host.
458  penetrationtest_otbn_sca_ecdsa_p256_signature_t uj_output;
459  memcpy(uj_output.r, ecc256_signature_r, sizeof(ecc256_signature_r));
460  memcpy(uj_output.s, ecc256_signature_s, sizeof(ecc256_signature_s));
461  RESP_OK(ujson_serialize_penetrationtest_otbn_sca_ecdsa_p256_signature_t, uj,
462  &uj_output);
463 
464  // Clear OTBN memory
465  TRY(clear_otbn());
466 
467  return OK_STATUS();
468 }
469 
470 status_t handle_otbn_pentest_init(ujson_t *uj) {
471  penetrationtest_cpuctrl_t uj_data;
472  TRY(ujson_deserialize_penetrationtest_cpuctrl_t(uj, &uj_data));
473 
474  // Configure the entropy complex for OTBN. Set the reseed interval to max
475  // to avoid a non-constant trigger window.
476  TRY(pentest_configure_entropy_source_max_reseed_interval());
477 
478  pentest_init(kPentestTriggerSourceOtbn,
479  kPentestPeripheralEntropy | kPentestPeripheralIoDiv4 |
480  kPentestPeripheralOtbn | kPentestPeripheralCsrng |
481  kPentestPeripheralEdn | kPentestPeripheralHmac |
482  kPentestPeripheralKmac);
483 
484  // Init the OTBN core.
485  TRY(dif_otbn_init(mmio_region_from_addr(TOP_EARLGREY_OTBN_BASE_ADDR), &otbn));
486 
487  // Load p256 keygen from seed app into OTBN.
488  if (otbn_load_app(kOtbnAppP256KeyFromSeed).value != OTCRYPTO_OK.value) {
489  return ABORTED();
490  }
491 
492  // Configure the CPU for the pentest.
493  penetrationtest_device_info_t uj_output;
494  TRY(pentest_configure_cpu(
495  uj_data.icache_disable, uj_data.dummy_instr_disable,
496  uj_data.enable_jittery_clock, uj_data.enable_sram_readback,
497  &uj_output.clock_jitter_locked, &uj_output.clock_jitter_en,
498  &uj_output.sram_main_readback_locked, &uj_output.sram_ret_readback_locked,
499  &uj_output.sram_main_readback_en, &uj_output.sram_ret_readback_en));
500 
501  // Read device ID and return to host.
502  TRY(pentest_read_device_id(uj_output.device_id));
503  RESP_OK(ujson_serialize_penetrationtest_device_info_t, uj, &uj_output);
504 
505  return OK_STATUS();
506 }
507 
508 status_t handle_otbn_pentest_init_keymgr(ujson_t *uj) {
509  if (kBootStage != kBootStageOwner) {
510  TRY(keymgr_testutils_startup(&keymgr, &kmac));
511  // Advance to OwnerIntermediateKey state.
512  TRY(keymgr_testutils_advance_state(&keymgr, &kOwnerIntParams));
513  TRY(keymgr_testutils_check_state(&keymgr,
515  LOG_INFO("Keymgr entered OwnerIntKey State");
516  } else {
518  &keymgr));
519  TRY(keymgr_testutils_check_state(&keymgr, kDifKeymgrStateOwnerRootKey));
520  }
521 
522  dif_otbn_t otbn;
523  TRY(dif_otbn_init(mmio_region_from_addr(TOP_EARLGREY_OTBN_BASE_ADDR), &otbn));
524 
525  return OK_STATUS();
526 }
527 
528 status_t handle_otbn_sca_insn_carry_flag(ujson_t *uj) {
529  // Get big number (256 bit).
530  penetrationtest_otbn_sca_big_num_t uj_data;
531  TRY(ujson_deserialize_penetrationtest_otbn_sca_big_num_t(uj, &uj_data));
532 
533  // INSN Carry Flag OTBN App.
534  OTBN_DECLARE_APP_SYMBOLS(otbn_insn_carry_flag);
535  OTBN_DECLARE_SYMBOL_ADDR(otbn_insn_carry_flag, big_num);
536  OTBN_DECLARE_SYMBOL_ADDR(otbn_insn_carry_flag, big_num_out);
537 
538  static const otbn_app_t kOtbnAppInsnCarryFlag =
539  OTBN_APP_T_INIT(otbn_insn_carry_flag);
540  static const otbn_addr_t kOtbnVarInsnCarryFlagBigNum =
541  OTBN_ADDR_T_INIT(otbn_insn_carry_flag, big_num);
542  static const otbn_addr_t kOtbnVarInsnCarryFlagBigNumOut =
543  OTBN_ADDR_T_INIT(otbn_insn_carry_flag, big_num_out);
544 
545  // Load app and write received big_num into DMEM.
546  otbn_load_app(kOtbnAppInsnCarryFlag);
547  TRY(dif_otbn_dmem_write(&otbn, kOtbnVarInsnCarryFlagBigNum, uj_data.big_num,
548  sizeof(uj_data.big_num)));
549 
550  pentest_set_trigger_high();
551  otbn_execute();
552  otbn_busy_wait_for_done();
553  pentest_set_trigger_low();
554 
555  penetrationtest_otbn_sca_big_num_t uj_output;
556  memset(uj_output.big_num, 0, sizeof(uj_output.big_num));
557  TRY(dif_otbn_dmem_read(&otbn, kOtbnVarInsnCarryFlagBigNumOut,
558  uj_output.big_num, sizeof(uj_output.big_num)));
559 
560  RESP_OK(ujson_serialize_penetrationtest_otbn_sca_big_num_t, uj, &uj_output);
561 
562  return OK_STATUS();
563 }
564 
565 status_t handle_otbn_sca_key_sideload_fvsr(ujson_t *uj) {
566  // Get fixed seed.
567  penetrationtest_otbn_sca_fixed_seed_t uj_data;
568  TRY(ujson_deserialize_penetrationtest_otbn_sca_fixed_seed_t(uj, &uj_data));
569 
570  // Key generation parameters.
571  dif_keymgr_versioned_key_params_t sideload_params[kKeySideloadNumIt];
572 
573  // Generate FvsR values.
574  bool sample_fixed = true;
575  for (size_t it = 0; it < kKeySideloadNumIt; it++) {
576  sideload_params[it].version = 0x0;
577  sideload_params[it].dest = kDifKeymgrVersionedKeyDestOtbn;
578  memset(sideload_params[it].salt, 0, sizeof(sideload_params[it].salt));
579  if (sample_fixed) {
580  sideload_params[it].salt[0] = uj_data.fixed_seed;
581  } else {
582  sideload_params[it].salt[0] = prng_rand_uint32();
583  }
584  sample_fixed = prng_rand_uint32() & 0x1;
585  }
586 
587  otbn_load_app(kOtbnAppKeySideloadSca);
588 
589  uint32_t key_share_0_l[kKeySideloadNumIt], key_share_0_h[kKeySideloadNumIt];
590  uint32_t key_share_1_l[16], key_share_1_h[kKeySideloadNumIt];
591  uint32_t key_l[kKeySideloadNumIt], key_h[kKeySideloadNumIt];
592 
593  // SCA code target.
594  for (size_t it = 0; it < kKeySideloadNumIt; it++) {
595  TRY(keymgr_testutils_generate_versioned_key(&keymgr, sideload_params[it]));
596 
597  TRY(dif_otbn_set_ctrl_software_errs_fatal(&otbn, /*enable=*/false));
598 
599  pentest_set_trigger_high();
600  // Give the trigger time to rise.
601  asm volatile(NOP30);
602  otbn_execute();
603  otbn_busy_wait_for_done();
604  pentest_set_trigger_low();
605  asm volatile(NOP30);
606 
607  otbn_dmem_read(1, kOtbnAppKeySideloadks0l, &key_share_0_l[it]);
608  otbn_dmem_read(1, kOtbnAppKeySideloadks0h, &key_share_0_h[it]);
609  otbn_dmem_read(1, kOtbnAppKeySideloadks1l, &key_share_1_l[it]);
610  otbn_dmem_read(1, kOtbnAppKeySideloadks1h, &key_share_1_h[it]);
611  otbn_dmem_read(1, kOtbnAppKeySideloadkl, &key_l[it]);
612  otbn_dmem_read(1, kOtbnAppKeySideloadkh, &key_h[it]);
613  }
614 
615  // Write back shares and keys to host.
616  penetrationtest_otbn_sca_key_t uj_output;
617  for (size_t it = 0; it < kKeySideloadNumIt; it++) {
618  uj_output.shares[0] = key_share_0_l[it];
619  uj_output.shares[1] = key_share_0_h[it];
620  uj_output.shares[2] = key_share_1_l[it];
621  uj_output.shares[3] = key_share_1_h[it];
622  uj_output.keys[0] = key_l[it];
623  uj_output.keys[1] = key_h[it];
624  RESP_OK(ujson_serialize_penetrationtest_otbn_sca_key_t, uj, &uj_output);
625  }
626 
627  return OK_STATUS();
628 }
629 
630 status_t handle_otbn_sca_rsa512_decrypt(ujson_t *uj) {
631  // Get RSA256 parameters.
632  penetrationtest_otbn_sca_rsa512_dec_t uj_data;
633  TRY(ujson_deserialize_penetrationtest_otbn_sca_rsa512_dec_t(uj, &uj_data));
634 
635  otbn_load_app(kOtbnAppRsa);
636 
637  uint32_t mode = 2; // Decrypt.
638  // RSA512 configuration.
639  uint32_t n_limbs = 2;
640 
641  // Write data into OTBN DMEM.
642  TRY(dif_otbn_dmem_write(&otbn, kOtbnVarRsaMode, &mode, sizeof(mode)));
643  TRY(dif_otbn_dmem_write(&otbn, kOtbnVarRsaNLimbs, &n_limbs, sizeof(n_limbs)));
644  TRY(dif_otbn_dmem_write(&otbn, kOtbnVarRsaModulus, uj_data.mod,
645  sizeof(uj_data.mod)));
646  TRY(dif_otbn_dmem_write(&otbn, kOtbnVarRsaExp, uj_data.exp,
647  sizeof(uj_data.exp)));
648  TRY(dif_otbn_dmem_write(&otbn, kOtbnVarRsaInOut, uj_data.msg,
649  sizeof(uj_data.msg)));
650 
651  pentest_set_trigger_high();
652  // Give the trigger time to rise.
653  asm volatile(NOP30);
654  otbn_execute();
655  otbn_busy_wait_for_done();
656  pentest_set_trigger_low();
657 
658  // Send back decryption result to host.
659  penetrationtest_otbn_sca_rsa512_dec_out_t uj_output;
660  TRY(dif_otbn_dmem_read(&otbn, kOtbnVarRsaInOut, uj_output.out,
661  sizeof(uj_output.out)));
662  RESP_OK(ujson_serialize_penetrationtest_otbn_sca_rsa512_dec_out_t, uj,
663  &uj_output);
664  return OK_STATUS();
665 }
666 
667 status_t handle_otbn_sca(ujson_t *uj) {
668  otbn_sca_subcommand_t cmd;
669  TRY(ujson_deserialize_otbn_sca_subcommand_t(uj, &cmd));
670  switch (cmd) {
671  case kOtbnScaSubcommandEcc256EcdsaKeygenFvsrKeyBatch:
672  return handle_otbn_sca_ecc256_ecdsa_keygen_fvsr_key_batch(uj);
673  case kOtbnScaSubcommandEcc256EcdsaKeygenFvsrSeedBatch:
674  return handle_otbn_sca_ecc256_ecdsa_keygen_fvsr_seed_batch(uj);
675  case kOtbnScaSubcommandEcc256EnMasks:
676  return handle_otbn_sca_ecc256_en_masks(uj);
677  case kOtbnScaSubcommandEcc256SetC:
678  return handle_otbn_sca_ecc256_set_c(uj);
679  case kOtbnScaSubcommandEcc256SetSeed:
680  return handle_otbn_sca_ecc256_set_seed(uj);
681  case kOtbnScaSubcommandEcdsaP256Sign:
682  return handle_otbn_sca_ecdsa_p256_sign(uj);
683  case kOtbnScaSubcommandEcdsaP256SignBatch:
684  return handle_otbn_sca_ecdsa_p256_sign_batch(uj);
685  case kOtbnScaSubcommandEcdsaP256SignFvsrBatch:
686  return handle_otbn_sca_ecdsa_p256_sign_fvsr_batch(uj);
687  case kOtbnScaSubcommandInit:
688  return handle_otbn_pentest_init(uj);
689  case kOtbnScaSubcommandInitKeyMgr:
690  return handle_otbn_pentest_init_keymgr(uj);
691  case kOtbnScaSubcommandInsnCarryFlag:
692  return handle_otbn_sca_insn_carry_flag(uj);
693  case kOtbnScaSubcommandKeySideloadFvsr:
694  return handle_otbn_sca_key_sideload_fvsr(uj);
695  case kOtbnScaSubcommandRsa512Decrypt:
696  return handle_otbn_sca_rsa512_decrypt(uj);
697  default:
698  LOG_ERROR("Unrecognized OTBN SCA subcommand: %d", cmd);
699  return INVALID_ARGUMENT();
700  }
701  return OK_STATUS();
702 }