From 4c7fffb9accc365b1945e111f70c2348eb9e4543 Mon Sep 17 00:00:00 2001 From: Pascal Nasahl Date: Wed, 20 Mar 2024 13:52:18 +0100 Subject: [PATCH] [pentest] Ibex SCA tests This commit adds the following penetration tests: - ibex.sca.register_file_read - ibex.sca.register_file_write - ibex.sca.tl_read - ibex.sca.tl_write This code is used to check whether data written/read to/from the tegister file or transmitted over TL-UL leaks. Signed-off-by: Pascal Nasahl --- .../tests/crypto/cryptotest/firmware/BUILD | 20 ++ .../crypto/cryptotest/firmware/firmware.c | 5 + .../crypto/cryptotest/firmware/ibex_sca.c | 238 ++++++++++++++++++ .../crypto/cryptotest/firmware/ibex_sca.h | 18 ++ sw/device/tests/crypto/cryptotest/json/BUILD | 8 + .../tests/crypto/cryptotest/json/commands.h | 1 + .../cryptotest/json/ibex_sca_commands.c | 6 + .../cryptotest/json/ibex_sca_commands.h | 36 +++ 8 files changed, 332 insertions(+) create mode 100644 sw/device/tests/crypto/cryptotest/firmware/ibex_sca.c create mode 100644 sw/device/tests/crypto/cryptotest/firmware/ibex_sca.h create mode 100644 sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.c create mode 100644 sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.h diff --git a/sw/device/tests/crypto/cryptotest/firmware/BUILD b/sw/device/tests/crypto/cryptotest/firmware/BUILD index d093381bdd9e9..421b0b5037ee2 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/BUILD +++ b/sw/device/tests/crypto/cryptotest/firmware/BUILD @@ -185,6 +185,25 @@ cc_library( ], ) +cc_library( + name = "ibex_sca", + srcs = ["ibex_sca.c"], + hdrs = [ + "ibex_sca.h", + "status.h", + ], + deps = [ + "//sw/device/lib/base:memory", + "//sw/device/lib/base:status", + "//sw/device/lib/runtime:log", + "//sw/device/lib/testing/test_framework:ujson_ottf", + "//sw/device/lib/ujson", + "//sw/device/sca/lib:sca", + "//sw/device/tests/crypto/cryptotest/firmware:sca_lib", + "//sw/device/tests/crypto/cryptotest/json:ibex_sca_commands", + ], +) + cc_library( name = "kmac_sca", srcs = ["kmac_sca.c"], @@ -301,6 +320,7 @@ FIRMWARE_DEPS = [ ":hash", ":hmac", ":ibex_fi", + ":ibex_sca", ":kmac_sca", ":kmac", ":otbn_fi", diff --git a/sw/device/tests/crypto/cryptotest/firmware/firmware.c b/sw/device/tests/crypto/cryptotest/firmware/firmware.c index 196f50ad5f6ce..c5c9d18b8b64b 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/firmware.c +++ b/sw/device/tests/crypto/cryptotest/firmware/firmware.c @@ -20,6 +20,7 @@ #include "sw/device/tests/crypto/cryptotest/json/hash_commands.h" #include "sw/device/tests/crypto/cryptotest/json/hmac_commands.h" #include "sw/device/tests/crypto/cryptotest/json/ibex_fi_commands.h" +#include "sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.h" #include "sw/device/tests/crypto/cryptotest/json/kmac_commands.h" #include "sw/device/tests/crypto/cryptotest/json/kmac_sca_commands.h" #include "sw/device/tests/crypto/cryptotest/json/otbn_fi_commands.h" @@ -36,6 +37,7 @@ #include "hash.h" #include "hmac.h" #include "ibex_fi.h" +#include "ibex_sca.h" #include "kmac.h" #include "kmac_sca.h" #include "otbn_fi.h" @@ -77,6 +79,9 @@ status_t process_cmd(ujson_t *uj) { case kCryptotestCommandIbexFi: RESP_ERR(uj, handle_ibex_fi(uj)); break; + case kCryptotestCommandIbexSca: + RESP_ERR(uj, handle_ibex_sca(uj)); + break; case kCryptotestCommandKmacSca: RESP_ERR(uj, handle_kmac_sca(uj)); break; diff --git a/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.c b/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.c new file mode 100644 index 0000000000000..fbaec64bcee85 --- /dev/null +++ b/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.c @@ -0,0 +1,238 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "sw/device/tests/crypto/cryptotest/firmware/ibex_sca.h" + +#include "sw/device/lib/base/memory.h" +#include "sw/device/lib/base/status.h" +#include "sw/device/lib/runtime/log.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" +#include "sw/device/sca/lib/sca.h" +#include "sw/device/tests/crypto/cryptotest/firmware/sca_lib.h" +#include "sw/device/tests/crypto/cryptotest/firmware/status.h" +#include "sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.h" + +#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" + +// 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.tl_write + * + * This SCA penetration test executes the following instructions: + * - Loop num_iterations: + * - Set trigger + * - Write data over TL-UL into SRAM. + * - Unset trigger + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj The received uJSON data. + */ +status_t handle_ibex_sca_tl_write(ujson_t *uj) { + // Get data to write into SRAM. + ibex_sca_test_data_t uj_data; + TRY(ujson_deserialize_ibex_sca_test_data_t(uj, &uj_data)); + + // Get address of buffer located in SRAM. + uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer; + mmio_region_t sram_region_main_addr = + mmio_region_from_addr(sram_main_buffer_addr); + + // SCA code target. + for (int it = 0; it < uj_data.num_iterations; it++) { + sca_set_trigger_high(); + // Write provided data into SRAM. + for (int i = 0; i < 8; i++) { + mmio_region_write32(sram_region_main_addr, + i * (ptrdiff_t)sizeof(uint32_t), uj_data.data[i]); + } + sca_set_trigger_low(); + } + + // Acknowledge test. + ibex_sca_result_t uj_output; + uj_output.result = 0; + RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output); + return OK_STATUS(0); +} + +/** + * ibex.sca.tl_read + * + * This SCA penetration test executes the following instructions: + * - Loop num_iterations: + * - Set trigger + * - Read data from SRAM over TL-UL. + * - Unset trigger + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj The received uJSON data. + */ +status_t handle_ibex_sca_tl_read(ujson_t *uj) { + // Get data to write into SRAM. + ibex_sca_test_data_t uj_data; + TRY(ujson_deserialize_ibex_sca_test_data_t(uj, &uj_data)); + + // Get address of buffer located in SRAM. + uintptr_t sram_main_buffer_addr = (uintptr_t)&sram_main_buffer; + mmio_region_t sram_region_main_addr = + mmio_region_from_addr(sram_main_buffer_addr); + + // Write provided data into SRAM. + for (int i = 0; i < 8; i++) { + mmio_region_write32(sram_region_main_addr, i * (ptrdiff_t)sizeof(uint32_t), + uj_data.data[i]); + } + + uint32_t read_data[8]; + + // SCA code target. + for (int it = 0; it < uj_data.num_iterations; it++) { + sca_set_trigger_high(); + // Fetch data from SRAM. + for (int i = 0; i < 8; i++) { + read_data[i] = mmio_region_read32(sram_region_main_addr, + i * (ptrdiff_t)sizeof(uint32_t)); + } + sca_set_trigger_low(); + } + // Acknowledge test. + ibex_sca_result_t uj_output; + uj_output.result = 0; + RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output); + return OK_STATUS(0); +} + +/** + * ibex.sca.register_file_write + * + * This SCA penetration test executes the following instructions: + * - Loop num_iterations: + * - Set trigger + * - Write provided data to registers in RF + * - Unset trigger + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj The received uJSON data. + */ +status_t handle_ibex_sca_register_file_write(ujson_t *uj) { + // Get data to write into RF. + ibex_sca_test_data_t uj_data; + TRY(ujson_deserialize_ibex_sca_test_data_t(uj, &uj_data)); + // SCA code target. + for (int it = 0; it < uj_data.num_iterations; it++) { + sca_set_trigger_high(); + // Write provided data into register file. + asm volatile("mv x5, %0" : : "r"(uj_data.data[0])); + asm volatile("mv x6, %0" : : "r"(uj_data.data[1])); + asm volatile("mv x7, %0" : : "r"(uj_data.data[2])); + asm volatile("mv x28, %0" : : "r"(uj_data.data[3])); + asm volatile("mv x29, %0" : : "r"(uj_data.data[4])); + asm volatile("mv x30, %0" : : "r"(uj_data.data[5])); + asm volatile("mv x31, %0" : : "r"(uj_data.data[6])); + sca_set_trigger_low(); + } + // Acknowledge test. + ibex_sca_result_t uj_output; + uj_output.result = 0; + RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output); + return OK_STATUS(0); +} + +/** + * ibex.sca.register_file_read + * + * This SCA penetration test executes the following instructions: + * - Loop num_iterations: + * - Set trigger + * - Read data from RF + * - Unset trigger + * + * SCA traces are captured during trigger_high & trigger_low. + * + * @param uj The received uJSON data. + */ +status_t handle_ibex_sca_register_file_read(ujson_t *uj) { + // Get data to write into RF. + ibex_sca_test_data_t uj_data; + TRY(ujson_deserialize_ibex_sca_test_data_t(uj, &uj_data)); + // Initialize temporary registers with reference values. + asm volatile("mv x5, %0" : : "r"(uj_data.data[0])); + asm volatile("mv x6, %0" : : "r"(uj_data.data[1])); + asm volatile("mv x7, %0" : : "r"(uj_data.data[2])); + asm volatile("mv x28, %0" : : "r"(uj_data.data[3])); + asm volatile("mv x29, %0" : : "r"(uj_data.data[4])); + asm volatile("mv x30, %0" : : "r"(uj_data.data[5])); + + // SCA code target. + for (int it = 0; it < uj_data.num_iterations; it++) { + sca_set_trigger_high(); + // Copy registers. + asm volatile("mv x28, x5"); + asm volatile("mv x29, x6"); + asm volatile("mv x30, x7"); + sca_set_trigger_low(); + } + // Acknowledge test. + ibex_sca_result_t uj_output; + uj_output.result = 0; + RESP_OK(ujson_serialize_ibex_sca_result_t, uj, &uj_output); + return OK_STATUS(0); +} + +/** + * Initializes the Ibex SCA test. + * + * + * @param uj The received uJSON data. + */ +status_t handle_ibex_sca_init(ujson_t *uj) { + // Setup trigger and enable peripherals needed for the test. + 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); + + // Disable the instruction cache and dummy instructions for SCA. + sca_configure_cpu(); + + return OK_STATUS(0); +} + +/** + * Ibex SCA command handler. + * + * Command handler for the Ibex SCA command. + * + * @param uj The received uJSON data. + */ +status_t handle_ibex_sca(ujson_t *uj) { + ibex_sca_subcommand_t cmd; + TRY(ujson_deserialize_ibex_sca_subcommand_t(uj, &cmd)); + switch (cmd) { + case kIbexScaSubcommandInit: + return handle_ibex_sca_init(uj); + case kIbexScaSubcommandRFRead: + return handle_ibex_sca_register_file_read(uj); + case kIbexScaSubcommandRFWrite: + return handle_ibex_sca_register_file_write(uj); + case kIbexScaSubcommandTLRead: + return handle_ibex_sca_tl_read(uj); + case kIbexScaSubcommandTLWrite: + return handle_ibex_sca_tl_write(uj); + default: + LOG_ERROR("Unrecognized IBEX SCA subcommand: %d", cmd); + return INVALID_ARGUMENT(); + } + return OK_STATUS(0); +} diff --git a/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.h b/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.h new file mode 100644 index 0000000000000..b77af6a2d4323 --- /dev/null +++ b/sw/device/tests/crypto/cryptotest/firmware/ibex_sca.h @@ -0,0 +1,18 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef OPENTITAN_SW_DEVICE_TESTS_CRYPTO_CRYPTOTEST_FIRMWARE_IBEX_SCA_H_ +#define OPENTITAN_SW_DEVICE_TESTS_CRYPTO_CRYPTOTEST_FIRMWARE_IBEX_SCA_H_ + +#include "sw/device/lib/base/status.h" +#include "sw/device/lib/ujson/ujson.h" + +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); +status_t handle_ibex_sca_register_file_read(ujson_t *uj); +status_t handle_ibex_sca_init(ujson_t *uj); +status_t handle_ibex_sca(ujson_t *uj); + +#endif // OPENTITAN_SW_DEVICE_TESTS_CRYPTO_CRYPTOTEST_FIRMWARE_IBEX_SCA_H_ diff --git a/sw/device/tests/crypto/cryptotest/json/BUILD b/sw/device/tests/crypto/cryptotest/json/BUILD index 7ce254c030cc1..a6944f6032358 100644 --- a/sw/device/tests/crypto/cryptotest/json/BUILD +++ b/sw/device/tests/crypto/cryptotest/json/BUILD @@ -17,6 +17,7 @@ cc_library( ":hash_commands", ":hmac_commands", ":ibex_fi_commands", + ":ibex_sca_commands", ":kmac_commands", ":kmac_sca_commands", ":otbn_fi_commands", @@ -90,6 +91,13 @@ cc_library( deps = ["//sw/device/lib/ujson"], ) +cc_library( + name = "ibex_sca_commands", + srcs = ["ibex_sca_commands.c"], + hdrs = ["ibex_sca_commands.h"], + deps = ["//sw/device/lib/ujson"], +) + cc_library( name = "kmac_sca_commands", srcs = ["kmac_sca_commands.c"], diff --git a/sw/device/tests/crypto/cryptotest/json/commands.h b/sw/device/tests/crypto/cryptotest/json/commands.h index c5e8a71094914..3d8ab92628511 100644 --- a/sw/device/tests/crypto/cryptotest/json/commands.h +++ b/sw/device/tests/crypto/cryptotest/json/commands.h @@ -21,6 +21,7 @@ extern "C" { value(_, Kmac) \ value(_, AesSca) \ value(_, IbexFi) \ + value(_, IbexSca) \ value(_, KmacSca) \ value(_, OtbnFi) \ value(_, PrngSca) \ diff --git a/sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.c b/sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.c new file mode 100644 index 0000000000000..e24f9aa1d29ac --- /dev/null +++ b/sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.c @@ -0,0 +1,6 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#define UJSON_SERDE_IMPL 1 +#include "ibex_sca_commands.h" diff --git a/sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.h b/sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.h new file mode 100644 index 0000000000000..68736441179f1 --- /dev/null +++ b/sw/device/tests/crypto/cryptotest/json/ibex_sca_commands.h @@ -0,0 +1,36 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef OPENTITAN_SW_DEVICE_TESTS_CRYPTO_CRYPTOTEST_JSON_IBEX_SCA_COMMANDS_H_ +#define OPENTITAN_SW_DEVICE_TESTS_CRYPTO_CRYPTOTEST_JSON_IBEX_SCA_COMMANDS_H_ +#include "sw/device/lib/ujson/ujson_derive.h" +#ifdef __cplusplus +extern "C" { +#endif + +// clang-format off + +#define IBEXSCA_SUBCOMMAND(_, value) \ + value(_, Init) \ + value(_, RFRead) \ + value(_, RFWrite) \ + value(_, TLRead) \ + value(_, TLWrite) +UJSON_SERDE_ENUM(IbexScaSubcommand, ibex_sca_subcommand_t, IBEXSCA_SUBCOMMAND); + +#define IBEXSCA_TEST_DATA(field, string) \ + field(num_iterations, uint32_t) \ + field(data, uint32_t, 8) +UJSON_SERDE_STRUCT(IbexScaTestData, ibex_sca_test_data_t, IBEXSCA_TEST_DATA); + +#define IBEXSCA_RESULT(field, string) \ + field(result, uint32_t) +UJSON_SERDE_STRUCT(IbexScaResult, ibex_sca_result_t, IBEXSCA_RESULT); + +// clang-format on + +#ifdef __cplusplus +} +#endif +#endif // OPENTITAN_SW_DEVICE_TESTS_CRYPTO_CRYPTOTEST_JSON_IBEX_SCA_COMMANDS_H_