dif_keymgr.h

To use this DIF, include the following C header:

#include "/home/runner/work/opentitan/opentitan/sw/device/lib/dif/dif_keymgr.h"

This header provides the following device interface functions:

Generated from dif_keymgr.h
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

#ifndef OPENTITAN_SW_DEVICE_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/macros.h"
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/dif/dif_base.h"

#include "keymgr_regs.h"
#include "sw/device/lib/dif/autogen/dif_keymgr_autogen.h"

#ifdef __cplusplus
extern "C" {
#endif  // __cplusplus

/**
 * A typical usage of this library during different secure boot
 * stages is as follows:
 *
 * - In 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()`.
 */

/**
 * Enumeration for side load slot clearing.
 */
typedef enum dif_keymgr_sideload_clr {
  kDifKeyMgrSideLoadClearNone = 0,
  kDifKeyMgrSideLoadClearAes = 1,
  kDifKeyMgrSideLoadClearKmac = 2,
  kDifKeyMgrSideLoadClearOtbn = 3,
  // Using different value than those enumerated above should clear all slots,
  // so we can use the mask value of this field to denote ALL case. This was
  // we can statically assert this value on the .c side of this DIF.
  kDifKeyMgrSideLoadClearAll = 7,
} dif_keymgr_sideload_clr_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;

/**
 * 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;

/**
 * Compound Device Identifier type.
 *
 * The key manager supports the DICE open profile consisting of two Compound
 * Device Identifiers (CDI):
 *
 *   - Sealing
 *   - Attestation
 *
 * In every operational state of the key manager, it is possible to derive
 * either sealing or attestation identifiers, software or hardware keys by
 * setting the `CDI_SEL` bit in the `CONTROL_SHADOWED` register.
 */
typedef enum dif_keymgr_cdi_type {
  /**
   * Sealing CDI.
   *
   * This is the default configuration, corresponding to an unset bit.
   */
  kDifKeymgrSealingCdi = KEYMGR_CONTROL_SHADOWED_CDI_SEL_VALUE_SEALING_CDI,
  /**
   * Attestation CDI.
   */
  kDifKeymgrAttestationCdi =
      KEYMGR_CONTROL_SHADOWED_CDI_SEL_VALUE_ATTESTATION_CDI
} dif_keymgr_cdi_type_t;

/**
 * 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.
 */
OT_WARN_UNUSED_RESULT
dif_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.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_keymgr_advance_state(const dif_keymgr_t *keymgr,
                                      const dif_keymgr_state_params_t *params);

/**
 * Advances key manager state without setting any of the required inputs.
 *
 * 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.
 *
 * This function does not have a `dif_keymgr_state_params_t` parameter since
 * these inputs are expected to be set before this function is called, e.g. when
 * the chip is using `rom` as opposed to `test_rom`. See
 * `dif_keymgr_advance_state()` if you need to set the binding value and max key
 * version before advancing the state.
 *
 * 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.
 *
 * 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.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_keymgr_advance_state_raw(const dif_keymgr_t *keymgr);

/**
 * 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.
 */
OT_WARN_UNUSED_RESULT
dif_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.
 */
OT_WARN_UNUSED_RESULT
dif_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.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_keymgr_get_state(const dif_keymgr_t *keymgr,
                                  dif_keymgr_state_t *state);

/**
 * Parameters for generating an identity seed.
 */
typedef struct dif_keymgr_identity_seed_params {
  /**
   * Compound Device Identifier type (sealing or attestation).
   */
  dif_keymgr_cdi_type_t cdi_type;
} dif_keymgr_identity_seed_params_t;

/**
 * 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.
 * @param params Identity seed generation params.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_keymgr_generate_identity_seed(
    const dif_keymgr_t *keymgr, dif_keymgr_identity_seed_params_t params);

/**
 * 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,
  /**
   * Sideload the generated versioned key to Otbn device.
   */
  kDifKeymgrVersionedKeyDestOtbn,
  /**
   * \internal Last key destination.
   */
  kDifKeymgrVersionedKeyDestLast = kDifKeymgrVersionedKeyDestOtbn,
} 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;
  /**
   * Coumpund Device Identifier type (sealing or attestation).
   */
  dif_keymgr_cdi_type_t cdi_type;
} 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.
 */
OT_WARN_UNUSED_RESULT
dif_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.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_keymgr_sideload_clear_set_enabled(const dif_keymgr_t *keymgr,
                                                   dif_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.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_keymgr_sideload_clear_get_enabled(const dif_keymgr_t *keymgr,
                                                   dif_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.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_keymgr_read_output(const dif_keymgr_t *keymgr,
                                    dif_keymgr_output_t *output);
/**
 * Attestation and sealing binding value.
 */
typedef struct dif_keymgr_binding_value {
  /**
   * Sealing binding value.
   */
  uint32_t sealing[8];
  /**
   * Attestation binding value.
   */
  uint32_t attestation[8];
} dif_keymgr_binding_value_t;

/**
 * Reads both the attestation or the binding value set.
 *
 * @param keymgr A key manager handle.
 * @param[out] output Value read.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_keymgr_read_binding(const dif_keymgr_t *keymgr,
                                     dif_keymgr_binding_value_t *output);

typedef struct dif_keymgr_max_key_version {
  /**
   * Max creator key version.
   */
  uint32_t creator_max_key_version;
  /**
   * Max owner intermediate key version.
   */
  uint32_t owner_int_max_key_version;
  /**
   * Max owner key version.
   */
  uint32_t owner_max_key_version;
} dif_keymgr_max_key_version_t;

/**
 * Reads the max key version of each stage.
 *
 * @param keymgr A key manager handle.
 * @param version Struct with the max versions set.
 * @return dif_result_t
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_keymgr_read_max_key_version(
    const dif_keymgr_t *keymgr, dif_keymgr_max_key_version_t *versions);
#ifdef __cplusplus
}  // extern "C"
#endif  // __cplusplus

#endif  // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_KEYMGR_H_