From d522c3d4421844f1acab44855eda703ec2d13849 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 22 Jul 2026 20:28:40 -0700 Subject: [PATCH 01/13] Add wolfCOSE as a submodule at lib/wolfCOSE --- .gitmodules | 3 +++ lib/wolfCOSE | 1 + 2 files changed, 4 insertions(+) create mode 160000 lib/wolfCOSE diff --git a/.gitmodules b/.gitmodules index 13396fd2ec..c0a5c290e1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "lib/wolfHAL"] path = lib/wolfHAL url = https://github.com/wolfSSL/wolfHAL.git +[submodule "lib/wolfCOSE"] + path = lib/wolfCOSE + url = https://github.com/wolfSSL/wolfCOSE.git diff --git a/lib/wolfCOSE b/lib/wolfCOSE new file mode 160000 index 0000000000..21bd185709 --- /dev/null +++ b/lib/wolfCOSE @@ -0,0 +1 @@ +Subproject commit 21bd18570934c15880bd73edaca1962c8d68ac04 From 6645acf2e0f6f50d8ea503eb02a47b074bad2fb1 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 22 Jul 2026 20:28:40 -0700 Subject: [PATCH 02/13] Build DICE attestation tokens with wolfCOSE instead of a local CBOR writer --- Makefile | 3 + options.mk | 5 + src/dice/dice.c | 528 +++++++++++++++++------------------------------- 3 files changed, 194 insertions(+), 342 deletions(-) diff --git a/Makefile b/Makefile index a011889aac..d14a96b04b 100644 --- a/Makefile +++ b/Makefile @@ -179,6 +179,7 @@ WOLFBOOT_LIB_WOLFTPM?=lib/wolfTPM WOLFBOOT_LIB_WOLFPKCS11?=lib/wolfPKCS11 WOLFBOOT_LIB_WOLFPSA?=lib/wolfPSA WOLFBOOT_LIB_WOLFHSM?=lib/wolfHSM +WOLFBOOT_LIB_WOLFCOSE?=lib/wolfCOSE # Convert to absolute paths using abspath function WOLFBOOT_LIB_WOLFSSL:=$(abspath $(WOLFBOOT_LIB_WOLFSSL)) @@ -186,6 +187,7 @@ WOLFBOOT_LIB_WOLFTPM:=$(abspath $(WOLFBOOT_LIB_WOLFTPM)) WOLFBOOT_LIB_WOLFPKCS11:=$(abspath $(WOLFBOOT_LIB_WOLFPKCS11)) WOLFBOOT_LIB_WOLFPSA:=$(abspath $(WOLFBOOT_LIB_WOLFPSA)) WOLFBOOT_LIB_WOLFHSM:=$(abspath $(WOLFBOOT_LIB_WOLFHSM)) +WOLFBOOT_LIB_WOLFCOSE:=$(abspath $(WOLFBOOT_LIB_WOLFCOSE)) # Export variables so they are available to sub-makefiles export WOLFBOOT_LIB_WOLFSSL @@ -193,6 +195,7 @@ export WOLFBOOT_LIB_WOLFTPM export WOLFBOOT_LIB_WOLFPKCS11 export WOLFBOOT_LIB_WOLFPSA export WOLFBOOT_LIB_WOLFHSM +export WOLFBOOT_LIB_WOLFCOSE ## Architecture/CPU configuration include arch.mk diff --git a/options.mk b/options.mk index c3d6b75bd6..2d733446a7 100644 --- a/options.mk +++ b/options.mk @@ -1122,6 +1122,9 @@ ifeq ($(WOLFCRYPT_TZ_PSA),1) CFLAGS+=-DWOLFSSL_PSA_ENGINE CFLAGS+=-DWOLFPSA_CUSTOM_STORE CFLAGS+=-DNO_DES3 -DNO_DES3_TLS_SUITES + CFLAGS+=-I$(WOLFBOOT_LIB_WOLFCOSE)/include + CFLAGS+=-DWOLFCOSE_LEAN -DWOLFCOSE_ENABLE_EXT_SIGN + CFLAGS+=-DWOLFCOSE_SIGN1_UNTAGGED WOLFPSA_CFLAGS+=-I$(WOLFBOOT_LIB_WOLFPSA) WOLFPSA_CFLAGS+=-I$(WOLFBOOT_LIB_WOLFPSA)/wolfpsa ifeq ($(USE_CLANG),1) @@ -1135,6 +1138,8 @@ ifeq ($(WOLFCRYPT_TZ_PSA),1) WOLFCRYPT_OBJS+=src/psa_store.o WOLFCRYPT_OBJS+=src/arm_tee_psa_veneer.o WOLFCRYPT_OBJS+=src/arm_tee_psa_ipc.o + WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFCOSE)/src/wolfcose.o + WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFCOSE)/src/wolfcose_cbor.o WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/pwdbased.o WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/hmac.o WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/dh.o diff --git a/src/dice/dice.c b/src/dice/dice.c index 63dd2e0b4b..f265b71c28 100644 --- a/src/dice/dice.c +++ b/src/dice/dice.c @@ -42,6 +42,8 @@ #include #endif +#include + #ifndef PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32 #define PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32 (32u) #define PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48 (48u) @@ -76,9 +78,6 @@ static NOINLINEFUNCTION void wolfboot_dice_zeroize(void *ptr, size_t len) } } -#define COSE_LABEL_ALG 1 -#define COSE_ALG_ES256 (-7) - #define EAT_CLAIM_NONCE 10 #define EAT_CLAIM_UEID 256 @@ -130,145 +129,6 @@ struct wolfboot_dice_claims { size_t component_count; }; -struct wolfboot_cbor_writer { - uint8_t *buf; - size_t size; - size_t offset; - int error; -}; - -static void wolfboot_cbor_init(struct wolfboot_cbor_writer *w, - uint8_t *buf, - size_t size) -{ - w->buf = buf; - w->size = size; - w->offset = 0; - w->error = 0; -} - -static void wolfboot_cbor_reserve(struct wolfboot_cbor_writer *w, size_t len) -{ - if (w->error != 0) { - return; - } - if (w->buf == NULL || w->size == 0) { - w->offset += len; - return; - } - if (w->offset + len > w->size) { - w->error = WOLFBOOT_DICE_ERR_BUFFER_TOO_SMALL; - return; - } - w->offset += len; -} - -static void wolfboot_cbor_put_type_val(struct wolfboot_cbor_writer *w, - uint8_t major, - uint64_t val) -{ - uint8_t tmp[9]; - size_t len = 0; - - if (val <= 23) { - tmp[len++] = (uint8_t)((major << 5) | (uint8_t)val); - } - else if (val <= 0xFF) { - tmp[len++] = (uint8_t)((major << 5) | 24); - tmp[len++] = (uint8_t)val; - } - else if (val <= 0xFFFF) { - tmp[len++] = (uint8_t)((major << 5) | 25); - tmp[len++] = (uint8_t)(val >> 8); - tmp[len++] = (uint8_t)(val & 0xFF); - } - else if (val <= 0xFFFFFFFFu) { - tmp[len++] = (uint8_t)((major << 5) | 26); - tmp[len++] = (uint8_t)(val >> 24); - tmp[len++] = (uint8_t)(val >> 16); - tmp[len++] = (uint8_t)(val >> 8); - tmp[len++] = (uint8_t)(val & 0xFF); - } - else { - tmp[len++] = (uint8_t)((major << 5) | 27); - tmp[len++] = (uint8_t)(val >> 56); - tmp[len++] = (uint8_t)(val >> 48); - tmp[len++] = (uint8_t)(val >> 40); - tmp[len++] = (uint8_t)(val >> 32); - tmp[len++] = (uint8_t)(val >> 24); - tmp[len++] = (uint8_t)(val >> 16); - tmp[len++] = (uint8_t)(val >> 8); - tmp[len++] = (uint8_t)(val & 0xFF); - } - - wolfboot_cbor_reserve(w, len); - if (w->error != 0) { - return; - } - if (w->buf == NULL || w->size == 0) { - return; - } - XMEMCPY(w->buf + (w->offset - len), tmp, len); -} - -static void wolfboot_cbor_put_uint(struct wolfboot_cbor_writer *w, uint64_t val) -{ - wolfboot_cbor_put_type_val(w, 0, val); -} - -static void wolfboot_cbor_put_int(struct wolfboot_cbor_writer *w, int64_t val) -{ - if (val >= 0) { - wolfboot_cbor_put_uint(w, (uint64_t)val); - } - else { - uint64_t n = (uint64_t)(-1 - val); - wolfboot_cbor_put_type_val(w, 1, n); - } -} - -static void wolfboot_cbor_put_bstr(struct wolfboot_cbor_writer *w, - const uint8_t *data, - size_t len) -{ - wolfboot_cbor_put_type_val(w, 2, len); - wolfboot_cbor_reserve(w, len); - if (w->error != 0) { - return; - } - if (w->buf == NULL || w->size == 0) { - return; - } - XMEMCPY(w->buf + (w->offset - len), data, len); -} - -static void wolfboot_cbor_put_tstr(struct wolfboot_cbor_writer *w, - const char *data, - size_t len) -{ - wolfboot_cbor_put_type_val(w, 3, len); - wolfboot_cbor_reserve(w, len); - if (w->error != 0) { - return; - } - if (w->buf == NULL || w->size == 0) { - return; - } - XMEMCPY(w->buf + (w->offset - len), data, len); -} - -static void wolfboot_cbor_put_array_start(struct wolfboot_cbor_writer *w, - size_t count) -{ - wolfboot_cbor_put_type_val(w, 4, count); -} - -static void wolfboot_cbor_put_map_start(struct wolfboot_cbor_writer *w, - size_t count) -{ - wolfboot_cbor_put_type_val(w, 5, count); -} - static int wolfboot_hash_region(uintptr_t address, uint32_t size, uint8_t *out) { #if defined(WOLFBOOT_HASH_SHA256) @@ -750,6 +610,11 @@ static int wolfboot_attest_get_private_key(ecc_key *key, key, ECC_SECP256R1) != 0) { goto cleanup; } + /* Import leaves the key ECC_PRIVATEKEY_ONLY; wolfCOSE treats a key as + * sign-capable only once the public point is present. */ + if (wc_ecc_make_pub(key, NULL) != 0) { + goto cleanup; + } ret = 0; cleanup: @@ -773,9 +638,10 @@ static int wolfboot_dice_encode_payload(uint8_t *buf, const struct wolfboot_dice_claims *claims, size_t *payload_len) { - struct wolfboot_cbor_writer w; + WOLFCOSE_CBOR_CTX ctx; size_t map_count = 2; size_t i; + int ret; if (claims->implementation_id_len > 0) { map_count++; @@ -787,194 +653,245 @@ static int wolfboot_dice_encode_payload(uint8_t *buf, map_count++; } - wolfboot_cbor_init(&w, buf, buf_len); - wolfboot_cbor_put_map_start(&w, map_count); + XMEMSET(&ctx, 0, sizeof(ctx)); + ctx.buf = buf; + ctx.bufSz = buf_len; - wolfboot_cbor_put_int(&w, EAT_CLAIM_NONCE); - wolfboot_cbor_put_bstr(&w, claims->challenge, claims->challenge_len); - - wolfboot_cbor_put_int(&w, EAT_CLAIM_UEID); - wolfboot_cbor_put_bstr(&w, claims->ueid, claims->ueid_len); + ret = wc_CBOR_EncodeMapStart(&ctx, map_count); + if (ret == 0) { + ret = wc_CBOR_EncodeInt(&ctx, EAT_CLAIM_NONCE); + } + if (ret == 0) { + ret = wc_CBOR_EncodeBstr(&ctx, claims->challenge, claims->challenge_len); + } + if (ret == 0) { + ret = wc_CBOR_EncodeInt(&ctx, EAT_CLAIM_UEID); + } + if (ret == 0) { + ret = wc_CBOR_EncodeBstr(&ctx, claims->ueid, claims->ueid_len); + } - if (claims->implementation_id_len > 0) { - wolfboot_cbor_put_int(&w, PSA_IAT_CLAIM_IMPLEMENTATION_ID); - wolfboot_cbor_put_bstr(&w, - claims->implementation_id, - claims->implementation_id_len); + if ((ret == 0) && (claims->implementation_id_len > 0)) { + ret = wc_CBOR_EncodeInt(&ctx, PSA_IAT_CLAIM_IMPLEMENTATION_ID); + if (ret == 0) { + ret = wc_CBOR_EncodeBstr(&ctx, claims->implementation_id, + claims->implementation_id_len); + } } - if (claims->has_lifecycle) { - wolfboot_cbor_put_int(&w, PSA_IAT_CLAIM_LIFECYCLE); - wolfboot_cbor_put_uint(&w, claims->lifecycle); + if ((ret == 0) && claims->has_lifecycle) { + ret = wc_CBOR_EncodeInt(&ctx, PSA_IAT_CLAIM_LIFECYCLE); + if (ret == 0) { + ret = wc_CBOR_EncodeUint(&ctx, claims->lifecycle); + } } - if (claims->component_count > 0) { - wolfboot_cbor_put_int(&w, PSA_IAT_CLAIM_SW_COMPONENTS); - wolfboot_cbor_put_array_start(&w, claims->component_count); - for (i = 0; i < claims->component_count; i++) { - wolfboot_cbor_put_map_start(&w, 3); - wolfboot_cbor_put_uint(&w, PSA_SW_COMPONENT_MEASUREMENT_TYPE); - wolfboot_cbor_put_tstr(&w, - claims->components[i].measurement_type, - claims->components[i].measurement_type_len); - wolfboot_cbor_put_uint(&w, PSA_SW_COMPONENT_MEASUREMENT_VALUE); - wolfboot_cbor_put_bstr(&w, - claims->components[i].measurement, - claims->components[i].measurement_len); - wolfboot_cbor_put_uint(&w, PSA_SW_COMPONENT_MEASUREMENT_DESCRIPTION); - wolfboot_cbor_put_tstr(&w, - claims->components[i].measurement_desc, - claims->components[i].measurement_desc_len); + if ((ret == 0) && (claims->component_count > 0)) { + ret = wc_CBOR_EncodeInt(&ctx, PSA_IAT_CLAIM_SW_COMPONENTS); + if (ret == 0) { + ret = wc_CBOR_EncodeArrayStart(&ctx, claims->component_count); + } + for (i = 0; (ret == 0) && (i < claims->component_count); i++) { + ret = wc_CBOR_EncodeMapStart(&ctx, 3); + if (ret == 0) { + ret = wc_CBOR_EncodeUint(&ctx, + PSA_SW_COMPONENT_MEASUREMENT_TYPE); + } + if (ret == 0) { + ret = wc_CBOR_EncodeTstr(&ctx, + (const uint8_t *)claims->components[i].measurement_type, + claims->components[i].measurement_type_len); + } + if (ret == 0) { + ret = wc_CBOR_EncodeUint(&ctx, + PSA_SW_COMPONENT_MEASUREMENT_VALUE); + } + if (ret == 0) { + ret = wc_CBOR_EncodeBstr(&ctx, + claims->components[i].measurement, + claims->components[i].measurement_len); + } + if (ret == 0) { + ret = wc_CBOR_EncodeUint(&ctx, + PSA_SW_COMPONENT_MEASUREMENT_DESCRIPTION); + } + if (ret == 0) { + ret = wc_CBOR_EncodeTstr(&ctx, + (const uint8_t *)claims->components[i].measurement_desc, + claims->components[i].measurement_desc_len); + } } } - if (w.error != 0) { - return w.error; + if (ret != 0) { + return WOLFBOOT_DICE_ERR_BUFFER_TOO_SMALL; } - *payload_len = w.offset; + *payload_len = ctx.idx; return 0; } -static int wolfboot_dice_encode_protected(uint8_t *buf, - size_t buf_len, - size_t *prot_len) +#ifdef WOLFBOOT_DICE_HW +static int wolfboot_dice_hw_sign_cb(void *cbCtx, int32_t alg, + const uint8_t *tbs, size_t tbs_len, + uint8_t *sig, size_t sig_sz, + size_t *sig_len) { - struct wolfboot_cbor_writer w; + size_t out_len = sig_sz; - wolfboot_cbor_init(&w, buf, buf_len); - wolfboot_cbor_put_map_start(&w, 1); - wolfboot_cbor_put_uint(&w, COSE_LABEL_ALG); - wolfboot_cbor_put_int(&w, COSE_ALG_ES256); + (void)cbCtx; + (void)alg; - if (w.error != 0) { - return w.error; + /* wolfCOSE pre-hashes the Sig_structure for ES256, so tbs is the 32-byte + * digest. hal_dice_sign_hash() outputs 64-byte raw R||S and keeps the + * private key inside the platform boundary. */ + if (hal_dice_sign_hash(tbs, tbs_len, sig, &out_len) != 0) { + return -1; } - - *prot_len = w.offset; + *sig_len = out_len; return 0; } +#endif /* WOLFBOOT_DICE_HW */ -static int wolfboot_dice_build_sig_structure(uint8_t *buf, - size_t buf_len, - const uint8_t *prot, - size_t prot_len, - const uint8_t *payload, - size_t payload_len, - size_t *tbs_len) +static int wolfboot_dice_encode_untagged_size(uint8_t *buf, + size_t buf_len, + const uint8_t *payload, + size_t payload_len, + size_t *out_len) { - struct wolfboot_cbor_writer w; + static const uint8_t protected_es256[3] = { 0xA1, 0x01, 0x26 }; + uint8_t zero_sig[WOLFBOOT_DICE_SIG_LEN]; + WOLFCOSE_CBOR_CTX ctx; + int ret; - wolfboot_cbor_init(&w, buf, buf_len); - wolfboot_cbor_put_array_start(&w, 4); - wolfboot_cbor_put_tstr(&w, "Signature1", 10); - wolfboot_cbor_put_bstr(&w, prot, prot_len); - wolfboot_cbor_put_bstr(&w, (const uint8_t *)"", 0); - wolfboot_cbor_put_bstr(&w, payload, payload_len); + XMEMSET(zero_sig, 0, sizeof(zero_sig)); + XMEMSET(&ctx, 0, sizeof(ctx)); + ctx.buf = buf; + ctx.bufSz = buf_len; - if (w.error != 0) { - return w.error; + ret = wc_CBOR_EncodeArrayStart(&ctx, 4); + if (ret == 0) { + ret = wc_CBOR_EncodeBstr(&ctx, protected_es256, sizeof(protected_es256)); + } + if (ret == 0) { + ret = wc_CBOR_EncodeMapStart(&ctx, 0); + } + if (ret == 0) { + ret = wc_CBOR_EncodeBstr(&ctx, payload, payload_len); + } + if (ret == 0) { + ret = wc_CBOR_EncodeBstr(&ctx, zero_sig, sizeof(zero_sig)); + } + if (ret != 0) { + return WOLFBOOT_DICE_ERR_BUFFER_TOO_SMALL; } - *tbs_len = w.offset; + *out_len = ctx.idx; return 0; } -static int wolfboot_dice_sign_tbs(const uint8_t *tbs, - size_t tbs_len, - uint8_t *sig, - size_t *sig_len, - const struct wolfboot_dice_claims *claims) +static int wolfboot_dice_build_token(uint8_t *token_buf, + size_t token_buf_size, + size_t *token_len, + const uint8_t *challenge, + size_t challenge_len) { - int ret = WOLFBOOT_DICE_ERR_CRYPTO; - uint8_t hash[SHA256_DIGEST_SIZE]; + struct wolfboot_dice_claims claims; + uint8_t payload[WOLFBOOT_DICE_MAX_PAYLOAD]; + size_t payload_len = 0; + uint8_t scratch[WOLFBOOT_DICE_MAX_TBS]; + WOLFCOSE_KEY cose_key; + int cose_key_inited = 0; + size_t out_len = 0; + int ret; #ifndef WOLFBOOT_DICE_HW ecc_key key; - int key_inited = 0; WC_RNG rng; - int wc_ret; + int key_inited = 0; 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; + ret = wolfboot_dice_collect_claims(&claims); + if (ret != 0) { + return ret; } + claims.challenge = challenge; + claims.challenge_len = challenge_len; + + ret = wolfboot_dice_encode_payload(payload, sizeof(payload), &claims, + &payload_len); + if (ret != 0) { + goto cleanup; + } + + /* Size query returns the exact untagged COSE_Sign1 length without signing: + * the HW DICE engine must not run and the CDI must not advance while sizing. */ + if (token_buf == NULL) { + ret = wolfboot_dice_encode_untagged_size(scratch, sizeof(scratch), + payload, payload_len, &out_len); + if (ret == 0) { + *token_len = out_len; + } + goto cleanup; + } + + ret = wc_CoseKey_Init(&cose_key); + if (ret != 0) { + ret = WOLFBOOT_DICE_ERR_CRYPTO; + goto cleanup; + } + cose_key_inited = 1; + #ifdef WOLFBOOT_DICE_HW - if (wolfboot_attest_get_private_key_hw(claims) != 0) { + if (wolfboot_attest_get_private_key_hw(&claims) != 0) { ret = WOLFBOOT_DICE_ERR_HW; goto cleanup; } + ret = wc_CoseKey_SetExtSigner(&cose_key, wolfboot_dice_hw_sign_cb, NULL); + if (ret != 0) { + ret = WOLFBOOT_DICE_ERR_CRYPTO; + goto cleanup; + } + ret = wc_CoseSign1_Sign(&cose_key, WOLFCOSE_ALG_ES256, NULL, 0, + payload, payload_len, NULL, 0, NULL, 0, + scratch, sizeof(scratch), + token_buf, token_buf_size, &out_len, NULL); #else wc_ecc_init(&key); key_inited = 1; - if (wolfboot_attest_get_private_key(&key, claims) != 0) { + 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; - 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 = wc_CoseKey_SetEcc(&cose_key, WOLFCOSE_CRV_P256, &key); + if (ret != 0) { ret = WOLFBOOT_DICE_ERR_CRYPTO; goto cleanup; } - - wc_ret = wc_ecc_sig_to_rs(der_sig, der_sig_len, r, &r_len, s, &s_len); - if (wc_ret != 0 || r_len > sizeof(r) || s_len > sizeof(s)) { + ret = wc_CoseSign1_Sign(&cose_key, WOLFCOSE_ALG_ES256, NULL, 0, + payload, payload_len, NULL, 0, NULL, 0, + scratch, sizeof(scratch), + token_buf, token_buf_size, &out_len, &rng); +#endif /* WOLFBOOT_DICE_HW */ + if (ret != 0) { ret = WOLFBOOT_DICE_ERR_CRYPTO; goto cleanup; } - XMEMSET(sig, 0, WOLFBOOT_DICE_SIG_LEN); - XMEMCPY(sig + (sizeof(r) - r_len), r, r_len); - XMEMCPY(sig + sizeof(r) + (sizeof(s) - s_len), s, s_len); - *sig_len = WOLFBOOT_DICE_SIG_LEN; + *token_len = out_len; ret = WOLFBOOT_DICE_SUCCESS; -#endif /* !WOLFBOOT_DICE_HW */ cleanup: + if (cose_key_inited) { + wc_CoseKey_Free(&cose_key); + } #ifndef WOLFBOOT_DICE_HW if (key_inited) { wc_ecc_free(&key); @@ -983,85 +900,12 @@ static int wolfboot_dice_sign_tbs(const uint8_t *tbs, if (rng_inited) { wc_FreeRng(&rng); } - wolfboot_dice_zeroize(der_sig, sizeof(der_sig)); #endif /* !WOLFBOOT_DICE_HW */ - wolfboot_dice_zeroize(hash, sizeof(hash)); + wolfboot_dice_zeroize(payload, sizeof(payload)); + wolfboot_dice_zeroize(scratch, sizeof(scratch)); return ret; } -static int wolfboot_dice_build_token(uint8_t *token_buf, - size_t token_buf_size, - size_t *token_len, - const uint8_t *challenge, - size_t challenge_len) -{ - struct wolfboot_dice_claims claims; - uint8_t payload[WOLFBOOT_DICE_MAX_PAYLOAD]; - size_t payload_len = 0; - uint8_t protected_hdr[32]; - size_t protected_len = 0; - uint8_t tbs[WOLFBOOT_DICE_MAX_TBS]; - size_t tbs_len = 0; - uint8_t sig[WOLFBOOT_DICE_SIG_LEN]; - size_t sig_len = sizeof(sig); - struct wolfboot_cbor_writer w; - int ret; - - ret = wolfboot_dice_collect_claims(&claims); - if (ret != 0) { - return ret; - } - - claims.challenge = challenge; - claims.challenge_len = challenge_len; - - ret = wolfboot_dice_encode_payload(payload, sizeof(payload), &claims, - &payload_len); - if (ret != 0) { - return ret; - } - - ret = wolfboot_dice_encode_protected(protected_hdr, sizeof(protected_hdr), - &protected_len); - if (ret != 0) { - return ret; - } - - ret = wolfboot_dice_build_sig_structure(tbs, sizeof(tbs), - protected_hdr, protected_len, - payload, payload_len, &tbs_len); - if (ret != 0) { - return ret; - } - - if (token_buf != NULL) { - ret = wolfboot_dice_sign_tbs(tbs, tbs_len, sig, &sig_len, &claims); - if (ret != 0) { - return ret; - } - } - - wolfboot_cbor_init(&w, token_buf, token_buf_size); - wolfboot_cbor_put_array_start(&w, 4); - wolfboot_cbor_put_bstr(&w, protected_hdr, protected_len); - wolfboot_cbor_put_map_start(&w, 0); - wolfboot_cbor_put_bstr(&w, payload, payload_len); - if (token_buf != NULL) { - wolfboot_cbor_put_bstr(&w, sig, sig_len); - } - else { - wolfboot_cbor_put_type_val(&w, 2, WOLFBOOT_DICE_SIG_LEN); - wolfboot_cbor_reserve(&w, WOLFBOOT_DICE_SIG_LEN); - } - - if (w.error != 0) { - return w.error; - } - - *token_len = w.offset; - return WOLFBOOT_DICE_SUCCESS; -} - int wolfBoot_dice_get_token(const uint8_t *challenge, size_t challenge_size, uint8_t *token_buf, From fb5c373e316742bf34cc7aa1c0fdd38877a78afe Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 22 Jul 2026 20:28:40 -0700 Subject: [PATCH 03/13] Read the STM32H5 unique device ID from 0x08FFF800 for DICE UDS derivation --- hal/stm32h5.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/hal/stm32h5.c b/hal/stm32h5.c index 3a2da3790e..5cd6b5f947 100644 --- a/hal/stm32h5.c +++ b/hal/stm32h5.c @@ -167,10 +167,11 @@ int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len) return 0; } -#define STM32H5_BSEC_BASE 0x46009000u -#define STM32H5_BSEC_UID0 (*(volatile uint32_t *)(STM32H5_BSEC_BASE + 0x14)) -#define STM32H5_BSEC_UID1 (*(volatile uint32_t *)(STM32H5_BSEC_BASE + 0x18)) -#define STM32H5_BSEC_UID2 (*(volatile uint32_t *)(STM32H5_BSEC_BASE + 0x1C)) +/* STM32H5 96-bit unique device ID, factory-programmed (RM0481). */ +#define STM32H5_UID_BASE 0x08FFF800u +#define STM32H5_UID0 (*(volatile uint32_t *)(STM32H5_UID_BASE + 0x0u)) +#define STM32H5_UID1 (*(volatile uint32_t *)(STM32H5_UID_BASE + 0x4u)) +#define STM32H5_UID2 (*(volatile uint32_t *)(STM32H5_UID_BASE + 0x8u)) #ifdef WOLFBOOT_UDS_OBKEYS __attribute__((weak)) int stm32h5_obkeys_read_uds(uint8_t *out, size_t out_len) @@ -205,18 +206,18 @@ static int uds_from_uid(uint8_t *out, size_t out_len) #endif size_t copy_len; - uid[0] = (uint8_t)(STM32H5_BSEC_UID0 >> 0); - uid[1] = (uint8_t)(STM32H5_BSEC_UID0 >> 8); - uid[2] = (uint8_t)(STM32H5_BSEC_UID0 >> 16); - uid[3] = (uint8_t)(STM32H5_BSEC_UID0 >> 24); - uid[4] = (uint8_t)(STM32H5_BSEC_UID1 >> 0); - uid[5] = (uint8_t)(STM32H5_BSEC_UID1 >> 8); - uid[6] = (uint8_t)(STM32H5_BSEC_UID1 >> 16); - uid[7] = (uint8_t)(STM32H5_BSEC_UID1 >> 24); - uid[8] = (uint8_t)(STM32H5_BSEC_UID2 >> 0); - uid[9] = (uint8_t)(STM32H5_BSEC_UID2 >> 8); - uid[10] = (uint8_t)(STM32H5_BSEC_UID2 >> 16); - uid[11] = (uint8_t)(STM32H5_BSEC_UID2 >> 24); + uid[0] = (uint8_t)(STM32H5_UID0 >> 0); + uid[1] = (uint8_t)(STM32H5_UID0 >> 8); + uid[2] = (uint8_t)(STM32H5_UID0 >> 16); + uid[3] = (uint8_t)(STM32H5_UID0 >> 24); + uid[4] = (uint8_t)(STM32H5_UID1 >> 0); + uid[5] = (uint8_t)(STM32H5_UID1 >> 8); + uid[6] = (uint8_t)(STM32H5_UID1 >> 16); + uid[7] = (uint8_t)(STM32H5_UID1 >> 24); + uid[8] = (uint8_t)(STM32H5_UID2 >> 0); + uid[9] = (uint8_t)(STM32H5_UID2 >> 8); + uid[10] = (uint8_t)(STM32H5_UID2 >> 16); + uid[11] = (uint8_t)(STM32H5_UID2 >> 24); #if defined(WOLFBOOT_HASH_SHA256) wc_InitSha256(&hash); From ba6c1d9fe337e28bf7673bea68b471efc3dbd9a0 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 22 Jul 2026 21:09:30 -0700 Subject: [PATCH 04/13] Wire wolfCOSE into the CMake WOLFCRYPT_TZ_PSA build path --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 344cc21d52..4f214d6475 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -566,6 +566,11 @@ endif() if(DEFINED WOLFCRYPT_TZ_PSA AND NOT WOLFCRYPT_TZ_PSA STREQUAL "0") list(APPEND WOLFBOOT_SOURCES "src/dice/dice.c") + list(APPEND WOLFBOOT_SOURCES "lib/wolfCOSE/src/wolfcose.c") + list(APPEND WOLFBOOT_SOURCES "lib/wolfCOSE/src/wolfcose_cbor.c") + list(APPEND WOLFBOOT_INCLUDE_DIRS ${WOLFBOOT_ROOT}/lib/wolfCOSE/include) + list(APPEND WOLFBOOT_DEFS WOLFCOSE_LEAN WOLFCOSE_ENABLE_EXT_SIGN + WOLFCOSE_SIGN1_UNTAGGED) endif() # build bin-assemble tool Windows From 1dec1b33839def1217f8658bbbbdc73e89c98e9b Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Mon, 27 Jul 2026 14:09:15 -0700 Subject: [PATCH 05/13] Assert DICE attestation output in the trustzone emulator test --- .github/workflows/trustzone-emulator-tests.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/trustzone-emulator-tests.yml b/.github/workflows/trustzone-emulator-tests.yml index aabfdcbe1d..20f6bee8ec 100644 --- a/.github/workflows/trustzone-emulator-tests.yml +++ b/.github/workflows/trustzone-emulator-tests.yml @@ -104,7 +104,13 @@ jobs: make clean distclean cp config/examples/stm32h5-tz-psa.config .config make - m33mu wolfboot.bin test-app/image_v1_signed.bin:0x60000 --uart-stdout --expect-bkpt 0x7f --timeout 600 + m33mu wolfboot.bin test-app/image_v1_signed.bin:0x60000 --uart-stdout --expect-bkpt 0x7f --timeout 600 \ + | tee /tmp/m33mu-dice.log + grep -q "get_token_size: status=0 size=" /tmp/m33mu-dice.log + grep -q "get_token: status=0 len=" /tmp/m33mu-dice.log + grep -q "PSA boot attestation: success" /tmp/m33mu-dice.log + grep -q "\\[BKPT\\] imm=0x7f" /tmp/m33mu-dice.log + grep -q "\\[EXPECT BKPT\\] Success" /tmp/m33mu-dice.log - name: Clean and build test with fwTPM (stm32h5) run: | From 2f52e07e0e9af29930734bf81a8e6c621df92ed5 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Mon, 27 Jul 2026 14:13:39 -0700 Subject: [PATCH 06/13] Build m33mu from danielinux/m33mu#10 in the trustzone emulator test --- .github/workflows/trustzone-emulator-tests.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/trustzone-emulator-tests.yml b/.github/workflows/trustzone-emulator-tests.yml index 20f6bee8ec..758c0884a8 100644 --- a/.github/workflows/trustzone-emulator-tests.yml +++ b/.github/workflows/trustzone-emulator-tests.yml @@ -17,6 +17,16 @@ jobs: git config --global --add safe.directory "$GITHUB_WORKSPACE" git submodule update --init --single-branch + # TEMPORARY: revert once danielinux/m33mu#10 merges and wolfboot-ci rebuilds. + - name: Build m33mu from danielinux/m33mu#10 + run: | + git clone --depth 1 https://github.com/danielinux/m33mu.git /tmp/m33mu-pr + git -C /tmp/m33mu-pr fetch --depth 1 origin pull/10/head:pr10 + git -C /tmp/m33mu-pr checkout pr10 + cmake -S /tmp/m33mu-pr -B /tmp/m33mu-pr/build -DCMAKE_BUILD_TYPE=Release + cmake --build /tmp/m33mu-pr/build -j"$(nproc)" + install -m 0755 /tmp/m33mu-pr/build/m33mu "$(command -v m33mu)" + - name: Configure stm32h5 (TZ) and build wolfboot run: | cp config/examples/stm32h5-tz.config .config From a7c02cd8103faad1e845b3775fc8bba1165ab79f Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Mon, 27 Jul 2026 14:25:35 -0700 Subject: [PATCH 07/13] Revert the temporary m33mu PR build step --- .github/workflows/trustzone-emulator-tests.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.github/workflows/trustzone-emulator-tests.yml b/.github/workflows/trustzone-emulator-tests.yml index 758c0884a8..20f6bee8ec 100644 --- a/.github/workflows/trustzone-emulator-tests.yml +++ b/.github/workflows/trustzone-emulator-tests.yml @@ -17,16 +17,6 @@ jobs: git config --global --add safe.directory "$GITHUB_WORKSPACE" git submodule update --init --single-branch - # TEMPORARY: revert once danielinux/m33mu#10 merges and wolfboot-ci rebuilds. - - name: Build m33mu from danielinux/m33mu#10 - run: | - git clone --depth 1 https://github.com/danielinux/m33mu.git /tmp/m33mu-pr - git -C /tmp/m33mu-pr fetch --depth 1 origin pull/10/head:pr10 - git -C /tmp/m33mu-pr checkout pr10 - cmake -S /tmp/m33mu-pr -B /tmp/m33mu-pr/build -DCMAKE_BUILD_TYPE=Release - cmake --build /tmp/m33mu-pr/build -j"$(nproc)" - install -m 0755 /tmp/m33mu-pr/build/m33mu "$(command -v m33mu)" - - name: Configure stm32h5 (TZ) and build wolfboot run: | cp config/examples/stm32h5-tz.config .config From c74f277a41efa3af2b7c8eaa5aee012f38a520fc Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Mon, 27 Jul 2026 14:39:00 -0700 Subject: [PATCH 08/13] Keep the DICE signing objects out of the token builder frame --- src/dice/dice.c | 96 ++++++++++++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 36 deletions(-) diff --git a/src/dice/dice.c b/src/dice/dice.c index f265b71c28..4201cf663a 100644 --- a/src/dice/dice.c +++ b/src/dice/dice.c @@ -790,6 +790,63 @@ static int wolfboot_dice_encode_untagged_size(uint8_t *buf, return 0; } +#ifndef WOLFBOOT_DICE_HW +/* Kept out of line so the secure-world sign path does not widen the caller's + * frame, which the size query also pays for. */ +static int NOINLINEFUNCTION wolfboot_dice_sign_payload( + WOLFCOSE_KEY *cose_key, + struct wolfboot_dice_claims *claims, + const uint8_t *payload, + size_t payload_len, + uint8_t *scratch, + size_t scratch_len, + uint8_t *token_buf, + size_t token_buf_size, + size_t *out_len) +{ + ecc_key key; + WC_RNG rng; + int key_inited = 0; + int rng_inited = 0; + int ret; + + wc_ecc_init(&key); + key_inited = 1; + if (wolfboot_attest_get_private_key(&key, claims) != 0) { + ret = WOLFBOOT_DICE_ERR_HW; + goto cleanup; + } + (void)wc_ecc_set_deterministic(&key, 1); + if (wc_InitRng(&rng) != 0) { + ret = WOLFBOOT_DICE_ERR_HW; + goto cleanup; + } + rng_inited = 1; + ret = wc_CoseKey_SetEcc(cose_key, WOLFCOSE_CRV_P256, &key); + if (ret != 0) { + ret = WOLFBOOT_DICE_ERR_CRYPTO; + goto cleanup; + } + ret = wc_CoseSign1_Sign(cose_key, WOLFCOSE_ALG_ES256, NULL, 0, + payload, payload_len, NULL, 0, NULL, 0, + scratch, scratch_len, + token_buf, token_buf_size, out_len, &rng); + if (ret != 0) { + ret = WOLFBOOT_DICE_ERR_CRYPTO; + } + +cleanup: + if (key_inited) { + wc_ecc_free(&key); + wolfboot_dice_zeroize(&key, sizeof(key)); + } + if (rng_inited) { + wc_FreeRng(&rng); + } + return ret; +} +#endif /* !WOLFBOOT_DICE_HW */ + static int wolfboot_dice_build_token(uint8_t *token_buf, size_t token_buf_size, size_t *token_len, @@ -804,12 +861,6 @@ static int wolfboot_dice_build_token(uint8_t *token_buf, int cose_key_inited = 0; size_t out_len = 0; int ret; -#ifndef WOLFBOOT_DICE_HW - ecc_key key; - WC_RNG rng; - int key_inited = 0; - int rng_inited = 0; -#endif /* !WOLFBOOT_DICE_HW */ ret = wolfboot_dice_collect_claims(&claims); if (ret != 0) { @@ -858,27 +909,9 @@ static int wolfboot_dice_build_token(uint8_t *token_buf, scratch, sizeof(scratch), token_buf, token_buf_size, &out_len, NULL); #else - wc_ecc_init(&key); - key_inited = 1; - if (wolfboot_attest_get_private_key(&key, &claims) != 0) { - ret = WOLFBOOT_DICE_ERR_HW; - goto cleanup; - } - (void)wc_ecc_set_deterministic(&key, 1); - if (wc_InitRng(&rng) != 0) { - ret = WOLFBOOT_DICE_ERR_HW; - goto cleanup; - } - rng_inited = 1; - ret = wc_CoseKey_SetEcc(&cose_key, WOLFCOSE_CRV_P256, &key); - if (ret != 0) { - ret = WOLFBOOT_DICE_ERR_CRYPTO; - goto cleanup; - } - ret = wc_CoseSign1_Sign(&cose_key, WOLFCOSE_ALG_ES256, NULL, 0, - payload, payload_len, NULL, 0, NULL, 0, - scratch, sizeof(scratch), - token_buf, token_buf_size, &out_len, &rng); + ret = wolfboot_dice_sign_payload(&cose_key, &claims, payload, payload_len, + scratch, sizeof(scratch), + token_buf, token_buf_size, &out_len); #endif /* WOLFBOOT_DICE_HW */ if (ret != 0) { ret = WOLFBOOT_DICE_ERR_CRYPTO; @@ -892,15 +925,6 @@ static int wolfboot_dice_build_token(uint8_t *token_buf, if (cose_key_inited) { wc_CoseKey_Free(&cose_key); } -#ifndef WOLFBOOT_DICE_HW - if (key_inited) { - wc_ecc_free(&key); - wolfboot_dice_zeroize(&key, sizeof(key)); - } - if (rng_inited) { - wc_FreeRng(&rng); - } -#endif /* !WOLFBOOT_DICE_HW */ wolfboot_dice_zeroize(payload, sizeof(payload)); wolfboot_dice_zeroize(scratch, sizeof(scratch)); return ret; From 902995cc7bb9d76bced115d7bb32f74ce9b95fe3 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Tue, 28 Jul 2026 09:05:06 -0700 Subject: [PATCH 09/13] Build a pinned m33mu in the trustzone emulator test --- .github/workflows/trustzone-emulator-tests.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/trustzone-emulator-tests.yml b/.github/workflows/trustzone-emulator-tests.yml index 20f6bee8ec..0328a32ea3 100644 --- a/.github/workflows/trustzone-emulator-tests.yml +++ b/.github/workflows/trustzone-emulator-tests.yml @@ -17,6 +17,19 @@ jobs: git config --global --add safe.directory "$GITHUB_WORKSPACE" git submodule update --init --single-branch + # The CI image bakes in whatever m33mu existed when it was last tagged, + # which predates the STM32H5 UID region the DICE test needs. Build a + # pinned m33mu here so this job does not wait on an image refresh. + - name: Build m33mu + env: + M33MU_REF: 01857fb283f2f5a1b54a7e3d28d8dca807ce4425 + run: | + git clone https://github.com/danielinux/m33mu.git /tmp/m33mu + git -C /tmp/m33mu checkout "$M33MU_REF" + cmake -S /tmp/m33mu -B /tmp/m33mu/build -DCMAKE_BUILD_TYPE=Release + cmake --build /tmp/m33mu/build -j"$(nproc)" + install -m 0755 /tmp/m33mu/build/m33mu "$(command -v m33mu)" + - name: Configure stm32h5 (TZ) and build wolfboot run: | cp config/examples/stm32h5-tz.config .config From 92d674ff2bf2ec8e343c868cd83510033c337959 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Wed, 29 Jul 2026 17:26:55 -0700 Subject: [PATCH 10/13] Drop the pinned m33mu build now that the CI image is refreshed --- .github/workflows/trustzone-emulator-tests.yml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/.github/workflows/trustzone-emulator-tests.yml b/.github/workflows/trustzone-emulator-tests.yml index 0328a32ea3..20f6bee8ec 100644 --- a/.github/workflows/trustzone-emulator-tests.yml +++ b/.github/workflows/trustzone-emulator-tests.yml @@ -17,19 +17,6 @@ jobs: git config --global --add safe.directory "$GITHUB_WORKSPACE" git submodule update --init --single-branch - # The CI image bakes in whatever m33mu existed when it was last tagged, - # which predates the STM32H5 UID region the DICE test needs. Build a - # pinned m33mu here so this job does not wait on an image refresh. - - name: Build m33mu - env: - M33MU_REF: 01857fb283f2f5a1b54a7e3d28d8dca807ce4425 - run: | - git clone https://github.com/danielinux/m33mu.git /tmp/m33mu - git -C /tmp/m33mu checkout "$M33MU_REF" - cmake -S /tmp/m33mu -B /tmp/m33mu/build -DCMAKE_BUILD_TYPE=Release - cmake --build /tmp/m33mu/build -j"$(nproc)" - install -m 0755 /tmp/m33mu/build/m33mu "$(command -v m33mu)" - - name: Configure stm32h5 (TZ) and build wolfboot run: | cp config/examples/stm32h5-tz.config .config From 2955e99696444efcd17e1e25a03d89fd9b5ee44d Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Wed, 29 Jul 2026 17:46:44 -0700 Subject: [PATCH 11/13] Use the PSA registered claim keys for lifecycle and measurement description --- src/dice/dice.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dice/dice.c b/src/dice/dice.c index 4201cf663a..c8836a22fe 100644 --- a/src/dice/dice.c +++ b/src/dice/dice.c @@ -82,12 +82,12 @@ static NOINLINEFUNCTION void wolfboot_dice_zeroize(void *ptr, size_t len) #define EAT_CLAIM_UEID 256 #define PSA_IAT_CLAIM_IMPLEMENTATION_ID 2396 -#define PSA_IAT_CLAIM_LIFECYCLE 2398 +#define PSA_IAT_CLAIM_LIFECYCLE 2395 #define PSA_IAT_CLAIM_SW_COMPONENTS 2399 #define PSA_SW_COMPONENT_MEASUREMENT_TYPE 1 #define PSA_SW_COMPONENT_MEASUREMENT_VALUE 2 -#define PSA_SW_COMPONENT_MEASUREMENT_DESCRIPTION 5 +#define PSA_SW_COMPONENT_MEASUREMENT_DESCRIPTION 6 #define WOLFBOOT_UEID_TYPE_RANDOM 0x01 From b1f8273081a24f4f11e6eb0ce0d4c0c589796fbf Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Wed, 29 Jul 2026 17:46:44 -0700 Subject: [PATCH 12/13] Fail attestation when a measurement cannot be collected --- src/dice/dice.c | 66 ++++++++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/src/dice/dice.c b/src/dice/dice.c index c8836a22fe..9a8999d620 100644 --- a/src/dice/dice.c +++ b/src/dice/dice.c @@ -429,35 +429,45 @@ static int wolfboot_dice_collect_claims(struct wolfboot_dice_claims *claims) claims->has_lifecycle = 1; } - if (wolfboot_get_wolfboot_hash(wb_hash, &wb_hash_len) == 0) { - claims->components[claims->component_count].measurement_type = - WOLFBOOT_MEASUREMENT_HASH_NAME; - claims->components[claims->component_count].measurement_type_len = - XSTRLEN(WOLFBOOT_MEASUREMENT_HASH_NAME); - claims->components[claims->component_count].measurement_desc = - WOLFBOOT_DICE_COMPONENT_WOLFBOOT; - claims->components[claims->component_count].measurement_desc_len = - 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; - claims->component_count++; - } - - if (wolfboot_get_boot_image_hash(boot_hash, &boot_hash_len) == 0) { - claims->components[claims->component_count].measurement_type = - WOLFBOOT_MEASUREMENT_HASH_NAME; - claims->components[claims->component_count].measurement_type_len = - XSTRLEN(WOLFBOOT_MEASUREMENT_HASH_NAME); - claims->components[claims->component_count].measurement_desc = - WOLFBOOT_DICE_COMPONENT_BOOTIMAGE; - claims->components[claims->component_count].measurement_desc_len = - 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++; + /* A measurement that silently vanishes leaves a token a verifier cannot + * tell from one for a device with nothing to measure. */ + if (wolfboot_get_wolfboot_hash(wb_hash, &wb_hash_len) != 0) { +#ifndef WOLFBOOT_DICE_HW + wc_ForceZero(uds, sizeof(uds)); +#endif + return WOLFBOOT_DICE_ERR_HW; + } + claims->components[claims->component_count].measurement_type = + WOLFBOOT_MEASUREMENT_HASH_NAME; + claims->components[claims->component_count].measurement_type_len = + XSTRLEN(WOLFBOOT_MEASUREMENT_HASH_NAME); + claims->components[claims->component_count].measurement_desc = + WOLFBOOT_DICE_COMPONENT_WOLFBOOT; + claims->components[claims->component_count].measurement_desc_len = + 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; + claims->component_count++; + + if (wolfboot_get_boot_image_hash(boot_hash, &boot_hash_len) != 0) { +#ifndef WOLFBOOT_DICE_HW + wc_ForceZero(uds, sizeof(uds)); +#endif + return WOLFBOOT_DICE_ERR_HW; } + claims->components[claims->component_count].measurement_type = + WOLFBOOT_MEASUREMENT_HASH_NAME; + claims->components[claims->component_count].measurement_type_len = + XSTRLEN(WOLFBOOT_MEASUREMENT_HASH_NAME); + claims->components[claims->component_count].measurement_desc = + WOLFBOOT_DICE_COMPONENT_BOOTIMAGE; + claims->components[claims->component_count].measurement_desc_len = + 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 From 9b9ca53454732c5385de764bfcfd192335c997a2 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Thu, 30 Jul 2026 15:43:24 -0700 Subject: [PATCH 13/13] Use the wolfCOSE untagged Sign1 API for DICE --- .gitmodules | 2 +- CMakeLists.txt | 3 +-- lib/wolfCOSE | 2 +- options.mk | 1 - src/dice/dice.c | 17 +++++++++-------- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/.gitmodules b/.gitmodules index c0a5c290e1..745cbe2738 100644 --- a/.gitmodules +++ b/.gitmodules @@ -18,4 +18,4 @@ url = https://github.com/wolfSSL/wolfHAL.git [submodule "lib/wolfCOSE"] path = lib/wolfCOSE - url = https://github.com/wolfSSL/wolfCOSE.git + url = https://github.com/aidangarske/wolfCOSE.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f214d6475..e467ae9fae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -569,8 +569,7 @@ if(DEFINED WOLFCRYPT_TZ_PSA AND NOT WOLFCRYPT_TZ_PSA STREQUAL "0") list(APPEND WOLFBOOT_SOURCES "lib/wolfCOSE/src/wolfcose.c") list(APPEND WOLFBOOT_SOURCES "lib/wolfCOSE/src/wolfcose_cbor.c") list(APPEND WOLFBOOT_INCLUDE_DIRS ${WOLFBOOT_ROOT}/lib/wolfCOSE/include) - list(APPEND WOLFBOOT_DEFS WOLFCOSE_LEAN WOLFCOSE_ENABLE_EXT_SIGN - WOLFCOSE_SIGN1_UNTAGGED) + list(APPEND WOLFBOOT_DEFS WOLFCOSE_LEAN WOLFCOSE_ENABLE_EXT_SIGN) endif() # build bin-assemble tool Windows diff --git a/lib/wolfCOSE b/lib/wolfCOSE index 21bd185709..4b3ed01af2 160000 --- a/lib/wolfCOSE +++ b/lib/wolfCOSE @@ -1 +1 @@ -Subproject commit 21bd18570934c15880bd73edaca1962c8d68ac04 +Subproject commit 4b3ed01af2988ff67d9b55b0c64a6a35bb2bbd12 diff --git a/options.mk b/options.mk index 2d733446a7..99e9a50886 100644 --- a/options.mk +++ b/options.mk @@ -1124,7 +1124,6 @@ ifeq ($(WOLFCRYPT_TZ_PSA),1) CFLAGS+=-DNO_DES3 -DNO_DES3_TLS_SUITES CFLAGS+=-I$(WOLFBOOT_LIB_WOLFCOSE)/include CFLAGS+=-DWOLFCOSE_LEAN -DWOLFCOSE_ENABLE_EXT_SIGN - CFLAGS+=-DWOLFCOSE_SIGN1_UNTAGGED WOLFPSA_CFLAGS+=-I$(WOLFBOOT_LIB_WOLFPSA) WOLFPSA_CFLAGS+=-I$(WOLFBOOT_LIB_WOLFPSA)/wolfpsa ifeq ($(USE_CLANG),1) diff --git a/src/dice/dice.c b/src/dice/dice.c index 9a8999d620..16e3f119b8 100644 --- a/src/dice/dice.c +++ b/src/dice/dice.c @@ -837,10 +837,10 @@ static int NOINLINEFUNCTION wolfboot_dice_sign_payload( ret = WOLFBOOT_DICE_ERR_CRYPTO; goto cleanup; } - ret = wc_CoseSign1_Sign(cose_key, WOLFCOSE_ALG_ES256, NULL, 0, - payload, payload_len, NULL, 0, NULL, 0, - scratch, scratch_len, - token_buf, token_buf_size, out_len, &rng); + ret = wc_CoseSign1_Sign_ex(cose_key, WOLFCOSE_ALG_ES256, NULL, 0, + payload, payload_len, NULL, 0, NULL, 0, + scratch, scratch_len, token_buf, token_buf_size, + out_len, &rng, WOLFCOSE_SIGN1_UNTAGGED); if (ret != 0) { ret = WOLFBOOT_DICE_ERR_CRYPTO; } @@ -914,10 +914,11 @@ static int wolfboot_dice_build_token(uint8_t *token_buf, ret = WOLFBOOT_DICE_ERR_CRYPTO; goto cleanup; } - ret = wc_CoseSign1_Sign(&cose_key, WOLFCOSE_ALG_ES256, NULL, 0, - payload, payload_len, NULL, 0, NULL, 0, - scratch, sizeof(scratch), - token_buf, token_buf_size, &out_len, NULL); + ret = wc_CoseSign1_Sign_ex(&cose_key, WOLFCOSE_ALG_ES256, NULL, 0, + payload, payload_len, NULL, 0, NULL, 0, + scratch, sizeof(scratch), token_buf, + token_buf_size, &out_len, NULL, + WOLFCOSE_SIGN1_UNTAGGED); #else ret = wolfboot_dice_sign_payload(&cose_key, &claims, payload, payload_len, scratch, sizeof(scratch),