Skip to content

Commit 5b43fcc

Browse files
authored
Merge pull request #668 from danielinux/dice
Add support for DICE attestation + PSA attestation
2 parents eddf74c + a20101d commit 5b43fcc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+2792
-82
lines changed

.github/workflows/trustzone-emulator-tests.yml

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
trustzone-emulator-tests:
99
runs-on: ubuntu-latest
1010
container:
11-
image: ghcr.io/danielinux/m33mu-ci:1.2
11+
image: ghcr.io/danielinux/m33mu-ci:1.3
1212
steps:
1313
- uses: actions/checkout@v4
1414

@@ -48,3 +48,20 @@ jobs:
4848
working-directory: test-app/emu-test-apps
4949
run: |
5050
TARGET=stm32l5 ./test.sh
51+
52+
- name: Clean and build test with DICE attestation (stm32h5)
53+
run: |
54+
make clean distclean
55+
cp config/examples/stm32h5-tz-psa.config .config
56+
make
57+
m33mu wolfboot.bin test-app/image_v1_signed.bin:0x60000 --uart-stdout --expect-bkpt 0x7f --timeout 300
58+
59+
- name: Clean and build test with DICE attestation + OTP (stm32h5)
60+
run: |
61+
make clean distclean
62+
cp config/examples/stm32h5-tz-psa-otp.config .config
63+
make
64+
make -C tools/keytools/otp TARGET=stm32h5 otp-keystore-primer.bin otp-keystore-gen
65+
./tools/keytools/otp/otp-keystore-gen
66+
m33mu tools/keytools/otp/otp-keystore-primer.bin --persist --timeout 10 || true
67+
m33mu wolfboot.bin test-app/image_v1_signed.bin:0x60000 --uart-stdout --expect-bkpt 0x7f --timeout 300 --persist

CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,10 @@ set(WOLFBOOT_SOURCES "include/loader.h"
557557
"src/image.c"
558558
"src/loader.c")
559559

560+
if(DEFINED WOLFCRYPT_TZ_PSA AND NOT WOLFCRYPT_TZ_PSA STREQUAL "0")
561+
list(APPEND WOLFBOOT_SOURCES "src/dice/dice.c")
562+
endif()
563+
560564
# build bin-assemble tool Windows
561565
set(BINASSEMBLE ${CMAKE_CURRENT_BINARY_DIR}/bin-assemble${HOST_EXE})
562566
set(BINASSEMBLE_OBJDIR "${CMAKE_CURRENT_BINARY_DIR}/obj_bin_assemble")

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ OBJS:= \
3636
./src/libwolfboot.o \
3737
./hal/hal.o
3838

39+
ifeq ($(WOLFCRYPT_TZ_PSA),1)
40+
OBJS+=./src/dice/dice.o
41+
endif
42+
3943
ifneq ($(TARGET),library)
4044
OBJS+=./hal/$(TARGET).o
4145
endif

config/examples/mcxn-tz.config

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ MCUXPRESSO_CPU?=MCXN947VDF_cm33_core0
1010
MCUXPRESSO_DRIVERS?=$(MCUXPRESSO)/devices/MCX/MCXN/MCXN947
1111
MCUXPRESSO_PROJECT_TEMPLATE?=$(MCUXPRESSO)/examples/_boards/frdmmcxn947/project_template
1212
DEBUG?=0
13-
DEBUG_UART?=1
13+
DEBUG_UART?=0
1414
VTOR?=1
1515
CORTEX_M0?=0
1616
CORTEX_M33?=1
@@ -34,13 +34,13 @@ WOLFBOOT_SECTOR_SIZE?=0x2000
3434

3535
# Default configuration
3636
# 64KB boot, 80KB keyvault, 8KB NSC, 60KB partitions, 8KB swap
37-
WOLFBOOT_KEYVAULT_ADDRESS?=0x10000
37+
WOLFBOOT_KEYVAULT_ADDRESS?=0x12000
3838
WOLFBOOT_KEYVAULT_SIZE?=0x14000
39-
WOLFBOOT_NSC_ADDRESS?=0x24000
39+
WOLFBOOT_NSC_ADDRESS?=0x26000
4040
WOLFBOOT_NSC_SIZE?=0x2000
41-
WOLFBOOT_PARTITION_SIZE?=0xF000
42-
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x26000
43-
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x35000
41+
WOLFBOOT_PARTITION_SIZE?=0xE000
42+
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x28000
43+
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x36000
4444
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x44000
4545

4646
# Alternate larger configuration for debugging or ARMASM
@@ -49,7 +49,7 @@ WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x44000
4949
#WOLFBOOT_KEYVAULT_SIZE?=0x14000
5050
#WOLFBOOT_NSC_ADDRESS?=0x34000
5151
#WOLFBOOT_NSC_SIZE?=0x2000
52-
#WOLFBOOT_PARTITION_SIZE?=0xF000
52+
#WOLFBOOT_PARTITION_SIZE?=0xE000
5353
#WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x36000
5454
#WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x45000
5555
#WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x54000
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
ARCH?=ARM
2+
TZEN?=1
3+
TARGET?=stm32h5
4+
SIGN?=ECC256
5+
IMAGE_HEADER_SIZE?=1024
6+
WOLFBOOT_UNIVERSAL_KEYSTORE=1
7+
HASH?=SHA256
8+
DEBUG?=0
9+
VTOR?=1
10+
CORTEX_M0?=0
11+
CORTEX_M33?=1
12+
NO_ASM?=0
13+
NO_MPU=1
14+
EXT_FLASH?=0
15+
SPI_FLASH?=0
16+
ALLOW_DOWNGRADE?=0
17+
NVM_FLASH_WRITEONCE?=1
18+
WOLFBOOT_VERSION?=1
19+
V?=0
20+
SPMATH?=1
21+
RAM_CODE?=1
22+
DUALBANK_SWAP?=0
23+
WOLFBOOT_PARTITION_SIZE?=0xA0000
24+
WOLFBOOT_SECTOR_SIZE?=0x2000
25+
WOLFBOOT_KEYVAULT_ADDRESS?=0x0C040000
26+
WOLFBOOT_KEYVAULT_SIZE?=0x1C000
27+
WOLFBOOT_NSC_ADDRESS?=0x0C05C000
28+
WOLFBOOT_NSC_SIZE?=0x4000
29+
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08060000
30+
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x0C100000
31+
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x0C1A0000
32+
FLAGS_HOME=0
33+
DISABLE_BACKUP=0
34+
FLASH_OTP_KEYSTORE=1
35+
WOLFCRYPT_TZ=1
36+
WOLFCRYPT_TZ_PSA=1
37+
ARMORED=1
38+
WOLFBOOT_UDS_UID_FALLBACK_FORTEST=0

config/examples/stm32h5-tz-psa.config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,4 @@ WOLFCRYPT_TZ=1
3333
WOLFCRYPT_TZ_PSA=1
3434
IMAGE_HEADER_SIZE?=1024
3535
ARMORED=1
36+
WOLFBOOT_UDS_UID_FALLBACK_FORTEST=1

docs/DICE.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# DICE Attestation
2+
3+
This document describes the DICE-based PSA attestation service in wolfBoot,
4+
including the token format, keying options, and how to access the service from
5+
non-secure code.
6+
7+
## Protocol overview
8+
9+
wolfBoot implements the PSA Certified Attestation API and emits a
10+
COSE_Sign1-wrapped EAT token following the PSA Attestation Token profile.
11+
The minimum claim set includes:
12+
13+
- Nonce binding (challenge).
14+
- Device identity (UEID).
15+
- Implementation ID and lifecycle when available.
16+
- Measured boot components for wolfBoot and the boot image.
17+
18+
The attestation token is produced by the secure world service and signed with
19+
an attestation key derived by DICE or supplied as a provisioned IAK.
20+
21+
## Implementation summary
22+
23+
The implementation lives under `src/dice/` and is shared across targets. The
24+
service is invoked through the PSA Initial Attestation API and builds the
25+
COSE_Sign1 token using a minimal CBOR encoder.
26+
27+
- Claim construction and COSE_Sign1 encoding: `src/dice/dice.c`.
28+
- PSA Initial Attestation service dispatch: `src/arm_tee_psa_ipc.c`.
29+
- NSC wrappers for the PSA Initial Attestation API: `zephyr/src/arm_tee_attest_api.c`.
30+
31+
Measured boot claims reuse the image hashing pipeline already used by
32+
wolfBoot to validate images. Component claims include a measurement type,
33+
measurement value, and a description string.
34+
35+
## Keying model
36+
37+
wolfBoot supports two keying modes selected at build time.
38+
39+
### DICE derived key (default for no provisioning)
40+
41+
- UDS/HUK-derived secret is fetched via `hal_uds_derive_key()`.
42+
- CDI and signing key material are derived deterministically using HKDF.
43+
- The attestation keypair is derived deterministically and used to sign the
44+
COSE_Sign1 payload.
45+
46+
This path requires no external provisioning and binds the attestation key to
47+
UDS plus measured boot material.
48+
49+
### Provisioned IAK
50+
51+
If a platform already provisions an Initial Attestation Key (IAK), wolfBoot
52+
can use it directly to sign the token.
53+
54+
The attestation service calls `hal_attestation_get_iak_private_key()` to
55+
retrieve the private key material from secure storage (or a manufacturer
56+
injection flow). The IAK is used instead of the DICE derived key.
57+
58+
## HAL integration (per-target)
59+
60+
These HAL hooks are optional and have weak stubs for non-TZ boards. Target
61+
families must implement the appropriate subset based on hardware support.
62+
63+
- `hal_uds_derive_key(uint8_t *out, size_t out_len)`
64+
- Returns a device-unique secret (UDS/HUK-derived) for DICE key derivation.
65+
- Test-only fallback: when `WOLFBOOT_UDS_UID_FALLBACK_FORTEST=1`, targets
66+
may derive UDS from the device UID for demo purposes. This should not be
67+
used in production builds.
68+
- HKDF hash selection follows the configured measurement hash; for
69+
`WOLFBOOT_HASH_SHA3_384`, HKDF uses SHA3-384 as well.
70+
- `hal_attestation_get_ueid(uint8_t *buf, size_t *len)`
71+
- Returns a stable UEID. If unavailable, the UEID is derived from UDS.
72+
- `hal_attestation_get_implementation_id(uint8_t *buf, size_t *len)`
73+
- Optional implementation ID for the token.
74+
- `hal_attestation_get_lifecycle(uint32_t *lifecycle)`
75+
- Optional lifecycle state for the token.
76+
- `hal_attestation_get_iak_private_key(uint8_t *buf, size_t *len)`
77+
- Optional provisioned IAK private key (used in IAK mode only).
78+
79+
## STM32H5 OBKeys UDS (optional)
80+
81+
STM32H5 devices provide OBKeys secure storage areas tied to temporal isolation
82+
levels (HDPL). The HDPL1 area is intended for iRoT keys and is the recommended
83+
location for a device-unique UDS when `WOLFBOOT_UDS_OBKEYS=1` is enabled. OBKeys
84+
secure storage is only available on STM32H5 lines except STM32H503.
85+
86+
Provisioning uses STs secure data provisioning flow:
87+
88+
1. Create an OBKeys provisioning file (`.obk`) using STM32TrustedPackageCreator
89+
(CLI supports `-obk <xml>` input).
90+
2. Program the `.obk` file using STM32CubeProgrammer CLI with the `-sdp` option.
91+
92+
3. After provisioning, move the device to the CLOSED state as appropriate for
93+
production.
94+
95+
When `WOLFBOOT_UDS_OBKEYS=1`, the STM32H5 HAL first attempts to read UDS from
96+
OBKeys using a platform hook (`stm32h5_obkeys_read_uds`). Integrate this hook
97+
with your RSSe/RSSLib provisioning flow (DataProvisioning API) as described in
98+
ST documentation.
99+
100+
## NSC access (non-secure API)
101+
102+
The non-secure application calls the PSA Initial Attestation API wrappers:
103+
104+
- `psa_initial_attest_get_token_size()`
105+
- `psa_initial_attest_get_token()`
106+
107+
These are provided in `zephyr/include/psa/initial_attestation.h` and are
108+
implemented as NSC calls in `zephyr/src/arm_tee_attest_api.c`.
109+
110+
When `WOLFCRYPT_TZ_PSA=1`, the NS application can also use PSA Crypto through
111+
`zephyr/include/psa/crypto.h` via the NSC dispatch path
112+
(`zephyr/src/arm_tee_crypto_api.c`). PSA Protected Storage uses
113+
`zephyr/include/psa/protected_storage.h` in the same fashion.
114+
115+
## Test application
116+
117+
The STM32H5 TrustZone test application in `test-app/` exercises PSA crypto,
118+
attestation, and store access. It requests a token at boot and can perform
119+
PSA crypto operations from the non-secure side.
120+
121+
See `docs/Targets.md` for the STM32H5 TrustZone scenarios and how to enable
122+
PSA mode.

docs/STM32-TZ.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,15 @@ The `WOLFCRYPT_TZ_PSA` option provides a standard PSA Crypto interface using
3333
wolfPSA in the secure domain. The key storage uses the same secure flash
3434
keystore backend as PKCS11, exposed through the wolfPSA store API.
3535

36+
### PSA Initial Attestation (DICE)
37+
38+
When `WOLFCRYPT_TZ_PSA=1` is enabled, wolfBoot exposes the PSA Initial
39+
Attestation API to non-secure applications. The attestation token is built
40+
using the DICE flow in `src/dice/` and returned as a COSE_Sign1 token.
41+
42+
See [DICE Attestation](DICE.md) for the full protocol description, HAL hooks
43+
(UDS, UEID, lifecycle, implementation ID), and provisioned IAK support.
44+
3645
### Image header size
3746

3847
The `IMAGE_HEADER_SIZE` option has to be carefully tuned to accommodate for the

docs/Targets.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,6 +1543,10 @@ non-secure callables (NSC).
15431543
15441544
The example configuration for this scenario is available in [/config/examples/stm32h5-tz.config](/config/examples/stm32h5-tz.config).
15451545
1546+
When `WOLFCRYPT_TZ_PSA=1` is enabled, the STM32H5 test application exercises PSA
1547+
Crypto, PSA Protected Storage, and PSA Initial Attestation from the non-secure
1548+
side. See [DICE Attestation](/docs/DICE.md) for details on the attestation flow
1549+
and APIs.
15461550
For more information, see [/docs/STM32-TZ.md](/docs/STM32-TZ.md).
15471551
15481552
### Scenario 3: DUALBANK mode

hal/hal.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "hal.h"
2626
#include "string.h"
2727
#include "printf.h"
28+
#include "wolfboot/wolfboot.h"
2829

2930
/* Test for internal flash erase/write */
3031
/* Use TEST_EXT_FLASH to test ext flash (see spi_flash.c or qspi_flash.c) */
@@ -279,3 +280,37 @@ int hal_flash_test_dualbank(void)
279280
#endif /* DUALBANK_SWAP */
280281

281282
#endif /* TEST_FLASH */
283+
284+
WEAKFUNCTION int hal_uds_derive_key(uint8_t *out, size_t out_len)
285+
{
286+
(void)out;
287+
(void)out_len;
288+
return -1;
289+
}
290+
291+
WEAKFUNCTION int hal_attestation_get_lifecycle(uint32_t *lifecycle)
292+
{
293+
(void)lifecycle;
294+
return -1;
295+
}
296+
297+
WEAKFUNCTION int hal_attestation_get_implementation_id(uint8_t *buf, size_t *len)
298+
{
299+
(void)buf;
300+
(void)len;
301+
return -1;
302+
}
303+
304+
WEAKFUNCTION int hal_attestation_get_ueid(uint8_t *buf, size_t *len)
305+
{
306+
(void)buf;
307+
(void)len;
308+
return -1;
309+
}
310+
311+
WEAKFUNCTION int hal_attestation_get_iak_private_key(uint8_t *buf, size_t *len)
312+
{
313+
(void)buf;
314+
(void)len;
315+
return -1;
316+
}

0 commit comments

Comments
 (0)