From 87605372c60ade77fa28ab6d9e9d8e9513b55da5 Mon Sep 17 00:00:00 2001 From: Pascal Nasahl Date: Tue, 26 Mar 2024 17:30:29 +0100 Subject: [PATCH] [pentest] Add Ibex FI & SCA tests This commit adds the following SCA and FI penetration tests: - ibex.fi.address_translation - ibex.fi.address_translation_config - ibex.fi.char.csr_write - ibex.fi.char.csr_read - ibex.sca.key_sideloading The host code is located in lowRISC/ot-sca#350 Signed-off-by: Pascal Nasahl --- .../tests/crypto/cryptotest/firmware/BUILD | 9 +- .../crypto/cryptotest/firmware/ibex_fi.S | 228 ++++++++++++ .../crypto/cryptotest/firmware/ibex_fi.c | 330 ++++++++++++++++++ .../crypto/cryptotest/firmware/ibex_fi.h | 5 + .../crypto/cryptotest/firmware/ibex_sca.c | 67 +++- .../crypto/cryptotest/firmware/ibex_sca.h | 1 + .../crypto/cryptotest/json/ibex_fi_commands.h | 6 +- .../cryptotest/json/ibex_sca_commands.h | 12 +- 8 files changed, 654 insertions(+), 4 deletions(-) create mode 100644 sw/device/tests/crypto/cryptotest/firmware/ibex_fi.S diff --git a/sw/device/tests/crypto/cryptotest/firmware/BUILD b/sw/device/tests/crypto/cryptotest/firmware/BUILD index b6e126dc6d04bb..8b653112615ce5 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/BUILD +++ b/sw/device/tests/crypto/cryptotest/firmware/BUILD @@ -168,12 +168,16 @@ cc_library( cc_library( name = "ibex_fi", - srcs = ["ibex_fi.c"], + srcs = [ + "ibex_fi.S", + "ibex_fi.c", + ], hdrs = [ "ibex_fi.h", "status.h", ], deps = [ + "//sw/device/lib/base:csr", "//sw/device/lib/base:memory", "//sw/device/lib/base:status", "//sw/device/lib/dif:flash_ctrl", @@ -198,7 +202,10 @@ cc_library( deps = [ "//sw/device/lib/base:memory", "//sw/device/lib/base:status", + "//sw/device/lib/dif:keymgr", + "//sw/device/lib/dif:kmac", "//sw/device/lib/runtime:log", + "//sw/device/lib/testing:keymgr_testutils", "//sw/device/lib/testing/test_framework:ujson_ottf", "//sw/device/lib/ujson", "//sw/device/sca/lib:sca", diff --git a/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.S b/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.S new file mode 100644 index 00000000000000..e8712d2706a759 --- /dev/null +++ b/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.S @@ -0,0 +1,228 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +/** + * Increments a value 100 times by 1. + * + * @param a0 initial value which gets incremented. + */ + .globl target_function + .type target_function, @function + .balign 256 +target_function: + // a0: init value + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + addi a0, a0, 1 + ret + + +/** + * Increments a value 100 times by 10. + * + * @param a0 initial value which gets incremented. + */ + .globl expected_function + .type expected_function, @function + .balign 256 +expected_function: + // a0: init value + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + addi a0, a0, 10 + ret diff --git a/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.c b/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.c index ae60d3aedd7071..954ad508046bac 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.c +++ b/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.c @@ -4,6 +4,8 @@ #include "sw/device/tests/crypto/cryptotest/firmware/ibex_fi.h" +#include "sw/device/lib/base/csr.h" +#include "sw/device/lib/base/csr_registers.h" #include "sw/device/lib/base/memory.h" #include "sw/device/lib/base/status.h" #include "sw/device/lib/dif/dif_flash_ctrl.h" @@ -20,6 +22,26 @@ #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" +// A function which takes an uint32_t as its only argument. +typedef uint32_t (*str_fn_t)(uint32_t); + +/** + * Increment start_value 100 times by 10. + * + * @param start_value The initial value which gets incremented. + */ +extern uint32_t expected_function(uint32_t start_value); + +/** + * Increment start_value 100 times by 1 + * + * @param input The initial value which gets incremented. + */ +extern uint32_t target_function(uint32_t start_value); + +static str_fn_t expected_function_remapped = (str_fn_t)expected_function; +static str_fn_t target_function_remapped = (str_fn_t)target_function; + // Make sure that this function does not get optimized by the compiler. uint32_t increment_counter(uint32_t counter) __attribute__((optnone)) { uint32_t return_value = counter + 1; @@ -90,6 +112,306 @@ static dif_flash_ctrl_device_info_t flash_info; OT_SECTION(".data") static volatile uint32_t sram_main_buffer[32]; +/** + * ibex.fi.address_translation command handler. + * + * This FI penetration tests executes the following instructions: + * - Configure the address translation for slot 0 and 1. + * - target_function gets remapped to expected_function and + * expected_function gets remapped to target_function using the address + * translation unit + * - Set the trigger. + * - Add 100 NOPs to delay the trigger. + * - Execute the expected_function. + * - Unset the trigger. + * - Check if instead of the expected function the target function was called. + * - Return the values over UART. + * + * Faults are injected during the trigger_high & trigger_low. + * It needs to be ensured that the compiler does not optimize this code. + * + * @param uj The received uJSON data. + */ +status_t handle_ibex_fi_address_translation(ujson_t *uj) { + // Configure Ibex to allow reading ERR_STATUS register. + dif_rv_core_ibex_t rv_core_ibex; + UJSON_CHECK_DIF_OK(dif_rv_core_ibex_init( + mmio_region_from_addr(TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR), + &rv_core_ibex)); + + // Create translation descriptions. + dif_rv_core_ibex_addr_translation_mapping_t expected_function_mapping = { + .matching_addr = (uintptr_t)target_function, + .remap_addr = (uintptr_t)expected_function, + .size = 256, + }; + dif_rv_core_ibex_addr_translation_mapping_t target_function_mapping = { + .matching_addr = (uintptr_t)expected_function, + .remap_addr = (uintptr_t)target_function, + .size = 256, + }; + + // Configure slot 0 for the expected_function. + UJSON_CHECK_DIF_OK(dif_rv_core_ibex_configure_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_0, + kDifRvCoreIbexAddrTranslationIBus, expected_function_mapping)); + UJSON_CHECK_DIF_OK(dif_rv_core_ibex_configure_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_0, + kDifRvCoreIbexAddrTranslationDBus, expected_function_mapping)); + + // Configure slot 1 for the target_function. + UJSON_CHECK_DIF_OK(dif_rv_core_ibex_configure_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_1, + kDifRvCoreIbexAddrTranslationIBus, target_function_mapping)); + UJSON_CHECK_DIF_OK(dif_rv_core_ibex_configure_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_1, + kDifRvCoreIbexAddrTranslationDBus, target_function_mapping)); + + // Enable the slots. + UJSON_CHECK_DIF_OK(dif_rv_core_ibex_enable_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_0, + kDifRvCoreIbexAddrTranslationIBus)); + UJSON_CHECK_DIF_OK(dif_rv_core_ibex_enable_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_0, + kDifRvCoreIbexAddrTranslationDBus)); + + UJSON_CHECK_DIF_OK(dif_rv_core_ibex_enable_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_1, + kDifRvCoreIbexAddrTranslationIBus)); + UJSON_CHECK_DIF_OK(dif_rv_core_ibex_enable_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_1, + kDifRvCoreIbexAddrTranslationDBus)); + + // FI code target. + uint32_t result_expected = 0; + sca_set_trigger_high(); + asm volatile(NOP100); + result_expected = expected_function_remapped(0); + sca_set_trigger_low(); + uint32_t result_target = target_function_remapped(0); + // Compare values + uint32_t res = 0; + if (result_expected != 100) { + res = 1; + } + + if (result_target != 1000) { + res |= 1; + } + + // Read ERR_STATUS register. + dif_rv_core_ibex_error_status_t codes; + UJSON_CHECK_DIF_OK(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); + + // Send res & ERR_STATUS to host. + ibex_fi_test_result_t uj_output; + uj_output.result = res; + uj_output.err_status = codes; + RESP_OK(ujson_serialize_ibex_fi_test_result_t, uj, &uj_output); + return OK_STATUS(0); +} + +/** + * ibex.fi.address_translation_config command handler. + * + * This FI penetration tests executes the following instructions: + * - Configure the address translation for DMEM and IMEM. + * - Set the trigger. + * - Add 1000 NOPs. + * - Unset the trigger. + * - Read address translation config. + * - Compare the values. + * - Return the values over UART. + * + * Faults are injected during the trigger_high & trigger_low. + * It needs to be ensured that the compiler does not optimize this code. + * + * @param uj The received uJSON data. + */ +status_t handle_ibex_fi_address_translation_config(ujson_t *uj) { + // Configure Ibex to allow reading ERR_STATUS register. + dif_rv_core_ibex_t rv_core_ibex; + UJSON_CHECK_DIF_OK(dif_rv_core_ibex_init( + mmio_region_from_addr(TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR), + &rv_core_ibex)); + + // Address translation configuration. + dif_rv_core_ibex_addr_translation_mapping_t mapping1 = { + .matching_addr = 0xa0000000, + .remap_addr = (uintptr_t)handle_ibex_fi_address_translation_config, + .size = 256, + }; + + dif_rv_core_ibex_addr_translation_mapping_t mapping2 = { + .matching_addr = 0xa0000000, + .remap_addr = (uintptr_t)handle_ibex_fi_address_translation_config, + .size = 256, + }; + + // Write address translation configuration. + UJSON_CHECK_DIF_OK(dif_rv_core_ibex_configure_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_0, + kDifRvCoreIbexAddrTranslationIBus, mapping1)); + + // FI code target. + // Either slot 0 config, which is already written, or slot 1 config, which + // gets written is targeted using FI. + sca_set_trigger_high(); + UJSON_CHECK_DIF_OK(dif_rv_core_ibex_configure_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_1, + kDifRvCoreIbexAddrTranslationDBus, mapping2)); + asm volatile(NOP1000); + sca_set_trigger_low(); + + // Read back address translation configuration. + dif_rv_core_ibex_addr_translation_mapping_t mapping1_read_back; + dif_rv_core_ibex_addr_translation_mapping_t mapping2_read_back; + UJSON_CHECK_DIF_OK(dif_rv_core_ibex_read_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_0, + kDifRvCoreIbexAddrTranslationIBus, &mapping1_read_back)); + UJSON_CHECK_DIF_OK(dif_rv_core_ibex_read_addr_translation( + &rv_core_ibex, kDifRvCoreIbexAddrTranslationSlot_1, + kDifRvCoreIbexAddrTranslationDBus, &mapping2_read_back)); + + uint32_t res = 0; + // Compare mapping 1. + if ((mapping1_read_back.matching_addr != mapping1.matching_addr) || + (mapping1_read_back.remap_addr != mapping1.remap_addr) || + (mapping1_read_back.size != mapping1.size)) { + res = 1; + } + + // Compare mapping 2. + if ((mapping2_read_back.matching_addr != mapping2.matching_addr) || + (mapping2_read_back.remap_addr != mapping2.remap_addr) || + (mapping2_read_back.size != mapping2.size)) { + res = 1; + } + + // Read ERR_STATUS register. + dif_rv_core_ibex_error_status_t codes; + UJSON_CHECK_DIF_OK(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); + + // Send res & ERR_STATUS to host. + ibex_fi_test_result_t uj_output; + uj_output.result = res; + uj_output.err_status = codes; + RESP_OK(ujson_serialize_ibex_fi_test_result_t, uj, &uj_output); + return OK_STATUS(0); +} + +/** + * ibex.fi.char.csr_write command handler. + * + * This FI penetration tests executes the following instructions: + * - Set the trigger. + * - Add 10 NOPs to delay the trigger + * - Write reference values into CSR. + * - Unset the trigger. + * - Read value from CSR. + * - Compare the values. + * - Return the values over UART. + * + * Faults are injected during the trigger_high & trigger_low. + * It needs to be ensured that the compiler does not optimize this code. + * + * @param uj The received uJSON data. + */ +status_t handle_ibex_fi_char_csr_write(ujson_t *uj) { + // Configure Ibex to allow reading ERR_STATUS register. + dif_rv_core_ibex_t rv_core_ibex; + UJSON_CHECK_DIF_OK(dif_rv_core_ibex_init( + mmio_region_from_addr(TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR), + &rv_core_ibex)); + + // FI code target. + sca_set_trigger_high(); + asm volatile(NOP10); + for (int i = 0; i < 100; i++) { + CSR_WRITE(CSR_REG_MSCRATCH, ref_values[0]); + } + asm volatile(NOP10); + sca_set_trigger_low(); + + uint32_t res_values; + // Read values from CSRs. + CSR_READ(CSR_REG_MSCRATCH, &res_values); + + // Compare against reference values. + uint32_t res = 0; + if (res_values != ref_values[0]) { + res = 1; + } + + // Read ERR_STATUS register. + dif_rv_core_ibex_error_status_t codes; + UJSON_CHECK_DIF_OK(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); + + // Send res & ERR_STATUS to host. + ibex_fi_test_result_t uj_output; + uj_output.result = res; + uj_output.err_status = codes; + RESP_OK(ujson_serialize_ibex_fi_test_result_t, uj, &uj_output); + return OK_STATUS(0); +} + +/** + * ibex.fi.char.csr_read command handler. + * + * This FI penetration tests executes the following instructions: + * - Write reference values into CSRs. + * - Set the trigger. + * - Add 10 NOPs to delay the trigger + * - Read values from CSRs. + * - Unset the trigger. + * - Compare the values. + * - Return the values over UART. + * + * Faults are injected during the trigger_high & trigger_low. + * It needs to be ensured that the compiler does not optimize this code. + * + * @param uj The received uJSON data. + */ +status_t handle_ibex_fi_char_csr_read(ujson_t *uj) { + // Configure Ibex to allow reading ERR_STATUS register. + dif_rv_core_ibex_t rv_core_ibex; + UJSON_CHECK_DIF_OK(dif_rv_core_ibex_init( + mmio_region_from_addr(TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR), + &rv_core_ibex)); + + // Write reference value into CSR. + CSR_WRITE(CSR_REG_MSCRATCH, ref_values[0]); + + uint32_t res_values[32]; + // FI code target. + sca_set_trigger_high(); + asm volatile(NOP10); + for (int i = 0; i < 32; i++) { + CSR_READ(CSR_REG_MSCRATCH, &res_values[i]); + } + asm volatile(NOP10); + sca_set_trigger_low(); + + // Compare against reference values. + uint32_t res = 0; + for (int i = 0; i < 32; i++) { + if (res_values[i] != ref_values[0]) { + res |= 1; + } + } + + // Read ERR_STATUS register. + dif_rv_core_ibex_error_status_t codes; + UJSON_CHECK_DIF_OK(dif_rv_core_ibex_get_error_status(&rv_core_ibex, &codes)); + + // Send res & ERR_STATUS to host. + ibex_fi_test_result_t uj_output; + uj_output.result = res; + uj_output.err_status = codes; + RESP_OK(ujson_serialize_ibex_fi_test_result_t, uj, &uj_output); + return OK_STATUS(0); +} + /** * ibex.char.flash_read command handler. * @@ -962,6 +1284,14 @@ status_t handle_ibex_fi(ujson_t *uj) { return handle_ibex_fi_char_flash_write(uj); case kIbexFiSubcommandCharFlashRead: return handle_ibex_fi_char_flash_read(uj); + case kIbexFiSubcommandCharCsrWrite: + return handle_ibex_fi_char_csr_write(uj); + case kIbexFiSubcommandCharCsrRead: + return handle_ibex_fi_char_csr_read(uj); + case kIbexFiSubcommandAddressTranslationCfg: + return handle_ibex_fi_address_translation_config(uj); + case kIbexFiSubcommandAddressTranslation: + return handle_ibex_fi_address_translation(uj); default: LOG_ERROR("Unrecognized IBEX FI subcommand: %d", cmd); return INVALID_ARGUMENT(); diff --git a/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.h b/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.h index 2e9f8d795b671c..1acc4ec044d90a 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.h +++ b/sw/device/tests/crypto/cryptotest/firmware/ibex_fi.h @@ -8,6 +8,11 @@ #include "sw/device/lib/base/status.h" #include "sw/device/lib/ujson/ujson.h" +status_t handle_ibex_fi_address_translation(ujson_t *uj); +status_t handle_ibex_fi_address_translation_config(ujson_t *uj); +status_t handle_ibex_fi_char_csr_read(ujson_t *uj); +status_t handle_ibex_fi_char_csr_write(ujson_t *uj); +status_t handle_ibex_fi_char_flash_write(ujson_t *uj); status_t handle_ibex_fi_char_flash_read(ujson_t *uj); status_t handle_ibex_fi_char_flash_write(ujson_t *uj); status_t handle_ibex_fi_char_sram_read(ujson_t *uj); diff --git a/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.c b/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.c index fbaec64bcee857..7c4eeab391bab7 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.c +++ b/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.c @@ -6,7 +6,10 @@ #include "sw/device/lib/base/memory.h" #include "sw/device/lib/base/status.h" +#include "sw/device/lib/dif/dif_keymgr.h" +#include "sw/device/lib/dif/dif_kmac.h" #include "sw/device/lib/runtime/log.h" +#include "sw/device/lib/testing/keymgr_testutils.h" #include "sw/device/lib/testing/test_framework/ottf_test_config.h" #include "sw/device/lib/testing/test_framework/ujson_ottf.h" #include "sw/device/lib/ujson/ujson.h" @@ -17,12 +20,72 @@ #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" +static dif_keymgr_t keymgr; +static dif_kmac_t kmac; + // Buffer to allow the compiler to allocate a safe area in Main SRAM where // we can do the write/read test without the risk of clobbering data // used by the program. OT_SECTION(".data") static volatile uint32_t sram_main_buffer[8]; +/** + * ibex.sca.key_sideloading + * + * This SCA penetration test executes the following instructions: + * - Retrieve salt over UART & feed salt into keymanager + * - Set trigger + * - Instruct the keymanager to generate a key based on the salt. + * - Unset trigger + * - Read back generated key provided at the SW interface of the keymanager. + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj The received uJSON data. + */ +status_t handle_ibex_sca_key_sideloading(ujson_t *uj) { + ibex_sca_salt_t uj_data; + TRY(ujson_deserialize_ibex_sca_salt_t(uj, &uj_data)); + + // Initialize keymgr and advance to CreatorRootKey state. + UJSON_CHECK_STATUS_OK(keymgr_testutils_startup(&keymgr, &kmac)); + + // Generate identity at CreatorRootKey (to follow same sequence and reuse + // chip_sw_keymgr_key_derivation_vseq.sv). + UJSON_CHECK_STATUS_OK(keymgr_testutils_generate_identity(&keymgr)); + + // Advance to OwnerIntermediateKey state. + UJSON_CHECK_STATUS_OK( + keymgr_testutils_advance_state(&keymgr, &kOwnerIntParams)); + UJSON_CHECK_STATUS_OK(keymgr_testutils_check_state( + &keymgr, kDifKeymgrStateOwnerIntermediateKey)); + + // Set the salt based on the input. + dif_keymgr_versioned_key_params_t sideload_params = kKeyVersionedParams; + for (int i = 0; i < 8; i++) { + sideload_params.salt[i] = uj_data.salt[i]; + } + + // Trigger keymanager to create a new key based on the provided salt. + sca_set_trigger_high(); + UJSON_CHECK_STATUS_OK( + keymgr_testutils_generate_versioned_key(&keymgr, sideload_params)); + sca_set_trigger_low(); + + // Read back generated key provided at the software interface. + dif_keymgr_output_t key; + UJSON_CHECK_DIF_OK(dif_keymgr_read_output(&keymgr, &key)); + + // Acknowledge test. + ibex_sca_key_t uj_key; + for (int i = 0; i < 8; i++) { + uj_key.share0[i] = key.value[0][i]; + uj_key.share1[i] = key.value[1][i]; + } + RESP_OK(ujson_serialize_ibex_sca_key_t, uj, &uj_key); + return OK_STATUS(0); +} + /** * ibex.sca.tl_write * @@ -201,7 +264,7 @@ status_t handle_ibex_sca_init(ujson_t *uj) { sca_select_trigger_type(kScaTriggerTypeSw); // As we are using the software defined trigger, the first argument of // sca_init is not needed. kScaTriggerSourceAes is selected as a placeholder. - sca_init(kScaTriggerSourceAes, kScaPeripheralIoDiv4); + sca_init(kScaTriggerSourceAes, kScaPeripheralIoDiv4 | kScaPeripheralKmac); // Disable the instruction cache and dummy instructions for SCA. sca_configure_cpu(); @@ -230,6 +293,8 @@ status_t handle_ibex_sca(ujson_t *uj) { return handle_ibex_sca_tl_read(uj); case kIbexScaSubcommandTLWrite: return handle_ibex_sca_tl_write(uj); + case kIbexScaSubcommandKeySideloading: + return handle_ibex_sca_key_sideloading(uj); default: LOG_ERROR("Unrecognized IBEX SCA subcommand: %d", cmd); return INVALID_ARGUMENT(); diff --git a/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.h b/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.h index b77af6a2d43234..2e05a832cf192c 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.h +++ b/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.h @@ -8,6 +8,7 @@ #include "sw/device/lib/base/status.h" #include "sw/device/lib/ujson/ujson.h" +status_t handle_ibex_sca_key_sideloading(ujson_t *uj); status_t handle_ibex_sca_tl_write(ujson_t *uj); status_t handle_ibex_sca_tl_read(ujson_t *uj); status_t handle_ibex_sca_register_file_write(ujson_t *uj); diff --git a/sw/device/tests/crypto/cryptotest/json/ibex_fi_commands.h b/sw/device/tests/crypto/cryptotest/json/ibex_fi_commands.h index 8c2daf1216f9f8..c3b6e8d377f8b0 100644 --- a/sw/device/tests/crypto/cryptotest/json/ibex_fi_commands.h +++ b/sw/device/tests/crypto/cryptotest/json/ibex_fi_commands.h @@ -24,7 +24,11 @@ extern "C" { value(_, CharSramWrite) \ value(_, CharSramRead) \ value(_, CharFlashWrite) \ - value(_, CharFlashRead) + value(_, CharFlashRead) \ + value(_, CharCsrRead) \ + value(_, CharCsrWrite) \ + value(_, AddressTranslationCfg) \ + value(_, AddressTranslation) UJSON_SERDE_ENUM(IbexFiSubcommand, ibex_fi_subcommand_t, IBEXFI_SUBCOMMAND); #define IBEXFI_TEST_RESULT(field, string) \ diff --git a/sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.h b/sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.h index 68736441179f18..74ca1a363d28c7 100644 --- a/sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.h +++ b/sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.h @@ -16,7 +16,8 @@ extern "C" { value(_, RFRead) \ value(_, RFWrite) \ value(_, TLRead) \ - value(_, TLWrite) + value(_, TLWrite) \ + value(_, KeySideloading) UJSON_SERDE_ENUM(IbexScaSubcommand, ibex_sca_subcommand_t, IBEXSCA_SUBCOMMAND); #define IBEXSCA_TEST_DATA(field, string) \ @@ -24,6 +25,15 @@ UJSON_SERDE_ENUM(IbexScaSubcommand, ibex_sca_subcommand_t, IBEXSCA_SUBCOMMAND); field(data, uint32_t, 8) UJSON_SERDE_STRUCT(IbexScaTestData, ibex_sca_test_data_t, IBEXSCA_TEST_DATA); +#define IBEXSCA_SALT(field, string) \ + field(salt, uint32_t, 8) +UJSON_SERDE_STRUCT(IbexScaSalt, ibex_sca_salt_t, IBEXSCA_SALT); + +#define IBEXSCA_KEY(field, string) \ + field(share0, uint32_t, 8) \ + field(share1, uint32_t, 8) +UJSON_SERDE_STRUCT(IbexScaKey, ibex_sca_key_t, IBEXSCA_KEY); + #define IBEXSCA_RESULT(field, string) \ field(result, uint32_t) UJSON_SERDE_STRUCT(IbexScaResult, ibex_sca_result_t, IBEXSCA_RESULT);