Add hardware-based DICE on mcxn

pull/785/head
Yosuke Shimizu 2026-04-27 14:31:38 +09:00 committed by Daniele Lacamera
parent b983fa7717
commit f4d5340641
20 changed files with 1357 additions and 34 deletions

View File

@ -273,6 +273,20 @@ jobs:
config-file: ./config/examples/mcxn-wolfcrypt-tz.config
board-name: frdmmcxn947
nxp_mcxn_tz_psa_test:
uses: ./.github/workflows/test-build-mcux-sdk-manifests.yml
with:
arch: arm
config-file: ./config/examples/mcxn-tz-psa.config
board-name: frdmmcxn947
nxp_mcxn_tz_psa_hw_test:
uses: ./.github/workflows/test-build-mcux-sdk-manifests.yml
with:
arch: arm
config-file: ./config/examples/mcxn-tz-psa-hw.config
board-name: frdmmcxn947
nxp_s32k142_test:
uses: ./.github/workflows/test-build.yml
with:

17
arch.mk
View File

@ -974,6 +974,23 @@ ifeq ($(TARGET),mcxn)
$(MCUXPRESSO)/drivers/lpuart/fsl_lpuart.o \
$(MCUXPRESSO_DRIVERS)/drivers/fsl_reset.o
endif
# Link ELS PKC only when -DWOLFBOOT_DICE_HW is emitted (WOLFCRYPT_TZ_PSA=1 in options.mk).
ifeq ($(WOLFCRYPT_TZ_PSA),1)
ifeq ($(WOLFBOOT_DICE_HW),1)
ELS_PKC=$(MCUXPRESSO)/components/els_pkc
CFLAGS+=\
-I$(ELS_PKC)/includes \
-I$(ELS_PKC)/src/comps/mcuxClEls/inc \
-I$(ELS_PKC)/src/platforms/mcxn \
-I$(ELS_PKC)/src/platforms/mcxn/inc
OBJS+=\
$(ELS_PKC)/src/comps/mcuxClEls/src/mcuxClEls_Common.o \
$(ELS_PKC)/src/comps/mcuxClEls/src/mcuxClEls_Kdf.o \
$(ELS_PKC)/src/comps/mcuxClEls/src/mcuxClEls_KeyManagement.o \
$(ELS_PKC)/src/comps/mcuxClEls/src/mcuxClEls_Ecc.o
endif
endif
endif
ifeq ($(TARGET),nrf5340)

View File

@ -0,0 +1,50 @@
ARCH?=ARM
TZEN?=1
TARGET?=mcxn
SIGN?=ECC384
HASH?=SHA384
MCUXSDK?=1
MCUXPRESSO?=$(PWD)/../NXP/mcuxpresso-sdk/mcuxsdk
MCUXPRESSO_CMSIS?=$(PWD)/../NXP/CMSIS_5/CMSIS
MCUXPRESSO_CPU?=MCXN947VDF_cm33_core0
MCUXPRESSO_DRIVERS?=$(MCUXPRESSO)/devices/MCX/MCXN/MCXN947
MCUXPRESSO_PROJECT_TEMPLATE?=$(MCUXPRESSO)/examples/_boards/frdmmcxn947/project_template
DEBUG?=0
DEBUG_UART?=1
VTOR?=1
CORTEX_M0?=0
CORTEX_M33?=1
NO_ASM?=0
NO_MPU=1
EXT_FLASH?=0
SPI_FLASH?=0
ALLOW_DOWNGRADE?=0
NVM_FLASH_WRITEONCE?=1
NO_ARM_ASM=1
WOLFBOOT_VERSION?=0
V?=0
SPMATH?=1
RAM_CODE?=1
DUALBANK_SWAP?=0
PKA?=1
WOLFCRYPT_TZ?=1
WOLFCRYPT_TZ_PSA?=1
WOLFCRYPT_SECURE_MODE?=1
WOLFBOOT_DICE_HW?=1
IMAGE_HEADER_SIZE?=1024
WOLFBOOT_ATTESTATION_TEST?=1
WOLFBOOT_UDS_UID_FALLBACK_FORTEST?=0
# 8KB sectors
WOLFBOOT_SECTOR_SIZE?=0x2000
# Default configuration
# 192KB boot, 96KB keyvault, 8KB NSC, 72KB partitions, 8KB swap
WOLFBOOT_KEYVAULT_ADDRESS?=0x30000
WOLFBOOT_KEYVAULT_SIZE?=0x18000
WOLFBOOT_NSC_ADDRESS?=0x48000
WOLFBOOT_NSC_SIZE?=0x2000
WOLFBOOT_PARTITION_SIZE?=0x12000
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x60000
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x72000
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x84000

View File

@ -0,0 +1,50 @@
ARCH?=ARM
TZEN?=1
TARGET?=mcxn
SIGN?=ECC384
HASH?=SHA384
MCUXSDK?=1
MCUXPRESSO?=$(PWD)/../NXP/mcuxpresso-sdk/mcuxsdk
MCUXPRESSO_CMSIS?=$(PWD)/../NXP/CMSIS_5/CMSIS
MCUXPRESSO_CPU?=MCXN947VDF_cm33_core0
MCUXPRESSO_DRIVERS?=$(MCUXPRESSO)/devices/MCX/MCXN/MCXN947
MCUXPRESSO_PROJECT_TEMPLATE?=$(MCUXPRESSO)/examples/_boards/frdmmcxn947/project_template
DEBUG?=0
DEBUG_UART?=1
VTOR?=1
CORTEX_M0?=0
CORTEX_M33?=1
NO_ASM?=0
NO_MPU=1
EXT_FLASH?=0
SPI_FLASH?=0
ALLOW_DOWNGRADE?=0
NVM_FLASH_WRITEONCE?=1
NO_ARM_ASM=1
WOLFBOOT_VERSION?=0
V?=0
SPMATH?=1
RAM_CODE?=1
DUALBANK_SWAP?=0
PKA?=1
WOLFCRYPT_TZ?=1
WOLFCRYPT_TZ_PSA?=1
WOLFCRYPT_SECURE_MODE?=1
WOLFBOOT_DICE_HW?=0
IMAGE_HEADER_SIZE?=1024
WOLFBOOT_ATTESTATION_TEST?=1
WOLFBOOT_UDS_UID_FALLBACK_FORTEST?=1
# 8KB sectors
WOLFBOOT_SECTOR_SIZE?=0x2000
# Default configuration
# 192KB boot, 96KB keyvault, 8KB NSC, 72KB partitions, 8KB swap
WOLFBOOT_KEYVAULT_ADDRESS?=0x30000
WOLFBOOT_KEYVAULT_SIZE?=0x18000
WOLFBOOT_NSC_ADDRESS?=0x48000
WOLFBOOT_NSC_SIZE?=0x2000
WOLFBOOT_PARTITION_SIZE?=0x12000
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x60000
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x72000
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x84000

View File

@ -34,7 +34,7 @@ measurement value, and a description string.
## Keying model
wolfBoot supports two keying modes selected at build time.
wolfBoot supports three keying modes selected at build time.
### DICE derived key (default for no provisioning)
@ -55,6 +55,17 @@ The attestation service calls `hal_attestation_get_iak_private_key()` to
retrieve the private key material from secure storage (or a manufacturer
injection flow). The IAK is used instead of the DICE derived key.
### Hardware-based DICE derived key
Some platforms have secure subsystem which supports hardware engines for DICE functionality.
Some of them don't expose the secrets like UDS, CDI and attestation key.
In that case, You can enable hardware-based DICE using `WOLFBOOT_DICE_HW` option.
wolfBoot calls `hal_dice_update_cdi()` to update CDI inside secure subsystem for each component.
Also, `hal_dice_create_attest_key()` is called to derive the attestation key from updated CDI as well.
Then, wolfBoot uses `hal_dice_sign_hash` to sign the token.
User can implement hardware-specific procedures inside the hooks.
## HAL integration (per-target)
These HAL hooks are optional and have weak stubs for non-TZ boards. Target
@ -76,6 +87,21 @@ families must implement the appropriate subset based on hardware support.
- `hal_attestation_get_iak_private_key(uint8_t *buf, size_t *len)`
- Optional provisioned IAK private key (used in IAK mode only).
If you enable hardware-based DICE, additional hooks are necessary.
- `hal_dice_update_cdi(const uint8_t *measurement, size_t meas_len, const char *measurement_desc, size_t measurement_desc_len)`
- Mixes one boot-component measurement into the platform CDI chain.
- measurement_desc identifies the component (e.g. "wolfboot", "boot-image").
- `hal_dice_create_attest_key(void)`
- Derive and store the attestation key pair from the current CDI state.
- The private key must not be exposed outside the platform security boundary.
- `hal_dice_sign_hash(const uint8_t *hash, size_t hash_len, uint8_t *sig, size_t *sig_len)`
- Sign a pre-computed SHA-256 hash with the platform private attestation key during token generation.
- Output: 64-byte raw R||S (big-endian), same format as wolfCrypt ES256.
- `hal_dice_get_attest_pubkey(uint8_t *buf, size_t *len)`
- Optional hook to get the public part of attestation key.
- This is called via PSA Initial Attestation dispatch `psa_initial_attest_get_iak_pubkey()`.
## STM32H5 OBKeys UDS (optional)
STM32H5 devices provide OBKeys secure storage areas tied to temporal isolation
@ -103,6 +129,7 @@ The non-secure application calls the PSA Initial Attestation API wrappers:
- `psa_initial_attest_get_token_size()`
- `psa_initial_attest_get_token()`
- `psa_initial_attest_get_iak_pubkey()`
These are provided in `zephyr/include/psa/initial_attestation.h` and are
implemented as NSC calls in `zephyr/src/arm_tee_attest_api.c`.
@ -114,9 +141,15 @@ When `WOLFCRYPT_TZ_PSA=1`, the NS application can also use PSA Crypto through
## Test application
### STM32H5
The STM32H5 TrustZone test application in `test-app/` exercises PSA crypto,
attestation, and store access. It requests a token at boot and can perform
PSA crypto operations from the non-secure side.
See `docs/Targets.md` for the STM32H5 TrustZone scenarios and how to enable
PSA mode.
### MCXN
MCXN has TrustZone test application in `test-app/` exercises PSA attestation.
Default setting is based on hardware secure subsystem called EdgeLock Secure Subsystem.
See `docs/Targets.md` and `docs/MCXN947-DICE.md` for details.

View File

@ -0,0 +1,79 @@
# DICE attestation sample on MCXN947
General concept of wolfBoot in TrustZone secure domain is explained in `docs/STM32-TZ.md`.
This focuses on a sample of PSA initial attestation for MCXN947.
Sample application is implemented in `test-app/app_mcxn.c`.
This supports hardware-based DICE using EdgeLock Secure Subsystem.
## How to build
Please use `config/examples/mcxn-tz-psa-hw.config` to build wolfBoot.
You need to update the path of SDK inside the config for your build environment.
```
cp config/examples/mcxn-tz-psa-hw.config .config
make
```
## How to run
MCXN947 requires us to enable secure boot to use DICE functionality of ELS.
So, We need to prepare the specific image file of wolfBoot binary and configuration files of CMPA/CFPA for secure bootROM and ELS.
Fortunately NXP provides the [secure provisioning tool](https://www.nxp.com/design/design-center/software/development-software/mcuxpresso-software-and-tools-/mcuxpresso-secure-provisioning-tool:MCUXPRESSO-SECURE-PROVISIONING) for such purpose.
At a minimum, you shall configure the following settings and encode the image with signature:
- Enable Image verification for secure boot (SEC_BOOT_EN == 0b10)
- Enable DICE (SKIP_DICE == 0b0)
All of these can be done using the NXP secure provisioning tool.
If you use secure provisioning tool, you can download the prepared image with configuration files to hardware as well.
Regarding to application image like image_v1_signed.bin, we don't need to encode it like the wolfBoot binary because it's verified by wolfBoot as usual.
But, we still recommend you to download the application image using the flash programmer tool in the secure provisioning tool for a safe download. You can access it via `Tools > Flash Programmer` on GUI.
Once both images are downloaded successfully, you'll see the log after reboot:
```
Boot partition: 0x60000 (sz 31508, ver 0x1, type 0x601)
Partition 1 header magic 0xFFFFFFFF invalid at 0x72000
Boot partition: 0x60000 (sz 31508, ver 0x1, type 0x601)
Booting version: 0x1
Checking integrity...done
Verifying signature...done
Hello from firmware version 1
Today's lucky number: 0xAF
PSA crypto init ok
Start attestation verify test
[ATTEST] GET_TOKEN: challenge_len=32 out_len=1024
Boot partition: 0x60000 (sz 31508, ver 0x1, type 0x601)
Boot partition: 0x60000 (sz 31508, ver 0x1, type 0x601)
[ATTEST] GET_TOKEN: dice_rc=0 token_len=356
attest_verify: token_len=356
84 43 A1 01 26 A0 59 01 19 A5 0A 58 20 01 02 03 | .C..&.Y....X ...
04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 | ................
14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 19 01 00 | ............ ...
58 21 01 AD 74 46 22 0C D0 5B 7A 1B 33 5E 37 28 | X!..tF"..[z.3^7(
0A 54 E6 DF 55 5B 40 A4 57 A0 43 0A 6D A5 AB E7 | .T..U[@.W.C.m...
5A 2B 5F 19 09 5C 58 30 E4 F9 83 72 7F A9 C5 CE | Z+_..\X0...r....
DD E0 79 A0 AD 0E 32 59 0A EA D3 10 43 BA 12 DD | ..y...2Y....C...
76 47 59 D1 42 8B 3A 75 F2 7E 75 CF 7D EE A2 B9 | vGY.B.:u.~u.}...
AA AB 7E E9 91 27 F7 21 19 09 5E 19 30 00 19 09 | ..~..'.!..^.0...
5F 82 A3 01 67 73 68 61 2D 33 38 34 02 58 30 E4 | _...gsha-384.X0.
F9 83 72 7F A9 C5 CE DD E0 79 A0 AD 0E 32 59 0A | ..r......y...2Y.
EA D3 10 43 BA 12 DD 76 47 59 D1 42 8B 3A 75 F2 | ...C...vGY.B.:u.
7E 75 CF 7D EE A2 B9 AA AB 7E E9 91 27 F7 21 05 | ~u.}.....~..'.!.
68 77 6F 6C 66 62 6F 6F 74 A3 01 67 73 68 61 2D | hwolfboot..gsha-
33 38 34 02 58 30 D4 F2 89 AD E4 4E 6E EB F4 C6 | 384.X0.....Nn...
7D 24 13 AD 6C E6 DC A6 E9 FC 67 4F CC CB DE 52 | }$..l.....gO...R
4D FD E2 73 9D 2A D7 B3 DD DF B8 51 F4 43 C5 59 | M..s.*.....Q.C.Y
48 8A 30 46 D7 E3 05 6A 62 6F 6F 74 2D 69 6D 61 | H.0F...jboot-ima
67 65 58 40 E8 3F 76 44 15 7C 62 76 33 56 6D F7 | geX@.?vD.|bv3Vm.
2B E1 57 40 C4 F1 7D 21 D3 E9 90 57 25 8F A3 14 | +.W@..}!...W%...
44 ED 1B CE 01 CA EF 52 6B 41 4C 44 DF 4E 04 D4 | D......RkALD.N..
AA CC A8 7F 20 3D AA 39 CA 3A 9F C2 B1 C0 28 43 | .... =.9.:....(C
DF BB 82 53 | ...S
[ATTEST] GET_IAK_PUBKEY: out_len=65
[ATTEST] GET_IAK_PUBKEY: dice_rc=0 key_len=65
attest_verify: IAK pubkey (65 bytes):
04 42 9B 43 75 BE B0 E9 A0 39 61 64 68 20 1E FC | .B.Cu....9adh ..
B6 68 F4 3E 25 74 F1 E2 CB 3D BD 09 A6 45 A7 E2 | .h.>%t...=...E..
6F E1 54 B8 20 61 96 79 6A E8 31 83 3A 82 DE 1C | o.T. a.yj.1.:...
87 46 E1 45 49 3D 6F 56 78 F4 14 B6 42 47 DD F1 | .F.EI=oVx...BG..
AC | .
attest_verify: IAK signature verified OK
```

View File

@ -6107,6 +6107,9 @@ mon reset
c
```
### MCX N: DICE attestation
Sample application for DICE attestation is available on MCXN947.
Please find the details in `docs/MCXN947-DICE.md`.
## NXP S32K1XX

View File

@ -321,3 +321,38 @@ WEAKFUNCTION int hal_attestation_get_iak_private_key(uint8_t *buf, size_t *len)
(void)len;
return -1;
}
#ifdef WOLFBOOT_DICE_HW
WEAKFUNCTION int hal_dice_update_cdi(const uint8_t *measurement, size_t meas_len,
const char *measurement_desc,
size_t measurement_desc_len)
{
(void)measurement;
(void)meas_len;
(void)measurement_desc;
(void)measurement_desc_len;
return -1;
}
WEAKFUNCTION int hal_dice_create_attest_key(void)
{
return -1;
}
WEAKFUNCTION int hal_dice_sign_hash(const uint8_t *hash, size_t hash_len,
uint8_t *sig, size_t *sig_len)
{
(void)hash;
(void)hash_len;
(void)sig;
(void)sig_len;
return -1;
}
WEAKFUNCTION int hal_dice_get_attest_pubkey(uint8_t *buf, size_t *len)
{
(void)buf;
(void)len;
return -1;
}
#endif /* WOLFBOOT_DICE_HW */

View File

@ -40,6 +40,112 @@
#include "hal/armv8m_tz.h"
#endif
#if defined(WOLFCRYPT_TZ_PSA)
/* 128-bit device UUID in IPC 1 (SYSCON UUID block) */
#define MCXN_UUID_ADDR 0x01100000U
#endif
#if defined(WOLFCRYPT_TZ_PSA) && defined(WOLFBOOT_DICE_HW)
#include "wolfboot/dice.h"
#include "mcuxClEls.h"
#include "mcuxClEls_Kdf.h"
#include "mcuxClEls_Ecc.h"
#include "mcuxClEls_KeyManagement.h"
#include "mcuxCsslFlowProtection.h"
#include <wolfssl/wolfcrypt/sha256.h>
/* Key slot pre-loaded by ROM DICE: HKDF(UDS, wolfBoot_hash) -> initial CDI. */
#define MCXN_ELS_DICE_CDI_INITIAL_KEYSLOT 7U
/* wolfBoot stores the boot-measurement-derived CDI here. */
#define MCXN_ELS_DICE_CDI_DERIVED_KEYSLOT 11U
/* wolfBoot stores the per-boot IAK (P-256) here.
* ELS EccKeyGen DETERMINISTIC mode uses privateKeyIdx as both the CDI seed
* source and the IAK output slot, so the IAK overwrites the CDI in-place. */
#define MCXN_ELS_DICE_IAK_KEYSLOT MCXN_ELS_DICE_CDI_DERIVED_KEYSLOT
#endif
#if defined(WOLFCRYPT_TZ_PSA) && !defined(WOLFBOOT_DICE_HW)
#include <wolfssl/wolfcrypt/sha256.h>
#include <wolfssl/wolfcrypt/sha512.h>
/* Derive UDS from device UUID for software DICE testing.
* NOT secure — UUID is publicly observable. Only enabled with
* WOLFBOOT_UDS_UID_FALLBACK_FORTEST. */
int hal_uds_derive_key(uint8_t *out, size_t out_len)
{
volatile const uint32_t *uuid_addr =
(volatile const uint32_t *)MCXN_UUID_ADDR;
uint8_t uuid_be[16];
uint32_t word;
int i;
#if defined(WOLFBOOT_HASH_SHA384)
wc_Sha384 hash;
uint8_t digest[SHA384_DIGEST_SIZE];
size_t copy_len = sizeof(digest);
#elif defined(WOLFBOOT_HASH_SHA256)
wc_Sha256 hash;
uint8_t digest[SHA256_DIGEST_SIZE];
size_t copy_len = sizeof(digest);
#else
(void)out; (void)out_len;
return -1;
#endif
if (out == NULL || out_len == 0)
return -1;
#ifndef WOLFBOOT_UDS_UID_FALLBACK_FORTEST
(void)uuid_addr; (void)uuid_be; (void)word; (void)i;
#if defined(WOLFBOOT_HASH_SHA384) || defined(WOLFBOOT_HASH_SHA256)
(void)hash; (void)digest; (void)copy_len;
#endif
return -1;
#else
for (i = 0; i < 4; i++) {
word = uuid_addr[i];
uuid_be[i * 4 + 0] = (uint8_t)(word >> 24);
uuid_be[i * 4 + 1] = (uint8_t)(word >> 16);
uuid_be[i * 4 + 2] = (uint8_t)(word >> 8);
uuid_be[i * 4 + 3] = (uint8_t)(word);
}
#if defined(WOLFBOOT_HASH_SHA384)
{
int ret = wc_InitSha384(&hash);
if (ret == 0) {
ret = wc_Sha384Update(&hash, uuid_be, sizeof(uuid_be));
if (ret == 0)
ret = wc_Sha384Final(&hash, digest);
wc_Sha384Free(&hash);
}
if (ret != 0)
return -1;
}
#elif defined(WOLFBOOT_HASH_SHA256)
{
int ret = wc_InitSha256(&hash);
if (ret == 0) {
ret = wc_Sha256Update(&hash, uuid_be, sizeof(uuid_be));
if (ret == 0)
ret = wc_Sha256Final(&hash, digest);
wc_Sha256Free(&hash);
}
if (ret != 0)
return -1;
}
#endif
if (copy_len > out_len)
copy_len = out_len;
XMEMCPY(out, digest, copy_len);
return 0;
#endif /* WOLFBOOT_UDS_UID_FALLBACK_FORTEST */
}
#endif /* WOLFCRYPT_TZ_PSA && !WOLFBOOT_DICE_HW */
#ifdef WOLFCRYPT_SECURE_MODE
void hal_trng_init(void);
int hal_trng_get_entropy(unsigned char *out, unsigned int len);
@ -212,7 +318,7 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
return 0;
}
#ifdef WOLFCRYPT_SECURE_MODE
#if defined(WOLFCRYPT_SECURE_MODE) && !defined(NONSECURE_APP)
#define ELS_CMD_RND_REQ 24U
void hal_trng_init(void)
@ -383,3 +489,468 @@ void uart_write(const char *buf, unsigned int sz)
sz -= line_sz + 1U;
}
}
#if defined(WOLFCRYPT_TZ_PSA) && defined(WOLFBOOT_DICE_HW) && defined(__WOLFBOOT)
/* Holds the raw 64-byte P-256 public key (X||Y) written by hal_dice_create_attest_key().
* Consumed and zeroized by hal_dice_get_attest_pubkey(). */
static uint8_t s_dice_attest_pubkey[64];
static int s_dice_attest_pubkey_valid = 0;
static NOINLINEFUNCTION void hal_dice_zeroize(void *ptr, size_t len)
{
volatile uint8_t *p = (volatile uint8_t *)ptr;
while (len-- > 0U) {
*p++ = 0U;
}
}
/* Derive 33-byte UEID from device UUID at IPC1 (MCXN_UUID_ADDR).
* UUID (16 bytes, big-endian) is SHA-256 hashed to produce a 32-byte
* opaque identifier. This matches WOLFBOOT_DICE_UEID_LEN = 33.
* We can't use UDS because NXP_DIE_DICE_UDS_MK_SK is not accessible,
* so we derive UEID from the UUID instead. */
int hal_attestation_get_ueid(uint8_t *buf, size_t *len)
{
volatile const uint32_t *uuid_addr =
(volatile const uint32_t *)MCXN_UUID_ADDR;
uint8_t uuid_be[16];
uint32_t word;
wc_Sha256 sha;
int i, ret = 0;
if (buf == NULL || len == NULL || *len < 33)
ret = -1;
if (ret == 0) {
/* Read 4 words (16 bytes) and convert each to big-endian */
for (i = 0; i < 4; i++) {
word = uuid_addr[i];
uuid_be[i * 4 + 0] = (uint8_t)(word >> 24);
uuid_be[i * 4 + 1] = (uint8_t)(word >> 16);
uuid_be[i * 4 + 2] = (uint8_t)(word >> 8);
uuid_be[i * 4 + 3] = (uint8_t)(word);
}
#ifdef DEBUG
wolfBoot_printf("[DICE] UUID:");
for (i = 0; i < (int)sizeof(uuid_be); i++)
wolfBoot_printf(" %02x", uuid_be[i]);
wolfBoot_printf("\r\n");
#endif
/* SHA-256(UUID) -> 32-byte UEID payload */
ret = wc_InitSha256(&sha);
if (ret == 0) {
ret = wc_Sha256Update(&sha, uuid_be, sizeof(uuid_be));
if (ret == 0)
ret = wc_Sha256Final(&sha, &buf[1]);
wc_Sha256Free(&sha);
}
if (ret == 0) {
/* UEID Type RANDOM per EAT spec */
buf[0] = 0x01;
*len = 33; /* WOLFBOOT_DICE_UEID_LEN */
#ifdef DEBUG
wolfBoot_printf("[DICE] UEID:");
for (i = 0; i < 33; i++)
wolfBoot_printf(" %02x", buf[i]);
wolfBoot_printf("\r\n");
#endif
}
}
XMEMSET(uuid_be, 0, sizeof(uuid_be));
return ret;
}
int hal_attestation_get_lifecycle(uint32_t *lifecycle)
{
if (lifecycle == NULL)
return -1;
*lifecycle = 0x3000u; /* PSA_LIFECYCLE_SECURED (default) */
return 0;
}
/* Counts actual hardware CDI derivations performed (wolfBoot is always skipped).
* Shared with hal_dice_create_attest_key so it can reset after each complete sequence. */
static int cdi_derivation_count = 0;
/* Derive new CDI from measurement and previous CDI */
int hal_dice_update_cdi(const uint8_t *measurement, size_t meas_len,
const char *measurement_desc, size_t measurement_desc_len)
{
uint8_t deriv[MCUXCLELS_HKDF_RFC5869_DERIVATIONDATA_SIZE];
_Static_assert(MCUXCLELS_HKDF_RFC5869_DERIVATIONDATA_SIZE >= SHA256_DIGEST_SIZE,
"MCUXCLELS_HKDF_RFC5869_DERIVATIONDATA_SIZE must be at least SHA256_DIGEST_SIZE");
mcuxClEls_HkdfOption_t opts = {0};
mcuxClEls_KeyProp_t props = {0};
int ret = 0;
#ifdef DEBUG
wolfBoot_printf("[DICE] update_cdi: derivation_count=%d meas_len=%u\r\n",
cdi_derivation_count, (unsigned)meas_len);
#endif
XMEMSET(deriv, 0, sizeof(deriv));
/* ROM DICE already incorporated wolfBoot as HKDF(UDS, wolfBoot_hash) -> initial_CDI.
* Skip re-applying it — doing so would produce the wrong CDI chain. */
if (measurement_desc != NULL &&
measurement_desc_len == (sizeof(WOLFBOOT_DICE_COMPONENT_WOLFBOOT) - 1) &&
XMEMCMP(measurement_desc, WOLFBOOT_DICE_COMPONENT_WOLFBOOT, measurement_desc_len) == 0) {
#ifdef DEBUG
wolfBoot_printf("[DICE] update_cdi: skipping wolfboot component (ROM already applied)\r\n");
#endif
return 0;
}
if (cdi_derivation_count > 0) {
/* Key-slot constraint: only 1 derived CDI slot available.
* Raise this limit only after adding extra slots. */
#ifdef DEBUG
wolfBoot_printf("[DICE] update_cdi: cdi_derivation_count=%d > 0, too many components\r\n",
cdi_derivation_count);
#endif
/* Do not return here: the shared epilogue resets cdi_derivation_count on error
* (same as other failure paths). This branch issues no ELS commands; any key
* material in the derived CDI slot is unchanged from the prior successful HKDF.
* After the epilogue, the next successful call KDELETEs that slot then HKDFs
* from the ROM initial CDI slot (count is zero again — fresh chain). */
ret = -1;
}
if (ret == 0 && (measurement == NULL || meas_len == 0)) {
#ifdef DEBUG
wolfBoot_printf("[DICE] update_cdi: invalid measurement (NULL or zero len)\r\n");
#endif
ret = -1;
}
if (ret == 0) {
if (meas_len > SHA256_DIGEST_SIZE) {
/* Pre-hash to SHA-256 digest */
wc_Sha256 sha;
ret = wc_InitSha256(&sha);
if (ret == 0) {
ret = wc_Sha256Update(&sha, measurement, (word32)meas_len);
if (ret == 0) {
ret = wc_Sha256Final(&sha, deriv);
}
wc_Sha256Free(&sha);
}
#ifdef DEBUG
if (ret != 0)
wolfBoot_printf("[DICE] update_cdi: wc_Sha256 failed %d\r\n", ret);
#endif
}
else {
XMEMCPY(deriv, measurement, meas_len);
}
}
if (ret == 0) {
/* Trigger the KDELETE command to free the key slot.
* Note that the slot may be empty on the first update, but that's not an error
* because ELS ignores the KDELETE command if the slot is empty.
* We just give the names of token and return value
* since it's declared within the macro */
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(res_kdel, tok_kdel,
mcuxClEls_KeyDelete_Async(MCXN_ELS_DICE_CDI_DERIVED_KEYSLOT));
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_KeyDelete_Async) != tok_kdel) ||
(MCUXCLELS_STATUS_OK_WAIT != res_kdel)) {
#ifdef DEBUG
wolfBoot_printf("[DICE] update_cdi: KeyDelete_Async failed"
" res=0x%x tok=0x%x\r\n",
(unsigned)res_kdel, (unsigned)tok_kdel);
#endif
ret = -1;
}
MCUX_CSSL_FP_FUNCTION_CALL_END();
/* Wait for hardware to finish */
if (ret == 0) {
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(res_w, tok_w,
mcuxClEls_WaitForOperation(MCUXCLELS_ERROR_FLAGS_CLEAR));
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_WaitForOperation) != tok_w) ||
(MCUXCLELS_STATUS_OK != res_w)) {
#ifdef DEBUG
wolfBoot_printf("[DICE] update_cdi: WaitForOperation(KDELETE) failed"
" res=0x%x tok=0x%x\r\n",
(unsigned)res_w, (unsigned)tok_w);
#endif
ret = -1;
}
MCUX_CSSL_FP_FUNCTION_CALL_END();
}
}
if (ret == 0) {
/* first derivation: start from ROM-loaded initial CDI; subsequent: chain from derived CDI */
mcuxClEls_KeyIndex_t hkdf_src_slot = (cdi_derivation_count == 0)
? MCXN_ELS_DICE_CDI_INITIAL_KEYSLOT
: MCXN_ELS_DICE_CDI_DERIVED_KEYSLOT;
/* Set HKDF options */
opts.bits.hkdf_algo = MCUXCLELS_HKDF_ALGO_RFC5869;
/* Set key properties */
props.bits.upprot_priv = MCUXCLELS_KEYPROPERTY_PRIVILEGED_TRUE;
props.bits.upprot_sec = MCUXCLELS_KEYPROPERTY_SECURE_TRUE;
props.bits.ukgsrc = MCUXCLELS_KEYPROPERTY_INPUT_FOR_ECC_TRUE;
props.bits.uhkdf = MCUXCLELS_KEYPROPERTY_HKDF_TRUE;
props.bits.fgp = MCUXCLELS_KEYPROPERTY_GENERAL_PURPOSE_SLOT_TRUE;
props.bits.kbase = MCUXCLELS_KEYPROPERTY_BASE_SLOT;
props.bits.kactv = MCUXCLELS_KEYPROPERTY_ACTIVE_TRUE;
props.bits.ksize = MCUXCLELS_KEYPROPERTY_KEY_SIZE_256;
/* Trigger the HKDF command.
* We just give the names of token and return value
* since it's declared within the macro */
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(res_hkdf, tok_hkdf,
mcuxClEls_Hkdf_Rfc5869_Async(opts,
hkdf_src_slot,
MCXN_ELS_DICE_CDI_DERIVED_KEYSLOT,
props, deriv));
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_Hkdf_Rfc5869_Async) != tok_hkdf) ||
(MCUXCLELS_STATUS_OK_WAIT != res_hkdf)) {
#ifdef DEBUG
wolfBoot_printf("[DICE] update_cdi: Hkdf_Rfc5869_Async failed"
" res=0x%x tok=0x%x\r\n",
(unsigned)res_hkdf, (unsigned)tok_hkdf);
#endif
ret = -1;
}
MCUX_CSSL_FP_FUNCTION_CALL_END();
/* Wait for hardware to finish */
if (ret == 0) {
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(res_w, tok_w,
mcuxClEls_WaitForOperation(MCUXCLELS_ERROR_FLAGS_CLEAR));
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_WaitForOperation) != tok_w) ||
(MCUXCLELS_STATUS_OK != res_w)) {
#ifdef DEBUG
wolfBoot_printf("[DICE] update_cdi: WaitForOperation(HKDF) failed"
" res=0x%x tok=0x%x\r\n",
(unsigned)res_w, (unsigned)tok_w);
#endif
ret = -1;
}
MCUX_CSSL_FP_FUNCTION_CALL_END();
}
}
if (ret == 0)
cdi_derivation_count++;
else
cdi_derivation_count = 0; /* reset on error — create_attest_key won't be called */
XMEMSET(deriv, 0, sizeof(deriv));
#ifdef DEBUG
wolfBoot_printf("[DICE] update_cdi: ret=%d\r\n", ret);
#endif
return ret;
}
/* Generate P-256 IAK from derived CDI using ELS KEYGEN.
* Private key stays in ELS keystore. Public key written to system memory. */
int hal_dice_create_attest_key(void)
{
uint8_t pub_key[64] __attribute__((aligned(4)));
mcuxClEls_EccKeyGenOption_t opts = {0};
mcuxClEls_KeyProp_t props = {0};
int ret = 0;
s_dice_attest_pubkey_valid = 0;
XMEMSET(s_dice_attest_pubkey, 0, sizeof(s_dice_attest_pubkey));
#ifdef DEBUG
wolfBoot_printf("[DICE] create_attest_key: start\r\n");
#endif
/* No KeyDelete here: DETERMINISTIC EccKeyGen reads the CDI from
* IAK_KEYSLOT (= CDI_DERIVED_KEYSLOT) as its seed input.
* Deleting that slot first would destroy the source material. */
/* Set KeyGen options */
opts.bits.kgsrc = MCUXCLELS_ECC_OUTPUTKEY_DETERMINISTIC;
opts.bits.kgtypedh = MCUXCLELS_ECC_OUTPUTKEY_SIGN;
/* Set key properties */
props.bits.upprot_priv = MCUXCLELS_KEYPROPERTY_PRIVILEGED_TRUE;
props.bits.upprot_sec = MCUXCLELS_KEYPROPERTY_SECURE_TRUE;
props.bits.uecsg = MCUXCLELS_KEYPROPERTY_ECC_TRUE;
props.bits.uksk = MCUXCLELS_KEYPROPERTY_KSK_TRUE;
props.bits.fgp = MCUXCLELS_KEYPROPERTY_GENERAL_PURPOSE_SLOT_TRUE;
props.bits.kbase = MCUXCLELS_KEYPROPERTY_BASE_SLOT;
props.bits.kactv = MCUXCLELS_KEYPROPERTY_ACTIVE_TRUE;
props.bits.ksize = MCUXCLELS_KEYPROPERTY_KEY_SIZE_256;
#ifdef DEBUG
wolfBoot_printf("[DICE] create_attest_key: EccKeyGen"
" CDI_DERIVED_SLOT=%d IAK_SLOT=%d\r\n",
MCXN_ELS_DICE_CDI_DERIVED_KEYSLOT,
MCXN_ELS_DICE_IAK_KEYSLOT);
#endif
/* Trigger the ECC KeyGen command.
* We just give the names of token and return value
* since it's declared within the macro */
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(res_kg, tok_kg,
mcuxClEls_EccKeyGen_Async(opts,
MCXN_ELS_DICE_CDI_DERIVED_KEYSLOT,
MCXN_ELS_DICE_IAK_KEYSLOT,
props, NULL, pub_key));
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_EccKeyGen_Async) != tok_kg) ||
(MCUXCLELS_STATUS_OK_WAIT != res_kg)) {
#ifdef DEBUG
wolfBoot_printf("[DICE] create_attest_key: EccKeyGen_Async failed"
" res=0x%x tok=0x%x\r\n",
(unsigned)res_kg, (unsigned)tok_kg);
#endif
ret = -1;
}
MCUX_CSSL_FP_FUNCTION_CALL_END();
/* Wait for hardware to finish */
if (ret == 0) {
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(res_w, tok_w,
mcuxClEls_WaitForOperation(MCUXCLELS_ERROR_FLAGS_CLEAR));
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_WaitForOperation) != tok_w) ||
(MCUXCLELS_STATUS_OK != res_w)) {
#ifdef DEBUG
wolfBoot_printf("[DICE] create_attest_key: WaitForOperation(KEYGEN) failed"
" res=0x%x tok=0x%x\r\n",
(unsigned)res_w, (unsigned)tok_w);
#endif
ret = -1;
}
MCUX_CSSL_FP_FUNCTION_CALL_END();
}
if (ret == 0) {
XMEMCPY(s_dice_attest_pubkey, pub_key, sizeof(s_dice_attest_pubkey));
s_dice_attest_pubkey_valid = 1;
}
cdi_derivation_count = 0; /* reset for the next token build */
XMEMSET(pub_key, 0, sizeof(pub_key));
#ifdef DEBUG
wolfBoot_printf("[DICE] create_attest_key: ret=%d\r\n", ret);
#endif
return ret;
}
int hal_dice_get_attest_pubkey(uint8_t *buf, size_t *len)
{
if (buf == NULL || len == NULL || *len < 65)
return -1;
if (!s_dice_attest_pubkey_valid)
return -1;
buf[0] = 0x04; /* X9.63 uncompressed prefix */
XMEMCPY(buf + 1, s_dice_attest_pubkey, sizeof(s_dice_attest_pubkey));
*len = 65;
/* Zeroize cached public key after copying out (read-once). */
hal_dice_zeroize(s_dice_attest_pubkey, sizeof(s_dice_attest_pubkey));
s_dice_attest_pubkey_valid = 0;
return 0;
}
int hal_dice_sign_hash(const uint8_t *hash, size_t hash_len,
uint8_t *sig, size_t *sig_len)
{
mcuxClEls_EccSignOption_t opts = {0};
uint8_t hash_buf[SHA256_DIGEST_SIZE] __attribute__((aligned(4)));
uint8_t sig_buf[MCUXCLELS_ECC_SIGNATURE_SIZE] __attribute__((aligned(4)));
int ret = 0;
_Static_assert(MCUXCLELS_ECC_SIGNATURE_SIZE == 64,
"MCUXCLELS_ECC_SIGNATURE_SIZE must equal WOLFBOOT_DICE_SIG_LEN (64)");
#ifdef DEBUG
wolfBoot_printf("[DICE] sign_hash: hash_len=%u\r\n", (unsigned)hash_len);
#endif
if (hash == NULL || sig == NULL || sig_len == NULL || hash_len != SHA256_DIGEST_SIZE ||
*sig_len < MCUXCLELS_ECC_SIGNATURE_SIZE) {
#ifdef DEBUG
wolfBoot_printf("[DICE] sign_hash: invalid args"
" hash=%p sig=%p sig_len=%p hash_len=%u\r\n",
hash, sig, sig_len, (unsigned)hash_len);
#endif
ret = -1;
}
if (ret == 0) {
XMEMCPY(hash_buf, hash, SHA256_DIGEST_SIZE);
/* Set options */
opts.bits.echashchl = MCUXCLELS_ECC_HASHED;
/* Trigger the ECC Sign command.
* We just give the names of token and return value
* since it's declared within the macro */
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(res_sign, tok_sign,
mcuxClEls_EccSign_Async(opts,
MCXN_ELS_DICE_IAK_KEYSLOT,
hash_buf, NULL, 0, sig_buf));
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_EccSign_Async) != tok_sign) ||
(MCUXCLELS_STATUS_OK_WAIT != res_sign)) {
#ifdef DEBUG
wolfBoot_printf("[DICE] sign_hash: EccSign_Async failed"
" res=0x%x tok=0x%x\r\n",
(unsigned)res_sign, (unsigned)tok_sign);
#endif
ret = -1;
}
MCUX_CSSL_FP_FUNCTION_CALL_END();
/* Wait for hardware to finish */
if (ret == 0) {
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(res_w, tok_w,
mcuxClEls_WaitForOperation(MCUXCLELS_ERROR_FLAGS_CLEAR));
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_WaitForOperation) != tok_w) ||
(MCUXCLELS_STATUS_OK != res_w)) {
#ifdef DEBUG
wolfBoot_printf("[DICE] sign_hash: WaitForOperation(SIGN) failed"
" res=0x%x tok=0x%x\r\n",
(unsigned)res_w, (unsigned)tok_w);
#endif
ret = -1;
}
MCUX_CSSL_FP_FUNCTION_CALL_END();
}
}
if (ret == 0) {
XMEMCPY(sig, sig_buf, MCUXCLELS_ECC_SIGNATURE_SIZE);
*sig_len = MCUXCLELS_ECC_SIGNATURE_SIZE;
}
hal_dice_zeroize(hash_buf, sizeof(hash_buf));
hal_dice_zeroize(sig_buf, sizeof(sig_buf));
#ifdef DEBUG
wolfBoot_printf("[DICE] sign_hash: ret=%d\r\n", ret);
#endif
return ret;
}
#endif /* WOLFCRYPT_TZ_PSA && WOLFBOOT_DICE_HW && __WOLFBOOT */

View File

@ -167,6 +167,35 @@ int hal_attestation_get_implementation_id(uint8_t *buf, size_t *len);
int hal_attestation_get_ueid(uint8_t *buf, size_t *len);
int hal_attestation_get_iak_private_key(uint8_t *buf, size_t *len);
#ifdef WOLFBOOT_DICE_HW
/* Hardware DICE hooks — implement these to delegate CDI derivation and
* attestation signing to a platform security boundary. */
/* Mix one boot-component measurement into the platform CDI chain.
* measurement_desc identifies the component; use the WOLFBOOT_DICE_COMPONENT_*
* macros from wolfboot/dice.h (e.g. WOLFBOOT_DICE_COMPONENT_WOLFBOOT,
* WOLFBOOT_DICE_COMPONENT_BOOTIMAGE).
* The platform updates its internal CDI state; no CDI material is returned. */
int hal_dice_update_cdi(const uint8_t *measurement, size_t meas_len,
const char *measurement_desc, size_t measurement_desc_len);
/* Derive and store the attestation keypair from the current CDI state.
* The private key must not be exposed outside the platform security boundary.
* Returns 0 on success. */
int hal_dice_create_attest_key(void);
/* Sign a pre-computed SHA-256 hash with the platform attestation key.
* Output: 64-byte raw R||S (big-endian), same format as wolfCrypt ES256.
* Must be called after hal_dice_create_attest_key(). */
int hal_dice_sign_hash(const uint8_t *hash, size_t hash_len,
uint8_t *sig, size_t *sig_len);
/* Retrieve the IAK public key cached by hal_dice_create_attest_key().
* Output: 65-byte X9.63 uncompressed point (0x04 || X || Y).
* The internal copy is zeroized after this call (read-once). */
int hal_dice_get_attest_pubkey(uint8_t *buf, size_t *len);
#endif /* WOLFBOOT_DICE_HW */
#ifdef FLASH_OTP_KEYSTORE
int hal_flash_otp_write(uint32_t flashAddress, const void* data, uint16_t length);

View File

@ -65,7 +65,7 @@ typedef struct psa_outvec {
((size_t)(((ctrl_param) & WOLFBOOT_ARM_TEE_OUT_LEN_MASK) >> \
WOLFBOOT_ARM_TEE_OUT_LEN_OFFSET))
#if defined(__ARM_FEATURE_CMSE) && defined(__GNUC__)
#if defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) && defined(__GNUC__)
#define WOLFBOOT_CMSE_NS_ENTRY __attribute__((cmse_nonsecure_entry))
#else
#define WOLFBOOT_CMSE_NS_ENTRY

View File

@ -27,6 +27,11 @@
#include <stddef.h>
#include <stdint.h>
/* Component name used in the DICE claims for the wolfBoot measurement.
* Shared between dice.c (producer) and HAL (consumer) to keep them in sync. */
#define WOLFBOOT_DICE_COMPONENT_WOLFBOOT "wolfboot"
#define WOLFBOOT_DICE_COMPONENT_BOOTIMAGE "boot-image"
#ifdef __cplusplus
extern "C" {
#endif
@ -39,6 +44,14 @@ int wolfBoot_dice_get_token(const uint8_t *challenge,
int wolfBoot_dice_get_token_size(size_t challenge_size, size_t *token_size);
/* Retrieve the IAK public key as a 65-byte X9.63 uncompressed point
* (0x04 || X[32] || Y[32]). Must be called after wolfBoot_dice_get_token().
* The internal copy is zeroized after this call (read-once).
* Not available when WOLFBOOT_ATTESTATION_IAK is set (provisioned key is used). */
#ifndef WOLFBOOT_ATTESTATION_IAK
int wolfBoot_dice_get_attest_pubkey(uint8_t *buf, size_t *len);
#endif /* !WOLFBOOT_ATTESTATION_IAK */
#ifdef __cplusplus
}
#endif

View File

@ -943,6 +943,12 @@ ifeq ($(WOLFCRYPT_TZ_PSA),1)
endif
endif
ifeq ($(WOLFBOOT_DICE_HW),1)
ifneq ($(WOLFCRYPT_TZ_PSA),1)
$(error WOLFBOOT_DICE_HW requires WOLFCRYPT_TZ_PSA=1)
endif
endif
ifeq ($(WOLFCRYPT_TZ_PKCS11),1)
CFLAGS+=-DSECURE_PKCS11
CFLAGS+=-DWOLFPKCS11_USER_SETTINGS
@ -998,6 +1004,9 @@ endif
ifeq ($(WOLFCRYPT_TZ_PSA),1)
CFLAGS+=-DWOLFCRYPT_TZ_PSA
CFLAGS+=-DWOLFCRYPT_SECURE_MODE
ifeq ($(WOLFBOOT_DICE_HW),1)
CFLAGS+=-DWOLFBOOT_DICE_HW
endif
CFLAGS+=-DWOLFSSL_PSA_ENGINE
CFLAGS+=-DWOLFPSA_CUSTOM_STORE
CFLAGS+=-DNO_DES3 -DNO_DES3_TLS_SUITES

View File

@ -77,6 +77,7 @@
/* ARM TEE Attestation message types. */
#define ARM_TEE_ATTEST_GET_TOKEN 1001
#define ARM_TEE_ATTEST_GET_TOKEN_SIZE 1002
#define ARM_TEE_ATTEST_GET_IAK_PUBKEY 1003
#ifndef PSA_STORAGE_FLAG_WRITE_ONCE
#define PSA_STORAGE_FLAG_WRITE_ONCE ((psa_storage_create_flags_t)0x00000001)
@ -168,6 +169,8 @@ static psa_status_t wolfboot_attest_status(int dice_rc)
return PSA_ERROR_HARDWARE_FAILURE;
case -4:
return PSA_ERROR_GENERIC_ERROR;
case -5:
return PSA_ERROR_BAD_STATE;
default:
return PSA_ERROR_GENERIC_ERROR;
}
@ -947,6 +950,35 @@ int32_t arm_tee_psa_call(psa_handle_t handle, int32_t type,
}
return PSA_SUCCESS;
}
#ifndef WOLFBOOT_ATTESTATION_IAK
if (type == ARM_TEE_ATTEST_GET_IAK_PUBKEY) {
size_t key_len;
int dice_rc;
psa_status_t status;
if (out_vec == NULL || out_len < 1 || out_vec[0].base == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (out_vec[0].len < 65) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
key_len = out_vec[0].len;
wolfBoot_printf("[ATTEST] GET_IAK_PUBKEY: out_len=%u\r\n",
(unsigned)key_len);
dice_rc = wolfBoot_dice_get_attest_pubkey((uint8_t *)out_vec[0].base,
&key_len);
wolfBoot_printf("[ATTEST] GET_IAK_PUBKEY: dice_rc=%d key_len=%u\r\n",
dice_rc, (unsigned)key_len);
status = wolfboot_attest_status(dice_rc);
if (status != PSA_SUCCESS) {
return status;
}
out_vec[0].len = key_len;
return PSA_SUCCESS;
}
#endif /* !WOLFBOOT_ATTESTATION_IAK */
return PSA_ERROR_NOT_SUPPORTED;
}

View File

@ -66,6 +66,7 @@
#define WOLFBOOT_DICE_ERR_BUFFER_TOO_SMALL -2
#define WOLFBOOT_DICE_ERR_HW -3
#define WOLFBOOT_DICE_ERR_CRYPTO -4
#define WOLFBOOT_DICE_ERR_KEY_NOT_FOUND -5
static NOINLINEFUNCTION void wolfboot_dice_zeroize(void *ptr, size_t len)
{
@ -514,8 +515,10 @@ static int wolfboot_dice_fixup_priv(uint8_t *priv, size_t priv_len)
static int wolfboot_dice_collect_claims(struct wolfboot_dice_claims *claims)
{
#ifndef WOLFBOOT_DICE_HW
uint8_t uds[WOLFBOOT_DICE_CDI_LEN];
size_t uds_len = sizeof(uds);
#endif
uint8_t wb_hash[WOLFBOOT_SHA_DIGEST_SIZE];
size_t wb_hash_len = sizeof(wb_hash);
uint8_t boot_hash[WOLFBOOT_SHA_DIGEST_SIZE];
@ -523,6 +526,13 @@ static int wolfboot_dice_collect_claims(struct wolfboot_dice_claims *claims)
XMEMSET(claims, 0, sizeof(*claims));
#ifdef WOLFBOOT_DICE_HW
/* UDS stays inside platform security boundary. wolfboot_dice_get_ueid()
* calls hal_attestation_get_ueid() first; with NULL UDS it uses the HAL path. */
if (wolfboot_dice_get_ueid(claims->ueid, &claims->ueid_len, NULL, 0) != 0) {
return WOLFBOOT_DICE_ERR_HW;
}
#else
if (hal_uds_derive_key(uds, uds_len) != 0) {
/* Buffer may be partially filled, zero it to be sure */
wc_ForceZero(uds, sizeof(uds));
@ -534,6 +544,7 @@ static int wolfboot_dice_collect_claims(struct wolfboot_dice_claims *claims)
wc_ForceZero(uds, sizeof(uds));
return WOLFBOOT_DICE_ERR_HW;
}
#endif
{
size_t impl_len = sizeof(claims->implementation_id);
@ -560,9 +571,9 @@ static int wolfboot_dice_collect_claims(struct wolfboot_dice_claims *claims)
claims->components[claims->component_count].measurement_type_len =
XSTRLEN(WOLFBOOT_MEASUREMENT_HASH_NAME);
claims->components[claims->component_count].measurement_desc =
"wolfboot";
WOLFBOOT_DICE_COMPONENT_WOLFBOOT;
claims->components[claims->component_count].measurement_desc_len =
XSTRLEN("wolfboot");
XSTRLEN(WOLFBOOT_DICE_COMPONENT_WOLFBOOT);
XMEMCPY(claims->components[claims->component_count].measurement,
wb_hash, wb_hash_len);
claims->components[claims->component_count].measurement_len = wb_hash_len;
@ -575,19 +586,28 @@ static int wolfboot_dice_collect_claims(struct wolfboot_dice_claims *claims)
claims->components[claims->component_count].measurement_type_len =
XSTRLEN(WOLFBOOT_MEASUREMENT_HASH_NAME);
claims->components[claims->component_count].measurement_desc =
"boot-image";
WOLFBOOT_DICE_COMPONENT_BOOTIMAGE;
claims->components[claims->component_count].measurement_desc_len =
XSTRLEN("boot-image");
XSTRLEN(WOLFBOOT_DICE_COMPONENT_BOOTIMAGE);
XMEMCPY(claims->components[claims->component_count].measurement,
boot_hash, boot_hash_len);
claims->components[claims->component_count].measurement_len = boot_hash_len;
claims->component_count++;
}
#ifndef WOLFBOOT_DICE_HW
wc_ForceZero(uds, sizeof(uds));
#endif
return WOLFBOOT_DICE_SUCCESS;
}
#ifndef WOLFBOOT_DICE_HW
/* Cached IAK public key (X9.63, 65 bytes) populated during key derivation.
* Consumed and zeroized by wolfBoot_dice_get_attest_pubkey(). */
static uint8_t s_dice_attest_pubkey[65];
static word32 s_dice_attest_pubkey_len;
#endif /* !WOLFBOOT_DICE_HW */
#ifndef WOLFBOOT_DICE_HW
static int wolfboot_dice_derive_attestation_key(ecc_key *key,
const uint8_t *uds,
size_t uds_len,
@ -652,6 +672,24 @@ static int wolfboot_dice_derive_attestation_key(ecc_key *key,
goto cleanup;
}
/* Compute and cache the public key for wolfBoot_dice_get_attest_pubkey().
* wc_ecc_import_private_key_ex with pub=NULL sets PRIVATEKEY_ONLY, so the
* public point must be computed explicitly before export. */
{
word32 pub_len = sizeof(s_dice_attest_pubkey);
/* Clear cached public key before new generation */
XMEMSET(s_dice_attest_pubkey, 0, sizeof(s_dice_attest_pubkey));
s_dice_attest_pubkey_len = 0;
if (wc_ecc_make_pub(key, NULL) == 0 &&
wc_ecc_export_x963(key, s_dice_attest_pubkey, &pub_len) == 0) {
s_dice_attest_pubkey_len = pub_len;
}
else {
goto cleanup;
}
}
ret = 0;
cleanup:
@ -660,7 +698,32 @@ cleanup:
wolfboot_dice_zeroize(cdi, sizeof(cdi));
return ret;
}
#endif /* !WOLFBOOT_DICE_HW */
#ifdef WOLFBOOT_DICE_HW
static int wolfboot_attest_get_private_key_hw(
const struct wolfboot_dice_claims *claims)
{
size_t i;
/* Mix each boot component measurement into the platform CDI chain */
for (i = 0; i < claims->component_count; i++) {
if (hal_dice_update_cdi(claims->components[i].measurement,
claims->components[i].measurement_len,
claims->components[i].measurement_desc,
claims->components[i].measurement_desc_len) != 0) {
return -1;
}
}
/* Derive attestation keypair from current CDI state.
* Private key stays inside the platform security boundary. */
if (hal_dice_create_attest_key() != 0) {
return -1;
}
return 0;
}
#endif /* WOLFBOOT_DICE_HW */
#ifndef WOLFBOOT_DICE_HW
static int wolfboot_attest_get_private_key(ecc_key *key,
const struct wolfboot_dice_claims *claims)
{
@ -699,6 +762,7 @@ cleanup:
return ret;
#endif
}
#endif /* !WOLFBOOT_DICE_HW */
static int wolfboot_dice_encode_payload(uint8_t *buf,
size_t buf_len,
@ -818,45 +882,75 @@ static int wolfboot_dice_sign_tbs(const uint8_t *tbs,
size_t *sig_len,
const struct wolfboot_dice_claims *claims)
{
ecc_key key;
WC_RNG rng;
int ret = WOLFBOOT_DICE_ERR_CRYPTO;
int wc_ret;
int key_inited = 0;
int rng_inited = 0;
uint8_t hash[SHA256_DIGEST_SIZE];
#ifndef WOLFBOOT_DICE_HW
ecc_key key;
int key_inited = 0;
WC_RNG rng;
int wc_ret;
int rng_inited = 0;
uint8_t der_sig[128];
word32 der_sig_len = sizeof(der_sig);
uint8_t r[WOLFBOOT_DICE_SIG_LEN / 2];
uint8_t s[WOLFBOOT_DICE_SIG_LEN / 2];
word32 r_len = sizeof(r);
word32 s_len = sizeof(s);
#endif /* !WOLFBOOT_DICE_HW */
if (sig == NULL || sig_len == NULL || *sig_len < WOLFBOOT_DICE_SIG_LEN) {
return WOLFBOOT_DICE_ERR_INVALID_ARGUMENT;
}
#ifdef WOLFBOOT_DICE_HW
if (wolfboot_attest_get_private_key_hw(claims) != 0) {
ret = WOLFBOOT_DICE_ERR_HW;
goto cleanup;
}
#else
wc_ecc_init(&key);
key_inited = 1;
if (wolfboot_attest_get_private_key(&key, claims) != 0) {
ret = WOLFBOOT_DICE_ERR_HW;
goto cleanup;
}
#endif
#ifndef WOLFBOOT_DICE_HW
(void)wc_ecc_set_deterministic(&key, 1);
if (wc_InitRng(&rng) != 0) {
ret = WOLFBOOT_DICE_ERR_HW;
goto cleanup;
}
rng_inited = 1;
#endif /* !WOLFBOOT_DICE_HW */
{
wc_Sha256 sha;
wc_InitSha256(&sha);
wc_Sha256Update(&sha, tbs, (word32)tbs_len);
wc_Sha256Final(&sha, hash);
ret = wc_InitSha256(&sha);
if (ret == 0) {
ret = wc_Sha256Update(&sha, tbs, (word32)tbs_len);
if (ret == 0) {
ret = wc_Sha256Final(&sha, hash);
}
wc_Sha256Free(&sha);
}
if (ret != 0) {
ret = WOLFBOOT_DICE_ERR_CRYPTO;
goto cleanup;
}
}
#ifdef WOLFBOOT_DICE_HW
/* Platform attestation key is ready. Sign pre-computed hash via HAL.
* hal_dice_sign_hash() MUST output 64-byte raw R||S (big-endian), NOT DER.
* This matches WOLFBOOT_DICE_SIG_LEN and the COSE_Sign1 signature field directly,
* bypassing the wc_ecc_sig_to_rs DER->raw conversion that the software path needs. */
ret = hal_dice_sign_hash(hash, sizeof(hash), sig, sig_len);
if (ret != 0)
ret = WOLFBOOT_DICE_ERR_HW;
#else /* !WOLFBOOT_DICE_HW */
wc_ret = wc_ecc_sign_hash(hash, sizeof(hash), der_sig, &der_sig_len, &rng, &key);
if (wc_ret != 0) {
ret = WOLFBOOT_DICE_ERR_CRYPTO;
@ -874,17 +968,20 @@ static int wolfboot_dice_sign_tbs(const uint8_t *tbs,
XMEMCPY(sig + sizeof(r) + (sizeof(s) - s_len), s, s_len);
*sig_len = WOLFBOOT_DICE_SIG_LEN;
ret = WOLFBOOT_DICE_SUCCESS;
#endif /* !WOLFBOOT_DICE_HW */
cleanup:
if (rng_inited) {
wc_FreeRng(&rng);
}
#ifndef WOLFBOOT_DICE_HW
if (key_inited) {
wc_ecc_free(&key);
wolfboot_dice_zeroize(&key, sizeof(key));
}
wolfboot_dice_zeroize(hash, sizeof(hash));
if (rng_inited) {
wc_FreeRng(&rng);
}
wolfboot_dice_zeroize(der_sig, sizeof(der_sig));
#endif /* !WOLFBOOT_DICE_HW */
wolfboot_dice_zeroize(hash, sizeof(hash));
return ret;
}
@ -1026,3 +1123,28 @@ int wolfBoot_dice_get_token_size(size_t challenge_size, size_t *token_size)
*token_size = needed;
return WOLFBOOT_DICE_SUCCESS;
}
#ifndef WOLFBOOT_ATTESTATION_IAK
int wolfBoot_dice_get_attest_pubkey(uint8_t *buf, size_t *len)
{
if (buf == NULL || len == NULL || *len < 65)
return WOLFBOOT_DICE_ERR_INVALID_ARGUMENT;
#ifdef WOLFBOOT_DICE_HW
if (hal_dice_get_attest_pubkey(buf, len) != 0)
return WOLFBOOT_DICE_ERR_KEY_NOT_FOUND; /* key not yet derived; call wolfBoot_dice_get_token() first */
else
return WOLFBOOT_DICE_SUCCESS;
#else
if (s_dice_attest_pubkey_len == 0)
return WOLFBOOT_DICE_ERR_KEY_NOT_FOUND; /* key not yet derived; call wolfBoot_dice_get_token() first */
XMEMCPY(buf, s_dice_attest_pubkey, s_dice_attest_pubkey_len);
*len = s_dice_attest_pubkey_len;
wolfboot_dice_zeroize(s_dice_attest_pubkey, sizeof(s_dice_attest_pubkey));
s_dice_attest_pubkey_len = 0;
return WOLFBOOT_DICE_SUCCESS;
#endif
}
#endif /* !WOLFBOOT_ATTESTATION_IAK */

View File

@ -20,6 +20,8 @@
*/
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "fsl_clock.h"
#include "fsl_gpio.h"
#include "fsl_port.h"
@ -33,6 +35,13 @@
#include "wolfssl/wolfcrypt/random.h"
#endif
#ifdef WOLFCRYPT_TZ_PSA
#include "psa/crypto.h"
#include "psa/error.h"
#include "psa/initial_attestation.h"
#include "wolfssl/wolfcrypt/types.h"
#endif
extern void hal_init(void);
static void gpio_init_output(GPIO_Type *gpio, PORT_Type *port,
@ -82,25 +91,221 @@ static void gpio_init_output(GPIO_Type *gpio, PORT_Type *port,
PORT_SetPinConfig(port, pin, &pin_config);
}
#ifdef WOLFCRYPT_TZ_PSA
#define LINE_LEN 16
static void print_hex(const uint8_t *buffer, uint32_t length, int dumpChars)
{
uint32_t i, sz;
if (!buffer) {
wolfBoot_printf("\tNULL\r\n");
return;
}
while (length > 0) {
sz = length;
if (sz > LINE_LEN)
sz = LINE_LEN;
wolfBoot_printf("\t");
for (i = 0; i < LINE_LEN; i++) {
if (i < sz)
wolfBoot_printf("%02x ", buffer[i]);
else
wolfBoot_printf(" ");
}
if (dumpChars) {
wolfBoot_printf("| ");
for (i = 0; i < sz; i++) {
if (buffer[i] > 31 && buffer[i] < 127)
wolfBoot_printf("%c", buffer[i]);
else
wolfBoot_printf(".");
}
}
wolfBoot_printf("\r\n");
buffer += sz;
length -= sz;
}
}
#endif
#if defined(WOLFBOOT_ATTESTATION_TEST) && defined(WOLFCRYPT_TZ_PSA)
/* Read a CBOR bstr at *offset; sets *data and *data_len, advances *offset. */
static int cbor_get_bstr(const uint8_t *buf, size_t buf_len, size_t *offset,
const uint8_t **data, size_t *data_len)
{
uint8_t b;
size_t len;
if (*offset >= buf_len) return -1;
b = buf[(*offset)++];
if ((b >> 5) != 2) return -1; /* must be CBOR major type 2 (bstr) */
switch (b & 0x1F) {
case 24:
if (*offset >= buf_len) return -1;
len = buf[(*offset)++]; break;
case 25:
if (*offset + 2 > buf_len) return -1;
len = ((size_t)buf[*offset] << 8) | buf[*offset + 1];
*offset += 2; break;
default:
if ((b & 0x1F) > 23) return -1; /* rejects AI>=26 */
len = b & 0x1F;
}
if (*offset + len > buf_len) return -1;
*data = buf + *offset;
*data_len = len;
*offset += len;
return 0;
}
/* Maximum fixed bytes in a COSE_Sign1 Sig_Structure before variable content:
* 1 (array(4) tag) + 1 (tstr(10) tag) + 10 ("Signature1") +
* 3 (max bstr hdr for prot) + 1 (empty-AAD 0x40) + 3 (max bstr hdr for payload)
*/
#define COSE_SIGN1_TBS_FIXED_OVERHEAD (1 + 1 + 10 + 3 + 1 + 3)
/* Write a CBOR bstr length header into buf; returns number of bytes written. */
static int cbor_put_bstr_hdr(uint8_t *buf, size_t len)
{
if (len <= 23) {
buf[0] = 0x40 | (uint8_t)len;
return 1;
}
if (len <= 0xFF) {
buf[0] = 0x58; buf[1] = (uint8_t)len;
return 2;
}
if (len > 0xFFFF)
return -1;
buf[0] = 0x59; buf[1] = (uint8_t)(len >> 8);
buf[2] = (uint8_t)len;
return 3;
}
static int run_attest_verify_test(void)
{
static const uint8_t challenge[PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32] = {
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,
0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20
};
static uint8_t token[1024];
static uint8_t tbs[1024]; /* Sig_Structure buffer */
uint8_t pubkey[65];
uint8_t hash[32];
size_t token_len = sizeof(token);
size_t pubkey_len = sizeof(pubkey);
size_t hash_len = 0;
size_t tbs_len = 0;
const uint8_t *prot_bytes, *payload_bytes, *sig_bytes;
size_t prot_len, payload_len, sig_len;
size_t off = 0;
int hdr;
psa_status_t st;
psa_key_attributes_t attrs = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t key_id;
wolfBoot_printf("Start attestation verify test\r\n");
/* 1. Generate token — also caches the IAK public key on the secure side */
st = psa_initial_attest_get_token(challenge, sizeof(challenge),
token, sizeof(token), &token_len);
if (st != PSA_SUCCESS) {
wolfBoot_printf("attest_verify: get_token failed (%d)\r\n", (int)st);
return -1;
}
wolfBoot_printf("attest_verify: token_len=%lu\r\n", (unsigned long)token_len);
print_hex(token, (uint32_t)token_len, 1);
/* 2. Retrieve IAK public key via PSA attestation service (read-once) */
st = psa_initial_attest_get_iak_pubkey(pubkey, sizeof(pubkey), &pubkey_len);
if (st != PSA_SUCCESS) {
wolfBoot_printf("attest_verify: get_iak_pubkey failed (%d)\r\n", (int)st);
return -1;
}
wolfBoot_printf("attest_verify: IAK pubkey (%lu bytes):\r\n",
(unsigned long)pubkey_len);
print_hex(pubkey, (uint32_t)pubkey_len, 1);
/* 3. Parse COSE_Sign1: 84 | prot_bstr | A0 | payload_bstr | sig_bstr */
if (off >= token_len || token[off++] != 0x84) {
wolfBoot_printf("attest_verify: bad array tag\r\n"); return -1;
}
if (cbor_get_bstr(token, token_len, &off, &prot_bytes, &prot_len) != 0 ||
off >= token_len || token[off++] != 0xA0 ||
cbor_get_bstr(token, token_len, &off, &payload_bytes, &payload_len) != 0 ||
cbor_get_bstr(token, token_len, &off, &sig_bytes, &sig_len) != 0 ||
sig_len != 64) {
wolfBoot_printf("attest_verify: COSE parse failed\r\n"); return -1;
}
/* 4. Reconstruct Sig_Structure = ["Signature1", prot_bstr, b"", payload_bstr] */
if (COSE_SIGN1_TBS_FIXED_OVERHEAD + prot_len + payload_len > sizeof(tbs)) {
wolfBoot_printf("attest_verify: tbs buffer too small\r\n");
return -1;
}
tbs[tbs_len++] = 0x84; /* array(4) */
tbs[tbs_len++] = 0x6A; /* tstr(10) */
memcpy(tbs + tbs_len, "Signature1", 10); tbs_len += 10;
hdr = cbor_put_bstr_hdr(tbs + tbs_len, prot_len);
if (hdr < 0) { wolfBoot_printf("attest_verify: cbor hdr failed\r\n"); return -1; }
tbs_len += hdr;
memcpy(tbs + tbs_len, prot_bytes, prot_len);
tbs_len += prot_len;
tbs[tbs_len++] = 0x40; /* bstr(0): empty AAD */
hdr = cbor_put_bstr_hdr(tbs + tbs_len, payload_len);
if (hdr < 0) { wolfBoot_printf("attest_verify: cbor hdr failed\r\n"); return -1; }
tbs_len += hdr;
memcpy(tbs + tbs_len, payload_bytes, payload_len);
tbs_len += payload_len;
/* 5. SHA-256 hash of Sig_Structure */
if (psa_hash_compute(PSA_ALG_SHA_256, tbs, tbs_len,
hash, sizeof(hash), &hash_len) != PSA_SUCCESS) {
wolfBoot_printf("attest_verify: hash failed\r\n");
return -1;
}
/* 6. Import IAK public key and verify ES256 signature (raw R||S, 64 bytes) */
psa_set_key_type(&attrs, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
psa_set_key_bits(&attrs, 256);
psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_VERIFY_HASH);
psa_set_key_algorithm(&attrs, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
if (psa_import_key(&attrs, pubkey, pubkey_len, &key_id) != PSA_SUCCESS) {
psa_reset_key_attributes(&attrs);
wolfBoot_printf("attest_verify: import_key failed\r\n");
return -1;
}
psa_reset_key_attributes(&attrs);
st = psa_verify_hash(key_id, PSA_ALG_ECDSA(PSA_ALG_SHA_256),
hash, hash_len, sig_bytes, sig_len);
psa_destroy_key(key_id);
if (st != PSA_SUCCESS) {
wolfBoot_printf("attest_verify: FAILED (%d)\r\n", (int)st);
return -1;
}
wolfBoot_printf("attest_verify: IAK signature verified OK\r\n");
return 0;
}
#endif
#ifdef WOLFCRYPT_SECURE_MODE
static void print_random_number(void)
{
WC_RNG rng;
uint32_t rnd;
uint8_t rnd;
int ret;
ret = wc_InitRng(&rng);
if (ret != 0) {
wolfBoot_printf("Random number: init failed (%d)\n", ret);
}
else {
ret = wc_RNG_GenerateBlock(&rng, (byte *)&rnd, sizeof(rnd));
if (ret != 0)
wolfBoot_printf("Random number: generate failed (%d)\n", ret);
else
wolfBoot_printf("Today's lucky number: 0x%08lx\n", (unsigned long)rnd);
wc_FreeRng(&rng);
}
ret = wcs_get_random(&rnd, sizeof(rnd));
if (ret != 0)
wolfBoot_printf("Random number: generate failed (%d)\n", ret);
else
wolfBoot_printf("Today's lucky number: 0x%02x\n", rnd);
}
#endif
@ -122,6 +327,21 @@ void main(void)
print_random_number();
#endif
#ifdef WOLFCRYPT_TZ_PSA
{
psa_status_t psa_ret = psa_crypto_init();
if (psa_ret == PSA_SUCCESS)
wolfBoot_printf("PSA crypto init ok\r\n");
else
wolfBoot_printf("PSA crypto init failed (%d)\r\n", (int)psa_ret);
}
#endif
#if defined(WOLFBOOT_ATTESTATION_TEST) && defined(WOLFCRYPT_TZ_PSA)
(void)run_attest_verify_test();
#endif
if (boot_ver == 1) {
/* Red off */
gpio_init_output(GPIO0, PORT0, kCLOCK_Gpio0, kCLOCK_Port0, 10U, 1U);

View File

@ -66,6 +66,7 @@ ifeq ($(ARCH),)
WOLFCRYPT_TZ?=0
WOLFCRYPT_TZ_PKCS11?=0
WOLFCRYPT_TZ_PSA?=0
WOLFBOOT_DICE_HW?=0
WOLFCRYPT_TZ_FWTPM?=0
WOLFBOOT_PARTITION_SIZE?=0x20000
WOLFBOOT_SECTOR_SIZE?=0x20000
@ -110,6 +111,7 @@ CONFIG_VARS:= ARCH TARGET SIGN HASH MCUXSDK MCUXPRESSO MCUXPRESSO_CPU MCUXPRESSO
WOLFBOOT_UDS_OBKEYS \
WOLFCRYPT_TZ WOLFCRYPT_TZ_PKCS11 \
WOLFCRYPT_TZ_PSA \
WOLFBOOT_DICE_HW \
WOLFCRYPT_TZ_FWTPM \
WOLFBOOT_PARTITION_SIZE WOLFBOOT_SECTOR_SIZE \
WOLFBOOT_PARTITION_BOOT_ADDRESS WOLFBOOT_PARTITION_UPDATE_ADDRESS \

View File

@ -31,6 +31,7 @@ extern "C" {
/* Initial Attestation message types that distinguish Attest services. */
#define ARM_TEE_ATTEST_GET_TOKEN 1001
#define ARM_TEE_ATTEST_GET_TOKEN_SIZE 1002
#define ARM_TEE_ATTEST_GET_IAK_PUBKEY 1003
#ifdef __cplusplus
}

View File

@ -47,6 +47,17 @@ psa_status_t psa_initial_attest_get_token(const uint8_t *auth_challenge,
psa_status_t psa_initial_attest_get_token_size(size_t challenge_size,
size_t *token_size);
/* This function retrieves the public key for the IAK generated during
* the most recent psa_initial_attest_get_token call. The public key is
* returned in X9.63 uncompressed format (0x04 || X || Y). The internal
* copy of the public key is zeroized after this call (read-once).
* Not available when WOLFBOOT_ATTESTATION_IAK is set (provisioned key is used). */
#ifndef WOLFBOOT_ATTESTATION_IAK
psa_status_t psa_initial_attest_get_iak_pubkey(uint8_t *buf,
size_t buf_size,
size_t *key_len);
#endif /* !WOLFBOOT_ATTESTATION_IAK */
#ifdef __cplusplus
}
#endif

View File

@ -97,3 +97,35 @@ psa_initial_attest_get_token_size(size_t challenge_size,
return status;
}
#ifndef WOLFBOOT_ATTESTATION_IAK
psa_status_t
psa_initial_attest_get_iak_pubkey(uint8_t *buf,
size_t buf_size,
size_t *key_len)
{
psa_status_t status;
if (buf == NULL || key_len == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (buf_size < 65) { /* 65 bytes for uncompressed ECC P-256 public key */
return PSA_ERROR_BUFFER_TOO_SMALL;
}
psa_outvec out_vec[] = {
{ buf, buf_size }
};
printf("[ATTEST-NS] get_iak_pubkey: buf_size=%u\r\n", (unsigned)buf_size);
status = psa_call(ARM_TEE_ATTESTATION_SERVICE_HANDLE,
ARM_TEE_ATTEST_GET_IAK_PUBKEY,
NULL, 0,
out_vec, IOVEC_LEN(out_vec));
printf("[ATTEST-NS] get_iak_pubkey: status=%ld key_len=%u\r\n",
(long)status, (unsigned)out_vec[0].len);
if (status == PSA_SUCCESS) {
*key_len = out_vec[0].len;
}
return status;
}
#endif /* !WOLFBOOT_ATTESTATION_IAK */