Software APIs
entropy_src_fips_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"
9 #include "sw/device/lib/base/status.h"
18 #include "sw/device/lib/testing/aes_testutils.h"
19 #include "sw/device/lib/testing/csrng_testutils.h"
20 #include "sw/device/lib/testing/entropy_testutils.h"
22 #include "sw/device/lib/testing/test_framework/check.h"
24 #include "sw/device/tests/otbn_randomness_impl.h"
25 
26 #include "entropy_src_regs.h" // autogenerated
28 
29 #define TIMEOUT (1000 * 1000)
30 
31 enum {
32  kEntropySrcStartupWaitMicros = 250000,
33 };
34 
35 OTTF_DEFINE_TEST_CONFIG();
36 
37 // Module handles
38 static dif_entropy_src_t entropy_src;
39 static dif_csrng_t csrng;
40 static dif_edn_t edn0;
41 static dif_edn_t edn1;
42 static dif_aes_t aes;
43 static dif_otbn_t otbn;
44 static dif_alert_handler_t alert_handler;
45 
46 status_t init_test_environment(void) {
47  LOG_INFO(
48  "Initializing modules entropy_src, csrng, edn0, edn1, aes, otbn and "
49  "alert_handler...");
50  TRY(dif_entropy_src_init(
53  &csrng));
54  TRY(dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN0_BASE_ADDR), &edn0));
55  TRY(dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN1_BASE_ADDR), &edn1));
56  TRY(dif_aes_init(mmio_region_from_addr(TOP_EARLGREY_AES_BASE_ADDR), &aes));
57  TRY(dif_otbn_init(mmio_region_from_addr(TOP_EARLGREY_OTBN_BASE_ADDR), &otbn));
58  TRY(dif_alert_handler_init(
60  &alert_handler));
61  return OK_STATUS();
62 }
63 
64 status_t print_entropy_src_state(const dif_entropy_src_t *entropy_src) {
65  // Declare a variable to hold the current state
67 
68  // Get the current state of the entropy source
69  TRY(dif_entropy_src_get_main_fsm_state(entropy_src, &cur_state));
70 
71  // Print the current state
72  LOG_INFO("Current ENTROPY_SRC state: 0x%x", cur_state);
73 
74  const char *state_description;
75  switch (cur_state) {
76  case kDifEntropySrcMainFsmStateIdle:
77  state_description = "Idle: Initial or inactive state.";
78  break;
79  case kDifEntropySrcMainFsmStateBootHTRunning:
80  state_description =
81  "Boot Health Tests Running: Health tests during boot.";
82  break;
83  case kDifEntropySrcMainFsmStateBootPostHTChk:
84  state_description =
85  "Boot Post Health Test Check: Health tests completed after boot.";
86  break;
87  case kDifEntropySrcMainFsmStateBootPhaseDone:
88  state_description =
89  "Boot Phase Done: Initial setup and checks completed.";
90  break;
91  case kDifEntropySrcMainFsmStateStartupHTStart:
92  state_description =
93  "Startup Health Tests Start: Start of health tests during startup.";
94  break;
95  case kDifEntropySrcMainFsmStateStartupPhase1:
96  state_description =
97  "Startup Phase 1: Initial configuration or loading constants.";
98  break;
99  case kDifEntropySrcMainFsmStateStartupPass1:
100  state_description =
101  "Startup Phase 1 Pass: Successful completion of the first phase of "
102  "startup.";
103  break;
104  case kDifEntropySrcMainFsmStateStartupFail1:
105  state_description =
106  "Startup Phase 1 Fail: Failure during the first phase of startup.";
107  break;
108  case kDifEntropySrcMainFsmStateContHTStart:
109  state_description =
110  "Continuous Health Tests Start: Start of continuous health tests.";
111  break;
112  case kDifEntropySrcMainFsmStateContHTRunning:
113  state_description =
114  "Continuous Health Tests Running: Health tests running in the "
115  "background.";
116  break;
117  case kDifEntropySrcMainFsmStateFWInsertStart:
118  state_description =
119  "Firmware Insert Start: Start of firmware insertion process.";
120  break;
121  case kDifEntropySrcMainFsmStateFWInsertMsg:
122  state_description =
123  "Firmware Insert Message: Firmware is providing data to the entropy "
124  "source.";
125  break;
126  case kDifEntropySrcMainFsmStateSha3MsgDone:
127  state_description =
128  "SHA-3 Message Done: SHA-3 message processing complete.";
129  break;
130  case kDifEntropySrcMainFsmStateSha3Process:
131  state_description =
132  "SHA-3 Process: SHA-3 hashing process actively running.";
133  break;
134  case kDifEntropySrcMainFsmStateSha3Valid:
135  state_description = "SHA-3 Valid: SHA-3 hash output is valid and ready.";
136  break;
137  case kDifEntropySrcMainFsmStateSha3Done:
138  state_description =
139  "SHA-3 Done: SHA-3 hashing process is fully complete.";
140  break;
141  case kDifEntropySrcMainFsmStateAlertState:
142  state_description = "Alert State: Entropy source has triggered an alert.";
143  break;
144  case kDifEntropySrcMainFsmStateAlertHang:
145  state_description =
146  "Alert Hang: Entropy source is in a hang state due to an alert.";
147  break;
148  case kDifEntropySrcMainFsmStateError:
149  state_description =
150  "Error: Generic error condition within the entropy source.";
151  break;
152  default:
153  state_description = "Unknown State";
154  break;
155  }
156  LOG_INFO("Current Entropy Source State: %s (0x%x)", state_description,
157  cur_state);
158 
159  return OK_STATUS();
160 }
161 
162 // Log alert fail test statistics
163 status_t log_entropy_src_failures_and_alerts(
164  const dif_entropy_src_t *entropy_src) {
165  // Statistics for total failures
167  TRY(dif_entropy_src_get_health_test_stats(entropy_src, &stats));
168 
169  // Fail counts
171  TRY(dif_entropy_src_get_alert_fail_counts(entropy_src, &fail_counts));
172 
173  // Iterate over all test variants (0..kDifEntropySrcTestNumVariants-1).
174  for (size_t i = 0; i < kDifEntropySrcTestNumVariants; ++i) {
175  switch ((dif_entropy_src_test_t)i) {
177  LOG_INFO("Test Repetition Count (Index %u):", i);
178  LOG_INFO("Watermarks: high=%u, low=%u", stats.high_watermark[i],
179  stats.low_watermark[i]);
180  LOG_INFO("All Fails: high=%u, low=%u", stats.high_fails[i],
181  stats.low_fails[i]);
182  LOG_INFO("Alert Fails (RepetitionCount): high=%u, low=%u",
183  fail_counts.high_fails[i], fail_counts.low_fails[i]);
184  break;
186  LOG_INFO("Test Adaptive Proportion (Index %u):", i);
187  LOG_INFO("Watermarks: high=%u, low=%u", stats.high_watermark[i],
188  stats.low_watermark[i]);
189  LOG_INFO("All Fails: high=%u, low=%u", stats.high_fails[i],
190  stats.low_fails[i]);
191  LOG_INFO("Alert Fails (Adaptive Proportion): high=%u, low=%u",
192  fail_counts.high_fails[i], fail_counts.low_fails[i]);
193  break;
195  LOG_INFO("Test Bucket (Index %u):", i);
196  LOG_INFO("Watermarks: high=%u, low=%u", stats.high_watermark[i],
197  stats.low_watermark[i]);
198  LOG_INFO("All Fails: high=%u, low=%u", stats.high_fails[i],
199  stats.low_fails[i]);
200  LOG_INFO("Alert Fails (Bucket): high=%u, low=%u",
201  fail_counts.high_fails[i], fail_counts.low_fails[i]);
202  break;
204  LOG_INFO("Test Markov (Index %u):", i);
205  LOG_INFO("Watermarks: high=%u, low=%u", stats.high_watermark[i],
206  stats.low_watermark[i]);
207  LOG_INFO("All Fails: high=%u, low=%u", stats.high_fails[i],
208  stats.low_fails[i]);
209  LOG_INFO("Alert Fails (Markov): high=%u, low=%u",
210  fail_counts.high_fails[i], fail_counts.low_fails[i]);
211  break;
212  default:
213  LOG_INFO("Test %u: Unused test type, moving on...", i);
214  break;
215  }
216  }
217 
218  return OK_STATUS();
219 }
220 
221 // Function to disable entropy complex
222 status_t disable_entropy_complex(void) {
223  // Using entropy test utility function to stop all EDN0, EDN1, CSRNG, and the
224  // Entropy
225  LOG_INFO("Disabling the entropy complex...");
226  return entropy_testutils_stop_all();
227 }
228 
229 status_t configure_realistic_fips_health_tests(void) {
230  LOG_INFO("Configuring loose health test thresholds...");
231 
232  // Check if entropy source is locked
233  bool is_locked;
234  TRY(dif_entropy_src_is_locked(&entropy_src, &is_locked));
235  TRY_CHECK(!is_locked,
236  "Entropy source is locked. Cannot configure ENTROPY_SRC");
237 
238  // Configure Repetition Count Test
239  dif_entropy_src_health_test_config_t repcnt_test_config = {
241  .high_threshold = 512,
242  .low_threshold = 0,
243  };
244  TRY(dif_entropy_src_health_test_configure(&entropy_src, repcnt_test_config));
245 
246  // Configure Adaptive Proportion Test
247  dif_entropy_src_health_test_config_t adaptp_test_config = {
249  .high_threshold = 512,
250  .low_threshold = 0,
251  };
252  TRY(dif_entropy_src_health_test_configure(&entropy_src, adaptp_test_config));
253 
254  // Configure Bucket Test
255  dif_entropy_src_health_test_config_t bucket_test_config = {
257  .high_threshold = 512,
258  .low_threshold = 0,
259  };
260  TRY(dif_entropy_src_health_test_configure(&entropy_src, bucket_test_config));
261 
262  // Configure Markov Test
263  dif_entropy_src_health_test_config_t markov_test_config = {
265  .high_threshold = 512,
266  .low_threshold = 0,
267  };
268  TRY(dif_entropy_src_health_test_configure(&entropy_src, markov_test_config));
269 
270  return OK_STATUS();
271 }
272 
273 status_t enable_realistic_entropy_src_fips_mode(
274  uint16_t health_test_window_size) {
275  LOG_INFO("Enabling ENTROPY_SRC in fips mode...");
276 
277  // Ensure the entropy source is not locked
278  bool is_locked;
279  TRY(dif_entropy_src_is_locked(&entropy_src, &is_locked));
280  TRY_CHECK(!is_locked,
281  "Entropy source is locked. Cannot configure ENTROPY_SRC");
282 
283  // Configure ENTROPY_SRC in fips mode with health tests enabled
284  dif_entropy_src_config_t config = {
285  .fips_enable = true,
286  .route_to_firmware = false,
287  .fips_flag = true,
288  .rng_fips = true,
289  .bypass_conditioner = false,
290  .single_bit_mode = kDifEntropySrcSingleBitModeDisabled,
291  .health_test_threshold_scope = true,
292  .health_test_window_size = health_test_window_size,
293  .alert_threshold = 0xFF,
294  };
295 
296  // Apply the configuration and enable ENTROPY_SRC
297  TRY(dif_entropy_src_configure(&entropy_src, config, kDifToggleEnabled));
298 
299  return OK_STATUS();
300 }
301 
302 status_t set_threshold_and_enable_stringent_entropy_src_fips_mode(void) {
303  LOG_INFO("Enabling stringent ENTROPY_SRC in fips mode...");
304 
305  // Ensure the entropy source is not locked
306  bool is_locked;
307  TRY(dif_entropy_src_is_locked(&entropy_src, &is_locked));
308  TRY_CHECK(!is_locked,
309  "Entropy source is locked. Cannot configure ENTROPY_SRC");
310 
311  // Configure ENTROPY_SRC in fips mode with health tests enabled
312  dif_entropy_src_config_t config = {
313  .fips_enable = true,
314  .route_to_firmware = false,
315  .fips_flag = true,
316  .rng_fips = true,
317  .bypass_conditioner = false,
318  .single_bit_mode = kDifEntropySrcSingleBitModeDisabled,
319  .health_test_threshold_scope = true,
320  .health_test_window_size = 4096,
321  .alert_threshold = 1,
322  };
323 
324  print_entropy_src_state(&entropy_src);
325  LOG_INFO("ENTROPY_SRC Configuration:");
326  LOG_INFO("fips_enable: %d", config.fips_enable);
327  LOG_INFO("route_to_firmware: %d", config.route_to_firmware);
328  LOG_INFO("fips_flag: %d", config.fips_flag);
329  LOG_INFO("rng_fips: %d", config.rng_fips);
330  LOG_INFO("bypass_conditioner: %d", config.bypass_conditioner);
331  LOG_INFO("single_bit_mode: %d", config.single_bit_mode);
332  LOG_INFO("health_test_threshold_scope: %d",
334  LOG_INFO("health_test_window_size: %d", config.health_test_window_size);
335  LOG_INFO("alert_threshold: %d", config.alert_threshold);
336 
337  // Apply the configuration and enable ENTROPY_SRC
338  TRY(dif_entropy_src_configure(&entropy_src, config, kDifToggleEnabled));
339  uint32_t errors;
340  TRY(dif_entropy_src_get_errors(&entropy_src, &errors));
341  LOG_INFO("ENTROPY_SRC Errors: 0x%x", errors);
342 
343  dif_entropy_src_irq_state_snapshot_t irq_state;
344  TRY(dif_entropy_src_irq_get_state(&entropy_src, &irq_state));
345  LOG_INFO("ENTROPY_SRC IRQ State: 0x%x", irq_state);
346  CHECK_STATUS_OK(print_entropy_src_state(&entropy_src));
347  // Debug try
349  TRY(dif_entropy_src_get_health_test_stats(&entropy_src, &stats));
350 
351  CHECK_STATUS_OK(print_entropy_src_state(&entropy_src));
352 
353  LOG_INFO("Done enabling stringent ENTROPY_SRC in fips mode...");
354  return OK_STATUS();
355 }
356 
357 status_t configure_stringent_fips_health_tests(void) {
358  LOG_INFO("Configuring stringent health test thresholds...");
359 
360  // Ensure the entropy source is not locked
361  bool is_locked;
362  TRY(dif_entropy_src_is_locked(&entropy_src, &is_locked));
363  TRY_CHECK(!is_locked,
364  "Entropy source is locked. Cannot configure ENTROPY_SRC");
365  // Configure Repetition Count Test with stringent threshold
366  dif_entropy_src_health_test_config_t repcnt_test_config = {
368  .high_threshold = 50,
369  .low_threshold = 0,
370  };
371  LOG_INFO("Repetition Count Test Configuration:");
372  LOG_INFO("test_type: %d", repcnt_test_config.test_type);
373  LOG_INFO("high_threshold: %d", repcnt_test_config.high_threshold);
374  LOG_INFO("low_threshold: %d", repcnt_test_config.low_threshold);
375  TRY(dif_entropy_src_health_test_configure(&entropy_src, repcnt_test_config));
376 
377  // Configure Adaptive Proportion Test with stringent threshold
378  dif_entropy_src_health_test_config_t adaptp_test_config = {
380  .high_threshold = 270,
381  .low_threshold = 0,
382  };
383  LOG_INFO("Adaptive Proportion Test Configuration:");
384  LOG_INFO("test_type: %d", adaptp_test_config.test_type);
385  LOG_INFO("high_threshold: %d", adaptp_test_config.high_threshold);
386  LOG_INFO("low_threshold: %d", adaptp_test_config.low_threshold);
387  TRY(dif_entropy_src_health_test_configure(&entropy_src, adaptp_test_config));
388 
389  // Configure Bucket Test with stringent threshold
390  dif_entropy_src_health_test_config_t bucket_test_config = {
392  .high_threshold = 270,
393  .low_threshold = 0,
394  };
395  LOG_INFO("Bucket Test Configuration:");
396  LOG_INFO("test_type: %d", bucket_test_config.test_type);
397  LOG_INFO("high_threshold: %d", bucket_test_config.high_threshold);
398  LOG_INFO("low_threshold: %d", bucket_test_config.low_threshold);
399  TRY(dif_entropy_src_health_test_configure(&entropy_src, bucket_test_config));
400 
401  // Configure Markov Test with stringent threshold
402  dif_entropy_src_health_test_config_t markov_test_config = {
404  .high_threshold = 270,
405  .low_threshold = 0,
406  };
407  LOG_INFO("Markov Test Configuration:");
408  LOG_INFO("test_type: %d", markov_test_config.test_type);
409  LOG_INFO("high_threshold: %d", markov_test_config.high_threshold);
410  LOG_INFO("low_threshold: %d", markov_test_config.low_threshold);
411  TRY(dif_entropy_src_health_test_configure(&entropy_src, markov_test_config));
412 
413  return OK_STATUS();
414 }
415 
416 //
417 // Custom version of entropy_testutils_auto_mode_init() for this test.
418 //
419 // Differences from the original version:
420 // Does NOT reinitialize the entropy complex (to retain previous state).
421 // Uses a custom reseed_interval (value = 4 instead of default 32).
422 // Includes additional debug logs to help track hang behavior.
423 
424 status_t my_entropy_testutils_auto_mode_init(void) {
425  TRY(entropy_testutils_stop_all());
426  busy_spin_micros(kEntropySrcStartupWaitMicros);
427 
428  print_entropy_src_state(&entropy_src);
429  // re-enable entropy src and csrng
430  CHECK_STATUS_OK(entropy_testutils_entropy_src_init());
431  print_entropy_src_state(&entropy_src);
432  busy_spin_micros(kEntropySrcStartupWaitMicros);
433  LOG_INFO("Configuring csrng:");
434  TRY(dif_csrng_configure(&csrng));
435  print_entropy_src_state(&entropy_src);
436 
437  LOG_INFO("Configuring csrng done:");
438  LOG_INFO("Setting EDN in auto mode...");
439  CHECK_STATUS_OK(print_entropy_src_state(&entropy_src));
440  const int my_reseed_interval = 4;
441  LOG_INFO("Setting EDN0 reseed_interval to %d", my_reseed_interval);
442  print_entropy_src_state(&entropy_src);
443  // Re-enable EDN0 in auto mode.
445  &edn0,
447  // EDN0 provides lower-quality entropy. Let one generate command
448  // return 8 blocks
449  .instantiate_cmd =
450  {
451  .cmd = csrng_cmd_header_build(kCsrngAppCmdInstantiate,
453  /*cmd_len=*/0,
454  /*generate_len=*/0),
455  .seed_material =
456  {
457  .len = 0,
458  },
459  },
460  .reseed_cmd =
461  {
462  .cmd = csrng_cmd_header_build(
463  kCsrngAppCmdReseed, kDifCsrngEntropySrcToggleEnable,
464  /*cmd_len=*/0, /*generate_len=*/0),
465  .seed_material =
466  {
467  .len = 0,
468  },
469  },
470  .generate_cmd =
471  {
472  // Generate 8 128-bit blocks.
473  .cmd = csrng_cmd_header_build(kCsrngAppCmdGenerate,
475  /*cmd_len=*/0,
476  /*generate_len=*/8),
477  .seed_material =
478  {
479  .len = 0,
480  },
481  },
482  // Reseed every 4 generates
483  .reseed_interval = my_reseed_interval,
484  }));
485 
486  LOG_INFO("Setting edn0 done:");
487  print_entropy_src_state(&entropy_src);
488  // Re-enable EDN1 in auto mode.
490  &edn1,
492  // EDN1 provides highest-quality entropy. Let one generate command
493  // return 1 block, and reseed after every generate.
494  .instantiate_cmd =
495  {
496  .cmd = csrng_cmd_header_build(kCsrngAppCmdInstantiate,
498  /*cmd_len=*/0,
499  /*generate_len=*/0),
500  .seed_material =
501  {
502  .len = 0,
503  },
504  },
505  .reseed_cmd =
506  {
507  .cmd = csrng_cmd_header_build(
508  kCsrngAppCmdReseed, kDifCsrngEntropySrcToggleEnable,
509  /*cmd_len=*/0, /*generate_len=*/0),
510  .seed_material =
511  {
512  .len = 0,
513  },
514  },
515  .generate_cmd =
516  {
517  // Generate 1 128-bit block.
518  .cmd = csrng_cmd_header_build(kCsrngAppCmdGenerate,
520  /*cmd_len=*/0,
521  /*generate_len=*/1),
522  .seed_material =
523  {
524  .len = 0,
525  },
526  },
527  // Reseed after every 4 generates.
528  .reseed_interval = 4,
529  }));
530  LOG_INFO("Setting edn1 done:");
531  return OK_STATUS();
532 }
533 
534 status_t enable_realistic_csrng_edns_auto_mode(void) {
535  LOG_INFO("Enabling EDNs in auto mode...");
536  CHECK_STATUS_OK(entropy_testutils_auto_mode_init());
537  return OK_STATUS();
538 }
539 
540 status_t enable_csrng_edns_auto_mode(void) {
541  LOG_INFO("Enabling EDNs in auto mode for fips(locally modified function)...");
542  CHECK_STATUS_OK(my_entropy_testutils_auto_mode_init());
543  LOG_INFO("Done Enabling EDNs in auto mode for fips...");
544  return OK_STATUS();
545 }
546 
547 status_t test_and_verify_aes_operation(void) {
548  LOG_INFO("Triggering AES operation in ECB mode...");
549 
550  // Setup ECB encryption transaction
551  dif_aes_transaction_t transaction = {
552  .operation = kDifAesOperationEncrypt,
553  .mode = kDifAesModeEcb,
554  .key_len = kDifAesKey256,
555  .key_provider = kDifAesKeySoftwareProvided,
556  .mask_reseeding = kDifAesReseedPerBlock,
557  .manual_operation = kDifAesManualOperationAuto,
558  .reseed_on_key_change = false,
559  .ctrl_aux_lock = false,
560  };
561 
562  // Configure encryption
563  CHECK_STATUS_OK(aes_testutils_setup_encryption(transaction, &aes));
564 
565  // Wait for the encryption to complete
566  AES_TESTUTILS_WAIT_FOR_STATUS(&aes, kDifAesStatusOutputValid, true, TIMEOUT);
567 
568  // Decrypt and verify
569  CHECK_STATUS_OK(aes_testutils_decrypt_ciphertext(transaction, &aes));
570 
571  LOG_INFO("AES operation in ECB mode verified successfully");
572  return OK_STATUS();
573 }
574 
575 static bool poll_for_output_valid_or_starve(const dif_aes_t *aes) {
576  const uint32_t kMaxRetries = 1000;
577  for (uint32_t i = 0; i < kMaxRetries; i++) {
578  bool out_valid = false;
579  dif_result_t dif_res =
581  if (dif_res != kDifOk) {
582  LOG_ERROR("dif_aes_get_status() = %d while polling OUTPUT_VALID.",
583  dif_res);
584  return false;
585  }
586  if (out_valid) {
587  return true;
588  }
589  // if no out_valid wait for 3ms
590  busy_spin_micros(3000);
591  }
592  // Timed out after kMaxRetries of 1000 * 3000 us i.e 3 sec
593  return false;
594 }
595 
596 #define AES_OPERATION_HANG_STATUS_VALUE 0x700B
597 static inline status_t aes_starve_ok_status(void) {
598  status_t st;
599  st.value = AES_OPERATION_HANG_STATUS_VALUE;
600  return st;
601 }
602 
603 static inline bool status_is_aes_starve_ok(status_t s) {
604  return (s.value == AES_OPERATION_HANG_STATUS_VALUE);
605 }
606 
607 status_t test_and_verify_aes_operation_hang(void) {
608  LOG_INFO("Perform AES-256 in ECB mode");
609 
610  // Construct a 256-bit software key share
611  // For a known 256-bit key: kAesModesKey256 (32 bytes)
612  // and a share array kKeyShare1[] (32 bytes).
613  static const uint8_t kKeyShare1[32] = {
614  0x0f, 0x1f, 0x2f, 0x3f, 0x4f, 0x5f, 0x6f, 0x7f, 0x8f, 0x9f, 0xaf,
615  0xbf, 0xcf, 0xdf, 0xef, 0xff, 0x0a, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a,
616  0x6a, 0x7a, 0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa};
617 
619  uint8_t key_share0[32];
620  for (int i = 0; i < 32; i++) {
621  key_share0[i] = kAesModesKey256[i] ^ kKeyShare1[i];
622  }
623  memcpy(key.share0, key_share0, 16);
624  memcpy(key.share1, &key_share0[16], 16);
625 
626  // Prepare an AES transaction for 256-bit ECB encryption.
627  dif_aes_transaction_t transaction = {
628  .operation = kDifAesOperationEncrypt,
629  .mode = kDifAesModeEcb,
630  .key_len = kDifAesKey256,
631  .key_provider = kDifAesKeySoftwareProvided,
632  .mask_reseeding = kDifAesReseedPerBlock,
633  .manual_operation = kDifAesManualOperationAuto,
634  .reseed_on_key_change = false,
635  .ctrl_aux_lock = false,
636  };
637 
638  // Single-block plaintext (16 bytes).
639  dif_aes_data_t in_data;
640  memcpy(in_data.data, kAesModesPlainText, 16);
641 
642  // Start AES encryption
643  LOG_INFO("Starting AES encryption...");
644  AES_TESTUTILS_WAIT_FOR_STATUS(&aes, kDifAesStatusIdle, true, TIMEOUT);
645  CHECK_DIF_OK(dif_aes_start(&aes, &transaction, &key, NULL));
646 
647  // Wait for InputReady, load the plaintext block.
648  LOG_INFO("Wait for AES InputReady, then load the single-block plaintext...");
649  AES_TESTUTILS_WAIT_FOR_STATUS(&aes, kDifAesStatusInputReady, true, TIMEOUT);
650  CHECK_DIF_OK(dif_aes_load_data(&aes, in_data));
651  LOG_INFO("Plaintext block loaded for encryption.");
652 
653  // Poll for OutputValid or starve
654  LOG_INFO("Polling for OutputValid in encryption...", TIMEOUT);
655  bool got_output_valid = poll_for_output_valid_or_starve(&aes);
656 
657  if (!got_output_valid) {
658  // starved; we shall treat it as pass
659  LOG_INFO(
660  "No OUTPUT_VALID... EDN starved during encryption expected pass "
661  "scenario");
662  return aes_starve_ok_status();
663  }
664 
665  // If we do get OUTPUT_VALID
666  dif_aes_data_t out_data;
667  CHECK_DIF_OK(dif_aes_read_output(&aes, &out_data));
668 
669  // End encryption transaction
670  CHECK_DIF_OK(dif_aes_end(&aes));
671  LOG_INFO("AES encryption transaction ended successfully.");
672 
673  // Switch to AES decryption
674  LOG_INFO("Switching to AES decryption mode...");
675  transaction.operation = kDifAesOperationDecrypt;
676  AES_TESTUTILS_WAIT_FOR_STATUS(&aes, kDifAesStatusIdle, true, TIMEOUT);
677  CHECK_DIF_OK(dif_aes_start(&aes, &transaction, &key, NULL));
678 
679  // Wait for InputReady, load the ciphertext
680  LOG_INFO("Waiting for InputReady to load ciphertext for decryption...");
681  AES_TESTUTILS_WAIT_FOR_STATUS(&aes, kDifAesStatusInputReady, true, TIMEOUT);
682  CHECK_DIF_OK(dif_aes_load_data(&aes, out_data));
683 
684  // Poll for OutputValid or starve
685  LOG_INFO("Polling for OutputValid in decryption...");
686  got_output_valid = poll_for_output_valid_or_starve(&aes);
687 
688  if (!got_output_valid) {
689  // starved; we shall treat it as pass
690  LOG_INFO(
691  "EDN starved during decryption expected pass "
692  "scenario");
693  return aes_starve_ok_status();
694  }
695 
696  // If we are here means we have a decrypted block
697  dif_aes_data_t dec_data;
698  CHECK_DIF_OK(dif_aes_read_output(&aes, &dec_data));
699  LOG_INFO("Decryption output read from hardware.");
700 
701  uint8_t *dec_bytes = (uint8_t *)dec_data.data;
702 
703  // End the AES decryption transaction
704  CHECK_DIF_OK(dif_aes_end(&aes));
705  LOG_INFO("ECB decryption transaction ended successfully.");
706 
707  // Compare the decrypted block with the original plaintext
708  LOG_INFO("Verifying decrypted block with original plaintext?");
709  if (memcmp(dec_data.data, kAesModesPlainText, 16) != 0) {
710  LOG_ERROR("Decryption mismatch => final plaintext != original!");
711  for (int i = 0; i < 16; i++) {
712  LOG_ERROR("Byte[%d]: got=0x%02x, want=0x%02x", i, dec_bytes[i],
713  kAesModesPlainText[i]);
714  }
715  return INTERNAL();
716  }
717 
718  LOG_INFO("AES operation in ECB mode verified successfully");
719  return OK_STATUS();
720 }
721 
722 status_t test_and_verify_otbn_operation(void) {
723  LOG_INFO("Starting OTBN randomness test...(expect completion)");
724 
725  // Start the OTBN randomness test with one iteration
726  otbn_randomness_test_start(&otbn, 1);
727  busy_spin_micros(9500);
728 
729  // Wait for a timeout period to check if OTBN is still busy
730  const uint32_t kIterateMaxRetries = 10;
731  bool otbn_busy = true;
732  uint32_t iter_cntr = kIterateMaxRetries;
733 
734  dif_otbn_status_t otbn_status;
735 
736  while (iter_cntr > 0) {
737  // Check if OTBN is still busy
738  TRY(dif_otbn_get_status(&otbn, &otbn_status));
739 
740  // Check if any of the busy status flags are set
741  otbn_busy = (otbn_status &
742  (kDifOtbnStatusBusyExecute | kDifOtbnStatusBusySecWipeDmem |
743  kDifOtbnStatusBusySecWipeImem)) != 0;
744  // If OTBN is no longer busy, it has completed successfully
745  // Break the loop
746  if (!otbn_busy) {
747  break;
748  }
749  iter_cntr--;
750  }
751 
752  // After timeout, if OTBN is not busy, we shall conclude it's
753  // completed running, lets check final status
754  if (!otbn_busy) {
755  // Print OTBN status and error bits
756  dif_otbn_err_bits_t otbn_err_bits;
757  TRY(dif_otbn_get_err_bits(&otbn, &otbn_err_bits));
758  LOG_INFO("OTBN status: 0x%x", otbn_status);
759  LOG_INFO("OTBN error bits: 0x%x", otbn_err_bits);
760 
761  LOG_INFO("OTBN program ran as expected with no hang");
762 
763  // Double check to confirm no other unexpected errors are
764  // present leading to hang
765  if (otbn_err_bits != kDifOtbnErrBitsNoError) {
766  LOG_ERROR("OTBN encountered unexpected errors");
767 
768  // Optionally, decode and print specific error bits
769  if (otbn_err_bits & kDifOtbnErrBitsBadDataAddr) {
770  LOG_ERROR("A BAD_DATA_ADDR error was observed");
771  }
772  if (otbn_err_bits & kDifOtbnErrBitsBadInsnAddr) {
773  LOG_ERROR("A BAD_INSN_ADDR error was observed");
774  }
775  if (otbn_err_bits & kDifOtbnErrBitsCallStack) {
776  LOG_ERROR("A CALL_STACK error was observed");
777  }
778  if (otbn_err_bits & kDifOtbnErrBitsIllegalInsn) {
779  LOG_ERROR("An ILLEGAL_INSN error was observed");
780  }
781  if (otbn_err_bits & kDifOtbnErrBitsLoop) {
782  LOG_ERROR("A LOOP error was observed");
783  }
784 
785  otbn_randomness_test_end(&otbn, 1);
786  return INTERNAL();
787  }
788  return OK_STATUS();
789  } else {
790  // If still busy after kIterateMaxRetries, OTBN has not completed and failed
791  LOG_ERROR("OTBN program did not complete run");
792  return INTERNAL();
793  }
794 }
795 
796 status_t wait_for_recoverable_alert(void) {
797  LOG_INFO("Waiting for Entropy Source recoverable alert to be asserted...");
798 
799  while (true) {
800  // Poll the recoverable alerts
801  uint32_t alerts = 0;
802  dif_result_t res =
803  dif_entropy_src_get_recoverable_alerts(&entropy_src, &alerts);
804  if (res != kDifOk) {
805  LOG_ERROR("dif_entropy_src_get_recoverable_alerts failed (res=%d)", res);
806  return INTERNAL();
807  }
808 
809  if (alerts != 0) {
810  // if found a recoverable alert => log & break
811  LOG_INFO("Recoverable alert detected. Alerts: 0x%x", alerts);
812 
813  print_entropy_src_state(&entropy_src);
814  log_entropy_src_failures_and_alerts(&entropy_src);
815 
816  const uint32_t kEsMainSmAlertBit =
817  ENTROPY_SRC_RECOV_ALERT_STS_ES_MAIN_SM_ALERT_BIT;
818 
819  if ((alerts & kEsMainSmAlertBit) != 0) {
820  LOG_INFO("ES_MAIN_SM_ALERT bit is set, as expected.");
821  } else {
822  LOG_INFO("ES_MAIN_SM_ALERT bit not set, continuing anyway...");
823  }
824 
825  // Acknowledge the Health Test Failed interrupt
826  dif_result_t ack_res = dif_entropy_src_irq_acknowledge(
827  &entropy_src, kDifEntropySrcIrqEsHealthTestFailed);
828  if (ack_res != kDifOk) {
829  LOG_INFO("Failed to acknowledge HealthTestFailed IRQ (res=%d).",
830  ack_res);
831  } else {
832  LOG_INFO("HealthTestFailed IRQ acknowledged.");
833  }
834  break;
835  }
836  // If no alerts --> sleep and poll again
837  busy_spin_micros(50000);
838  }
839 
840  LOG_INFO("Done waiting for Entropy Source recoverable alert (found).");
841  return OK_STATUS();
842 }
843 
844 status_t start_otbn_program(void) {
845  LOG_INFO("Starting OTBN randomness test...");
846 
847  // Start the OTBN randomness test with one iteration
848  otbn_randomness_test_start(&otbn, 1);
849 
850  LOG_INFO("OTBN randomness test started");
851  return OK_STATUS();
852 }
853 
854 status_t execute_test(void) {
855  // Initialize peripherals and test environments
856  CHECK_STATUS_OK(init_test_environment());
857 
858  // Step 8: Repeat the procedure with different health test window sizes for
859  // FIPS mode.
860  uint16_t window_sizes[5] = {256, 512, 1024, 2048, 4096};
861  for (uint16_t i = 0; i < ARRAYSIZE(window_sizes); i++) {
862  LOG_INFO("Testing health test window size value = %u", window_sizes[i]);
863  // Step 1: Disable the entropy complex
864  CHECK_STATUS_OK(disable_entropy_complex());
865 
866  // Step 2: Configure realistic health test threshold values for fips FIPS/CC
867  // compliant mode mode
868  CHECK_STATUS_OK(configure_realistic_fips_health_tests());
869 
870  // Step 3: Enable ENTROPY_SRC in FIPS mode
871  CHECK_STATUS_OK(enable_realistic_entropy_src_fips_mode(window_sizes[i]));
872 
873  // Step 4: Enable CSRNG
874  // Step 5: Enable both EDNs in auto request mode
875  CHECK_STATUS_OK(enable_realistic_csrng_edns_auto_mode());
876 
877  // Step 6: Trigger the execution of a cryptographic hardware block to stess
878  // test the entropy (e.g. AES, OTBN) to test EDN0
879  // Step 7: Verify the entropy consuming endpoint(e.g. AES, OTBN)
880  // finishes its operation
881  CHECK_STATUS_OK(test_and_verify_aes_operation());
882  CHECK_STATUS_OK(test_and_verify_aes_operation());
883  CHECK_STATUS_OK(test_and_verify_aes_operation());
884  CHECK_STATUS_OK(test_and_verify_otbn_operation());
885  CHECK_STATUS_OK(test_and_verify_otbn_operation());
886  CHECK_STATUS_OK(test_and_verify_otbn_operation());
887  }
888  LOG_INFO(
889  "Realistic Test successfully passed with different health test window "
890  "sizes...");
891 
892  for (uint16_t iter = 0; iter < 1; iter++) {
893  LOG_INFO("iter = %d", iter);
894 
895  // Step 9: Disable the entropy complex again
896  LOG_INFO("Step 9: Disable the entropy complex again. iter = %d", iter);
897  CHECK_STATUS_OK(disable_entropy_complex());
898 
899  // Step 10: Configure unrealistically stringent health test threshold values
900  // for FIPS mode
901  LOG_INFO(
902  "Step 10: Configure unrealistically stringent health test threshold "
903  "values. iter = %d",
904  iter);
905  CHECK_STATUS_OK(configure_stringent_fips_health_tests());
906 
907  // Step 11: Configure a low alert threshold value in the ALERT_THRESHOLD
908  // register Step 12: Enable ENTROPY_SRC in FIPS mode
909  LOG_INFO(
910  "Step 11 and Step 12:Configure a low alert threshold value in the "
911  "ALERT_THRESHOLD and enable entropy_src. iter = %d",
912  iter);
913  CHECK_STATUS_OK(set_threshold_and_enable_stringent_entropy_src_fips_mode());
914 
915  // Wait for Entropy Source startup tests to complete
916  busy_spin_micros(kEntropySrcStartupWaitMicros);
917  // Step 13: Enable CSRNG
918  // Step 14: Enable both EDNs in auto request mode and with low values for
919  // the generate length parameter to request fresh entropy more often
920  LOG_INFO(
921  "Step 13 and Step 14:Enable CSRNG and both EDNs in auto request mode. "
922  "iter = %d",
923  iter);
924  CHECK_STATUS_OK(enable_csrng_edns_auto_mode());
925  CHECK_STATUS_OK(print_entropy_src_state(&entropy_src));
926 
927  busy_spin_micros(kEntropySrcStartupWaitMicros);
928 
929  // Step 15: Trigger the execution of various cryptographic hardware blocks
930  // consuming entropy to stress test the entropy complex
931  LOG_INFO("Step 15 skipped!");
932  CHECK_STATUS_OK(print_entropy_src_state(&entropy_src));
933 
934  busy_spin_micros(kEntropySrcStartupWaitMicros);
935  // Step 16: Verify that ENTROPY_SRC triggers a recoverable alert and sets
936  // the RECOV_ALERT_STS.ES_MAIN_SM_ALERT bit
937  CHECK_STATUS_OK(print_entropy_src_state(&entropy_src));
938  // Find if we get recoverable alert and untill we hit
939  // recoverable alert we do not proceed
940  LOG_INFO("Step 16: Wait for recoverable alert");
941  LOG_INFO("Step 16:iter = %d", iter);
942  status_t st = wait_for_recoverable_alert();
943  if (!status_ok(st)) {
944  LOG_ERROR("wait_for_recoverable_alert() error=0x%x", st.value);
945  return INTERNAL();
946  }
947  CHECK_STATUS_OK(print_entropy_src_state(&entropy_src));
948 
949  // Step 17 Verify that various entropy consuming endpoints hang as
950  // ENTROPY_SRC stops generating entropy after triggering the recoverable
951  // alert
952  for (uint16_t i = 0; i < 500; i++) {
953  status_t st = test_and_verify_aes_operation_hang();
954  if (status_is_aes_starve_ok(st)) {
955  LOG_INFO(
956  "Step 17: Starve event encountered confirming AES expected hang");
957  break;
958  }
959  TRY(st);
960  }
961  CHECK_STATUS_OK(print_entropy_src_state(&entropy_src));
962  }
963 
964  LOG_INFO("Entropy source fips mode health test completed");
965 
966  return OK_STATUS();
967 }
968 
969 bool test_main(void) {
970  LOG_INFO("Entering Entropy Source FIPS Mode Health Test");
971 
972  return status_ok(execute_test());
973 }