Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ownership] manual cherry-pick for #24745, #24766, #24798, #24683, #24799 #25028

Open
wants to merge 5 commits into
base: earlgrey_1.0.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions sw/device/silicon_creator/lib/ownership/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,11 @@ dual_cc_library(
deps = dual_inputs(
device = [
":ecdsa",
"//sw/device/lib/base:memory",
"//sw/device/lib/base:hardened_memory",
"//sw/device/silicon_creator/lib/drivers:keymgr",
"//sw/device/silicon_creator/lib/drivers:kmac",
"//sw/device/silicon_creator/lib/drivers:flash_ctrl",
],
host = [
"//sw/device/lib/base:global_mock",
Expand All @@ -88,6 +90,7 @@ dual_cc_library(
shared = [
":datatypes",
"//sw/device/lib/base:hardened",
"//sw/device/silicon_creator/lib/drivers:hmac",
"//sw/device/silicon_creator/lib:error",
],
),
Expand All @@ -101,11 +104,13 @@ cc_library(
":datatypes",
":ecdsa",
":owner_block",
":ownership_activate",
":ownership_key",
"//sw/device/lib/base:hardened_memory",
"//sw/device/silicon_creator/lib:boot_data",
"//sw/device/silicon_creator/lib:dbg_print",
"//sw/device/silicon_creator/lib/drivers:flash_ctrl",
"//sw/device/silicon_creator/lib/drivers:lifecycle",
],
)

Expand Down
21 changes: 19 additions & 2 deletions sw/device/silicon_creator/lib/ownership/datatypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,19 @@ typedef enum ownership_update_mode {
* if the config_version is newer)
*/
kOwnershipUpdateModeNewVersion = 0x5657454e,
/**
* Update mode SelfVersion: `SELV`
* (unlock key only unlocks to UnlockedSelf; accept new owner configs from
* self-same owner if the config_version is newer)
*/
kOwnershipUpdateModeSelfVersion = 0x564c4553,
} ownership_update_mode_t;

typedef enum lock_constraint {
/** No locking constraint: `~~~~`. */
kLockConstraintNone = 0x7e7e7e7e,
} lock_constraint_t;

typedef enum tlv_tag {
/** Owner struct: `OWNR`. */
kTlvTagOwner = 0x524e574f,
Expand Down Expand Up @@ -130,8 +141,12 @@ typedef struct owner_block {
uint32_t update_mode;
/** Set the minimum security version to this value (UINT32_MAX: no change) */
uint32_t min_security_version_bl0;
/** The device ID locking constraint */
uint32_t lock_constraint;
/** The device ID to which this config applies */
uint32_t device_id[8];
/** Reserved space for future use. */
uint32_t reserved[25];
uint32_t reserved[16];
/** Owner public key. */
owner_key_t owner_key;
/** Owner's Activate public key. */
Expand All @@ -152,7 +167,9 @@ OT_ASSERT_MEMBER_OFFSET(owner_block_t, sram_exec_mode, 12);
OT_ASSERT_MEMBER_OFFSET(owner_block_t, ownership_key_alg, 16);
OT_ASSERT_MEMBER_OFFSET(owner_block_t, update_mode, 20);
OT_ASSERT_MEMBER_OFFSET(owner_block_t, min_security_version_bl0, 24);
OT_ASSERT_MEMBER_OFFSET(owner_block_t, reserved, 28);
OT_ASSERT_MEMBER_OFFSET(owner_block_t, lock_constraint, 28);
OT_ASSERT_MEMBER_OFFSET(owner_block_t, device_id, 32);
OT_ASSERT_MEMBER_OFFSET(owner_block_t, reserved, 64);
OT_ASSERT_MEMBER_OFFSET(owner_block_t, owner_key, 128);
OT_ASSERT_MEMBER_OFFSET(owner_block_t, activate_key, 224);
OT_ASSERT_MEMBER_OFFSET(owner_block_t, unlock_key, 320);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,9 @@ rom_error_t ownership_seal_check(size_t page) {
return MockOwnershipKey::Instance().seal_check(page);
}

rom_error_t ownership_secret_new() {
return MockOwnershipKey::Instance().secret_new();
}

} // extern "C"
} // namespace rom_test
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class MockOwnershipKey : public global_mock::GlobalMock<MockOwnershipKey> {
MOCK_METHOD(rom_error_t, seal_init, ());
MOCK_METHOD(rom_error_t, seal_page, (size_t));
MOCK_METHOD(rom_error_t, seal_check, (size_t));
MOCK_METHOD(rom_error_t, secret_new, ());
};

} // namespace internal
Expand Down
9 changes: 9 additions & 0 deletions sw/device/silicon_creator/lib/ownership/owner_block.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ enum {
kFlashBankSize = FLASH_CTRL_PARAM_REG_PAGES_PER_BANK,
};

hardened_bool_t owner_block_newversion_mode(void) {
if (owner_page_valid[0] == kOwnerPageStatusSealed &&
(owner_page[0].update_mode == kOwnershipUpdateModeNewVersion ||
owner_page[0].update_mode == kOwnershipUpdateModeSelfVersion)) {
return kHardenedBoolTrue;
}
return kHardenedBoolFalse;
}

hardened_bool_t owner_block_page1_valid_for_transfer(boot_data_t *bootdata) {
if (bootdata->ownership_state == kOwnershipStateLockedOwner &&
owner_page_valid[1] == kOwnerPageStatusSealed) {
Expand Down
7 changes: 7 additions & 0 deletions sw/device/silicon_creator/lib/ownership/owner_block.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ typedef struct owner_application_keyring {
const owner_application_key_t *key[16];
} owner_application_keyring_t;

/**
* Determine if the ownership update mode is one of the "newversion" modes.
*
* @return kHardenedBoolTrue if it is a newversion mode.
*/
hardened_bool_t owner_block_newversion_mode(void);

/**
* Check if owner page 1 is valid for ownership transfer.
*
Expand Down
72 changes: 43 additions & 29 deletions sw/device/silicon_creator/lib/ownership/ownership.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,41 @@
#include "sw/device/silicon_creator/lib/dbg_print.h"
#include "sw/device/silicon_creator/lib/drivers/flash_ctrl.h"
#include "sw/device/silicon_creator/lib/drivers/hmac.h"
#include "sw/device/silicon_creator/lib/drivers/lifecycle.h"
#include "sw/device/silicon_creator/lib/error.h"
#include "sw/device/silicon_creator/lib/ownership/ecdsa.h"
#include "sw/device/silicon_creator/lib/ownership/owner_block.h"
#include "sw/device/silicon_creator/lib/ownership/ownership.h"
#include "sw/device/silicon_creator/lib/ownership/ownership_activate.h"
#include "sw/device/silicon_creator/lib/ownership/ownership_key.h"

static owner_page_status_t owner_page_validity_check(size_t page) {
size_t sig_len =
(uintptr_t)&owner_page[0].signature - (uintptr_t)&owner_page[0];

// Any non-constrained words of the owner block device_id field are required
// to be `kLockConstraintNone`. We wipe the field and then fill in the
// relevant words from the lifecycle constroller.
//
// For node-locked owner configurations, this makes the device_id from the
// lifecycle controller relevant to the cryptographic verification.
memset(owner_page[page].device_id, 0, sizeof(owner_page[page].device_id));
lifecycle_device_id_t id;
lifecycle_device_id_get(&id);
for (uint32_t i = 0; i < ARRAYSIZE(owner_page[0].device_id); ++i) {
if (owner_page[page].lock_constraint & (1u << i)) {
owner_page[page].device_id[i] = id.device_id[i];
} else {
owner_page[page].device_id[i] = kLockConstraintNone;
}
}

rom_error_t sealed = ownership_seal_check(page);
if (sealed == kErrorOk) {
HARDENED_CHECK_EQ(sealed, kErrorOk);
return kOwnerPageStatusSealed;
}

hardened_bool_t result = ownership_key_validate(page, kOwnershipKeyOwner,
&owner_page[page].signature,
&owner_page[page], sig_len);
Expand All @@ -49,39 +69,20 @@ static rom_error_t locked_owner_init(boot_data_t *bootdata,
owner_application_keyring_t *keyring) {
if (owner_page_valid[0] == kOwnerPageStatusSealed &&
owner_page_valid[1] == kOwnerPageStatusSigned &&
owner_page[0].update_mode == kOwnershipUpdateModeNewVersion &&
owner_block_newversion_mode() == kHardenedBoolTrue &&
owner_page[1].config_version > owner_page[0].config_version &&
hardened_memeq(owner_page[0].owner_key.raw, owner_page[1].owner_key.raw,
ARRAYSIZE(owner_page[0].owner_key.raw)) ==
kHardenedBoolTrue) {
// TODO(cfrantz): Consider refactoring this block along with the body
// of the `ownership_activate.c%activate` function into a common
// activation function.
owner_config_t tmpcfg;
owner_application_keyring_t tmpkey;
// Trial parse of the new page: it has to be valid to accept the update.
rom_error_t error = owner_block_parse(&owner_page[1], &tmpcfg, &tmpkey);
if (error == kErrorOk &&
owner_page[1].config_version > owner_page[0].config_version) {
// Page 1 parses and has a newer version: seal it into flash.
ownership_seal_page(/*page=*/1);
owner_page_valid[1] = kOwnerPageStatusSealed;
HARDENED_RETURN_IF_ERROR(flash_ctrl_info_erase(
&kFlashCtrlInfoPageOwnerSlot1, kFlashCtrlEraseTypePage));
HARDENED_RETURN_IF_ERROR(flash_ctrl_info_write(
&kFlashCtrlInfoPageOwnerSlot1, 0,
sizeof(owner_page[1]) / sizeof(uint32_t), &owner_page[1]));

// If the new owner page resets the BL0 min_security_version, perform
// the reset now.
if (owner_page[1].min_security_version_bl0 != UINT32_MAX) {
bootdata->min_security_version_bl0 =
owner_page[1].min_security_version_bl0;
HARDENED_RETURN_IF_ERROR(boot_data_write(bootdata));
}
rom_error_t error =
ownership_activate(bootdata, /*write_both_pages=*/kHardenedBoolFalse);
if (error == kErrorOk) {
HARDENED_CHECK_EQ(error, kErrorOk);
// Thunk the status of page 0 to Invalid so the next set of validity
// checks will copy the new page 1 content over to page 0 and establish a
// redundant backup of the new configuration.
owner_page_valid[0] = kOwnerPageStatusInvalid;
owner_page_valid[1] = kOwnerPageStatusSealed;
} else {
// If the new page wasn't good, we'll do nothing here and let the next set
// of validity checks copy page 0 over to page 1 and re-establish a
Expand Down Expand Up @@ -184,6 +185,9 @@ rom_error_t ownership_init(boot_data_t *bootdata, owner_config_t *config,
flash_ctrl_info_cfg_set(&kFlashCtrlInfoPageOwnerSlot0, cfg);
flash_ctrl_info_perms_set(&kFlashCtrlInfoPageOwnerSlot1, perm);
flash_ctrl_info_cfg_set(&kFlashCtrlInfoPageOwnerSlot1, cfg);
// Set up the OwnerSecret page for ECC & Scrambling. We won't
// turn on read/write/earse permissions until we need them.
flash_ctrl_info_cfg_set(&kFlashCtrlInfoPageOwnerSecret, cfg);

ownership_seal_init();
// We don't want to abort ownership setup if we fail to
Expand Down Expand Up @@ -276,6 +280,18 @@ rom_error_t ownership_flash_lockdown(boot_data_t *bootdata,
}

void ownership_pages_lockdown(boot_data_t *bootdata, hardened_bool_t rescue) {
#ifdef ROM_EXT_KLOBBER_ALLOWED
if (rescue == kHardenedBoolTrue) {
// If ROM_EXT_KLOBBER_ALLOWED and we're in rescue mode, we skip
// lockdown because the rescue protcol is permitted, on DEV chips
// only, to erase the ownership pages. This exists to simulate
// disaster scenarios and test the disaster recovery mechanisms.
//
// Under normal circumstances, the ROM_EXT is not built with this
// capability.
return;
}
#endif
flash_ctrl_perms_t perm = {
.read = kMultiBitBool4True,
.write = kMultiBitBool4False,
Expand All @@ -296,9 +312,7 @@ void ownership_pages_lockdown(boot_data_t *bootdata, hardened_bool_t rescue) {
return;
}
if (bootdata->ownership_state == kOwnershipStateLockedOwner) {
if (owner_page[0].update_mode == kOwnershipUpdateModeNewVersion) {
HARDENED_CHECK_EQ(owner_page[0].update_mode,
kOwnershipUpdateModeNewVersion);
if (owner_block_newversion_mode() == kHardenedBoolTrue) {
// Leave page 1 unlocked if we're in "NewVersion" update mode.
} else {
// Otherwise, make the page read-only.
Expand Down
83 changes: 52 additions & 31 deletions sw/device/silicon_creator/lib/ownership/ownership_activate.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,46 @@
#include "sw/device/silicon_creator/lib/ownership/owner_block.h"
#include "sw/device/silicon_creator/lib/ownership/ownership_key.h"

static rom_error_t activate(boot_svc_msg_t *msg, boot_data_t *bootdata) {
rom_error_t ownership_activate(boot_data_t *bootdata,
hardened_bool_t write_both_pages) {
// Check if page1 parses correctly.
owner_config_t config;
owner_application_keyring_t keyring;
HARDENED_RETURN_IF_ERROR(
owner_block_parse(&owner_page[1], &config, &keyring));

// Seal page one to this chip.
ownership_seal_page(/*page=*/1);

// If requested, reset the mim security version of the application firmware.
if (owner_page[1].min_security_version_bl0 != UINT32_MAX) {
bootdata->min_security_version_bl0 = owner_page[1].min_security_version_bl0;
}

// TODO(cfrantz): Consider reading back the flash pages to check that the
// flash writes succeeded.
//
// Program the sealed page into slot 1.
HARDENED_RETURN_IF_ERROR(flash_ctrl_info_erase(&kFlashCtrlInfoPageOwnerSlot1,
kFlashCtrlEraseTypePage));
HARDENED_RETURN_IF_ERROR(flash_ctrl_info_write(
&kFlashCtrlInfoPageOwnerSlot1, 0,
sizeof(owner_page[1]) / sizeof(uint32_t), &owner_page[1]));

if (write_both_pages == kHardenedBoolTrue) {
// Program the same data into slot 0.
HARDENED_RETURN_IF_ERROR(flash_ctrl_info_erase(
&kFlashCtrlInfoPageOwnerSlot0, kFlashCtrlEraseTypePage));
HARDENED_RETURN_IF_ERROR(flash_ctrl_info_write(
&kFlashCtrlInfoPageOwnerSlot0, 0,
sizeof(owner_page[1]) / sizeof(uint32_t), &owner_page[1]));
}

return kErrorOk;
}

static rom_error_t activate_handler(boot_svc_msg_t *msg,
boot_data_t *bootdata) {
// Check if page1 is in a valid state for a transfer (e.g. signature and owner
// requirements are met). We do this first (rather than parse) because if the
// signature requirements are not met, the RAM copy of the owner page will be
Expand All @@ -23,12 +62,6 @@ static rom_error_t activate(boot_svc_msg_t *msg, boot_data_t *bootdata) {
return kErrorOwnershipInvalidInfoPage;
}

// Check if page1 parses correctly.
owner_config_t config;
owner_application_keyring_t keyring;
HARDENED_RETURN_IF_ERROR(
owner_block_parse(&owner_page[1], &config, &keyring));

// Check the activation key and the nonce.
size_t len = (uintptr_t)&msg->ownership_activate_req.signature -
(uintptr_t)&msg->ownership_activate_req.primary_bl0_slot;
Expand All @@ -50,25 +83,8 @@ static rom_error_t activate(boot_svc_msg_t *msg, boot_data_t *bootdata) {
return kErrorOwnershipInvalidDin;
}

// Seal page one to this chip.
ownership_seal_page(/*page=*/1);

// TODO(cfrantz): Consider reading back the flash pages to check that the
// flash writes succeeded.
//
// Program the sealed page into slot 1.
HARDENED_RETURN_IF_ERROR(flash_ctrl_info_erase(&kFlashCtrlInfoPageOwnerSlot1,
kFlashCtrlEraseTypePage));
HARDENED_RETURN_IF_ERROR(flash_ctrl_info_write(
&kFlashCtrlInfoPageOwnerSlot1, 0,
sizeof(owner_page[1]) / sizeof(uint32_t), &owner_page[1]));

// Program the same data into slot 0.
HARDENED_RETURN_IF_ERROR(flash_ctrl_info_erase(&kFlashCtrlInfoPageOwnerSlot0,
kFlashCtrlEraseTypePage));
HARDENED_RETURN_IF_ERROR(flash_ctrl_info_write(
&kFlashCtrlInfoPageOwnerSlot0, 0,
sizeof(owner_page[1]) / sizeof(uint32_t), &owner_page[1]));
HARDENED_RETURN_IF_ERROR(
ownership_activate(bootdata, /*write_both_pages=*/kHardenedBoolTrue));

// The requested primary_bl0_slot is user input. Validate and clamp it to
// legal values.
Expand All @@ -78,15 +94,20 @@ static rom_error_t activate(boot_svc_msg_t *msg, boot_data_t *bootdata) {
bootdata->primary_bl0_slot = kBootSlotA;
}

// If requested, reset the mim security version of the application firmware.
if (owner_page[1].min_security_version_bl0 != UINT32_MAX) {
bootdata->min_security_version_bl0 = owner_page[1].min_security_version_bl0;
if (bootdata->ownership_state == kOwnershipStateUnlockedSelf) {
// An activate from UnlockedSelf is not a transfer and should not
// regenerate the OwnerSecret page.
HARDENED_CHECK_EQ(bootdata->ownership_state, kOwnershipStateUnlockedSelf);
} else {
// All other activations are transfers and need to regenerate entropy stored
// in the OwnerSecret page.
HARDENED_RETURN_IF_ERROR(ownership_secret_new());
bootdata->ownership_transfers += 1;
}

// Set the ownership state to LockedOwner.
nonce_new(&bootdata->nonce);
bootdata->ownership_state = kOwnershipStateLockedOwner;
bootdata->ownership_transfers += 1;
memset(bootdata->next_owner, 0, sizeof(bootdata->next_owner));
return kErrorWriteBootdataThenReboot;
}
Expand All @@ -98,7 +119,7 @@ rom_error_t ownership_activate_handler(boot_svc_msg_t *msg,
case kOwnershipStateUnlockedSelf:
case kOwnershipStateUnlockedAny:
case kOwnershipStateUnlockedEndorsed:
error = activate(msg, bootdata);
error = activate_handler(msg, bootdata);
break;
default:
/* nothing */;
Expand Down
Loading
Loading