From fbf18cebc240b0f0b16de2749beeae31e03a0af3 Mon Sep 17 00:00:00 2001 From: Chris Frantz Date: Mon, 23 Sep 2024 16:13:09 -0700 Subject: [PATCH] [ownership] Require the device ID for ownership unlock/activate 1. Include the Device Identification Number (DIN) subfield of the full 256-bit device ID into the ownership unlock and activate commands. 2. Update the Rust versions of the unlock/activate requests to include the DIN. 3. Update unittests. 4. Update the rescue mode-change function to wait for the requested `mode` event to confirm entry into the requested mode. 5. Update ownership transfer tests. Signed-off-by: Chris Frantz (cherry picked from commit 0a8689fb2b32fa0b4519479a785fb691ff179933) (cherry picked from commit 6a2fce85e3e42b0f10420c01e03c4c9915e684d1) --- .../boot_svc/boot_svc_ownership_activate.h | 12 +++-- .../lib/boot_svc/boot_svc_ownership_unlock.h | 10 ++++- .../silicon_creator/lib/drivers/lifecycle.c | 6 +++ .../silicon_creator/lib/drivers/lifecycle.h | 9 ++++ .../lib/drivers/mock_lifecycle.cc | 6 +++ sw/device/silicon_creator/lib/error.h | 1 + sw/device/silicon_creator/lib/ownership/BUILD | 3 ++ .../lib/ownership/ownership_activate.c | 9 ++++ .../ownership/ownership_activate_unittest.cc | 22 +++++++++ .../lib/ownership/ownership_unlock.c | 18 ++++++++ .../ownership/ownership_unlock_unittest.cc | 31 +++++++++++++ .../rom_ext/e2e/boot_svc/BUILD | 45 +++---------------- sw/host/opentitanlib/src/chip/boot_svc.rs | 12 ++++- sw/host/opentitanlib/src/chip/device_id.rs | 16 +++---- sw/host/opentitanlib/src/chip/helper.rs | 10 +++++ sw/host/opentitanlib/src/ownership/owner.rs | 18 +++++--- sw/host/opentitanlib/src/ownership/rescue.rs | 6 +++ sw/host/opentitanlib/src/rescue/serial.rs | 8 +++- .../tests/ownership/flash_permission_test.rs | 6 ++- sw/host/tests/ownership/rescue_limit_test.rs | 6 ++- .../tests/ownership/rescue_permission_test.rs | 6 ++- sw/host/tests/ownership/transfer_lib.rs | 23 ++++++++-- sw/host/tests/ownership/transfer_test.rs | 6 ++- 23 files changed, 218 insertions(+), 71 deletions(-) diff --git a/sw/device/silicon_creator/lib/boot_svc/boot_svc_ownership_activate.h b/sw/device/silicon_creator/lib/boot_svc/boot_svc_ownership_activate.h index d613449d6c42f..1bd25fa3b0d7b 100644 --- a/sw/device/silicon_creator/lib/boot_svc/boot_svc_ownership_activate.h +++ b/sw/device/silicon_creator/lib/boot_svc/boot_svc_ownership_activate.h @@ -37,6 +37,10 @@ typedef struct boot_svc_ownership_activate_req { * Which side of the flash is primary after activation. */ uint32_t primary_bl0_slot; + /** + * The 64-bit DIN subfield of the full 256-bit device ID. + */ + uint32_t din[2]; /** * Erase previous owner's flash (hardened_bool_t). */ @@ -44,7 +48,7 @@ typedef struct boot_svc_ownership_activate_req { /** * Reserved for future use. */ - uint32_t reserved[33]; + uint32_t reserved[31]; /** * The current ownership nonce. */ @@ -59,10 +63,12 @@ typedef struct boot_svc_ownership_activate_req { OT_ASSERT_MEMBER_OFFSET(boot_svc_ownership_activate_req_t, header, 0); OT_ASSERT_MEMBER_OFFSET(boot_svc_ownership_activate_req_t, primary_bl0_slot, CHIP_BOOT_SVC_MSG_HEADER_SIZE); -OT_ASSERT_MEMBER_OFFSET(boot_svc_ownership_activate_req_t, erase_previous, +OT_ASSERT_MEMBER_OFFSET(boot_svc_ownership_activate_req_t, din, CHIP_BOOT_SVC_MSG_HEADER_SIZE + 4); +OT_ASSERT_MEMBER_OFFSET(boot_svc_ownership_activate_req_t, erase_previous, + CHIP_BOOT_SVC_MSG_HEADER_SIZE + 12); OT_ASSERT_MEMBER_OFFSET(boot_svc_ownership_activate_req_t, reserved, - CHIP_BOOT_SVC_MSG_HEADER_SIZE + 8); + CHIP_BOOT_SVC_MSG_HEADER_SIZE + 16); OT_ASSERT_MEMBER_OFFSET(boot_svc_ownership_activate_req_t, nonce, CHIP_BOOT_SVC_MSG_HEADER_SIZE + 140); OT_ASSERT_MEMBER_OFFSET(boot_svc_ownership_activate_req_t, signature, diff --git a/sw/device/silicon_creator/lib/boot_svc/boot_svc_ownership_unlock.h b/sw/device/silicon_creator/lib/boot_svc/boot_svc_ownership_unlock.h index 317f1fbeb4e10..9c3cb42e7e3f0 100644 --- a/sw/device/silicon_creator/lib/boot_svc/boot_svc_ownership_unlock.h +++ b/sw/device/silicon_creator/lib/boot_svc/boot_svc_ownership_unlock.h @@ -46,10 +46,14 @@ typedef struct boot_svc_ownership_unlock_req { * Unlock mode: Any, Endorsed, Update or Abort. */ uint32_t unlock_mode; + /** + * The 64-bit ID subfield of the full 256-bit device ID. + */ + uint32_t din[2]; /** * Reserved for future use. */ - uint32_t reserved[10]; + uint32_t reserved[8]; /** * The current ownership nonce. */ @@ -68,8 +72,10 @@ typedef struct boot_svc_ownership_unlock_req { OT_ASSERT_MEMBER_OFFSET(boot_svc_ownership_unlock_req_t, header, 0); OT_ASSERT_MEMBER_OFFSET(boot_svc_ownership_unlock_req_t, unlock_mode, CHIP_BOOT_SVC_MSG_HEADER_SIZE); -OT_ASSERT_MEMBER_OFFSET(boot_svc_ownership_unlock_req_t, reserved, +OT_ASSERT_MEMBER_OFFSET(boot_svc_ownership_unlock_req_t, din, CHIP_BOOT_SVC_MSG_HEADER_SIZE + 4); +OT_ASSERT_MEMBER_OFFSET(boot_svc_ownership_unlock_req_t, reserved, + CHIP_BOOT_SVC_MSG_HEADER_SIZE + 12); OT_ASSERT_MEMBER_OFFSET(boot_svc_ownership_unlock_req_t, nonce, CHIP_BOOT_SVC_MSG_HEADER_SIZE + 44); OT_ASSERT_MEMBER_OFFSET(boot_svc_ownership_unlock_req_t, next_owner_key, diff --git a/sw/device/silicon_creator/lib/drivers/lifecycle.c b/sw/device/silicon_creator/lib/drivers/lifecycle.c index d047695286171..d72af506f7b8b 100644 --- a/sw/device/silicon_creator/lib/drivers/lifecycle.c +++ b/sw/device/silicon_creator/lib/drivers/lifecycle.c @@ -100,3 +100,9 @@ void lifecycle_hw_rev_get(lifecycle_hw_rev_t *hw_rev) { reg1, LC_CTRL_HW_REVISION1_REVISION_ID_FIELD), }; } + +hardened_bool_t lifecycle_din_eq(lifecycle_device_id_t *id, uint32_t *din) { + if (id->device_id[1] == din[0] && id->device_id[2] == din[1]) + return kHardenedBoolTrue; + return kHardenedBoolFalse; +} diff --git a/sw/device/silicon_creator/lib/drivers/lifecycle.h b/sw/device/silicon_creator/lib/drivers/lifecycle.h index d3c86122f8637..88aef18aa6a6d 100644 --- a/sw/device/silicon_creator/lib/drivers/lifecycle.h +++ b/sw/device/silicon_creator/lib/drivers/lifecycle.h @@ -7,6 +7,7 @@ #include +#include "sw/device/lib/base/hardened.h" #include "sw/device/lib/base/macros.h" #ifdef __cplusplus @@ -117,6 +118,14 @@ void lifecycle_device_id_get(lifecycle_device_id_t *device_id); */ void lifecycle_hw_rev_get(lifecycle_hw_rev_t *hw_rev); +/** + * Determine if the device identification number subfield of the Device Id is + * equal to the supplied DIN. + * + * @returns kHardenedBoolTrue if equal, kHardenedBoolFalse if not equal. + */ +hardened_bool_t lifecycle_din_eq(lifecycle_device_id_t *id, uint32_t *din); + #ifdef __cplusplus } #endif diff --git a/sw/device/silicon_creator/lib/drivers/mock_lifecycle.cc b/sw/device/silicon_creator/lib/drivers/mock_lifecycle.cc index 1a3bcbf90e6d4..4f29aa3fc3bff 100644 --- a/sw/device/silicon_creator/lib/drivers/mock_lifecycle.cc +++ b/sw/device/silicon_creator/lib/drivers/mock_lifecycle.cc @@ -21,5 +21,11 @@ void lifecycle_device_id_get(lifecycle_device_id_t *device_id) { void lifecycle_hw_rev_get(lifecycle_hw_rev_t *hw_rev) { MockLifecycle::Instance().HwRev(hw_rev); } + +hardened_bool_t lifecycle_din_eq(lifecycle_device_id_t *id, uint32_t *din) { + if (id->device_id[1] == din[0] && id->device_id[2] == din[1]) + return kHardenedBoolTrue; + return kHardenedBoolFalse; +} } // extern "C" } // namespace rom_test diff --git a/sw/device/silicon_creator/lib/error.h b/sw/device/silicon_creator/lib/error.h index 2f50e099f5435..f490f349dfdf5 100644 --- a/sw/device/silicon_creator/lib/error.h +++ b/sw/device/silicon_creator/lib/error.h @@ -217,6 +217,7 @@ enum module_ { X(kErrorOwnershipNoOwner, ERROR_(11, kModuleOwnership, kInternal)), \ X(kErrorOwnershipKeyNotFound, ERROR_(12, kModuleOwnership, kNotFound)), \ X(kErrorOwnershipInvalidVersion, ERROR_(13, kModuleOwnership, kInvalidArgument)), \ + X(kErrorOwnershipInvalidDin, ERROR_(14, kModuleOwnership, kInvalidArgument)), \ \ X(kErrorPersoTlvInternal, ERROR_(0, kModulePersoTlv, kInternal)), \ X(kErrorPersoTlvCertObjNotFound, ERROR_(1, kModulePersoTlv, kNotFound)), \ diff --git a/sw/device/silicon_creator/lib/ownership/BUILD b/sw/device/silicon_creator/lib/ownership/BUILD index 48769dfd62d7e..28f679e989624 100644 --- a/sw/device/silicon_creator/lib/ownership/BUILD +++ b/sw/device/silicon_creator/lib/ownership/BUILD @@ -153,6 +153,7 @@ cc_library( "//sw/device/silicon_creator/lib/boot_svc:boot_svc_msg", "//sw/device/silicon_creator/lib/drivers:flash_ctrl", "//sw/device/silicon_creator/lib/drivers:hmac", + "//sw/device/silicon_creator/lib/drivers:lifecycle", ], ) @@ -168,6 +169,7 @@ cc_test( "//sw/device/lib/base:hardened", "//sw/device/silicon_creator/lib:boot_data", "//sw/device/silicon_creator/lib/boot_svc:boot_svc_header", + "//sw/device/silicon_creator/lib/drivers:lifecycle", "//sw/device/silicon_creator/testing:rom_test", "@googletest//:gtest_main", ], @@ -186,6 +188,7 @@ cc_library( "//sw/device/silicon_creator/lib:error", "//sw/device/silicon_creator/lib/boot_svc:boot_svc_msg", "//sw/device/silicon_creator/lib/drivers:flash_ctrl", + "//sw/device/silicon_creator/lib/drivers:lifecycle", ], ) diff --git a/sw/device/silicon_creator/lib/ownership/ownership_activate.c b/sw/device/silicon_creator/lib/ownership/ownership_activate.c index 75fc3b1e99ce6..619b5fb9057f5 100644 --- a/sw/device/silicon_creator/lib/ownership/ownership_activate.c +++ b/sw/device/silicon_creator/lib/ownership/ownership_activate.c @@ -9,6 +9,7 @@ #include "sw/device/silicon_creator/lib/boot_data.h" #include "sw/device/silicon_creator/lib/boot_svc/boot_svc_msg.h" #include "sw/device/silicon_creator/lib/drivers/flash_ctrl.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/owner_block.h" #include "sw/device/silicon_creator/lib/ownership/ownership_key.h" @@ -41,6 +42,14 @@ static rom_error_t activate(boot_svc_msg_t *msg, boot_data_t *bootdata) { return kErrorOwnershipInvalidNonce; } + // Verify the device identification number is correct. + lifecycle_device_id_t device_id; + lifecycle_device_id_get(&device_id); + if (lifecycle_din_eq(&device_id, msg->ownership_activate_req.din) != + kHardenedBoolTrue) { + return kErrorOwnershipInvalidDin; + } + // Seal page one to this chip. ownership_seal_page(/*page=*/1); diff --git a/sw/device/silicon_creator/lib/ownership/ownership_activate_unittest.cc b/sw/device/silicon_creator/lib/ownership/ownership_activate_unittest.cc index 6e403a81c9572..6da59b0dceb69 100644 --- a/sw/device/silicon_creator/lib/ownership/ownership_activate_unittest.cc +++ b/sw/device/silicon_creator/lib/ownership/ownership_activate_unittest.cc @@ -14,6 +14,7 @@ #include "sw/device/silicon_creator/lib/boot_svc/mock_boot_svc_header.h" #include "sw/device/silicon_creator/lib/drivers/mock_flash_ctrl.h" #include "sw/device/silicon_creator/lib/drivers/mock_hmac.h" +#include "sw/device/silicon_creator/lib/drivers/mock_lifecycle.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/nonce.h" @@ -97,6 +98,7 @@ class OwnershipActivateTest : public rom_test::RomTest { rom_test::MockRnd rnd_; rom_test::MockFlashCtrl flash_ctrl_; rom_test::MockBootSvcHeader hdr_; + rom_test::MockLifecycle lifecycle_; rom_test::MockOwnershipKey ownership_key_; }; @@ -162,6 +164,22 @@ TEST_P(OwnershipActivateValidStateTest, InvalidNonce) { EXPECT_EQ(error, kErrorOwnershipInvalidNonce); } +// Tests that an owner block with an invalid DIN fails. +TEST_P(OwnershipActivateValidStateTest, InvalidDin) { + bootdata_.ownership_state = static_cast(GetParam()); + // We want to pass the page 1 validity test to check the nonce of the + // message. + MakePage1Valid(true); + EXPECT_CALL(ownership_key_, validate(1, kOwnershipKeyActivate, _, _, _)) + .WillOnce(Return(kHardenedBoolTrue)); + EXPECT_CALL(lifecycle_, DeviceId(_)) + .WillOnce(SetArgPointee<0>((lifecycle_device_id_t){0, 1, 1})); + EXPECT_CALL(hdr_, Finalize(_, _, _)); + + rom_error_t error = ownership_activate_handler(&message_, &bootdata_); + EXPECT_EQ(error, kErrorOwnershipInvalidDin); +} + // Tests that an owner block with an invalid owner page with respect to the // current update state fails. TEST_P(OwnershipActivateValidStateTest, OwnerPageInvalid) { @@ -206,6 +224,8 @@ TEST_P(OwnershipActivateValidStateTest, OwnerPageValid) { EXPECT_CALL(ownership_key_, validate(1, kOwnershipKeyActivate, _, _, _)) .WillOnce(Return(kHardenedBoolTrue)); + EXPECT_CALL(lifecycle_, DeviceId(_)) + .WillOnce(SetArgPointee<0>((lifecycle_device_id_t){0})); switch (state) { case kOwnershipStateUnlockedSelf: @@ -269,6 +289,8 @@ TEST_P(OwnershipActivateValidStateTest, UpdateBootdataBl0) { EXPECT_CALL(ownership_key_, validate(1, kOwnershipKeyActivate, _, _, _)) .WillOnce(Return(kHardenedBoolTrue)); + EXPECT_CALL(lifecycle_, DeviceId(_)) + .WillOnce(SetArgPointee<0>((lifecycle_device_id_t){0})); switch (state) { case kOwnershipStateUnlockedSelf: diff --git a/sw/device/silicon_creator/lib/ownership/ownership_unlock.c b/sw/device/silicon_creator/lib/ownership/ownership_unlock.c index 69cfced66cde0..700426e181897 100644 --- a/sw/device/silicon_creator/lib/ownership/ownership_unlock.c +++ b/sw/device/silicon_creator/lib/ownership/ownership_unlock.c @@ -9,6 +9,7 @@ #include "sw/device/silicon_creator/lib/boot_data.h" #include "sw/device/silicon_creator/lib/boot_svc/boot_svc_msg.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/ownership_key.h" @@ -27,6 +28,15 @@ static rom_error_t do_unlock(boot_svc_msg_t *msg, boot_data_t *bootdata) { if (!nonce_equal(&msg->ownership_unlock_req.nonce, &bootdata->nonce)) { return kErrorOwnershipInvalidNonce; } + + // Verify the device identification number is correct. + lifecycle_device_id_t device_id; + lifecycle_device_id_get(&device_id); + if (lifecycle_din_eq(&device_id, msg->ownership_unlock_req.din) != + kHardenedBoolTrue) { + return kErrorOwnershipInvalidDin; + } + if (msg->ownership_unlock_req.unlock_mode == kBootSvcUnlockEndorsed) { hmac_digest_t digest; hmac_sha256(&msg->ownership_unlock_req.next_owner_key, @@ -106,6 +116,14 @@ static rom_error_t unlock_abort(boot_svc_msg_t *msg, boot_data_t *bootdata) { if (!nonce_equal(&msg->ownership_unlock_req.nonce, &bootdata->nonce)) { return kErrorOwnershipInvalidNonce; } + + // Verify the device identification number is correct. + lifecycle_device_id_t device_id; + lifecycle_device_id_get(&device_id); + if (lifecycle_din_eq(&device_id, msg->ownership_unlock_req.din) != + kHardenedBoolTrue) { + return kErrorOwnershipInvalidDin; + } // Go back to locked owner. bootdata->ownership_state = kOwnershipStateLockedOwner; nonce_new(&bootdata->nonce); diff --git a/sw/device/silicon_creator/lib/ownership/ownership_unlock_unittest.cc b/sw/device/silicon_creator/lib/ownership/ownership_unlock_unittest.cc index 2828fbf5c9030..4b4e62ec1b622 100644 --- a/sw/device/silicon_creator/lib/ownership/ownership_unlock_unittest.cc +++ b/sw/device/silicon_creator/lib/ownership/ownership_unlock_unittest.cc @@ -13,6 +13,7 @@ #include "sw/device/silicon_creator/lib/boot_data.h" #include "sw/device/silicon_creator/lib/boot_svc/mock_boot_svc_header.h" #include "sw/device/silicon_creator/lib/drivers/mock_hmac.h" +#include "sw/device/silicon_creator/lib/drivers/mock_lifecycle.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/ownership/datatypes.h" @@ -22,6 +23,7 @@ namespace { using ::testing::_; using ::testing::Return; +using ::testing::SetArgPointee; /* * The OwnershipUnlockTest fixture provides a pre-initialized bootdata and @@ -42,6 +44,7 @@ class OwnershipUnlockTest : public rom_test::RomTest { { .type = kBootSvcOwnershipUnlockReqType, }, + .din = {0, 0}, .nonce = {1, 2}, }, }; @@ -49,6 +52,7 @@ class OwnershipUnlockTest : public rom_test::RomTest { rom_test::MockHmac hmac_; rom_test::MockRnd rnd_; rom_test::MockBootSvcHeader hdr_; + rom_test::MockLifecycle lifecycle_; rom_test::MockOwnershipKey ownership_key_; }; @@ -89,6 +93,8 @@ TEST_F(OwnershipUnlockTest, UnlockAny) { kOwnershipKeyRecovery), _, _, _)) .WillOnce(Return(kHardenedBoolTrue)); + EXPECT_CALL(lifecycle_, DeviceId(_)) + .WillOnce(SetArgPointee<0>((lifecycle_device_id_t){0})); EXPECT_CALL(rnd_, Uint32()).WillRepeatedly(Return(5)); EXPECT_CALL(hdr_, Finalize(_, _, _)); @@ -116,6 +122,25 @@ TEST_F(OwnershipUnlockTest, UnlockAnyBadSignature) { EXPECT_EQ(bootdata_.ownership_state, kOwnershipStateLockedOwner); } +// Test that requesting LockedOwner->UnlockedAny fails when the DIN doesn't +// match. +TEST_F(OwnershipUnlockTest, UnlockAnyBadDin) { + message_.ownership_unlock_req.unlock_mode = kBootSvcUnlockAny; + EXPECT_CALL(ownership_key_, + validate(0, + static_cast(kOwnershipKeyUnlock | + kOwnershipKeyRecovery), + _, _, _)) + .WillOnce(Return(kHardenedBoolTrue)); + EXPECT_CALL(lifecycle_, DeviceId(_)) + .WillOnce(SetArgPointee<0>((lifecycle_device_id_t){0, 1, 1})); + EXPECT_CALL(hdr_, Finalize(_, _, _)); + + rom_error_t error = ownership_unlock_handler(&message_, &bootdata_); + EXPECT_EQ(error, kErrorOwnershipInvalidDin); + EXPECT_EQ(bootdata_.ownership_state, kOwnershipStateLockedOwner); +} + // Test that requesting LockedOwner->UnlockedAny fails when the nonce doesn't // match. TEST_F(OwnershipUnlockTest, UnlockAnyBadNonce) { @@ -158,6 +183,8 @@ TEST_F(OwnershipUnlockTest, UnlockEndorsed) { kOwnershipKeyRecovery), _, _, _)) .WillOnce(Return(kHardenedBoolTrue)); + EXPECT_CALL(lifecycle_, DeviceId(_)) + .WillOnce(SetArgPointee<0>((lifecycle_device_id_t){0})); EXPECT_CALL(hmac_, sha256(_, _, _)) .WillOnce([&](const void *, size_t, hmac_digest_t *digest) { for (size_t i = 0; i < ARRAYSIZE(digest->digest); ++i) { @@ -234,6 +261,8 @@ TEST_F(OwnershipUnlockTest, UnlockUpdate) { ownership_key_, validate(0, static_cast(kOwnershipKeyUnlock), _, _, _)) .WillOnce(Return(kHardenedBoolTrue)); + EXPECT_CALL(lifecycle_, DeviceId(_)) + .WillOnce(SetArgPointee<0>((lifecycle_device_id_t){0})); EXPECT_CALL(rnd_, Uint32()).WillRepeatedly(Return(5)); EXPECT_CALL(hdr_, Finalize(_, _, _)); @@ -299,6 +328,8 @@ TEST_P(OwnershipUnlockAbortValidStateTest, UnlockAbort) { ownership_key_, validate(0, static_cast(kOwnershipKeyUnlock), _, _, _)) .WillOnce(Return(kHardenedBoolTrue)); + EXPECT_CALL(lifecycle_, DeviceId(_)) + .WillOnce(SetArgPointee<0>((lifecycle_device_id_t){0})); EXPECT_CALL(rnd_, Uint32()).WillRepeatedly(Return(5)); EXPECT_CALL(hdr_, Finalize(_, _, _)); diff --git a/sw/device/silicon_creator/rom_ext/e2e/boot_svc/BUILD b/sw/device/silicon_creator/rom_ext/e2e/boot_svc/BUILD index 19c768286a580..6f8316670bce9 100644 --- a/sw/device/silicon_creator/rom_ext/e2e/boot_svc/BUILD +++ b/sw/device/silicon_creator/rom_ext/e2e/boot_svc/BUILD @@ -1,6 +1,7 @@ # Copyright lowRISC contributors (OpenTitan project). # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 + load("//rules:const.bzl", "CONST", "hex") load( "//rules/opentitan:defs.bzl", @@ -27,6 +28,12 @@ cc_library( ], ) +# Note: the boot_svc commands for ownership_{activate,unlock} are tested by +# the ownership transfer tests. These two commands are unlike the rest of +# the ownership commands in that they require a nonce, the device +# identification number and a signature, and thus require far more test +# infrastructure than the common boot_svc commands. + opentitan_test( name = "boot_svc_empty_test", srcs = ["boot_svc_empty_test.c"], @@ -166,44 +173,6 @@ opentitan_test( ], ) -opentitan_test( - name = "boot_svc_ownership_unlock_test", - srcs = [ - "//sw/device/silicon_creator/rom_ext/e2e/verified_boot:boot_test", - ], - exec_env = { - "//hw/top_earlgrey:fpga_hyper310_rom_ext": None, - }, - fpga = fpga_params( - data = [ - "//sw/device/silicon_creator/lib/ownership/keys/fake:no_owner_recovery_key", - ], - exit_failure = "(PASS|FAIL|FAULT).*\n", - test_cmd = """ - --exec="transport init" - --exec="fpga clear-bitstream" - --exec="fpga load-bitstream {bitstream}" - --exec="bootstrap --clear-uart=true {firmware}" - --exec="console --non-interactive --exit-success='ownership_state = OWND\r\n' --exit-failure='{exit_failure}'" - --exec="rescue boot-svc ownership-unlock \ - --mode Any \ - --nonce 0 \ - --sign $(location //sw/device/silicon_creator/lib/ownership/keys/fake:no_owner_recovery_key)" - --exec="console --non-interactive --exit-success='ownership_state = UANY\r\n' --exit-failure='{exit_failure}'" - - # Since we've altered the ownership state, clear the bitstream to not affect later tests. - --exec="fpga clear-bitstream" - no-op - """, - ), - deps = [ - "//sw/device/lib/base:status", - "//sw/device/lib/testing/test_framework:ottf_main", - "//sw/device/silicon_creator/lib:boot_log", - "//sw/device/silicon_creator/lib/drivers:retention_sram", - ], -) - manifest({ "name": "manifest_version_4", "security_version": "4", diff --git a/sw/host/opentitanlib/src/chip/boot_svc.rs b/sw/host/opentitanlib/src/chip/boot_svc.rs index 1bb37d00e460a..57819a2a9d3c3 100644 --- a/sw/host/opentitanlib/src/chip/boot_svc.rs +++ b/sw/host/opentitanlib/src/chip/boot_svc.rs @@ -115,6 +115,8 @@ pub struct NextBl0SlotResponse { pub struct OwnershipUnlockRequest { /// The desired unlock mode. pub unlock_mode: UnlockMode, + /// The Device Identification Number of the chip. + pub din: u64, /// Reserved for future use. #[serde(with = "serde_bytes", skip_serializing_if = "Vec::is_empty")] #[annotate(format=hexstr)] @@ -145,6 +147,8 @@ pub struct OwnershipUnlockResponse { pub struct OwnershipActivateRequest { /// The new primary boot slot after activating ownership. pub primary_bl0_slot: BootSlot, + /// The Device Identification Number of the chip. + pub din: u64, /// Whether to erase the previous owner's data during activation. pub erase_previous: HardenedBool, /// Reserved for future use. @@ -438,6 +442,7 @@ impl TryFrom<&[u8]> for OwnershipUnlockRequest { let mut reader = std::io::Cursor::new(buf); let mut val = Self::default(); val.unlock_mode = UnlockMode(reader.read_u32::()?); + val.din = reader.read_u64::()?; val.reserved.resize(Self::RESERVED_SIZE, 0); reader.read_exact(&mut val.reserved)?; val.nonce = reader.read_u64::()?; @@ -453,10 +458,11 @@ impl TryFrom<&[u8]> for OwnershipUnlockRequest { } impl OwnershipUnlockRequest { pub const SIZE: usize = 212; - const RESERVED_SIZE: usize = 10 * std::mem::size_of::(); + const RESERVED_SIZE: usize = 8 * std::mem::size_of::(); const SIGNATURE_OFFSET: usize = 148; pub fn write(&self, dest: &mut impl Write) -> Result<()> { dest.write_u32::(u32::from(self.unlock_mode))?; + dest.write_u64::(self.din)?; for i in 0..Self::RESERVED_SIZE { let p = self.reserved.get(i).unwrap_or(&0x00); dest.write_all(std::slice::from_ref(p))?; @@ -510,6 +516,7 @@ impl TryFrom<&[u8]> for OwnershipActivateRequest { let mut reader = std::io::Cursor::new(buf); let mut val = Self::default(); val.primary_bl0_slot = BootSlot(reader.read_u32::()?); + val.din = reader.read_u64::()?; val.erase_previous = HardenedBool(reader.read_u32::()?); val.reserved.resize(Self::RESERVED_SIZE, 0); reader.read_exact(&mut val.reserved)?; @@ -520,10 +527,11 @@ impl TryFrom<&[u8]> for OwnershipActivateRequest { } impl OwnershipActivateRequest { pub const SIZE: usize = 212; - const RESERVED_SIZE: usize = 33 * std::mem::size_of::(); + const RESERVED_SIZE: usize = 31 * std::mem::size_of::(); const SIGNATURE_OFFSET: usize = 148; pub fn write(&self, dest: &mut impl Write) -> Result<()> { dest.write_u32::(u32::from(self.primary_bl0_slot))?; + dest.write_u64::(self.din)?; dest.write_u32::(u32::from(self.erase_previous))?; for i in 0..Self::RESERVED_SIZE { let p = self.reserved.get(i).unwrap_or(&0x00); diff --git a/sw/host/opentitanlib/src/chip/device_id.rs b/sw/host/opentitanlib/src/chip/device_id.rs index 80f2e120335ba..63347e1b8ce94 100644 --- a/sw/host/opentitanlib/src/chip/device_id.rs +++ b/sw/host/opentitanlib/src/chip/device_id.rs @@ -11,29 +11,29 @@ use std::io::{Read, Write}; #[derive(Debug, Default, Serialize, Annotate)] pub struct DeviceId { #[annotate(format=hex)] - creator: u16, + pub creator: u16, #[annotate(format=hex)] - product: u16, + pub product: u16, #[annotate(format=hex)] - id: u64, + pub din: u64, #[annotate(format=hex)] - crc32: u32, + pub crc32: u32, #[annotate(format=hex)] - sku_specific: [u32; 4], + pub sku_specific: [u32; 4], } impl DeviceId { pub fn read(src: &mut impl Read) -> Result { let creator = src.read_u16::()?; let product = src.read_u16::()?; - let id = src.read_u64::()?; + let din = src.read_u64::()?; let crc32 = src.read_u32::()?; let mut sku_specific = [0u32; 4]; src.read_u32_into::(&mut sku_specific)?; Ok(Self { creator, product, - id, + din, crc32, sku_specific, }) @@ -42,7 +42,7 @@ impl DeviceId { pub fn write(&self, dest: &mut impl Write) -> Result<()> { dest.write_u16::(self.creator)?; dest.write_u16::(self.product)?; - dest.write_u64::(self.id)?; + dest.write_u64::(self.din)?; dest.write_u32::(self.crc32)?; for sku_specific in &self.sku_specific { dest.write_u32::(*sku_specific)?; diff --git a/sw/host/opentitanlib/src/chip/helper.rs b/sw/host/opentitanlib/src/chip/helper.rs index cf4e3717272a9..20110d018b499 100644 --- a/sw/host/opentitanlib/src/chip/helper.rs +++ b/sw/host/opentitanlib/src/chip/helper.rs @@ -17,6 +17,8 @@ pub struct OwnershipUnlockParams { pub mode: Option, #[arg(long, value_parser = u64::from_str, help="Current ROM_EXT nonce")] pub nonce: Option, + #[arg(long, value_parser = u64::from_str, help="Device Identification Number of the chip")] + pub din: Option, #[arg(long, help = "A path to the next owner key (for endorsed mode)")] pub next_owner: Option, #[arg(long, help = "A path to a detached signature for the unlock request")] @@ -34,6 +36,9 @@ impl OwnershipUnlockParams { if let Some(nonce) = &self.nonce { unlock.nonce = *nonce; } + if let Some(din) = &self.din { + unlock.din = *din; + } if let Some(next_owner) = &self.next_owner { let key = EcdsaPublicKey::load(next_owner)?; unlock.next_owner_key = EcdsaRawPublicKey::try_from(&key)?; @@ -67,6 +72,8 @@ impl OwnershipUnlockParams { pub struct OwnershipActivateParams { #[arg(long, value_parser = u64::from_str, help="Current ROM_EXT nonce")] pub nonce: Option, + #[arg(long, value_parser = u64::from_str, help="Device Identification Number of the chip")] + pub din: Option, #[arg(long, help = "A path to a detached signature for the activate request")] pub signature: Option, #[arg(long, help = "A path to a private key to sign the request")] @@ -79,6 +86,9 @@ impl OwnershipActivateParams { if let Some(nonce) = &self.nonce { activate.nonce = *nonce; } + if let Some(din) = &self.din { + activate.din = *din; + } if let Some(signature) = &self.signature { let mut f = File::open(signature)?; activate.signature = EcdsaRawSignature::read(&mut f)?; diff --git a/sw/host/opentitanlib/src/ownership/owner.rs b/sw/host/opentitanlib/src/ownership/owner.rs index 76299be173271..20c7a87b11909 100644 --- a/sw/host/opentitanlib/src/ownership/owner.rs +++ b/sw/host/opentitanlib/src/ownership/owner.rs @@ -281,11 +281,11 @@ r#"00000000: 4f 57 4e 52 00 08 00 00 00 00 00 00 4c 4e 45 58 OWNR........LNEX 00000220: 66 06 00 00 00 01 00 02 77 17 11 88 77 17 11 11 f.......w...w... 00000230: 49 4e 46 4f 20 00 00 00 00 01 00 00 66 06 00 99 INFO .......f... 00000240: 66 06 00 00 01 05 00 00 77 17 11 88 77 17 11 11 f.......w...w... -00000250: 52 45 53 51 38 00 00 00 58 4d 44 4d 20 00 e0 00 RESQ8...XMDM ... +00000250: 52 45 53 51 50 00 00 00 58 4d 44 4d 20 00 e0 00 RESQP...XMDM ... 00000260: 45 4d 50 54 4d 53 45 43 4e 45 58 54 55 4e 4c 4b EMPTMSECNEXTUNLK -00000270: 41 43 54 56 51 53 45 52 47 4f 4c 42 51 45 52 42 ACTVQSERGOLBQERB -00000280: 50 53 52 42 52 4e 57 4f 5a 5a 5a 5a 5a 5a 5a 5a PSRBRNWOZZZZZZZZ -00000290: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ +00000270: 41 43 54 56 51 53 45 52 42 53 45 52 4f 42 45 52 ACTVQSERBSEROBER +00000280: 47 4f 4c 42 51 45 52 42 50 53 52 42 52 4e 57 4f GOLBQERBPSRBRNWO +00000290: 30 47 50 4f 31 47 50 4f 44 49 54 4f 54 49 41 57 0GPO1GPODITOTIAW 000002a0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ 000002b0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ 000002c0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ @@ -530,7 +530,7 @@ r#"00000000: 4f 57 4e 52 00 08 00 00 00 00 00 00 4c 4e 45 58 OWNR........LNEX RescueConfig: { header: { identifier: "Rescue", - length: 56 + length: 80 }, rescue_type: "Xmodem", start: 32, @@ -542,10 +542,16 @@ r#"00000000: 4f 57 4e 52 00 08 00 00 00 00 00 00 4c 4e 45 58 OWNR........LNEX "OwnershipUnlockRequest", "OwnershipActivateRequest", "Rescue", + "RescueB", + "Reboot", "GetBootLog", "BootSvcReq", "BootSvcRsp", - "OwnerBlock" + "OwnerBlock", + "GetOwnerPage0", + "GetOwnerPage1", + "GetDeviceId", + "Wait" ] } } diff --git a/sw/host/opentitanlib/src/ownership/rescue.rs b/sw/host/opentitanlib/src/ownership/rescue.rs index feae26acda95c..d17635f7c9da1 100644 --- a/sw/host/opentitanlib/src/ownership/rescue.rs +++ b/sw/host/opentitanlib/src/ownership/rescue.rs @@ -118,10 +118,16 @@ impl OwnerRescueConfig { CommandTag::OwnershipUnlockRequest, CommandTag::OwnershipActivateRequest, CommandTag::Rescue, + CommandTag::RescueB, + CommandTag::Reboot, CommandTag::GetBootLog, CommandTag::BootSvcReq, CommandTag::BootSvcRsp, CommandTag::OwnerBlock, + CommandTag::GetOwnerPage0, + CommandTag::GetOwnerPage1, + CommandTag::GetDeviceId, + CommandTag::Wait, ], ..Default::default() } diff --git a/sw/host/opentitanlib/src/rescue/serial.rs b/sw/host/opentitanlib/src/rescue/serial.rs index 2700f907f8266..b126018a91911 100644 --- a/sw/host/opentitanlib/src/rescue/serial.rs +++ b/sw/host/opentitanlib/src/rescue/serial.rs @@ -96,7 +96,13 @@ impl RescueSerial { self.uart.write(&mode)?; let enter = b'\r'; self.uart.write(std::slice::from_ref(&enter))?; - let result = UartConsole::wait_for(&*self.uart, r"(ok|error):.*\r\n", Self::ONE_SECOND)?; + let mode = std::str::from_utf8(&mode)?; + let result = UartConsole::wait_for( + &*self.uart, + &format!("mode: {mode}\r\n(ok|error):.*\r\n"), + Self::ONE_SECOND, + )?; + if result[1] == "error" { return Err(RescueError::BadMode(result[0].clone()).into()); } diff --git a/sw/host/tests/ownership/flash_permission_test.rs b/sw/host/tests/ownership/flash_permission_test.rs index fc331584b660a..1e197a586549b 100644 --- a/sw/host/tests/ownership/flash_permission_test.rs +++ b/sw/host/tests/ownership/flash_permission_test.rs @@ -108,13 +108,14 @@ fn flash_permission_test(opts: &Opts, transport: &TransportWrapper) -> Result<() let rescue = RescueSerial::new(Rc::clone(&uart)); log::info!("###### Get Boot Log (1/2) ######"); - let data = transfer_lib::get_boot_log(transport, &rescue)?; + let (data, devid) = transfer_lib::get_device_info(transport, &rescue)?; log::info!("###### Ownership Unlock ######"); transfer_lib::ownership_unlock( transport, &rescue, opts.unlock_mode, data.rom_ext_nonce, + devid.din, &opts.unlock_key, if opts.unlock_mode == UnlockMode::Endorsed { opts.next_owner_key_pub.as_deref() @@ -194,13 +195,14 @@ fn flash_permission_test(opts: &Opts, transport: &TransportWrapper) -> Result<() } log::info!("###### Get Boot Log (2/2) ######"); - let data = transfer_lib::get_boot_log(transport, &rescue)?; + let (data, _) = transfer_lib::get_device_info(transport, &rescue)?; log::info!("###### Ownership Activate Block ######"); transfer_lib::ownership_activate( transport, &rescue, data.rom_ext_nonce, + devid.din, opts.activate_key .as_deref() .unwrap_or(&opts.next_activate_key), diff --git a/sw/host/tests/ownership/rescue_limit_test.rs b/sw/host/tests/ownership/rescue_limit_test.rs index 49ba679051465..adccaad4b93c5 100644 --- a/sw/host/tests/ownership/rescue_limit_test.rs +++ b/sw/host/tests/ownership/rescue_limit_test.rs @@ -65,13 +65,14 @@ fn flash_limit_test(opts: &Opts, transport: &TransportWrapper) -> Result<()> { let rescue = RescueSerial::new(Rc::clone(&uart)); log::info!("###### Get Boot Log (1/2) ######"); - let data = transfer_lib::get_boot_log(transport, &rescue)?; + let (data, devid) = transfer_lib::get_device_info(transport, &rescue)?; log::info!("###### Ownership Unlock ######"); transfer_lib::ownership_unlock( transport, &rescue, opts.unlock_mode, data.rom_ext_nonce, + devid.din, &opts.unlock_key, if opts.unlock_mode == UnlockMode::Endorsed { opts.next_owner_key_pub.as_deref() @@ -93,13 +94,14 @@ fn flash_limit_test(opts: &Opts, transport: &TransportWrapper) -> Result<()> { )?; log::info!("###### Get Boot Log (2/2) ######"); - let data = transfer_lib::get_boot_log(transport, &rescue)?; + let (data, _) = transfer_lib::get_device_info(transport, &rescue)?; log::info!("###### Ownership Activate Block ######"); transfer_lib::ownership_activate( transport, &rescue, data.rom_ext_nonce, + devid.din, opts.activate_key .as_deref() .unwrap_or(&opts.next_activate_key), diff --git a/sw/host/tests/ownership/rescue_permission_test.rs b/sw/host/tests/ownership/rescue_permission_test.rs index 3b2c208a48d95..30c02111bec6f 100644 --- a/sw/host/tests/ownership/rescue_permission_test.rs +++ b/sw/host/tests/ownership/rescue_permission_test.rs @@ -57,13 +57,14 @@ fn rescue_permission_test(opts: &Opts, transport: &TransportWrapper) -> Result<( let rescue = RescueSerial::new(Rc::clone(&uart)); log::info!("###### Get Boot Log (1/2) ######"); - let data = transfer_lib::get_boot_log(transport, &rescue)?; + let (data, devid) = transfer_lib::get_device_info(transport, &rescue)?; log::info!("###### Ownership Unlock ######"); transfer_lib::ownership_unlock( transport, &rescue, opts.unlock_mode, data.rom_ext_nonce, + devid.din, &opts.unlock_key, if opts.unlock_mode == UnlockMode::Endorsed { opts.next_owner_key_pub.as_deref() @@ -85,13 +86,14 @@ fn rescue_permission_test(opts: &Opts, transport: &TransportWrapper) -> Result<( )?; log::info!("###### Get Boot Log (2/2) ######"); - let data = transfer_lib::get_boot_log(transport, &rescue)?; + let (data, _) = transfer_lib::get_device_info(transport, &rescue)?; log::info!("###### Ownership Activate Block ######"); transfer_lib::ownership_activate( transport, &rescue, data.rom_ext_nonce, + devid.din, opts.activate_key .as_deref() .unwrap_or(&opts.next_activate_key), diff --git a/sw/host/tests/ownership/transfer_lib.rs b/sw/host/tests/ownership/transfer_lib.rs index 2441c28b54407..c9371b3112152 100644 --- a/sw/host/tests/ownership/transfer_lib.rs +++ b/sw/host/tests/ownership/transfer_lib.rs @@ -8,6 +8,7 @@ use clap::ValueEnum; use opentitanlib::app::TransportWrapper; use opentitanlib::chip::boot_log::BootLog; use opentitanlib::chip::boot_svc::{Message, UnlockMode}; +use opentitanlib::chip::device_id::DeviceId; use opentitanlib::chip::helper::{OwnershipActivateParams, OwnershipUnlockParams}; use opentitanlib::crypto::ecdsa::{EcdsaPrivateKey, EcdsaPublicKey}; use opentitanlib::ownership::{ @@ -21,9 +22,12 @@ use std::path::Path; pub const TEST_OWNER_CONFIG_VERSION: u32 = 1; /// Gets the BootLog. -pub fn get_boot_log(transport: &TransportWrapper, rescue: &RescueSerial) -> Result { +pub fn get_device_info( + transport: &TransportWrapper, + rescue: &RescueSerial, +) -> Result<(BootLog, DeviceId)> { rescue.enter(transport, /*reset=*/ true)?; - rescue.get_boot_log() + Ok((rescue.get_boot_log()?, rescue.get_device_id()?)) } /// Prepares an UnlockOwnership command, sends it to the chip and gets the response. @@ -32,12 +36,14 @@ pub fn ownership_unlock( rescue: &RescueSerial, mode: UnlockMode, nonce: u64, + din: u64, unlock_key: &Path, next_owner: Option<&Path>, ) -> Result<()> { let unlock = OwnershipUnlockParams { mode: Some(mode), nonce: Some(nonce), + din: Some(din), next_owner: next_owner.map(|p| p.into()), sign: Some(unlock_key.into()), ..Default::default() @@ -59,9 +65,18 @@ pub fn ownership_unlock_any( transport: &TransportWrapper, rescue: &RescueSerial, nonce: u64, + din: u64, unlock_key: &Path, ) -> Result<()> { - ownership_unlock(transport, rescue, UnlockMode::Any, nonce, unlock_key, None) + ownership_unlock( + transport, + rescue, + UnlockMode::Any, + nonce, + din, + unlock_key, + None, + ) } /// Prepares an OwnershipActivate command, sends it to the chip and gets the response. @@ -69,10 +84,12 @@ pub fn ownership_activate( transport: &TransportWrapper, rescue: &RescueSerial, nonce: u64, + din: u64, activate_key: &Path, ) -> Result<()> { let activate = OwnershipActivateParams { nonce: Some(nonce), + din: Some(din), sign: Some(activate_key.into()), ..Default::default() } diff --git a/sw/host/tests/ownership/transfer_test.rs b/sw/host/tests/ownership/transfer_test.rs index 7c6024d505553..35cba4646fd46 100644 --- a/sw/host/tests/ownership/transfer_test.rs +++ b/sw/host/tests/ownership/transfer_test.rs @@ -74,13 +74,14 @@ fn transfer_test(opts: &Opts, transport: &TransportWrapper) -> Result<()> { let rescue = RescueSerial::new(Rc::clone(&uart)); log::info!("###### Get Boot Log (1/2) ######"); - let data = transfer_lib::get_boot_log(transport, &rescue)?; + let (data, devid) = transfer_lib::get_device_info(transport, &rescue)?; log::info!("###### Ownership Unlock ######"); transfer_lib::ownership_unlock( transport, &rescue, opts.unlock_mode, data.rom_ext_nonce, + devid.din, &opts.unlock_key, if opts.unlock_mode == UnlockMode::Endorsed { opts.next_owner_key_pub.as_deref() @@ -128,13 +129,14 @@ fn transfer_test(opts: &Opts, transport: &TransportWrapper) -> Result<()> { } log::info!("###### Get Boot Log (2/2) ######"); - let data = transfer_lib::get_boot_log(transport, &rescue)?; + let (data, _) = transfer_lib::get_device_info(transport, &rescue)?; log::info!("###### Ownership Activate Block ######"); transfer_lib::ownership_activate( transport, &rescue, data.rom_ext_nonce, + devid.din, opts.activate_key .as_deref() .unwrap_or(&opts.next_activate_key),