From 76e7434fcc6ebb39e8d5a1069b858dbd3f1353dc Mon Sep 17 00:00:00 2001 From: Pascal Nasahl Date: Thu, 12 Dec 2024 06:18:52 +0100 Subject: [PATCH] [pentest] Update EDN SCA tests This commit updates the EDN SCA tests to use asm instead of C code such that the SCA target is more accurate. Signed-off-by: Pascal Nasahl Co-authored-by: Alexander Wagner (cherry picked from commit cb3defc058df2dd36e08bb3916378a1c088627ab) --- .../penetrationtests/firmware/sca/edn_sca.c | 222 ++++++------------ .../penetrationtests/firmware/sca/edn_sca.h | 26 +- .../penetrationtests/json/edn_sca_commands.h | 18 +- 3 files changed, 83 insertions(+), 183 deletions(-) diff --git a/sw/device/tests/penetrationtests/firmware/sca/edn_sca.c b/sw/device/tests/penetrationtests/firmware/sca/edn_sca.c index 8c66bb28e4f44..2e65686f14936 100644 --- a/sw/device/tests/penetrationtests/firmware/sca/edn_sca.c +++ b/sw/device/tests/penetrationtests/firmware/sca/edn_sca.c @@ -4,22 +4,19 @@ #include "sw/device/lib/base/memory.h" #include "sw/device/lib/base/status.h" -#include "sw/device/lib/dif/dif_csrng.h" -#include "sw/device/lib/dif/dif_csrng_shared.h" -#include "sw/device/lib/dif/dif_edn.h" -#include "sw/device/lib/dif/dif_entropy_src.h" #include "sw/device/lib/dif/dif_rv_core_ibex.h" +#include "sw/device/lib/runtime/ibex.h" #include "sw/device/lib/runtime/log.h" -#include "sw/device/lib/testing/entropy_testutils.h" #include "sw/device/lib/testing/rv_core_ibex_testutils.h" +#include "sw/device/lib/testing/test_framework/check.h" #include "sw/device/lib/testing/test_framework/ujson_ottf.h" #include "sw/device/lib/ujson/ujson.h" -#include "sw/device/sca/lib/prng.h" #include "sw/device/tests/penetrationtests/firmware/lib/pentest_lib.h" #include "sw/device/tests/penetrationtests/json/edn_sca_commands.h" #include "edn_regs.h" // Generated #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" +#include "rv_core_ibex_regs.h" // Generated // NOP macros. #define NOP1 "addi x0, x0, 0\n" @@ -38,165 +35,95 @@ enum { }; static dif_rv_core_ibex_t rv_core_ibex; -static dif_entropy_src_t entropy_src; -static dif_csrng_t csrng; -static dif_edn_t edn0; - -// Generate random values used by the test by calling the SCA PRNG. -static void generate_random(size_t num_values, uint32_t values[]) { - for (size_t i = 0; i < num_values; i++) { - values[i] = prng_rand_uint32(); + +/** + * Read randomness. + * + * The goal of this function is to allow the SCA setup to measure randomness + * transmitted from the 128-bit FIFO within the EDN to the Ibex RND_DATA + * register. + * + * To do so, this function first clears the 128-bit FIFO by reading it. When the + * FIFO is empty, the EDN sends a request to the CSRNG. When the FIFO again is + * full, set the SCA trigger and read the randomness from the FIFO to the + * RND_DATA register. + * + * @param ibex_rnd_data The array containing the randomness. + * @return OK or error. + */ +static status_t read_rnd_data_reg(uint32_t ibex_rnd_data[4]) { + // Clear the CSRNG FIFO containing randomness before starting the test. + for (size_t it = 0; it < 4; it++) { + TRY(dif_rv_core_ibex_read_rnd_data(&rv_core_ibex, &ibex_rnd_data[0])); + } + memset(ibex_rnd_data, 0, 4 * sizeof(uint32_t)); + // Wait until RND_DATA_VALID becomes true, i.e., randomness is available. + bool rnd_data_valid = rv_core_ibex_testutils_is_rnd_data_valid(&rv_core_ibex); + while (!rnd_data_valid) { + rnd_data_valid = rv_core_ibex_testutils_is_rnd_data_valid(&rv_core_ibex); } -} -// Configure the EDN with the provided seed material, set the SCA trigger, -// generate and receive random data, and unset the trigger. -static status_t config_run_edn(uint32_t init_seed[12], uint32_t reseed[12]) { - // Setup seed material. - // Seed material for the EDN instantiate command. - dif_edn_seed_material_t kEdnKatSeedMaterialInstantiate = { - .len = kEdnKatMaxClen, - .data = {init_seed[0], init_seed[1], init_seed[2], init_seed[3], - init_seed[4], init_seed[5], init_seed[6], init_seed[7], - init_seed[8], init_seed[9], init_seed[10], init_seed[11]}}; - // Seed material for the EDN reseed command. - dif_edn_seed_material_t kEdnKatSeedMaterialReseed = { - .len = kEdnKatMaxClen, - .data = {reseed[0], reseed[1], reseed[2], reseed[3], reseed[4], reseed[5], - reseed[6], reseed[7], reseed[8], reseed[9], reseed[10], - reseed[11]}}; - // Seed material for the EDN generate command. - const dif_edn_seed_material_t kEdnKatSeedMaterialGenerate = { - .len = 0, - }; - - dif_edn_auto_params_t edn_params; - edn_params.instantiate_cmd.cmd = csrng_cmd_header_build( - kCsrngAppCmdInstantiate, kDifCsrngEntropySrcToggleDisable, - kEdnKatSeedMaterialInstantiate.len, /*generate_len=*/0); - edn_params.instantiate_cmd.seed_material = kEdnKatSeedMaterialInstantiate; - edn_params.reseed_cmd.cmd = csrng_cmd_header_build( - kCsrngAppCmdReseed, kDifCsrngEntropySrcToggleDisable, - kEdnKatSeedMaterialReseed.len, - /*generate_len=*/0); - edn_params.reseed_cmd.seed_material = kEdnKatSeedMaterialReseed; - edn_params.generate_cmd.cmd = csrng_cmd_header_build( - kCsrngAppCmdGenerate, kDifCsrngEntropySrcToggleDisable, - kEdnKatSeedMaterialGenerate.len, - /*generate_len=*/ - kEdnKatOutputLen / kEdnKatWordsPerBlock); - - edn_params.generate_cmd.seed_material = kEdnKatSeedMaterialGenerate; - edn_params.reseed_interval = 32; - - // Disable the entropy complex. - TRY(entropy_testutils_stop_all()); - // Enable ENTROPY_SRC in FIPS mode. - TRY(dif_entropy_src_configure( - &entropy_src, entropy_testutils_config_default(), kDifToggleEnabled)); - // Enable CSRNG. - TRY(dif_csrng_configure(&csrng)); - // Enable EDN0 in auto request mode. - TRY(dif_edn_set_auto_mode(&edn0, edn_params)); - - uint32_t ibex_rnd_data; - - // Capture trace during generation and transportation of random data. + // Read RND_DATA register. First access contains randomness that already was + // transmitted over the bus. Afterwards, data needs to be transmitted from the + // randomness FIFO into the RND_DATA register - this is what we want to + // measure. pentest_set_trigger_high(); asm volatile(NOP30); - TRY(rv_core_ibex_testutils_get_rnd_data(&rv_core_ibex, kEdnKatTimeout, - &ibex_rnd_data)); - pentest_set_trigger_low(); + asm volatile("li t0, %0" + : + : "i"(TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR) + : "t0"); + asm volatile("lw t1, %0(t0)" + : + : "i"(RV_CORE_IBEX_RND_DATA_REG_OFFSET) + : "t1"); asm volatile(NOP30); + asm volatile(NOP30); + pentest_set_trigger_low(); + // Read RND_DATA which was transmitted from FIFO into RND_DATA register. + // Read it after the trigger window to not measure load into Ibex register + TRY(dif_rv_core_ibex_read_rnd_data(&rv_core_ibex, &ibex_rnd_data[3])); return OK_STATUS(); } -status_t handle_edn_sca_bus_data(ujson_t *uj) { - // Get seed material. - edn_sca_seed_t uj_data; - TRY(ujson_deserialize_edn_sca_seed_t(uj, &uj_data)); - - // Configure EDN with provided seed material, set trigger and start generating - // and fetching data. - config_run_edn(uj_data.init_seed, uj_data.reseed); - - // Acknowledge test. - edn_sca_result_t uj_output; - uj_output.result = 0; - RESP_OK(ujson_serialize_edn_sca_result_t, uj, &uj_output); - return OK_STATUS(); -} - -status_t handle_edn_sca_bus_data_batch_fvsr(ujson_t *uj) { - // Get seed material. - edn_sca_seed_batch_t uj_data; - TRY(ujson_deserialize_edn_sca_seed_batch_t(uj, &uj_data)); - - bool sample_fixed = true; - uint32_t last_value = 0; - - uint32_t init_seed[kNumBatchOpsMax][12]; - uint32_t reseed[kNumBatchOpsMax][12]; +status_t handle_edn_sca_bus_data_batch(ujson_t *uj) { + // Get number of iterations. + edn_sca_batch_t uj_data; + uint32_t max_iterations = 128; + TRY(ujson_deserialize_edn_sca_batch_t(uj, &uj_data)); + CHECK(uj_data.num_iterations <= max_iterations); + // Start num_iterations trigger windows. + uint32_t rand_data[max_iterations][4]; for (size_t it = 0; it < uj_data.num_iterations; it++) { - if (sample_fixed) { - memcpy(init_seed[it], uj_data.init_seed, 12 * sizeof(uint32_t)); - memcpy(reseed[it], uj_data.reseed, 12 * sizeof(uint32_t)); - } else { - // Generate random seeds for the EDN configuration. - generate_random(12, init_seed[it]); - generate_random(12, reseed[it]); - } - sample_fixed = prng_rand_uint32() & 0x1; + TRY(read_rnd_data_reg(rand_data[it])); } + // Send back num_iterations rand_data. for (size_t it = 0; it < uj_data.num_iterations; it++) { - // Configure EDN with random seed material, set trigger and start generating - // and fetching data. - TRY(config_run_edn(init_seed[it], reseed[it])); - last_value = reseed[it][11]; + edn_sca_result_t uj_output; + memcpy(&uj_output.rnd_data, rand_data[it], 4 * sizeof(uint32_t)); + RESP_OK(ujson_serialize_edn_sca_result_t, uj, &uj_output); } - // Acknowledge test, send last reseed value back to host - // for verification. - edn_sca_result_t uj_output; - uj_output.result = last_value; - RESP_OK(ujson_serialize_edn_sca_result_t, uj, &uj_output); return OK_STATUS(); } -status_t handle_edn_sca_bus_data_batch_random(ujson_t *uj) { - // Get number of iterations. - edn_sca_batch_t uj_data; - TRY(ujson_deserialize_edn_sca_batch_t(uj, &uj_data)); - - uint32_t init_seed[kNumBatchOpsMax][12]; - uint32_t reseed[kNumBatchOpsMax][12]; - for (size_t it = 0; it < uj_data.num_iterations; it++) { - // Generate random seeds for the EDN configuration. - generate_random(12, init_seed[it]); - generate_random(12, reseed[it]); - } +status_t handle_edn_sca_bus_data(ujson_t *uj) { + edn_sca_result_t uj_output; - for (size_t it = 0; it < uj_data.num_iterations; it++) { - // Configure EDN with random seed material, set trigger and start generating - // and fetching data. - TRY(config_run_edn(init_seed[it], reseed[it])); - } + TRY(read_rnd_data_reg(uj_output.rnd_data)); - // Acknowledge test, send last random reseed value back to host - // for verification. - edn_sca_result_t uj_output; - uj_output.result = reseed[uj_data.num_iterations - 1][11]; + // Send data back to host. RESP_OK(ujson_serialize_edn_sca_result_t, uj, &uj_output); return OK_STATUS(); } -status_t handle_edn_pentest_init(ujson_t *uj) { +status_t handle_edn_sca_init(ujson_t *uj) { pentest_select_trigger_type(kPentestTriggerTypeSw); // As we are using the software defined trigger, the first argument of - // pentest_init is not needed. kPentestTriggerSourceAes is selected as a + // sca_init is not needed. kPentestTriggerSourceAes is selected as a // placeholder. pentest_init(kPentestTriggerSourceAes, kPentestPeripheralIoDiv4 | kPentestPeripheralEntropy | @@ -210,12 +137,9 @@ status_t handle_edn_pentest_init(ujson_t *uj) { mmio_region_from_addr(TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR), &rv_core_ibex)); - // Initialize peripherals used in this SCA test. - TRY(dif_entropy_src_init( - mmio_region_from_addr(TOP_EARLGREY_ENTROPY_SRC_BASE_ADDR), &entropy_src)); - TRY(dif_csrng_init(mmio_region_from_addr(TOP_EARLGREY_CSRNG_BASE_ADDR), - &csrng)); - TRY(dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN0_BASE_ADDR), &edn0)); + // Configure the entropy complex. Set the reseed interval to max to avoid + // reseed during the trigger window. + TRY(pentest_configure_entropy_source_max_reseed_interval()); return OK_STATUS(); } @@ -224,14 +148,12 @@ status_t handle_edn_sca(ujson_t *uj) { edn_sca_subcommand_t cmd; TRY(ujson_deserialize_edn_sca_subcommand_t(uj, &cmd)); switch (cmd) { + case kEdnScaSubcommandInit: + return handle_edn_sca_init(uj); case kEdnScaSubcommandBusData: return handle_edn_sca_bus_data(uj); - case kEdnScaSubcommandBusDataBatchFvsr: - return handle_edn_sca_bus_data_batch_fvsr(uj); - case kEdnScaSubcommandBusDataBatchRandom: - return handle_edn_sca_bus_data_batch_random(uj); - case kEdnScaSubcommandInit: - return handle_edn_pentest_init(uj); + case kEdnScaSubcommandBusDataBatch: + return handle_edn_sca_bus_data_batch(uj); default: LOG_ERROR("Unrecognized EDN SCA subcommand: %d", cmd); return INVALID_ARGUMENT(); diff --git a/sw/device/tests/penetrationtests/firmware/sca/edn_sca.h b/sw/device/tests/penetrationtests/firmware/sca/edn_sca.h index 3dc704c1ee3f0..f623719d85124 100644 --- a/sw/device/tests/penetrationtests/firmware/sca/edn_sca.h +++ b/sw/device/tests/penetrationtests/firmware/sca/edn_sca.h @@ -9,35 +9,25 @@ #include "sw/device/lib/ujson/ujson.h" /** - * edn.sca.bus_data command handler. - * - * The goal of this penetration test is to capture traces when - * the EDN generated random data and transfers it to Ibex. + * edn.sca.bus_data_batch command handler. * - * @param uj An initialized uJSON context. - * @return OK or error. - */ -status_t handle_edn_sca_bus_data(ujson_t *uj); - -/** - * edn.sca.bus_data_batch_fvsr command handler. - * - * Batch version of edn.sca.bus_data with FvsR data. + * Batch version of edn.sca.bus_data with random data. * * @param uj An initialized uJSON context. * @return OK or error. */ -status_t handle_edn_sca_bus_data_batch_fvsr(ujson_t *uj); +status_t handle_edn_sca_bus_data_batch(ujson_t *uj); /** - * edn.sca.bus_data_batch_random command handler. + * edn.sca.bus_data command handler. * - * Batch version of edn.sca.bus_data with random data. + * The goal of this penetration test is to capture traces when + * randomness is transported over the bus to Ibex. * * @param uj An initialized uJSON context. * @return OK or error. */ -status_t handle_edn_sca_bus_data_batch_random(ujson_t *uj); +status_t handle_edn_sca_bus_data(ujson_t *uj); /** * Initializes the trigger and configures the device for the EDN SCA test. @@ -45,7 +35,7 @@ status_t handle_edn_sca_bus_data_batch_random(ujson_t *uj); * @param uj An initialized uJSON context. * @return OK or error. */ -status_t handle_edn_pentest_init(ujson_t *uj); +status_t handle_edn_sca_init(ujson_t *uj); /** * EDN SCA command handler. diff --git a/sw/device/tests/penetrationtests/json/edn_sca_commands.h b/sw/device/tests/penetrationtests/json/edn_sca_commands.h index b5c7e48635a65..95d0e54264b62 100644 --- a/sw/device/tests/penetrationtests/json/edn_sca_commands.h +++ b/sw/device/tests/penetrationtests/json/edn_sca_commands.h @@ -12,27 +12,15 @@ extern "C" { // clang-format off #define EDNSCA_SUBCOMMAND(_, value) \ + value(_, Init) \ value(_, BusData) \ - value(_, BusDataBatchFvsr) \ - value(_, BusDataBatchRandom) \ - value(_, Init) + value(_, BusDataBatch) UJSON_SERDE_ENUM(EdnScaSubcommand, edn_sca_subcommand_t, EDNSCA_SUBCOMMAND); #define EDNSCA_RESULT(field, string) \ - field(result, uint32_t) + field(rnd_data, uint32_t, 4) UJSON_SERDE_STRUCT(EdnScaResult, edn_sca_result_t, EDNSCA_RESULT); -#define EDNSCA_SEED(field, string) \ - field(init_seed, uint32_t, 12) \ - field(reseed, uint32_t, 12) -UJSON_SERDE_STRUCT(EdnScaSeed, edn_sca_seed_t, EDNSCA_SEED); - -#define EDNSCA_SEED_BATCH(field, string) \ - field(init_seed, uint32_t, 12) \ - field(reseed, uint32_t, 12) \ - field(num_iterations, uint32_t) -UJSON_SERDE_STRUCT(EdnScaSeedBatch, edn_sca_seed_batch_t, EDNSCA_SEED_BATCH); - #define EDNSCA_BATCH(field, string) \ field(num_iterations, uint32_t) UJSON_SERDE_STRUCT(EdnScaBatch, edn_sca_batch_t, EDNSCA_BATCH);