Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pentest] Update EDN SCA tests #25619

Merged
merged 1 commit into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 72 additions & 150 deletions sw/device/tests/penetrationtests/firmware/sca/edn_sca.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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 |
Expand All @@ -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();
}
Expand All @@ -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();
Expand Down
26 changes: 8 additions & 18 deletions sw/device/tests/penetrationtests/firmware/sca/edn_sca.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,43 +9,33 @@
#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.
*
* @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.
Expand Down
18 changes: 3 additions & 15 deletions sw/device/tests/penetrationtests/json/edn_sca_commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading