diff --git a/Makefile b/Makefile index 2051b7900a..d28a1da7ed 100644 --- a/Makefile +++ b/Makefile @@ -289,6 +289,10 @@ ifeq ($(TARGET),stm32n6) endif endif # TZEN=1 +ifeq ($(TARGET),pic32cz) + MAIN_TARGET:=wolfboot.bin test-app/image_v1_signed.bin +endif + ifeq ($(TARGET),x86_64_efi) MAIN_TARGET:=wolfboot.efi endif @@ -485,6 +489,14 @@ endif ifeq ($(WOLFHSM_SERVER),1) _DO_WH_NVMTOOL:=1 endif +# Not every wolfHSM port provisions keys from a pre-built NVM image. A HAL may +# instead install the verification key into the server's key cache at boot (see +# hal_hsm_init_connect on pic32cz), which is the only option on targets whose +# server wipes its NVM partition on startup. Those set WOLFHSM_NVM_IMAGE=0. +WOLFHSM_NVM_IMAGE?=1 +ifeq ($(WOLFHSM_NVM_IMAGE),0) + _DO_WH_NVMTOOL:= +endif # Disable NVM image generation if user-provided keys without explicit USER_NVM_INIT # (providing USER_NVM_INIT allows users to supply keys and still generate a custom NVM image) ifeq ($(_USER_PROVIDED_KEYS),1) diff --git a/arch.mk b/arch.mk index e1bf73c7c8..350da45e93 100644 --- a/arch.mk +++ b/arch.mk @@ -191,6 +191,46 @@ ifeq ($(ARCH),ARM) ARCH_FLASH_OFFSET=0x08000000 CORTEX_M7=1 OBJS+=hal/pic32c.o + + ifeq ($(WOLFHSM_CLIENT),1) + ifeq ($(WOLFHSM_MICROCHIP_PIC32CZ),) + $(error WOLFHSM_MICROCHIP_PIC32CZ is not set: point it at the wolfHSM \ + PIC32CZ client port directory (the one containing port/)) + endif + + CFLAGS+=-I$(WOLFHSM_MICROCHIP_PIC32CZ) \ + -DWOLFHSM_CFG_NO_SYS_TIME \ + -DWOLFHSM_CFG_TRANSPORT_MEM \ + -DWOLFHSM_CFG_CLIENT_ID=WOLFBOOT_WOLFHSM_CLIENT_ID \ + -DPIC32CZ_CFG_SHARED_MEM_PHYS_BASE=0x20100000U \ + -DPIC32CZ_CFG_SHARED_MEM_REQ_SIZE=4096 \ + -DPIC32CZ_CFG_SHARED_MEM_RESP_SIZE=4096 \ + '-DPIC32CZ_CFG_SHARED_MEM_TOTAL_SIZE=(PIC32CZ_CFG_SHARED_MEM_REQ_SIZE+PIC32CZ_CFG_SHARED_MEM_RESP_SIZE)' + + OBJS+=$(WOLFHSM_MICROCHIP_PIC32CZ)/port/mailbox.o \ + $(WOLFHSM_MICROCHIP_PIC32CZ)/port/client/czhsm_client.o \ + $(WOLFHSM_MICROCHIP_PIC32CZ)/port/client/fwmetadata.o \ + $(WOLFBOOT_LIB_WOLFHSM)/src/wh_transport_mem.o + + # HSM server firmware. Optional: set HSM_FW_BIN to have wolfBoot load/boot + # the HSM core from it at boot; leave it unset when the firmware is already + # resident and wolfBoot must not touch it. + ifneq ($(HSM_FW_BIN),) + ifeq ($(wildcard $(HSM_FW_BIN)),) + $(error HSM_FW_BIN=$(HSM_FW_BIN) not found: build the wolfHSM server \ + firmware before wolfBoot) + endif + HSM_FW_ADDR?=0x0c1c0000 + HSM_FW_SIZE:=$(shell stat -c %s $(HSM_FW_BIN)) + CFLAGS+=-DHSM_FW_ADDR=$(HSM_FW_ADDR) -DHSM_FW_SIZE=$(HSM_FW_SIZE) + endif + + # Signing pubkey header. Optional: set HSM_PUBKEY_HEADER to have the HAL + # push the key into the HSM at boot; leave it unset when pre-provisioned. + ifneq ($(HSM_PUBKEY_HEADER),) + CFLAGS+=-DHSM_PUBKEY_HEADER='"$(HSM_PUBKEY_HEADER)"' + endif + endif endif ifeq ($(TARGET),pic32ck) diff --git a/config/examples/pic32cz-wolfHSM.config b/config/examples/pic32cz-wolfHSM.config new file mode 100644 index 0000000000..bf565de640 --- /dev/null +++ b/config/examples/pic32cz-wolfHSM.config @@ -0,0 +1,30 @@ +ARCH=ARM +TARGET=pic32cz +SIGN?=ECC256 +HASH?=SHA256 +VTOR?=1 +SPMATH?=1 +NO_MPU=1 +DEBUG_UART=1 + +WOLFHSM_CLIENT=1 + +# Must match the client ID the server provisions keys under. +WOLFHSM_CLIENT_ID=12 + +WOLFHSM_NVM_IMAGE=0 + +# MUST equal the czhsm-server build's WOLFHSM_CFG_COMM_DATA_LEN +WOLFHSM_CFG_COMM_DATA_LEN=1280 + +BOOTLOADER_PARTITION_SIZE=0x10000 + +HSM_FW_ADDR=0x0c1c0000 + +WOLFBOOT_SECTOR_SIZE=0x1000 +WOLFBOOT_PARTITION_SIZE=0x100000 +WOLFBOOT_PARTITION_BOOT_ADDRESS=0x0c000000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x0c200000 +WOLFBOOT_PARTITION_SWAP_ADDRESS=0x0c1ff000 + +DUALBANK_SWAP=1 diff --git a/docs/Targets.md b/docs/Targets.md index d0b84e0dba..ef3456cd65 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -5129,6 +5129,21 @@ The test behavior depends on whether the `DUALBANK_SWAP` feature is enabled: - **If `DUALBANK_SWAP=1`:** The higher version of the application will be automatically selected, and LED1 will turn on. - **If `DUALBANK_SWAP=0`:** The application version 1 will boot first. The application will trigger the update and light LED0. On the next reset, wolfBoot will update the application, boot application version 2, and turn on LED1. +### PIC32CZ with wolfHSM + +On Microchip PIC32CZ CA9x devices, wolfBoot can run on the Cortex-M7 host core as +a [wolfHSM](https://www.wolfssl.com/products/wolfhsm/) client, offloading the +image digest and signature verification to the wolfHSM server running on the +Cortex-M0+ HSM core. + +Currently, wolfBoot as wolfHSM for PIC32CZ is distributed as part of the wolfHSM +PIC32CZ platform release bundle, not as a standalone package. This bundle is +under NDA and is not publicly available. + +For access to the PIC32CZ platform release or for more information on using +wolfBoot and wolfHSM on PIC32CZ devices, contact +[facts@wolfssl.com](mailto:facts@wolfssl.com). + ## Microchip SAME51 diff --git a/docs/wolfHSM.md b/docs/wolfHSM.md index db42170bc2..dbefd8f8fd 100644 --- a/docs/wolfHSM.md +++ b/docs/wolfHSM.md @@ -21,6 +21,7 @@ wolfBoot supports using wolfHSM on the following platforms: - wolfBoot simulator (using wolfHSM POSIX TCP transport) - AURIX TC3xx (shared memory transport) +- Microchip PIC32CZ CA9x (shared memory transport) - STM32H5 TrustZone (the secure-side wolfBoot hosts a wolfHSM server and exposes it to the non-secure application through a single NSC veneer; see [STM32H5 TrustZone Engine](#stm32h5-trustzone-engine) below) Details on configuring wolfBoot to use wolfHSM on each of these platforms can be found in the wolfBoot (and wolfHSM) documentation specific to that target, with the exception of the simulator, which is documented here. The remainder of this document focuses on the generic wolfHSM-related configuration options. diff --git a/hal/pic32cz.c b/hal/pic32cz.c index 33dd80f430..32424011d5 100644 --- a/hal/pic32cz.c +++ b/hal/pic32cz.c @@ -25,6 +25,41 @@ #include +#ifdef DEBUG_UART +#include "uart_drv.h" +#endif + +#if defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) + +/* wolfHSM */ +#include "wolfhsm/wh_error.h" +#include "wolfhsm/wh_client.h" +#include "wolfhsm/wh_client_crypto.h" +#include "wolfhsm/wh_transport_mem.h" + +/* PIC32CZ wolfHSM port (shared with the czhsm-client reference application) */ +#include "port/client/czhsm_client.h" +#include "port/client/fwmetadata.h" +/* PIC32CZ_CFG_* (shared-memory window) comes from arch.mk, not a header: unlike + * the czhsm-client application, wolfBoot does not define WOLFHSM_CFG, so the + * port sources skip "pic32cz_cfg.h" and take the configuration on the command + * line instead. */ + +/* FCW_BASE */ +#include "hal/pic32cz_registers.h" + +#include +#include + +#ifndef WOLFBOOT_WOLFHSM_CLIENT_ID +#error "WOLFBOOT_WOLFHSM_CLIENT_ID is not defined. Set WOLFHSM_CLIENT_ID in your .config." +#endif + +#define FCW_MUTEX (*(volatile uint32_t*)(FCW_BASE + 0x08U)) +#define FCW_MUTEX_RELEASE (0x2) + +#endif /* WOLFBOOT_ENABLE_WOLFHSM_CLIENT */ + #define SUPC_BASE (0x44020000U) #define SUPC_VREGCTRL (*(volatile uint32_t *)(SUPC_BASE + 0x1CU)) #define SUPC_STATUS (*(volatile uint32_t *)(SUPC_BASE + 0x0CU)) @@ -88,6 +123,12 @@ void hal_init(void) pic32_clock_pll0_init(12, 225, 1, 3); pic32_clock_gclk_gen0(2, 1); pic32_delay_cnt(700); +#ifdef DEBUG_UART + /* Must follow the PLL setup above: the SERCOM baud divisor assumes + * GCLK1 = PLL0/2 = 150 MHz. */ + uart_init(115200, 8, 'N', 1); + uart_write("wolfBoot PIC32CZ\r\n", 18); +#endif #if defined(TEST_FLASH) pic32_flash_test(); while (1) {} @@ -106,3 +147,101 @@ void hal_prepare_boot(void) pic32_clock_reset(); #endif } + +#if defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) + +/* wolfBoot's signing public key, DER encoded, as a 'hsm_pubkey_der[]' C array. + */ +#ifdef HSM_PUBKEY_HEADER +#include HSM_PUBKEY_HEADER +#endif + +whClientContext hsmClientCtx = {0}; + +const int hsmDevIdHash = WH_DEV_ID; +const int hsmDevIdPubKey = WH_DEV_ID; + +/* Key slot the verification key lives at on the server; image.c references it by + * this id (wh_Client_EccSetKeyId(hsmKeyIdPubKey)). wolfBoot either pushes the key + * here at boot (HSM_PUBKEY_HEADER) or relies on it being pre-provisioned. */ +const int hsmKeyIdPubKey = 0xFF; + +/* + * Boot the HSM core and connect to the wolfHSM server running on it. + */ +int hal_hsm_init_connect(void) +{ + int rc; + whClientConfig cfg; + + memset((void*)PIC32CZ_CFG_SHARED_MEM_PHYS_BASE, 0, + PIC32CZ_CFG_SHARED_MEM_TOTAL_SIZE); + + FCW_MUTEX = FCW_MUTEX_RELEASE; + +#if defined(HSM_FW_ADDR) && defined(HSM_FW_SIZE) + /* Load/boot the HSM core from the firmware image; blocks until it has booted + * and acknowledged. Skipped when HSM_FW_BIN is unset: the firmware is then + * assumed already resident and wolfBoot connects to the running server. */ + rc = czhsm_load_hsm_firmware(HSM_FW_ADDR, HSM_FW_SIZE); + if (rc != 0) { + return rc; + } +#endif + + rc = czhsm_setup(&cfg); + if (rc != 0) { + return rc; + } + + rc = wh_Client_Init(&hsmClientCtx, &cfg); + if (rc != WH_ERROR_OK) { + return rc; + } + + rc = wh_Client_CommInit(&hsmClientCtx, NULL, NULL); + if (rc != WH_ERROR_OK) { + return rc; + } + +#ifdef HSM_PUBKEY_HEADER + { + ecc_key pubkey; + whKeyId keyId = (whKeyId)hsmKeyIdPubKey; + word32 idx = 0; + + rc = wc_ecc_init_ex(&pubkey, NULL, INVALID_DEVID); + if (rc != 0) { + return rc; + } + + rc = wc_EccPublicKeyDecode(hsm_pubkey_der, &idx, &pubkey, + (word32)sizeof(hsm_pubkey_der)); + if (rc == 0) { + rc = wh_Client_EccImportKey(&hsmClientCtx, &pubkey, &keyId, + WH_NVM_FLAGS_USAGE_VERIFY, 0, NULL); + } + + wc_ecc_free(&pubkey); + } +#endif /* HSM_PUBKEY_HEADER */ + + return rc; +} + +/* + * Close the wolfHSM session before handing control to the application. + */ +int hal_hsm_disconnect(void) +{ + int rc; + + rc = wh_Client_CommClose(&hsmClientCtx); + if (rc != WH_ERROR_OK) { + return rc; + } + + return wh_Client_Cleanup(&hsmClientCtx); +} + +#endif /* WOLFBOOT_ENABLE_WOLFHSM_CLIENT */ diff --git a/hal/uart/uart_drv_pic32cz.c b/hal/uart/uart_drv_pic32cz.c new file mode 100644 index 0000000000..f1ee49c40f --- /dev/null +++ b/hal/uart/uart_drv_pic32cz.c @@ -0,0 +1,168 @@ +/* uart_drv_pic32cz.c + * + * Driver for the PIC32CZ SERCOM UART, used for wolfBoot debug output. + * + * Uses SERCOM1 on the host (Cortex-M7) core: TX on PC4 (EXT1 pin 14), + * RX on PC7. 115200 8N1, transmit only. + * + * Derived from the reference driver in the wolfHSM PIC32CZ port + * (czhsm-client/uart.c), which is in turn based on the plib driver generated + * by MPLAB. + * + * 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. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#ifdef TARGET_pic32cz + +#include +#include + +#define GCLK_BASE (0x44050000U) +#define SERCOM_BASE (0x46000000U) +#define PORT_BASE (0x44840000U) + +/* SERCOM1 */ +#define SERCOM_OFF (0x2000U) +#define SERCOM1 (SERCOM_BASE + SERCOM_OFF) +#define SERCOM_PCHCTRL (22) /* GCLK peripheral channel for SERCOM1 */ + +#define SERCOM_CTRLA (*(volatile uint32_t*)(SERCOM1 + 0x00U)) +#define SERCOM_CTRLB (*(volatile uint32_t*)(SERCOM1 + 0x04U)) +#define SERCOM_BAUD (*(volatile uint16_t*)(SERCOM1 + 0x0CU)) +#define SERCOM_INTFLAG (*(volatile uint8_t*)(SERCOM1 + 0x18U)) +#define SERCOM_SYNCBUSY (*(volatile uint32_t*)(SERCOM1 + 0x1CU)) +#define SERCOM_DATA (*(volatile uint32_t*)(SERCOM1 + 0x28U)) + +#define CTRLA_MODE_USART_INT (0x1U << 2) /* USART with internal clock */ +#define CTRLA_ENABLE (0x1U << 1) +#define CTRLA_IBON (0x1U << 8) +#define CTRLA_DORD (0x1U << 30) /* LSB first */ + +#define CTRLB_CHSIZE_8BIT (0x0U << 0) +#define CTRLB_SBMODE_1BIT (0x0U << 6) +#define CTRLB_TXEN (0x1U << 16) + +#define INTFLAG_DRE (0x1U << 0) /* Data Register Empty */ + +/* GCLK: generator 1 sources SERCOM1 */ +#define GCLK_GENCTRL1 (*(volatile uint32_t*)(GCLK_BASE + 0x20U + (1 * 4))) +#define GCLK_SYNCBUSY (*(volatile uint32_t*)(GCLK_BASE + 0x04U)) +#define GCLK_PCHCTRL(n) (*(volatile uint32_t*)(GCLK_BASE + 0x80U + ((n) * 4))) + +#define GCLK_GENCTRL_SRC_PLL0 (6U << 0) +#define GCLK_GENCTRL_DIV(x) (((uint32_t)(x) & 0xFFFFU) << 16) +#define GCLK_GENCTRL_GENEN (0x1U << 8) +#define GCLK_SYNCBUSY_GENCTRL1 (0x1U << 3) +#define GCLK_PCHCTRL_GEN1 (0x1U << 0) +#define GCLK_PCHCTRL_CHEN (0x1U << 6) + +/* PORT group 2 == port C */ +#define PORT_GROUP_SIZE (0x80U) +#define PORTC (PORT_BASE + (2 * PORT_GROUP_SIZE)) +#define PORTC_PMUX(n) (*(volatile uint8_t*)(PORTC + 0x30U + (n))) +#define PORTC_PINCFG(n) (*(volatile uint8_t*)(PORTC + 0x40U + (n))) + +#define PINCFG_PMUXEN (0x1U) + +/* Baud register value for 115200 with GCLK1 = PLL0/2 (150 MHz), 16x sampling. + * + * hal_init() programs PLL0 to 300 MHz before uart_init() runs, and GCLK + * generator 1 below divides it by 2, so the source clock is fixed regardless of + * what the caller passes. wolfBoot only ever asks for 115200, so rather than + * divide at runtime we use the same constant the reference driver does. */ +#define BAUD_115200 (64730U) + +static void pins_setup(void) +{ + /* PC4 = SERCOM1 TX, PC7 = SERCOM1 RX; both on peripheral function D. */ + PORTC_PINCFG(4) = PINCFG_PMUXEN; + PORTC_PINCFG(7) = PINCFG_PMUXEN; + PORTC_PMUX(2) = 0x3U; /* PC4 -> even nibble */ + PORTC_PMUX(3) = 0x30U; /* PC7 -> odd nibble */ +} + +static void clock_setup(void) +{ + GCLK_GENCTRL1 = + GCLK_GENCTRL_DIV(2U) | GCLK_GENCTRL_SRC_PLL0 | GCLK_GENCTRL_GENEN; + while ((GCLK_SYNCBUSY & GCLK_SYNCBUSY_GENCTRL1) != 0U) { + /* wait for generator 1 to synchronise */ + } + + GCLK_PCHCTRL(SERCOM_PCHCTRL) = GCLK_PCHCTRL_GEN1 | GCLK_PCHCTRL_CHEN; + while ((GCLK_PCHCTRL(SERCOM_PCHCTRL) & GCLK_PCHCTRL_CHEN) == 0U) { + /* wait for the peripheral channel to be enabled */ + } +} + +int uart_init(uint32_t bitrate, uint8_t data, char parity, uint8_t stop) +{ + /* Fixed 115200 8N1: see BAUD_115200. */ + (void)bitrate; + (void)data; + (void)parity; + (void)stop; + + pins_setup(); + clock_setup(); + + SERCOM_CTRLA = CTRLA_MODE_USART_INT | CTRLA_DORD | CTRLA_IBON; + SERCOM_BAUD = (uint16_t)BAUD_115200; + + /* Transmit only: nothing on this port ever reads from the console. */ + SERCOM_CTRLB = CTRLB_CHSIZE_8BIT | CTRLB_SBMODE_1BIT | CTRLB_TXEN; + while (SERCOM_SYNCBUSY != 0U) { + /* wait */ + } + + SERCOM_CTRLA |= CTRLA_ENABLE; + while (SERCOM_SYNCBUSY != 0U) { + /* wait */ + } + + return 0; +} + +int uart_tx(const uint8_t c) +{ + while ((SERCOM_INTFLAG & INTFLAG_DRE) == 0U) { + /* wait for the data register to drain */ + } + SERCOM_DATA = c; + return 1; +} + +int uart_rx(uint8_t* c) +{ + /* RX is not enabled on this port: CTRLB sets TXEN only. */ + (void)c; + return 0; +} + +#ifdef DEBUG_UART +void uart_write(const char* buf, unsigned int len) +{ + while (len--) { + uart_tx((uint8_t)*buf); + buf++; + } +} +#endif + +#endif /* TARGET_pic32cz */ diff --git a/include/user_settings.h b/include/user_settings.h index 7886a1bcc2..ed462afcc4 100644 --- a/include/user_settings.h +++ b/include/user_settings.h @@ -859,8 +859,13 @@ extern int tolower(int c); /* WOLF_CRYPTO_CB requires WC_RNG type for cryptocb.h function declarations. * Forward-declare as incomplete type — sufficient for WC_RNG* pointers in - * function signatures. We never call functions that dereference WC_RNG. */ -#if defined(WOLF_CRYPTO_CB) && defined(WC_NO_RNG) + * function signatures. We never call functions that dereference WC_RNG. + * + * Skipped under __ASSEMBLER__: wolfSSL's ARM .S sources pull settings.h in + * through the assembler, which cannot parse a C typedef. Only targets that + * combine a crypto callback (e.g. wolfHSM client) with ARM assembly reach + * this, which is why it went unnoticed. */ +#if defined(WOLF_CRYPTO_CB) && defined(WC_NO_RNG) && !defined(__ASSEMBLER__) typedef struct WC_RNG WC_RNG; #endif diff --git a/options.mk b/options.mk index 68f7bec926..bd2a6a2499 100644 --- a/options.mk +++ b/options.mk @@ -852,7 +852,10 @@ ifeq ($(DEBUG_UART),1) else ifeq ($(strip $(UART_TARGET)),) else UART_DRV_OBJ:=hal/uart/uart_drv_$(UART_TARGET).o - ifneq ($(wildcard $(UART_DRV_OBJ)),) + # Test for the driver SOURCE, not the object: the object does not exist on a + # clean tree, so testing for it meant DEBUG_UART was silently dropped on the + # very build that was supposed to enable it. + ifneq ($(wildcard $(UART_DRV_OBJ:.o=.c)),) CFLAGS+=-DDEBUG_UART ifneq ($(findstring $(UART_DRV_OBJ),$(OBJS)),$(UART_DRV_OBJ)) OBJS+=$(UART_DRV_OBJ) @@ -1465,6 +1468,17 @@ ifeq ($(WOLFBOOT_TEST_SIM_CRYPTOCB),1) endif endif +# Size of the wolfHSM comm data payload, shared by the client and server blocks +# below. The default is sized for certificate chains (the whole DER chain is +# shipped to the HSM in a single message) and for ML-DSA keys/signatures. +# +# Targets whose transport slot is smaller MUST override this in their .config: +# e.g. PIC32CZ's shared-memory slot is 4096 B, of which the transport CSR takes +# 8 B and the comm header another 8 B, so 4080 is a hard ceiling -- overrunning +# it silently corrupts the slot rather than failing the build. The value must +# also match the wolfHSM server's own build, or the two disagree on the layout. +WOLFHSM_CFG_COMM_DATA_LEN ?= 5000 + # wolfHSM client options ifeq ($(WOLFHSM_CLIENT),1) WOLFCRYPT_OBJS += \ @@ -1476,9 +1490,6 @@ ifeq ($(WOLFHSM_CLIENT),1) # ML-DSA asn.c decode/encode requires mp_xxx functions WOLFCRYPT_OBJS += \ $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/random.o - - # Large enough to handle the largest ML-DSA key/signature - CFLAGS += -DWOLFHSM_CFG_COMM_DATA_LEN=5000 endif WOLFHSM_OBJS += $(WOLFHSM_CLIENT_OBJS) @@ -1500,8 +1511,7 @@ ifeq ($(WOLFHSM_CLIENT),1) # authenticated via a certificate chain. Public keys baked into a local # keystore.c are not supported. KEYGEN_OPTIONS += --nolocalkeys - # big enough for cert chain - CFLAGS += -DWOLFHSM_CFG_COMM_DATA_LEN=5000 + CFLAGS += -DWOLFHSM_CFG_COMM_DATA_LEN=$(WOLFHSM_CFG_COMM_DATA_LEN) # wolfHSM client ID presented to the HSM server during the connection # handshake. Single value shared by all targets; defaults to 1. Override in the @@ -1545,7 +1555,7 @@ ifeq ($(WOLFHSM_SERVER),1) ifeq ($(SIGN),ML_DSA) WOLFCRYPT_OBJS += $(MATH_OBJS) # Large enough to handle the largest ML-DSA key/signature - CFLAGS += -DWOLFHSM_CFG_COMM_DATA_LEN=5000 + CFLAGS += -DWOLFHSM_CFG_COMM_DATA_LEN=$(WOLFHSM_CFG_COMM_DATA_LEN) endif WOLFHSM_OBJS += $(WOLFHSM_SERVER_OBJS) diff --git a/test-app/Makefile b/test-app/Makefile index c8c6fed54e..2369dbfaad 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -1083,6 +1083,9 @@ endif ifeq ($(TARGET), pic32cz) APP_OBJS+=../hal/pic32c.o + ifeq ($(DEBUG_UART),1) + APP_OBJS+=../hal/uart/uart_drv_pic32cz.o + endif endif CFLAGS+=-I"$(WOLFBOOT_LIB_WOLFSSL)" diff --git a/test-app/app_pic32cz.c b/test-app/app_pic32cz.c index 1354ccb374..8edc593595 100644 --- a/test-app/app_pic32cz.c +++ b/test-app/app_pic32cz.c @@ -28,6 +28,8 @@ #if defined(TARGET_pic32cz) +extern void uart_write(const char* buf, unsigned int len); + #define PORT_BASE (0x44840000U) #define PORTB_BASE (PORT_BASE + 0x80 * 1) @@ -58,6 +60,13 @@ void main(void) uint32_t boot_version; hal_init(); boot_version = wolfBoot_current_firmware_version(); + if (boot_version >= 2) { + static const char m[] = "APP: booted, verified firmware v2 (update applied)\r\n"; + uart_write(m, sizeof(m) - 1); + } else { + static const char m[] = "APP: booted, verified firmware v1\r\n"; + uart_write(m, sizeof(m) - 1); + } if (boot_version == 1) { wolfBoot_update_trigger(); led0_on(); diff --git a/tools/scripts/der2c.sh b/tools/scripts/der2c.sh new file mode 100755 index 0000000000..ae377b6680 --- /dev/null +++ b/tools/scripts/der2c.sh @@ -0,0 +1,60 @@ +#!/bin/sh +# +# der2c.sh - emit a DER blob as a C array on stdout. +# +# Used to embed wolfBoot's exported signing public key into a HAL that must +# hand it to an HSM at boot +# +# 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. +# +# wolfBoot is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + +set -eu + +if [ $# -ne 2 ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +DER="$1" +SYM="$2" + +if [ ! -r "$DER" ]; then + echo "$0: cannot read $DER" >&2 + exit 1 +fi + +echo "/* Generated from $(basename "$DER") by tools/scripts/der2c.sh. Do not edit. */" +echo "#ifndef WOLFBOOT_GEN_$(echo "$SYM" | tr '[:lower:]' '[:upper:]')_H" +echo "#define WOLFBOOT_GEN_$(echo "$SYM" | tr '[:lower:]' '[:upper:]')_H" +echo "" +echo "#include " +echo "" +echo "static const uint8_t ${SYM}[] = {" +od -An -v -tx1 "$DER" | awk ' +{ + for (i = 1; i <= NF; i++) { + if (n % 12 == 0) printf " " + printf " 0x%s,", $i + n++ + if (n % 12 == 0) printf "\n" + } +} +END { if (n % 12 != 0) printf "\n" }' +echo "};" +echo "" +echo "#endif"