| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| #include "sw/device/lib/dif/dif_keymgr.h" |
| |
| #include "gtest/gtest.h" |
| #include "sw/device/lib/base/mmio.h" |
| #include "sw/device/lib/base/testing/mock_mmio.h" |
| |
| #include "keymgr_regs.h" // Generated |
| |
| namespace dif_keymgr_unittest { |
| namespace { |
| |
| /** |
| * Returns a `uint32_t` with a single zero bit. |
| */ |
| uint32_t AllOnesExcept(uint32_t index) { return ~(1u << index); } |
| |
| /** |
| * Returns a vector of values for a given enum type. |
| * |
| * Assumes that the values are sequential and the first value is 0. `last` must |
| * be the last valid value for the given enum and is included in the returned |
| * vector. |
| */ |
| template <typename T> |
| std::vector<T> CreateEnumVector(T last) { |
| using TT = typename std::underlying_type<T>::type; |
| std::vector<T> res; |
| for (TT i = 0; i <= static_cast<TT>(last); ++i) { |
| res.push_back(static_cast<T>(i)); |
| } |
| return res; |
| } |
| |
| /** |
| * Returns a seemingly valid, i.e. nonzero, pointer for the given type or a |
| * `nullptr`. |
| */ |
| template <typename T> |
| T *GetGoodBadPtrArg(bool is_good) { |
| if (is_good) { |
| return reinterpret_cast<T *>(alignof(T)); |
| } else { |
| return nullptr; |
| } |
| } |
| |
| /** |
| * Returns a valid or invalid value for the given enum type. |
| * |
| * `last` must be the last valid value of the given enum type and `last+1` must |
| * be an invalid value. |
| */ |
| template <typename T> |
| T GetGoodBadEnumArg(bool is_good, T last) { |
| if (is_good) { |
| return last; |
| } else { |
| return static_cast<T>(last + 1); |
| } |
| } |
| |
| /** |
| * Constants used in tests. |
| */ |
| static constexpr std::array<uint32_t, 3> kStatesWithOperationalNextStates{ |
| KEYMGR_WORKING_STATE_STATE_VALUE_INIT, |
| KEYMGR_WORKING_STATE_STATE_VALUE_CREATOR_ROOT_KEY, |
| KEYMGR_WORKING_STATE_STATE_VALUE_OWNER_INTERMEDIATE_KEY, |
| }; |
| static constexpr std::array<uint32_t, 4> kStatesWithNonOperationalNextStates{ |
| KEYMGR_WORKING_STATE_STATE_VALUE_RESET, |
| KEYMGR_WORKING_STATE_STATE_VALUE_OWNER_KEY, |
| KEYMGR_WORKING_STATE_STATE_VALUE_DISABLED, |
| KEYMGR_WORKING_STATE_STATE_VALUE_INVALID, |
| }; |
| |
| class DifKeymgrTest : public testing::Test, public mock_mmio::MmioTest { |
| protected: |
| /** |
| * Parameters for initializing a `dif_keymgr_t`. |
| */ |
| const dif_keymgr_params_t params_ = {.base_addr = dev().region()}; |
| }; |
| |
| /** |
| * Class for parameterizing bad argument tests for functions with two arguments. |
| */ |
| class BadArgsTwo : public DifKeymgrTest, |
| public testing::WithParamInterface<std::tuple<bool, bool>> { |
| protected: |
| bool AllParamsGood() { |
| return std::get<0>(GetParam()) && std::get<1>(GetParam()); |
| } |
| |
| void SetUp() override { |
| if (AllParamsGood()) { |
| // Only test negative cases. |
| GTEST_SKIP(); |
| } |
| } |
| }; |
| |
| INSTANTIATE_TEST_SUITE_P( |
| BadArgsTwo, BadArgsTwo, testing::Combine(testing::Bool(), testing::Bool()), |
| [&](testing::TestParamInfo<std::tuple<bool, bool>> info) { |
| auto stringify = [](bool foo) { return foo ? "Good" : "Bad"; }; |
| std::stringstream ss; |
| ss << stringify(std::get<0>(info.param)) |
| << stringify(std::get<1>(info.param)); |
| return ss.str(); |
| }); |
| |
| /** |
| * Class for parameterizing bad argument tests for functions with three |
| * arguments. |
| */ |
| class BadArgsThree |
| : public DifKeymgrTest, |
| public testing::WithParamInterface<std::tuple<bool, bool, bool>> { |
| protected: |
| bool AllParamsGood() { |
| return std::get<0>(GetParam()) && std::get<1>(GetParam()) && |
| std::get<2>(GetParam()); |
| } |
| |
| void SetUp() override { |
| if (AllParamsGood()) { |
| // Only test negative cases. |
| GTEST_SKIP(); |
| } |
| } |
| }; |
| |
| INSTANTIATE_TEST_SUITE_P( |
| BadArgsThree, BadArgsThree, |
| testing::Combine(testing::Bool(), testing::Bool(), testing::Bool()), |
| [&](testing::TestParamInfo<std::tuple<bool, bool, bool>> info) { |
| auto stringify = [](bool foo) { return foo ? "Good" : "Bad"; }; |
| std::stringstream ss; |
| ss << stringify(std::get<0>(info.param)) |
| << stringify(std::get<1>(info.param)) |
| << stringify(std::get<2>(info.param)); |
| return ss.str(); |
| }); |
| |
| class InitTest : public DifKeymgrTest {}; |
| |
| TEST_F(InitTest, BadArgs) { |
| EXPECT_EQ(dif_keymgr_init(params_, nullptr), kDifKeymgrBadArg); |
| } |
| |
| TEST_F(InitTest, Init) { |
| dif_keymgr_t keymgr; |
| EXPECT_EQ(dif_keymgr_init(params_, &keymgr), kDifKeymgrOk); |
| } |
| |
| /** |
| * Base class for the rest of the tests in this file, provides a |
| * `dif_keymgr_t` instance and some methods for common expectations. |
| */ |
| class DifKeymgrInitialized : public DifKeymgrTest { |
| protected: |
| /** |
| * Expectations for an idle key manager. |
| */ |
| void ExpectIdle() { |
| EXPECT_READ32(KEYMGR_OP_STATUS_REG_OFFSET, |
| {{ |
| .offset = KEYMGR_OP_STATUS_STATUS_OFFSET, |
| .value = KEYMGR_OP_STATUS_STATUS_VALUE_IDLE, |
| }}); |
| EXPECT_READ32(KEYMGR_CFG_REGWEN_REG_OFFSET, |
| {{ |
| .offset = KEYMGR_CFG_REGWEN_EN_BIT, |
| .value = 1, |
| }}); |
| } |
| |
| /** |
| * Expectations for an idle key manager at a given state. |
| */ |
| void ExpectIdleAtState(uint32_t state) { |
| ExpectIdle(); |
| EXPECT_READ32(KEYMGR_WORKING_STATE_REG_OFFSET, |
| {{ |
| .offset = KEYMGR_WORKING_STATE_STATE_OFFSET, |
| .value = state, |
| }}); |
| } |
| |
| /** |
| * Expectations for a busy key manager. |
| */ |
| void ExpectBusy() { |
| EXPECT_READ32(KEYMGR_OP_STATUS_REG_OFFSET, |
| {{ |
| .offset = KEYMGR_OP_STATUS_STATUS_OFFSET, |
| .value = KEYMGR_OP_STATUS_STATUS_VALUE_WIP, |
| }}); |
| } |
| |
| /** |
| * Expectations for a locked CONFIG register. |
| */ |
| void ExpectLockedConfig() { |
| EXPECT_READ32(KEYMGR_OP_STATUS_REG_OFFSET, |
| {{ |
| .offset = KEYMGR_OP_STATUS_STATUS_OFFSET, |
| .value = KEYMGR_OP_STATUS_STATUS_VALUE_IDLE, |
| }}); |
| EXPECT_READ32(KEYMGR_CFG_REGWEN_REG_OFFSET, |
| AllOnesExcept(KEYMGR_CFG_REGWEN_EN_BIT)); |
| } |
| |
| struct OperationStartParams { |
| uint32_t dest_sel; |
| uint32_t operation; |
| }; |
| |
| /** |
| * Expectations for starting an operation. |
| */ |
| void ExpectOperationStart(const OperationStartParams ¶ms) { |
| EXPECT_WRITE32(KEYMGR_CONTROL_REG_OFFSET, |
| {{ |
| .offset = KEYMGR_CONTROL_DEST_SEL_OFFSET, |
| .value = params.dest_sel, |
| }, |
| { |
| .offset = KEYMGR_CONTROL_OPERATION_OFFSET, |
| .value = params.operation, |
| }, |
| { |
| .offset = KEYMGR_CONTROL_START_BIT, |
| .value = 1, |
| }}); |
| } |
| |
| /** |
| * Initialized `dif_keymgr_t` used in tests. |
| */ |
| const dif_keymgr_t keymgr_ = {.params = params_}; |
| }; |
| |
| class ConfigureTest : public DifKeymgrInitialized {}; |
| |
| TEST_F(ConfigureTest, BadArgs) { |
| EXPECT_EQ(dif_keymgr_configure(nullptr, {}), kDifKeymgrBadArg); |
| } |
| |
| TEST_F(ConfigureTest, Configure) { |
| constexpr dif_keymgr_config_t kConfig = {.entropy_reseed_interval = 0xA5A5}; |
| |
| EXPECT_WRITE32_SHADOWED(KEYMGR_RESEED_INTERVAL_SHADOWED_REG_OFFSET, |
| kConfig.entropy_reseed_interval); |
| |
| EXPECT_EQ(dif_keymgr_configure(&keymgr_, kConfig), kDifKeymgrOk); |
| } |
| |
| class AdvanceStateTest : public DifKeymgrInitialized { |
| protected: |
| dif_keymgr_state_params_t kStateParams{ |
| .binding_value = {0xFF, 0xC3, 0xB9, 0xA5, 0x00, 0x3C, 0x46, 0x5A}, |
| .max_key_version = 0xA5A5A5A5, |
| }; |
| |
| struct MaxKeyVersionRegInfo { |
| uint32_t offset; |
| uint32_t wen_offset; |
| uint32_t wen_bit_index; |
| }; |
| |
| /** |
| * Returns max key version register information for the given state. |
| */ |
| MaxKeyVersionRegInfo GetMaxKeyVersionRegInfo(uint32_t state) { |
| switch (state) { |
| case KEYMGR_WORKING_STATE_STATE_VALUE_INIT: |
| return { |
| .offset = KEYMGR_MAX_CREATOR_KEY_VER_SHADOWED_REG_OFFSET, |
| .wen_offset = KEYMGR_MAX_CREATOR_KEY_VER_REGWEN_REG_OFFSET, |
| .wen_bit_index = KEYMGR_MAX_CREATOR_KEY_VER_REGWEN_EN_BIT, |
| }; |
| case KEYMGR_WORKING_STATE_STATE_VALUE_CREATOR_ROOT_KEY: |
| return { |
| .offset = KEYMGR_MAX_OWNER_INT_KEY_VER_SHADOWED_REG_OFFSET, |
| .wen_offset = KEYMGR_MAX_OWNER_INT_KEY_VER_REGWEN_REG_OFFSET, |
| .wen_bit_index = KEYMGR_MAX_OWNER_INT_KEY_VER_REGWEN_EN_BIT, |
| }; |
| case KEYMGR_WORKING_STATE_STATE_VALUE_OWNER_INTERMEDIATE_KEY: |
| return { |
| .offset = KEYMGR_MAX_OWNER_KEY_VER_SHADOWED_REG_OFFSET, |
| .wen_offset = KEYMGR_MAX_OWNER_KEY_VER_REGWEN_REG_OFFSET, |
| .wen_bit_index = KEYMGR_MAX_OWNER_KEY_VER_REGWEN_EN_BIT, |
| }; |
| default: |
| ADD_FAILURE(); |
| abort(); |
| break; |
| } |
| } |
| }; |
| |
| TEST_F(AdvanceStateTest, BadArgsNoKeymgr) { |
| EXPECT_EQ(dif_keymgr_advance_state(nullptr, &kStateParams), |
| kDifKeymgrLockableBadArg); |
| EXPECT_EQ(dif_keymgr_advance_state(nullptr, nullptr), |
| kDifKeymgrLockableBadArg); |
| } |
| |
| class AdvanceToOperational : public AdvanceStateTest, |
| public testing::WithParamInterface<uint32_t> {}; |
| |
| TEST_P(AdvanceToOperational, BadArgsToOperationalWithoutParams) { |
| ExpectIdleAtState(GetParam()); |
| |
| EXPECT_EQ(dif_keymgr_advance_state(&keymgr_, nullptr), |
| kDifKeymgrLockableBadArg); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(AdvanceToOperational, AdvanceToOperational, |
| testing::ValuesIn(kStatesWithOperationalNextStates)); |
| |
| class AdvanceToNonOperational : public AdvanceStateTest, |
| public testing::WithParamInterface<uint32_t> {}; |
| |
| TEST_P(AdvanceToNonOperational, BadArgsToNonOperationalWithParams) { |
| ExpectIdleAtState(GetParam()); |
| |
| EXPECT_EQ(dif_keymgr_advance_state(&keymgr_, &kStateParams), |
| kDifKeymgrLockableBadArg); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| AdvanceToNonOperational, AdvanceToNonOperational, |
| testing::ValuesIn(kStatesWithNonOperationalNextStates)); |
| |
| TEST_F(AdvanceStateTest, LockedBusy) { |
| ExpectBusy(); |
| |
| EXPECT_EQ(dif_keymgr_advance_state(&keymgr_, &kStateParams), |
| kDifKeymgrLockableLocked); |
| } |
| |
| TEST_F(AdvanceStateTest, LockedConfig) { |
| ExpectLockedConfig(); |
| |
| EXPECT_EQ(dif_keymgr_advance_state(&keymgr_, &kStateParams), |
| kDifKeymgrLockableLocked); |
| } |
| |
| TEST_P(AdvanceToOperational, LockedBinding) { |
| ExpectIdleAtState(GetParam()); |
| EXPECT_READ32(KEYMGR_SW_BINDING_REGWEN_REG_OFFSET, 0); |
| |
| EXPECT_EQ(dif_keymgr_advance_state(&keymgr_, &kStateParams), |
| kDifKeymgrLockableLocked); |
| } |
| |
| TEST_P(AdvanceToOperational, LockedMaxKeyVersion) { |
| ExpectIdleAtState(GetParam()); |
| EXPECT_READ32(KEYMGR_SW_BINDING_REGWEN_REG_OFFSET, |
| {{ |
| .offset = KEYMGR_SW_BINDING_REGWEN_EN_BIT, |
| .value = 1, |
| }}); |
| EXPECT_READ32(GetMaxKeyVersionRegInfo(GetParam()).wen_offset, 0); |
| |
| EXPECT_EQ(dif_keymgr_advance_state(&keymgr_, &kStateParams), |
| kDifKeymgrLockableLocked); |
| } |
| |
| TEST_P(AdvanceToOperational, Success) { |
| ExpectIdleAtState(GetParam()); |
| EXPECT_READ32(KEYMGR_SW_BINDING_REGWEN_REG_OFFSET, |
| {{ |
| .offset = KEYMGR_SW_BINDING_REGWEN_EN_BIT, |
| .value = 1, |
| }}); |
| auto reg_info = GetMaxKeyVersionRegInfo(GetParam()); |
| EXPECT_READ32(reg_info.wen_offset, {{ |
| .offset = reg_info.wen_bit_index, |
| .value = 1, |
| }}); |
| size_t binding_len = sizeof(kStateParams.binding_value) / |
| sizeof(kStateParams.binding_value[0]); |
| for (size_t i = 0; i < binding_len; ++i) { |
| EXPECT_WRITE32(KEYMGR_SEALING_SW_BINDING_0_REG_OFFSET + i * 4, |
| kStateParams.binding_value[i]); |
| } |
| EXPECT_WRITE32(KEYMGR_SW_BINDING_REGWEN_REG_OFFSET, 0); |
| EXPECT_WRITE32_SHADOWED(reg_info.offset, kStateParams.max_key_version); |
| EXPECT_WRITE32(reg_info.wen_offset, 0); |
| ExpectOperationStart({ |
| .dest_sel = KEYMGR_CONTROL_DEST_SEL_VALUE_NONE, |
| .operation = KEYMGR_CONTROL_OPERATION_VALUE_ADVANCE, |
| }); |
| |
| EXPECT_EQ(dif_keymgr_advance_state(&keymgr_, &kStateParams), |
| kDifKeymgrLockableOk); |
| } |
| |
| TEST_P(AdvanceToNonOperational, Success) { |
| ExpectIdleAtState(GetParam()); |
| ExpectOperationStart({ |
| .dest_sel = KEYMGR_CONTROL_DEST_SEL_VALUE_NONE, |
| .operation = KEYMGR_CONTROL_OPERATION_VALUE_ADVANCE, |
| }); |
| |
| EXPECT_EQ(dif_keymgr_advance_state(&keymgr_, nullptr), kDifKeymgrLockableOk); |
| } |
| |
| class DisableTest : public DifKeymgrInitialized {}; |
| |
| TEST_F(DisableTest, BadArgs) { |
| EXPECT_EQ(dif_keymgr_disable(nullptr), kDifKeymgrLockableBadArg); |
| } |
| |
| TEST_F(DisableTest, LockedBusy) { |
| ExpectBusy(); |
| EXPECT_EQ(dif_keymgr_disable(&keymgr_), kDifKeymgrLockableLocked); |
| } |
| |
| TEST_F(DisableTest, LockedConfig) { |
| ExpectLockedConfig(); |
| |
| EXPECT_EQ(dif_keymgr_disable(&keymgr_), kDifKeymgrLockableLocked); |
| } |
| |
| TEST_F(DisableTest, Disable) { |
| ExpectIdle(); |
| ExpectOperationStart({ |
| .dest_sel = KEYMGR_CONTROL_DEST_SEL_VALUE_NONE, |
| .operation = KEYMGR_CONTROL_OPERATION_VALUE_DISABLE, |
| }); |
| |
| EXPECT_EQ(dif_keymgr_disable(&keymgr_), kDifKeymgrLockableOk); |
| } |
| |
| TEST_P(BadArgsTwo, GetStatusCodes) { |
| auto keymgr = GetGoodBadPtrArg<dif_keymgr_t>(std::get<0>(GetParam())); |
| auto status_codes = |
| GetGoodBadPtrArg<dif_keymgr_status_codes_t>(std::get<1>(GetParam())); |
| |
| EXPECT_EQ(dif_keymgr_get_status_codes(keymgr, status_codes), |
| kDifKeymgrBadArg); |
| } |
| |
| struct GetStatusCodesTestCase { |
| /** |
| * Values of OP_STATUS or ERR_CODE registers. |
| */ |
| std::vector<mock_mmio::BitField> reg_val; |
| /** |
| * Expected output of `dif_keymgr_get_status_codes()`. |
| */ |
| dif_keymgr_status_codes_t exp_val; |
| }; |
| |
| class GetStatusCodesNoError |
| : public DifKeymgrInitialized, |
| public testing::WithParamInterface<GetStatusCodesTestCase> {}; |
| |
| TEST_P(GetStatusCodesNoError, Success) { |
| EXPECT_READ32(KEYMGR_OP_STATUS_REG_OFFSET, GetParam().reg_val); |
| EXPECT_WRITE32(KEYMGR_OP_STATUS_REG_OFFSET, GetParam().reg_val); |
| |
| dif_keymgr_status_codes_t act_val; |
| EXPECT_EQ(dif_keymgr_get_status_codes(&keymgr_, &act_val), kDifKeymgrOk); |
| EXPECT_EQ(GetParam().exp_val, act_val); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| GetStatusCodesNoError, GetStatusCodesNoError, |
| testing::Values( |
| GetStatusCodesTestCase{ |
| .reg_val = {{ |
| .offset = KEYMGR_OP_STATUS_STATUS_OFFSET, |
| .value = KEYMGR_OP_STATUS_STATUS_VALUE_IDLE, |
| }}, |
| .exp_val = kDifKeymgrStatusCodeIdle, |
| }, |
| GetStatusCodesTestCase{ |
| .reg_val = {{ |
| .offset = KEYMGR_OP_STATUS_STATUS_OFFSET, |
| .value = KEYMGR_OP_STATUS_STATUS_VALUE_DONE_SUCCESS, |
| }}, |
| .exp_val = kDifKeymgrStatusCodeIdle, |
| }, |
| GetStatusCodesTestCase{ |
| .reg_val = {{ |
| .offset = KEYMGR_OP_STATUS_STATUS_OFFSET, |
| .value = KEYMGR_OP_STATUS_STATUS_VALUE_WIP, |
| }}, |
| .exp_val = 0, |
| })); |
| |
| class GetStatusCodesWithError |
| : public DifKeymgrInitialized, |
| public testing::WithParamInterface<GetStatusCodesTestCase> {}; |
| |
| TEST_P(GetStatusCodesWithError, Success) { |
| EXPECT_READ32(KEYMGR_OP_STATUS_REG_OFFSET, |
| KEYMGR_OP_STATUS_STATUS_VALUE_DONE_ERROR); |
| EXPECT_WRITE32(KEYMGR_OP_STATUS_REG_OFFSET, |
| KEYMGR_OP_STATUS_STATUS_VALUE_DONE_ERROR); |
| EXPECT_READ32(KEYMGR_ERR_CODE_REG_OFFSET, GetParam().reg_val); |
| EXPECT_WRITE32(KEYMGR_ERR_CODE_REG_OFFSET, GetParam().reg_val); |
| |
| dif_keymgr_status_codes_t act_val; |
| EXPECT_EQ(dif_keymgr_get_status_codes(&keymgr_, &act_val), kDifKeymgrOk); |
| EXPECT_EQ(GetParam().exp_val, act_val); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| GetStatusCodesWithError, GetStatusCodesWithError, |
| testing::Values( |
| GetStatusCodesTestCase{ |
| .reg_val = {{ |
| .offset = KEYMGR_ERR_CODE_INVALID_OP_BIT, |
| .value = 1, |
| }}, |
| .exp_val = kDifKeymgrStatusCodeIdle | |
| kDifKeymgrStatusCodeInvalidOperation, |
| }, |
| GetStatusCodesTestCase{ |
| .reg_val = {{ |
| .offset = KEYMGR_ERR_CODE_INVALID_KMAC_INPUT_BIT, |
| .value = 1, |
| }}, |
| .exp_val = kDifKeymgrStatusCodeIdle | |
| kDifKeymgrStatusCodeInvalidKmacInput, |
| }, |
| GetStatusCodesTestCase{ |
| .reg_val = {{ |
| .offset = KEYMGR_ERR_CODE_INVALID_OP_BIT, |
| .value = 1, |
| }, |
| { |
| .offset = KEYMGR_ERR_CODE_INVALID_KMAC_INPUT_BIT, |
| .value = 1, |
| }}, |
| .exp_val = kDifKeymgrStatusCodeIdle | |
| kDifKeymgrStatusCodeInvalidOperation | |
| kDifKeymgrStatusCodeInvalidKmacInput, |
| })); |
| |
| class GetStateTest : public DifKeymgrInitialized {}; |
| |
| TEST_P(BadArgsTwo, GetState) { |
| auto keymgr = GetGoodBadPtrArg<dif_keymgr_t>(std::get<0>(GetParam())); |
| auto state = GetGoodBadPtrArg<dif_keymgr_state_t>(std::get<1>(GetParam())); |
| |
| EXPECT_EQ(dif_keymgr_get_state(keymgr, state), kDifKeymgrBadArg); |
| } |
| |
| struct GetStateTestCase { |
| /** |
| * Value of the WORKING_STATE register. |
| */ |
| std::vector<mock_mmio::BitField> reg_val; |
| /** |
| * Expected output of `dif_keymgr_get_state()`. |
| */ |
| dif_keymgr_state_t exp_output; |
| }; |
| |
| class GetState : public GetStateTest, |
| public testing::WithParamInterface<GetStateTestCase> {}; |
| |
| TEST_P(GetState, Success) { |
| EXPECT_READ32(KEYMGR_WORKING_STATE_REG_OFFSET, GetParam().reg_val); |
| |
| dif_keymgr_state_t state; |
| EXPECT_EQ(dif_keymgr_get_state(&keymgr_, &state), kDifKeymgrOk); |
| EXPECT_EQ(state, GetParam().exp_output); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| AllValidStates, GetState, |
| testing::Values( |
| GetStateTestCase{ |
| .reg_val = {{ |
| .offset = KEYMGR_WORKING_STATE_STATE_OFFSET, |
| .value = KEYMGR_WORKING_STATE_STATE_VALUE_RESET, |
| }}, |
| .exp_output = kDifKeymgrStateReset, |
| }, |
| GetStateTestCase{ |
| .reg_val = {{ |
| .offset = KEYMGR_WORKING_STATE_STATE_OFFSET, |
| .value = KEYMGR_WORKING_STATE_STATE_VALUE_INIT, |
| }}, |
| .exp_output = kDifKeymgrStateInitialized, |
| }, |
| GetStateTestCase{ |
| .reg_val = {{ |
| .offset = KEYMGR_WORKING_STATE_STATE_OFFSET, |
| .value = KEYMGR_WORKING_STATE_STATE_VALUE_CREATOR_ROOT_KEY, |
| }}, |
| .exp_output = kDifKeymgrStateCreatorRootKey, |
| }, |
| GetStateTestCase{ |
| .reg_val = {{ |
| .offset = KEYMGR_WORKING_STATE_STATE_OFFSET, |
| .value = |
| KEYMGR_WORKING_STATE_STATE_VALUE_OWNER_INTERMEDIATE_KEY, |
| }}, |
| .exp_output = kDifKeymgrStateOwnerIntermediateKey, |
| }, |
| GetStateTestCase{ |
| .reg_val = {{ |
| .offset = KEYMGR_WORKING_STATE_STATE_OFFSET, |
| .value = KEYMGR_WORKING_STATE_STATE_VALUE_OWNER_KEY, |
| }}, |
| .exp_output = kDifKeymgrStateOwnerRootKey, |
| }, |
| GetStateTestCase{ |
| .reg_val = {{ |
| .offset = KEYMGR_WORKING_STATE_STATE_OFFSET, |
| .value = KEYMGR_WORKING_STATE_STATE_VALUE_DISABLED, |
| }}, |
| .exp_output = kDifKeymgrStateDisabled, |
| }, |
| GetStateTestCase{ |
| .reg_val = {{ |
| .offset = KEYMGR_WORKING_STATE_STATE_OFFSET, |
| .value = KEYMGR_WORKING_STATE_STATE_VALUE_INVALID, |
| }}, |
| .exp_output = kDifKeymgrStateInvalid, |
| })); |
| |
| TEST_F(GetStateTest, UnexpectedState) { |
| EXPECT_READ32(KEYMGR_WORKING_STATE_REG_OFFSET, |
| KEYMGR_WORKING_STATE_STATE_MASK); |
| |
| dif_keymgr_state_t state; |
| EXPECT_EQ(dif_keymgr_get_state(&keymgr_, &state), kDifKeymgrError); |
| } |
| |
| class GenerateIdentityTest : public DifKeymgrInitialized {}; |
| |
| TEST_F(GenerateIdentityTest, BadArgs) { |
| EXPECT_EQ(dif_keymgr_generate_identity_seed(nullptr), |
| kDifKeymgrLockableBadArg); |
| } |
| |
| TEST_F(GenerateIdentityTest, LockedBusy) { |
| ExpectBusy(); |
| |
| EXPECT_EQ(dif_keymgr_generate_identity_seed(&keymgr_), |
| kDifKeymgrLockableLocked); |
| } |
| |
| TEST_F(GenerateIdentityTest, LockedConfig) { |
| ExpectLockedConfig(); |
| |
| EXPECT_EQ(dif_keymgr_generate_identity_seed(&keymgr_), |
| kDifKeymgrLockableLocked); |
| } |
| |
| TEST_F(GenerateIdentityTest, Generate) { |
| ExpectIdle(); |
| ExpectOperationStart({ |
| .dest_sel = KEYMGR_CONTROL_DEST_SEL_VALUE_NONE, |
| .operation = KEYMGR_CONTROL_OPERATION_VALUE_GENERATE_ID, |
| }); |
| |
| EXPECT_EQ(dif_keymgr_generate_identity_seed(&keymgr_), kDifKeymgrLockableOk); |
| } |
| |
| class GenerateVersionedKeyTest : public DifKeymgrInitialized {}; |
| |
| TEST_P(BadArgsTwo, GenerateVersionedKey) { |
| auto keymgr = GetGoodBadPtrArg<dif_keymgr_t>(std::get<0>(GetParam())); |
| auto dest = GetGoodBadEnumArg<dif_keymgr_versioned_key_dest_t>( |
| std::get<1>(GetParam()), kDifKeymgrVersionedKeyDestLast); |
| |
| EXPECT_EQ(dif_keymgr_generate_versioned_key(keymgr, {.dest = dest}), |
| kDifKeymgrLockableBadArg); |
| } |
| |
| TEST_F(GenerateVersionedKeyTest, LockedBusy) { |
| ExpectBusy(); |
| |
| EXPECT_EQ(dif_keymgr_generate_versioned_key(&keymgr_, {}), |
| kDifKeymgrLockableLocked); |
| } |
| |
| TEST_F(GenerateVersionedKeyTest, LockedConfig) { |
| ExpectLockedConfig(); |
| |
| EXPECT_EQ(dif_keymgr_generate_versioned_key(&keymgr_, {}), |
| kDifKeymgrLockableLocked); |
| } |
| |
| struct GenerateVersionedKeyTestCase { |
| /** |
| * Destination of the generated key. |
| */ |
| dif_keymgr_versioned_key_dest_t dest; |
| /** |
| * Expected DEST_SEL value to be written to the CONTROL register. |
| */ |
| uint32_t exp_dest_sel; |
| /** |
| * Expected OPERATION values to be written to the CONTROL register. |
| */ |
| uint32_t exp_operation; |
| }; |
| |
| class GenerateVersionedKey |
| : public GenerateVersionedKeyTest, |
| public testing::WithParamInterface<GenerateVersionedKeyTestCase> {}; |
| |
| TEST_P(GenerateVersionedKey, Success) { |
| dif_keymgr_versioned_key_params_t params{ |
| .dest = GetParam().dest, |
| .salt = {0x5A, 0x46, 0x3C, 0x00, 0xA5, 0xB9, 0xC3, 0xFF}, |
| .version = 0xA5A5A5A5, |
| }; |
| |
| ExpectIdle(); |
| size_t salt_len = sizeof(params.salt) / sizeof(params.salt[0]); |
| for (size_t i = 0; i < salt_len; ++i) { |
| EXPECT_WRITE32(KEYMGR_SALT_0_REG_OFFSET + i * 4, params.salt[i]); |
| } |
| EXPECT_WRITE32(KEYMGR_KEY_VERSION_REG_OFFSET, params.version); |
| ExpectOperationStart({ |
| .dest_sel = GetParam().exp_dest_sel, |
| .operation = GetParam().exp_operation, |
| }); |
| |
| EXPECT_EQ(dif_keymgr_generate_versioned_key(&keymgr_, params), |
| kDifKeymgrLockableOk); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| GenerateVersionedKeyAllDests, GenerateVersionedKey, |
| testing::Values( |
| GenerateVersionedKeyTestCase{ |
| .dest = kDifKeymgrVersionedKeyDestSw, |
| .exp_dest_sel = KEYMGR_CONTROL_DEST_SEL_VALUE_NONE, |
| .exp_operation = KEYMGR_CONTROL_OPERATION_VALUE_GENERATE_SW_OUTPUT, |
| }, |
| GenerateVersionedKeyTestCase{ |
| .dest = kDifKeymgrVersionedKeyDestAes, |
| .exp_dest_sel = KEYMGR_CONTROL_DEST_SEL_VALUE_AES, |
| .exp_operation = KEYMGR_CONTROL_OPERATION_VALUE_GENERATE_HW_OUTPUT, |
| }, |
| GenerateVersionedKeyTestCase{ |
| .dest = kDifKeymgrVersionedKeyDestKmac, |
| .exp_dest_sel = KEYMGR_CONTROL_DEST_SEL_VALUE_KMAC, |
| .exp_operation = KEYMGR_CONTROL_OPERATION_VALUE_GENERATE_HW_OUTPUT, |
| })); |
| |
| class SideloadClearTest : public DifKeymgrInitialized {}; |
| |
| TEST_P(BadArgsTwo, GetBadArg) { |
| auto keymgr = GetGoodBadPtrArg<dif_keymgr_t>(std::get<0>(GetParam())); |
| auto state = GetGoodBadPtrArg<dif_keymgr_toggle_t>(std::get<1>(GetParam())); |
| |
| EXPECT_EQ(dif_keymgr_sideload_clear_get_enabled(keymgr, state), |
| kDifKeymgrBadArg); |
| } |
| |
| TEST_P(BadArgsTwo, SetBadArg) { |
| auto keymgr = GetGoodBadPtrArg<dif_keymgr_t>(std::get<0>(GetParam())); |
| auto state = GetGoodBadEnumArg<dif_keymgr_toggle_t>(std::get<1>(GetParam()), |
| kDifKeymgrToggleDisabled); |
| |
| EXPECT_EQ(dif_keymgr_sideload_clear_set_enabled(keymgr, state), |
| kDifKeymgrBadArg); |
| } |
| |
| TEST_F(SideloadClearTest, Set) { |
| EXPECT_WRITE32(KEYMGR_SIDELOAD_CLEAR_REG_OFFSET, |
| {{ |
| .offset = KEYMGR_SIDELOAD_CLEAR_VAL_OFFSET, |
| .value = kDifKeyMgrSideLoadClearAll, |
| }}); |
| EXPECT_EQ( |
| dif_keymgr_sideload_clear_set_enabled(&keymgr_, kDifKeymgrToggleEnabled), |
| kDifKeymgrOk); |
| |
| EXPECT_WRITE32(KEYMGR_SIDELOAD_CLEAR_REG_OFFSET, |
| {{ |
| .offset = KEYMGR_SIDELOAD_CLEAR_VAL_OFFSET, |
| .value = kDifKeyMgrSideLoadClearNone, |
| }}); |
| EXPECT_EQ( |
| dif_keymgr_sideload_clear_set_enabled(&keymgr_, kDifKeymgrToggleDisabled), |
| kDifKeymgrOk); |
| } |
| |
| TEST_F(SideloadClearTest, Get) { |
| EXPECT_READ32(KEYMGR_SIDELOAD_CLEAR_REG_OFFSET, |
| {{ |
| .offset = KEYMGR_SIDELOAD_CLEAR_VAL_OFFSET, |
| .value = kDifKeyMgrSideLoadClearAll, |
| }}); |
| dif_keymgr_toggle_t state = kDifKeymgrToggleDisabled; |
| EXPECT_EQ(dif_keymgr_sideload_clear_get_enabled(&keymgr_, &state), |
| kDifKeymgrOk); |
| EXPECT_EQ(state, kDifKeymgrToggleEnabled); |
| |
| EXPECT_READ32(KEYMGR_SIDELOAD_CLEAR_REG_OFFSET, |
| {{ |
| .offset = KEYMGR_SIDELOAD_CLEAR_VAL_OFFSET, |
| .value = kDifKeyMgrSideLoadClearNone, |
| }}); |
| state = kDifKeymgrToggleEnabled; |
| EXPECT_EQ(dif_keymgr_sideload_clear_get_enabled(&keymgr_, &state), |
| kDifKeymgrOk); |
| EXPECT_EQ(state, kDifKeymgrToggleDisabled); |
| } |
| |
| class ReadOutputTest : public DifKeymgrInitialized {}; |
| |
| TEST_P(BadArgsTwo, ReadOutput) { |
| auto keymgr = GetGoodBadPtrArg<dif_keymgr_t>(std::get<0>(GetParam())); |
| auto output = GetGoodBadPtrArg<dif_keymgr_output_t>(std::get<1>(GetParam())); |
| |
| EXPECT_EQ(dif_keymgr_read_output(keymgr, output), kDifKeymgrBadArg); |
| } |
| |
| TEST_F(ReadOutputTest, Read) { |
| constexpr size_t kNumShares = 2; |
| constexpr size_t kNumShareWords = 8; |
| constexpr std::array<std::array<uint32_t, kNumShareWords>, kNumShares> |
| kExpected{{{0x8D, 0x25, 0x44, 0x0A, 0xEC, 0x1C, 0xAC, 0x0E}, |
| {0x44, 0x5B, 0x90, 0x39, 0x24, 0x72, 0xA7, 0xCB}}}; |
| constexpr std::array<uint32_t, kNumShares> kShareRegOffsets{ |
| {KEYMGR_SW_SHARE0_OUTPUT_0_REG_OFFSET, |
| KEYMGR_SW_SHARE1_OUTPUT_0_REG_OFFSET}}; |
| |
| for (size_t i = 0; i < kNumShares; ++i) { |
| for (size_t j = 0; j < kNumShareWords; ++j) { |
| EXPECT_READ32(kShareRegOffsets[i] + j * 4, kExpected[i][j]); |
| } |
| } |
| |
| dif_keymgr_output_t output; |
| EXPECT_EQ(dif_keymgr_read_output(&keymgr_, &output), kDifKeymgrOk); |
| for (size_t i = 0; i < kNumShares; ++i) { |
| EXPECT_THAT(kExpected[i], ::testing::ElementsAreArray(output.value[i])); |
| } |
| } |
| |
| TEST_P(BadArgsTwo, AlertForce) { |
| auto keymgr = GetGoodBadPtrArg<dif_keymgr_t>(std::get<0>(GetParam())); |
| auto alert = GetGoodBadEnumArg<dif_keymgr_alert_t>(std::get<1>(GetParam()), |
| kDifKeymgrAlertLast); |
| |
| EXPECT_EQ(dif_keymgr_alert_force(keymgr, alert), kDifKeymgrBadArg); |
| } |
| |
| struct AlertTestCase { |
| dif_keymgr_alert_t alert; |
| bitfield_bit32_index_t bit_index; |
| }; |
| |
| class AlertForce : public DifKeymgrInitialized, |
| public testing::WithParamInterface<AlertTestCase> {}; |
| |
| TEST_P(AlertForce, Success) { |
| EXPECT_WRITE32(KEYMGR_ALERT_TEST_REG_OFFSET, |
| {{ |
| .offset = GetParam().bit_index, |
| .value = 1, |
| }}); |
| |
| EXPECT_EQ(dif_keymgr_alert_force(&keymgr_, GetParam().alert), kDifKeymgrOk); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| AlertForceAll, AlertForce, |
| testing::Values( |
| AlertTestCase{ |
| .alert = kDifKeymgrAlertHardware, |
| .bit_index = KEYMGR_ALERT_TEST_FATAL_FAULT_ERR_BIT, |
| }, |
| AlertTestCase{ |
| .alert = kDifKeymgrAlertSoftware, |
| .bit_index = KEYMGR_ALERT_TEST_RECOV_OPERATION_ERR_BIT, |
| })); |
| |
| class IrqTest : public DifKeymgrInitialized {}; |
| |
| TEST_P(BadArgsThree, IrqIsPending) { |
| auto keymgr = GetGoodBadPtrArg<dif_keymgr_t>(std::get<0>(GetParam())); |
| auto irq = GetGoodBadEnumArg<dif_keymgr_irq_t>(std::get<1>(GetParam()), |
| kDifKeymgrIrqLast); |
| auto is_pending = GetGoodBadPtrArg<bool>(std::get<2>(GetParam())); |
| |
| EXPECT_EQ(dif_keymgr_irq_is_pending(keymgr, irq, is_pending), |
| kDifKeymgrBadArg); |
| } |
| |
| class IrqIsPending |
| : public IrqTest, |
| public testing::WithParamInterface<std::tuple<dif_keymgr_irq_t, bool>> {}; |
| |
| TEST_P(IrqIsPending, IsPending) { |
| auto irq = std::get<0>(GetParam()); |
| bool exp_val = std::get<1>(GetParam()); |
| |
| EXPECT_READ32(KEYMGR_INTR_STATE_REG_OFFSET, {{ |
| .offset = irq, |
| .value = exp_val, |
| }}); |
| bool is_pending = !exp_val; |
| EXPECT_EQ(dif_keymgr_irq_is_pending(&keymgr_, irq, &is_pending), |
| kDifKeymgrOk); |
| EXPECT_EQ(is_pending, exp_val); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| IsPendingAllIrqs, IrqIsPending, |
| testing::Combine(testing::ValuesIn( |
| CreateEnumVector<dif_keymgr_irq_t>(kDifKeymgrIrqLast)), |
| testing::Bool())); |
| |
| TEST_P(BadArgsTwo, IrqAck) { |
| auto keymgr = GetGoodBadPtrArg<dif_keymgr_t>(std::get<0>(GetParam())); |
| auto irq = GetGoodBadEnumArg<dif_keymgr_irq_t>(std::get<1>(GetParam()), |
| kDifKeymgrIrqLast); |
| |
| EXPECT_EQ(dif_keymgr_irq_acknowledge(keymgr, irq), kDifKeymgrBadArg); |
| } |
| |
| class Irq : public IrqTest, |
| public testing::WithParamInterface<dif_keymgr_irq_t> {}; |
| |
| TEST_P(Irq, Ack) { |
| EXPECT_WRITE32(KEYMGR_INTR_STATE_REG_OFFSET, {{ |
| .offset = GetParam(), |
| .value = 1, |
| }}); |
| |
| EXPECT_EQ(dif_keymgr_irq_acknowledge(&keymgr_, GetParam()), kDifKeymgrOk); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| AllIrqs, Irq, |
| testing::ValuesIn(CreateEnumVector<dif_keymgr_irq_t>(kDifKeymgrIrqLast))); |
| |
| TEST_P(BadArgsThree, GetEnabled) { |
| auto keymgr = GetGoodBadPtrArg<dif_keymgr_t>(std::get<0>(GetParam())); |
| auto irq = GetGoodBadEnumArg<dif_keymgr_irq_t>(std::get<1>(GetParam()), |
| kDifKeymgrIrqLast); |
| auto is_enabled = |
| GetGoodBadPtrArg<dif_keymgr_toggle_t>(std::get<2>(GetParam())); |
| |
| EXPECT_EQ(dif_keymgr_irq_get_enabled(keymgr, irq, is_enabled), |
| kDifKeymgrBadArg); |
| } |
| |
| class IrqGetSetEnabled |
| : public IrqTest, |
| public testing::WithParamInterface< |
| std::tuple<dif_keymgr_irq_t, dif_keymgr_toggle_t>> {}; |
| |
| TEST_P(IrqGetSetEnabled, GetEnabled) { |
| auto irq = std::get<0>(GetParam()); |
| auto exp_val = std::get<1>(GetParam()); |
| |
| EXPECT_READ32(KEYMGR_INTR_ENABLE_REG_OFFSET, |
| {{ |
| .offset = irq, |
| .value = (exp_val == kDifKeymgrToggleEnabled), |
| }}); |
| |
| dif_keymgr_toggle_t is_enabled = (exp_val == kDifKeymgrToggleEnabled) |
| ? kDifKeymgrToggleDisabled |
| : kDifKeymgrToggleEnabled; |
| EXPECT_EQ(dif_keymgr_irq_get_enabled(&keymgr_, irq, &is_enabled), |
| kDifKeymgrOk); |
| EXPECT_EQ(is_enabled, exp_val); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| AllIrqsAndToggles, IrqGetSetEnabled, |
| testing::Combine(testing::ValuesIn( |
| CreateEnumVector<dif_keymgr_irq_t>(kDifKeymgrIrqLast)), |
| testing::ValuesIn(CreateEnumVector<dif_keymgr_toggle_t>( |
| kDifKeymgrToggleDisabled)))); |
| |
| TEST_P(BadArgsThree, SetEnabled) { |
| auto keymgr = GetGoodBadPtrArg<dif_keymgr_t>(std::get<0>(GetParam())); |
| auto irq = GetGoodBadEnumArg<dif_keymgr_irq_t>(std::get<1>(GetParam()), |
| kDifKeymgrIrqLast); |
| auto state = GetGoodBadEnumArg<dif_keymgr_toggle_t>(std::get<2>(GetParam()), |
| kDifKeymgrToggleDisabled); |
| |
| EXPECT_EQ(dif_keymgr_irq_set_enabled(keymgr, irq, state), kDifKeymgrBadArg); |
| } |
| |
| TEST_P(IrqGetSetEnabled, SetEnabled) { |
| auto irq = std::get<0>(GetParam()); |
| auto new_state = std::get<1>(GetParam()); |
| EXPECT_MASK32(KEYMGR_INTR_ENABLE_REG_OFFSET, |
| {{ |
| .offset = irq, |
| .mask = 1, |
| .value = (new_state == kDifKeymgrToggleEnabled), |
| }}); |
| |
| EXPECT_EQ(dif_keymgr_irq_set_enabled(&keymgr_, irq, new_state), kDifKeymgrOk); |
| } |
| |
| TEST_P(BadArgsTwo, IrqForce) { |
| auto keymgr = GetGoodBadPtrArg<dif_keymgr_t>(std::get<0>(GetParam())); |
| auto irq = GetGoodBadEnumArg<dif_keymgr_irq_t>(std::get<1>(GetParam()), |
| kDifKeymgrIrqLast); |
| |
| EXPECT_EQ(dif_keymgr_irq_force(keymgr, irq), kDifKeymgrBadArg); |
| } |
| |
| TEST_P(Irq, Force) { |
| EXPECT_WRITE32(KEYMGR_INTR_TEST_REG_OFFSET, {{ |
| .offset = GetParam(), |
| .value = 1, |
| }}); |
| |
| EXPECT_EQ(dif_keymgr_irq_force(&keymgr_, GetParam()), kDifKeymgrOk); |
| } |
| |
| TEST_P(BadArgsTwo, DisableAll) { |
| // `snapshot` (second argument) is optional, skip if `keymgr` (first argument) |
| // is good. |
| if (std::get<0>(GetParam())) { |
| GTEST_SKIP(); |
| } |
| |
| auto keymgr = GetGoodBadPtrArg<dif_keymgr_t>(std::get<0>(GetParam())); |
| auto snapshot = |
| GetGoodBadPtrArg<dif_keymgr_irq_snapshot_t>(std::get<1>(GetParam())); |
| |
| EXPECT_EQ(dif_keymgr_irq_disable_all(keymgr, snapshot), kDifKeymgrBadArg); |
| } |
| |
| TEST_F(IrqTest, DisableAll) { |
| constexpr uint32_t kExpVal = 0xA5A5A5A5; |
| |
| // With `snapshot`. |
| EXPECT_READ32(KEYMGR_INTR_ENABLE_REG_OFFSET, kExpVal); |
| EXPECT_WRITE32(KEYMGR_INTR_ENABLE_REG_OFFSET, 0); |
| |
| dif_keymgr_irq_snapshot_t snapshot = 0; |
| EXPECT_EQ(dif_keymgr_irq_disable_all(&keymgr_, &snapshot), kDifKeymgrOk); |
| EXPECT_EQ(snapshot, kExpVal); |
| |
| // Without `snapshot`. |
| EXPECT_WRITE32(KEYMGR_INTR_ENABLE_REG_OFFSET, 0); |
| EXPECT_EQ(dif_keymgr_irq_disable_all(&keymgr_, nullptr), kDifKeymgrOk); |
| } |
| |
| TEST_P(BadArgsTwo, IrqRestore) { |
| auto keymgr = GetGoodBadPtrArg<dif_keymgr_t>(std::get<0>(GetParam())); |
| auto snapshot = |
| GetGoodBadPtrArg<dif_keymgr_irq_snapshot_t>(std::get<1>(GetParam())); |
| |
| EXPECT_EQ(dif_keymgr_irq_restore_all(keymgr, snapshot), kDifKeymgrBadArg); |
| } |
| |
| TEST_F(IrqTest, RestoreAll) { |
| dif_keymgr_irq_snapshot_t snapshot = 0xA5A5A5A5; |
| |
| EXPECT_WRITE32(KEYMGR_INTR_ENABLE_REG_OFFSET, snapshot); |
| |
| EXPECT_EQ(dif_keymgr_irq_restore_all(&keymgr_, &snapshot), kDifKeymgrOk); |
| } |
| |
| } // namespace |
| } // namespace dif_keymgr_unittest |