From d522c3d4421844f1acab44855eda703ec2d13849 Mon Sep 17 00:00:00 2001 From: aidan garske Date: Wed, 22 Jul 2026 20:28:40 -0700 Subject: [PATCH 1/4] 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 2/4] 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 3/4] 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 4/4] 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