blob: 903db601e10adc08c0177688e60551d15bc914c2 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#include "sw/device/silicon_creator/rom/sigverify_keys.h"
#include <array>
#include <cstring>
#include <limits>
#include <numeric>
#include <unordered_set>
#include "gtest/gtest.h"
#include "sw/device/lib/base/hardened.h"
#include "sw/device/silicon_creator/lib/drivers/mock_lifecycle.h"
#include "sw/device/silicon_creator/lib/drivers/mock_otp.h"
#include "sw/device/silicon_creator/lib/drivers/mock_rnd.h"
#include "sw/device/silicon_creator/lib/error.h"
#include "sw/device/silicon_creator/lib/sigverify/mock_mod_exp_otbn.h"
#include "sw/device/silicon_creator/lib/sigverify/sigverify.h"
#include "sw/device/silicon_creator/testing/rom_test.h"
#include "otp_ctrl_regs.h"
// Define the symbols that the sigverify library expects for the mock keys
// defined below.
extern "C" {
/**
* Mock keys used in tests.
*
* We only initialize the first word of `n`, which is the key ID, and `key_type`
* since these are the only fields that are used for determining the validity of
* a key. The remaining fields are initialized only because non-trivial
* designated initializers are not supported.
*/
constexpr sigverify_rom_key_t kSigverifyRsaKeys[]{
{
.key = {.n = {{0xa0}}, .n0_inv = {0}},
.key_type = kSigverifyKeyTypeTest,
},
{
.key = {.n = {{0xb0}}, .n0_inv = {0}},
.key_type = kSigverifyKeyTypeProd,
},
{
.key = {.n = {{0xc0}}, .n0_inv = {0}},
.key_type = kSigverifyKeyTypeDev,
},
{
.key = {.n = {{0xa1}}, .n0_inv = {0}},
.key_type = kSigverifyKeyTypeTest,
},
{
.key = {.n = {{0xb1}}, .n0_inv = {0}},
.key_type = kSigverifyKeyTypeProd,
},
{
.key = {.n = {{0xc1}}, .n0_inv = {0}},
.key_type = kSigverifyKeyTypeDev,
},
{
.key = {.n = {{0xff}}, .n0_inv = {0}},
.key_type = static_cast<sigverify_key_type_t>(
std::numeric_limits<uint32_t>::max()),
},
};
constexpr size_t kSigverifyRsaKeysCnt =
std::extent<decltype(kSigverifyRsaKeys)>::value;
static_assert(OTP_CTRL_PARAM_CREATOR_SW_CFG_SIGVERIFY_RSA_KEY_EN_SIZE >=
kSigverifyRsaKeysCnt,
"CREATOR_SW_CFG_SIGVERIFY_RSA_KEY_EN OTP item must be at least "
"`kSigVerifyRsaKeysCnt` bytes.");
// Using 1 as the step size since it is coprime with every integer.
constexpr size_t kSigverifyRsaKeysStep = 1;
}
namespace sigverify_keys_unittest {
namespace {
using ::testing::Return;
/**
* Returns the indices of mock keys of the given type.
*
* @param key_type A key type.
* @return Indices of mock keys of the given type.
*/
std::vector<size_t> MockKeyIndicesOfType(sigverify_key_type_t key_type) {
std::vector<size_t> indices;
for (size_t i = 0; i < kSigverifyRsaKeysCnt; ++i) {
if (kSigverifyRsaKeys[i].key_type == key_type) {
indices.push_back(i);
}
}
return indices;
}
/**
* Life cycle states used in parameterized tests.
*/
constexpr std::array<lifecycle_state_t, 4> kLcStatesNonTestOperational{
kLcStateDev,
kLcStateProd,
kLcStateProdEnd,
kLcStateRma,
};
constexpr std::array<lifecycle_state_t, 6> kLcStatesAll{
kLcStateTest,
kLcStateDev,
kLcStateProd,
kLcStateProdEnd,
kLcStateRma,
// An invalid state
static_cast<lifecycle_state_t>(0),
};
class SigverifyKeys : public rom_test::RomTest {
protected:
/**
* Sets expectations for getting the keys stored in the ROM.
*/
void ExpectKeysGet() {
EXPECT_CALL(rnd_, Uint32())
.WillOnce(Return(std::numeric_limits<uint32_t>::max()));
}
/**
* Sets an expectation for an OTP read for the key at the given index.
*
* The value that corresponds to `key_index` will be `is_valid` and the
* values for all other keys in the corresponding OTP word will be the
* complement of `is_valid`.
*
* @param key_index Index of a key.
* @param is_valid Validitiy of the key.
*/
void ExpectOtpRead(size_t key_index, hardened_byte_bool_t is_valid) {
const uint32_t read_addr =
OTP_CTRL_PARAM_CREATOR_SW_CFG_SIGVERIFY_RSA_KEY_EN_OFFSET +
(key_index / kSigverifyNumEntriesPerOtpWord) * sizeof(uint32_t);
const size_t entry_index = key_index % kSigverifyNumEntriesPerOtpWord;
std::array<uint8_t, kSigverifyNumEntriesPerOtpWord> entries;
hardened_byte_bool_t others_val = is_valid == kHardenedByteBoolTrue
? kHardenedByteBoolFalse
: kHardenedByteBoolTrue;
entries.fill(others_val);
entries[entry_index] = is_valid;
uint32_t read_val;
std::memcpy(&read_val, entries.data(), sizeof(read_val));
EXPECT_CALL(otp_, read32(read_addr)).WillOnce(Return(read_val));
}
rom_test::MockOtp otp_;
rom_test::MockRnd rnd_;
};
class BadKeyIdTypeTest : public SigverifyKeys,
public testing::WithParamInterface<lifecycle_state_t> {
};
TEST_P(BadKeyIdTypeTest, BadKeyId) {
ExpectKeysGet();
const sigverify_rsa_key_t *key;
EXPECT_EQ(sigverify_rsa_key_get(0, GetParam(), &key), kErrorSigverifyBadKey);
}
INSTANTIATE_TEST_SUITE_P(AllLcStates, BadKeyIdTypeTest,
testing::ValuesIn(kLcStatesAll));
class BadKeyIdTypeDeathTest : public BadKeyIdTypeTest {};
TEST_P(BadKeyIdTypeDeathTest, BadKeyType) {
const sigverify_rsa_key_t *key;
EXPECT_DEATH(
{
ExpectKeysGet();
sigverify_rsa_key_get(0xff, GetParam(), &key);
},
"");
}
INSTANTIATE_TEST_SUITE_P(AllLcStates, BadKeyIdTypeDeathTest,
testing::ValuesIn(kLcStatesAll));
/**
* Base class for paramaterized tests below.
*/
class KeyValidityTest : public SigverifyKeys,
public testing::WithParamInterface<
std::tuple<size_t, lifecycle_state_t>> {};
class NonOperationalStateDeathTest : public KeyValidityTest {};
TEST_P(NonOperationalStateDeathTest, BadKey) {
size_t key_index;
lifecycle_state_t lc_state;
std::tie(key_index, lc_state) = GetParam();
const sigverify_rsa_key_t *key;
EXPECT_DEATH(
{
ExpectKeysGet();
sigverify_rsa_key_get(
sigverify_rsa_key_id_get(&kSigverifyRsaKeys[key_index].key.n),
lc_state, &key);
},
"");
}
INSTANTIATE_TEST_SUITE_P(
AllKeysAndNonOperationalStates, NonOperationalStateDeathTest,
testing::Combine(testing::Range<size_t>(0, kSigverifyRsaKeysCnt - 1),
testing::Values(static_cast<lifecycle_state_t>(0))));
class ValidBasedOnOtp : public KeyValidityTest {};
TEST_P(ValidBasedOnOtp, ValidInOtp) {
size_t key_index;
lifecycle_state_t lc_state;
std::tie(key_index, lc_state) = GetParam();
ExpectKeysGet();
ExpectOtpRead(key_index, kHardenedByteBoolTrue);
ExpectOtpRead(key_index, kHardenedByteBoolTrue);
const sigverify_rsa_key_t *key;
EXPECT_EQ(sigverify_rsa_key_get(
sigverify_rsa_key_id_get(&kSigverifyRsaKeys[key_index].key.n),
lc_state, &key),
kErrorOk);
EXPECT_EQ(key, &kSigverifyRsaKeys[key_index].key);
}
TEST_P(ValidBasedOnOtp, InvalidInOtp) {
size_t key_index;
lifecycle_state_t lc_state;
std::tie(key_index, lc_state) = GetParam();
ExpectKeysGet();
ExpectOtpRead(key_index, kHardenedByteBoolFalse);
const sigverify_rsa_key_t *key;
EXPECT_EQ(sigverify_rsa_key_get(
sigverify_rsa_key_id_get(&kSigverifyRsaKeys[key_index].key.n),
lc_state, &key),
kErrorSigverifyBadKey);
}
INSTANTIATE_TEST_SUITE_P(
ProdKeysInNonTestStates, ValidBasedOnOtp,
testing::Combine(
testing::ValuesIn(MockKeyIndicesOfType(kSigverifyKeyTypeProd)),
testing::ValuesIn(kLcStatesNonTestOperational)));
INSTANTIATE_TEST_SUITE_P(
TestKeysInRmaState, ValidBasedOnOtp,
testing::Combine(
testing::ValuesIn(MockKeyIndicesOfType(kSigverifyKeyTypeTest)),
testing::Values(kLcStateRma)));
INSTANTIATE_TEST_SUITE_P(
DevKeysInDevState, ValidBasedOnOtp,
testing::Combine(
testing::ValuesIn(MockKeyIndicesOfType(kSigverifyKeyTypeDev)),
testing::Values(kLcStateDev)));
class ValidInState : public KeyValidityTest {};
TEST_P(ValidInState, Get) {
size_t key_index;
lifecycle_state_t lc_state;
std::tie(key_index, lc_state) = GetParam();
ExpectKeysGet();
const sigverify_rsa_key_t *key;
EXPECT_EQ(sigverify_rsa_key_get(
sigverify_rsa_key_id_get(&kSigverifyRsaKeys[key_index].key.n),
lc_state, &key),
kErrorOk);
EXPECT_EQ(key, &kSigverifyRsaKeys[key_index].key);
}
INSTANTIATE_TEST_SUITE_P(
ProdKeysInTestStates, ValidInState,
testing::Combine(
testing::ValuesIn(MockKeyIndicesOfType(kSigverifyKeyTypeProd)),
testing::Values(kLcStateTest)));
INSTANTIATE_TEST_SUITE_P(
TestKeysInTestStates, ValidInState,
testing::Combine(
testing::ValuesIn(MockKeyIndicesOfType(kSigverifyKeyTypeTest)),
testing::Values(kLcStateTest)));
class InvalidInState : public KeyValidityTest {};
TEST_P(InvalidInState, Get) {
size_t key_index;
lifecycle_state_t lc_state;
std::tie(key_index, lc_state) = GetParam();
ExpectKeysGet();
const sigverify_rsa_key_t *key;
EXPECT_EQ(sigverify_rsa_key_get(
sigverify_rsa_key_id_get(&kSigverifyRsaKeys[key_index].key.n),
lc_state, &key),
kErrorSigverifyBadKey);
}
INSTANTIATE_TEST_SUITE_P(
TestKeysAndProdDevStates, InvalidInState,
testing::Combine(
testing::ValuesIn(MockKeyIndicesOfType(kSigverifyKeyTypeTest)),
testing::Values(kLcStateProd, kLcStateProdEnd, kLcStateDev)));
INSTANTIATE_TEST_SUITE_P(
DevKeysAndTestStates, InvalidInState,
testing::Combine(
testing::ValuesIn(MockKeyIndicesOfType(kSigverifyKeyTypeDev)),
testing::Values(kLcStateTest)));
INSTANTIATE_TEST_SUITE_P(
DevKeysAndNonDevOperStates, InvalidInState,
testing::Combine(
testing::ValuesIn(MockKeyIndicesOfType(kSigverifyKeyTypeDev)),
testing::Values(kLcStateProd, kLcStateProdEnd, kLcStateRma)));
} // namespace
} // namespace sigverify_keys_unittest