Software APIs
entropy_src_bypass_mode_health_test.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 "hw/ip/aes/model/aes_modes.h"
17 #include "sw/device/lib/dif/dif_rv_core_ibex.h"
21 #include "sw/device/lib/testing/aes_testutils.h"
22 #include "sw/device/lib/testing/entropy_testutils.h"
24 #include "sw/device/lib/testing/test_framework/check.h"
26 #include "sw/device/tests/otbn_randomness_impl.h"
27 
29 #include "sw/device/lib/dif/autogen/dif_entropy_src_autogen.h"
30 
31 #define TIMEOUT (1000 * 1000)
32 
33 OTTF_DEFINE_TEST_CONFIG();
34 
35 // Module handles
36 static dif_entropy_src_t entropy_src;
37 static dif_csrng_t csrng;
38 static dif_edn_t edn0;
39 static dif_edn_t edn1;
40 static dif_aes_t aes;
41 static dif_otbn_t otbn;
42 static dif_alert_handler_t alert_handler;
43 
44 status_t init_test_environment(void) {
45  LOG_INFO(
46  "Initializing modules sntropy_src, csrng, edn0, edn1, aes, otbn and "
47  "alert_handler...");
48  TRY(dif_entropy_src_init(
51  &csrng));
52  TRY(dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN0_BASE_ADDR), &edn0));
53  TRY(dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN1_BASE_ADDR), &edn1));
54  TRY(dif_aes_init(mmio_region_from_addr(TOP_EARLGREY_AES_BASE_ADDR), &aes));
55  TRY(dif_otbn_init(mmio_region_from_addr(TOP_EARLGREY_OTBN_BASE_ADDR), &otbn));
56  TRY(dif_alert_handler_init(
58  &alert_handler));
59  return OK_STATUS();
60 }
61 
62 // Function to disable entropy complex
63 status_t disable_entropy_complex(void) {
64  // Using entropy test utility to stop all EDN0, EDN1, CSRNG, and the Entropy
65  // Source
66  LOG_INFO("Disabling the entropy complex...");
67  return entropy_testutils_stop_all();
68 }
69 
70 status_t configure_loose_health_tests(void) {
71  LOG_INFO("Configuring loose health test thresholds...");
72 
73  // Check if entropy source is locked
74  bool is_locked;
75  TRY(dif_entropy_src_is_locked(&entropy_src, &is_locked));
76  TRY_CHECK(!is_locked,
77  "Entropy source is locked. Cannot configure ENTROPY_SRC");
78 
79  // Configure Repetition Count Test
80  dif_entropy_src_health_test_config_t repcnt_test_config = {
82  .high_threshold = 512,
83  .low_threshold = 0,
84  };
85  TRY(dif_entropy_src_health_test_configure(&entropy_src, repcnt_test_config));
86 
87  // Configure Adaptive Proportion Test
88  dif_entropy_src_health_test_config_t adaptp_test_config = {
90  .high_threshold = 512,
91  .low_threshold = 0,
92  };
93  TRY(dif_entropy_src_health_test_configure(&entropy_src, adaptp_test_config));
94 
95  // Configure Bucket Test
96  dif_entropy_src_health_test_config_t bucket_test_config = {
98  .high_threshold = 512,
99  .low_threshold = 0,
100  };
101  TRY(dif_entropy_src_health_test_configure(&entropy_src, bucket_test_config));
102 
103  // Configure Markov Test
104  dif_entropy_src_health_test_config_t markov_test_config = {
106  .high_threshold = 512,
107  .low_threshold = 0,
108  };
109  TRY(dif_entropy_src_health_test_configure(&entropy_src, markov_test_config));
110 
111  return OK_STATUS();
112 }
113 
114 status_t enable_loose_entropy_src_bypass_mode(void) {
115  LOG_INFO("Enabling ENTROPY_SRC in bypass mode...");
116 
117  // Ensure the entropy source is not locked
118  bool is_locked;
119  TRY(dif_entropy_src_is_locked(&entropy_src, &is_locked));
120  TRY_CHECK(!is_locked,
121  "Entropy source is locked. Cannot configure ENTROPY_SRC");
122 
123  // Configure ENTROPY_SRC in bypass mode with health tests enabled
124  dif_entropy_src_config_t config = {
125  .fips_enable = false,
126  .route_to_firmware = false,
127  .fips_flag = false,
128  .rng_fips = false,
129  .bypass_conditioner = true,
130  .single_bit_mode = kDifEntropySrcSingleBitModeDisabled,
131  .health_test_threshold_scope = false,
132  .health_test_window_size = 512,
133  .alert_threshold = 0xFFFF,
134  };
135 
136  // Apply the configuration and enable ENTROPY_SRC
137  TRY(dif_entropy_src_configure(&entropy_src, config, kDifToggleEnabled));
138 
139  return OK_STATUS();
140 }
141 
142 status_t enable_csrng(void) {
143  LOG_INFO("Enabling and instantiating CSRNG...");
144 
145  // Configure CSRNG with default settings
146  TRY(dif_csrng_configure(&csrng));
147 
148  // Instantiate the CSRNG
149  dif_csrng_seed_material_t seed_material = {
150  .seed_material_len = 0,
151  .seed_material = {0},
152  };
154  &seed_material));
155 
158  TRY_CHECK(status.cmd_sts == kDifCsrngCmdStsSuccess,
159  "csrng error status. err: 0x%x, kind: 0x%x", status.cmd_sts,
160  status.kind);
161 
162  LOG_INFO("CSRNG is now instantiated and enabled");
163 
164  return OK_STATUS();
165 }
166 
167 status_t enable_edns_boot_mode(void) {
168  LOG_INFO("Enabling EDNs in boot-time request mode...");
169  TRY(dif_edn_set_boot_mode(&edn0));
170  TRY(dif_edn_set_boot_mode(&edn1));
171  TRY(dif_edn_configure(&edn0));
172  TRY(dif_edn_configure(&edn1));
173  return OK_STATUS();
174 }
175 
176 status_t entropy_testutils_error_check_b4_proceeding(void) {
177  LOG_INFO("Debugging error checks b4 proceeding...");
178  return entropy_testutils_error_check(&csrng, &edn0, &edn1);
179 }
180 
181 status_t test_and_verify_aes_operation(void) {
182  LOG_INFO("Triggering AES operation in ECB mode...");
183 
184  // Setup ECB encryption transaction
185  dif_aes_transaction_t transaction = {
186  .operation = kDifAesOperationEncrypt,
187  .mode = kDifAesModeEcb,
188  .key_len = kDifAesKey256,
189  .key_provider = kDifAesKeySoftwareProvided,
190  .mask_reseeding = kDifAesReseedPer8kBlock,
191  .manual_operation = kDifAesManualOperationAuto,
192  .reseed_on_key_change = false,
193  .ctrl_aux_lock = false,
194  };
195 
196  // Configure encryption
197  CHECK_STATUS_OK(aes_testutils_setup_encryption(transaction, &aes));
198 
199  // Wait for the encryption to complete
200  AES_TESTUTILS_WAIT_FOR_STATUS(&aes, kDifAesStatusOutputValid, true, TIMEOUT);
201 
202  // Decrypt and verify
203  CHECK_STATUS_OK(aes_testutils_decrypt_ciphertext(transaction, &aes));
204 
205  LOG_INFO("AES operation in ECB mode verified successfully");
206  return OK_STATUS();
207 }
208 
209 status_t start_otbn_program(void) {
210  LOG_INFO("Starting OTBN randomness test...");
211 
212  // Start the OTBN randomness test with one iteration
213  otbn_randomness_test_start(&otbn, 1);
214 
215  LOG_INFO("OTBN randomness test started");
216  return OK_STATUS();
217 }
218 
219 status_t verify_otbn_hang(void) {
220  LOG_INFO("Verifying OTBN program hang...");
221 
222  // Wait for a timeout period to check if OTBN is still busy
223  const uint32_t kIterateMaxRetries = 1000000;
224  bool otbn_busy = true;
225  uint32_t iter_cntr = kIterateMaxRetries;
226 
227  dif_otbn_status_t otbn_status;
228 
229  while (iter_cntr > 0) {
230  // Check if OTBN is still busy
231  TRY(dif_otbn_get_status(&otbn, &otbn_status));
232 
233  // Check if any of the busy status flags are set
234  otbn_busy = (otbn_status &
235  (kDifOtbnStatusBusyExecute | kDifOtbnStatusBusySecWipeDmem |
236  kDifOtbnStatusBusySecWipeImem)) != 0;
237  TRY_CHECK(otbn_busy,
238  "OTBN program completed unexpectedly; expected it to hang");
239  iter_cntr--;
240  }
241 
242  // After timeout, if OTBN is still busy, we shall conclude it's hanging as
243  // expected
244  if (otbn_busy) {
245  LOG_INFO("OTBN program is still running as expected (hang detected)");
246 
247  // Print OTBN status and error bits
248  dif_otbn_err_bits_t otbn_err_bits;
249  TRY(dif_otbn_get_err_bits(&otbn, &otbn_err_bits));
250  LOG_INFO("OTBN status: 0x%x", otbn_status);
251  LOG_INFO("OTBN error bits: 0x%x", otbn_err_bits);
252 
253  // Double check to confirm no other unexpected errors are
254  // present leading to hang
255  if (otbn_err_bits != kDifOtbnErrBitsNoError) {
256  LOG_ERROR("OTBN encountered unexpected errors");
257 
258  // Optionally, decode and print specific error bits
259  if (otbn_err_bits & kDifOtbnErrBitsBadDataAddr) {
260  LOG_ERROR("A BAD_DATA_ADDR error was observed");
261  }
262  if (otbn_err_bits & kDifOtbnErrBitsBadInsnAddr) {
263  LOG_ERROR("A BAD_INSN_ADDR error was observed");
264  }
265  if (otbn_err_bits & kDifOtbnErrBitsCallStack) {
266  LOG_ERROR("A CALL_STACK error was observed");
267  }
268  if (otbn_err_bits & kDifOtbnErrBitsIllegalInsn) {
269  LOG_ERROR("An ILLEGAL_INSN error was observed");
270  }
271  if (otbn_err_bits & kDifOtbnErrBitsLoop) {
272  LOG_ERROR("A LOOP error was observed");
273  }
274 
275  otbn_randomness_test_end(&otbn, 1);
276  return INTERNAL();
277  }
278  return OK_STATUS();
279  } else {
280  LOG_ERROR("OTBN program did not hang as expected");
281  return INTERNAL();
282  }
283 }
284 
285 status_t set_threshold_and_enable_stringent_entropy_src_bypass_mode(void) {
286  LOG_INFO("Enabling ENTROPY_SRC in bypass mode...");
287 
288  // Ensure the entropy source is not locked
289  bool is_locked;
290  TRY(dif_entropy_src_is_locked(&entropy_src, &is_locked));
291  TRY_CHECK(!is_locked,
292  "Entropy source is locked. Cannot configure ENTROPY_SRC");
293 
294  // Configure ENTROPY_SRC in bypass mode with health tests enabled
295  dif_entropy_src_config_t config = {
296  .fips_enable = false,
297  .route_to_firmware = false,
298  .fips_flag = false,
299  .rng_fips = false,
300  .bypass_conditioner = true,
301  .single_bit_mode = kDifEntropySrcSingleBitModeDisabled,
302  .health_test_threshold_scope = false,
303  .health_test_window_size = 512,
304  .alert_threshold = 1,
305  };
306 
307  // Apply the configuration and enable ENTROPY_SRC
308  TRY(dif_entropy_src_configure(&entropy_src, config, kDifToggleEnabled));
309 
310  return OK_STATUS();
311 }
312 
313 status_t configure_stringent_health_tests(void) {
314  LOG_INFO("Configuring stringent health test thresholds...");
315 
316  // Ensure the entropy source is not locked
317  bool is_locked;
318  TRY(dif_entropy_src_is_locked(&entropy_src, &is_locked));
319  TRY_CHECK(!is_locked,
320  "Entropy source is locked. Cannot configure ENTROPY_SRC");
321 
322  // Configure Repetition Count Test with stringent threshold
323  dif_entropy_src_health_test_config_t repcnt_test_config = {
325  .high_threshold = 1,
326  .low_threshold = 0,
327  };
328  TRY(dif_entropy_src_health_test_configure(&entropy_src, repcnt_test_config));
329 
330  // Configure Adaptive Proportion Test with stringent threshold
331  dif_entropy_src_health_test_config_t adaptp_test_config = {
333  .high_threshold = 1,
334  .low_threshold = 0,
335  };
336  TRY(dif_entropy_src_health_test_configure(&entropy_src, adaptp_test_config));
337 
338  // Configure Bucket Test with stringent threshold
339  dif_entropy_src_health_test_config_t bucket_test_config = {
341  .high_threshold = 1,
342  .low_threshold = 0,
343  };
344  TRY(dif_entropy_src_health_test_configure(&entropy_src, bucket_test_config));
345 
346  // Configure Markov Test with stringent threshold
347  dif_entropy_src_health_test_config_t markov_test_config = {
349  .high_threshold = 1,
350  .low_threshold = 0,
351  };
352  TRY(dif_entropy_src_health_test_configure(&entropy_src, markov_test_config));
353 
354  return OK_STATUS();
355 }
356 
357 status_t verify_recoverable_alert(void) {
358  LOG_INFO("Verifying recoverable alerts...");
359 
360  // Retrieve the recoverable alerts
361  uint32_t alerts;
362  TRY(dif_entropy_src_get_recoverable_alerts(&entropy_src, &alerts));
363 
364  if (alerts != 0) {
365  LOG_INFO("Recoverable alert detected. Alerts: 0x%x", alerts);
366 
367  // Define alert bit masks based on documentation
368  const uint32_t kEsMainSmAlertBit = 1 << 12;
369  const uint32_t kEsThreshCfgAlertBit = 1 << 14;
370 
371  // Debug check if ES_THRESH_CFG_ALERT is set
372  TRY_CHECK((alerts & kEsThreshCfgAlertBit) == 0,
373  "ES_THRESH_CFG_ALERT is asserted");
374  LOG_INFO("ES_THRESH_CFG_ALERT is not asserted and expected");
375 
376  // Check if ES_MAIN_SM_ALERT is set
377  TRY_CHECK((alerts & kEsMainSmAlertBit) != 0,
378  "ES_MAIN_SM_ALERT is not asserted when expected");
379  LOG_INFO("ES_MAIN_SM_ALERT is asserted as expected");
380 
381  // Clear the recoverable alerts
382  TRY(dif_entropy_src_clear_recoverable_alerts(&entropy_src, alerts));
383 
384  // Verify that the alerts have been cleared
385  TRY(dif_entropy_src_get_recoverable_alerts(&entropy_src, &alerts));
386 
387  TRY_CHECK(alerts == 0, "Recoverable alerts not cleared. Alerts: 0x%x",
388  alerts);
389  LOG_INFO("Recoverable alerts successfully cleared");
390 
391  // Acknowledge the Health Test Failed interrupt
392  TRY(dif_entropy_src_irq_acknowledge(&entropy_src,
393  kDifEntropySrcIrqEsHealthTestFailed));
394 
395  // Check the IRQ state again
396  dif_entropy_src_irq_state_snapshot_t irq_state;
397  TRY(dif_entropy_src_irq_get_state(&entropy_src, &irq_state));
398  LOG_INFO("ENTROPY_SRC IRQ State after acknowledging: 0x%x", irq_state);
399 
400  return OK_STATUS();
401  } else {
402  LOG_ERROR("No recoverable alerts detected when expected");
403  return INTERNAL();
404  }
405 }
406 
407 status_t execute_test(void) {
408  // Initialize peripherals and test environments
409  CHECK_STATUS_OK(init_test_environment());
410 
411  // Step 1: Disable the entropy complex
412  CHECK_STATUS_OK(disable_entropy_complex());
413 
414  // Step 2: Configure loose health test threshold values for boot-time / bypass
415  // mode
416  CHECK_STATUS_OK(configure_loose_health_tests());
417 
418  // Step 3: Enable ENTROPY_SRC in boot-time / bypass mode
419  CHECK_STATUS_OK(enable_loose_entropy_src_bypass_mode());
420 
421  // Step 4: Enable CSRNG
422  CHECK_STATUS_OK(enable_csrng());
423 
424  // Step 5: Enable both EDNs in boot-time request mode
425  CHECK_STATUS_OK(enable_edns_boot_mode());
426 
427  // Check for any error in configuring the modules
428  CHECK_STATUS_OK(entropy_testutils_error_check_b4_proceeding());
429 
430  // Step 6: Trigger the execution of a cryptographic hardware block consuming
431  // entropy (e.g. AES) to test EDN0
432  // Step 7: Verify the entropy consuming
433  // endpoint(e.g. AES) finishes its operation
434  CHECK_STATUS_OK(test_and_verify_aes_operation());
435 
436  // Step 8: Trigger the execution of an OTBN program requiring entropy from
437  // both EDN1 and EDN0
438  CHECK_STATUS_OK(start_otbn_program());
439 
440  // Step 9: Verify the OTBN program hangs
441  CHECK_STATUS_OK(verify_otbn_hang());
442 
443  // Step 10: Disable the entropy complex again
444  CHECK_STATUS_OK(disable_entropy_complex());
445 
446  // Step 11: Configure unrealistically stringent health test threshold values
447  // for boot-time / bypass mode
448  CHECK_STATUS_OK(configure_stringent_health_tests());
449 
450  // Step 12: Configure an alert threshold value of 1 in the ALERT_THRESHOLD
451  // register Step 13,14,15: Enable ENTROPY_SRC, CSRNG, and EDNs in boot-time /
452  // bypass mode again (complex)
453  CHECK_STATUS_OK(set_threshold_and_enable_stringent_entropy_src_bypass_mode());
454  CHECK_STATUS_OK(enable_csrng());
455  CHECK_STATUS_OK(enable_edns_boot_mode());
456 
457  // Check for any error in configuring the modules
458  CHECK_STATUS_OK(entropy_testutils_error_check_b4_proceeding());
459 
460  // Step 16: Verify that ENTROPY_SRC triggers a recoverable alert and sets the
461  // RECOV_ALERT_STS.ES_MAIN_SM_ALERT bit
462  CHECK_STATUS_OK(verify_recoverable_alert());
463 
464  LOG_INFO("Entropy source bypass mode health test completed");
465 
466  return OK_STATUS();
467 }
468 
469 bool test_main(void) {
470  LOG_INFO("Entering Entropy Source Bypass Mode Health Test");
471 
472  return status_ok(execute_test());
473 }