diff --git a/.github/workflows/test-external-library-paths.yml b/.github/workflows/test-external-library-paths.yml index daaa1a6825..a94ce1c0a1 100644 --- a/.github/workflows/test-external-library-paths.yml +++ b/.github/workflows/test-external-library-paths.yml @@ -89,4 +89,5 @@ jobs: WOLFBOOT_LIB_WOLFPKCS11="$(realpath ../external-libs/wolfPKCS11)" \ WOLFBOOT_LIB_WOLFPSA="$(realpath ../external-libs/wolfPSA)" \ WOLFBOOT_LIB_WOLFTPM="$(realpath ../external-libs/wolfTPM)" \ - WOLFBOOT_LIB_WOLFHSM="$(realpath ../external-libs/wolfHSM)" + WOLFBOOT_LIB_WOLFHSM="$(realpath ../external-libs/wolfHSM)" \ + WOLFBOOT_LIB_WOLFCOSE="$(realpath ../external-libs/wolfCOSE)" diff --git a/.github/workflows/trustzone-emulator-tests.yml b/.github/workflows/trustzone-emulator-tests.yml index aabfdcbe1d..c122a9966b 100644 --- a/.github/workflows/trustzone-emulator-tests.yml +++ b/.github/workflows/trustzone-emulator-tests.yml @@ -104,7 +104,12 @@ 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 "IAT size match: challenge=64 token=" /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: | diff --git a/.gitmodules b/.gitmodules index 13396fd2ec..745cbe2738 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/aidangarske/wolfCOSE.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 344cc21d52..e467ae9fae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -566,6 +566,10 @@ 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) endif() # build bin-assemble tool Windows 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/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); diff --git a/lib/wolfCOSE b/lib/wolfCOSE new file mode 160000 index 0000000000..c962707860 --- /dev/null +++ b/lib/wolfCOSE @@ -0,0 +1 @@ +Subproject commit c96270786043244f8a001595c5d59e79772eec72 diff --git a/options.mk b/options.mk index c3d6b75bd6..99e9a50886 100644 --- a/options.mk +++ b/options.mk @@ -1122,6 +1122,8 @@ 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 WOLFPSA_CFLAGS+=-I$(WOLFBOOT_LIB_WOLFPSA) WOLFPSA_CFLAGS+=-I$(WOLFBOOT_LIB_WOLFPSA)/wolfpsa ifeq ($(USE_CLANG),1) @@ -1135,6 +1137,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..b9771633ca 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) @@ -59,7 +61,6 @@ #define WOLFBOOT_DICE_CDI_LEN 32 #define WOLFBOOT_DICE_KEY_LEN 32 #define WOLFBOOT_DICE_UEID_LEN 33 -#define WOLFBOOT_DICE_SIG_LEN 64 #define WOLFBOOT_DICE_SUCCESS 0 #define WOLFBOOT_DICE_ERR_INVALID_ARGUMENT -1 @@ -76,19 +77,16 @@ 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 #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 @@ -130,145 +128,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) @@ -569,35 +428,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 @@ -750,6 +619,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 +647,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,195 +662,152 @@ 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); - - 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); + XMEMSET(&ctx, 0, sizeof(ctx)); + ctx.buf = buf; + ctx.bufSz = buf_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); + ret = wc_CBOR_EncodeMapStart(&ctx, map_count); + if (ret == 0) { + ret = wc_CBOR_EncodeInt(&ctx, EAT_CLAIM_NONCE); } - - if (claims->has_lifecycle) { - wolfboot_cbor_put_int(&w, PSA_IAT_CLAIM_LIFECYCLE); - wolfboot_cbor_put_uint(&w, claims->lifecycle); + 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->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->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 (w.error != 0) { - return w.error; + 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); + } } - *payload_len = w.offset; - return 0; -} - -static int wolfboot_dice_encode_protected(uint8_t *buf, - size_t buf_len, - size_t *prot_len) -{ - struct wolfboot_cbor_writer w; - - 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); + 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; } - *prot_len = w.offset; + *payload_len = ctx.idx; return 0; } -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) +#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_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); + (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; } - - *tbs_len = w.offset; + *sig_len = out_len; return 0; } +#endif /* WOLFBOOT_DICE_HW */ -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) -{ - int ret = WOLFBOOT_DICE_ERR_CRYPTO; - uint8_t hash[SHA256_DIGEST_SIZE]; #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; - 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; - } + int ret; -#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; - 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_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; - 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; - ret = WOLFBOOT_DICE_SUCCESS; -#endif /* !WOLFBOOT_DICE_HW */ - cleanup: -#ifndef WOLFBOOT_DICE_HW if (key_inited) { wc_ecc_free(&key); wolfboot_dice_zeroize(&key, sizeof(key)); @@ -983,11 +815,9 @@ 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)); return ret; } +#endif /* !WOLFBOOT_DICE_HW */ static int wolfboot_dice_build_token(uint8_t *token_buf, size_t token_buf_size, @@ -998,13 +828,10 @@ static int wolfboot_dice_build_token(uint8_t *token_buf, 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; + uint8_t scratch[WOLFBOOT_DICE_MAX_TBS]; + WOLFCOSE_KEY cose_key; + int cose_key_inited = 0; + size_t out_len = 0; int ret; ret = wolfboot_dice_collect_claims(&claims); @@ -1018,48 +845,66 @@ static int wolfboot_dice_build_token(uint8_t *token_buf, ret = wolfboot_dice_encode_payload(payload, sizeof(payload), &claims, &payload_len); if (ret != 0) { - return ret; + goto cleanup; } - ret = wolfboot_dice_encode_protected(protected_hdr, sizeof(protected_hdr), - &protected_len); - if (ret != 0) { - return ret; + /* 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 = wc_CoseSign1_SignSize_ex(NULL, WOLFCOSE_ALG_ES256, 0, + payload_len, 0, + WOLFCOSE_SIGN1_UNTAGGED, &out_len); + if (ret == 0) { + *token_len = out_len; + } + else { + ret = WOLFBOOT_DICE_ERR_CRYPTO; + } + goto cleanup; } - ret = wolfboot_dice_build_sig_structure(tbs, sizeof(tbs), - protected_hdr, protected_len, - payload, payload_len, &tbs_len); + ret = wc_CoseKey_Init(&cose_key); if (ret != 0) { - return ret; + ret = WOLFBOOT_DICE_ERR_CRYPTO; + goto cleanup; } + cose_key_inited = 1; - if (token_buf != NULL) { - ret = wolfboot_dice_sign_tbs(tbs, tbs_len, sig, &sig_len, &claims); - if (ret != 0) { - return ret; - } +#ifdef WOLFBOOT_DICE_HW + if (wolfboot_attest_get_private_key_hw(&claims) != 0) { + ret = WOLFBOOT_DICE_ERR_HW; + goto cleanup; } - - 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); + ret = wc_CoseKey_SetExtSigner(&cose_key, wolfboot_dice_hw_sign_cb, NULL); + if (ret != 0) { + ret = WOLFBOOT_DICE_ERR_CRYPTO; + goto cleanup; } - else { - wolfboot_cbor_put_type_val(&w, 2, WOLFBOOT_DICE_SIG_LEN); - wolfboot_cbor_reserve(&w, WOLFBOOT_DICE_SIG_LEN); + 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), + token_buf, token_buf_size, &out_len); +#endif /* WOLFBOOT_DICE_HW */ + if (ret != 0) { + ret = WOLFBOOT_DICE_ERR_CRYPTO; + goto cleanup; } - if (w.error != 0) { - return w.error; - } + *token_len = out_len; + ret = WOLFBOOT_DICE_SUCCESS; - *token_len = w.offset; - return WOLFBOOT_DICE_SUCCESS; +cleanup: + if (cose_key_inited) { + wc_CoseKey_Free(&cose_key); + } + wolfboot_dice_zeroize(payload, sizeof(payload)); + wolfboot_dice_zeroize(scratch, sizeof(scratch)); + return ret; } int wolfBoot_dice_get_token(const uint8_t *challenge, diff --git a/test-app/app_stm32h5.c b/test-app/app_stm32h5.c index 9b810d251c..d47281d175 100644 --- a/test-app/app_stm32h5.c +++ b/test-app/app_stm32h5.c @@ -754,7 +754,8 @@ static int run_psa_boot_attestation(void) #if (APP_HASH_SIZE > 0u) uint8_t hash_buf[APP_HASH_SIZE]; #endif - size_t token_size = 0; + size_t queried_token_size; + size_t emitted_token_size; int ret = 0; size_t i; @@ -802,30 +803,39 @@ static int run_psa_boot_attestation(void) } printf(" step 5: request IAT token size\r\n"); - status = psa_initial_attest_get_token_size(sizeof(challenge), &token_size); + queried_token_size = 0; + status = psa_initial_attest_get_token_size(sizeof(challenge), + &queried_token_size); if (status != PSA_SUCCESS) { printf(" step 5: token size failed (%ld)\r\n", (long)status); ret = -1; } else { printf(" step 5: token size %lu bytes\r\n", - (unsigned long)token_size); + (unsigned long)queried_token_size); } - printf(" step 6: request IAT token\r\n"); - if (ret == 0 && token_size <= sizeof(token)) { + printf(" step 6: request exact-size IAT token\r\n"); + if (ret == 0 && queried_token_size <= sizeof(token)) { + emitted_token_size = 0; status = psa_initial_attest_get_token(challenge, sizeof(challenge), - token, sizeof(token), &token_size); - if (status != PSA_SUCCESS) { - printf(" step 6: token failed (%ld)\r\n", (long)status); + token, queried_token_size, + &emitted_token_size); + if (status != PSA_SUCCESS || + emitted_token_size != queried_token_size) { + printf(" step 6: size mismatch (status=%ld size=%lu " + "expected=%lu)\r\n", (long)status, + (unsigned long)emitted_token_size, + (unsigned long)queried_token_size); ret = -1; } else { - printf(" step 6: token received (%lu bytes)\r\n", - (unsigned long)token_size); - print_hex(token, (uint32_t)token_size, 1); + printf(" IAT size match: challenge=64 token=%lu\r\n", + (unsigned long)emitted_token_size); + print_hex(token, (uint32_t)emitted_token_size, 1); } } else if (ret == 0) { printf(" step 6: token buffer too small (%lu > %lu)\r\n", - (unsigned long)token_size, (unsigned long)sizeof(token)); + (unsigned long)queried_token_size, + (unsigned long)sizeof(token)); ret = -1; } diff --git a/tools/unit-tests/Makefile b/tools/unit-tests/Makefile index 3a1b466086..e1582fa9ae 100644 --- a/tools/unit-tests/Makefile +++ b/tools/unit-tests/Makefile @@ -11,6 +11,7 @@ WOLFBOOT_LIB_WOLFPKCS11?=../../lib/wolfPKCS11 WOLFBOOT_LIB_WOLFPSA?=../../lib/wolfPSA WOLFBOOT_LIB_WOLFTPM?=../../lib/wolfTPM WOLFBOOT_LIB_WOLFHSM?=../../lib/wolfHSM +WOLFBOOT_LIB_WOLFCOSE?=../../lib/wolfCOSE ifeq ($(wildcard $(WOLFBOOT_LIB_WOLFPSA)),) WOLFBOOT_LIB_WOLFPSA=../../../external-libs/wolfPSA @@ -21,6 +22,9 @@ endif ifeq ($(wildcard $(WOLFBOOT_LIB_WOLFHSM)),) WOLFBOOT_LIB_WOLFHSM=../../../external-libs/wolfHSM endif +ifeq ($(wildcard $(WOLFBOOT_LIB_WOLFCOSE)),) +WOLFBOOT_LIB_WOLFCOSE=../../../external-libs/wolfCOSE +endif # Convert to absolute paths for standalone usage WOLFBOOT_LIB_WOLFSSL:=$(abspath $(WOLFBOOT_LIB_WOLFSSL)) @@ -28,6 +32,7 @@ WOLFBOOT_LIB_WOLFPKCS11:=$(abspath $(WOLFBOOT_LIB_WOLFPKCS11)) WOLFBOOT_LIB_WOLFPSA:=$(abspath $(WOLFBOOT_LIB_WOLFPSA)) WOLFBOOT_LIB_WOLFTPM:=$(abspath $(WOLFBOOT_LIB_WOLFTPM)) WOLFBOOT_LIB_WOLFHSM:=$(abspath $(WOLFBOOT_LIB_WOLFHSM)) +WOLFBOOT_LIB_WOLFCOSE:=$(abspath $(WOLFBOOT_LIB_WOLFCOSE)) CFLAGS=-I. -I../../src -I../../include -I$(WOLFBOOT_LIB_WOLFSSL) CFLAGS+=-g -ggdb @@ -84,6 +89,7 @@ TESTS+=unit-fwtpm-nv-oob TESTS+=unit-elf-bss-guard TESTS+=unit-image-elf-scatter TESTS+=unit-arm-tee-psa-ipc +TESTS+=unit-dice-token-size TESTS+=unit-va416x0-fram TESTS+=unit-flash-write-mcxa TESTS+=unit-flash-write-samr21 @@ -331,6 +337,19 @@ unit-arm-tee-psa-ipc: ../../include/target.h unit-arm-tee-psa-ipc.c ../../src/ar -ffunction-sections -fdata-sections \ $(LDFLAGS) -Wl,--gc-sections +unit-dice-token-size:CFLAGS+=-I$(WOLFBOOT_LIB_WOLFCOSE)/include \ + -I$(WOLFBOOT_LIB_WOLFSSL) -DUNIT_TEST_AUTH -DWOLFBOOT_SIGN_ECC256 \ + -DWOLFCRYPT_SECURE_MODE -DHAVE_HKDF -DWOLFBOOT_NO_PARTITIONS \ + -DWOLFCOSE_LEAN -DWOLFCOSE_ENABLE_EXT_SIGN \ + -ffunction-sections -fdata-sections +unit-dice-token-size: ../../include/target.h unit-dice-token-size.c \ + $(WOLFBOOT_LIB_WOLFCOSE)/src/wolfcose.c \ + $(WOLFBOOT_LIB_WOLFCOSE)/src/wolfcose_cbor.c \ + $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sha256.c \ + $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/hash.c \ + $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/memory.c + gcc -o $@ $^ $(CFLAGS) $(LDFLAGS) -Wl,--gc-sections + unit-va416x0-fram: unit-va416x0-fram.c ../../hal/va416x0.c gcc -o $@ unit-va416x0-fram.c $(CFLAGS) $(LDFLAGS) diff --git a/tools/unit-tests/unit-dice-token-size.c b/tools/unit-tests/unit-dice-token-size.c new file mode 100644 index 0000000000..6d015d46b7 --- /dev/null +++ b/tools/unit-tests/unit-dice-token-size.c @@ -0,0 +1,242 @@ +/* unit-dice-token-size.c + * + * DICE COSE_Sign1 token sizing tests. + * + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include + +static uint8_t test_wolfboot_region[64]; + +#define ARCH_FLASH_OFFSET 0x1000u +#define WOLFBOOT_PARTITION_BOOT_ADDRESS 0x1040u +#define EXT_FLASH +#define NO_XIP +#define WOLFBOOT_DICE_HW +#define WOLFBOOT_HASH_SHA256 + +#include "../../src/dice/dice.c" + +static uint8_t test_boot_hash[WOLFBOOT_SHA_DIGEST_SIZE]; +static unsigned int test_cdi_update_calls; +static unsigned int test_key_create_calls; +static unsigned int test_sign_calls; + +/* Local ECC signing must never be reached: this test exercises the delegated + * hardware-signing path. These stubs keep that failure mode link-visible. */ +int wc_ecc_sign_hash(const byte *in, word32 in_len, byte *out, + word32 *out_len, WC_RNG *rng, ecc_key *key) +{ + (void)in; + (void)in_len; + (void)out; + (void)out_len; + (void)rng; + (void)key; + return -1; +} + +int wc_ecc_sig_to_rs(const byte *sig, word32 sig_len, byte *r, + word32 *r_len, byte *s, word32 *s_len) +{ + (void)sig; + (void)sig_len; + (void)r; + (void)r_len; + (void)s; + (void)s_len; + return -1; +} + +int ext_flash_read(uintptr_t address, uint8_t *data, int len) +{ + size_t offset; + + if (address < ARCH_FLASH_OFFSET || data == NULL || len < 0) { + return -1; + } + offset = (size_t)(address - ARCH_FLASH_OFFSET); + if (offset > sizeof(test_wolfboot_region) || + (size_t)len > sizeof(test_wolfboot_region) - offset) { + return -1; + } + memcpy(data, test_wolfboot_region + offset, (size_t)len); + return len; +} + +int wolfBoot_open_image(struct wolfBoot_image *img, uint8_t part) +{ + (void)img; + return part == PART_BOOT ? 0 : -1; +} + +uint16_t wolfBoot_get_header(struct wolfBoot_image *img, uint16_t type, + uint8_t **ptr) +{ + (void)img; + if (type != HDR_HASH || ptr == NULL) { + return 0; + } + *ptr = test_boot_hash; + return (uint16_t)sizeof(test_boot_hash); +} + +int hal_attestation_get_ueid(uint8_t *buf, size_t *len) +{ + size_t i; + + if (buf == NULL || len == NULL || *len < WOLFBOOT_DICE_UEID_LEN) { + return -1; + } + for (i = 0; i < WOLFBOOT_DICE_UEID_LEN; i++) { + buf[i] = (uint8_t)(i + 1u); + } + *len = WOLFBOOT_DICE_UEID_LEN; + return 0; +} + +int hal_attestation_get_implementation_id(uint8_t *buf, size_t *len) +{ + if (buf == NULL || len == NULL || *len < WOLFBOOT_SHA_DIGEST_SIZE) { + return -1; + } + memset(buf, 0xA5, WOLFBOOT_SHA_DIGEST_SIZE); + *len = WOLFBOOT_SHA_DIGEST_SIZE; + return 0; +} + +int hal_attestation_get_lifecycle(uint32_t *lifecycle) +{ + if (lifecycle == NULL) { + return -1; + } + *lifecycle = 0x3000u; + return 0; +} + +int hal_dice_update_cdi(const uint8_t *measurement, size_t meas_len, + const char *measurement_desc, + size_t measurement_desc_len) +{ + test_cdi_update_calls++; + return measurement != NULL && meas_len > 0u && + measurement_desc != NULL && measurement_desc_len > 0u ? 0 : -1; +} + +int hal_dice_create_attest_key(void) +{ + test_key_create_calls++; + return 0; +} + +int hal_dice_sign_hash(const uint8_t *hash, size_t hash_len, + uint8_t *sig, size_t *sig_len) +{ + test_sign_calls++; + if (hash == NULL || hash_len != SHA256_DIGEST_SIZE || sig == NULL || + sig_len == NULL || *sig_len < 64u) { + return -1; + } + memset(sig, 0x5A, 64u); + *sig_len = 64u; + return 0; +} + +int hal_dice_get_attest_pubkey(uint8_t *buf, size_t *len) +{ + (void)buf; + (void)len; + return -1; +} + +static void check_token_size(size_t challenge_size) +{ + uint8_t challenge[PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64]; + uint8_t token[WOLFBOOT_DICE_MAX_PAYLOAD + 128u]; + size_t queried_size = 0; + size_t actual_size = 0; + size_t short_size = 0; + int ret; + + memset(challenge, 0x3C, sizeof(challenge)); + test_cdi_update_calls = 0; + test_key_create_calls = 0; + test_sign_calls = 0; + + ret = wolfBoot_dice_get_token_size(challenge_size, &queried_size); + ck_assert_int_eq(ret, WOLFBOOT_DICE_SUCCESS); + ck_assert_uint_gt(queried_size, 0u); + ck_assert_uint_le(queried_size, sizeof(token)); + ck_assert_uint_eq(test_cdi_update_calls, 0u); + ck_assert_uint_eq(test_key_create_calls, 0u); + ck_assert_uint_eq(test_sign_calls, 0u); + + ret = wolfBoot_dice_get_token(challenge, challenge_size, token, + queried_size - 1u, &short_size); + ck_assert_int_eq(ret, WOLFBOOT_DICE_ERR_BUFFER_TOO_SMALL); + ck_assert_uint_eq(short_size, queried_size); + ck_assert_uint_eq(test_cdi_update_calls, 0u); + ck_assert_uint_eq(test_key_create_calls, 0u); + ck_assert_uint_eq(test_sign_calls, 0u); + + ret = wolfBoot_dice_get_token(challenge, challenge_size, token, + queried_size, &actual_size); + ck_assert_int_eq(ret, WOLFBOOT_DICE_SUCCESS); + ck_assert_uint_eq(actual_size, queried_size); + ck_assert_uint_eq(test_cdi_update_calls, 2u); + ck_assert_uint_eq(test_key_create_calls, 1u); + ck_assert_uint_eq(test_sign_calls, 1u); +} + +START_TEST(test_dice_token_size_32) +{ + check_token_size(PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32); +} +END_TEST + +START_TEST(test_dice_token_size_48) +{ + check_token_size(PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48); +} +END_TEST + +START_TEST(test_dice_token_size_64) +{ + check_token_size(PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64); +} +END_TEST + +static Suite *dice_token_size_suite(void) +{ + Suite *suite = suite_create("dice-token-size"); + TCase *test_case = tcase_create("size-consistency"); + + tcase_add_test(test_case, test_dice_token_size_32); + tcase_add_test(test_case, test_dice_token_size_48); + tcase_add_test(test_case, test_dice_token_size_64); + suite_add_tcase(suite, test_case); + return suite; +} + +int main(void) +{ + int failures; + Suite *suite = dice_token_size_suite(); + SRunner *runner = srunner_create(suite); + + srunner_run_all(runner, CK_NORMAL); + failures = srunner_ntests_failed(runner); + srunner_free(runner); + return failures; +}