Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
76db63f
F-7063: add missing break in arg2num case 4
danielinux Sep 22, 2026
bfda601
F-7059: detect short reads in the image hashing loops
danielinux Sep 22, 2026
96f507e
F-7058: bound-check positional and option arguments
danielinux Sep 22, 2026
16ab1e0
F-7057: use the size of the destination buffer
danielinux Sep 22, 2026
53f1d4e
F-7060: fill the swap area with erased bytes, not the update flags
danielinux Sep 22, 2026
2f9a8ea
F-7064: give the erase-completion ACK its long timeout
danielinux Sep 22, 2026
769c388
Remove the obsolete python keytools, convert remaining users to C
danielinux Sep 22, 2026
7b4a2ec
F-6758: hal_flash_write: derive DW base from address+i in else branch
danielinux Sep 23, 2026
bb99d7d
F-7061: sim: reject powerfail without an address argument
danielinux Sep 23, 2026
b092968
F-7384: hal_flash_erase: erase to the end of the requested range
danielinux Sep 23, 2026
0000505
F-7385: nrf54l spi: unblock spi_read after a DMA bus error
danielinux Sep 23, 2026
c94453b
F-7972: disk_open_mbr: return -1 when no usable partition
danielinux Sep 23, 2026
0f266e6
F-7973: qspi test_ext_flash: return -1, not -i, on mismatch
danielinux Sep 23, 2026
9b73957
F-7387: sdcard_send_switch_function: reject group 0
danielinux Sep 23, 2026
ab3b6f6
F-7386: sdcard_send_switch_function: fail when busy budget runs out
danielinux Sep 23, 2026
02f15ef
F-7062: sdhci: check sdhci_set_clock results at all three call sites
danielinux Sep 23, 2026
6b50581
F-13660: zeroize the nonce-derived IV copy in disk_crypto_set_iv
danielinux Sep 23, 2026
217dbe8
F-11039: zeroize XFREE'd slots in the static malloc pool
danielinux Sep 23, 2026
60803ad
F-14156: mp_clear the ECDSA r/s scalars after verify
danielinux Sep 23, 2026
8cec76e
F-14155: scrub the decoded key objects in sign.c cleanup
danielinux Sep 23, 2026
e1c7fb1
F-7393: zeroize the TPM session/SRK globals at deinit
danielinux Sep 23, 2026
525fd76
F-7395: zeroize the stack auth blobs in the TPM seal/unseal and NV paths
danielinux Sep 23, 2026
07301f9
F-12943: zeroize the policy session in seal/unseal blob cleanup
danielinux Sep 23, 2026
3e1f4a1
F-7395/F-12943: update the tpm unit tests for the new scrubs
danielinux Sep 23, 2026
b31a7c9
F-7395/F-12943: assert both scrub lengths in the unseal tests
danielinux Sep 23, 2026
a6eb491
unit-uart-flash: cover the extended erase-ACK budget
danielinux Sep 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 7 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Design based on [RFC 9019](https://datatracker.ietf.org/doc/rfc9019/) - A Firmwa

This repository contains the following components:
- the wolfBoot bootloader
- key generator and image signing tools (requires python 3.x and wolfcrypt-py https://github.com/wolfSSL/wolfcrypt-py)
- key generator and image signing tools
- Baremetal test applications

### wolfBoot bootloader
Expand Down Expand Up @@ -63,17 +63,17 @@ Additional examples available on our GitHub wolfBoot-examples repository [here](
The following steps are automated in the default `Makefile` target, using the baremetal test
application as an example to create the factory image. By running `make`, the build system will:

- Create a Ed25519 Key-pair using the `ed25519_keygen` tool
- Create a Ed25519 Key-pair using the `keygen` tool
- Compile the bootloader. The public key generated in the step above is included in the build
- Compile the firmware image from the test application in [test\_app](test-app/)
- Re-link the firmware to change the entry-point to the start address of the primary partition
- Sign the firmware image using the `ed25519_sign` tool
- Sign the firmware image using the `sign` tool
- Create a factory image by concatenating the bootloader and the firmware image

The factory image can be flashed to the target device. It contains the bootloader and the signed initial
firmware at the specified address on the flash.

The `sign.py` tool transforms a bootable firmware image to comply with the firmware image format required by the bootloader.
The `sign` tool transforms a bootable firmware image to comply with the firmware image format required by the bootloader.

For detailed information about the firmware image format, see [Firmware image](docs/firmware_image.md)

Expand All @@ -82,7 +82,7 @@ For detailed information about the configuration options for the target system,
### Upgrading the firmware

- Compile the new firmware image, and link it so that its entry point is at the start address of the primary partition
- Sign the firmware using the `sign.py` tool and the private key generated for the factory image
- Sign the firmware using the `sign` tool and the private key generated for the factory image
- Transfer the image using a secure connection, and store it to the secondary firmware slot
- Trigger the image swap using libwolfboot `wolfBoot_update_trigger()` function. See [wolfBoot library API](docs/API.md) for a description of the operation
- Reboot to let the bootloader begin the image swap
Expand Down Expand Up @@ -171,45 +171,13 @@ guidance and worked SBOM examples, see the

## Troubleshooting

1. Python errors when signing a key:

```
Traceback (most recent call last):
File "tools/keytools/keygen.py", line 135, in <module>
rsa = ciphers.RsaPrivate.make_key(2048)
AttributeError: type object 'RsaPrivate' has no attribute 'make_key'
```

```
Traceback (most recent call last):
File "tools/keytools/sign.py", line 189, in <module>
r, s = ecc.sign_raw(digest)
AttributeError: 'EccPrivate' object has no attribute 'sign_raw'
```

You need to install the latest wolfcrypt-py here: https://github.com/wolfSSL/wolfcrypt-py

Use `pip3 install wolfcrypt`.

Or to install based on a local wolfSSL installation use:

```sh
cd wolfssl
./configure --enable-keygen --enable-rsa --enable-ecc --enable-ed25519 --enable-des3 CFLAGS="-DFP_MAX_BITS=8192 -DWOLFSSL_PUBLIC_MP"
make
sudo make install

cd wolfcrypt-py
USE_LOCAL_WOLFSSL=/usr/local pip3 install .
```

2. Key algorithm mismatch:
1. Key algorithm mismatch:

The error `Key algorithm mismatch. Remove old keys via 'make keysclean'` indicates the current `.config` `SIGN` algorithm does not match what is in the generated `src/keystore.c` file.
Use `make keysclean` to delete keys and regenerate.


3. Cannot open compiler generated file ... Permission denied
2. Cannot open compiler generated file ... Permission denied

This may occur due to multiple environments being opened concurrently, or anti-virus software.
Try manually deleting the respective build directories and/or restarting your IDE.
Expand Down
8 changes: 6 additions & 2 deletions hal/max32666.c
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,11 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
{
int ret;
volatile uint32_t *flc_base;
uint32_t end;

/* Drive the loop from the end of the requested range so the tail is
* erased when the start address is rounded back to a page. */
end = address + (uint32_t)len;

/* Align to page boundary */
if (address & (FLASH_PAGE_SIZE - 1)) {
Expand All @@ -429,7 +434,7 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len)

icc_disable();

while (len > 0) {
while (address < end) {
flc_base = flc_base_for_addr(address);

ret = flc_page_erase(address, flc_base);
Expand All @@ -439,7 +444,6 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
}

address += FLASH_PAGE_SIZE;
len -= FLASH_PAGE_SIZE;
}

icc_enable();
Expand Down
7 changes: 5 additions & 2 deletions hal/mcxn.c
Original file line number Diff line number Diff line change
Expand Up @@ -310,16 +310,20 @@ void RAMFUNCTION hal_flash_lock(void)
int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
{
uint32_t sector_size = pflash_sector_size;
uint32_t end;

if (sector_size == 0U) {
sector_size = WOLFBOOT_SECTOR_SIZE;
}

/* Drive the loop from the end of the requested range so the tail is
* erased when the start address is rounded back to a sector. */
end = address + (uint32_t)len;
if ((address % sector_size) != 0U) {
address -= address % sector_size;
}

while (len > 0) {
while (address < end) {
if (FLASH_Erase(&pflash, address, sector_size,
kFLASH_ApiEraseKey) != kStatus_FLASH_Success) {
return -1;
Expand All @@ -329,7 +333,6 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
return -1;
}
address += sector_size;
len -= (int)sector_size;
}

return 0;
Expand Down
4 changes: 4 additions & 0 deletions hal/sim.c
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,10 @@ void hal_init(void)

for (i = 1; i < main_argc; i++) {
if (strcmp(main_argv[i], "powerfail") == 0) {
if ((i + 1) >= main_argc) {
wolfBoot_printf( "powerfail requires a hex address argument\n");
exit(-1);
}
erasefail_address = strtol(main_argv[++i], NULL, 16);
wolfBoot_printf( "Set power fail to erase at address %x\n",
erasefail_address);
Expand Down
8 changes: 7 additions & 1 deletion hal/spi/spi_drv_nrf54l.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,14 @@ void RAMFUNCTION spi_write(const char byte)
;
SPI_EVENTS_STOPPED = 0;

if (SPI_EVENTS_DMA_RX_BUSERROR == 0 && SPI_EVENTS_DMA_TX_BUSERROR == 0)
if (SPI_EVENTS_DMA_RX_BUSERROR == 0 && SPI_EVENTS_DMA_TX_BUSERROR == 0) {
spi_rx_ready = 1;
} else {
/* DMA bus error: force a defined byte and unblock the caller, or
* spi_read() would spin forever on spi_rx_ready == 0. */
spi_rx_byte = 0xFF;
spi_rx_ready = 1;
}
}


Expand Down
15 changes: 7 additions & 8 deletions hal/stm32g0.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,18 +150,17 @@ int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
flash_wait_complete();
i+=8;
} else {
uint32_t unit_addr = (address + i) & (~0x07);
int off = (address + i) - unit_addr;
uint32_t val[2];
uint8_t *vbytes = (uint8_t *)(val);
int off = (address + i) - (((address + i) >> 3) << 3);
uint32_t base_addr = address & (~0x07); /* aligned to 64 bit */
int u32_idx = (i >> 2);
dst = (uint32_t *)(base_addr);
val[0] = dst[u32_idx];
val[1] = dst[u32_idx + 1];
dst = (uint32_t *)unit_addr;
val[0] = dst[0];
val[1] = dst[1];
while ((off < 8) && (i < len))
vbytes[off++] = data[i++];
dst[u32_idx] = val[0];
dst[u32_idx + 1] = val[1];
dst[0] = val[0];
dst[1] = val[1];
flash_wait_complete();
}
}
Expand Down
15 changes: 7 additions & 8 deletions hal/stm32l4.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,18 +146,17 @@ int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
flash_wait_complete();
i+=8;
} else {
uint32_t unit_addr = (address + i) & (~0x07);
int off = (address + i) - unit_addr;
uint32_t val[2];
uint8_t *vbytes = (uint8_t *)(val);
int off = (address + i) - (((address + i) >> 3) << 3);
uint32_t base_addr = address & (~0x07); /* aligned to 64 bit */
int u32_idx = (i >> 2);
dst = (uint32_t *)(base_addr);
val[0] = dst[u32_idx];
val[1] = dst[u32_idx + 1];
dst = (uint32_t *)unit_addr;
val[0] = dst[0];
val[1] = dst[1];
while ((off < 8) && (i < len))
vbytes[off++] = data[i++];
dst[u32_idx] = val[0];
dst[u32_idx + 1] = val[1];
dst[0] = val[0];
dst[1] = val[1];
flash_wait_complete();
}
}
Expand Down
15 changes: 7 additions & 8 deletions hal/stm32wb.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,18 +204,17 @@ int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
flash_wait_complete();
i+=8;
} else {
uint32_t unit_addr = (address + i) & (~0x07);
int off = (address + i) - unit_addr;
uint32_t val[2];
uint8_t *vbytes = (uint8_t *)(val);
int off = (address + i) - (((address + i) >> 3) << 3);
uint32_t base_addr = address & (~0x07); /* aligned to 64 bit */
int u32_idx = (i >> 2);
dst = (uint32_t *)(base_addr);
val[0] = dst[u32_idx];
val[1] = dst[u32_idx + 1];
dst = (uint32_t *)unit_addr;
val[0] = dst[0];
val[1] = dst[1];
while ((off < 8) && (i < len))
vbytes[off++] = data[i++];
dst[u32_idx] = val[0];
dst[u32_idx + 1] = val[1];
dst[0] = val[0];
dst[1] = val[1];
flash_wait_complete();
}
}
Expand Down
2 changes: 1 addition & 1 deletion include/delta.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*
* Compile with DELTA_UPDATES=1
*
* Use tools/sign.py or tool/sign.c on the host to provide small
* Use the sign tool (tools/keytools/sign.c) on the host to provide small
* secure update packages containing only binary difference, using the
* --delta option.
*
Expand Down
4 changes: 4 additions & 0 deletions src/disk.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ static int disk_open_mbr(struct disk_drive *drive, const uint8_t *mbr_sector)
}
}

if (drive->n_parts == 0) {
return -1; /* no usable partition entries */
}

return drive->n_parts;
}

Expand Down
3 changes: 3 additions & 0 deletions src/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,9 @@ static void wolfBoot_verify_signature_ecc(uint8_t key_slot,
mp_read_unsigned_bin(&s, sig + point_sz, point_sz);
VERIFY_FN(img, &verify_res, wc_ecc_verify_hash_ex, &r, &s,
img->sha_hash, WOLFBOOT_SHA_DIGEST_SIZE, &verify_res, &ecc);
/* Signature scalars: scrub before the stack frame retires. */
mp_clear(&r);
mp_clear(&s);
}
#endif
}
Expand Down
2 changes: 1 addition & 1 deletion src/qspi_flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ static int test_ext_flash(void)
#endif
if (pageData[i] != (i & 0xff)) {
wolfBoot_printf("Check Data @ %d failed\n", i);
return -i;
return -1;
}
}

Expand Down
22 changes: 18 additions & 4 deletions src/sdhci.c
Original file line number Diff line number Diff line change
Expand Up @@ -1187,7 +1187,10 @@ static int sdcard_card_full_init(void)
}

if (status == 0) {
sdhci_set_clock(SDHCI_CLK_50MHZ);
if (sdhci_set_clock(SDHCI_CLK_50MHZ) == 0) {
wolfBoot_printf("UHS-I: failed to set 50MHz clock\n");
status = -1;
}
}

SDHCI_REG_SET(SDHCI_SRS13, irq_restore); /* re-enable interrupt */
Expand Down Expand Up @@ -1235,7 +1238,7 @@ static int sdcard_send_switch_function(uint32_t mode, uint32_t function_number,
uint32_t func_status[64/sizeof(uint32_t)]; /* fixed 512 bits */
uint8_t* p_func_status = (uint8_t*)func_status;

if (group_number > 6 || function_number > 15) {
if (group_number < 1 || group_number > 6 || function_number > 15) {
return -1; /* Invalid group or function number */
}

Expand Down Expand Up @@ -1268,6 +1271,11 @@ static int sdcard_send_switch_function(uint32_t mode, uint32_t function_number,
break;
}
} while (status == 0 && --timeout > 0); /* retry until function not busy */

if (timeout == 0) {
/* Card stayed busy until the retry budget ran out. */
status = -1;
}
return status;
}

Expand Down Expand Up @@ -1495,7 +1503,10 @@ static int emmc_card_full_init(void)
}

/* Set clock to 25MHz for legacy mode */
sdhci_set_clock(SDHCI_CLK_25MHZ);
if (sdhci_set_clock(SDHCI_CLK_25MHZ) == 0) {
wolfBoot_printf("eMMC: failed to set 25MHz clock\n");
return -1;
}

/* Enable high speed if desired (optional for legacy mode) */
sdhci_reg_or(SDHCI_SRS10, SDHCI_SRS10_HSE);
Expand Down Expand Up @@ -2000,7 +2011,10 @@ int sdhci_init(void)
SDHCI_REG_SET(SDHCI_SRS10, reg);

/* Setup 400khz starting clock */
sdhci_set_clock(SDHCI_CLK_400KHZ);
if (sdhci_set_clock(SDHCI_CLK_400KHZ) == 0) {
wolfBoot_printf("Failed to set 400kHz starting clock\n");
return -1;
}

/* Allow clock to stabilize before issuing first command */
udelay(1000); /* 1ms */
Expand Down
Loading
Loading