Skip to content

Commit

Permalink
[rom_ext] Implement Integrator Specific FW Binding (ISFB) logic.
Browse files Browse the repository at this point in the history
Implements Integrator Specific FW Binding (ISFB) functionality to provide
anti-rollback and product binding functionality to application firmware.

The following changes are included:

1. Add flash_ctrl helper function to generate the info flash page
   configuration based on the ownership ISFB config.
2. Implement isfb logic as a separate module to simplify ROM_EXT
   integration.
3. Add unittest cases to verify anti-rollback and product association
   functionality.
4. Add minimum level of hardening against FI.

The ROM_EXT integration and e2e test cases will be implemented in a
follow up commit.

Signed-off-by: Miguel Osorio <[email protected]>
  • Loading branch information
moidx committed Nov 14, 2024
1 parent bb7b328 commit 482f889
Show file tree
Hide file tree
Showing 11 changed files with 492 additions and 5 deletions.
31 changes: 31 additions & 0 deletions sw/device/silicon_creator/lib/drivers/flash_ctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -789,3 +789,34 @@ void flash_ctrl_cert_info_pages_owner_restrict(void) {
HARDENED_CHECK_EQ(i, kFlashCtrlNumCertInfoPages);
HARDENED_CHECK_EQ((uint32_t)r, UINT32_MAX);
}

rom_error_t flash_ctrl_info_type0_params_build(
uint8_t bank, uint8_t page, flash_ctrl_info_page_t *info_page) {
HARDENED_CHECK_LT(bank, FLASH_CTRL_PARAM_REG_NUM_BANKS);
HARDENED_CHECK_LT(page, FLASH_CTRL_PARAM_NUM_INFOS0);

uint32_t cfg_addr = kBase;
uint32_t cfg_wen_Addr = kBase;

switch (bank) {
case 0:
cfg_addr += FLASH_CTRL_BANK0_INFO0_PAGE_CFG_0_REG_OFFSET;
cfg_wen_Addr += FLASH_CTRL_BANK0_INFO0_REGWEN_0_REG_OFFSET;
break;
case 1:
cfg_addr += FLASH_CTRL_BANK1_INFO0_PAGE_CFG_0_REG_OFFSET;
cfg_wen_Addr += FLASH_CTRL_BANK1_INFO0_REGWEN_0_REG_OFFSET;
break;
default:
HARDENED_TRAP();
}

*info_page = (flash_ctrl_info_page_t){
.base_addr = bank * FLASH_CTRL_PARAM_BYTES_PER_BANK +
page * FLASH_CTRL_PARAM_BYTES_PER_PAGE,
.cfg_addr = kBase + cfg_addr + page * sizeof(uint32_t),
.cfg_wen_addr = kBase + cfg_wen_Addr + page * sizeof(uint32_t),
};

return kErrorOk;
}
11 changes: 11 additions & 0 deletions sw/device/silicon_creator/lib/drivers/flash_ctrl.h
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,17 @@ void flash_ctrl_cert_info_pages_creator_cfg(void);
*/
void flash_ctrl_cert_info_pages_owner_restrict(void);

/**
* Builds a `flash_ctrl_info_page_t` struct for a given bank and page.
*
* @param bank Bank index.
* @param page Page index.
* @param[out] info_page Pointer to the `flash_ctrl_info_page_t` struct to fill.
* @return Result of the operation.
*/
rom_error_t flash_ctrl_info_type0_params_build(
uint8_t bank, uint8_t page, flash_ctrl_info_page_t *info_page);

#ifdef __cplusplus
}
#endif
Expand Down
5 changes: 5 additions & 0 deletions sw/device/silicon_creator/lib/drivers/mock_flash_ctrl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,10 @@ void flash_ctrl_creator_info_pages_lockdown(void) {
MockFlashCtrl::Instance().CreatorInfoPagesLockdown();
}

rom_error_t flash_ctrl_info_type0_params_build(
uint8_t bank, uint8_t page, flash_ctrl_info_page_t *info_page) {
return MockFlashCtrl::Instance().InfoType0ParamsBuild(bank, page, info_page);
}

} // extern "C"
} // namespace rom_test
2 changes: 2 additions & 0 deletions sw/device/silicon_creator/lib/drivers/mock_flash_ctrl.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ class MockFlashCtrl : public global_mock::GlobalMock<MockFlashCtrl> {
MOCK_METHOD(void, BankErasePermsSet, (hardened_bool_t));
MOCK_METHOD(void, ExecSet, (uint32_t));
MOCK_METHOD(void, CreatorInfoPagesLockdown, ());
MOCK_METHOD(rom_error_t, InfoType0ParamsBuild,
(uint32_t, uint32_t, flash_ctrl_info_page_t *));
};

} // namespace internal
Expand Down
5 changes: 5 additions & 0 deletions sw/device/silicon_creator/lib/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,11 @@ enum module_ {
X(kErrorOwnershipInvalidDin, ERROR_(13, kModuleOwnership, kInvalidArgument)), \
X(kErrorOwnershipUnlockDenied, ERROR_(14, kModuleOwnership, kPermissionDenied)), \
X(kErrorOwnershipFlashConfigRomExt, ERROR_(15, kModuleOwnership, kInvalidArgument)), \
X(kErrorOwnershipISFBNotPresent, ERROR_(16, kModuleOwnership, kNotFound)), \
X(kErrorOwnershipISFBProductExpCnt, ERROR_(17, kModuleOwnership, kOutOfRange)), \
X(kErrorOwnershipISFBStrikeMask, ERROR_(18, kModuleOwnership, kInvalidArgument)), \
X(kErrorOwnershipISFBProductExp, ERROR_(19, kModuleOwnership, kInvalidArgument)), \
X(kErrorOwnershipISFBFailed, ERROR_(20, kModuleOwnership, kInternal)), \
/* Group all of the tag version error codes together */ \
X(kErrorOwnershipOWNRVersion, ERROR_(0x70, kModuleOwnership, kInvalidArgument)), \
X(kErrorOwnershipAPPKVersion, ERROR_(0x71, kModuleOwnership, kInvalidArgument)), \
Expand Down
37 changes: 32 additions & 5 deletions sw/device/silicon_creator/lib/ownership/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,10 @@

load(
"//rules/opentitan:defs.bzl",
"EARLGREY_TEST_ENVS",
"cw310_params",
"fpga_params",
"opentitan_test",
"verilator_params",
)
load(
"//rules:cross_platform.bzl",
"dual_cc_device_library_of",
"dual_cc_library",
"dual_inputs",
)
Expand Down Expand Up @@ -68,6 +63,38 @@ opentitan_test(
],
)

cc_library(
name = "isfb",
srcs = ["isfb.c"],
hdrs = ["isfb.h"],
deps = [
":datatypes",
":owner_block",
"//sw/device/lib/base:hardened",
"//sw/device/lib/base:hardened_memory",
"//sw/device/silicon_creator/lib:error",
"//sw/device/silicon_creator/lib:manifest",
"//sw/device/silicon_creator/lib/drivers:flash_ctrl",
],
)

cc_test(
name = "isfb_unittest",
srcs = [
"isfb_unittest.cc",
],
deps = [
":datatypes",
":isfb",
":owner_block",
"//sw/device/lib/base:hardened",
"//sw/device/silicon_creator/lib:manifest",
"//sw/device/silicon_creator/lib/drivers:flash_ctrl",
"//sw/device/silicon_creator/testing:rom_test",
"@googletest//:gtest_main",
],
)

dual_cc_library(
name = "ownership_key",
srcs = dual_inputs(
Expand Down
120 changes: 120 additions & 0 deletions sw/device/silicon_creator/lib/ownership/isfb.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

#include "sw/device/silicon_creator/lib/drivers/flash_ctrl.h"
#include "sw/device/silicon_creator/lib/error.h"
#include "sw/device/silicon_creator/lib/manifest.h"
#include "sw/device/silicon_creator/lib/ownership/owner_block.h"

enum {
kFlashWordSize = 64,

// The number of bits in the strike mask is fixed to 128. Each bit in the
// strike mask corresponds to a flash word.
kExpectedStrikeBitCount = 128,

// The expected size of the strike region in bytes and words.
kExpectedStrikeRegionBytesCount =
(kExpectedStrikeBitCount * kFlashWordSize) / CHAR_BIT,
kExpectedStrikeRegionWordsCount =
kExpectedStrikeRegionBytesCount / sizeof(uint32_t),
};

rom_error_t isfb_boot_request_process(const manifest_ext_isfb_t *ext,
const owner_config_t *owner_config,
uint32_t *checks_performed_count) {
*checks_performed_count = UINT32_MAX;
if (ext->header.name != kManifestExtIdIsfb ||
(hardened_bool_t)owner_config->isfb == kHardenedBoolFalse) {
return kErrorOwnershipISFBNotPresent;
}
const owner_isfb_config_t *isfb = owner_config->isfb;
if (ext->product_expr_count * 2 > isfb->product_words) {
return kErrorOwnershipISFBProductExpCnt;
}

flash_ctrl_perms_t perm = {
.read = kMultiBitBool4True,
.write = kMultiBitBool4False,
.erase = kMultiBitBool4False,
};
flash_ctrl_cfg_t cfg = {
.scrambling = kMultiBitBool4True,
.ecc = kMultiBitBool4True,
.he = kMultiBitBool4True,
};

flash_ctrl_info_page_t isfb_info_page;
HARDENED_RETURN_IF_ERROR(flash_ctrl_info_type0_params_build(
isfb->bank, isfb->page, &isfb_info_page));
flash_ctrl_info_perms_set(&isfb_info_page, perm);
flash_ctrl_info_cfg_set(&isfb_info_page, cfg);

// There are in total 128 bits in the strike mask. Each bit corresponds to a
// flash word. Each flash word is 64 bits.
uint32_t data[kExpectedStrikeRegionWordsCount];
static_assert(sizeof(ext->strike_mask) * CHAR_BIT == kExpectedStrikeBitCount,
"Strike mask size mismatch");
static_assert(sizeof(data) == kExpectedStrikeRegionBytesCount,
"Data size mismatch");

HARDENED_RETURN_IF_ERROR(flash_ctrl_info_read(&isfb_info_page, /*offset=*/0,
ARRAYSIZE(data), data));

uint32_t strike_cnt_ok = 0;
uint32_t strike_cnt_bad = 0;
uint64_t *strike_word = (uint64_t *)data;
size_t i;
for (i = 0; i < ARRAYSIZE(data) / 2; ++i, ++strike_word) {
uint32_t strike_bit = ext->strike_mask[i >> 5] & (1 << (i & 31));
if (launder32(strike_bit) && *strike_word == 0) {
strike_cnt_bad++;
} else if (!launder32(strike_bit) || *strike_word != 0) {
strike_cnt_ok++;
} else {
// This condition is equivalent to a potential fault in either the strike
// mask or the ISFB info buffer.
strike_cnt_bad++;
}
}
// Check loop completion and count consistency.
HARDENED_CHECK_EQ(strike_cnt_ok + strike_cnt_bad + i,
kExpectedStrikeBitCount * 2);

if (launder32(strike_cnt_bad) > 0) {
return kErrorOwnershipISFBStrikeMask;
}

// Read the product expressions from the ISFB info page.
HARDENED_RETURN_IF_ERROR(flash_ctrl_info_read(
&isfb_info_page, /*offset=*/1024, ARRAYSIZE(data), data));

uint32_t pexpr_cnt_ok = 0;
uint32_t pexpr_cnt_bad = 0;
for (i = 0; i < ext->product_expr_count; ++i) {
if ((data[i] & ext->product_expr[i].mask) == ext->product_expr[i].value) {
pexpr_cnt_ok++;
} else {
pexpr_cnt_bad++;
}
}
HARDENED_CHECK_EQ(pexpr_cnt_ok + pexpr_cnt_bad, ext->product_expr_count);
HARDENED_CHECK_EQ(i, ext->product_expr_count);

if (launder32(pexpr_cnt_bad) > 0) {
return kErrorOwnershipISFBProductExp;
}

// Redundant checks to ensure there were no faults in any previous checks.
if (launder32(strike_cnt_ok) == kExpectedStrikeBitCount &&
launder32(strike_cnt_bad) == 0 &&
launder32(pexpr_cnt_ok) == ext->product_expr_count &&
launder32(pexpr_cnt_bad) == 0) {
*checks_performed_count = kExpectedStrikeBitCount + ext->product_expr_count;
return kErrorOk;
}

*checks_performed_count = UINT32_MAX;
return kErrorOwnershipISFBFailed;
}
51 changes: 51 additions & 0 deletions sw/device/silicon_creator/lib/ownership/isfb.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

#ifndef OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_OWNERSHIP_ECDSA_H_
#define OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_OWNERSHIP_ECDSA_H_

#include <stdint.h>

#include "sw/device/silicon_creator/lib/error.h"
#include "sw/device/silicon_creator/lib/manifest.h"
#include "sw/device/silicon_creator/lib/ownership/owner_block.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
* Processes the Integrator Specific FW Binding (ISFB) boot request.
*
* This function processes the ISFB boot request and performs the necessary
* checks to ensure that the firmware is bound to the correct
* integrator-specific firmware binding configuration.
*
* The checks performed are:
* - The ISFB extension is valid.
* - The ISFB configuration is present in the owner configuration.
* - The product expression count set in the manifest is within the bounds of
* the owner configuration.
* - The strike mask yields the expected number of strikes in the ISFB info
* page.
* - The product expressions in the ISFB info page match the expected values.
*
* @param ext The ISFB extension from the manifest.
* @param owner_config The owner configuration.
* @param[out] checks_performed_count The number of checks performed. This
* should be equivalent to the number of strike bits and the number of product
* expressions. Use this value in the consuming code as a way to harden the call
* against fault injection.
*
* @return The result of the operation.
*/
rom_error_t isfb_boot_request_process(const manifest_ext_isfb_t *ext,
const owner_config_t *owner_config,
uint32_t *checks_performed_count);

#ifdef __cplusplus
}
#endif

#endif // OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_OWNERSHIP_ECDSA_H_
Loading

0 comments on commit 482f889

Please sign in to comment.