diff --git a/sw/device/lib/crypto/drivers/BUILD b/sw/device/lib/crypto/drivers/BUILD index eddeeaf3875db..17173c700222f 100644 --- a/sw/device/lib/crypto/drivers/BUILD +++ b/sw/device/lib/crypto/drivers/BUILD @@ -145,6 +145,7 @@ cc_library( "//hw/top/dt:keymgr_dpe", "//sw/device/lib/base:abs_mmio", "//sw/device/lib/base:bitfield", + "//sw/device/lib/base:hardened", "//sw/device/lib/base:hardened_memory", "//sw/device/lib/base:macros", "//sw/device/lib/crypto/impl:status", diff --git a/sw/device/lib/crypto/drivers/keymgr_dpe.c b/sw/device/lib/crypto/drivers/keymgr_dpe.c index a1eb32b6e6dfb..5f1b05cf24462 100644 --- a/sw/device/lib/crypto/drivers/keymgr_dpe.c +++ b/sw/device/lib/crypto/drivers/keymgr_dpe.c @@ -29,6 +29,12 @@ static_assert(kKeymgrDPEOutputShareNumWords == static_assert(kKeymgrDPEOutputShareNumWords == KEYMGR_DPE_SW_SHARE1_OUTPUT_MULTIREG_COUNT, "Number of output share 1 registers does not match."); +static_assert(KEYMGR_DPE_METADATA_LOW_MULTIREG_COUNT == + KEYMGR_DPE_PARAM_NUM_MAX_HW_SLOT, + "Number of metadata low registers does not match."); +static_assert(KEYMGR_DPE_METADATA_HIGH_MULTIREG_COUNT == + KEYMGR_DPE_PARAM_NUM_MAX_HW_SLOT, + "Number of metadata high registers does not match."); /** * Fails if the keymgr dpe is not idle. @@ -334,3 +340,42 @@ status_t keymgr_dpe_sideload_clear_otbn(void) { status_t keymgr_dpe_sideload_clear_hmac(void) { return keymgr_dpe_sideload_clear(KEYMGR_DPE_SIDELOAD_CLEAR_VAL_VALUE_HMAC); } + +status_t keymgr_dpe_get_metadata(uint32_t slot, + keymgr_dpe_metadata_t *metadata) { + if (launder32(slot) >= KEYMGR_DPE_PARAM_NUM_MAX_HW_SLOT) { + return OTCRYPTO_BAD_ARGS; + } + HARDENED_CHECK_LT(slot, KEYMGR_DPE_PARAM_NUM_MAX_HW_SLOT); + + const uint32_t kBase = keymgr_dpe_base(); + metadata->max_key_version = abs_mmio_read32( + kBase + KEYMGR_DPE_METADATA_LOW_0_REG_OFFSET + slot * sizeof(uint32_t)); + + uint32_t reg_high = abs_mmio_read32( + kBase + KEYMGR_DPE_METADATA_HIGH_0_REG_OFFSET + slot * sizeof(uint32_t)); + metadata->valid = + bitfield_bit32_read(reg_high, KEYMGR_DPE_METADATA_HIGH_0_VALID_0_BIT) + ? kHardenedBoolTrue + : kHardenedBoolFalse; + metadata->boot_stage = (keymgr_dpe_boot_stage_t)bitfield_field32_read( + reg_high, KEYMGR_DPE_METADATA_HIGH_0_BOOT_STAGE_0_FIELD); + + metadata->slot_policy.allow_child = + bitfield_bit32_read(reg_high, + KEYMGR_DPE_METADATA_HIGH_0_ALLOW_CHILD_POLICY_0_BIT) + ? kHardenedBoolTrue + : kHardenedBoolFalse; + metadata->slot_policy.exportable = + bitfield_bit32_read(reg_high, + KEYMGR_DPE_METADATA_HIGH_0_EXPORTABLE_POLICY_0_BIT) + ? kHardenedBoolTrue + : kHardenedBoolFalse; + metadata->slot_policy.retain_parent = + bitfield_bit32_read(reg_high, + KEYMGR_DPE_METADATA_HIGH_0_RETAIN_PARENT_POLICY_0_BIT) + ? kHardenedBoolTrue + : kHardenedBoolFalse; + + return OTCRYPTO_OK; +} diff --git a/sw/device/lib/crypto/drivers/keymgr_dpe.h b/sw/device/lib/crypto/drivers/keymgr_dpe.h index 2619bcdd2a4e0..ff37f8a1f2692 100644 --- a/sw/device/lib/crypto/drivers/keymgr_dpe.h +++ b/sw/device/lib/crypto/drivers/keymgr_dpe.h @@ -5,10 +5,10 @@ #ifndef OPENTITAN_SW_DEVICE_LIB_CRYPTO_DRIVERS_KEYMGR_DPE_H_ #define OPENTITAN_SW_DEVICE_LIB_CRYPTO_DRIVERS_KEYMGR_DPE_H_ -#include #include #include +#include "sw/device/lib/base/hardened.h" #include "sw/device/lib/base/macros.h" #include "sw/device/lib/crypto/impl/status.h" @@ -55,6 +55,57 @@ typedef struct keymgr_dpe_output { uint32_t share1[kKeymgrDPEOutputShareNumWords]; } keymgr_dpe_output_t; +/** + * Policy bits associated with the DPE context held in one HW slot. + */ +typedef struct keymgr_dpe_policy { + /** + * Set if this DPE context allows deriving further DPE contexts. + */ + hardened_bool_t allow_child; + /** + * Set if the key for this slot is exportable. + */ + hardened_bool_t exportable; + /** + * Set if further advance operations retain (do not erase) this slot. + */ + hardened_bool_t retain_parent; +} keymgr_dpe_policy_t; + +/** + * Boot stage associated with a DPE context. + * Mirrors `keymgr_dpe_boot_stage_e` in keymgr_dpe_pkg.sv. + */ +typedef enum keymgr_dpe_boot_stage { + kKeymgrDPEBootStageCreator = 0, + kKeymgrDPEBootStageOwnerInt = 1, + kKeymgrDPEBootStageOwner = 2, + kKeymgrDPEBootStageRuntime = 3, +} keymgr_dpe_boot_stage_t; + +/** + * Output metadata from one HW slot. + */ +typedef struct keymgr_dpe_metadata { + /** + * Maximum allowed version for keys to be generated from this DPE context. + */ + uint32_t max_key_version; + /** + * The current boot_stage of this DPE context. + */ + keymgr_dpe_boot_stage_t boot_stage; + /** + * The current slot policy bits for this DPE context. + */ + keymgr_dpe_policy_t slot_policy; + /** + * Validity of this DPE context. + */ + hardened_bool_t valid; +} keymgr_dpe_metadata_t; + /** * Derive a key manager dpe key that is visible to software. * @@ -151,6 +202,18 @@ status_t keymgr_dpe_sideload_clear_otbn(void); OT_WARN_UNUSED_RESULT status_t keymgr_dpe_sideload_clear_hmac(void); +/** + * Reads back the metadata of a keymgr_dpe HW slot. + * + * @param slot Index of the HW slot to read metadata from. Must be less than + * `KEYMGR_DPE_PARAM_NUM_MAX_HW_SLOT`. + * @param[out] metadata Metadata of the DPE context held in `slot`. + * @return OK, or `OTCRYPTO_BAD_ARGS` if `slot` is out of range. + */ +OT_WARN_UNUSED_RESULT +status_t keymgr_dpe_get_metadata(uint32_t slot, + keymgr_dpe_metadata_t *metadata); + #ifdef __cplusplus } #endif diff --git a/sw/device/lib/dif/dif_keymgr_dpe.c b/sw/device/lib/dif/dif_keymgr_dpe.c index b22a7f5bced8d..71849d13e7121 100644 --- a/sw/device/lib/dif/dif_keymgr_dpe.c +++ b/sw/device/lib/dif/dif_keymgr_dpe.c @@ -97,6 +97,21 @@ static_assert(KEYMGR_DPE_SW_SHARE1_OUTPUT_7_REG_OFFSET == KEYMGR_DPE_SW_SHARE1_OUTPUT_0_REG_OFFSET + 28, "SW_SHARE1_OUTPUT_N registers must be contiguous."); +static_assert(KEYMGR_DPE_METADATA_LOW_1_REG_OFFSET == + KEYMGR_DPE_METADATA_LOW_0_REG_OFFSET + 4, + "METADATA_LOW_N registers must be contiguous."); +static_assert(KEYMGR_DPE_METADATA_HIGH_1_REG_OFFSET == + KEYMGR_DPE_METADATA_HIGH_0_REG_OFFSET + 4, + "METADATA_HIGH_N registers must be contiguous."); +static_assert(KEYMGR_DPE_METADATA_LOW_MULTIREG_COUNT == + KEYMGR_DPE_PARAM_NUM_MAX_HW_SLOT, + "METADATA_LOW_N register count must match the number of HW " + "slots."); +static_assert(KEYMGR_DPE_METADATA_HIGH_MULTIREG_COUNT == + KEYMGR_DPE_PARAM_NUM_MAX_HW_SLOT, + "METADATA_HIGH_N register count must match the number of HW " + "slots."); + /** * Error code constants of `dif_keymgr_dpe_status_code_t` are masks for the bits * of ERR_CODE register shifted left by 1. @@ -286,6 +301,44 @@ dif_result_t dif_keymgr_dpe_erase_slot( return kDifOk; } +dif_result_t dif_keymgr_dpe_get_metadata(const dif_keymgr_dpe_t *keymgr_dpe, + uint32_t slot, + dif_keymgr_dpe_metadata_t *metadata) { + if (keymgr_dpe == NULL || metadata == NULL || + slot >= KEYMGR_DPE_PARAM_NUM_MAX_HW_SLOT) { + return kDifBadArg; + } + + metadata->max_key_version = mmio_region_read32( + keymgr_dpe->base_addr, (ptrdiff_t)(KEYMGR_DPE_METADATA_LOW_0_REG_OFFSET + + slot * sizeof(uint32_t))); + + uint32_t reg_high = mmio_region_read32( + keymgr_dpe->base_addr, (ptrdiff_t)(KEYMGR_DPE_METADATA_HIGH_0_REG_OFFSET + + slot * sizeof(uint32_t))); + metadata->valid = + bitfield_bit32_read(reg_high, KEYMGR_DPE_METADATA_HIGH_0_VALID_0_BIT); + metadata->boot_stage = bitfield_field32_read( + reg_high, KEYMGR_DPE_METADATA_HIGH_0_BOOT_STAGE_0_FIELD); + + uint32_t slot_policy = 0; + slot_policy = bitfield_bit32_write( + slot_policy, KEYMGR_DPE_SLOT_POLICY_ALLOW_CHILD_BIT, + bitfield_bit32_read(reg_high, + KEYMGR_DPE_METADATA_HIGH_0_ALLOW_CHILD_POLICY_0_BIT)); + slot_policy = bitfield_bit32_write( + slot_policy, KEYMGR_DPE_SLOT_POLICY_EXPORTABLE_BIT, + bitfield_bit32_read(reg_high, + KEYMGR_DPE_METADATA_HIGH_0_EXPORTABLE_POLICY_0_BIT)); + slot_policy = bitfield_bit32_write( + slot_policy, KEYMGR_DPE_SLOT_POLICY_RETAIN_PARENT_BIT, + bitfield_bit32_read( + reg_high, KEYMGR_DPE_METADATA_HIGH_0_RETAIN_PARENT_POLICY_0_BIT)); + metadata->slot_policy = slot_policy; + + return kDifOk; +} + dif_result_t dif_keymgr_dpe_disable(const dif_keymgr_dpe_t *keymgr_dpe) { if (keymgr_dpe == NULL) { return kDifBadArg; diff --git a/sw/device/lib/dif/dif_keymgr_dpe.h b/sw/device/lib/dif/dif_keymgr_dpe.h index 22e3975723608..cae96d9cf0876 100644 --- a/sw/device/lib/dif/dif_keymgr_dpe.h +++ b/sw/device/lib/dif/dif_keymgr_dpe.h @@ -104,6 +104,32 @@ typedef struct dif_keymgr_dpe_advance_params { uint32_t slot_policy; } dif_keymgr_dpe_advance_params_t; +/** + * Output metadata from one HW slot + */ +typedef struct dif_keymgr_dpe_metadata { + /** + * Maximum allowed version for keys to be generated from this DPE context + */ + uint32_t max_key_version; + + /** + * The current boot_stage of this DPE context. + */ + uint32_t boot_stage; + + /** + * The current slot policy bits for this DPE context, using the same bit + * layout as the `SLOT_POLICY` register. + */ + uint32_t slot_policy; + + /** + * Validity of this DPE context. + */ + uint32_t valid; +} dif_keymgr_dpe_metadata_t; + /** * Key destination of a versioned key generation operation. * @@ -285,6 +311,20 @@ dif_result_t dif_keymgr_dpe_erase_slot( const dif_keymgr_dpe_t *keymgr_dpe, const dif_keymgr_dpe_erase_params_t *params); +/** + * Reads back the metadata of a keymgr_dpe HW slot. + * + * @param keymgr_dpe A key manager handle. + * @param slot Index of the HW slot to read metadata from. + * @param[out] metadata The maximum key version, boot stage, slot policy and + * validity of the DPE context held in `slot`. + * @return The result of the operation. + */ +OT_WARN_UNUSED_RESULT +dif_result_t dif_keymgr_dpe_get_metadata(const dif_keymgr_dpe_t *keymgr_dpe, + uint32_t slot, + dif_keymgr_dpe_metadata_t *metadata); + /** * Disables key manager dpe. * diff --git a/sw/device/lib/testing/keymgr_dpe_testutils.c b/sw/device/lib/testing/keymgr_dpe_testutils.c index 0c87d844a46cc..4b56bdd34e6fe 100644 --- a/sw/device/lib/testing/keymgr_dpe_testutils.c +++ b/sw/device/lib/testing/keymgr_dpe_testutils.c @@ -421,6 +421,28 @@ status_t keymgr_dpe_testutils_check_state( return OK_STATUS(); } +status_t keymgr_dpe_testutils_check_metadata(const dif_keymgr_dpe_t *keymgr_dpe, + uint32_t slot, + uint32_t exp_max_key_version, + uint32_t exp_boot_stage, + uint32_t exp_policy) { + dif_keymgr_dpe_metadata_t metadata; + TRY(dif_keymgr_dpe_get_metadata(keymgr_dpe, slot, &metadata)); + TRY_CHECK(metadata.valid, "Keymgr DPE slot %d is not valid", slot); + TRY_CHECK(metadata.max_key_version == exp_max_key_version, + "Keymgr DPE slot %d has unexpected max key version: %x, expected " + "to be %x", + slot, metadata.max_key_version, exp_max_key_version); + TRY_CHECK( + metadata.boot_stage == exp_boot_stage, + "Keymgr DPE slot %d in unexpected boot stage: %x, expected to be %x", + slot, metadata.boot_stage, exp_boot_stage); + TRY_CHECK(metadata.slot_policy == exp_policy, + "Keymgr DPE slot %d has unexpected policy: %x, expected to be %x", + slot, metadata.slot_policy, exp_policy); + return OK_STATUS(); +} + status_t keymgr_dpe_testutils_generate_key( const dif_keymgr_dpe_t *keymgr_dpe, const dif_keymgr_dpe_generate_params_t *params) { diff --git a/sw/device/lib/testing/keymgr_dpe_testutils.h b/sw/device/lib/testing/keymgr_dpe_testutils.h index ac56897c6343c..94e1fb4546ea5 100644 --- a/sw/device/lib/testing/keymgr_dpe_testutils.h +++ b/sw/device/lib/testing/keymgr_dpe_testutils.h @@ -326,6 +326,26 @@ OT_WARN_UNUSED_RESULT status_t keymgr_dpe_testutils_check_state( const dif_keymgr_dpe_t *keymgr_dpe, const dif_keymgr_dpe_state_t exp_state); +/** + * Checks that a keymgr dpe HW slot holds a valid DPE context with the expected + * maximum key version, boot stage and slot policy. + * + * @param keymgr_dpe A key manager dpe handle. + * @param slot The HW slot to check. + * @param exp_max_key_version The expected maximum key version for the DPE + * context in `slot`. + * @param exp_boot_stage The expected boot stage for the DPE context in + * `slot`. + * @param exp_policy The expected policy bits for the DPE context in `slot`, + * using the same bit layout as the `SLOT_POLICY` register. + */ +OT_WARN_UNUSED_RESULT +status_t keymgr_dpe_testutils_check_metadata(const dif_keymgr_dpe_t *keymgr_dpe, + uint32_t slot, + uint32_t exp_max_key_version, + uint32_t exp_boot_stage, + uint32_t exp_policy); + /** * Issues a keymgr dpe HW/SW versioned key generation and wait for it * to complete. diff --git a/sw/device/silicon_creator/lib/drivers/BUILD b/sw/device/silicon_creator/lib/drivers/BUILD index a435c26a3c398..e246bfbf5ddb3 100644 --- a/sw/device/silicon_creator/lib/drivers/BUILD +++ b/sw/device/silicon_creator/lib/drivers/BUILD @@ -339,6 +339,7 @@ cc_library( "//hw/top:keymgr_dpe_c_regs", "//hw/top/dt", "//sw/device/lib/base:abs_mmio", + "//sw/device/lib/base:hardened", "//sw/device/lib/base:hardened_memory", "//sw/device/lib/base:macros", "//sw/device/lib/runtime:hart", @@ -398,6 +399,7 @@ opentitan_test( "//sw/device/lib/testing/test_framework:ottf_main", "//sw/device/silicon_creator/lib:error", "//sw/device/silicon_creator/lib:keymgr_dpe_binding", + "//sw/device/silicon_creator/lib:manifest", "//sw/device/silicon_creator/lib/base:chip", "//sw/device/silicon_creator/lib/base:sec_mmio", ], diff --git a/sw/device/silicon_creator/lib/drivers/keymgr_dpe.c b/sw/device/silicon_creator/lib/drivers/keymgr_dpe.c index 07cb952bb1ad3..ffee2b159718b 100644 --- a/sw/device/silicon_creator/lib/drivers/keymgr_dpe.c +++ b/sw/device/silicon_creator/lib/drivers/keymgr_dpe.c @@ -24,6 +24,10 @@ KEYMGR_DPE_ASSERT(kScKeymgrDPEStateDisabled, KEYMGR_DPE_WORKING_STATE_STATE_VALUE_DISABLED); KEYMGR_DPE_ASSERT(kScKeymgrDPEStateInvalid, KEYMGR_DPE_WORKING_STATE_STATE_VALUE_INVALID); +KEYMGR_DPE_ASSERT(KEYMGR_DPE_METADATA_LOW_MULTIREG_COUNT, + KEYMGR_DPE_PARAM_NUM_MAX_HW_SLOT); +KEYMGR_DPE_ASSERT(KEYMGR_DPE_METADATA_HIGH_MULTIREG_COUNT, + KEYMGR_DPE_PARAM_NUM_MAX_HW_SLOT); /** * Internal keymgr dpe operation definition @@ -604,6 +608,67 @@ rom_error_t sc_keymgr_dpe_erase_slot(uint32_t sel_dst_slot) { return sc_keymgr_dpe_wait_until_done(); } +/** + * Reads back the metadata of a keymgr_dpe HW slot. + */ +rom_error_t sc_keymgr_dpe_get_metadata(uint32_t slot, + sc_keymgr_dpe_metadata_t *metadata) { + if (launder32(slot) >= KEYMGR_DPE_PARAM_NUM_MAX_HW_SLOT) { + return kErrorKeymgrInternal; + } + HARDENED_CHECK_LT(slot, KEYMGR_DPE_PARAM_NUM_MAX_HW_SLOT); + + metadata->max_key_version = abs_mmio_read32( + sc_keymgr_dpe_base() + KEYMGR_DPE_METADATA_LOW_0_REG_OFFSET + + slot * sizeof(uint32_t)); + + uint32_t reg_high = abs_mmio_read32(sc_keymgr_dpe_base() + + KEYMGR_DPE_METADATA_HIGH_0_REG_OFFSET + + slot * sizeof(uint32_t)); + metadata->valid = + bitfield_bit32_read(reg_high, KEYMGR_DPE_METADATA_HIGH_0_VALID_0_BIT) + ? kHardenedBoolTrue + : kHardenedBoolFalse; + metadata->boot_stage = (sc_keymgr_dpe_boot_stage_t)bitfield_field32_read( + reg_high, KEYMGR_DPE_METADATA_HIGH_0_BOOT_STAGE_0_FIELD); + + metadata->slot_policy.child = bitfield_bit32_read( + reg_high, KEYMGR_DPE_METADATA_HIGH_0_ALLOW_CHILD_POLICY_0_BIT); + metadata->slot_policy.expo = bitfield_bit32_read( + reg_high, KEYMGR_DPE_METADATA_HIGH_0_EXPORTABLE_POLICY_0_BIT); + metadata->slot_policy.parent = bitfield_bit32_read( + reg_high, KEYMGR_DPE_METADATA_HIGH_0_RETAIN_PARENT_POLICY_0_BIT); + + return kErrorOk; +} + +/** + * Checks that a keymgr_dpe HW slot holds a valid DPE context with the expected + * maximum key version, boot stage and slot policy. + */ +rom_error_t sc_keymgr_dpe_check_metadata( + uint32_t slot, uint32_t expected_max_key_version, + sc_keymgr_dpe_boot_stage_t expected_boot_stage, + const sc_keymgr_dpe_policies_t *expected_policy) { + sc_keymgr_dpe_metadata_t metadata; + HARDENED_RETURN_IF_ERROR(sc_keymgr_dpe_get_metadata(slot, &metadata)); + if (launder32(metadata.valid) == kHardenedBoolTrue && + launder32(metadata.max_key_version) == expected_max_key_version && + launder32(metadata.boot_stage) == expected_boot_stage && + launder32(metadata.slot_policy.child) == expected_policy->child && + launder32(metadata.slot_policy.expo) == expected_policy->expo && + launder32(metadata.slot_policy.parent) == expected_policy->parent) { + HARDENED_CHECK_EQ(metadata.valid, kHardenedBoolTrue); + HARDENED_CHECK_EQ(metadata.max_key_version, expected_max_key_version); + HARDENED_CHECK_EQ(metadata.boot_stage, expected_boot_stage); + HARDENED_CHECK_EQ(metadata.slot_policy.child, expected_policy->child); + HARDENED_CHECK_EQ(metadata.slot_policy.expo, expected_policy->expo); + HARDENED_CHECK_EQ(metadata.slot_policy.parent, expected_policy->parent); + return kErrorOk; + } + return kErrorKeymgrInternal; +} + /** * Advances the keymgr dpe into the disable state. All keys store in the * sideloaded interface are continuously scrambled. diff --git a/sw/device/silicon_creator/lib/drivers/keymgr_dpe.h b/sw/device/silicon_creator/lib/drivers/keymgr_dpe.h index a3da307f17a1c..7df6338480f0a 100644 --- a/sw/device/silicon_creator/lib/drivers/keymgr_dpe.h +++ b/sw/device/silicon_creator/lib/drivers/keymgr_dpe.h @@ -8,6 +8,7 @@ #include #include +#include "sw/device/lib/base/hardened.h" #include "sw/device/silicon_creator/lib/error.h" #include "sw/device/silicon_creator/lib/keymgr_dpe_binding_value.h" @@ -144,6 +145,39 @@ typedef struct sc_keymgr_dpe_advance_data { uint32_t version; } sc_keymgr_dpe_advance_data_t; +/** + * Boot stage associated with a DPE context. + * Mirrors `keymgr_dpe_boot_stage_e` in keymgr_dpe_pkg.sv. + */ +typedef enum sc_keymgr_dpe_boot_stage { + kScKeymgrDPEBootStageCreator = 0, + kScKeymgrDPEBootStageOwnerInt = 1, + kScKeymgrDPEBootStageOwner = 2, + kScKeymgrDPEBootStageRuntime = 3, +} sc_keymgr_dpe_boot_stage_t; + +/** + * Output metadata from one HW slot. + */ +typedef struct sc_keymgr_dpe_metadata { + /** + * Maximum allowed version for keys to be generated from this DPE context. + */ + uint32_t max_key_version; + /** + * The current boot_stage of this DPE context. + */ + sc_keymgr_dpe_boot_stage_t boot_stage; + /** + * The current slot policy bits for this DPE context. + */ + sc_keymgr_dpe_policies_t slot_policy; + /** + * Validity of this DPE context. + */ + hardened_bool_t valid; +} sc_keymgr_dpe_metadata_t; + /** * Destination for key generation. */ @@ -481,6 +515,39 @@ rom_error_t sc_keymgr_dpe_advance_owner( OT_WARN_UNUSED_RESULT rom_error_t sc_keymgr_dpe_erase_slot(uint32_t sel_dst_slot); +/** + * Reads back the metadata of a keymgr_dpe HW slot. + * + * @param slot Index of the HW slot to read metadata from. + * @param[out] metadata The maximum key version, boot stage, slot policy and + * validity of the DPE context held in `slot`. + * @return `kErrorOk` on success, `kErrorKeymgrInternal` if `slot` is out of + * range. + */ +OT_WARN_UNUSED_RESULT +rom_error_t sc_keymgr_dpe_get_metadata(uint32_t slot, + sc_keymgr_dpe_metadata_t *metadata); + +/** + * Checks that a keymgr_dpe HW slot holds a valid DPE context with the + * expected maximum key version, boot stage and slot policy. + * + * @param slot Index of the HW slot to check. + * @param expected_max_key_version Expected maximum key version for the DPE + * context held in `slot`. + * @param expected_boot_stage Expected boot stage for the DPE context held in + * `slot`. + * @param expected_policy Expected policy for the DPE context held in `slot`. + * @return `kErrorOk` if `slot` is in range, holds a valid DPE context and + * matches `expected_max_key_version`, `expected_boot_stage` and + * `expected_policy`, `kErrorKeymgrInternal` otherwise. + */ +OT_WARN_UNUSED_RESULT +rom_error_t sc_keymgr_dpe_check_metadata( + uint32_t slot, uint32_t expected_max_key_version, + sc_keymgr_dpe_boot_stage_t expected_boot_stage, + const sc_keymgr_dpe_policies_t *expected_policy); + /** * Advances the keymgr dpe into the disable state. * diff --git a/sw/device/silicon_creator/lib/drivers/keymgr_dpe_functest.c b/sw/device/silicon_creator/lib/drivers/keymgr_dpe_functest.c index 29f32912bf1f1..ef09c40092822 100644 --- a/sw/device/silicon_creator/lib/drivers/keymgr_dpe_functest.c +++ b/sw/device/silicon_creator/lib/drivers/keymgr_dpe_functest.c @@ -28,6 +28,8 @@ #include "sw/device/silicon_creator/lib/drivers/retention_sram.h" #include "sw/device/silicon_creator/lib/error.h" #include "sw/device/silicon_creator/lib/keymgr_dpe_binding_value.h" +#include "sw/device/silicon_creator/lib/manifest.h" +#include "sw/device/silicon_creator/lib/manifest_def.h" #include "hw/top/keymgr_dpe_regs.h" #include "hw/top/kmac_regs.h" @@ -118,6 +120,10 @@ rom_error_t keymgr_dpe_rom_test(void) { .sel_dst_slot = kSealingSlot, .version = kMaxVerRom}; + // When the CreatorRootKey is derived by the rom code, it uses the maximum key + // version from the manifest of this image. + uint32_t creator_max_key_version = manifest_def_get()->max_key_version; + // Bypass the CreatorRootKey when not in TEST_ROM as the key should already be // derived by the rom code. if (retention_sram_get() @@ -146,15 +152,19 @@ rom_error_t keymgr_dpe_rom_test(void) { sc_keymgr_dpe_advance_creator(sealing_key, attestation_key)); LOG_INFO("Keymgr DPE: CreatorRootKey derived"); sec_mmio_check_values(/*rnd_offset=*/0); + creator_max_key_version = kMaxVerRom; } else { // Two dummy `sec_mmio_check_values` to keep both path in sync. sec_mmio_check_values(/*rnd_offset=*/0); sec_mmio_check_values(/*rnd_offset=*/0); } - // TODO(#30759): Verify the kKeymgrDPESealSlot / kKeymgrDPEAttestSlot - // hold keys with boot stage set to BootStageOwnerInt (1). (Note: - // Current bootstage + 1) + CHECK(sc_keymgr_dpe_check_metadata(kSealingSlot, creator_max_key_version, + kScKeymgrDPEBootStageOwnerInt, + &kDefaultPolicy) == kErrorOk); + CHECK(sc_keymgr_dpe_check_metadata(kAttestationSlot, creator_max_key_version, + kScKeymgrDPEBootStageOwnerInt, + &kDefaultPolicy) == kErrorOk); // ------ OwnerIntKey Stage ------------------------ // Derive both the attestation and sealing OwnerIntKey @@ -174,9 +184,12 @@ rom_error_t keymgr_dpe_rom_test(void) { sec_mmio_check_counters(/*expected_check_count=*/3); - // TODO(#30759): Verify the kKeymgrDPESealSlot / kKeymgrDPEAttestSlot - // hold keys with boot stage set to BootStageOwner (2). (Note: - // Current bootstage + 1) + CHECK(sc_keymgr_dpe_check_metadata(kSealingSlot, kMaxVerRomExt, + kScKeymgrDPEBootStageOwner, + &kDefaultPolicy) == kErrorOk); + CHECK(sc_keymgr_dpe_check_metadata(kAttestationSlot, kMaxVerRomExt, + kScKeymgrDPEBootStageOwner, + &kDefaultPolicy) == kErrorOk); return kErrorOk; } @@ -207,9 +220,12 @@ rom_error_t keymgr_dpe_rom_ext_test(void) { sec_mmio_check_counters(/*expected_check_count=*/5); - // TODO(#30759): Verify the kKeymgrDPESealSlot / kKeymgrDPEAttestSlot - // hold keys with boot stage set to BootStageRuntime (3). (Note: - // Current bootstage + 1) + CHECK(sc_keymgr_dpe_check_metadata(kSealingSlot, kMaxVerBl0, + kScKeymgrDPEBootStageRuntime, + &kDefaultPolicy) == kErrorOk); + CHECK(sc_keymgr_dpe_check_metadata(kAttestationSlot, kMaxVerBl0, + kScKeymgrDPEBootStageRuntime, + &kDefaultPolicy) == kErrorOk); return kErrorOk; } diff --git a/sw/device/silicon_creator/lib/drivers/keymgr_dpe_unittest.cc b/sw/device/silicon_creator/lib/drivers/keymgr_dpe_unittest.cc index 0185819e801a2..5b9f514c70fac 100644 --- a/sw/device/silicon_creator/lib/drivers/keymgr_dpe_unittest.cc +++ b/sw/device/silicon_creator/lib/drivers/keymgr_dpe_unittest.cc @@ -159,6 +159,26 @@ class KeymgrDpeTest : public rom_test::RomTest { KEYMGR_DPE_OP_STATUS_STATUS_VALUE_DONE_SUCCESS); } + /** + * Expects a `sc_keymgr_dpe_get_metadata()` sequence. + */ + void ExpectGetMetadata(uint32_t slot, uint32_t max_key_version, bool valid, + uint32_t boot_stage, sc_keymgr_dpe_policies_t policy) { + EXPECT_ABS_READ32( + base_ + KEYMGR_DPE_METADATA_LOW_0_REG_OFFSET + slot * sizeof(uint32_t), + max_key_version); + EXPECT_ABS_READ32( + base_ + KEYMGR_DPE_METADATA_HIGH_0_REG_OFFSET + slot * sizeof(uint32_t), + { + {KEYMGR_DPE_METADATA_HIGH_0_VALID_0_BIT, valid}, + {KEYMGR_DPE_METADATA_HIGH_0_BOOT_STAGE_0_OFFSET, boot_stage}, + {KEYMGR_DPE_METADATA_HIGH_0_ALLOW_CHILD_POLICY_0_BIT, policy.child}, + {KEYMGR_DPE_METADATA_HIGH_0_EXPORTABLE_POLICY_0_BIT, policy.expo}, + {KEYMGR_DPE_METADATA_HIGH_0_RETAIN_PARENT_POLICY_0_BIT, + policy.parent}, + }); + } + uint32_t base_ = dt_keymgr_dpe_reg_block(kDtKeymgrDpe, kDtKeymgrDpeRegBlockCore); keymgr_dpe_binding_value_t binding_value_sealing_ = { @@ -678,6 +698,122 @@ TEST_F(KeymgrDpeTest, EraseSlot) { EXPECT_EQ(sc_keymgr_dpe_erase_slot(/*sel_dst_slot=*/2), kErrorOk); } +TEST_F(KeymgrDpeTest, GetMetadata) { + sc_keymgr_dpe_policies_t policy = { + .parent = kScKeymgrDPESlotPolRetainParent, + .child = kScKeymgrDPESlotPolAllowChild, + .expo = kScKeymgrDPESlotPolNoExport, + }; + ExpectGetMetadata(/*slot=*/3, /*max_key_version=*/0xA5A5A5A5, + /*valid=*/true, kScKeymgrDPEBootStageOwner, policy); + + sc_keymgr_dpe_metadata_t metadata; + EXPECT_EQ(sc_keymgr_dpe_get_metadata(/*slot=*/3, &metadata), kErrorOk); + EXPECT_EQ(metadata.max_key_version, 0xA5A5A5A5); + EXPECT_EQ(metadata.valid, kHardenedBoolTrue); + EXPECT_EQ(metadata.boot_stage, kScKeymgrDPEBootStageOwner); + EXPECT_EQ(metadata.slot_policy.parent, kScKeymgrDPESlotPolRetainParent); + EXPECT_EQ(metadata.slot_policy.child, kScKeymgrDPESlotPolAllowChild); + EXPECT_EQ(metadata.slot_policy.expo, kScKeymgrDPESlotPolNoExport); +} + +TEST_F(KeymgrDpeTest, GetMetadataInvalidSlot) { + sc_keymgr_dpe_policies_t policy = { + .parent = kScKeymgrDPESlotPolEraseParent, + .child = kScKeymgrDPESlotPolNoChild, + .expo = kScKeymgrDPESlotPolAllowExport, + }; + ExpectGetMetadata(/*slot=*/0, /*max_key_version=*/0, /*valid=*/false, + kScKeymgrDPEBootStageRuntime, policy); + + sc_keymgr_dpe_metadata_t metadata; + EXPECT_EQ(sc_keymgr_dpe_get_metadata(/*slot=*/0, &metadata), kErrorOk); + EXPECT_EQ(metadata.max_key_version, 0u); + EXPECT_EQ(metadata.valid, kHardenedBoolFalse); + EXPECT_EQ(metadata.boot_stage, kScKeymgrDPEBootStageRuntime); + EXPECT_EQ(metadata.slot_policy.parent, kScKeymgrDPESlotPolEraseParent); + EXPECT_EQ(metadata.slot_policy.child, kScKeymgrDPESlotPolNoChild); + EXPECT_EQ(metadata.slot_policy.expo, kScKeymgrDPESlotPolAllowExport); +} + +TEST_F(KeymgrDpeTest, GetMetadataSlotOutOfRange) { + // An out-of-range slot is rejected without touching any register. + sc_keymgr_dpe_metadata_t metadata; + EXPECT_EQ( + sc_keymgr_dpe_get_metadata(KEYMGR_DPE_PARAM_NUM_MAX_HW_SLOT, &metadata), + kErrorKeymgrInternal); +} + +TEST_F(KeymgrDpeTest, CheckMetadata) { + ExpectGetMetadata(/*slot=*/1, /*max_key_version=*/0xA5A5A5A5, + /*valid=*/true, kScKeymgrDPEBootStageOwnerInt, + policy_erase_parent_); + + EXPECT_EQ(sc_keymgr_dpe_check_metadata( + /*slot=*/1, /*expected_max_key_version=*/0xA5A5A5A5, + kScKeymgrDPEBootStageOwnerInt, &policy_erase_parent_), + kErrorOk); +} + +TEST_F(KeymgrDpeTest, CheckMetadataSlotOutOfRange) { + EXPECT_EQ(sc_keymgr_dpe_check_metadata(KEYMGR_DPE_PARAM_NUM_MAX_HW_SLOT, + /*expected_max_key_version=*/0, + kScKeymgrDPEBootStageCreator, + &policy_erase_parent_), + kErrorKeymgrInternal); +} + +TEST_F(KeymgrDpeTest, CheckMetadataMismatch) { + const uint32_t kSlot = 1; + const uint32_t kMaxKeyVersion = 0xA5A5A5A5; + const sc_keymgr_dpe_boot_stage_t kBootStage = kScKeymgrDPEBootStageOwnerInt; + + // Invalid slot. + ExpectGetMetadata(kSlot, kMaxKeyVersion, /*valid=*/false, kBootStage, + policy_erase_parent_); + EXPECT_EQ(sc_keymgr_dpe_check_metadata(kSlot, kMaxKeyVersion, kBootStage, + &policy_erase_parent_), + kErrorKeymgrInternal); + + // Wrong maximum key version. + ExpectGetMetadata(kSlot, kMaxKeyVersion - 1, /*valid=*/true, kBootStage, + policy_erase_parent_); + EXPECT_EQ(sc_keymgr_dpe_check_metadata(kSlot, kMaxKeyVersion, kBootStage, + &policy_erase_parent_), + kErrorKeymgrInternal); + + // Wrong boot stage. + ExpectGetMetadata(kSlot, kMaxKeyVersion, /*valid=*/true, + kScKeymgrDPEBootStageOwner, policy_erase_parent_); + EXPECT_EQ(sc_keymgr_dpe_check_metadata(kSlot, kMaxKeyVersion, kBootStage, + &policy_erase_parent_), + kErrorKeymgrInternal); + + // Wrong retain parent policy. + sc_keymgr_dpe_policies_t policy = policy_erase_parent_; + policy.parent = kScKeymgrDPESlotPolRetainParent; + ExpectGetMetadata(kSlot, kMaxKeyVersion, /*valid=*/true, kBootStage, policy); + EXPECT_EQ(sc_keymgr_dpe_check_metadata(kSlot, kMaxKeyVersion, kBootStage, + &policy_erase_parent_), + kErrorKeymgrInternal); + + // Wrong allow child policy. + policy = policy_erase_parent_; + policy.child = kScKeymgrDPESlotPolNoChild; + ExpectGetMetadata(kSlot, kMaxKeyVersion, /*valid=*/true, kBootStage, policy); + EXPECT_EQ(sc_keymgr_dpe_check_metadata(kSlot, kMaxKeyVersion, kBootStage, + &policy_erase_parent_), + kErrorKeymgrInternal); + + // Wrong exportable policy. + policy = policy_erase_parent_; + policy.expo = kScKeymgrDPESlotPolAllowExport; + ExpectGetMetadata(kSlot, kMaxKeyVersion, /*valid=*/true, kBootStage, policy); + EXPECT_EQ(sc_keymgr_dpe_check_metadata(kSlot, kMaxKeyVersion, kBootStage, + &policy_erase_parent_), + kErrorKeymgrInternal); +} + TEST_F(KeymgrDpeTest, Disable) { ExpectStatusCheck(KEYMGR_DPE_OP_STATUS_STATUS_VALUE_IDLE, KEYMGR_DPE_WORKING_STATE_STATE_VALUE_AVAILABLE,