Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,17 @@ ifneq ($(USER_NVM_INIT),)
NVM_CONFIG:=$(USER_NVM_INIT)
endif

# Eliminates compilation and linkage of the built-in wolfBoot keystore
WOLFHSM_NO_KEYSTORE :=
ifeq ($(WOLFHSM_CLIENT),1)
WOLFHSM_NO_KEYSTORE := 1
endif
ifeq ($(WOLFHSM_SERVER),1)
ifneq ($(CERT_CHAIN_VERIFY),)
WOLFHSM_NO_KEYSTORE := 1
endif
endif

ifeq ($(SIGN),NONE)
PRIVATE_KEY=
else
Expand All @@ -139,6 +150,8 @@ else
endif
ifeq ($(FLASH_OTP_KEYSTORE),1)
OBJS+=./src/flash_otp_keystore.o
else ifeq ($(WOLFHSM_NO_KEYSTORE),1)
CFLAGS+=-DWOLFBOOT_NO_KEYSTORE
else
OBJS+=./src/keystore.o
endif
Expand Down Expand Up @@ -548,7 +561,7 @@ wolfboot_stage1.bin: wolfboot.elf stage1/loader_stage1.bin
$(Q) cp stage1/loader_stage1.bin wolfboot_stage1.bin

wolfboot.elf: include/target.h $(LSCRIPT) $(OBJS) $(BINASSEMBLE) FORCE
$(Q)(test $(SIGN) = NONE) || (test $(FLASH_OTP_KEYSTORE) = 1) || (grep -q $(SIGN_ALG) src/keystore.c) || \
$(Q)(test $(SIGN) = NONE) || (test $(FLASH_OTP_KEYSTORE) = 1) || (test "$(WOLFHSM_NO_KEYSTORE)" = "1") || (grep -q $(SIGN_ALG) src/keystore.c) || \
(echo "Key mismatch: please run 'make keysclean' to remove all keys if you want to change algorithm" && false)
@echo "\t[LD] $@"
@echo $(OBJS)
Expand Down
10 changes: 3 additions & 7 deletions docs/wolfHSM.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,12 @@ This section describes the configuration options available for wolfHSM integrati

This option enables wolfHSM client support in wolfBoot. Without defining this option, support for wolfHSM client mode is not compiled in.

In client mode, wolfBoot always uses HSM-resident public keys for firmware authentication; public keys are never baked into a local `keystore.c`. The key to verify against is referenced either by the reserved key ID defined in the HAL (`hsmKeyIdPubKey`), or, when certificate-chain verification (`WOLFBOOT_CERT_CHAIN_VERIFY`) is enabled, by the leaf key ID resolved from the verified chain.

### `WOLFBOOT_ENABLE_WOLFHSM_SERVER`

This option enables wolfHSM server support in wolfBoot. When defined, wolfBoot includes an embedded wolfHSM server that provides HSM functionality locally within the bootloader. This is mutually exclusive with `WOLFBOOT_ENABLE_WOLFHSM_CLIENT`.

### `WOLFBOOT_USE_WOLFHSM_PUBKEY_ID`

This option enables use of the reserved wolfHSM public key ID for firmware authentication, and is typically the desired behavior for using wolfHSM. When this option is defined, wolfBoot will use the reserved wolfHSM keyId defined by the HAL (`hsmKeyIdPubKey`). This option is meant to be used in conjunction with the `--nolocalkeys` keygen option, as the key material in the keystore will not be used.

If this option is not defined, cryptographic operations are still performed on the wolfHSM server, but wolfBoot assumes the key material is present in the keystore and NOT stored on the HSM. This means that wolfBoot will first load keys from the keystore, send the key material to the wolfHSM server at the time of use (cached as ephemeral keys), and finally evict the key from the HSM after usage. This behavior is typically only useful for debugging or testing scenarios, where the keys may not be pre-loaded onto the HSM. The keystore for use in this mode should not be generated with the `--nolocalkeys` option.

## HAL Implementations

In addition to the standard wolfBoot HAL functions, wolfHSM-enabled platforms must also implement or instantiate the following wolfHSM-specific items in the platform HAL:
Expand Down Expand Up @@ -126,7 +122,7 @@ The wolfBoot simulator supports using wolfHSM with all algorithms mentioned in [

#### wolfHSM Client Mode Build

To build the simulator configured to use wolfHSM client mode, ensure you build with the `WOLFHSM_CLIENT=1` makefile option. This will automatically define `WOLFBOOT_USE_WOLFHSM_PUBKEY_ID`, and requires the public key corresponding to the private key that signed the image to be pre-loaded into the HSM at the keyId specified by `hsmKeyIdPubKey` in the simulator HAL.
To build the simulator configured to use wolfHSM client mode, ensure you build with the `WOLFHSM_CLIENT=1` makefile option. This requires the public key corresponding to the private key that signed the image to be pre-loaded into the HSM at the keyId specified by `hsmKeyIdPubKey` in the simulator HAL.

```sh
# Grab the HSM client simulator configuration
Expand Down
13 changes: 6 additions & 7 deletions options.mk
Original file line number Diff line number Diff line change
Expand Up @@ -1390,13 +1390,12 @@ ifeq ($(WOLFHSM_CLIENT),1)
# HSM out-of-band
KEYGEN_OPTIONS += --exportpubkey --der

# Default to using public keys on the HSM
ifneq ($(WOLFHSM_CLIENT_LOCAL_KEYS),1)
KEYGEN_OPTIONS += --nolocalkeys
CFLAGS += -DWOLFBOOT_USE_WOLFHSM_PUBKEY_ID
# big enough for cert chain
CFLAGS += -DWOLFHSM_CFG_COMM_DATA_LEN=5000
endif
# wolfHSM clients always use HSM-resident public keys, referenced by key ID or
# authenticated via a certificate chain. Public keys baked into a local
# keystore.c are not supported.
KEYGEN_OPTIONS += --nolocalkeys
# big enough for cert chain
CFLAGS += -DWOLFHSM_CFG_COMM_DATA_LEN=5000

# Ensure wolfHSM is configured to use certificate manager if we are
# doing cert chain verification
Expand Down
78 changes: 38 additions & 40 deletions src/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,8 @@ static void wolfBoot_verify_signature_ecc(uint8_t key_slot,
int ret, verify_res = 0;
ecc_key ecc;
mp_int r, s;
#if (!defined WOLFBOOT_ENABLE_WOLFHSM_CLIENT && \
!defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER)) || \
(defined WOLFBOOT_ENABLE_WOLFHSM_CLIENT && \
!defined(WOLFBOOT_USE_WOLFHSM_PUBKEY_ID))
#if !defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) && \
!defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER)
uint8_t* pubkey = keystore_get_buffer(key_slot);
int pubkey_sz = keystore_get_size(key_slot);
int point_sz = pubkey_sz / 2;
Expand Down Expand Up @@ -251,7 +249,7 @@ static void wolfBoot_verify_signature_ecc(uint8_t key_slot,
uint8_t tmpSigBuf[ECC_MAX_SIG_SIZE] = {0};
size_t tmpSigSz = sizeof(tmpSigBuf);

#if defined(WOLFBOOT_USE_WOLFHSM_PUBKEY_ID) || \
#if defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) || \
(defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER) && \
defined(WOLFBOOT_CERT_CHAIN_VERIFY))
Comment on lines +252 to 254
(void)key_slot;
Expand Down Expand Up @@ -281,11 +279,11 @@ static void wolfBoot_verify_signature_ecc(uint8_t key_slot,
ret = wh_Client_EccSetKeyId(&ecc, hsmKeyIdPubKey);
#endif
}
#else
#else /* WOLFBOOT_CERT_CHAIN_VERIFY */
#if defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT)
ret = wh_Client_EccSetKeyId(&ecc, hsmKeyIdPubKey);
#endif
#endif /* WOLFBOOT_USE_WOLFHSM_PUBKEY_ID */
#endif /* !WOLFBOOT_CERT_CHAIN_VERIFY */
Comment on lines +282 to +286
if (ret != 0) {
return;
}
Expand All @@ -299,7 +297,7 @@ static void wolfBoot_verify_signature_ecc(uint8_t key_slot,
return;
}

#endif /* !WOLFBOOT_USE_WOLFHSM_PUBKEY_ID */
#endif /* WOLFBOOT_ENABLE_WOLFHSM_CLIENT || (SERVER && CERT_CHAIN) */
/* wc_ecc_verify_hash_ex() doesn't trigger a crypto callback, so we need
to use wc_ecc_verify_hash instead. Unfortunately, that requires
converting the signature to intermediate DER format first */
Expand Down Expand Up @@ -436,10 +434,8 @@ static void wolfBoot_verify_signature_rsa_common(uint8_t key_slot,
#endif
#endif /* WOLFBOOT_SIGN_RSAPSS_ANY */

#if (!defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) && \
!defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER)) || \
(defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) && \
!defined(WOLFBOOT_USE_WOLFHSM_PUBKEY_ID))
#if !defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) && \
!defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER)
uint8_t *pubkey = keystore_get_buffer(key_slot);
int pubkey_sz = keystore_get_size(key_slot);

Expand Down Expand Up @@ -472,7 +468,7 @@ static void wolfBoot_verify_signature_rsa_common(uint8_t key_slot,
if (ret != 0) {
return;
}
#if defined(WOLFBOOT_USE_WOLFHSM_PUBKEY_ID) || \
#if defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) || \
(defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER) && \
defined(WOLFBOOT_CERT_CHAIN_VERIFY))
Comment on lines +471 to 473
(void)key_slot;
Expand Down Expand Up @@ -519,7 +515,7 @@ static void wolfBoot_verify_signature_rsa_common(uint8_t key_slot,
wc_FreeRsaKey(&rsa);
return;
}
#endif /* !WOLFBOOT_USE_WOLFHSM_PUBKEY_ID */
#endif /* WOLFBOOT_ENABLE_WOLFHSM_CLIENT || (SERVER && CERT_CHAIN) */
XMEMCPY(output, sig, RSA_IMAGE_SIGNATURE_SIZE);
#ifdef WOLFBOOT_SIGN_RSAPSS_ANY
if (is_pss) {
Expand All @@ -532,14 +528,7 @@ static void wolfBoot_verify_signature_rsa_common(uint8_t key_slot,
RSA_VERIFY_FN(ret, wc_RsaSSL_VerifyInline, output,
RSA_IMAGE_SIGNATURE_SIZE, &digest_out, &rsa);
}
#if defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) && \
!defined(WOLFBOOT_USE_WOLFHSM_PUBKEY_ID)
/* evict the key after use, since we aren't using the RSA import API */
if (WH_ERROR_OK != wh_Client_KeyEvict(&hsmClientCtx, hsmKeyId)) {
wc_FreeRsaKey(&rsa);
return;
}
#elif defined(WOLFBOOT_CERT_CHAIN_VERIFY)
#if defined(WOLFBOOT_CERT_CHAIN_VERIFY)
if (g_leafKeyIdValid) {
#if defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT)
(void)wh_Client_KeyEvict(&hsmClientCtx, g_certLeafKeyId);
Expand All @@ -548,7 +537,7 @@ static void wolfBoot_verify_signature_rsa_common(uint8_t key_slot,
#endif
g_leafKeyIdValid = 0;
}
#endif /* !WOLFBOOT_USE_WOLFHSM_PUBKEY_ID */
#endif /* WOLFBOOT_CERT_CHAIN_VERIFY */
#else
/* wolfCrypt software RSA verify */
ret = wc_InitRsaKey_ex(&rsa, NULL, WOLFBOOT_DEVID_PUBKEY);
Expand Down Expand Up @@ -735,9 +724,7 @@ static void wolfBoot_verify_signature_ml_dsa(uint8_t key_slot,
{
int ret = 0;
wc_MlDsaKey ml_dsa;
#if !defined WOLFBOOT_ENABLE_WOLFHSM_CLIENT || \
(defined WOLFBOOT_ENABLE_WOLFHSM_CLIENT && \
!defined(WOLFBOOT_USE_WOLFHSM_PUBKEY_ID))
#if !defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT)
uint8_t * pubkey = NULL;
int pub_len = 0;
#endif
Expand All @@ -747,9 +734,7 @@ static void wolfBoot_verify_signature_ml_dsa(uint8_t key_slot,
wolfBoot_printf("info: ML-DSA %d verify_signature: pubkey %d, sig %d\n",
ML_DSA_LEVEL, KEYSTORE_PUBKEY_SIZE, ML_DSA_IMAGE_SIGNATURE_SIZE);

#if !defined WOLFBOOT_ENABLE_WOLFHSM_CLIENT || \
(defined WOLFBOOT_ENABLE_WOLFHSM_CLIENT && \
!defined(WOLFBOOT_USE_WOLFHSM_PUBKEY_ID))
#if !defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT)
pubkey = keystore_get_buffer(key_slot);

if (pubkey == NULL) {
Expand All @@ -774,8 +759,7 @@ static void wolfBoot_verify_signature_ml_dsa(uint8_t key_slot,
}
}

#if defined WOLFBOOT_ENABLE_WOLFHSM_CLIENT && \
defined(WOLFBOOT_USE_WOLFHSM_PUBKEY_ID)
#if defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT)
/* Use key slot ID directly with wolfHSM */
#if defined(WOLFBOOT_CERT_CHAIN_VERIFY)
/* If using certificate chain verification and we have a verified leaf key
Expand Down Expand Up @@ -820,8 +804,7 @@ static void wolfBoot_verify_signature_ml_dsa(uint8_t key_slot,
ret);
}
}
#endif /* !defined WOLFBOOT_ENABLE_WOLFHSM_CLIENT &&
!defined(WOLFBOOT_USE_WOLFHSM_PUBKEY_ID) */
#endif /* WOLFBOOT_ENABLE_WOLFHSM_CLIENT */


/* Make sure sig len matches parameters. */
Expand Down Expand Up @@ -1076,7 +1059,7 @@ static int image_sha256(struct wolfBoot_image *img, uint8_t *hash)
return 0;
}

#ifndef WOLFBOOT_NO_SIGN
#if !defined(WOLFBOOT_NO_SIGN) && !defined(WOLFBOOT_NO_KEYSTORE)

/**
* @brief Calculate the SHA256 hash of the key.
Expand Down Expand Up @@ -1187,7 +1170,7 @@ static int image_sha384(struct wolfBoot_image *img, uint8_t *hash)
return 0;
}

#ifndef WOLFBOOT_NO_SIGN
#if !defined(WOLFBOOT_NO_SIGN) && !defined(WOLFBOOT_NO_KEYSTORE)

/**
* @brief Calculate SHA-384 hash of a public key in the keystore.
Expand Down Expand Up @@ -1303,7 +1286,7 @@ static int image_sha3_384(struct wolfBoot_image *img, uint8_t *hash)
wc_Sha3_384_Free(&sha3_ctx);
return 0;
}
#ifndef WOLFBOOT_NO_SIGN
#if !defined(WOLFBOOT_NO_SIGN) && !defined(WOLFBOOT_NO_KEYSTORE)

/**
* @brief Calculate SHA3-384 hash of a public key in the keystore.
Expand Down Expand Up @@ -2267,10 +2250,14 @@ int wolfBoot_verify_authenticity(struct wolfBoot_image *img)
}
key_slot = 0;

#elif defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) && \
defined(WOLFBOOT_USE_WOLFHSM_PUBKEY_ID)
#elif defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT)
/* Don't care about the key slot, we are using a fixed wolfHSM keyId */
key_slot = 0;
#elif defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER) && \
defined(WOLFBOOT_CERT_CHAIN_VERIFY)
/* Don't care about the key slot, we are using the public key from the
* leaf cert */
key_slot = 0;
#else
key_slot = keyslot_id_by_sha(pubkey_hint);
if (key_slot < 0) {
Expand Down Expand Up @@ -2298,15 +2285,25 @@ int wolfBoot_verify_authenticity(struct wolfBoot_image *img)
return -1;
img->sha_hash = digest;
}
key_mask = keystore_get_mask(key_slot);
image_part = image_type & HDR_IMG_TYPE_PART_MASK;
#ifdef WOLFBOOT_NO_KEYSTORE
/* No local keystore is linked: there is no per-key partition permission
* mask to consult. Key authorization and usage are enforced by the HSM
* (cert-chain root-of-trust plus per-key usage flags), so the wolfBoot
* keystore mask check does not apply here. */
(void)key_slot;
(void)key_mask;
(void)image_part;
#else
key_mask = keystore_get_mask(key_slot);

/* Check if the key permission mask matches the current partition id */
if (((1U << image_part) & key_mask) != (1U << image_part)) {
return -1; /* Key not allowed to verify this partition id */
}

CONFIRM_MASK_VALID(image_part, key_mask);
#endif

#if defined(WOLFBOOT_CERT_CHAIN_VERIFY) && \
(defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) || \
Expand Down Expand Up @@ -2510,7 +2507,8 @@ uint8_t* wolfBoot_peek_image(struct wolfBoot_image *img, uint32_t offset,
return p;
}

#if !defined(WOLFBOOT_NO_SIGN) && !defined(WOLFBOOT_RENESAS_SCEPROTECT)
#if !defined(WOLFBOOT_NO_SIGN) && !defined(WOLFBOOT_RENESAS_SCEPROTECT) && \
!defined(WOLFBOOT_NO_KEYSTORE)

/* Compare fixed-size key hints without early exit to avoid leaking hash prefix
* matches through lookup timing. */
Expand Down
Loading