blob: 76cfd0d52871679e5f83946ff937e5639890de42 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#ifndef OPENTITAN_SW_DEVICE_LIB_DIF_DIF_KEYMGR_H_
#define OPENTITAN_SW_DEVICE_LIB_DIF_DIF_KEYMGR_H_
/**
* @file
* @brief <a href="/hw/ip/keymgr/doc/">Key Manager</a> Device Interface
* Functions
*/
#include <stdint.h>
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/dif/dif_warn_unused_result.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/**
* Enumeration for enabling/disabling various functionality.
*/
typedef enum dif_keymgr_toggle {
/**
* Enabled state.
*/
kDifKeymgrToggleEnabled,
/**
* Disabled state.
*/
kDifKeymgrToggleDisabled,
} dif_keymgr_toggle_t;
/**
* Enumeration for side load slot clearing.
*/
typedef enum dif_keymgr_sideload_clr {
kDifKeyMgrSideLoadClearNone,
kDifKeyMgrSideLoadClearAes,
kDifKeyMgrSideLoadClearHmac,
kDifKeyMgrSideLoadClearKmac,
kDifKeyMgrSideLoadClearOtbn,
kDifKeyMgrSideLoadClearAll,
} dif_keymgr_sideload_clr_t;
/**
* Hardware instantiation parameters for key manager.
*
* This struct describes information about the underlying hardware that is
* not determined until the hardware design is used as part of a top-level
* design.
*/
typedef struct dif_keymgr_params {
/**
* Base address of key manager registers.
*/
mmio_region_t base_addr;
} dif_keymgr_params_t;
/**
* Runtime configuration for key manager.
*
* This struct describes runtime information for one-time configuration of the
* hardware.
*/
typedef struct dif_keymgr_config {
/**
* Number of key manager cycles before the entropy is reseeded.
*
* Key manager uses random values generated by the entropy source for
* initializing its state and clearing sideload keys. This value determines
* the frequency at which this random value is updated.
*/
uint16_t entropy_reseed_interval;
} dif_keymgr_config_t;
/**
* A handle to a key manager.
*
* This type should be treated as opaque by users.
*/
typedef struct dif_keymgr {
/**
* Hardware instantiation parameters.
*/
dif_keymgr_params_t params;
} dif_keymgr_t;
/**
* Result of a key manager operation.
*/
typedef enum dif_keymgr_result {
/**
* The call succeeded.
*/
kDifKeymgrOk = 0,
/**
* A non-specific error occurred and the hardware is in an invalid or
* irrecoverable state.
*/
kDifKeymgrError = 1,
/**
* The caller supplied invalid arguments but the call did not cause any
* side-effects and the hardware is in a valid and recoverable state.
*/
kDifKeymgrBadArg = 2,
} dif_keymgr_result_t;
/**
* Result of a key manager operation that writes to lockable registers.
*/
typedef enum dif_keymgr_lockable_result {
/**
* The call succeeded.
*/
kDifKeymgrLockableOk = kDifKeymgrOk,
/**
* A non-specific error occurred and the hardware is in an invalid or
* irrecoverable state.
*/
kDifKeymgrLockableError = kDifKeymgrError,
/**
* The caller supplied invalid arguments but the call did not cause any
* side-effects and the hardware is in a valid and recoverable state.
*/
kDifKeymgrLockableBadArg = kDifKeymgrBadArg,
/**
* The register that needs to be written to is locked.
*/
kDifKeymgrLockableLocked,
} dif_keymgr_lockable_result_t;
/**
* Key manager interrupts.
*/
typedef enum dif_keymgr_irq {
/**
* Operation was completed.
*
* This interrupt is triggered regardless of the outcome of the operation.
* Clients can use `dif_keymgr_get_status_codes()` to determine whether a key
* manager operation was successful or not.
*/
kDifKeymgrIrqDone,
/**
* \internal Last key manager interrupt.
*/
kDifKeymgrIrqLast = kDifKeymgrIrqDone,
} dif_keymgr_irq_t;
/**
* A snapshot of the enablement state of key manager interrupts.
*
* This is an opaque type, to be used with the `dif_keymgr_irq_disable_all()`
* and `dif_keymgr_irq_restore_all()` functions.
*/
typedef uint32_t dif_keymgr_irq_snapshot_t;
/**
* Key manager alerts.
*
* Key manager generates alerts when it encounters a hardware or software
* error. Clients can use `dif_keymgr_get_status_codes()` to determine the type
* of error that occurred.
*/
typedef enum dif_keymgr_alert {
/**
* A hardware error occurred.
*
* This alert is triggered when the hardware encounters an error condition
* that cannot be caused by the software, e.g. invalid KMAC commands, states,
* or outputs.
*/
kDifKeymgrAlertHardware,
/**
* A software error occurred.
*
* This alert is triggered when the software attempts to start an invalid
* operation, e.g. attempting to generate keys when the key manager is at
* Initialized state, or use invalid inputs, e.g. a key with a forbidden
* version.
*/
kDifKeymgrAlertSoftware,
/**
* \internal Last key manager alert.
*/
kDifKeymgrAlertLast = kDifKeymgrAlertSoftware,
} dif_keymgr_alert_t;
/**
* Key manager states.
*
* Key manager has seven states that control its operation. During secure boot,
* key manager transitions between these states sequentially and these
* transitions are irreversible until a power cycle.
*
* The secret value of key manager changes at each state transition in a
* well-defined manner, thus its meaning is tied to the current state of key
* manager.
*
* The functionality of key manager is directly tied to the life cycle
* controller peripheral and it is explicitly disabled during specific life
* cycle stages. If key manager has not been initialized, it cannot be
* initialized until it is enabled by life cycle controller. If key manager is
* disabled by life cycle controller while it is in an operational state, it
* immediately wipes its contents and transitions to Disabled state.
*/
typedef enum dif_keymgr_state {
/**
* Reset state.
*
* This is the initial state of key manager after PoR. At this state, the
* secret value of key manager is non-deterministic, i.e. some value based on
* the physical characteristics of the device and environment conditions.
*/
kDifKeymgrStateReset,
/**
* Initialized state.
*
* Secret value of key manager is initialized with random values generated by
* the entropy source. This is not an operational state and the key manager
* state must be advanced one more time before keys or identity seeds can be
* generated.
*/
kDifKeymgrStateInitialized,
/**
* CreatorRootKey state.
*
* This is the first operational state of key manager. At this state, key
* manager can generate a versioned creator key or a creator identity seed
* that can be used to generate a creator identity using an asymmetric KDF.
*/
kDifKeymgrStateCreatorRootKey,
/**
* OwnerIntermediateKey state.
*
* This is the second operational state of key manager. At this state, key
* manager can generate a versioned intermediate owner key or an intermediate
* owner identity seed that can be used to generate an intermediate owner
* identity using an asymmetric KDF.
*/
kDifKeymgrStateOwnerIntermediateKey,
/**
* OwnerRootKey state.
*
* This is the last operational state of key manager. At this state, key
* manager can generate a versioned owner key or an owner identity seed that
* can be used to generate an owner identity using an asymmetric KDF.
*/
kDifKeymgrStateOwnerRootKey,
/**
* Disabled state.
*
* This is a terminal state where key manager is no longer operational. At
* this state, the secret value of key manager is a random value.
*/
kDifKeymgrStateDisabled,
/**
* Invalid state.
*
* Keymgr is in an invalid state and must be reset.
*/
kDifKeymgrStateInvalid,
} dif_keymgr_state_t;
/**
* Creates a new handle for key manager.
*
* This function does not actuate the hardware and must be called to initialize
* the handle that must be passed to other functions in this library in each
* boot stage. A typical usage of this library during different secure boot
* stages is as follows:
*
* - In Mask ROM:
* - Create a new handle: `dif_keymgr_init()`.
* - Configure hardware: `dif_keymgr_configure()`.
* - Initialize state: `dif_keymgr_advance_state()`,
* `dif_keymgr_get_status_codes()`, `dif_keymgr_get_state()`.
* - Advance state: `dif_keymgr_advance_state()`,
* `dif_keymgr_get_status_codes()`, `dif_keymgr_get_state()`.
* - In subsequent boot stages, i.e. ROM_EXT, BL0, kernel:
* - Create a new handle: `dif_keymgr_init()`.
* - Generate keys and/or identity seeds:
* `dif_keymgr_generate_versioned_key()`,
* `dif_keymgr_generate_identity_seed()`, `dif_keymgr_get_status_codes()`.
* - Read output (if applicable): `dif_keymgr_read_output()`.
* - Advance state: `dif_keymgr_advance_state()`,
* `dif_keymgr_get_status_codes()`, `dif_keymgr_get_state()`.
*
* @param params Hardware instantiation parameters.
* @param[out] keymgr Out-param for the initialized handle.
* @return The result of the operation.
*/
DIF_WARN_UNUSED_RESULT
dif_keymgr_result_t dif_keymgr_init(dif_keymgr_params_t params,
dif_keymgr_t *keymgr);
/**
* Configures key manager with runtime information.
*
* This function should need to be called once for the lifetime of `keymgr`.
*
* @param keymgr A key manager handle.
* @param config Runtime configuration parameters.
* @return The result of the operation.
*/
DIF_WARN_UNUSED_RESULT
dif_keymgr_result_t dif_keymgr_configure(const dif_keymgr_t *keymgr,
dif_keymgr_config_t config);
/**
* Parameters for a key manager state.
*/
typedef struct dif_keymgr_state_params {
/**
* This value is used by key manager to derive secret values and can be either
* a value that represents the contents of a boot stage, e.g. a (truncated)
* hash, or a tag.
*
* If it is a hash, changes in a boot stage will change the secret value, and
* consequently the versioned keys and identity seeds generated at subsequent
* boot stages. If it is a tag, those secret values, versioned keys, and
* identity seeds will be preserved across updates of the boot stage as long
* as the tag remains the same.
*/
uint32_t binding_value[8];
/**
* Maximum allowed version for keys generated at a state.
*/
uint32_t max_key_version;
} dif_keymgr_state_params_t;
/**
* Advances key manager state.
*
* This function instructs key manager to transition to the next state, i.e.
* Reset -> Initialized -> CreatorRootKey -> OwnerIntermediateKey ->
* OwnerRootKey -> Disabled. Once a state transition starts, key manager locks
* the control register until the transition is complete. State transitions are
* irreversible until a power cycle.
*
* The entropy source must be initialized before this function is called. After
* PoR, key manager is in Reset state with a non-deterministic secret value. The
* first call to this function after PoR causes key manager to initialize its
* secret value using the random values generated by the entropy source and
* transition to Initialized state.
*
* `params` is required when the next state is an operational state,
* i.e. `CreatorRootKey`, `OwnerIntermediateKey`, or `OwnerRootKey`. It must be
* `NULL` for all other cases.
*
* This is an asynchronous function because key manager state transitions
* involve KMAC operations that can take some time to complete. Clients must
* check the status of key manager using `dif_keymgr_get_status_codes()` before
* calling other functions in this library.
*
* @param keymgr A key manager handle.
* @param params The binding and max key version value for the next state.
* @return The result of the operation.
*/
DIF_WARN_UNUSED_RESULT
dif_keymgr_lockable_result_t dif_keymgr_advance_state(
const dif_keymgr_t *keymgr, const dif_keymgr_state_params_t *params);
/**
* Disables key manager.
*
* This function disables key manager until the next power cycle by making it
* transition to Disabled state. Disabled state is a terminal state where key
* manager is no longer operational and its secret value is a random value.
*
* @param keymgr A key manager handle.
* @return The result of the operation.
*/
DIF_WARN_UNUSED_RESULT
dif_keymgr_lockable_result_t dif_keymgr_disable(const dif_keymgr_t *keymgr);
/**
* Status code bit flags.
*
* See also: `dif_keymgr_status_codes_t`.
*/
typedef enum dif_keymgr_status_code {
/**
* Key manager is idle.
*/
kDifKeymgrStatusCodeIdle = 1 << 0,
/**
* Software invoked an invalid operation.
*/
kDifKeymgrStatusCodeInvalidOperation = 1 << 1,
/**
* Key manager issued invalid data to KMAC interface.
*/
kDifKeymgrStatusCodeInvalidKmacInput = 1 << 2,
/**
* Software performed an invalid shadow update.
*/
kDifKeymgrStatusCodeInvalidKmacOutput = 1 << 3,
/**
* Key manager encountered invalid state
*/
kDifKeymgrStatusCodeInvalidState = 1 << 4,
} dif_keymgr_status_code_t;
/**
* A bit vector of status codes.
*
* The following snippet can be used to check if key manager is idle:
*
* bool is_idle = (status_codes & kDifKeymgrStatusCodeIdle);
*
* The following snippet can be used to check if key manager is idle and
* error-free:
*
* bool is_idle_and_ok = (status_codes == kDifKeymgrStatusCodeIdle);
*
* See also: `dif_keymgr_status_code_t`.
*/
typedef uint8_t dif_keymgr_status_codes_t;
/**
* Gets the operational status of key manager.
*
* This function also clears OP_STATUS and ERR_CODE registers after reading
* them.
*
* @param keymgr A key manager handle.
* @param[out] status_codes Out-param for key manager status codes.
* @return The result of the operation.
*/
DIF_WARN_UNUSED_RESULT
dif_keymgr_result_t dif_keymgr_get_status_codes(
const dif_keymgr_t *keymgr, dif_keymgr_status_codes_t *status_codes);
/**
* Gets the current state of key manager.
*
* @param keymgr A key manager handle.
* @param[out] state Out-param for current key manager state.
* @return The result of the operation.
*/
DIF_WARN_UNUSED_RESULT
dif_keymgr_result_t dif_keymgr_get_state(const dif_keymgr_t *keymgr,
dif_keymgr_state_t *state);
/**
* Generates an identity seed.
*
* This function requests key manager to generate an identity seed using its
* current secret value. Clients must first verify that the operation was
* successful using `dif_keymgr_get_status_codes()` before reading the generated
* identity seed using `dif_keymgr_read_output()`.
*
* The generated seed can be used to generate an identity using an asymmetric
* KDF.
*
* @param keymgr A key manager handle.
* @return The result of the operation.
*/
DIF_WARN_UNUSED_RESULT
dif_keymgr_lockable_result_t dif_keymgr_generate_identity_seed(
const dif_keymgr_t *keymgr);
/**
* Destination of a versioned key generation operation.
*
* Key manager can make the output of a versioned key generation operation
* available to software or sideload it directly to a peripheral device. When
* the destination is a peripheral device, the output of the operation is not
* visible to software and a different derivation constant is used for each
* peripheral.
*/
typedef enum dif_keymgr_versioned_key_dest {
/**
* Store the generated versioned key in software visible registers.
*
* The generated versioned key can be read by calling
* `dif_keymgr_read_output()` after verifying that the operation was
* successful using `dif_keymgr_get_status_codes()`.
*/
kDifKeymgrVersionedKeyDestSw,
/**
* Sideload the generated versioned key to AES device.
*/
kDifKeymgrVersionedKeyDestAes,
/**
* Sideload the generated versioned key to KMAC device.
*/
kDifKeymgrVersionedKeyDestKmac,
/**
* \internal Last key destination.
*/
kDifKeymgrVersionedKeyDestLast = kDifKeymgrVersionedKeyDestKmac,
} dif_keymgr_versioned_key_dest_t;
/**
* Parameters for generating a versioned key.
*/
typedef struct dif_keymgr_versioned_key_params {
/**
* Destination of the generated versioned key.
*
* See also: `dif_keymgr_versioned_key_dest_t`.
*/
dif_keymgr_versioned_key_dest_t dest;
/**
* Salt value to use for key generation.
*/
uint32_t salt[8];
/**
* Version value to use for key generation.
*/
uint32_t version;
} dif_keymgr_versioned_key_params_t;
/**
* Generates a versioned key.
*
* This function requests key manager to generate a versioned key using its
* current secret value and the provided parameters. The generated key can be
* sideloaded directly to a peripheral device or made visible to software using
* `params.dest`. If the destination is software, clients must first verify that
* the operation was successful using `dif_keymgr_get_status_codes()` before
* reading the generated key using `dif_keymgr_read_output()`.
*
* @param keymgr A key manager handle.
* @param params Key generation parameters.
* @return The result of the operation.
*/
DIF_WARN_UNUSED_RESULT
dif_keymgr_lockable_result_t dif_keymgr_generate_versioned_key(
const dif_keymgr_t *keymgr, dif_keymgr_versioned_key_params_t params);
/**
* Starts or stops clearing of sideload keys.
*
* When a key is generated to be sideloaded to a hardware peripheral, key
* manager stores it in a set of storage registers. Calling this function with
* `state` set to `kDifKeymgrToggleEnabled` causes key manager to clear sideload
* keys continously using random values from the entropty source. Callers must
* disable clearing of sideload keys to resume normal sideload operation.
*
* @param keymgr A key manager handle.
* @param state The new toggle state for sideload clear.
* @return The result of the operation.
*/
DIF_WARN_UNUSED_RESULT
dif_keymgr_result_t dif_keymgr_sideload_clear_set_enabled(
const dif_keymgr_t *keymgr, dif_keymgr_toggle_t state);
/**
* Checks whether clearing of sideload keys is enabled or not.
*
* @param keymgr A key manager handle.
* @param[out] Out-param for the current toggle state of sideload clear.
* @return The result of the operation.
*/
DIF_WARN_UNUSED_RESULT
dif_keymgr_result_t dif_keymgr_sideload_clear_get_enabled(
const dif_keymgr_t *keymgr, dif_keymgr_toggle_t *state);
/**
* Output of a key manager operation.
*
* Key manager outputs are in two-shares.
*/
typedef struct dif_keymgr_output {
uint32_t value[2][8];
} dif_keymgr_output_t;
/**
* Reads the output of the last key manager operation.
*
* After starting a key manager operation, clients must verify that the
* operation was successful using `dif_keymgr_get_status_codes()` before calling
* this function.
*
* When key manager is used for versioned key generation, the output of this
* function is valid only if the destination of the operation was
* `kDifKeymgrVersionedKeyDestSw`.
*
* See also: `dif_keymgr_output_t`.
*
* @param keymgr A key manager handle.
* @param[out] output Out-param for key manager output.
* @return The result of the operation.
*/
DIF_WARN_UNUSED_RESULT
dif_keymgr_result_t dif_keymgr_read_output(const dif_keymgr_t *keymgr,
dif_keymgr_output_t *output);
/**
* Forces a particular alert as if hardware had asserted it.
*
* @param keymgr A key manager handle.
* @param alert An alert type.
* @return The result of the operation.
*/
DIF_WARN_UNUSED_RESULT
dif_keymgr_result_t dif_keymgr_alert_force(const dif_keymgr_t *keymgr,
dif_keymgr_alert_t alert);
/**
* Returns whether a particular interrupt is currently pending.
*
* @param keymgr A key manager handle.
* @param irq An interrupt type.
* @param[out] is_pending Out-param for whether the interrupt is pending.
* @return The result of the operation.
*/
DIF_WARN_UNUSED_RESULT
dif_keymgr_result_t dif_keymgr_irq_is_pending(const dif_keymgr_t *keymgr,
dif_keymgr_irq_t irq,
bool *is_pending);
/**
* Acknowledges a particular interrupt, indicating to the hardware that it has
* been successfully serviced.
*
* @param keymgr A key manager handle.
* @param irq An interrupt type.
* @return The result of the operation.
*/
DIF_WARN_UNUSED_RESULT
dif_keymgr_result_t dif_keymgr_irq_acknowledge(const dif_keymgr_t *keymgr,
dif_keymgr_irq_t irq);
/**
* Checks whether a particular interrupt is currently enabled or disabled.
*
* @param keymgr A key manager handle.
* @param irq An interrupt type.
* @param[out] state Out-param for toggle state of the interrupt.
* @return The result of the operation.
*/
DIF_WARN_UNUSED_RESULT
dif_keymgr_result_t dif_keymgr_irq_get_enabled(const dif_keymgr_t *keymgr,
dif_keymgr_irq_t irq,
dif_keymgr_toggle_t *state);
/**
* Sets whether a particular interrupt is currently enabled or disabled.
*
* @param keymgr A key manager handle.
* @param irq An interrupt type.
* @param state The new toggle state for the interrupt.
* @return The result of the operation.
*/
DIF_WARN_UNUSED_RESULT
dif_keymgr_result_t dif_keymgr_irq_set_enabled(const dif_keymgr_t *keymgr,
dif_keymgr_irq_t irq,
dif_keymgr_toggle_t state);
/**
* Forces a particular interrupt, causing it to be serviced as if hardware had
* asserted it.
*
* @param keymgr A key manager handle.
* @param irq An interrupt type.
* @return The result of the operation.
*/
DIF_WARN_UNUSED_RESULT
dif_keymgr_result_t dif_keymgr_irq_force(const dif_keymgr_t *keymgr,
dif_keymgr_irq_t irq);
/**
* Disables all interrupts, optionally snapshotting all toggle state for later
* restoration.
*
* @param keymgr A key manager handle.
* @param[out] snapshot Out-param for the snapshot; may be `NULL`.
* @return The result of the operation.
*/
DIF_WARN_UNUSED_RESULT
dif_keymgr_result_t dif_keymgr_irq_disable_all(
const dif_keymgr_t *keymgr, dif_keymgr_irq_snapshot_t *snapshot);
/**
* Restores interrupts from the given snapshot.
*
* This function can be used with `dif_keymgr_irq_disable_all()` to temporary
* interrupt save-and-restore.
*
* @param keymgr A key manager handle.
* @param snapshot A snapshot to restore from.
* @return The result of the operation.
*/
DIF_WARN_UNUSED_RESULT
dif_keymgr_result_t dif_keymgr_irq_restore_all(
const dif_keymgr_t *keymgr, const dif_keymgr_irq_snapshot_t *snapshot);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_KEYMGR_H_