diff --git a/docs/API.md b/docs/API.md index ebc0883d..95530691 100644 --- a/docs/API.md +++ b/docs/API.md @@ -1,68 +1,105 @@ -# Application interface for interactions with the bootloader +# Application Interface for wolfBoot -wolfBoot offers a small interface to interact with the images stored in the partition, -explicitly initiate an update and confirm the success of a previously scheduled update. +wolfBoot provides an API through libwolfboot that allows applications to: +- Query firmware versions in both BOOT and UPDATE partitions +- Initiate firmware updates +- Confirm successful firmware boots +- Access partition states -## Compiling and linking with libwolfboot +## Compiling and Linking with libwolfboot -An application that requires interactions with wolfBoot must include the header file: +Applications using wolfBoot functionality must: -`#include ` +1. Include the wolfBoot header: + ```c + #include ` + ``` -This exports the API function declarations, and the predefined values for the flags -and tags stored together with the firmware images in the two partitions. +2. Link against libwolfboot library -For more information about flash partitions, flags and states see [Flash partitions](flash_partitions.md). +The header provides: +- API function declarations +- Predefined partition flag values +- Image tag definitions +- Partition state constants -## API +For details about flash partitions, flags and states see [Flash partitions](flash_partitions.md). -libwolfboot provides low-level access interface to flash partition states. The state -of each partition can be retrieved and altered by the application. +## Core API Functions -Basic interaction from the application is provided via the following high-level function calls: +libwolfboot provides both high-level and low-level interfaces to manage firmware updates: -`uint32_t wolfBoot_get_image_version(uint8_t part)` +### High-Level Functions -`void wolfBoot_update_trigger(void)` +```c +uint32_t wolfBoot_get_image_version(uint8_t part) +void wolfBoot_update_trigger(void) +void wolfBoot_success(void) +``` -`void wolfBoot_success(void)` +### Version Management Functions -### Firmware version +#### Get Image Version +```c +uint32_t wolfBoot_get_image_version(uint8_t part) +``` +Retrieves the version number of the firmware in the specified partition. -Current (boot) firmware and update firmware versions can be retrieved from the application using: +Parameters: +- `part`: Partition ID (PART_BOOT or PART_UPDATE) -`uint32_t wolfBoot_get_image_version(uint8_t part)` +Returns: +- Version number of the firmware in the specified partition +- 0 if no valid firmware exists in the partition -Or via the shortcut macros: +#### Convenience Macros +```c +wolfBoot_current_firmware_version() // Get version of firmware in BOOT partition +wolfBoot_update_firmware_version() // Get version of firmware in UPDATE partition +``` -`wolfBoot_current_firmware_version()` +### Update Management Functions -and +#### Trigger Update +```c +void wolfBoot_update_trigger(void) +``` +Initiates the firmware update process for the next boot. -`wolfBoot_update_firmware_version()` +Operation: +1. Sets UPDATE partition state to `STATE_UPDATING` +2. On next boot, wolfBoot will: + - Verify the update image signature + - Swap BOOT and UPDATE partition contents using SWAP space + - Set new firmware state to `STATE_TESTING` + - Boot into new firmware -### Trigger an update +Note: The update image must be stored in the UPDATE partition before calling this function. - - `wolfBoot_update_trigger()` is used to trigger an update upon the next reboot, and it is normally used by -an update application that has retrieved a new version of the running firmware, and has -stored it in the UPDATE partition on the flash. This function will set the state of the UPDATE partition -to `STATE_UPDATING`, instructing the bootloader to perform the update upon the next execution (after reboot). +### Boot Confirmation Functions -wolfBoot update process swaps the contents of the UPDATE and the BOOT partitions, using a temporary -single-block SWAP space. +#### Confirm Successful Boot +```c +void wolfBoot_success(void) +``` +Confirms successful boot of the current firmware. -### Confirm current image +Operation: +1. Marks current firmware in BOOT partition as `STATE_SUCCESS` +2. Prevents automatic rollback on next boot -- `wolfBoot_success()` indicates a successful boot of a new firmware. This can be called by the application -at any time, but it will only be effective to mark the current firmware (in the BOOT partition) with the state -`STATE_SUCCESS`, indicating that no roll-back is required. An application should typically call `wolfBoot_success()` -only after verifying that the basic system features are up and running, including the possibility to retrieve -a new firmware for the next upgrade. +Important: +- Should be called only after verifying critical system functionality +- Recommended to verify: + - Core system features work correctly + - Update capability is functional + - Any required peripherals are accessible -If after an upgrade and reboot wolfBoot detects that the active firmware is still in `STATE_TESTING` state, it means that -a successful boot has not been confirmed for the application, and will attempt to revert the update by swapping -the two images again. +Rollback Behavior: +- If firmware remains in `STATE_TESTING` state after reboot +- wolfBoot will automatically rollback to previous version +- Accomplished by re-swapping BOOT and UPDATE partitions -For more information about the update process, see [Firmware Update](firmware_update.md) - -For the image format, see [Firmware Image](firmware_image.md) +Related Documentation: +- [Firmware Update Process](firmware_update.md) +- [Firmware Image Format](firmware_image.md) diff --git a/docs/HAL.md b/docs/HAL.md index 148deaad..bab85f55 100644 --- a/docs/HAL.md +++ b/docs/HAL.md @@ -1,147 +1,263 @@ -# Hardware abstraction layer +# Hardware Abstraction Layer (HAL) -In order to run wolfBoot on a target microcontroller, an implementation of the HAL -must be provided. +The Hardware Abstraction Layer (HAL) provides the interface between wolfBoot and target hardware. Each supported microcontroller requires its own HAL implementation. -The HAL's purpose is to allow write/erase operations from the bootloader -and the application initiating the firmware upgrade through the application library, and -ensuring that the MCU is running at full speed during boot (to optimize the -verification of the signatures). +## Overview -The implementation of the hardware-specific calls for each platform are grouped in -a single c file in the [hal](../hal) directory. +The HAL serves two primary purposes: +1. Provide hardware-specific flash operations (read/write/erase) for both: + - Bootloader operations + - Application-initiated firmware updates +2. Ensure optimal MCU performance during boot for fast signature verification -The directory also contains a platform-specific linker script for each supported MCU, -with the same name and the `.ld` extension. This is used to link the bootloader's -firmware on the specific hardware, exporting all the necessary symbols for flash -and RAM boundaries. +## Implementation Structure + +HAL implementations are organized as follows: + +1. Platform-specific C files: + - Located in the [hal](../hal) directory + - One file per supported platform + - Contains all hardware-specific function implementations + +2. Platform-specific linker scripts: + - Located alongside HAL C files + - Named `platform_name.ld` + - Defines: + - Flash memory layout + - RAM boundaries + - Required symbol exports ## Supported platforms Please see [Targets](Targets.md) -## API +## Core HAL API -The Hardware Abstraction Layer (HAL) consists of six function calls -be implemented for each supported target: +Every HAL implementation must provide these six core functions: -`void hal_init(void)` +### System Initialization +```c +void hal_init(void) +``` +Called at bootloader startup to initialize the hardware. -This function is called by the bootloader at the very beginning of the execution. -Ideally, the implementation provided configures the clock settings for the target -microcontroller, to ensure that it runs at at the required speed to shorten the -time required for the cryptography primitives to verify the firmware images. +**Responsibilities:** +- Configure system clock for optimal performance +- Initialize critical peripherals +- Set up flash controller +- Configure any required hardware accelerators -`void hal_flash_unlock(void)` +### Flash Memory Operations -If the IAP interface of the flash memory of the target requires it, this function -is called before every write and erase operations to unlock write access to the -flash. On some targets, this function may be empty. +#### Unlock Flash +```c +void hal_flash_unlock(void) +``` +Prepares flash memory for write/erase operations. -`int hal_flash_write(uint32_t address, const uint8_t *data, int len)` +**Notes:** +- Called before any flash write/erase operation +- May be empty if target doesn't require explicit unlocking +- Must handle any required flash controller configuration -This function provides an implementation of the flash write function, using the -target's IAP interface. `address` is the offset from the beginning of the -flash area, `data` is the payload to be stored in the flash using the IAP interface, -and `len` is the size of the payload. Implementations of this function must be able to -handle writes of any size and alignment. Targets with a minimum programmable size -\> 1 byte must implement the appropriate read-modify-write logic in order to enable -wolfBoot to perform unaligned single-byte writes. `hal_flash_write` should return 0 upon -success, or a negative value in case of failure. +#### Write to Flash +```c +int hal_flash_write(uint32_t address, const uint8_t *data, int len) +``` +Writes data to internal flash memory. -`void hal_flash_lock(void)` +**Parameters:** +- `address`: Offset from flash start address +- `data`: Pointer to data buffer to write +- `len`: Number of bytes to write -If the IAP interface of the flash memory requires locking/unlocking, this function -restores the flash write protection by excluding write accesses. This function is called -by the bootloader at the end of every write and erase operations. +**Requirements:** +- Must handle any size/alignment of writes +- Must implement read-modify-write if needed +- Must work with minimum programmable unit size -`int hal_flash_erase(uint32_t address, int len)` +**Returns:** +- 0 on success +- Negative value on failure -Called by the bootloader to erase part of the flash memory to allow subsequent boots. -Erase operations must be performed via the specific IAP interface of the target microcontroller. -`address` marks the start of the area that the bootloader wants to erase, and `len` specifies -the size of the area to be erased. `address` is guaranteed to be aligned to `WOLFBOOT_SECTOR_SIZE`, -and `len` is guaranteed to be a multiple of `WOLFBOOT_SECTOR_SIZE`. This function must take into account -the geometry of the flash sectors, and erase all the sectors in between. +#### Lock Flash +```c +void hal_flash_lock(void) +``` +Re-enables flash write protection after operations. -`void hal_prepare_boot(void)` +**Notes:** +- Called after flash write/erase operations complete +- Restores flash controller to protected state +- Must reverse any changes made by `hal_flash_unlock()` -This function is called by the bootloader at a very late stage, before chain-loading the firmware -in the next stage. This can be used to revert all the changes made to the clock settings, to ensure -that the state of the microcontroller is restored to its original settings. +#### Erase Flash +```c +int hal_flash_erase(uint32_t address, int len) +``` +Erases a section of internal flash memory. -### Optional support for external flash memory +**Parameters:** +- `address`: Start address to erase (aligned to `WOLFBOOT_SECTOR_SIZE`) +- `len`: Number of bytes to erase (multiple of `WOLFBOOT_SECTOR_SIZE`) -WolfBoot can be compiled with the makefile option `EXT_FLASH=1`. When the external flash support is -enabled, update and swap partitions can be associated to an external memory, and will use alternative -HAL function for read/write/erase access. It can also be used in any scenario where flash reads require -special handling and must be redirected to a custom implementation. Note that `EXT_FLASH=1` is incompatible -with the `NVM_FLASH_WRITEONCE` option. +**Requirements:** +- Must handle flash sector geometry +- Must erase all sectors in specified range +- Must use target's IAP interface -To associate the update or the swap partition to an external memory, define `PART_UPDATE_EXT` and/or -`PART_SWAP_EXT`, respectively. +**Returns:** +- 0 on success +- Negative value on failure -The following functions are used to access the external memory, and must be defined when `EXT_FLASH` -is on: +### Boot Preparation +```c +void hal_prepare_boot(void) +``` +Prepares system for firmware execution. -`int ext_flash_write(uintptr_t address, const uint8_t *data, int len)` +**Called:** +- Just before chain-loading firmware +- After all bootloader operations complete -This function provides an implementation of the flash write function, using the -external memory's specific interface. `address` is the offset from the beginning of the -addressable space in the device, `data` is the payload to be stored, -and `len` is the size of the payload. The function is subject to the same restrictions as -`hal_flash_write()`. `ext_flash_write` should return 0 upon success, -or a negative value in case of failure. +**Responsibilities:** +- Restore default clock settings +- Reset modified peripherals +- Ensure clean hardware state for firmware -`int ext_flash_read(uintptr_t address, uint8_t *data, int len)` +## Optional HAL Extensions -This function provides an indirect read of the external memory, using the -driver's specific interface. `address` is the offset from the beginning of the -addressable space in the device, `data` is a pointer where payload is stored upon a successful -call, and `len` is the maximum size allowed for the payload. This function must be able to handle -reads of any size and alignment. `ext_flash_read` should return 0 upon success, or a negative value -in case of failure. +### External Flash Support -`int ext_flash_erase(uintptr_t address, int len)` +Enable with: `make EXT_FLASH=1` -Called by the bootloader to erase part of the external memory. -Erase operations must be performed via the specific interface of the target driver (e.g. SPI flash). -`address` marks the start of the area relative to the device, that the bootloader wants to erase, -and `len` specifies the size of the area to be erased. This function is subject to the same restrictions -as `hal_flash_erase()` and must take into account the geometry of the sectors, and erase all the sectors -in between. +This extension allows: +- Using external memory for UPDATE/SWAP partitions +- Custom handling of flash read operations +- Support for special flash interfaces -`void ext_flash_lock(void)` +**Configuration:** +- `PART_UPDATE_EXT`: Store UPDATE partition in external memory +- `PART_SWAP_EXT`: Store SWAP partition in external memory -If the interface of the external flash memory requires locking/unlocking, this function -may be used to restore the flash write protection or exclude write accesses. This function is called -by the bootloader at the end of every write and erase operations on the external device. +**Important Notes:** +- Incompatible with `NVM_FLASH_WRITEONCE` +- Requires implementing additional HAL functions +- Can be used for special flash handling needs + +### External Flash API + +When `EXT_FLASH=1` is enabled, the following functions must be implemented: + +#### Write to External Flash +```c +int ext_flash_write(uintptr_t address, const uint8_t *data, int len) +``` +Writes data to external flash memory. + +**Parameters:** +- `address`: Offset from external memory base address +- `data`: Pointer to data buffer to write +- `len`: Number of bytes to write + +**Requirements:** +- Must follow same restrictions as `hal_flash_write()` +- Must handle device-specific protocols (e.g., SPI) + +**Returns:** +- 0 on success +- Negative value on failure + +#### Read from External Flash +```c +int ext_flash_read(uintptr_t address, uint8_t *data, int len) +``` +Reads data from external flash memory. + +**Parameters:** +- `address`: Offset from external memory base address +- `data`: Buffer to store read data +- `len`: Number of bytes to read + +**Requirements:** +- Must handle any size/alignment of reads +- Must implement device-specific read protocol + +**Returns:** +- 0 on success +- Negative value on failure + +#### Erase External Flash +```c +int ext_flash_erase(uintptr_t address, int len) +``` +Erases a section of external flash memory. + +**Parameters:** +- `address`: Start address to erase +- `len`: Number of bytes to erase + +**Requirements:** +- Must follow same restrictions as `hal_flash_erase()` +- Must handle device-specific sector geometry +- Must implement proper erase commands + +**Returns:** +- 0 on success +- Negative value on failure + +#### External Flash Protection + +```c +void ext_flash_lock(void) +``` +Re-enables write protection for external flash. + +**Called:** +- After external flash operations complete +- Before returning control to application + +```c +void ext_flash_unlock(void) +``` +Disables write protection for external flash. + +**Called:** +- Before external flash write/erase operations +- May be empty if device doesn't require unlocking -`void ext_flash_unlock(void)` +### Dual-Bank Support -If the IAP interface of the external memory requires it, this function -is called before every write and erase operations to unlock write access to the -device. On some drivers, this function may be empty. - - -### Additional functions required by `DUALBANK_SWAP` option - -If the target device supports hardware-assisted bank swapping, it is appropriate -to provide two additional functions in the port: - -`void hal_flash_dualbank_swap(void)` - -Called by the bootloader when the two banks must be swapped. On some architectures -this operation implies a reboot, so this function may also never return. - - -`void fork_bootloader(void)` - -This function is called to provide a second copy of the bootloader. Wolfboot will -clone itself if the content does not already match. `fork_bootloader()` -implementation in new ports must return immediately without performing any actions -if the content of the bootloader partition in the two banks already match. +Some MCUs support hardware-assisted bank swapping for fail-safe updates. Enable with `DUALBANK_SWAP=1`. + +#### Required Functions + +```c +void hal_flash_dualbank_swap(void) +``` +Performs hardware bank swap operation. + +**Notes:** +- Called to switch between flash banks +- May trigger system reboot +- Implementation is platform-specific +- May not return on some architectures + +```c +void fork_bootloader(void) +``` +Manages bootloader redundancy across banks. + +**Responsibilities:** +- Creates backup copy of bootloader if needed +- Ensures both banks have identical bootloader code +- Returns immediately if banks already match + +**Usage:** +- Called during bank management operations +- Critical for fail-safe dual-bank operation +- Must be carefully implemented per platform diff --git a/docs/Loader.md b/docs/Loader.md index 7738dc95..b1512b15 100644 --- a/docs/Loader.md +++ b/docs/Loader.md @@ -1,30 +1,80 @@ -# wolfBoot Loaders / Updaters +# wolfBoot Loaders and Updaters -## loader.c +This document describes the different loader and updater implementations available in wolfBoot. -The default wolfBoot loader entry point that starts the wolfBoot secure boot process and leverages one of the `*_updater.c` implementations. +## Loader Types -## loader_stage1.c +### Primary Loader (loader.c) +The main wolfBoot entry point that: +- Initializes the secure boot process +- Manages the boot sequence +- Coordinates with updater implementations +- Verifies firmware signatures +- Handles partition management -A first stage loader whose purpose is to load wolfBoot from flash to ram and jump to it. This is required on platforms where flash is not memory mapped (XIP). For example on PowerPC e500v2 where external NAND flash is used for boot only a small 4KB region is available, so wolfBoot must be loaded to RAM and then run. +### Stage 1 Loader (loader_stage1.c) +A specialized first-stage loader for platforms without memory-mapped flash. -Example: `make WOLFBOOT_STAGE1_LOAD_ADDR=0x1000 stage1` +**Purpose:** +- Load wolfBoot from flash to RAM +- Initialize minimal hardware +- Jump to wolfBoot main entry -* `WOLFBOOT_STAGE1_SIZE`: Maximum size of wolfBoot stage 1 loader -* `WOLFBOOT_STAGE1_FLASH_ADDR`: Location in Flash for stage 1 loader (XIP from boot ROM) -* `WOLFBOOT_STAGE1_BASE_ADDR`: Address in RAM to load stage 1 loader to -* `WOLFBOOT_STAGE1_LOAD_ADDR`: Address in RAM to load wolfBoot to -* `WOLFBOOT_LOAD_ADDRESS`: Address in RAM to load application partition +**Use Cases:** +- Non-XIP (Execute-in-Place) flash systems +- Limited boot ROM regions (e.g., PowerPC e500v2 with 4KB boot area) +- External NAND flash configurations + +#### Configuration Options + +```make +make WOLFBOOT_STAGE1_LOAD_ADDR=0x1000 stage1 +``` + +| Option | Description | Usage | +|--------|-------------|--------| +| `WOLFBOOT_STAGE1_SIZE` | Maximum size of stage 1 loader | Ensure loader fits in boot ROM | +| `WOLFBOOT_STAGE1_FLASH_ADDR` | Flash location of stage 1 loader | Must match boot ROM entry point | +| `WOLFBOOT_STAGE1_BASE_ADDR` | RAM address for stage 1 loader | Temporary execution address | +| `WOLFBOOT_STAGE1_LOAD_ADDR` | RAM address for wolfBoot | Final wolfBoot location | +| `WOLFBOOT_LOAD_ADDRESS` | RAM address for application | Where firmware will be loaded | -## update_ram.c +## Updater Implementations -Implementation for RAM based updater +wolfBoot provides three different updater implementations to handle various hardware configurations: -## update_flash.c +### RAM-based Updater (update_ram.c) +Manages updates using system RAM as temporary storage. -Implementation for Flash based updater +**Features:** +- Loads firmware into RAM before verification +- Suitable for systems with sufficient RAM +- Reduces flash wear during update process -## update_flash_hwswap.c +### Flash-based Updater (update_flash.c) +Performs updates directly using flash memory. -Implementation for hardware assisted updater +**Features:** +- In-place update verification +- Efficient for systems with limited RAM +- Uses swap partition for fail-safe updates + +### Hardware-assisted Updater (update_flash_hwswap.c) +Leverages hardware-specific features for updates. + +**Features:** +- Uses hardware bank-switching capabilities +- Optimized for dual-bank flash systems +- Fastest update mechanism when supported +- No swap partition required + +## Implementation Selection + +The appropriate updater is selected based on: +- Available system memory +- Flash memory architecture +- Hardware capabilities +- Platform-specific requirements + +See [compile.md](compile.md) for configuration options affecting loader selection. diff --git a/docs/PQ.md b/docs/PQ.md index 9eb0caa2..f5144bdc 100644 --- a/docs/PQ.md +++ b/docs/PQ.md @@ -1,278 +1,257 @@ -# Post-Quantum Signatures +# Post-Quantum Signatures in wolfBoot -wolfBoot is continuously adding support for post-quantum (PQ) signature -algorithms as they mature. At present, support has been added for three NIST -approved PQ signature algorithms: +wolfBoot provides support for NIST-approved post-quantum (PQ) signature algorithms to ensure future-proof secure boot capabilities. -- ML-DSA: https://csrc.nist.gov/pubs/fips/204/final -- LMS/HSS: https://csrc.nist.gov/projects/stateful-hash-based-signatures -- XMSS/XMSS^MT: https://csrc.nist.gov/projects/stateful-hash-based-signatures +## Supported Algorithms -ML-DSA is a PQ lattice-based algorithm, derived from -CRYSTALS-DILITHIUM (a round three NIST finalist). +### 1. ML-DSA (Lattice-Based) +- FIPS 204 standardized algorithm +- Derived from CRYSTALS-DILITHIUM +- Reference: [FIPS 204 Final](https://csrc.nist.gov/pubs/fips/204/final) -LMS/HSS and XMSS/XMSS^MT are both PQ stateful hash-based signature (HBS) -schemes, recommended in NIST SP 800-208. +### 2. LMS/HSS (Hash-Based) +- Stateful hash-based signature scheme +- NIST SP 800-208 recommended +- Reference: [NIST Stateful HBS](https://csrc.nist.gov/projects/stateful-hash-based-signatures) -In terms of relative tradeoffs: -- All three methods have fast verifying operations. -- All three methods have variable length signature sizes. -- ML-DSA key generation is much faster than LMS/HSS and XMSS/XMSS^MT. -- ML-DSA public keys are larger than LMS/HSS and XMSS/XMSS^MT, and - variable sized. -- LMS/HSS and XMSS/XMSS^MT have stateful private keys, which requires - more care with key generation and signing operations. +### 3. XMSS/XMSS^MT (Hash-Based) +- Stateful hash-based signature scheme +- NIST SP 800-208 recommended +- Reference: [NIST Stateful HBS](https://csrc.nist.gov/projects/stateful-hash-based-signatures) -See these config files for simulated target examples: +## Algorithm Comparison -- `config/examples/sim-ml-dsa.config` -- `config/examples/sim-lms.config` -- `config/examples/sim-xmss.config` +| Feature | ML-DSA | LMS/HSS & XMSS/XMSS^MT | +|---------|--------|------------------------| +| Verification Speed | Fast | Fast | +| Signature Size | Variable | Variable | +| Key Generation | Fast | Slower | +| Public Key Size | Larger, Variable | Smaller | +| Private Key | Stateless | Stateful* | -## Lattice Based Signature Methods +*Stateful private keys require careful management during key generation and signing. -### ML-DSA - -ML-DSA (Module-Lattice Digital Signature Algorithm) was standardized in -FIPS 204 (https://csrc.nist.gov/pubs/fips/204/final), based on its -round 3 predecessor CRYSTALS-DILITHIUM. - -ML-DSA has three standardized parameter sets: - -- `ML-DSA-44` -- `ML-DSA-65` -- `ML-DSA-87` - -The numerical suffix (44, 65, 87) denotes the dimension of the matrix used -in the underlying lattice construction. - -The private key, public key, signature size, and overall security strength -all depend on the parameter set: +## Example Configurations +Find example configurations in: ``` -# -# Private Key Public Key Signature Size Security Strength -# ML-DSA-44 2560 1312 2420 Category 2 -# ML-DSA-65 4032 1952 3309 Category 3 -# ML-DSA-87 4896 2592 4627 Category 5 -# +config/examples/sim-ml-dsa.config # ML-DSA example +config/examples/sim-lms.config # LMS/HSS example +config/examples/sim-xmss.config # XMSS/XMSS^MT example ``` -### ML-DSA Config +## ML-DSA Implementation -A new ML-DSA sim example has been added here: +### Overview +ML-DSA (Module-Lattice Digital Signature Algorithm) is a FIPS 204 standardized algorithm based on lattice cryptography, derived from CRYSTALS-DILITHIUM. -``` -config/examples/sim-ml-dsa.config +### Parameter Sets + +ML-DSA offers three security levels, with numerical suffixes indicating matrix dimensions: + +| Parameter Set | Security Category | Description | +|--------------|-------------------|-------------| +| ML-DSA-44 | Category 2 | Lower security, smaller sizes | +| ML-DSA-65 | Category 3 | Medium security, balanced | +| ML-DSA-87 | Category 5 | Highest security, larger sizes | + +### Key and Signature Sizes + +| Parameter Set | Private Key (bytes) | Public Key (bytes) | Signature (bytes) | Security Category | +|--------------|---------------------|-------------------|-------------------|-------------------| +| ML-DSA-44 | 2,560 | 1,312 | 2,420 | Category 2 | +| ML-DSA-65 | 4,032 | 1,952 | 3,309 | Category 3 | +| ML-DSA-87 | 4,896 | 2,592 | 4,627 | Category 5 | + +### Configuration + +#### Basic Setup +```make +# In config file (e.g., config/examples/sim-ml-dsa.config) +ML_DSA_LEVEL=2 # Security category (2, 3, or 5) +IMAGE_SIGNATURE_SIZE=2420 # Must match parameter set +IMAGE_HEADER_SIZE?=4840 # Typically 2x signature size ``` -The security category level is configured with `ML_DSA_LEVEL=`, where -num = 2, 3, 5. Here is an example from the `sim-ml-dsa.config` for category -2: +#### Standards Compliance +- Default: FIPS 204 Final Standard +- Legacy Support: Use `WOLFSSL_DILITHIUM_FIPS204_DRAFT` for draft standard -``` -# ML-DSA config examples: -# -# Category 2: -ML_DSA_LEVEL=2 -IMAGE_SIGNATURE_SIZE=2420 -IMAGE_HEADER_SIZE?=4840 -``` +## Stateful Hash-Based Signatures (HBS) -Note: The wolfcrypt implementation of ML-DSA (dilithium) builds to the -FIPS 204 final standard by default. If you wish to conform to the older -FIPS 204 draft standard, then build with `WOLFSSL_DILITHIUM_FIPS204_DRAFT` -instead. +### Overview +LMS/HSS and XMSS/XMSS^MT are quantum-resistant signature schemes based on hash functions and Merkle trees. -## Stateful Hash-Based Signature Methods +**Key Features:** +- Small public key sizes +- Fast signature operations +- Configurable signature sizes +- Strong security foundations + - Based on hash function security + - Quantum-resistant by design + - Recommended by NIST SP 800-208 + - Included in NSA's CNSA 2.0 suite -LMS/HSS and XMSS/XMSS^MT are both post-quantum stateful hash-based signature -(HBS) schemes. They are known for having small public keys, relatively fast -signing and verifying operations, but larger signatures. Their signature sizes -however are tunable via their different parameters, which affords a space-time -tradeoff. +**Implementation Details:** +- LMS/HSS Implementation: + - Core files: `wc_lms.c`, `wc_lms_impl.c` + - Provides HSS (Hierarchical Signature System) + +- XMSS/XMSS^MT Implementation: + - Core files: `wc_xmss.c`, `wc_xmss_impl.c` + - Supports both single-tree and multi-tree variants -Stateful HBS schemes are based on the security of their underlying hash -functions and Merkle trees, which are not expected to be broken by the advent -of cryptographically relevant quantum computers. For this reason they have -been recommended by both NIST SP 800-208, and the NSA’s CNSA 2.0 suite. +**Additional Resources:** +- [wolfSSL HBS Documentation](https://www.wolfssl.com/documentation/manuals/wolfssl/appendix07.html#post-quantum-stateful-hash-based-signatures) +- [wolfSSL HBS Examples](https://github.com/wolfSSL/wolfssl-examples/tree/master/pq/stateful_hash_sig) -See these links for more info on stateful HBS support and wolfSSL/wolfCrypt: -- https://www.wolfssl.com/documentation/manuals/wolfssl/appendix07.html#post-quantum-stateful-hash-based-signatures -- https://github.com/wolfSSL/wolfssl-examples/tree/master/pq/stateful_hash_sig +### LMS/HSS Configuration -### Supported PQ HBS Options - -These two hash-based PQ signature options are supported: -- LMS: uses wolfcrypt implementation from `wc_lms.c`, and `wc_lms_impl.c`. -- XMSS: uses wolfcrypt implementation from `wc_xmss.c`, and `wc_xmss_impl.c`. - -### LMS/HSS Config - -A new LMS sim example has been added here: -``` -config/examples/sim-lms.config -``` - -The `LMS_LEVELS`, `LMS_HEIGHT`, and `LMS_WINTERNITZ`, `IMAGE_SIGNATURE_SIZE`, -and (optionally) `IMAGE_HEADER_SIZE` must be set: - -``` +#### Basic Setup +```make +# In config/examples/sim-lms.config SIGN?=LMS -... -LMS_LEVELS=2 -LMS_HEIGHT=5 -LMS_WINTERNITZ=8 -... -IMAGE_SIGNATURE_SIZE=2644 -IMAGE_HEADER_SIZE?=5288 +LMS_LEVELS=2 # Number of HSS levels +LMS_HEIGHT=5 # Tree height +LMS_WINTERNITZ=8 # Winternitz parameter +IMAGE_SIGNATURE_SIZE=2644 # From lms_siglen.sh +IMAGE_HEADER_SIZE?=5288 # Typically 2x signature size ``` -In LMS the signature size is a function of the parameters. Use the added helper -script `tools/lms/lms_siglen.sh` to calculate your signature length given your -LMS parameters: -``` -$ ./tools/lms/lms_siglen.sh 2 5 8 +#### Signature Size Calculator +Use the provided helper script to calculate required signature size: +```bash +$ ./tools/lms/lms_siglen.sh 2 5 8 levels: 2 height: 5 winternitz: 8 signature length: 2644 ``` -### XMSS/XMSS^MT Config +### XMSS/XMSS^MT Configuration -A new XMSS sim example has been added here: -``` -config/examples/sim-xmss.config -``` - -The `XMSS_PARAMS`, `IMAGE_SIGNATURE_SIZE`, and (optionally) `IMAGE_HEADER_SIZE` -must be set: - -``` +#### Basic Setup +```make +# In config/examples/sim-xmss.config SIGN?=XMSS -... -XMSS_PARAMS='XMSS-SHA2_10_256' -... -IMAGE_SIGNATURE_SIZE=2500 -IMAGE_HEADER_SIZE?=5000 +XMSS_PARAMS='XMSS-SHA2_10_256' # From NIST SP 800-208 +IMAGE_SIGNATURE_SIZE=2500 # From xmss_siglen.sh +IMAGE_HEADER_SIZE?=5000 # Typically 2x signature size ``` -The `XMSS_PARAMS` may be any SHA256 parameter set string from Tables 10 and 11 -from NIST SP 800-208. Use the helper script `tools/xmss/xmss_siglen.sh` to -calculate your signature length given your XMSS/XMSS^MT parameter string, e.g.: -``` +#### Parameter Sets +Supports all SHA256 parameter sets from NIST SP 800-208 Tables 10 and 11. + +#### Signature Size Calculator +```bash +# Single-tree XMSS $ ./tools/xmss/xmss_siglen.sh XMSS-SHA2_10_256 parameter set: XMSS-SHA2_10_256 signature length: 2500 -``` -``` +# Multi-tree XMSS^MT $ ./tools/xmss/xmss_siglen.sh XMSSMT-SHA2_20/2_256 parameter set: XMSSMT-SHA2_20/2_256 signature length: 4963 ``` -## Hybrid mode (classic + PQ) +## Hybrid Mode (Classic + Post-Quantum) -wolfBoot supports a hybrid mode where both classic and PQ signatures are verified, -sequentially. This allows for a gradual transition from classic to PQ signatures, -and protects the secure boot mechanism from potential vulnerabilities in either of -the two ciphers in use. +### Overview +wolfBoot supports hybrid signatures combining classic and post-quantum algorithms for: +- Gradual transition to post-quantum security +- Protection against vulnerabilities in either algorithm +- Maintaining backwards compatibility -The hybrid mode is enabled by setting a `SECONDARY_SIGN` option in the config file, -which specifies the secondary signature algorithm to be used. The secondary signature -option requires the option `WOLFBOOT_UNIVERSAL_KEYSTORE=1`, to ensure that the -keystore can handle both classic and PQ keys. +### Configuration -The secondary signature option can be set to any of the supported PQ signature options. - -The example configuration provided in `config/examples/sim-ml-dsa-ecc-hybrid.config` -demonstrates the use of hybrid mode with both ML-DSA-65 and ECC-384. - -### Hybrid signature - -The `sign` tool supports hybrid signatures. It is sufficient to specify two -ciphers argument from command line. When you do that, the tool expects two private -key files path passed as arguments, instead of one. - -The two public keys must be added to the same keystore. For this reason, the two -keypairs must be generated either at the same time, or in two subsequent steps. - -### Generating keypairs for hybrid signatures - -#### Generate both keys at the same time: - -``` -./tools/keytools/keygen --ml_dsa -g wolfboot_signing_private_key.der --ecc384 -g wolfboot_signing_second_private_key.der +#### Required Settings +```make +SECONDARY_SIGN= # Enable hybrid mode +WOLFBOOT_UNIVERSAL_KEYSTORE=1 # Required for hybrid keys ``` -both keys are automatically added to the same keystore. +#### Example Configuration +See `config/examples/sim-ml-dsa-ecc-hybrid.config` for ML-DSA-65 + ECC-384 hybrid setup. +### Hybrid Signature Support -#### Generate the two keys in separate steps +#### Key Generation Options -If you want to generate the keys in two steps, you will have to import the first -key in the new keystore. The first public key is stored in `keystore.der` during -the keypair generation: +1. **Simultaneous Key Generation** (Recommended) + - Generates both keys at once + - Automatically adds both to keystore + - Ensures proper key compatibility + +2. **Sequential Key Generation** + - Allows adding PQ keys to existing classic setup + - Requires manual keystore management + - Must follow specific import procedure + +### Key Generation Procedures + +#### Method 1: Single Command Generation +```bash +# Generate both ML-DSA and ECC384 keys +./tools/keytools/keygen --ml_dsa -g wolfboot_signing_private_key.der \ + --ecc384 -g wolfboot_signing_second_private_key.der ``` -./tools/keytools/keygen --ml_dsa -g wolfboot_signing_private_key.der +**Result:** Both keys are automatically added to keystore + +#### Method 2: Sequential Generation + +1. Generate First Key: + ```bash + # Generate ML-DSA key + ./tools/keytools/keygen --ml_dsa -g wolfboot_signing_private_key.der + ``` + +2. Extract Public Key: + ```bash + # Skip 16-byte keystore header + dd if=keystore.der of=ml_dsa-pubkey.der bs=1 skip=16 + ``` + +3. Generate Second Key with Import: + ```bash + # Generate ECC384 key while importing ML-DSA key + ./tools/keytools/keygen --ml_dsa -i ml_dsa-pubkey.der \ + --ecc384 -g wolfboot_signing_second_private_key.der + ``` + +**Result:** Complete keystore with both keys ready for hybrid verification + +### Firmware Signing with Hybrid Keys + +#### Signing Command +```bash +./tools/sign/sign --ml_dsa --ecc384 --sha256 test-app/image.elf \ + wolfboot_signing_private_key.der \ + wolfboot_signing_second_private_key.der 1 ``` -The first 16 bytes contain the keystore header, and must be skipped: +#### Command Parameters +- `--ml_dsa --ecc384`: Specify both signature algorithms +- `--sha256`: Hash algorithm +- `test-app/image.elf`: Input firmware image +- `wolfboot_signing_private_key.der`: Primary key (ML-DSA) +- `wolfboot_signing_second_private_key.der`: Secondary key (ECC384) +- `1`: Target partition ID -``` -dd if=keystore.der of=ml_dsa-pubkey.der bs=1 skip=16 -``` - -The new keypair can be generated (`-g`) while importing (`-i`)the old public key: - -``` -./tools/keytools/keygen --ml_dsa -i ml_dsa-pubkey.der -g --ecc384 wolfboot_signing_second_private_key.der -``` - -The keystore generated is now ready to be used by wolfBoot for hybrid signature verification. - -### Hybrid signature of the firmware - -In both examples above, the two private keys are now available in separate .der files. -The `sign` tool can now be used to sign the firmware with both keys: - -``` -./tools/sign/sign --ml_dsa --ecc384 --sha256 test-app/image.elf wolfboot_signing_private_key.der wolfboot_signing_second_private_key.der 1 -``` - -The command should confirm that both keys are loaded, and that the image is signed and includes the hybrid signature: +#### Expected Output ``` wolfBoot KeyTools (Compiled C version) wolfBoot version 2020000 Parsing arguments in hybrid mode -Secondary private key: wolfboot_signing_second_private_key.der -Secondary cipher: ECC384 -Version: 1 -Update type: Firmware -Input image: test-app/image.elf -Selected cipher: ML-DSA -Selected hash : SHA256 -Private key: wolfboot_signing_private_key.der -Secondary cipher: ECC384 -Secondary private key: wolfboot_signing_second_private_key.der -Output image: test-app/image_v1_signed.bin -Target partition id : 1 -info: using ML-DSA parameters: 3 -info: ML-DSA signature size: 3309 -Key buffer size: 5984 -info: ml-dsa priv len: 4032 -info: ml-dsa pub len: 1952 -Found ml-dsa key -image header size overridden by config value (8192 bytes) -Loading secondary key -Key buffer size: 144 -Secondary ECC key, size: 96 -image header size overridden by config value (8192 bytes) +... Creating hybrid signature -[...] ``` -The resulting image `image_v1_signed.bin` contains both signatures, and can be verified using a wolfBoot with hybrid signature support. +#### Results +- Output file: `test-app/image_v1_signed.bin` +- Contains both ML-DSA and ECC384 signatures +- Compatible with hybrid-enabled wolfBoot +- Verifiable using both algorithms during boot + +**Note:** Ensure wolfBoot is compiled with hybrid signature support to verify these images. diff --git a/docs/Renesas.md b/docs/Renesas.md index a2e5fd72..bfe076a5 100644 --- a/docs/Renesas.md +++ b/docs/Renesas.md @@ -1,80 +1,122 @@ -# Renesas wolfBoot +# Renesas wolfBoot Integration Guide -Platforms Supported: -* Renesas RZ (RZN2L) (RSIP) - - [docs/Targets.md#renesas-rzn2l](/docs/Targets.md#renesas-rzn2l) - - [IDE/Renesas/e2studio/RZN2L/Readme.md](/IDE/Renesas/e2studio/RZN2L/Readme.md) - - [IDE/Renesas/e2studio/RZN2L/Readme_wRSIP.md](/IDE/Renesas/e2studio/RZN2L/Readme_wRSIP.md) -* Renesas RA (RA6M4) (SCE) - - [docs/Targets.md#renesas-ra6m4](/docs/Targets.md#renesas-ra6m4) - - [IDE/Renesas/e2studio/RA6M4/Readme.md](/IDE/Renesas/e2studio/RA6M4/Readme.md) - - [IDE/Renesas/e2studio/RA6M4/Readme_withSCE.md](/IDE/Renesas/e2studio/RA6M4/Readme_withSCE.md) -* Renesas RX (RX65N/RX72N) (TSIP) - - [docs/Targets.md#renesas-rx72n](/docs/Targets.md#renesas-rx72n) - - [IDE/Renesas/e2studio/RX72N/Readme.md](/IDE/Renesas/e2studio/RX72N/Readme.md) - - [IDE/Renesas/e2studio/RX72N/Readme_withTSIP.md](/IDE/Renesas/e2studio/RX72N/Readme_withTSIP.md) +This guide covers wolfBoot integration with Renesas microcontrollers, including security features and development tools. -All of the Renesas examples support using e2Studio. -The Renesas RX parts support using wolfBoot Makefile's with the rx-elf-gcc cross-compiler and example .config files. +## Supported Platforms -### Security Key Management Tool (SKMT) Key Wrapping +### RZ Series +* **RZN2L with RSIP** + - Hardware Security: RSIP (Renesas Security IP) + - Documentation: + - [Target Details](docs/Targets.md#renesas-rzn2l) + - [e2studio Setup](IDE/Renesas/e2studio/RZN2L/Readme.md) + - [RSIP Integration](IDE/Renesas/e2studio/RZN2L/Readme_wRSIP.md) -1) Setup a Renesas KeyWrap account and do the PGP key exchange. -https://dlm.renesas.com/keywrap -You will get a public key from Renesas `keywrap-pub.key` that needs imported to PGP/GPG. -Note: You cannot use RSA 4096-bit key, must be RSA-2048 or RSA-3072. +### RA Series +* **RA6M4 with SCE** + - Hardware Security: SCE (Secure Crypto Engine) + - Documentation: + - [Target Details](docs/Targets.md#renesas-ra6m4) + - [e2studio Setup](IDE/Renesas/e2studio/RA6M4/Readme.md) + - [SCE Integration](IDE/Renesas/e2studio/RA6M4/Readme_withSCE.md) -2) Using "Security Key Management Tool" create 32-byte UFPK (User Factory Programming Key). This can be a random 32-byte value. -Example: Random 32-bytes `B94A2B96 1C755101 74F0C967 ECFC20B3 77C7FB25 6DB627B1 BFFADEE0 5EE98AC4` +### RX Series +* **RX65N/RX72N with TSIP** + - Hardware Security: TSIP (Trusted Secure IP) + - Documentation: + - [Target Details](docs/Targets.md#renesas-rx72n) + - [e2studio Setup](IDE/Renesas/e2studio/RX72N/Readme.md) + - [TSIP Integration](IDE/Renesas/e2studio/RX72N/Readme_withTSIP.md) -3) Sign and Encrypt the 32-byte binary file with PGP the `sample.key`. Result is `sample.key.gpg`. -Use GPG4Win and the Sign/Encrypt option. Sign with your own GPG key and encrypt with the Renesas public key. +## Development Environment -4) Use https://dlm.renesas.com/keywrap to wrap `sample.key.gpg`. -It will use the Hidden Root Key (HRK) that both Renesas and the RX TSIP have pre-provisioned from Renesas Factory. -Result is `sample.key_enc.key`. Example: `00000001 6CCB9A1C 8AA58883 B1CB02DE 6C37DA60 54FB94E2 06EAE720 4D9CCF4C 6EEB288C` +### IDE Support +- All platforms: Renesas e2studio IDE -### RX TSIP +### Build System Options +- RX Series: + - Makefile-based build with rx-elf-gcc + - Example configurations provided -1) Build key tools for Renesas +## Security Key Management + +### SKMT (Security Key Management Tool) Setup + +#### 1. KeyWrap Account Setup +1. Register at [Renesas KeyWrap Portal](https://dlm.renesas.com/keywrap) +2. Complete PGP key exchange process + - Receive Renesas public key (`keywrap-pub.key`) + - Import key to PGP/GPG system + +**Important:** Use RSA-2048 or RSA-3072 keys only (RSA-4096 not supported) + +#### 2. UFPK Generation +1. Launch Security Key Management Tool +2. Generate 32-byte UFPK (User Factory Programming Key) + ``` + Example UFPK: + B94A2B96 1C755101 74F0C967 ECFC20B3 + 77C7FB25 6DB627B1 BFFADEE0 5EE98AC4 + ``` + +#### 3. Key Encryption +1. Create binary key file (`sample.key`) +2. Using GPG4Win: + - Sign with your GPG key + - Encrypt with Renesas public key + - Output: `sample.key.gpg` + +#### 4. Key Wrapping +1. Visit [KeyWrap Portal](https://dlm.renesas.com/keywrap) +2. Upload `sample.key.gpg` +3. System uses factory-provisioned HRK (Hidden Root Key) +4. Download wrapped key (`sample.key_enc.key`) + ``` + Example wrapped key: + 00000001 6CCB9A1C 8AA58883 B1CB02DE + 6C37DA60 54FB94E2 06EAE720 4D9CCF4C + 6EEB288C + ``` + +## RX TSIP Integration + +### Building Key Tools ```sh -# Build keytools for Renesas RX (TSIP) -$ make keytools RENESAS_KEY=2 +# Build keytools with Renesas RX (TSIP) support +make keytools RENESAS_KEY=2 ``` -2) wolfBoot public key (create or import existing) +### Key Management -Instructions below for ECDSA P384 (SECP384R1). -For SECP256R1 replace "ecc384" with "ecc256" and "secp384r1" with "secp256r1". - -Create new signing key: +#### Option 1: Create New Signing Keys +For ECDSA P384 (SECP384R1): ```sh -# Create new signing key -$ ./tools/keytools/keygen --ecc384 -g ./pri-ecc384.der -Keytype: ECC384 -Generating key (type: ECC384) -Associated key file: ./pri-ecc384.der -Partition ids mask: ffffffff -Key type : ECC384 -Public key slot: 0 -Done. +# Generate private key +./tools/keytools/keygen --ecc384 -g ./pri-ecc384.der -# Export public portion of key as PEM -$ openssl ec -inform der -in ./pri-ecc384.der -pubout -out ./pub-ecc384.pem +# Export public key as PEM +openssl ec -inform der -in ./pri-ecc384.der -pubout -out ./pub-ecc384.pem ``` -OR +**Note:** For SECP256R1, replace: +- `ecc384` with `ecc256` +- `secp384r1` with `secp256r1` -Import Public Key: +#### Option 2: Import Existing Public Key ```sh -# Export public portion of key as DER -$ openssl ec -inform der -in ./pri-ecc384.der -pubout -outform der -out ./pub-ecc384.der +# Export public key as DER +openssl ec -inform der -in ./pri-ecc384.der -pubout \ + -outform der -out ./pub-ecc384.der -# Import public key and populate src/keystore.c -$ ./tools/keytools/keygen --ecc384 -i ./pub-ecc384.der +# Import to keystore +./tools/keytools/keygen --ecc384 -i ./pub-ecc384.der +``` + +**Expected Output:** +``` Keytype: ECC384 Associated key file: ./pub-ecc384.der Partition ids mask: ffffffff @@ -83,67 +125,85 @@ Public key slot: 0 Done. ``` -3) Create wrapped public key (code files) +### Wrapped Key Generation -Use the Security Key Management Tool (SKMT) command line tool (CLI) to create a wrapped public key. - -This will use the user encryption key to wrap the public key and output key_data.c / key_data.h files. +#### 1. Generate Source Files +Use SKMT CLI to create wrapped key source files: ```sh -$ C:\Renesas\SecurityKeyManagementTool\cli\skmt.exe -genkey -ufpk file=./sample.key -wufpk file=./sample.key_enc.key -key file=./pub-ecc384.pem -mcu RX-TSIP -keytype secp384r1-public -output include/key_data.c -filetype csource -keyname enc_pub_key -Output File: include\key_data.h -Output File: include\key_data.c -UFPK: B94A2B961C75510174F0C967ECFC20B377C7FB256DB627B1BFFADEE05EE98AC4 -W-UFPK: 000000016CCB9A1C8AA58883B1CB02DE6C37DA6054FB94E206EAE7204D9CCF4C6EEB288C -IV: 6C296A040EEF5EDD687E8D3D98D146D0 -Encrypted key: 5DD8D7E59E6AC85AE340BBA60AA8F8BE56C4C1FE02340C49EB8F36DA79B8D6640961FE9EAECDD6BADF083C5B6060C1D0309D28EFA25946F431979B9F9D21E77BDC5B1CC7165DE2F4AE51E418746260F518ED0C328BD3020DEC9B774DC00270B0CFBBE3DD738FDF715342CFBF2D461239 +C:\Renesas\SecurityKeyManagementTool\cli\skmt.exe -genkey \ + -ufpk file=./sample.key \ + -wufpk file=./sample.key_enc.key \ + -key file=./pub-ecc384.pem \ + -mcu RX-TSIP \ + -keytype secp384r1-public \ + -output include/key_data.c \ + -filetype csource \ + -keyname enc_pub_key ``` -4) Create wrapped public key (flash file) +**Output Files:** +- `include/key_data.h` +- `include/key_data.c` -Generate Motorola HEX file to write wrapped key to flash. +#### 2. Generate Flash Image +Create Motorola S-Record (SREC) file for flash programming: ```sh -$ C:\Renesas\SecurityKeyManagementTool\cli\skmt.exe -genkey -ufpk file=./sample.key -wufpk file=./sample.key_enc.key -key file=./pub-ecc384.pem -mcu RX-TSIP -keytype secp384r1-public -output pub-ecc384.srec -filetype "mot" -address FFFF0000 -Output File: Y:\GitHub\wolfboot\pub-ecc384.srec -UFPK: B94A2B961C75510174F0C967ECFC20B377C7FB256DB627B1BFFADEE05EE98AC4 -W-UFPK: 000000016CCB9A1C8AA58883B1CB02DE6C37DA6054FB94E206EAE7204D9CCF4C6EEB288C -IV: 9C13402DF1AF631DC2A10C2424182601 -Encrypted key: C4A0B368552EB921A3AF3427FD7403BBE6CB8EE259D6CC0692AA72D46F7343F5FFE7DA97A1C811B21BF392E3834B67C3CE6F84707CCB8923D4FBB8DA003EF23C1CD785B6F58E5DB161F575F78D646434AC2BFAF207F6FFF6363C800CFF7E7BFF4857452A70C496B675D08DD6924CAB5E +C:\Renesas\SecurityKeyManagementTool\cli\skmt.exe -genkey \ + -ufpk file=./sample.key \ + -wufpk file=./sample.key_enc.key \ + -key file=./pub-ecc384.pem \ + -mcu RX-TSIP \ + -keytype secp384r1-public \ + -output pub-ecc384.srec \ + -filetype "mot" \ + -address FFFF0000 ``` -The generated file is a Motorola HEX (S-Record) formatted image containing the wrapped public key with instructions to use the `0xFFFF0000` address. +#### Flash Memory Configuration -``` -S00E00007075622D65636333737265D5 -S315FFFF000000000000000000006CCB9A1C8AA58883C5 -S315FFFF0010B1CB02DE6C37DA6054FB94E206EAE720E7 -S315FFFF00204D9CCF4C6EEB288C9C13402DF1AF631D7F -S315FFFF0030C2A10C2424182601C4A0B368552EB921EA -S315FFFF0040A3AF3427FD7403BBE6CB8EE259D6CC06AE -S315FFFF005092AA72D46F7343F5FFE7DA97A1C811B27D -S315FFFF00601BF392E3834B67C3CE6F84707CCB8923ED -S315FFFF0070D4FBB8DA003EF23C1CD785B6F58E5DB1F0 -S315FFFF008061F575F78D646434AC2BFAF207F6FFF66C -S315FFFF0090363C800CFF7E7BFF4857452A70C496B6D9 -S311FFFF00A075D08DD6924CAB5ED6FF44C5E3 -S705FFFF0000FC +**Default Address:** `0xFFFF0000` + +To modify the default address, update: +1. Build Configuration: + ```c + // In user_settings.h + #define RENESAS_TSIP_INSTALLEDKEY_ADDR 0xFFFF0000 + ``` + +2. Linker Script: + ``` + // In hal/rx72n.ld or hal/rx65n.ld + .rot : { + /* Update address here */ + } + ``` + +### Building and Flashing + +#### 1. Configure Build +Edit `.config`: +```make +PKA?=1 # Enable Public Key Acceleration ``` -The default flash memory address is `0xFFFF0000`, but it can be changed. The following two places must be set: -a) The `user_settings.h` build macro `RENESAS_TSIP_INSTALLEDKEY_ADDR` -b) The linker script `.rot` section (example `hal/rx72n.ld` or `hal/rx65n.ld`). - -5) Edit .config `PKA?=1`. - -6) Rebuild wolfBoot. `make clean && make wolfboot.srec` - -7) Sign application - -Sign application using the created private key above `pri-ecc384.der`: - +#### 2. Build wolfBoot ```sh -$ ./tools/keytools/sign --ecc384 --sha256 test-app/image.bin pri-ecc384.der 1 +make clean +make wolfboot.srec +``` + +#### 3. Sign Application +Use private key to sign the application image: +```sh +./tools/keytools/sign --ecc384 --sha256 \ + test-app/image.bin \ + pri-ecc384.der 1 +``` + +**Expected Output:** +``` wolfBoot KeyTools (Compiled C version) wolfBoot version 2010000 Update type: Firmware @@ -153,22 +213,30 @@ Selected hash : SHA256 Public key: pri-ecc384.der Output image: test-app/image_v1_signed.bin Target partition id : 1 -image header size overridden by config value (1024 bytes) -Calculating SHA256 digest... -Signing the digest... +... Output image(s) successfully created. ``` -8) Flash wolfboot.srec, pub-ecc384.srec and signed application binary - -Download files to flash using Renesas flash programmer. +#### 4. Flash Images +Using Renesas Flash Programmer, flash: +1. `wolfboot.srec` (Bootloader) +2. `pub-ecc384.srec` (Public Key) +3. `test-app/image_v1_signed.bin` (Application) -#### RX TSIP Benchmarks +### Performance Benchmarks -| Hardware | Clock | Algorithm | RX TSIP | Debug | Release (-Os) | Release (-O2) | -| -------- | ------ | ----------------- | -------- | -------- | ------------- | ------------- | -| RX72N | 240MHz | ECDSA Verify P384 | 17.26 ms | 1570 ms | 441 ms | 313 ms | -| RX72N | 240MHz | ECDSA Verify P256 | 2.73 ms | 469 ms | 135 ms | 107 ms | -| RX65N | 120MHz | ECDSA Verify P384 | 18.57 ms | 4213 ms | 2179 ms | 1831 ms | -| RX65N | 120MHz | ECDSA Verify P256 | 2.95 ms | 1208 ms | 602 ms | 517 ms | +#### RX TSIP Signature Verification + +| MCU | Clock | Algorithm | Hardware Accel | Debug | Release (-Os) | Release (-O2) | +|-------|--------|-----------|----------------|--------|---------------|---------------| +| RX72N | 240MHz | P384 ECDSA| 17.26 ms | 1570 ms| 441 ms | 313 ms | +| RX72N | 240MHz | P256 ECDSA| 2.73 ms | 469 ms | 135 ms | 107 ms | +| RX65N | 120MHz | P384 ECDSA| 18.57 ms | 4213 ms| 2179 ms | 1831 ms | +| RX65N | 120MHz | P256 ECDSA| 2.95 ms | 1208 ms| 602 ms | 517 ms | + +**Notes:** +- Hardware acceleration provides 10-90x speedup +- P256 operations are significantly faster than P384 +- Higher clock speeds improve performance proportionally +- Optimization levels have significant impact on software implementation diff --git a/docs/STM32-TZ.md b/docs/STM32-TZ.md index d928760a..72a10f44 100644 --- a/docs/STM32-TZ.md +++ b/docs/STM32-TZ.md @@ -1,131 +1,154 @@ -## wolfCrypt in TrustZone-M secure domain +# TrustZone-M Integration Guide -ARMv8-M microcontrollers support hardware-assisted domain separation for running -software. This TEE mechanism provides two separate domains (secure & non-secure), -and an additional zone that can be used as interface to call into secure -functions from the non-secure domain (non-secure callable). +## Overview -wolfBoot may optionally export the crypto functions as a non-callable APIs that -are accessible from any software staged in non-secure domain. +### TrustZone-M Architecture +ARMv8-M microcontrollers provide hardware-assisted security through domain separation: +- Secure Domain: For trusted code and resources +- Non-secure Domain: For application code +- Non-secure Callable: Interface for secure function calls -### Compiling wolfBoot with wolfCrypt in TrustZone-M secure domain +### wolfBoot TrustZone Features +wolfBoot leverages TrustZone-M to: +- Isolate cryptographic operations +- Protect sensitive key material +- Provide secure services to applications -When wolfBoot is compiled with the options `TZEN=1` and `WOLFCRYPT_TZ=1`, -a more complete set of components of the wolfCrypt crypto library are built-in -the bootloader, and they can be accessed by applications or OSs running in -non-secure domain through non-secure callable APIs. - -This feature is used to isolate the core crypto operations from the applications. - -### PKCS11 API in non-secure world - -The `WOLFCRYPT_TZ_PKCS11` option provides a standard PKCS11 interface, -including a storage for PKCS11 objects in a dedicated flash area in secure mode. - -This means that applications, TLS libraries and operating systems running in -non-secure domain can access wolfCrypt through a standard PKCS11 interface and -use the crypto library with pre-provisioned keys that are never exposed to the -non-secure domain. - -### Example using STM32L552 - - - Copy the example configuration for STM32-L5 with support for wolfCrypt in - TrustZone-M and PKCS11 interface: `cp config/examples/stm32l5-wolfcrypt-tz.config .config` - - - Run `make`. `wolfboot.elf` and the test applications are built as separate - objects. The application is signed and stored as `test-app/image_v1_signed.bin`. - - - Ensure that the option bytes on your target device are set as follows: +## Configuration Options +### Core TrustZone Support +```make +TZEN=1 # Enable TrustZone support +WOLFCRYPT_TZ=1 # Build wolfCrypt in secure domain ``` -OPTION BYTES BANK: 0 - Read Out Protection: +**Features:** +- Complete wolfCrypt library in secure domain +- Non-secure callable crypto APIs +- Isolated crypto operations from applications - RDP : 0xAA (Level 0, no protection) +### PKCS#11 Integration +```make +WOLFCRYPT_TZ_PKCS11=1 # Enable PKCS#11 interface +``` - BOR Level: +**Features:** +- Standard PKCS#11 API for non-secure domain +- Secure flash storage for PKCS#11 objects +- Pre-provisioned keys never exposed to non-secure world +- TLS and application support through standard interface - BOR_LEV : 0x0 (BOR Level 0, reset level threshold is around 1.7 V) +## STM32L552 Implementation - User Configuration: +### Quick Start +1. Copy example configuration: + ```bash + cp config/examples/stm32l5-wolfcrypt-tz.config .config + ``` - nRST_STOP : 0x1 (No reset generated when entering Stop mode) - nRST_STDBY : 0x1 (No reset generated when entering Standby mode) - nRST_SHDW : 0x1 (No reset generated when entering the Shutdown mode) - IWDG_SW : 0x1 (Software independant watchdog) - IWDG_STOP : 0x1 (IWDG counter active in stop mode) - IWDG_STDBY : 0x1 (IWDG counter active in standby mode) - WWDG_SW : 0x1 (Software window watchdog) - SWAP_BANK : 0x0 (Bank 1 and bank 2 address are not swapped) - DB256 : 0x1 (256Kb dual-bank Flash with contiguous addresses) - DBANK : 0x0 (Single bank mode with 128 bits data read width) - SRAM2_PE : 0x1 (SRAM2 parity check disable) - SRAM2_RST : 0x1 (SRAM2 is not erased when a system reset occurs) - nSWBOOT0 : 0x1 (BOOT0 taken from PH3/BOOT0 pin) - nBOOT0 : 0x1 (nBOOT0 = 1) - PA15_PUPEN : 0x1 (USB power delivery dead-battery disabled/ TDI pull-up activated) - TZEN : 0x1 (Global TrustZone security enabled) - HDP1EN : 0x0 (No HDP area 1) - HDP1_PEND : 0x0 (0x8000000) - HDP2EN : 0x0 (No HDP area 2) - HDP2_PEND : 0x0 (0x8000000) - NSBOOTADD0 : 0x100000 (0x8000000) - NSBOOTADD1 : 0x17F200 (0xBF90000) - SECBOOTADD0 : 0x180000 (0xC000000) - BOOT_LOCK : 0x0 (Boot based on the pad/option bit configuration) +2. Build project: + ```bash + make + ``` + Outputs: + - `wolfboot.elf`: Secure bootloader + - `test-app/image_v1_signed.bin`: Signed application - Secure Area 1: +### Option Bytes Configuration - SECWM1_PSTRT : 0x0 (0x8000000) - SECWM1_PEND : 0x39 (0x8039000) +#### Bank 0: Core Configuration +``` +Read Out Protection: + RDP : 0xAA (Level 0, no protection) - Write Protection 1: +BOR Level: + BOR_LEV : 0x0 (Reset at 1.7V) - WRP1A_PSTRT : 0x7F (0x807F000) - WRP1A_PEND : 0x0 (0x8000000) - WRP1B_PSTRT : 0x7F (0x807F000) - WRP1B_PEND : 0x0 (0x8000000) -OPTION BYTES BANK: 1 +TrustZone Settings: + TZEN : 0x1 (TrustZone enabled) + NSBOOTADD0 : 0x100000 (0x8000000) + NSBOOTADD1 : 0x17F200 (0xBF90000) + SECBOOTADD0 : 0x180000 (0xC000000) + BOOT_LOCK : 0x0 (Option-based boot) - Secure Area 2: +Memory Configuration: + DB256 : 0x1 (256KB dual-bank flash) + DBANK : 0x0 (Single bank, 128-bit width) + SRAM2_PE : 0x1 (SRAM2 parity disabled) + SRAM2_RST : 0x1 (SRAM2 preserved on reset) - SECWM2_PSTRT : 0x7F (0x807F000) - SECWM2_PEND : 0x0 (0x8000000) +System Settings: + nRST_STOP : 0x1 (No reset in Stop mode) + nRST_STDBY : 0x1 (No reset in Standby) + nRST_SHDW : 0x1 (No reset in Shutdown) + IWDG_SW : 0x1 (Software watchdog) + WWDG_SW : 0x1 (Software window watchdog) +``` - Write Protection 2: +#### Bank 1: Memory Protection +``` +Secure Areas: + SECWM1_PSTRT : 0x0 (0x8000000) + SECWM1_PEND : 0x39 (0x8039000) + SECWM2_PSTRT : 0x7F (0x807F000) + SECWM2_PEND : 0x0 (0x8000000) - WRP2A_PSTRT : 0x7F (0x80BF000) - WRP2A_PEND : 0x0 (0x8040000) - WRP2B_PSTRT : 0x7F (0x80BF000) - WRP2B_PEND : 0x0 (0x8040000) +Write Protection: + WRP1A/B_PSTRT: 0x7F (0x807F000) + WRP1A/B_PEND : 0x0 (0x8000000) + WRP2A/B_PSTRT: 0x7F (0x80BF000) + WRP2A/B_PEND : 0x0 (0x8040000) ``` - - Upload `wolfboot.bin` and the test application to the two different domains in flash: +### Programming and Testing -``` +#### Flash Programming +```bash +# Program secure bootloader STM32_Programmer_CLI -c port=swd -d wolfboot.bin 0x0C000000 + +# Program application image STM32_Programmer_CLI -c port=swd -d test-app/image_v1_signed.bin 0x08040000 ``` - - After rebooting, the LED on the board should turn on sequentially: - - Red LED: Secure boot was successful. Application has started. - - Blue LED: PKCS11 Token has been initialized and stored - - Green LED: ECDSA Sign/Verify test successful +#### Verification Steps +Monitor LED sequence: +1. **Red LED**: Secure boot verification passed +2. **Blue LED**: PKCS#11 token initialized +3. **Green LED**: ECDSA test successful + +**Note:** LED sequence confirms proper: +- Domain separation +- Secure boot chain +- Cryptographic operations -### Example using STM32H563 +## STM32H563 Implementation - - Copy one of the example configurations for STM32H5 with support for TrustZone and PKCS11 to `.config`: - `cp config/examples/stm32h5-tz.config .config` - `cp config/examples/stm32h5-tz-dualbank-otp.config .config` (with Dual Bank) - `cp config/examples/stm32h5-tz-dualbank-otp-lms.config .config` (with Dual Bank and PQ LMS) +### Configuration Options - - Run `make`. `wolfboot.elf` and the test applications are built as separate - objects. The application is signed and stored as `test-app/image_v1_signed.bin`. +Choose one of these example configurations: +```bash +# Basic TrustZone + PKCS#11 +cp config/examples/stm32h5-tz.config .config - - Ensure that the option bytes on your target device are set as follows: +# TrustZone + Dual Bank + OTP +cp config/examples/stm32h5-tz-dualbank-otp.config .config + +# TrustZone + Dual Bank + OTP + Post-Quantum +cp config/examples/stm32h5-tz-dualbank-otp-lms.config .config +``` + +### Build Process +```bash +make +``` +**Outputs:** +- `wolfboot.elf`: Secure bootloader +- `test-app/image_v1_signed.bin`: Signed application + +### Required Option Bytes ``` OPTION BYTES BANK: 0 @@ -219,14 +242,24 @@ OPTION BYTES BANK: 9 HDP2_END : 0x0 (0x0) ``` - - Upload `wolfboot.bin` and the test application to the two different domains in flash: +### Programming and Testing -``` +#### Flash Programming +```bash +# Program secure bootloader STM32_Programmer_CLI -c port=swd -d wolfboot.bin 0x0C000000 + +# Program application image STM32_Programmer_CLI -c port=swd -d test-app/image_v1_signed.bin 0x08040000 ``` - - After rebooting, the LED on the board should turn on sequentially: - - Red LED: Secure boot was successful. Application has started. - - Blue LED: PKCS11 Token has been initialized and stored - - Green LED: ECDSA Sign/Verify test successful +#### Verification Steps +Monitor LED sequence: +1. **Red LED**: Secure boot verification passed +2. **Blue LED**: PKCS#11 token initialized +3. **Green LED**: ECDSA test successful + +**Note:** LED sequence confirms proper: +- Domain separation +- Secure boot chain +- Cryptographic operations diff --git a/docs/Signing.md b/docs/Signing.md index e0fa7af7..98ffcaea 100644 --- a/docs/Signing.md +++ b/docs/Signing.md @@ -1,289 +1,389 @@ -# wolfBoot Key Tools +# wolfBoot Key Management Tools -`keygen` and `sign` are two command line tools to be used on a PC (or automated -server) environment to manage wolfBoot private keys and sign the initial -firmware and all the updates for the target. +This document describes the tools used for key management and firmware signing in wolfBoot. -## C Key Tools +## Overview -A standalone C version of the key tools is available in: `./tools/keytools`. +Two primary tools are provided: +- `keygen`: Manages private keys and keystore +- `sign`: Creates signed firmware images -These can be built in `tools/keytools` using `make` or from the wolfBoot root using `make keytools`. +These tools can be used on: +- Development machines +- Build servers +- CI/CD pipelines -#### Windows Visual Studio +## Building the Tools -Use the `wolfBootSignTool.vcxproj` Visual Studio project to build the `sign.exe` and `keygen.exe` tools for use on Windows. - -If you see any error about missing `target.h` this is a generated file based on your .config using the make process. It is needed for `WOLFBOOT_SECTOR_SIZE` used in delta updates. - - -## Command Line Usage - -### Keygen tool - -Usage: `keygen [OPTIONS] [-g new-keypair.der] [-i existing-pubkey.der] [...]` - -`keygen` is used to populate a keystore with existing and new public keys. -The following options are supported: - -- `-g privkey.der` to generate a new keypair, add the public key to the keystore and save the private key in a new file `privkey.der` -- `-i existing.der` to import an existing public key from `existing.der` -- `--der` save generated private key in DER format. -- `--exportpubkey` to export the public key (corresponding to the private key generated with `-g`) to a DER file. This option only has an effect if used in conjunction with the `-g` option. -- `--nolocalkeys` to generate a keystore entry with zeroized key material. This option is only useful on platforms that support using an external key by reference, such as wolfHSM. Only has an effect if used in conjunction with the `-g` option. - -Arguments are not exclusive, and can be repeated more than once to populate a keystore with multiple keys. - -One option must be specified to select the algorithm enabled in the keystore (e.g. `--ed25519` or `--rsa3072`). See the section "Public key signature options" for the sign tool for the available options. - -The files generate by the keygen tool is the following: - -- A C file `src/keystore.c`, which is normally linked with the wolfBoot image, when the keys are provisioned through generated C code. -- A binary file `keystore.img` that can be used to provision the public keys through an alternative storage -- The private key, for each `-g` option provided from command line - -For more information about the keystore mechanism, see [keystore.md](keystore.md). - - -### Sign tool - -`sign` produces a signed firmware image by creating a manifest header -in the format supported by wolfBoot. - -Usage: `sign [OPTIONS] IMAGE.BIN KEY.DER VERSION` - -`IMAGE.BIN`: A file containing the binary firmware/software to sign -`KEY.DER`: Private key file, in DER format, to sign the binary image -`VERSION`: The version associated with this signed software -`OPTIONS`: Zero or more options, described below - -#### Image header size - -By default, the manifest header size used by SIGN tool depends on the ideal -value for the configuration chosen. In some cases however, it is necessary to use -a different value than the default. To override the `IMAGE_HEADER_SIZE` value, -set an environment variable with the same name and the desired value, via `setenv`, -`export`, or simply inlining it with the sign command: +### Linux/Unix +```bash +# From tools/keytools directory +make +# From wolfBoot root +make keytools ``` + +### Windows +Use Visual Studio project: +- Project file: `wolfBootSignTool.vcxproj` +- Outputs: `sign.exe` and `keygen.exe` + +**Note:** If `target.h` is missing: +- This file is generated from your `.config` +- Required for `WOLFBOOT_SECTOR_SIZE` definition +- Used in delta update calculations + + +## Keygen Tool + +### Basic Usage +```bash +keygen [OPTIONS] [-g new-keypair.der] [-i existing-pubkey.der] [...] +``` + +### Purpose +Creates and manages keystores containing public keys for firmware verification. + +### Key Options +| Option | Description | +|--------|-------------| +| `-g privkey.der` | Generate new keypair, save private key | +| `-i existing.der` | Import existing public key | +| `--der` | Save private key in DER format | +| `--exportpubkey` | Export public key to DER (with `-g`) | +| `--nolocalkeys` | Create keystore entry without key material* | + +*Used with wolfHSM for external key reference + +### Algorithm Selection +Must specify one: +- `--ed25519` +- `--rsa3072` +- (See "Public Key Options" section below) + +### Multiple Keys +- Options can be combined +- Multiple `-g` or `-i` allowed +- Builds keystore with all specified keys + +### Output Files +1. `src/keystore.c` + - C source for linking with wolfBoot + - Contains embedded public keys + +2. `keystore.img` + - Binary keystore file + - For alternative storage methods + +3. Private Key Files + - One per `-g` option + - Used for firmware signing + +For detailed keystore information, see [keystore.md](keystore.md) + + +## Sign Tool + +### Basic Usage +```bash +sign [OPTIONS] IMAGE.BIN KEY.DER VERSION +``` + +### Parameters +| Parameter | Description | +|-----------|-------------| +| `IMAGE.BIN` | Binary firmware/software to sign | +| `KEY.DER` | Private key in DER format | +| `VERSION` | Version number for the firmware | +| `OPTIONS` | Optional configuration flags | + +### Header Size Configuration + +The manifest header size can be customized: + +```bash +# Default: Automatically determined based on configuration +# Override: Set IMAGE_HEADER_SIZE environment variable + +# Method 1: Export variable +export IMAGE_HEADER_SIZE=2048 +sign [OPTIONS] IMAGE.BIN KEY.DER VERSION + +# Method 2: Inline setting IMAGE_HEADER_SIZE=2048 sign [OPTIONS] IMAGE.BIN KEY.DER VERSION ``` - -#### Public key signature options - -If none of the following arguments is given, the tool will try to guess the key -size from the format and key length detected in KEY.DER. - - * `--ed25519` Use ED25519 for signing the firmware. Assume that the given KEY.DER -file is in this format. - - * `--ed448` Use ED448 for signing the firmware. Assume that the given KEY.DER -file is in this format. - - * `--ecc256` Use ecc256 for signing the firmware. Assume that the given KEY.DER -file is in this format. - - * `--ecc384` Use ecc384 for signing the firmware. Assume that the given KEY.DER -file is in this format. - - * `--ecc521` Use ecc521 for signing the firmware. Assume that the given KEY.DER -file is in this format. - - * `--rsa2048` Use rsa2048 for signing the firmware. Assume that the given KEY.DER -file is in this format. - - * `--rsa3072` Use rsa3072 for signing the firmware. Assume that the given KEY.DER -file is in this format. - - * `--rsa4096` Use rsa4096 for signing the firmware. Assume that the given KEY.DER -file is in this format. - - * `--lms` Use LMS/HSS for signing the firmware. Assume that the given KEY.DER -file is in this format. - - * `--xmss` Use XMSS/XMSS^MT for signing the firmware. Assume that the given KEY.DER -file is in this format. - - * `--no-sign` Disable secure boot signature verification. No signature - verification is performed in the bootloader, and the KEY.DER argument should - not be supplied. - -#### Hash digest options - -If none of the following is used, '--sha256' is assumed by default. - - * `--sha256` Use sha256 for digest calculation on binary images and public keys. - - * `--sha348` Use sha384 for digest calculation on binary images and public keys. - - * `--sha3` Use sha3-384 for digest calculation on binary images and public keys. - -#### Target partition id (Multiple partition images, "self-update" feature) - -If none of the following is used, "--id=1" is assumed by default. On systems -with a single image to verify (e.g. microcontroller with a single active -partition), ID=1 is the default identifier for the firmware image to stage. -ID=0 is reserved for wolfBoot 'self-update', and refers to the partition where -the bootloader itself is stored. - - * `--id N` Set image partition id to "N". - - * `--wolfboot-update` Indicate that the image contains a signed self-update -package for the bootloader. Equivalent to `--id 0`. - -#### Encryption using a symmetric key - -Although signed to be authenticated, by default the image is not encrypted and -it's distributed as plain text. End-to-end encryption from the firmware -packaging to the update process can be used if the firmware is stored on -external non-volatile memories. Encrypted updates can be produced using a -pre-shared, secret symmetric key, by passing the following option: - - * `--encrypt SHAREDKEY.BIN` use the file SHAREKEY.BIN to encrypt the image. +**Note:** Custom header size may be needed for: +- Large signatures (e.g., RSA-4096) +- Multiple signatures (hybrid mode) +- Additional custom TLV fields -The format of the file depends on the algorithm selected for the encryption. -If no format is specified, and the `--encrypt SHAREDKEY.BIN` option is present, -`--chacha` is assumed by default. +### Signature Algorithms -See options below. +The tool automatically detects key type from KEY.DER if no algorithm is specified. - * `--chacha` Use ChaCha20 algorithm for encrypting the image. The file - SHAREDKEY.BIN is expected to be exactly 44 bytes in size, of which 32 will -be used for the key, 12 for the initialization of the IV. +#### Classical Algorithms +| Option | Algorithm | Description | +|--------|-----------|-------------| +| `--ed25519` | ED25519 | Edwards curve signature | +| `--ed448` | ED448 | Edwards curve signature | +| `--ecc256` | ECDSA P-256 | NIST P-256 curve | +| `--ecc384` | ECDSA P-384 | NIST P-384 curve | +| `--ecc521` | ECDSA P-521 | NIST P-521 curve | +| `--rsa2048` | RSA-2048 | 2048-bit RSA | +| `--rsa3072` | RSA-3072 | 3072-bit RSA | +| `--rsa4096` | RSA-4096 | 4096-bit RSA | - * `--aes128` Use AES-128 algorithm in counter mode for encrypting the image. The file - SHAREDKEY.BIN is expected to be exactly 32 bytes in size, of which 16 will -be used for the key, 16 for the initialization of the IV. +#### Post-Quantum Algorithms +| Option | Algorithm | Description | +|--------|-----------|-------------| +| `--lms` | LMS/HSS | Hash-based signature | +| `--xmss` | XMSS/XMSS^MT | Hash-based signature | - * `--aes256` Use AES-256 algorithm in counter mode for encrypting the image. The file - SHAREDKEY.BIN is expected to be exactly 48 bytes in size, of which 32 will -be used for the key, 16 for the initialization of the IV. +#### Special Options +| Option | Description | +|--------|-------------| +| `--no-sign` | Disable signature verification | -#### Delta updates (incremental updates from a known version) +**Note:** With `--no-sign`: +- No KEY.DER required +- No signature verification in bootloader +- Not recommended for production use -An incremental update is created using the sign tool when the following option -is provided: +### Hash Algorithm Options - * `--delta BASE_SIGNED_IMG.BIN` This option creates a binary diff file between - `BASE_SIGNED_IMG.BIN` and the new image signed starting from `IMAGE.BIN`. The -result is stored in a file ending in `_signed_diff.bin`. +Default: `--sha256` -The compression scheme used is Bentley–McIlroy. +| Option | Algorithm | Description | +|--------|-----------|-------------| +| `--sha256` | SHA-256 | Standard SHA-2 256-bit | +| `--sha384` | SHA-384 | Standard SHA-2 384-bit | +| `--sha3` | SHA3-384 | SHA-3 384-bit variant | -Options: - * `--no-base-sha` : Avoid adding the sha of the base image to the manifest header. - By default, the sign tool appends the sha of the base image to the manifest header, - so wolfBoot will refuse to start a delta update if the sha does not match the - one of the existing image. However, this takes up 32 to 48 bytes extra in the - manifest header, so this option is available to provide compatibility on - existing installations without this feature, where the header size does not - allow to accommodate the field +### Target Partition Configuration +Default: `--id=1` -#### Policy signing (for sealing/unsealing with a TPM) +#### Partition IDs +| ID | Purpose | Description | +|----|---------|-------------| +| 0 | Bootloader | Reserved for wolfBoot self-update | +| 1 | Primary Firmware | Default application partition | +| N | Custom | User-defined partitions | -Provides a PCR mask and digest to be signed and included in the header. The signing key is used to sign the digest. +#### Options +| Option | Description | +|--------|-------------| +| `--id N` | Target partition N | +| `--wolfboot-update` | Bootloader update (same as `--id 0`) | - * `--policy policy.bin`: This argument is multi-purpose. - By default the file should contain a 4-byte PCR mask and SHA2-256 PCR digest to be signed. - If using `--manual-sign` then the file should contain the 4-byte PCR mask and signature. - The PCR mask and signature will be included in the `HDR_POLICY_SIGNATURE` header tag. - A copy of the final signed policy (including 4 byte PCR mask) will be output to `[inputname].sig`. - Note: This may require increasing the `IMAGE_HEADER_SIZE` as two signatures will be stored in the header. +**Use Cases:** +- Single partition systems: Use default `--id=1` +- Multi-partition systems: Specify partition with `--id N` +- Bootloader update: Use `--wolfboot-update` or `--id 0` -#### Adding custom fields to the manifest header +### Firmware Encryption -Provides a value to be set with a custom tag +By default, firmware images are signed but not encrypted. For secure external storage, end-to-end encryption is available. - * `--custom-tlv tag len val`: Adds a TLV entry to the manifest header, corresponding - to the type identified by `tag`, with length `len` bytes, and assigns the value `val`. - Values can be decimal or hex numbers (prefixed by '0x'). The tag is a 16-bit number. - Valid tags are in the range between 0x0030 and 0xFEFE. - - * `--custom-tlv-buffer tag value`: Adds a TLV entry with arbitrary length to the manifest - header, corresponding to the type identified by `tag`, and assigns the value `value`. The - tag is a 16-bit number. Valid tags are in the range between 0x0030 and 0xFEFE. The length - is implicit, and is the length of the value. - Value argument is in the form of a hex string, e.g. `--custom-tlv-buffer 0x0030 AABBCCDDEE` - will add a TLV entry with tag 0x0030, length 5 and value 0xAABBCCDDEE. - - * `--custom-tlv-string tag ascii-string`: Adds a TLV entry with arbitrary length to the manifest - header, corresponding to the type identified by `tag`, and assigns the value of `ascii-string`. The - tag is a 16-bit number. Valid tags are in the range between 0x0030 and 0xFEFE. The length - is implicit, and is the length of the `ascii-string`. `ascii-string` argument is in the form of a string, - e.g. `--custom-tlv-string 0x0030 "Version-1"` will add a TLV entry with tag 0x0030, - length 9 and value Version-1. - -#### Three-steps signing using external provisioning tools - -If the private key is not accessible, while it's possible to sign payloads using -a third-party tool, the sign mechanism can be split in three phases: - -- Phase 1: Only create the sha digest for the image, and prepare an intermediate - file that can be signed by third party tool. - -This is done using the following option: - - * `--sha-only` When this option is selected, the sign tool will create an - intermediate image including part of the manifest that must be signed, -ending in `_digest.bin`. In this case, KEY.DER contains the public part of the -key that will be used to sign the firmware in Phase 2. - -- Phase 2: The intermediate image `*_digest.bin` is signed by an external tool, - an HSM or a third party signing service. The signature is then exported in -its raw format and copied to a file, e.g. IMAGE_SIGNATURE.SIG - -- Phase 3: use the following option to build the final authenticated firmware - image, including its manifest header in front: - - * `--manual-sign` When this option is provided, the KEY.DER argument contains - the public part of the key that was used to sign the firmware in Phase 2. -This option requires one extra argument at the end, after VERSION, which should -be the filename of the signature that was the output of the previous phase, so -`IMAGE_SIGNATURE.SIG` - -For a real-life example, see the section below. - -## Examples - -### Signing Firmware - -1. Load the private key to use for signing into `./wolfboot_signing_private_key.der` -2. Run the signing tool with asymmetric algorithm, hash algorithm, file to sign, key and version. - -```sh -./tools/keytools/sign --rsa2048 --sha256 test-app/image.bin wolfboot_signing_private_key.der 1 +#### Basic Encryption +```bash +--encrypt SHAREDKEY.BIN # Enable encryption with shared key ``` -Note: The last argument is the “version” number. +#### Encryption Algorithms -### Signing Firmware with External Private Key (HSM) +Default: `--chacha` (when using `--encrypt`) -Steps for manually signing firmware using an external key source. +| Algorithm | Option | Key File Size | Key Size | IV Size | +|-----------|--------|---------------|----------|----------| +| ChaCha20 | `--chacha` | 44 bytes | 32 bytes | 12 bytes | +| AES-128-CTR | `--aes128` | 32 bytes | 16 bytes | 16 bytes | +| AES-256-CTR | `--aes256` | 48 bytes | 32 bytes | 16 bytes | -```sh -# Create file with Public Key -openssl rsa -inform DER -outform DER -in my_key.der -out rsa2048_pub.der -pubout +**Use Cases:** +- External flash storage +- Over-the-air updates +- Sensitive firmware protection -# Add the public key to the wolfBoot keystore using `keygen -i` +**Note:** Key file (SHAREDKEY.BIN) must be pre-shared and kept secure + +### Delta Updates + +Create incremental updates between firmware versions to minimize update size. + +#### Basic Usage +```bash +--delta BASE_SIGNED_IMG.BIN # Create incremental update +``` + +**Process:** +1. Takes base image (`BASE_SIGNED_IMG.BIN`) +2. Compares with new image (`IMAGE.BIN`) +3. Creates diff file (`*_signed_diff.bin`) +4. Uses Bentley-McIlroy compression + +#### Options +| Option | Description | Impact | +|--------|-------------|---------| +| Default | Includes base image SHA | +32-48 bytes header | +| `--no-base-sha` | Skips base image SHA | Smaller header | + +**Considerations:** +- Base image SHA ensures correct update base +- `--no-base-sha` for legacy header size compatibility +- Reduces update bandwidth and storage requirements + + +### TPM Policy Signing + +Enable TPM-based sealing/unsealing with signed policies. + +#### Basic Usage +```bash +--policy policy.bin # Add signed TPM policy +``` + +#### Policy File Format +1. Default Mode: + - 4-byte PCR mask + - SHA2-256 PCR digest (to be signed) + +2. Manual Sign Mode: + - 4-byte PCR mask + - Pre-computed signature + +#### Outputs +- Policy signature in `HDR_POLICY_SIGNATURE` header +- Signed policy (with PCR mask) in `[inputname].sig` + +**Note:** May require increased `IMAGE_HEADER_SIZE` for dual signatures + +### Custom Manifest Fields + +Add custom Type-Length-Value (TLV) entries to the manifest header. + +#### TLV Tag Range +- Valid tags: `0x0030` to `0xFEFE` +- 16-bit values + +#### Options + +1. **Fixed-Length Values** +```bash +--custom-tlv +``` +- Numeric values (decimal/hex) +- Fixed length in bytes + +2. **Buffer Values** +```bash +--custom-tlv-buffer +``` +Example: +```bash +--custom-tlv-buffer 0x0030 AABBCCDDEE +# Creates: tag=0x0030, len=5, val=0xAABBCCDDEE +``` + +3. **String Values** +```bash +--custom-tlv-string "" +``` +Example: +```bash +--custom-tlv-string 0x0030 "Version-1" +# Creates: tag=0x0030, len=9, val="Version-1" +``` + +### External Signing Process + +For scenarios where private keys are managed by HSMs or external services, the signing process can be split into three phases. + +#### Phase 1: Generate Digest +```bash +--sha-only # Generate intermediate digest file +``` +**Inputs:** +- `IMAGE.BIN`: Firmware to sign +- `KEY.DER`: Public key only + +**Output:** +- `*_digest.bin`: Intermediate file for signing + +#### Phase 2: External Signing +Sign the digest using external tools: +- Hardware Security Module (HSM) +- Cloud Key Management Service +- Third-party signing service + +**Output:** +- `IMAGE_SIGNATURE.SIG`: Raw signature file + +#### Phase 3: Create Final Image +```bash +--manual-sign IMAGE_SIGNATURE.SIG # Combine components +``` +**Inputs:** +- Original `IMAGE.BIN` +- Public key (`KEY.DER`) +- Version number +- `IMAGE_SIGNATURE.SIG` + +**Output:** +- Complete signed firmware with manifest + +**Note:** See Examples section below for detailed workflow + +## Usage Examples + +### Basic Firmware Signing + +#### Direct Signing with Local Key +```bash +# 1. Prepare private key +cp signing_key.der wolfboot_signing_private_key.der + +# 2. Sign firmware +./tools/keytools/sign --rsa2048 --sha256 \ + test-app/image.bin \ + wolfboot_signing_private_key.der 1 +``` + +### HSM Integration Example + +#### Complete HSM Workflow +```bash +# 1. Export public key +openssl rsa -inform DER -outform DER \ + -in my_key.der \ + -out rsa2048_pub.der -pubout + +# 2. Add to wolfBoot keystore ./tools/keytools/keygen --rsa2048 -i rsa2048_pub.der -# Generate Hash to Sign -./tools/keytools/sign --rsa2048 --sha-only --sha256 test-app/image.bin rsa2048_pub.der 1 +# 3. Generate digest for HSM +./tools/keytools/sign --rsa2048 --sha-only --sha256 \ + test-app/image.bin rsa2048_pub.der 1 -# Sign hash Example (here is where you would use an HSM) -openssl pkeyutl -sign -keyform der -inkey my_key.der -in test-app/image_v1_digest.bin > test-app/image_v1.sig +# 4. Sign with HSM (example using OpenSSL) +openssl pkeyutl -sign -keyform der \ + -inkey my_key.der \ + -in test-app/image_v1_digest.bin \ + -out test-app/image_v1.sig -# Generate final signed binary -./tools/keytools/sign --rsa2048 --sha256 --manual-sign test-app/image.bin rsa2048_pub.der 1 test-app/image_v1.sig +# 5. Create signed firmware +./tools/keytools/sign --rsa2048 --sha256 --manual-sign \ + test-app/image.bin rsa2048_pub.der 1 \ + test-app/image_v1.sig -# Combine into factory image (0xc0000 is the WOLFBOOT_PARTITION_BOOT_ADDRESS) -tools/bin-assemble/bin-assemble factory.bin 0x0 wolfboot.bin \ - 0xc0000 test-app/image_v1_signed.bin +# 6. Create factory image +tools/bin-assemble/bin-assemble factory.bin \ + 0x0 wolfboot.bin \ + 0xc0000 test-app/image_v1_signed.bin ``` -### Signing Firmware with Azure Key Vault - -See [docs/azure_keyvault.md](/docs/azure_keyvault.md). +### Cloud Service Integration +For Azure Key Vault integration, see [azure_keyvault.md](/docs/azure_keyvault.md) diff --git a/docs/TPM.md b/docs/TPM.md index 6a58185d..96e168a6 100644 --- a/docs/TPM.md +++ b/docs/TPM.md @@ -1,222 +1,323 @@ -# wolfBoot TPM support +# TPM Integration Guide -In wolfBoot we support TPM based root of trust, sealing/unsealing, cryptographic offloading and measured boot using a TPM. +This guide describes wolfBoot's integration with Trusted Platform Module (TPM) for enhanced security features. -## Build Options +## Features Overview -| Config Option | Preprocessor Macro | Description | -| ------------- | ------------------ | ----------------------------------- | -| `WOLFTPM=1` | `WOLFBOOT_TPM` | Enables wolfTPM support | -| `WOLFBOOT_TPM_VERIFY=1` | `WOLFBOOT_TPM_VERIFY` | Enables cryptographic offloading for RSA2048 and ECC256/384 to the TPM. | -| `WOLFBOOT_TPM_KEYSTORE=1` | `WOLFBOOT_TPM_KEYSTORE` | Enables TPM based root of trust. NV Index must store a hash of the trusted public key. | -| `WOLFBOOT_TPM_KEYSTORE_NV_BASE=0x` | `WOLFBOOT_TPM_KEYSTORE_NV_BASE=0x` | NV index in platform range 0x1400000 - 0x17FFFFF. | -| `WOLFBOOT_TPM_KEYSTORE_AUTH=secret` | `WOLFBOOT_TPM_KEYSTORE_AUTH` | Password for NV access | -| `MEASURED_BOOT=1` | `WOLFBOOT_MEASURED_BOOT` | Enable measured boot. Extend PCR with wolfBoot hash. | -| `MEASURED_PCR_A=16` | `WOLFBOOT_MEASURED_PCR_A=16` | The PCR index to use. See [docs/measured_boot.md](/docs/measured_boot.md). | -| `WOLFBOOT_TPM_SEAL=1` | `WOLFBOOT_TPM_SEAL` | Enables support for sealing/unsealing based on PCR policy signed externally. | -| `WOLFBOOT_TPM_SEAL_NV_BASE=0x01400300` | `WOLFBOOT_TPM_SEAL_NV_BASE` | To override the default sealed blob storage location in the platform hierarchy. | -| `WOLFBOOT_TPM_SEAL_AUTH=secret` | `WOLFBOOT_TPM_SEAL_AUTH` | Password for sealing/unsealing secrets, if omitted the PCR policy will be used | +- Root of Trust (RoT) using TPM +- Cryptographic operation offloading +- Measured boot support +- Secure sealing/unsealing of secrets +- PCR-based policy enforcement -## Root of Trust (ROT) +## Configuration Options -See wolfTPM Secure Root of Trust (ROT) example [here](https://github.com/wolfSSL/wolfTPM/tree/master/examples/boot). +### Core TPM Support +| Option | Macro | Description | +|--------|-------|-------------| +| `WOLFTPM=1` | `WOLFBOOT_TPM` | Enable TPM integration | -The design uses a platform NV handle that has been locked. The NV stores a hash of the public key. It is recommended to supply a derived "authentication" value to prevent TPM tampering. This authentication value is encrypted on the bus. +### Cryptographic Features +| Option | Macro | Description | +|--------|-------|-------------| +| `WOLFBOOT_TPM_VERIFY=1` | `WOLFBOOT_TPM_VERIFY` | Offload RSA2048/ECC256/384 to TPM | +| `WOLFBOOT_TPM_KEYSTORE=1` | `WOLFBOOT_TPM_KEYSTORE` | Enable TPM-based root of trust | -## Cryptographic offloading +### Storage Configuration +| Option | Macro | Description | +|--------|-------|-------------| +| `WOLFBOOT_TPM_KEYSTORE_NV_BASE=0x` | Same | NV index (0x1400000-0x17FFFFF) | +| `WOLFBOOT_TPM_KEYSTORE_AUTH=secret` | Same | NV access password | +| `WOLFBOOT_TPM_SEAL_NV_BASE=0x01400300` | Same | Sealed blob storage location | +| `WOLFBOOT_TPM_SEAL_AUTH=secret` | Same | Sealing/unsealing password | -The RSA2048 and ECC256/384 bit verification can be offloaded to a TPM for code size reduction or performance improvement. Enabled using `WOLFBOOT_TPM_VERIFY`. -NOTE: The TPM's RSA verify requires ASN.1 encoding, so use SIGN=RSA2048ENC +### Measured Boot +| Option | Macro | Description | +|--------|-------|-------------| +| `MEASURED_BOOT=1` | `WOLFBOOT_MEASURED_BOOT` | Enable PCR measurements | +| `MEASURED_PCR_A=16` | `WOLFBOOT_MEASURED_PCR_A=16` | PCR index selection | +| `WOLFBOOT_TPM_SEAL=1` | `WOLFBOOT_TPM_SEAL` | Enable PCR-based sealing | -## Measured Boot +For detailed measured boot information, see [measured_boot.md](/docs/measured_boot.md) -The wolfBoot image is hashed and extended to the indicated PCR. This can be used later in the application to prove the boot process was not tampered with. Enabled with `WOLFBOOT_MEASURED_BOOT` and exposes API `wolfBoot_tpm2_extend`. +## Feature Details -## Sealing and Unsealing a secret +### Root of Trust (RoT) +Implements secure boot chain using TPM-based key verification. -See the wolfTPM Sealing/Unsealing example [here](https://github.com/wolfSSL/wolfTPM/tree/master/examples/boot#secure-boot-encryption-key-storage) +**Implementation:** +- Uses locked platform NV handle +- Stores public key hash +- Requires authentication for tampering prevention +- Authentication encrypted during transit -Known PCR values must be signed to seal/unseal a secret. The signature for the authorization policy resides in the signed header using the `--policy` argument. -If a signed policy is not in the header then a value cannot be sealed. Instead the PCR(s) values and a PCR policy digest will be printed to sign. You can use `./tools/keytools/sign` or `./tools/tpm/policy_sign` to sign the policy externally. +**Example:** See [wolfTPM RoT Example](https://github.com/wolfSSL/wolfTPM/tree/master/examples/boot) -This exposes two new wolfBoot API's for sealing and unsealing data with blob stored to NV index: +### Cryptographic Offloading +Delegates cryptographic operations to TPM hardware. + +**Supported Operations:** +- RSA2048 verification +- ECC256/384 verification + +**Notes:** +- Reduces code size +- Improves performance +- Requires `WOLFBOOT_TPM_VERIFY` +- Use `SIGN=RSA2048ENC` for ASN.1 encoding + +### Measured Boot +Tracks boot process integrity using PCR measurements. + +**Features:** +- Hashes wolfBoot image +- Extends PCR with hash +- Verifiable boot attestation +- API: `wolfBoot_tpm2_extend` + +### Secret Management + +#### Sealing/Unsealing API ```c -int wolfBoot_seal_auth(const uint8_t* pubkey_hint, const uint8_t* policy, uint16_t policySz, - int index, const uint8_t* secret, int secret_sz, const byte* auth, int authSz); -int wolfBoot_unseal_auth(const uint8_t* pubkey_hint, const uint8_t* policy, uint16_t policySz, - int index, uint8_t* secret, int* secret_sz, const byte* auth, int authSz); +// Seal data with policy and authentication +int wolfBoot_seal_auth( + const uint8_t* pubkey_hint, // Public key reference + const uint8_t* policy, // Policy data + uint16_t policySz, // Policy size + int index, // NV index + const uint8_t* secret, // Data to seal + int secret_sz, // Data size + const byte* auth, // Authentication + int authSz // Auth size +); + +// Unseal previously sealed data +int wolfBoot_unseal_auth( + const uint8_t* pubkey_hint, // Public key reference + const uint8_t* policy, // Policy data + uint16_t policySz, // Policy size + int index, // NV index + uint8_t* secret, // Buffer for unsealed data + int* secret_sz, // Buffer size + const byte* auth, // Authentication + int authSz // Auth size +); ``` -By default this index will be based on an NV Index at `(0x01400300 + index)`. -The default NV base can be overridden with `WOLFBOOT_TPM_SEAL_NV_BASE`. +**Storage Location:** +- Default: `0x01400300 + index` +- Configurable via `WOLFBOOT_TPM_SEAL_NV_BASE` + +For implementation examples, see [wolfTPM Sealing Example](https://github.com/wolfSSL/wolfTPM/tree/master/examples/boot#secure-boot-encryption-key-storage) NOTE: The TPM's RSA verify requires ASN.1 encoding, so use SIGN=RSA2048ENC -### Testing seal/unseal with simulator +## Testing Guide -```sh -% cp config/examples/sim-tpm-seal.config .config -% make keytools -% make tpmtools -% echo aaa > aaa.bin -% echo bbb > bbb.bin -% ./tools/tpm/pcr_extend 0 aaa.bin -% ./tools/tpm/pcr_extend 1 bbb.bin -# hash for policy PCR is done 1 then 0 -% ./tools/tpm/policy_create -pcr=1 -pcr=0 -out=policy.bin -# if ROT enabled -% ./tools/tpm/rot -write [-auth=TestAuth] -% make clean -$ make POLICY_FILE=policy.bin [WOLFBOOT_TPM_KEYSTORE_AUTH=TestAuth] [WOLFBOOT_TPM_SEAL_AUTH=SealAuth] +### Simulator Testing -% ./wolfboot.elf get_version -Simulator assigned ./internal_flash.dd to base 0x107175000 -Mfg IBM (0), Vendor SW TPM, Fw 8228.293 (0x120000), FIPS 140-2 1, CC-EAL4 0 +#### Setup and Configuration +```bash +# 1. Copy TPM simulator config +cp config/examples/sim-tpm-seal.config .config + +# 2. Build required tools +make keytools +make tpmtools + +# 3. Create test files +echo aaa > aaa.bin +echo bbb > bbb.bin + +# 4. Configure PCR values +./tools/tpm/pcr_extend 0 aaa.bin +./tools/tpm/pcr_extend 1 bbb.bin + +# 5. Create policy (PCR 1 then 0) +./tools/tpm/policy_create -pcr=1 -pcr=0 -out=policy.bin + +# 6. Setup Root of Trust (optional) +./tools/tpm/rot -write [-auth=TestAuth] + +# 7. Build with policy +make clean +make POLICY_FILE=policy.bin \ + [WOLFBOOT_TPM_KEYSTORE_AUTH=TestAuth] \ + [WOLFBOOT_TPM_SEAL_AUTH=SealAuth] +``` + +#### Testing Sequence +```bash +# First Run - Initial Secret Creation +./wolfboot.elf get_version +``` + +**Expected Output:** +``` +Mfg IBM (0), Vendor SW TPM, Fw 8228.293 (0x120000)... Unlocking disk... -Boot partition: 0x1071f5000 (size 21288, version 0x1) -Error 395 reading blob from NV index 1400300 (error TPM_RC_HANDLE) -Error 395 unsealing secret! (TPM_RC_HANDLE) -Sealed secret does not exist! +Error 395 reading blob... (First run expected error) Creating new secret (32 bytes) 7801a7fb716371c975a9a1bca6159a223bc7dba6adb2acf82781421062e498a5 -Error 395 deleting blob from NV index 1400300 (error TPM_RC_HANDLE) Wrote 242 bytes to NV index 0x1400300 -Read 242 bytes from NV index 0x1400300 -Secret Check 32 bytes -7801a7fb716371c975a9a1bca6159a223bc7dba6adb2acf82781421062e498a5 -Secret 32 bytes -7801a7fb716371c975a9a1bca6159a223bc7dba6adb2acf82781421062e498a5 -Boot partition: 0x1071f5000 (size 21288, version 0x1) -Boot header magic 0x00000000 invalid at 0x107275000 -Boot partition: 0x1071f5000 (size 21288, version 0x1) -Booting version: 0x1 TPM Root of Trust valid (id 0) -Simulator assigned ./internal_flash.dd to base 0x1073cc000 -1 -% ./wolfboot.elf get_version -Simulator assigned ./internal_flash.dd to base 0x102f38000 -Mfg IBM (0), Vendor SW TPM, Fw 8228.293 (0x120000), FIPS 140-2 1, CC-EAL4 0 -Unlocking disk... -Boot partition: 0x102fb8000 (size 21288, version 0x1) -Read 242 bytes from NV index 0x1400300 -Secret 32 bytes -7801a7fb716371c975a9a1bca6159a223bc7dba6adb2acf82781421062e498a5 -Boot partition: 0x102fb8000 (size 21288, version 0x1) -Boot header magic 0x00000000 invalid at 0x103038000 -Boot partition: 0x102fb8000 (size 21288, version 0x1) -Booting version: 0x1 -TPM Root of Trust valid (id 0) -Simulator assigned ./internal_flash.dd to base 0x10318f000 -1 ``` -### Testing seal/unseal on actual hardware +**Subsequent Runs:** +```bash +./wolfboot.elf get_version +``` -1) Get the actual PCR digest for policy. -2) Sign policy and include in firmware image header. +**Expected Output:** +``` +Unlocking disk... +Read 242 bytes from NV index 0x1400300 +Secret 32 bytes +7801a7fb716371c975a9a1bca6159a223bc7dba6adb2acf82781421062e498a5 +TPM Root of Trust valid (id 0) +``` +``` +### Hardware Testing -#### Getting PCR values +#### Policy Generation Process -If no signed policy exists, then the seal function will generate and display the active PCR's, PCR digest and policy digest (to sign) +1. Build Tools and Setup +```bash +make tpmtools +./tools/tpm/rot -write +./tools/tpm/pcr_reset 16 +``` -```sh -% make tpmtools -% ./tools/tpm/rot -write -% ./tools/tpm/pcr_reset 16 -% ./wolfboot.elf get_version -Simulator assigned ./internal_flash.dd to base 0x101a64000 -Mfg IBM (0), Vendor SW TPM, Fw 8217.4131 (0x163636), FIPS 140-2 1, CC-EAL4 0 -Boot partition: 0x101ae4000 -Image size 57192 +2. Generate Initial Policy +```bash +./wolfboot.elf get_version +``` + +**Expected Output:** +``` Policy header not found! Generating policy based on active PCR's! Getting active PCR's (0-16) PCR 16 (counter 20) 8f7ac1d5a5eac58a2305ca459f27c35705a9212c0fb2a9088b1df761f3d5f842 Found 1 active PCR's (mask 0x00010000) -PCR Digest (32 bytes): +PCR Digest: f84085631f85333ad0338b06c82f16888b7923abaccffb881d5416e389be256c -PCR Mask (0x00010000) and PCR Policy Digest (36 bytes): +PCR Policy: 0000010034ba061436aba2e9a167a1ee46af4a9578a8c6b9f71fdece21607a0cb40468ec -Use this policy with the sign tool (--policy arg) or POLICY_FILE config -Image policy signature missing! -Boot partition: 0x101ae4000 -Image size 57192 -TPM Root of Trust valid (id 0) -Simulator assigned ./internal_flash.dd to base 0x101c2f000 -1 ``` -The `0000010034ba061436aba2e9a167a1ee46af4a9578a8c6b9f71fdece21607a0cb40468ec` above can be directly used by the keytool. The +#### Policy Creation Methods -`echo "0000010034ba061436aba2e9a167a1ee46af4a9578a8c6b9f71fdece21607a0cb40468ec" | xxd -r -p > policy.bin` +1. **Direct Method** +```bash +# Convert hex policy to binary +echo "0000010034ba061436aba2e9a167a1ee46af4a9578a8c6b9f71fdece21607a0cb40468ec" | \ + xxd -r -p > policy.bin +``` -OR use the `tools/tpm/policy_create` tool to generate a digest to be signed. The used PCR(s) must be set using "-pcr=#". The PCR digest can be supplied using "-pcrdigest=" or if not supplied will be read from the TPM directly. +2. **Using Policy Creation Tool** +```bash +# Method A: Specify PCR Index +./tools/tpm/policy_create \ + -pcr=16 \ + -pcrdigest=f84085631f85333ad0338b06c82f16888b7923abaccffb881d5416e389be256c \ + -out=policy.bin -```sh -% ./tools/tpm/policy_create -pcr=16 -pcrdigest=f84085631f85333ad0338b06c82f16888b7923abaccffb881d5416e389be256c -out=policy.bin -# OR -% ./tools/tpm/policy_create -pcrmask=0x00010000 -pcrdigest=f84085631f85333ad0338b06c82f16888b7923abaccffb881d5416e389be256c -out=policy.bin +# Method B: Specify PCR Mask +./tools/tpm/policy_create \ + -pcrmask=0x00010000 \ + -pcrdigest=f84085631f85333ad0338b06c82f16888b7923abaccffb881d5416e389be256c \ + -out=policy.bin +``` + +**Tool Output:** +``` Policy Create Tool PCR Index(s) (SHA256): 16 (mask 0x00010000) PCR Digest (32 bytes): - f84085631f85333ad0338b06c82f16888b7923abaccffb881d5416e389be256c -PCR Mask (0x00010000) and PCR Policy Digest (36 bytes): - 0000010034ba061436aba2e9a167a1ee46af4a9578a8c6b9f71fdece21607a0cb40468ec + f84085631f85333ad0338b06c82f16888b7923abaccffb881d5416e389be256c +PCR Policy (36 bytes): + 0000010034ba061436aba2e9a167a1ee46af4a9578a8c6b9f71fdece21607a0cb40468ec Wrote 36 bytes to policy.bin ``` -#### Signing Policy +#### Policy Signing -Building firmware with the policy digest to sign: +Two methods are available for signing the policy: -```sh -% make POLICY_FILE=policy.bin +1. **Simple Build Method** +```bash +make POLICY_FILE=policy.bin ``` -OR manually sign the policy using the `tools/tpm/policy_sign` or `tools/keytools/sign` tools. -These tools do not need access to a TPM, they are signing a policy digest. The result is a 32-bit PCR mask + signature. +2. **Manual Signing Tools** +Both tools below sign policy digest without TPM access: +- `tools/tpm/policy_sign` +- `tools/keytools/sign` -Sign with policy_sign tool: +##### Using Policy Sign Tool +```bash +./tools/tpm/policy_sign \ + -pcr=0 \ + -pcrdigest=eca4e8eda468b8667244ae972b8240d3244ea72341b2bf2383e79c66643bbecc +``` -```sh -% ./tools/tpm/policy_sign -pcr=0 -pcrdigest=eca4e8eda468b8667244ae972b8240d3244ea72341b2bf2383e79c66643bbecc +**Output Details:** +``` Sign PCR Policy Tool Signing Algorithm: ECC256 -PCR Index(s) (SHA256): 0 -Policy Signing Key: wolfboot_signing_private_key.der -PCR Digest (32 bytes): - eca4e8eda468b8667244ae972b8240d3244ea72341b2bf2383e79c66643bbecc -PCR Policy Digest (32 bytes): - 2d401eb05f45ba2b15c35f628b5896cc7de9745bb6e722363e2dbee804e0500f -PCR Policy Digest (w/PolicyRef) (32 bytes): - 749b3139ece21449a7828f11ee05303b0473ff1a26cf41d6f9ff28b24c717f02 -PCR Mask (0x1) and Policy Signature (68 bytes): - 01000000 - 5b5f875b3f7ce78b5935abe4fc5a4d8a6e87c4b4ac0836fbab909e232b6d7ca2 - 3ecfc6be723b695b951ba2886d3c7b83ab2f8cc0e96d766bc84276eaf3f213ee -Wrote PCR Mask + Signature (68 bytes) to policy.bin.sig +PCR Index(s): 0 +Key: wolfboot_signing_private_key.der + +Digests: +1. PCR Digest (32 bytes): + eca4e8eda468b8667244ae972b8240d3244ea72341b2bf2383e79c66643bbecc + +2. Policy Digest (32 bytes): + 2d401eb05f45ba2b15c35f628b5896cc7de9745bb6e722363e2dbee804e0500f + +3. Policy Digest w/Ref (32 bytes): + 749b3139ece21449a7828f11ee05303b0473ff1a26cf41d6f9ff28b24c717f02 + +Output: +PCR Mask (0x1) + Signature (68 bytes total): +01000000 +5b5f875b3f7ce78b5935abe4fc5a4d8a6e87c4b4ac0836fbab909e232b6d7ca2 +3ecfc6be723b695b951ba2886d3c7b83ab2f8cc0e96d766bc84276eaf3f213ee + +File: policy.bin.sig (68 bytes written) ``` -Sign using the signing key tool: - -```sh -% ./tools/keytools/sign --ecc256 --policy policy.bin test-app/image.elf wolfboot_signing_private_key.der 1 -wolfBoot KeyTools (Compiled C version) -wolfBoot version 1100000 -Update type: Firmware -Input image: test-app/image.elf -Selected cipher: ECC256 -Selected hash : SHA256 -Public key: wolfboot_signing_private_key.der -Output image: test-app/image_v1_signed.bin -Target partition id : 1 -image header size calculated at runtime (256 bytes) -Calculating SHA256 digest... -Signing the digest... -Opening policy file policy.bin -Signing the policy digest... -Saving policy signature to policy.bin.sig -Output image(s) successfully created. +##### Using Signing Key Tool +```bash +./tools/keytools/sign \ + --ecc256 \ + --policy policy.bin \ + test-app/image.elf \ + wolfboot_signing_private_key.der 1 +``` + +**Process Details:** +``` +wolfBoot KeyTools v1100000 +Configuration: +- Update Type: Firmware +- Input: test-app/image.elf +- Cipher: ECC256 +- Hash: SHA256 +- Key: wolfboot_signing_private_key.der +- Output: test-app/image_v1_signed.bin +- Partition: 1 +- Header Size: 256 bytes (runtime calculated) + +Steps: +1. Calculate SHA256 digest +2. Sign digest +3. Process policy file +4. Sign policy digest +5. Save policy signature +6. Generate final image +``` ``` diff --git a/docs/Targets.md b/docs/Targets.md index fdc1242c..5138690d 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -1,47 +1,44 @@ -# Targets +# Target Configuration Guide -This README describes configuration of supported targets. +This guide provides configuration and setup instructions for all supported targets in wolfBoot. -## Supported Targets +## Quick Reference -* [Simulated](#simulated) -* [Cortex-A53 / Raspberry PI 3](#cortex-a53--raspberry-pi-3-experimental) -* [Cypress PSoC-6](#cypress-psoc-6) -* [Infineon AURIX TC3xx](#infineon-aurix-tc3xx) -* [Intel x86-64 Intel FSP](#intel-x86_64-with-intel-fsp-support) -* [Kontron VX3060-S2](#kontron-vx3060-s2) -* [Microchip SAMA5D3](#microchip-sama5d3) -* [Microchip SAME51](#microchip-same51) -* [Nordic nRF52840](#nordic-nrf52840) -* [Nordic nRF5340](#nordic-nrf5340) -* [NXP iMX-RT](#nxp-imx-rt) -* [NXP Kinetis](#nxp-kinetis) -* [NXP LPC54xxx](#nxp-lpc54xxx) -* [NXP LS1028A](#nxp-ls1028a) -* [NXP MCXA153](#nxp-mcxa153) -* [NXP P1021 PPC](#nxp-qoriq-p1021-ppc) -* [NXP T1024 PPC](#nxp-qoriq-t1024-ppc) -* [NXP T2080 PPC](#nxp-qoriq-t2080-ppc) -* [Qemu x86-64 UEFI](#qemu-x86-64-uefi) -* [Raspberry Pi pico 2 (rp2350)](#raspberry-pi-pico-rp2350) -* [Renesas RA6M4](#renesas-ra6m4) -* [Renesas RX65N](#renesas-rx65n) -* [Renesas RX72N](#renesas-rx72n) -* [Renesas RZN2L](#renesas-rzn2l) -* [SiFive HiFive1 RISC-V](#sifive-hifive1-risc-v) -* [STM32C0](#stm32c0) -* [STM32F4](#stm32f4) -* [STM32F7](#stm32f7) -* [STM32G0](#stm32g0) -* [STM32H5](#stm32h5) -* [STM32H7](#stm32h7) -* [STM32L0](#stm32l0) -* [STM32L4](#stm32l4) -* [STM32L5](#stm32l5) -* [STM32U5](#stm32u5) -* [STM32WB55](#stm32wb55) -* [TI Hercules TMS570LC435](#ti-hercules-tms570lc435) -* [Xilinx Zynq UltraScale](#xilinx-zynq-ultrascale) +### Target Categories + +#### ARM-based MCUs +- STM32 Family (F4, F7, G0, H5, H7, L0, L4, L5, U5, WB55, C0) +- NXP Family (iMX-RT, Kinetis, LPC54xxx, MCXA153) +- Nordic Family (nRF52840, nRF5340) +- Renesas Family (RA6M4, RX65N, RX72N, RZN2L) +- Other ARM (Cypress PSoC-6, Microchip SAME51) + +#### RISC-V +- SiFive HiFive1 + +#### PowerPC +- NXP QorIQ (P1021, T1024, T2080) + +#### x86-64 +- Intel FSP Support +- QEMU x86-64 UEFI +- Kontron VX3060-S2 + +#### Development/Testing +- Simulated Target +- QEMU Support + +## Target Index + +| Target | Architecture | Key Features | Documentation Link | +|--------|--------------|--------------|-------------------| +| STM32F4 | ARM Cortex-M4 | Dual Bank Flash, TrustZone | [Details](#stm32f4) | +| STM32H5 | ARM Cortex-M33 | TrustZone, OTP Support | [Details](#stm32h5) | +| nRF5340 | ARM Cortex-M33 | Dual Core, TrustZone | [Details](#nordic-nrf5340) | +| RX65N | Renesas RX | TSIP Support | [Details](#renesas-rx65n) | +| x86_64 FSP | x86-64 | Intel FSP Support | [Details](#intel-x86_64-with-intel-fsp-support) | + +[Full list of supported targets below] ## STM32F4 @@ -2886,32 +2883,39 @@ You can `Ctrl-C` or login as `root` and power off qemu with `poweroff` -## Intel x86_64 with Intel FSP support +## Intel x86_64 with Intel FSP Support -This setup is more complex than the UEFI approach described earlier, but allows -for complete control of the machine since the very first stage after poweron. +### Overview +This configuration enables wolfBoot to function as a secure system BIOS replacement by integrating with Intel's Firmware Support Package (FSP). This provides lower-level hardware control compared to the UEFI approach. -In other words, wolfBoot can run as a secure replacement of the system BIOS, thanks to the -integration with the Intel Firmware Support Package (FSP). FSP provides services -for target-specific initial configuration (memory and silicon initialization, -power management, etc.). These services are designed to be accessed and invoked -by the bootloader. +### Key Features +- Complete system control from power-on +- Hardware initialization via FSP +- Memory and silicon configuration +- Power management integration +- Secure boot chain from reset -If wolfBoot is compiled with FSP support, it invokes the necessary machine-dependent -binary code, which that can be obtained from the chip manufacturer. +### FSP Integration +wolfBoot interfaces with Intel FSP to handle platform-specific initialization: +- Memory configuration +- Silicon initialization +- Power management +- Hardware abstraction -The following variables must be set in your `.config` file when using this feature: +### Configuration Requirements +Required `.config` variables: -- `ARCH` = `x86_64` -- `TARGET` = A useful name for the target you want to support. You can refer to - x86_fsp_qemu or kontron_vx3060_s2 for reference -- `FSP_T_BASE`: the base address where the FSP-T binary blob will be loaded. -- `FSP_M_BASE`: the base address where the FSP-M binary blob will be loaded. -- `FSP_S_BASE`: the base address where the FSP-S binary blob will be loaded. -- `FSP_T_BIN`: path to the FSP-T binary blob -- `FSP_M_BIN`: path to the FSP-M binary blob -- `FSP_S_BIN`: path to the FSP-S binary blob +| Variable | Description | Example | +|----------|-------------|----------| +| `ARCH` | Architecture setting | `x86_64` | +| `TARGET` | Target platform name | `x86_fsp_qemu` | +| `FSP_T_BASE` | FSP-T load address | Platform specific | +| `FSP_M_BASE` | FSP-M load address | Platform specific | +| `FSP_S_BASE` | FSP-S load address | Platform specific | +| `FSP_T_BIN` | Path to FSP-T binary | `/path/to/fspt.bin` | +| `FSP_M_BIN` | Path to FSP-M binary | `/path/to/fspm.bin` | +| `FSP_S_BIN` | Path to FSP-S binary | `/path/to/fsps.bin` | - `WOLFBOOT_ORIGIN`: the start address of wolfBoot inside the flash (flash is mapped so that it ends at the 4GB boundary) - `BOOTLOADER_PARTITION_SIZE`: the size of the partition that stores wolfBoot in the flash - `WOLFBOOT_LOAD_BASE`: the address where wolfboot will be loaded in RAM after the first initialization phase diff --git a/docs/ata_security.md b/docs/ata_security.md index 4f354c9d..8515fd51 100644 --- a/docs/ata_security.md +++ b/docs/ata_security.md @@ -1,44 +1,71 @@ -# ATA Security +# ATA Security in wolfBoot -## Introduction -This document provides an overview of how wolfBoot can leaverage the ATA security features to lock or unlock ATA drive. -The ATA drive may be locked either by using a hardcoded password or by using a secret that is sealed in the TPM. +## Overview +wolfBoot provides secure ATA drive locking and unlocking capabilities through two mechanisms: +1. Hardcoded password authentication +2. TPM-sealed secret authentication -## Table of Contents -- [ATA Security](#ata-security) - - [Introduction](#introduction) - - [Table of Contents](#table-of-contents) - - [Unlocking the Disk with a Hardcoded Password](#unlocking-the-disk-with-a-hardcoded-password) - - [Unlocking the Disk with a TPM-Sealed Secret](#unlocking-the-disk-with-a-tpm-sealed-secret) - - [Disabling the password](#disabling-the-password) +This integration enables secure storage protection while maintaining compatibility with standard ATA security features. -## Unlocking the Disk with a Hardcoded Password -To unlock the disk using a hardcoded password, use the following options in your .config file: +## Key Features +- ATA drive locking/unlocking support +- TPM integration for secure secret storage +- First-boot password initialization +- Master password support for administrative control +- Configurable security policies + +## Configuration Methods + +### Hardcoded Password Authentication +Uses a static password defined at compile time for drive locking/unlocking. + +#### Configuration Options +```make +DISK_LOCK=1 # Enable ATA security features +DISK_LOCK_PASSWORD=hardcoded_password # Set static password ``` -DISK_LOCK=1 -DISK_LOCK_PASSWORD=hardcoded_password + +#### Behavior +- First boot: If drive is unlocked, sets configured password +- Subsequent boots: Uses configured password to unlock drive + +### TPM-Sealed Secret Authentication +Leverages TPM capabilities to securely store and manage drive unlock secrets. For detailed TPM integration information, see [TPM.md](TPM.md) and [measured_boot.md](measured_boot.md). + +#### Configuration Options +| Option | Description | Usage | +|--------|-------------|--------| +| `WOLFBOOT_TPM_SEAL` | Enable TPM sealing support | Required with `DISK_LOCK=1` | +| `WOLFBOOT_TPM_SEAL_KEY_ID` | Policy signing key identifier | Used for TPM policy binding | +| `ATA_UNLOCK_DISK_KEY_NV_INDEX` | TPM NV storage index | Location for sealed secret | +| `WOLFBOOT_DEBUG_REMOVE_SEALED_ON_ERROR` | Error handling behavior | Deletes secret and panics on error | + +#### Behavior +- First boot with no sealed secret: + 1. Generates random secret + 2. Seals secret to TPM + 3. Locks drive with sealed secret +- Subsequent boots: + 1. Unseals secret from TPM + 2. Unlocks drive using unsealed secret + +### Administrative Control + +#### Disabling User Password +Requires existing master password configuration. + +```make +# Configuration for password disable +WOLFBOOT_ATA_DISABLE_USER_PASSWORD=1 # Enable password disable +ATA_MASTER_PASSWORD=master_password # Set master password ``` -If the ATA disk has no password set, the disk will be locked with the password provided at the first boot. -## Unlocking the Disk with a TPM-Sealed Secret -wolfBoot allows to seal secret safely in the TPM in a way that it can be unsealed only under specific conditions. Please refer to files TPM.md and measured_boot.md for more information. -If the options `WOLFBOOT_TPM_SEAL` and `DISK_LOCK` are enabled, wolfBoot will use a TPM sealed secret as the password to unlock the disk. The following options controls the sealing and unsealing of the secret: +#### Operation Flow +1. Verifies master password +2. Disables user password +3. Executes panic sequence -| Option | Description | -|--------|-------------| -| WOLFBOOT_TPM_SEAL_KEY_ID| The key ID to use for sign the policy | -| ATA_UNLOCK_DISK_KEY_NV_INDEX | The NV index to store the sealed secret. | -| WOLFBOOT_DEBUG_REMOVE_SEALED_ON_ERROR| In case of error, delete the secret and panic() | - -In case there are no secret sealed at `ATA_UNLOCK_DISK_KEY_NV_INDEX`, a new random secret will be created and sealed at that index. -In case the ATA drive is not locked, it will be locked at the first boot with the secret sealed in the TPM. - -## Disabling the password - -If you need to disable the password, a master password should be already set on the device. Then you can use the following options to compile wolfBoot so that it will disable the password from the drive and panic: - -``` -WOLFBOOT_ATA_DISABLE_USER_PASSWORD=1 -ATA_MASTER_PASSWORD=the_master_password -``` +For more information about TPM integration, see: +- [TPM Security](TPM.md) +- [Measured Boot](measured_boot.md) diff --git a/docs/azure_keyvault.md b/docs/azure_keyvault.md index d9f2c40d..4f93e0ac 100644 --- a/docs/azure_keyvault.md +++ b/docs/azure_keyvault.md @@ -1,109 +1,123 @@ -## Signing firmware using Microsoft Azure Key Vault +# Azure Key Vault Integration for Firmware Signing -Microsoft offers secure key management and provisioning tools, using keys stored -in HSMs. This mechanisms helps to centralize key management for several purposes, -including the support for signing payloads using the managed keys, which can be -used in combination with wolfBoot for provisioning public keys in a fleet of -devices. +## Overview +wolfBoot integrates with Microsoft Azure Key Vault to provide secure firmware signing using Hardware Security Modules (HSMs). This integration enables: +- Centralized key management +- Secure key storage in HSMs +- Fleet-wide public key provisioning +- Automated firmware signing workflow + +## Key Features +- Azure Key Vault integration +- HSM-backed key storage +- Support for ECC256 signatures +- ASN.1 DER format compatibility +- REST API-based signing process -### Preparing the keystore +## Setup and Configuration -wolfBoot can import public keys in the keystore using the `keygen` command line -tool provided. `keygen` supports both raw ECC keys and ASN.1 format (.der). +### Keystore Preparation -Azure allows to download the public keys in ASN.1 format to provision the device. -To retrieve each public key to use for firmware authentication in wolfBoot, use: - -```sh -az keyvault key download --vault-name -n test-signing-key-1 -e DER -f public-key-1.der +#### 1. Download Public Keys +Retrieve public keys from Azure Key Vault in ASN.1 DER format: +```bash +az keyvault key download \ + --vault-name \ + -n test-signing-key-1 \ + -e DER \ + -f public-key-1.der ``` -A keystore can now be created importing the public keys and with `keygen`'s `-i` -(import) option. The option may be repeated multiple times to add more keys to -the keystore. +#### 2. Import Keys to wolfBoot +Create a keystore using wolfBoot's `keygen` tool: +```bash +# Import single key +./tools/keytools/keygen --ecc256 -i public-key-1.der -```sh -./tools/keytools/keygen --ecc256 -i public-key-1.der [-i public-key-2.der ...] +# Import multiple keys +./tools/keytools/keygen --ecc256 \ + -i public-key-1.der \ + -i public-key-2.der \ + -i public-key-3.der ``` -### Signing the firmware image for wolfBoot +**Note**: `keygen` supports both raw ECC keys and ASN.1 DER format -The signing operation using any external HSM is performed through three-steps, -as described in the relevant section in [Signing.md](signing.md). -In this section we describe the procedure to sign the firmware image using Azure key vault. +## Firmware Signing Process +The signing process with Azure Key Vault follows a three-step procedure as outlined in [Signing.md](signing.md). Below is the detailed workflow for Azure Key Vault integration. -#### Obtaining the SHA256 digest +### Step 1: Generate Image Digest -Step 1 consists in calling the `./sign` tool with the extra `--sha-only` argument, -to generate the digest to sign. The public key associated to the selected signing -key in the vault needs to be provided: - -```sh -./tools/keytools/sign --ecc256 --sha-only --sha256 test-app/image.bin public-key-1.der 1 +1. Create SHA256 digest using wolfBoot tools: +```bash +./tools/keytools/sign \ + --ecc256 \ + --sha-only \ + --sha256 \ + test-app/image.bin \ + public-key-1.der \ + 1 ``` -To fit in a https REST request, the digest obtained must be encoded using base64: - -```sh +2. Encode digest for HTTP transport: +```bash DIGEST=$(cat test-app/image_v1_digest.bin | base64url_encode) ``` -The variable `DIGEST` now contains a printable encoding of the key, which can be -attached to the request. +### Step 2: Sign with Azure Key Vault -#### HTTPS request for signing the digest with the Key Vault - - -To prepare the request, first get an access token from the vault and store it in a variable: - -```sh -ACCESS_TOKEN=$(az account get-access-token --resource "https://vault.azure.net" --query "accessToken" -o tsv) +1. Obtain Azure access token: +```bash +ACCESS_TOKEN=$(az account get-access-token \ + --resource "https://vault.azure.net" \ + --query "accessToken" \ + -o tsv) ``` -Use the URL associated to the selected key vault: - -```sh +2. Configure Key Vault endpoint: +```bash KEY_IDENTIFIER="https://.vault.azure.net/keys/test-signing-key" ``` -Perform the request using cURL, and store the result in a variable: - -```sh +3. Request signature via REST API: +```bash SIGNING_RESULT=$(curl -X POST \ -s "${KEY_IDENTIFIER}/sign?api-version=7.4" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type:application/json" \ -H "Accept:application/json" \ -d "{\"alg\":\"ES256\",\"value\":\"${DIGEST}\"}") -echo $SIGNING_RESULT ``` -The field `.value` in the result contains the (base64 encoded) signature. -To extract the signature from the response, you can use a JSON parser: - -```sh +4. Extract and decode signature: +```bash +# Extract base64 signature SIGNATURE=$(jq -jn "$SIGNING_RESULT|.value") + +# Decode to binary +echo $SIGNATURE | base64url_decode > test-app/image_v1_digest.sig ``` -The signature can now be decoded from base64 into a binary, so the -`sign` tool can incorporate the signature into the manifest header. +### Step 3: Create Signed Firmware -```sh -echo $SIGNATURE| base64url_decode > test-app/image_v1_digest.sig +Generate final signed firmware image: +```bash +./tools/keytools/sign \ + --ecc256 \ + --sha256 \ + --manual-sign \ + test-app/image.bin \ + test-signin-key_pub.der \ + 1 \ + test-app/image_v1_digest.sig ``` -#### Final step: create the signed firmware image +The output file `image_v1_signed.bin` contains the firmware image with embedded signature, ready for deployment to wolfBoot-enabled devices. -The 'third step' in the HSM three-steps procedure requires the `--manual-sign` option and the -signature obtained through the Azure REST API. - - -``` -./tools/keytools/sign --ecc256 --sha256 --manual-sign test-app/image.bin test-signin-key_pub.der 1 test-app/image_v1_digest.sig -``` - -The resulting binary file `image_v1_signed.bin` will now contain a signed firmware -image that can be authenticated and staged by wolfBoot. +## Related Documentation +- [Signing Process Details](signing.md) +- [Firmware Image Format](firmware_image.md) +- [Key Management](keystore.md) diff --git a/docs/compile.md b/docs/compile.md index 436dc26b..03e544f1 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -1,290 +1,444 @@ -# Compiling wolfBoot +# wolfBoot Build System Guide -WolfBoot is portable across different types of embedded systems. The platform-specific code -is contained in a single file under the `hal` directory, and implements the hardware-specific functions. +## Overview +wolfBoot provides a flexible build system supporting multiple embedded platforms through a modular Hardware Abstraction Layer (HAL). This guide explains the build configuration options and compilation process. -To enable specific compile options, use environment variables while calling make, e.g. +## Build Configuration Methods -`make CORTEX_M0=1` +### 1. Command Line Options +Set build options directly via environment variables: +```bash +make CORTEX_M0=1 +``` -As an alternative, you can provide a .config file in the root directory of wolfBoot. -Command line options have priority on `.config` options, as long as .config options are -defined using the `?=` operator, e.g.: +### 2. Configuration File (.config) +Create a persistent configuration in the root directory: +```make +# Example .config entry +WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x14000 +``` + +**Note**: Command line options take precedence over `.config` entries when using `?=` operator. + +## Configuration Setup + +### Generate New Configuration +```bash +# Create default configuration +make config + +# Follow prompts to configure: +# - Press Enter to accept default values [shown in brackets] +# - Enter new value to override defaults +``` + +The generated `.config` file can be: +- Used as default for subsequent `make` commands +- Modified manually with a text editor +- Overridden by command line options -`WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x14000` +## Platform Configuration -## Generate a new configuration +### Target Selection +Set target platform using `TARGET` variable: +```bash +make TARGET=stm32f4 # Default if unspecified +``` + +For supported platforms, see: +- [HAL Documentation](./HAL.md) +- [Platform Support Matrix](./Targets.md) + +### Architecture-Specific Options +Default architecture support: +- ARM Cortex-M3/M4/M7 + +For other architectures: +```bash +# Cortex-M0 support +make CORTEX_M0=1 + +# See HAL documentation for other architecture options +``` + +### Adding New Platforms +1. Create HAL driver in [hal/](../hal/) directory +2. Add corresponding linker script +3. Implement required HAL functions + +## Optimization Options + +### Size vs Speed Tradeoffs + +#### Assembly Optimizations +```bash +# Disable all assembly optimizations (smallest code) +make NO_ASM=1 + +# Disable ARM-specific optimizations only +make NO_ARM_ASM=1 # Keeps SP math optimizations +``` + +#### Performance Impact Example +ECC256 + SHA256 on STM32H7 (100KB image verification): + +| Optimization Level | Configuration | Size (B) | Time (s) | Notes | +|-------------------|---------------|-----------|-----------|--------| +| Maximum Speed | `SIGN=ECC256` | 21,836 | 0.583 | Full assembly optimizations | +| Balanced | `SIGN=ECC256 NO_ARM_ASM=1` | 18,624 | 0.760 | ECC/SP math only | +| Minimum Size | `SIGN=ECC256 NO_ASM=1` | 14,416 | 3.356 | No assembly code | -A new `.config` file with a set of default parameters -can be generated by running `make config`. The build script will ask to enter a default value for -each configuration parameter. Enter confirm the current value, indicated in between `[]`. +**Note**: Disabling optimizations significantly impacts boot time but reduces code size. + + +## Flash Memory Configuration + +### Partition Configuration +The flash memory layout is defined in [include/target.h](../include/target.h), generated based on the following configuration parameters: -Once a .config file is in place, it will change the default compile-time options when running `make` -without parameters. +| Parameter | Description | Usage | +|-----------|-------------|--------| +| `WOLFBOOT_SECTOR_SIZE` | Physical flash sector size | - Minimum swap unit
- Must be largest sector size if partitions have different geometries | +| `WOLFBOOT_PARTITION_SIZE` | Size of BOOT/UPDATE partitions | - Same size for both partitions
- Must accommodate firmware + headers | +| `WOLFBOOT_PARTITION_BOOT_ADDRESS` | Boot partition start address | - Must be sector-aligned
- App starts after header (256B) | +| `WOLFBOOT_PARTITION_UPDATE_ADDRESS` | Update partition start address | - Physical address for internal flash
- Offset for external flash | +| `WOLFBOOT_PARTITION_SWAP_ADDRESS` | Swap area start address | - Used for reversible updates
- Size = one sector | + +### Memory Layout Example +``` +Flash Memory ++------------------------+ <- 0x00000000 +| wolfBoot | ++------------------------+ <- WOLFBOOT_PARTITION_BOOT_ADDRESS +| Header | Firmware | Boot Partition ++------------------------+ <- WOLFBOOT_PARTITION_UPDATE_ADDRESS +| Header | Update | Update Partition ++------------------------+ <- WOLFBOOT_PARTITION_SWAP_ADDRESS +| Swap | Swap Area (1 sector) ++------------------------+ +``` -.config can be modified with a text editor to alter the default options later on. +### Configuration Methods +Set parameters via: +1. Command line: +```bash +make WOLFBOOT_SECTOR_SIZE=0x1000 WOLFBOOT_PARTITION_SIZE=0x20000 +``` -## Platform selection +2. .config file: +```make +WOLFBOOT_SECTOR_SIZE?=0x1000 +WOLFBOOT_PARTITION_SIZE?=0x20000 +``` -If supported natively, the target platform can be specified using the `TARGET` variable. -Make will automatically select the correct compile option, and include the corresponding HAL for -the selected target. +## Bootloader Configuration + +### Digital Signature Algorithms + +wolfBoot supports multiple signature algorithms with different security and performance characteristics. + +#### Available Algorithms + +| Algorithm | Command | Key Size | Performance | Size Impact | +|-----------|---------|-----------|-------------|-------------| +| Ed25519 (default) | `SIGN=ED25519` | 256-bit | Good | Smallest | +| ECDSA P-256 | `SIGN=ECC256` | 256-bit | Better | Medium | +| ECDSA P-384 | `SIGN=ECC384` | 384-bit | Good | Medium | +| ECDSA P-521 | `SIGN=ECC521` | 521-bit | Good | Larger | +| RSA-2048 | `SIGN=RSA2048` | 2048-bit | Good | Large | +| RSA-3072 | `SIGN=RSA3072` | 3072-bit | Moderate | Larger | +| RSA-4096 | `SIGN=RSA4096` | 4096-bit | Moderate | Largest | +| Ed448 | `SIGN=ED448` | 448-bit | Good | Medium | +| No Authentication | `SIGN=NONE` | N/A | Best | Minimal | + +#### Usage Examples +```bash +# Use Ed25519 (default) +make + +# Use ECDSA P-256 +make SIGN=ECC256 + +# Use RSA-2048 +make SIGN=RSA2048 + +# Disable authentication +make SIGN=NONE +``` + +#### Key Generation +- Each algorithm requires specific key generation tools +- Tools available in [tools/](../tools/) directory +- See [Signing.md](Signing.md) for detailed key management instructions + +**Warning**: Using `SIGN=NONE` disables secure boot authentication + +### Advanced Features + +#### Incremental Updates +Enable delta-based firmware updates to minimize update size and flash operations. + +```bash +# Enable incremental updates +make DELTA_UPDATES=1 + +# Generate delta update +./tools/keytools/sign --delta old.bin new.bin key.der version +``` + +For detailed information, see [Firmware Updates](firmware_update.md). -For a list of the platforms currently supported, see the [HAL documentation](./HAL.md). +#### Debug Support +Enable debugging features and symbols: +```bash +make DEBUG=1 +``` + +**Important**: Debug build increases bootloader size significantly. Ensure sufficient flash space before `WOLFBOOT_PARTITION_BOOT_ADDRESS`. + +#### Interrupt Vector Configuration +Control interrupt vector table (IVT) relocation: + +| Option | Description | Use Case | +|--------|-------------|----------| +| Default | Relocates IVT via VTOR | Standard operation | +| `VTOR=0` | Disables IVT relocation | - External IVT management
- Platforms without VTOR
- Custom relocation schemes | -To add a new platform, simply create the corresponding HAL driver and linker script file -in the [hal](../hal) directory. +```bash +# Disable vector table relocation +make VTOR=0 +``` + +### Memory Management + +#### Stack Configuration Options -Default option if none specified: `TARGET=stm32f4` +wolfBoot provides flexible stack management options to accommodate different memory constraints: -Some platforms will require extra options, specific for the architecture. -By default, wolfBoot is compiled for ARM Cortex-M3/4/7. To compile for Cortex-M0, use: +| Option | Description | Use Case | +|--------|-------------|----------| +| Default | Stack-only operation | - No dynamic allocation
- Predictable memory usage | +| `WOLFBOOT_SMALL_STACK=1` | Static memory pool | - Limited RAM systems
- Dedicated bootloader RAM | +| `WOLFBOOT_HUGE_STACK=1` | Large stack allowed | - Systems with ample RAM
- Complex crypto operations | -`CORTEX_M0=1` +#### Memory Usage Characteristics -### Speed vs. size +1. **Default Mode** + - Uses stack for all operations + - No dynamic memory allocation + - Stack usage varies by algorithm + - Predictable at compile time -Some targets support assembly optimizations by default. -To disable assembly optimizations, use `NO_ASM=1`. This option will -produce smaller code, but will also impact on the boot time. +2. **Small Stack Mode** + ```bash + make WOLFBOOT_SMALL_STACK=1 + ``` + - Creates fixed-size memory pool + - Reduces runtime stack usage + - Uses static allocation + - Simulates dynamic allocation + - Suitable for RAM-constrained systems + +3. **Large Stack Mode** + ```bash + make WOLFBOOT_HUGE_STACK=1 + ``` + - Bypasses stack size checks + - Required for some crypto configs + - Use when RAM is abundant + - Enables complex operations -ARM-specific ARM optimizations affecting hash and symmetric key ciphers can be -disabled with the option `NO_ARM_ASM=1`. This is useful for example when you want -to use SP math optimizations for key verification, but exclude SHA2/AES optimizations -to save some space. +**Warning**: Large stack mode may cause issues on RAM-constrained systems -#### Example: ECC256 + SHA256 on STM32H7 +### Safety and Recovery Features -Benchmark footprint vs. boot time SHA of 100KB image + signature verification +#### Firmware Backup Control +Control backup behavior during updates: -| Description | Selected options | wolfBoot size (B) | Boot time (s) | -|-------------|------------------|-------------------|---------------| -| Full ECC256 assembly optimizations. Fastest. | `SIGN=ECC256` | 21836 | .583 | -| Optimize ECC only (SP math assembly only) | `SIGN=ECC256 NO_ARM_ASM=1` | 18624 | .760 | -| No assembly optimizations (smallest) | `SIGN=ECC256 NO_ASM=1` | 14416 | 3.356 | +```bash +# Disable firmware backup +make DISABLE_BACKUP=1 +``` +| Mode | Description | Use Case | Risk Level | +|------|-------------|----------|------------| +| Default | Creates backup copy | Normal operation | Safe | +| `DISABLE_BACKUP=1` | No backup created | - Limited flash space
- Read-only update partition | High | -### Flash partitions +**Warning**: Disabling backup removes fallback protection against failed updates -The file [include/target.h](../include/target.h) is generated according to the configured flash geometry, -partitions size and offset of the target system. The following values must be set to provide the -desired flash configuration, either via the command line, or using the .config file: +#### Flash Memory Handling - - `WOLFBOOT_SECTOR_SIZE` +##### Write-Once Flash Support +For flash that doesn't support multiple writes between erases: -This variable determines the size of the physical sector on the flash memory. If areas with different -block sizes are used for the two partitions (e.g. update partition on an external flash), this variable -should indicate the size of the biggest sector shared between the two partitions. - -WolfBoot uses this value as minimum unit when swapping the firmware images in place. For this reason, -this value is also used to set the size of the SWAP partition. - - - `WOLFBOOT_PARTITION_BOOT_ADDRESS` - -This is the start address of the boot partition, aligned to the beginning of a new flash sector. -The application code starts after a further offset, equal to the partition header size (256B -for Ed25519 and ECC signature headers). - - - `WOLFBOOT_PARTITION_UPDATE_ADDRESS` - -This is the start address of the update partition. If an external memory is used via the -`EXT_FLASH` option, this variable contains the offset of the update partition from the -beginning of the external memory addressable space. - - - `WOLFBOOT_PARTITION_SWAP_ADDRESS` - -The address for the swap spaced used by wolfBoot to swap the two firmware images in place, -in order to perform a reversible update. The size of the SWAP partition is exactly one sector on the flash. -If an external memory is used, the variable contains the offset of the SWAP area from the beginning -of its addressable space. - - - `WOLFBOOT_PARTITION_SIZE` - -The size of the BOOT and UPDATE partition. The size is the same for both partitions. - -## Bootloader features - -A number of characteristics can be turned on/off during wolfBoot compilation. Bootloader size, -performance and activated features are affected by compile-time flags. - -### Change DSA algorithm - -By default, wolfBoot is compiled to use Ed25519 DSA. The implementation of ed25519 is smaller, -while giving a good compromise in terms of boot-up time. - -Better performance can be achieved using ECDSA with curve p-256. -To activate ECC256, ECC384 or ECC521 support, use: - -`SIGN=ECC256` or `SIGN=ECC384` or `SIGN=ECC521` respectively. - -when invoking `make`. - -RSA is also supported, with different key length. -To activate RSA2048, RSA3072 or RSA4096, use: - -`SIGN=RSA2048` or `SIGN=RSA3072` or `SIGN=RSA4096` respectively. - -Ed448 is also supported via `SIGN=ED448`. - -The default option, if no value is provided for the `SIGN` variable, is - -`SIGN=ED25519` - -Changing the DSA algorithm will also result in compiling a different set of tools for key generation -and firmware signature. - -Find the corresponding key generation and firmware signing tools in the [tools](../tools) directory. - -It's possible to disable authentication of the firmware image by explicitly using: - -`SIGN=NONE` - -in the Makefile commandline. This will compile a minimal bootloader with no support for public-key authenticated -secure boot. - -### Incremental updates - -wolfBoot support incremental updates. To enable this feature, compile with `DELTA_UPDATES=1`. - -An additional file is generated when the sign tool is invoked with the `--delta` option, containing only the -differences between the old firmware to replace, currently running on the target, and the new version. - -For more information and examples, see the [firmware update](firmware_update.md) section. - -### Enable debug symbols - -To debug the bootloader, simply compile with `DEBUG=1`. The size of the bootloader will increase -consistently, so ensure that you have enough space at the beginning of the flash before -`WOLFBOOT_PARTITION_BOOT_ADDRESS`. - -### Disable interrupt vector relocation - -On some platforms, it might be convenient to avoid the interrupt vector relocation before boot-up. -This is required when a component on the system already manages the interrupt relocation at a different -stage, or on these platform that do not support interrupt vector relocation. - -To disable interrupt vector table relocation, compile with `VTOR=0`. By default, wolfBoot will relocate the -interrupt vector by setting the offset in the vector relocation offset register (VTOR). - -### Limit stack usage - -By default, wolfBoot does not require any memory allocation. It does this by performing all the operations -using the stack. Although the stack space used by the algorithms can be predicted at compile time, the amount -of stack space be relatively big, depending on the algorithm selected. - -Some targets offer limited amount of RAM to use as stack space, either in general, or in a configuration -dedicated for the bootloader stage. - -In these cases, it might be useful to activate `WOLFBOOT_SMALL_STACK=1`. With this option, a fixed-size pool -is created at compile time to assist the allocation of the object needed by the cryptography implementation. -When compiled with `WOLFBOOT_SMALL_STACK=1`, wolfBoot reduces the stack usage considerably, and simulates dynamic -memory allocations by assigning dedicated, statically allocated, pre-sized memory areas. - -### Allow bigger stack size allocation - -Some combinations of authentication algorithms, key sizes and math configuration in wolfCrypt require -a large amount of memory to be allocated in the stack at runtime. By default, if your configuration -falls in one of these cases, wolfBoot compilation will terminate with an explicit error. - -In some cases you might have enough memory available to allow large stack allocations. -To circumvent the compile-time checks on the maximum allowed stack size, use `WOLFBOOT_HUGE_STACK=1`. - -### Disable Backup of current running firmware - -Optionally, it is possible to disable the backup copy of the current running firmware upon the installation of the -update. This implies that no fall-back mechanism is protecting the target from a faulty firmware installation, but may be useful -in some cases where it is not possible to write on the update partition from the bootloader. -The associated compile-time option is - -`DISABLE_BACKUP=1` - -### Enable workaround for 'write once' flash memories - -On some microcontrollers, the internal flash memory does not allow subsequent writes (adding zeroes) to a -sector, after the entire sector has been erased. WolfBoot relies on the mechanism of adding zeroes to the -'flags' fields at the end of both partitions to provide a fail-safe swap mechanism. - -To enable the workaround for 'write once' internal flash, compile with - -`NVM_FLASH_WRITEONCE=1` - -**warning** When this option is enabled, the fail-safe swap is not guaranteed, i.e. the microcontroller -cannot be safely powered down or restarted during a swap operation. - -### Allow version roll-back - -WolfBoot will not allow updates to a firmware with a version number smaller than the current one. To allow -downgrades, compile with `ALLOW_DOWNGRADE=1`. - -Warning: this option will disable version checking before the updates, thus exposing the system to potential -forced downgrade attacks. - -### Enable optional support for external flash memory - -WolfBoot can be compiled with the makefile option `EXT_FLASH=1`. When the external flash support is -enabled, update and swap partitions can be associated to an external memory, and will use alternative -HAL function for read/write/erase access. - -To associate the update or the swap partition to an external memory, define `PART_UPDATE_EXT` and/or -`PART_SWAP_EXT`, respectively. By default, the makefile assumes that if an external memory is present, -both `PART_UPDATE_EXT` and `PART_SWAP_EXT` are defined. - -If the `NO_XIP=1` makefile option is present, `PART_BOOT_EXT` is assumed too, as no execute-in-place is -available on the system. This is typically the case of MMU system (e.g. Cortex-A) where the operating system -image(s) are position-independent ELF images stored in a non-executable non-volatile memory, and must be -copied in RAM to boot after verification. - -When external memory is used, the HAL API must be extended to define methods to access the custom memory. -Refer to the [HAL](HAL.md) page for the description of the `ext_flash_*` API. - -The `EXT_FLASH` option can also be used if the target device requires special handling for flash reads -(e.g. word size requirements or other restrictions), regardless of whether the flash is internal or external. - -Note that the `EXT_FLASH` option is incompatible with the `NVM_FLASH_WRITEONCE` option. Targets that need -both these options must implement the sector-based read-modify-erase-write sequence at the HAL layer. +```bash +# Enable write-once flash support +make NVM_FLASH_WRITEONCE=1 +``` + +**Important Notes**: +- Required for some microcontrollers +- Affects flag field operations +- Compromises fail-safe swap guarantee +- Power loss during swap may corrupt firmware + +##### Version Control + +Control firmware version enforcement: + +| Option | Command | Behavior | Security Impact | +|--------|---------|----------|-----------------| +| Default | N/A | Prevents downgrades | Secure | +| `ALLOW_DOWNGRADE=1` | `make ALLOW_DOWNGRADE=1` | Allows older versions | Vulnerable to downgrade attacks | + +**Security Warning**: +- Enabling downgrades bypasses version checks +- May expose system to malicious downgrades +- Use only in development/testing + +### External Flash Support + +#### Overview +wolfBoot supports external flash memory for storing firmware updates and swap partitions, with configurable partition mapping and access methods. + +#### Configuration Options + +| Option | Description | Default | Usage | +|--------|-------------|---------|--------| +| `EXT_FLASH=1` | Enable external flash | No | Basic external flash support | +| `PART_UPDATE_EXT` | Map update to external | Yes* | Store updates externally | +| `PART_SWAP_EXT` | Map swap to external | Yes* | Use external swap space | +| `PART_BOOT_EXT` | Map boot to external | No** | For non-XIP systems | +| `NO_XIP=1` | Disable execute-in-place | No | For MMU systems | + +\* When `EXT_FLASH=1` +\** Unless `NO_XIP=1` + +#### Memory Configurations + +1. **Standard External Flash** + ```bash + make EXT_FLASH=1 + ``` + - Updates and swap in external flash + - Boot partition in internal flash + - Requires HAL extension + +2. **Non-XIP Systems** (e.g., Cortex-A) + ```bash + make EXT_FLASH=1 NO_XIP=1 + ``` + - All partitions in external flash + - Images loaded to RAM for execution + - Supports position-independent code + +#### Implementation Requirements + +1. **HAL Extension** + - Implement `ext_flash_*` API + - See [HAL Documentation](HAL.md) + - Handle custom memory access + +2. **Compatibility Notes** + - Incompatible with `NVM_FLASH_WRITEONCE` + - Use HAL layer for special flash handling + - Consider word size requirements For an example of using `EXT_FLASH` to bypass read restrictions, (in this case, the inability to read from erased flash due to ECC errors) on a platform with write-once flash, see the [infineon tricore port](../hal/aurix_tc3xx.c). -#### SPI devices +### External Memory Interfaces -In combination with the `EXT_FLASH=1` configuration parameter, it is possible to use a platform-specific SPI drivers, -e.g. to access an external SPI flash memory. By compiling wolfBoot with the makefile option `SPI_FLASH=1`, the external -memory is directly mapped to the additional SPI layer, so the user does not have to define the `ext_flash_*` functions. +#### SPI Flash Support -SPI functions, instead, must be defined. Example SPI drivers are available for multiple platforms in the [hal/spi](../hal/spi) directory. +Enable SPI flash memory integration: +```bash +make EXT_FLASH=1 SPI_FLASH=1 +``` -#### UART bridge towards neighbor systems +**Features**: +- Automatic ext_flash API mapping +- Platform-specific SPI drivers +- Multiple platform support -Another alternative available to map external devices consists in enabling a UART bridge towards a neighbor system. -The neighbor system must expose a service through the UART interface that is compatible with the wolfBoot protocol. +**Implementation**: +1. Define SPI functions +2. See examples in [hal/spi/](../hal/spi/) +3. No manual ext_flash_* implementation needed -In the same way as for SPI devices, the `ext_flash_*` API is automatically defined by wolfBoot when the option `UART_FLASH=1` is used. +#### UART Bridge Support -For more details, see the manual page [Remote External flash memory support via UART](remote_flash.md) +Enable UART-based external memory access: +```bash +make EXT_FLASH=1 UART_FLASH=1 +``` -#### Encryption support for external partitions +**Capabilities**: +- Remote flash access +- Neighbor system integration +- Protocol-based communication -When update and swap partitions are mapped to an external device using `EXT_FLASH=1`, either in combination with `SPI_FLASH`, -`UART_FLASH`, or any custom external mapping, it is possible to enable ChaCha20 encryption when accessing those partition from the -bootloader. The update images must be pre-encrypted at the source using the key tools, and wolfBoot should be instructed to use a temporary -ChaCha20 symmetric key to access the content of the updates. +**Requirements**: +- Compatible neighbor service +- wolfBoot protocol support +- UART interface availability -For more details about this optional feature, please refer to the [Encrypted external partitions](encrypted_partitions.md) manual page. +For detailed UART implementation, see: +- [Remote Flash Support](remote_flash.md) +- [Protocol Specification](firmware_update.md) +### Advanced Memory Features -### Executing flash access code from RAM +#### External Partition Encryption -On some platform, flash access code requires to be executed from RAM, to avoid conflict e.g. when writing -to the same device where wolfBoot is executing, or when changing the configuration of the flash itself. +Enable ChaCha20 encryption for external partitions: +```bash +make EXT_FLASH=1 [SPI_FLASH=1|UART_FLASH=1] +``` -To move all the code accessing the internal flash for writing, into a section in RAM, use the compile time option -`RAM_CODE=1` (on some hardware configurations this is required for the bootloader to access the flash for writing). +**Requirements**: +- External flash configuration +- Pre-encrypted update images +- ChaCha20 symmetric key setup -### Enable Dual-bank hardware-assisted swapping +**Compatibility**: +- Works with SPI flash +- Works with UART bridge +- Supports custom mappings -When supported by the target platform, hardware-assisted dual-bank swapping can be used to perform updates. -To enable this functionality, use `DUALBANK_SWAP=1`. Currently, only STM32F76x and F77x support this feature. +For implementation details, see [Encrypted Partitions](encrypted_partitions.md). + +#### RAM-Based Flash Operations + +Execute flash access code from RAM: +```bash +make RAM_CODE=1 +``` + +**Use Cases**: +- Avoid flash conflicts +- Self-modifying operations +- Flash configuration changes + +**Important**: Required for some hardware configurations to enable flash write access. + +#### Hardware-Assisted Updates + +Enable dual-bank swap support: +```bash +make DUALBANK_SWAP=1 +``` + +**Features**: +- Hardware-assisted updates +- Efficient bank switching +- Reduced update time + +**Support**: +- STM32F76x series +- STM32F77x series +- Future platform support planned ### Store UPDATE partition flags in a sector in the BOOT partition @@ -323,23 +477,36 @@ iterating over a range of flash sectors and erasing them one at a time. Setting single HAL flash erase invocation with a larger erase length versus the iterative approach. On targets where multi-sector erases are more performant, this option can be used to dramatically speed up the image swap procedure. -### Using Mac OS/X +### Platform-Specific Notes -If you see 0xC3 0xBF (C3BF) repeated in your factory.bin then your OS is using Unicode characters. +#### macOS Build Environment -The "tr" command for assembling the 0xFF padding between `"bootloader" ... 0xFF ... "application" = factory.bin`, which requires the "C" locale. +##### Unicode Character Issues +When building on macOS, you may encounter Unicode-related issues in binary files: +- Symptom: 0xC3 0xBF (C3BF) patterns in factory.bin +- Cause: macOS Unicode locale settings +- Affects: Binary padding operations -Set this in your terminal -``` -LANG= -LC_COLLATE="C" -LC_CTYPE="C" -LC_MESSAGES="C" -LC_MONETARY="C" -LC_NUMERIC="C" -LC_TIME="C" -LC_ALL= +##### Solution +Set C locale in terminal: +```bash +# Required environment variables +export LANG= +export LC_COLLATE="C" +export LC_CTYPE="C" +export LC_MESSAGES="C" +export LC_MONETARY="C" +export LC_NUMERIC="C" +export LC_TIME="C" +export LC_ALL= ``` -Then run the normal `make` steps. +**Workflow**: +1. Set environment variables +2. Run make commands normally +3. Verify binary output + +For more platform-specific details, see: +- [Build System](HAL.md) +- [Troubleshooting](firmware_update.md) diff --git a/docs/encrypted_partitions.md b/docs/encrypted_partitions.md index 54d08df2..ceb62b71 100644 --- a/docs/encrypted_partitions.md +++ b/docs/encrypted_partitions.md @@ -1,192 +1,247 @@ -## Encrypted external partitions +# External Partition Encryption in wolfBoot -wolfBoot offers the possibility to encrypt the content of the entire UPDATE partition, -by using a pre-shared symmetric key which can be temporarily stored in a safer non-volatile memory area. +## Overview +wolfBoot provides encryption capabilities for external partitions to enhance firmware update security. This feature: +- Encrypts entire UPDATE partition content +- Uses pre-shared symmetric keys +- Protects SWAP partition during updates +- Integrates with existing signing process -SWAP partition is also temporarily encrypted using the same key, so a dump of the external flash won't reveal -any content of the firmware update packages. +## Key Features +- Transparent encryption layer +- Secure key storage options +- Multiple encryption algorithms +- Automated encryption/decryption +- Support for incremental updates -### Rationale - -Encryption of external partition works at the level of the external flash interface. - -All write calls to external partitions from the bootloader perform an additional encryption step -to hide the actual content of the external non-volatile memory. - -Vice-versa, all read operations will decrypt the data stored when the feature is enabled. - -An extra option is provided to the `sign` tool to encrypt the firmware update after signing it, so -that it can be stored as is in the external memory by the application, and will be decrypted by the bootloader -in order to verify the update and begin the installation. - - -### Temporary key storage - -By default, wolfBoot will store the pre-shared symmetric key used for encryption in a temporary area -on the internal flash. This allows read-out protections to be used to hide the temporary key. - -Alternatively, more secure mechanisms are available to store the temporary key in a different key storage -(e.g. using a hardware security module or a TPM device). - -The temporary key can be set at run time by the application, and will be used exactly once by the bootloader -to verify and install the next update. The key can be for example received from a back-end during the update -process using secure communication, and set by the application, using `libwolfboot` API, to be used by -wolfBoot upon next boot. - -Aside from setting the temporary key, the update mechanism remains the same for distributing, uploading and -installing firmware updates through wolfBoot. - -### Libwolfboot API - -The API to communicate with the bootloader from the application is expanded when this feature is enabled, -to allow setting a temporary key to process the next update. - -The functions +## Architecture +### Encryption Layer ``` -int wolfBoot_set_encrypt_key(const uint8_t *key, const uint8_t *nonce); +Application Layer + ↓ +Encryption Layer (ChaCha20/AES) + ↓ +External Flash Interface + ↓ +Physical Storage +``` + +### Operation Flow +1. **Write Operations**: + - Encrypt data before writing + - Store encrypted content in flash + - Hide actual firmware content + +2. **Read Operations**: + - Read encrypted data + - Decrypt automatically + - Return plaintext to bootloader + +3. **Update Process**: + - Sign firmware normally + - Encrypt signed package + - Store encrypted in external memory + - Decrypt during verification + + +## Key Management + +### Storage Options + +#### Default Storage +- Internal flash temporary storage +- Protected by read-out protection +- Single-use key mechanism +- Automatic key cleanup + +#### Advanced Storage +- Hardware Security Module (HSM) +- Trusted Platform Module (TPM) +- Custom secure storage implementation + +### Runtime Key Management + +#### Key Lifecycle +1. Key reception from backend +2. Secure storage setup +3. Single update usage +4. Automatic cleanup + +## API Reference + +### Encryption Control API +```c +// Set encryption key and nonce +int wolfBoot_set_encrypt_key( + const uint8_t *key, // Encryption key + const uint8_t *nonce // Initialization vector +); + +// Clear stored encryption key int wolfBoot_erase_encrypt_key(void); ``` -can be used to set a temporary encryption key for the external partition, or erase a key previously set, respectively. +### Usage Notes +- Keys are single-use only +- Application manages key reception +- Keys cleared after update +- No encryption in direct HAL access +- Supports pre-encrypted updates -Moreover, using `libwolfboot` to access the external flash with wolfboot hal from the application will not -use encryption. This way the received update, already encrypted at origin, can be stored in the external -memory unchanged, and retrieved in its encrypted format, e.g. to verify that the transfer has been successful before -reboot. +## Encryption Algorithms -### Symmetric encryption algorithm +### Supported Algorithms -The default algorithm used to encrypt and decrypt data in external partitions -is Chacha20-256. +| Algorithm | Key Size | IV/Nonce Size | Performance | Configuration | +|-----------|----------|---------------|-------------|---------------| +| ChaCha20-256 (default) | 32 bytes | 12 bytes | Fast | `ENCRYPT_WITH_CHACHA=1` | +| AES-128 CTR | 16 bytes | 16 bytes | Good | `ENCRYPT_WITH_AES128=1` | +| AES-256 CTR | 32 bytes | 16 bytes | Good | `ENCRYPT_WITH_AES256=1` | - - The `key` provided to `wolfBoot_set_encrypt_key()` must be exactly 32 Bytes long. - - The `nonce` argument must be a 96-bit (12 Bytes) randomly generated buffer, to be used as IV for encryption and decryption. +### Configuration Options -AES-128 and AES-256 are also supported. AES is used in counter mode. AES-128 and AES-256 have a key length of 16 and 32 bytes -respectively, and the IV size is 16 bytes long in both cases. +```bash +# Enable encryption support +make ENCRYPT=1 -## Example usage - -To compile wolfBoot with encryption support, use the option `ENCRYPT=1`. - -By default, this also selects `ENCRYPT_WITH_CHACHA=1`. To use AES encryption instead, -select `ENCRYPT_WITH_AES128=1` or `ENCRYPT_WITH_AES256=1`. - - -### Signing and encrypting the update bundle with ChaCha20-256 - -The `sign` tool can sign and encrypt the image with a single command. -In case of chacha20, the encryption secret is provided in a binary file that should contain a concatenation of -a 32B ChaCha-256 key and a 12B nonce. - -In the examples provided, the test application uses the following parameters: - -``` -key = "0123456789abcdef0123456789abcdef" -nonce = "0123456789ab" +# Select specific algorithm +make ENCRYPT=1 ENCRYPT_WITH_CHACHA=1 # Default +make ENCRYPT=1 ENCRYPT_WITH_AES128=1 # AES-128 +make ENCRYPT=1 ENCRYPT_WITH_AES256=1 # AES-256 ``` -So it is easy to prepare the encryption secret in the test scripts or from the command line using: +### Algorithm Details -``` +#### ChaCha20-256 +- Default algorithm +- 32-byte key requirement +- 12-byte random nonce +- Optimized for software implementation + +#### AES Counter Mode +- AES-128 and AES-256 support +- 16/32-byte keys respectively +- 16-byte IV requirement +- Hardware acceleration where available + + +## Implementation Examples + +### ChaCha20-256 Example + +#### 1. Prepare Encryption Key +```bash +# Create key file (32B key + 12B nonce) +# Example key: "0123456789abcdef0123456789abcdef" +# Example nonce: "0123456789ab" echo -n "0123456789abcdef0123456789abcdef0123456789ab" > enc_key.der ``` -The `sign` tool can now be invoked to produce a signed+encrypted image, by using the extra argument `--encrypt` followed by the -secret file: - -``` -./tools/keytools/sign --encrypt enc_key.der test-app/image.bin wolfboot_signing_private_key.der 24 - +#### 2. Sign and Encrypt +```bash +# Generate encrypted firmware +./tools/keytools/sign \ + --encrypt enc_key.der \ + test-app/image.bin \ + wolfboot_signing_private_key.der \ + 24 ``` -which will produce as output the file `test-app/image_v24_signed_and_encrypted.bin`, that can be transferred to the target's external device. +Output: `test-app/image_v24_signed_and_encrypted.bin` -### Signing and encrypting the update bundle with AES-256 +### AES-256 Example -In case of AES-256, the encryption secret is provided in a binary file that should contain a concatenation of -a 32B key and a 16B IV. - -In the examples provided, the test application uses the following parameters: - -``` -key = "0123456789abcdef0123456789abcdef" -iv = "0123456789abcdef" -``` - -So it is easy to prepare the encryption secret in the test scripts or from the command line using: - -``` +#### 1. Prepare Encryption Key +```bash +# Create key file (32B key + 16B IV) +# Example key: "0123456789abcdef0123456789abcdef" +# Example IV: "0123456789abcdef" echo -n "0123456789abcdef0123456789abcdef0123456789abcdef" > enc_key.der ``` -The `sign` tool can now be invoked to produce a signed+encrypted image, by using the extra argument `--encrypt` followed by the -secret file. To select AES-256, use the `--aes256` option. - -``` -./tools/keytools/sign --aes256 --encrypt enc_key.der test-app/image.bin wolfboot_signing_private_key.der 24 - +#### 2. Sign and Encrypt +```bash +# Generate encrypted firmware +./tools/keytools/sign \ + --aes256 \ + --encrypt enc_key.der \ + test-app/image.bin \ + wolfboot_signing_private_key.der \ + 24 ``` -which will produce as output the file `test-app/image_v24_signed_and_encrypted.bin`, that can be transferred to the target's external device. +Output: `test-app/image_v24_signed_and_encrypted.bin` -### Encryption of incremental (delta) updates +## Special Update Cases -When used in combination with delta updates, encryption works the same way as in full-update mode. The final delta image is encrypted with the selected algorithm. +### Delta Updates +- Compatible with encryption +- Same workflow as full updates +- Delta image encrypted after generation +- No special configuration needed +### Self-Updates -### Encryption of self-updates - -When used in combination with bootloader 'self' updates, the encryption algorithm must be configured to run from RAM. - -This is done by changing the linker script for the target. At the moment the feature has been successfully tested -with the ChaCha algorithm. - -The `.text` and `.rodata` segments in FLASH must be updated to not include symbols to be loaded in memory, so the following lines in the .text section: - -``` - *(.text*) - *(.rodata*) +#### RAM Configuration +Encryption algorithm must run from RAM for self-updates: +1. **Linker Script Modifications** +```ld +/* Flash Section */ +.text : { + *(EXCLUDE_FILE(*chacha.o).text*) + *(EXCLUDE_FILE(*chacha.o).rodata*) +} +/* RAM Section */ +.data : { + KEEP(*(.ramcode)) + /* ChaCha20 RAM symbols */ + KEEP(*(.text.wc_Chacha*)) + KEEP(*(.text.rotlFixed*)) + KEEP(*(.rodata.sigma)) + KEEP(*(.rodata.tau)) +} ``` - -Must be replaced with: - -``` - *(EXCLUDE_FILE(*chacha.o).text*) - *(EXCLUDE_FILE(*chacha.o).rodata*) +2. **Build Configuration** +```bash +# Use RAM-optimized linker script +make TARGET=stm32l0 ENCRYPT=1 ``` +#### Platform Support +- Tested on STM32L0 +- Uses `hal/$(TARGET)_chacha_ram.ld` +- ChaCha20 recommended -Similarly, the .data section loaded in RAM should contain all the .text and .rodata also coming -from the symbols of the encryption algorithm. The .data section should have the following added, -after `KEEP(*(.ramcode))`: +## Application Integration -``` - KEEP(*(.text.wc_Chacha*)) - KEEP(*(.text.rotlFixed*)) - KEEP(*(.rodata.sigma)) - KEEP(*(.rodata.tau)) +### Update Process +1. **Store Encrypted Update** +```c +// Store encrypted firmware directly +ext_flash_write(address, encrypted_data, size); ``` -The combination of encryption + self update has been successfully tested on STM32L0. -When using makefile based build, a different linker script `hal/$(TARGET)_chacha_ram.ld` is used -as template. The file `hal/stm32l0_chacha_ram.ld` contains the changes described above to place -all the needed symbols in RAM. +2. **Trigger Update** +```c +// Set encryption key before update +wolfBoot_set_encrypt_key(key, nonce); +// Trigger update +wolfBoot_update_trigger(); +``` -### API usage in the application +### Example Implementation +See [STM32WB Example](../test-app/app_stm32wb.c) for complete implementation. -When transferring the image, the application can still use the libwolfboot API functions to store the encrypted firmware. When called from the application, -the function `ext_flash_write` will store the payload unencrypted. - -In order to trigger an update, before calling `wolfBoot_update_trigger` it is necessary to set the temporary key used by the bootloader by calling `wolfBoot_set_encrypt_key`. - -An example of encrypted update trigger can be found in the [stm32wb test application source code](../test-app/app_stm32wb.c). +## Related Documentation +- [Firmware Updates](firmware_update.md) +- [HAL Interface](HAL.md) +- [API Reference](API.md) diff --git a/docs/firmware_image.md b/docs/firmware_image.md index 4cceaa9a..53f5559f 100644 --- a/docs/firmware_image.md +++ b/docs/firmware_image.md @@ -1,115 +1,218 @@ -# Firmware image +# Firmware Image Format -## Firmware entry point +## Overview +This document describes the wolfBoot firmware image format, including: +- Image header structure +- Entry point requirements +- Partition management +- Signing and verification -WolfBoot can only chain-load and execute firmware images from a specific entry point in memory, -which must be specified as the origin of the FLASH memory in the linker script of the embedded -application. This corresponds to the first partition in the flash memory. +## Memory Layout -Multiple firmware images can be created this way, and stored in two different partitions. The bootloader -will take care of moving the selected firmware to the first (BOOT) partition before chain-loading the image. +### Entry Point Requirements +- Fixed memory location required +- Specified in linker script +- Must match FLASH origin +- Located in first partition -Due to the presence of an image header, the entry point of the application has a fixed additional offset -of 256B from the beginning of the flash partition. +### Partition Structure +``` +Flash Memory ++------------------------+ <- Partition Start +| Image Header | 256B aligned ++------------------------+ <- Entry Point +| Firmware Image | +| | ++------------------------+ +``` -## Firmware image header +### Key Characteristics +- 256B header offset +- Multiple partition support +- Automatic image relocation +- Chain-load execution model -Each (signed) firmware image is prepended with a fixed-size **image header**, containing useful information about the -firmware. The exact size of the **image header** depends on the size of the image digest and signature, which depend on -the algorithms/key sizes used. Larger key sizes will result in a larger image header. The size of the image header is -determined by the build system and provided to the application code in the `IMAGE_HEADER_SIZE` macro. The size of the generated -image header is also output by the keytools during the signing operation. The **image header** data is padded out to the next -multiple of 256B, in order to guarantee that the entry point of the actual firmware is stored on the flash starting from a -256-Bytes aligned address. This ensures that the bootloader can relocate the vector table before chain-loading the firmware -so interrupts continue to work properly after the boot is complete. When porting wolfBoot to a platform that doesn't use wolfBoot's -Makefile-based build system, extra care should be taken to ensure `IMAGE_HEADER_SIZE` is set to a value that matches the output of -the wolfBoot `sign` key tool. +## Image Header -![Image header](png/image_header.png) +### Structure Overview +The image header contains metadata and security information for the firmware: -*The image header is stored at the beginning of the slot and the actual firmware image starts `IMAGE_HEADER_SIZE` Bytes after it* +``` ++------------------------+ <- Header Start +| Magic Number | 4 bytes +| Image Size | 4 bytes +| Tags Section | Variable size +| Padding | To 256B alignment ++------------------------+ <- IMAGE_HEADER_SIZE +| Firmware Start | +``` -### Image header: Tags +### Header Characteristics +- Variable total size based on: + - Digest algorithm + - Signature size + - Key length +- 256-byte alignment enforced +- Size defined by `IMAGE_HEADER_SIZE` +- Supports vector table relocation -The **image header** is prepended with a single 4-byte magic number, followed by a 4-byte field indicating the -firmware image size (excluding the header). All numbers in the header are stored in Little-endian format. +### Implementation Notes +- Size determined at build time +- Reported by signing tools +- Critical for interrupt handling +- Must match across toolchain -The two fixed fields are followed by one or more tags. Each TAG is structured as follows: +**Important**: When porting to custom build systems, ensure `IMAGE_HEADER_SIZE` matches the `sign` tool output. - - 2 bytes indicating the **Type** - - 2 bytes indicating the **size** of the tag, excluding the type and size bytes - - ***N*** bytes of tag content +### Tag System -With the following exception: - - A '0xFF' in the Type field indicate a simple padding byte. The 'padding' byte has no **size** field, and the next byte should be processed as **Type** again. +#### Base Format +All values stored in little-endian format. -Each **Type** has a different meaning, and integrate information about the firmware. The following Tags are mandatory for validating the firmware image: +##### Fixed Fields +| Field | Size | Description | +|-------|------|-------------| +| Magic Number | 4 bytes | Header identifier | +| Image Size | 4 bytes | Firmware size (excluding header) | - - A 'version' Tag (type: 0x0001, size: 4 Bytes) indicating the version number for the firmware stored in the image - - A 'timestamp' Tag (type: 0x0002, size 8 Bytes) indicating the timestamp in unix seconds for the creation of the firmware - - A 'sha digest' Tag (type: 0x0003, size: digest size (32 Bytes for SHA256)) used for integrity check of the firmware - - A 'firmware signature' Tag (type: 0x0020, size: 64 Bytes) used to validate the signature stored with the firmware against a known public key - - A 'firmware type' Tag (type: 0x0030, size: 2 Bytes) used to identify the type of firmware, and the authentication mechanism in use. +##### Tag Structure +```c +struct tag { + uint16_t type; // Tag identifier + uint16_t size; // Content size + uint8_t data[]; // Variable length content +}; +``` -A 'public key hint digest' tag is transmitted in the header (type: 0x10, size:32 Bytes). This tag contains the SHA digest of the public key used -by the signing tool. The bootloader may use this field to locate the correct public key in case of multiple keys available. +#### Mandatory Tags + +| Type | Name | Size | Description | +|------|------|------|-------------| +| 0x0001 | Version | 4B | Firmware version number | +| 0x0002 | Timestamp | 8B | Creation time (Unix seconds) | +| 0x0003 | SHA Digest | 32B* | Integrity check (SHA256) | +| 0x0020 | Signature | 64B | Firmware authentication | +| 0x0030 | Type | 2B | Firmware type & auth method | +| 0x0010 | Key Hint | 32B | Public key SHA digest | + +\* Size varies with hash algorithm + +#### Special Cases +- Type field = 0xFF: Padding byte + - No size field + - Next byte is new Type + - Used for alignment + +#### Key Management +- Key hint enables multi-key support +- Bootloader uses hint for key selection +- Required for signature verification wolfBoot will, in all cases, refuse to boot an image that cannot be verified and authenticated using the built-in digital signature authentication mechanism. -### Adding custom fields to the manifest header +## Custom Fields Support -It is possible to add custom fields to the manifest header, by using the `--custom-tlv` option in the signing tool. +### Overview +wolfBoot supports extending the manifest header with custom fields: +- Secured by signature verification +- Flexible field types +- Runtime accessible +- Little-endian format -In order for the fields to be secured (checked by wolfBoot for integrity and authenticity), -their value is placed in the manifest header before the signature is calculated. The signing tool takes care of the alignment and padding of the fields. - -The custom fields are identified by a 16-bit tag, and their size is indicated by a 16-bit length field. The tag and length fields are stored in little-endian format. - -At runtime, the values stored in the manifest header can be accessed using the `wolfBoot_find_header` function. - -The syntax for `--custom-tlv` option is also documented in [docs/Signing.md](/docs/Signing.md#adding-custom-fields-to-the-manifest-header). - -### Image header: Example - -This example adds a custom field when the signing tool is used to sign the firmware image: +### Adding Custom Fields +#### Command Line Usage ```bash -./tools/keytools/sign --ed25519 --custom-tlv 0x34 4 0xAABBCCDD test-app/image.bin wolfboot_signing_private_key.der 4 +# Add custom TLV field +./tools/keytools/sign \ + --ed25519 \ + --custom-tlv 0x34 4 0xAABBCCDD \ + test-app/image.bin \ + wolfboot_signing_private_key.der \ + 4 ``` -The output image `test-app/image_v4_signed.bin` will contain the custom field with tag `0x34` with length `4` and value `0xAABBCCDD`. - -From the bootloader code, we can then retrieve the value of the custom field using the `wolfBoot_find_header` function: - +#### Field Structure ```c +struct custom_field { + uint16_t tag; // Custom identifier + uint16_t length; // Field size + uint8_t value[]; // Field content +}; +``` + +### Runtime Access + +#### API Usage +```c +// Access custom field uint32_t value; uint8_t* ptr = NULL; uint16_t tlv = 0x34; -uint8_t* imageHdr = (uint8_t*)WOLFBOOT_PARTITION_BOOT_ADDRESS + IMAGE_HEADER_OFFSET; +uint8_t* imageHdr = (uint8_t*)WOLFBOOT_PARTITION_BOOT_ADDRESS + + IMAGE_HEADER_OFFSET; + +// Find and read field uint16_t size = wolfBoot_find_header(imageHdr, tlv, &ptr); if (size > 0 && ptr != NULL) { - /* Found field and ptr points to value 0xAABBCCDD */ - memcpy(&value, ptr, size); - printf("TLV 0x%x=0x%x\n", tlv, value); + // Field found - read value + memcpy(&value, ptr, size); + printf("TLV 0x%x=0x%x\n", tlv, value); } else { - /* Error: the field is not found */ + // Field not found + handle_error(); } ``` -### Image signing tool +#### Security Notes +- Fields included in signature +- Protected against tampering +- Alignment handled automatically -The image signing tool generates the header with all the required Tags for the compiled image, and add them to the output file that can be then -stored on the primary slot on the device, or transmitted later to the device through a secure channel to initiate an update. +For detailed syntax, see [Signing Documentation](Signing.md#adding-custom-fields-to-the-manifest-header) -### Storing firmware image +## Image Management -Firmware images are stored with their full header at the beginning of any of the partitions on the system. -wolfBoot can only boot images from the BOOT partition, while keeping a second firmware image in the UPDATE partition. +### Signing Process -In order to boot a different image, wolfBoot will have to swap the content of the two images. +#### Tool Overview +The signing tool provides: +- Automatic header generation +- Required tag creation +- Signature calculation +- Output file creation -For more information on how firmware images are stored and managed within the two partitions, see [Flash partitions](flash_partitions.md) +#### Usage Flow +1. Compile firmware +2. Generate header +3. Sign image +4. Store or transmit + +### Storage Management + +#### Partition Layout +``` +Flash Memory ++------------------------+ +| BOOT Partition | +| [Header + Firmware A] | ++------------------------+ +| UPDATE Partition | +| [Header + Firmware B] | ++------------------------+ +``` + +#### Key Points +- Headers required in all partitions +- Boot only from BOOT partition +- Swap mechanism for updates +- Secure update process + +For detailed partition information, see: +- [Flash Partitions](flash_partitions.md) +- [Firmware Updates](firmware_update.md) +- [Security Features](Signing.md) diff --git a/docs/firmware_update.md b/docs/firmware_update.md index 4b546169..b8889270 100644 --- a/docs/firmware_update.md +++ b/docs/firmware_update.md @@ -1,174 +1,242 @@ -# Firmware update +# Firmware Update Guide -This section documents the complete firmware update procedure, enabling secure boot -for an existing embedded application. +## Overview +This guide details wolfBoot's secure firmware update process, including: +- Update procedures +- Security mechanisms +- Rollback protection +- Integration steps +## Update Process -## Updating Microcontroller FLASH +### High-Level Flow +``` +1. Prepare Update ─────► 2. Transfer & Store ─────► 3. Trigger Update ─────► 4. Verify & Install + - Compile - Secure transfer - Mark for update - Validate signature + - Sign - Store in UPDATE - Schedule swap - Perform swap + - Package partition - Reboot - Boot new firmware +``` -The steps to complete a firmware update with wolfBoot are: - - Compile the firmware with the correct entry point - - Sign the firmware - - Transfer the image using a secure connection, and store it to the secondary firmware slot - - Trigger the image swap - - Reboot to let the bootloader begin the image swap - -At any given time, an application or OS running on a wolfBoot system can receive an updated version of itself, -and store the updated image in the second partition in the FLASH memory. +### Key Components +- [libwolfboot](API.md) for update management +- [HAL](HAL.md) for flash operations +- Secure boot chain +- Rollback protection ![Update and Rollback](png/wolfboot_update_rollback.png) -Applications or OS threads can be linked to the [libwolfboot library](API.md), which exports the API to trigger -the update at the next reboot, and some helper functions to access the flash partition for -erase/write through the target specific [HAL](HAL.md). +## Update Implementation -## Update procedure description +### Update Sequence -Using the [API](API.md) provided to the application, wolfBoot offers the possibility to initiate, confirm or -rollback an update. +#### 1. Initiation +```c +// Store new firmware in UPDATE partition +// Then trigger update +wolfBoot_update_trigger(); +``` -After storing the new firmware image in the UPDATE partition, the application should initiate the update by calling -`wolfBoot_update_trigger()`. By doing so, the UPDATE partition is marked for update. Upon the next reboot, wolfBoot will: - - Validate the new firmware image stored in the UPDATE partition - - Verify the signature attached against a known public key stored in the bootloader image - - Swap the content of the BOOT and the UPDATE partitions - - Mark the new firmware in the BOOT partition as in state `STATE_TESTING` - - Boot into the newly received firmware +#### 2. Bootloader Actions +On next reboot, wolfBoot: +1. Validates UPDATE partition +2. Verifies digital signature +3. Performs partition swap +4. Sets `STATE_TESTING` +5. Boots new firmware -If the system is interrupted during the swap operation and reboots, -wolfBoot will pick up where it left off and continue the update -procedure. +#### 3. Recovery Mechanism +- Automatic resume on interruption +- Maintains system integrity +- Preserves update state -### Successful boot +### Update Confirmation -Upon a successful boot, the application should inform the bootloader by calling `wolfBoot_success()`, after verifying that -the system is up and running again. This operation confirms the update to a new firmware. +#### Success Path +```c +// After system verification +wolfBoot_success(); // Confirm update +``` -Failing to set the BOOT partition to `STATE_SUCCESS` before the next reboot triggers a roll-back operation. -Roll-back is initiated by the bootloader by triggering a new update, this time starting from the backup copy of the original -(pre-update) firmware, which is now stored in the UPDATE partition due to the swap occurring earlier. +#### Rollback Triggers +- Missing `wolfBoot_success()` call +- Reboot before confirmation +- System validation failure -### Building a new firmware image +#### Rollback Process +1. Detects unconfirmed state +2. Initiates reverse update +3. Restores original firmware +4. Maintains system availability -Firmware images are position-dependent, and can only boot from the origin of the **BOOT** partition in FLASH. -This design constraint implies that the chosen firmware is always stored in the **BOOT** partition, and wolfBoot -is responsible for pre-validating an update image and copy it to the correct address. +## Firmware Build Process -All the firmware images must therefore have their entry point set to the address corresponding to the beginning -of the **BOOT** partition, plus an offset of 256 Bytes to account for the image header. +### Image Requirements -Once the firmware is compiled and linked, it must be signed using the `sign` tool. The tool produces -a signed image that can be transferred to the target using a secure connection, using the same key corresponding -to the public key currently used for verification. +#### Position Dependencies +``` +Flash Layout ++------------------------+ <- 0x00000000 +| wolfBoot | ++------------------------+ <- BOOT_PARTITION +| Header (256B) | Entry Point = BOOT_PARTITION + 256 +| Firmware | ++------------------------+ +``` -The tool also adds all the required Tags to the image header, containing the signatures and the SHA256 hash of -the firmware. +#### Build Steps +1. Configure entry point + - Must match BOOT partition + - Account for header offset -### Self-update +2. Compile and link + ```bash + # Example linker configuration + ENTRY_POINT = BOOT_PARTITION + 256 + ``` -wolfBoot can update itself if `RAM_CODE` is set. This procedure -operates almost the same as firmware update with a few key -differences. The header of the update is marked as a bootloader -update (use `--wolfboot-update` for the sign tools). +3. Sign image + ```bash + ./tools/keytools/sign \ + --ed25519 \ + firmware.bin \ + private_key.der \ + version + ``` -The new signed wolfBoot image is loaded into the UPDATE partition and -triggered the same as a firmware update. Instead of performing a swap, -after the image is validated and signature verified, the bootloader is -erased and the new image is written to flash. This operation is _not_ -safe from interruption. Interruption will prevent the device from -rebooting. +### Self-Update Support + +#### Configuration +```bash +# Enable self-update support +make RAM_CODE=1 +``` + +#### Key Differences +| Feature | Normal Update | Self-Update | +|---------|---------------|-------------| +| Storage | Swap-based | Direct write | +| Safety | Interrupt-safe | Not interrupt-safe | +| Header | Standard | `--wolfboot-update` | +| Process | Two-stage | Single-stage | + +#### Usage +```bash +# Sign bootloader update +./tools/keytools/sign \ + --ed25519 \ + --wolfboot-update \ + new_bootloader.bin \ + private_key.der \ + version +``` + +**Warning**: Do not interrupt self-update process wolfBoot can be used to deploy new bootloader versions as well as update keys. -### Incremental updates (aka: 'delta' updates) +## Delta Updates -wolfBoot supports incremental updates, based on a specific older version. The sign tool -can create a small "patch" that only contains the binary difference between the version -currently running on the target and the update package. This reduces the size of the image -to be transferred to the target, while keeping the same level of security through public key -verification, and integrity due to the repeated check (on the patch and the resulting image). +### Overview +wolfBoot supports bandwidth-efficient incremental updates through binary differencing: +- Minimizes update package size +- Maintains security standards +- Supports bidirectional patching +- Uses Bentley/McIlroy algorithm -The format of the patch is based on the mechanism suggested by Bentley/McIlroy, which is particularly effective -to generate small binary patches. This is useful to minimize time and resources needed to transfer, -authenticate and install updates. +### Architecture +#### Delta Generation +``` +Base Firmware (v1) ──┐ + ├─► Delta Package ──► Target Device +New Firmware (v2) ───┘ +``` -#### How it works - -As an alternative to transferring the entire firmware image, the key tools create -a binary diff between a base version previously uploaded and the new updated image. - -The resulting bundle (delta update) contains the information to derive the content -of version '2' of the firmware, starting from the base version, that is currently -running on the target (version '1' in this example), and the reverse patch to downgrade -version '2' back to version '1' if something goes wrong running the new version. +#### Package Contents +1. Forward patch (v1 → v2) +2. Reverse patch (v2 → v1) +3. Authentication data +4. Version information ![Delta update](png/delta_updates.png) -On the device side, wolfboot will recognize and verify the authenticity of the delta update before -applying the patch to the current firmware. The new firmware is rebuilt in place, -replacing the content of the BOOT partition according to the indication in the -(authenticated) 'delta update' bundle. +### Security Features + +#### Dual Verification +1. Package Authentication + - Signed delta bundle + - Version verification + - Integrity checking + +2. Result Validation + - Patch application verification + - Final image authentication + - Signature verification -#### Two-steps verification +### Implementation Details -Binary patches are created by comparing signed firmware images. wolfBoot verifies -that the patch is applied correctly by checking for the integrity and the authenticity -of the resulting image after the patch. +#### Update Process Flow +``` +1. Delta Bundle ──► 2. Authentication ──► 3. Patch Application ──► 4. Result Verification + Reception Bundle Signature Forward/Reverse Final Image Check +``` -The delta update bundle itself, containing the patches, is prefixed with a manifest -header describing the details for the patch, and signed like a normal full update bundle. - -This means that wolfBoot will apply two levels of authentication: the first one -when the delta bundle is processed (e.g. when an update is triggered), and the second -one every time a patch is applied, or reversed, to validate the firmware image -before booting. - -These steps are performed automatically by the key tools when using the `--delta` -option, as described in the example. - - -#### Confirming the update - -From the application perspective, nothing changes from the normal, 'full' update case. -Application must still call `wolfBoot_success()` on the first boot with the updated version -to ensure that the update is confirmed. - -Failing to confirm the success of the update will cause wolfBoot to revert the patch -applied during the update. The 'delta update' bundle also contains a reverse patch, -which can revert the update and restore the base version of the firmware. - -The diagram below shows the authentication steps and the diff/patch process in both -directions (update and roll-back for missed confirmation). +#### Update Confirmation +- Uses standard `wolfBoot_success()` +- Same API as full updates +- Automatic rollback support ![Delta update: details](png/delta_updates_2.png) +### Usage Guide -#### Incremental update: example +#### Prerequisites +```bash +# Enable delta updates +make DELTA_UPDATES=1 +``` -Requirement: wolfBoot is compiled with `DELTA_UPDATES=1` +#### Creating Updates -Version "1" is signed as usual, as a standalone image: +1. Sign base version: +```bash +# Sign version 1 +./tools/keytools/sign \ + --ecc256 \ + --sha256 \ + test-app/image.bin \ + wolfboot_signing_private_key.der \ + 1 +``` -`tools/keytools/sign --ecc256 --sha256 test-app/image.bin wolfboot_signing_private_key.der 1` +2. Create delta update: +```bash +# Generate delta v1->v2 +./tools/keytools/sign \ + --delta test-app/image_v1_signed.bin \ + --ecc256 \ + --sha256 \ + test-app/image.bin \ + wolfboot_signing_private_key.der \ + 2 +``` -When updating from version 1 to version 2, you can invoke the sign tool as: +#### Output Files +| File | Description | +|------|-------------| +| `image_v2_signed.bin` | Complete v2 image | +| `image_v2_signed_diff.bin` | Delta package | -`tools/keytools/sign --delta test-app/image_v1_signed.bin --ecc256 --sha256 test-app/image.bin wolfboot_signing_private_key.der 2` +#### Update Flow +1. Transfer delta package +2. Store in UPDATE partition +3. Trigger update +4. Automatic patch application +5. Boot new version +6. Confirm or rollback -Besides the usual output file `image_v2_signed.bin`, the sign tool creates an additional `image_v2_signed_diff.bin` -which should be noticeably smaller in size as long as the two binary files contain overlapping areas. - -This is the delta update bundle, a signed package containing the patches for updating version 1 to version 2, and to roll back to version 1 if needed, after the first patch has been applied. - -The delta bundle `image_v2_signed_diff.bin` can be now transferred to the update partition on the target like a full update image. - -At next reboot, wolfBoot recognizes the incremental update, checks the integrity, the authenticity and the versions -of the patch. If all checks succeed, the new version is installed by applying the patch on the current firmware image. - -If the update is not confirmed, at the next reboot wolfBoot will restore the original base `image_v1_signed.bin`, using -the reverse patch contained in the delta update bundle. +**Note**: Failed confirmation triggers automatic rollback using reverse patch diff --git a/docs/flash-OTP.md b/docs/flash-OTP.md index 4b2bcca2..19b9f25a 100644 --- a/docs/flash-OTP.md +++ b/docs/flash-OTP.md @@ -1,66 +1,102 @@ -# Using One-Time Programmable (OTP) flash area for keystore +# OTP Flash Keystore Guide -Some microcontrollers provide a special area in flash memory that can -only be written once and cannot be erased. +## Overview +This guide explains how to use One-Time Programmable (OTP) flash memory for secure key storage in wolfBoot. -This feature comes particularly handy when you want to store the public keys required -to authenticate the firmware update images, which has exactly the same requirements. A public -key is a cryptographic key that can be freely distributed and is used to verify the signature -of the firmware update image. By storing the public keys in the OTP area, you can ensure that -they are immutable and cannot be tampered with. +### Key Features +- Immutable key storage +- Tamper-resistant security +- Runtime key access +- Multiple key support +- Header-based organization -## Compiling wolfBoot to access OTP as keystore +## Architecture -To use the OTP area as a keystore, you need to compile wolfBoot with the `FLASH_OTP_KEYSTORE` -option enabled. This option is disabled by default, which means that the keystore is incorporated into -the wolfBoot binary itself. +### Memory Layout +``` +OTP Area ++------------------------+ <- OTP Start +| 16-byte Header | - Key count +| | - Key sizes +| | - Metadata ++------------------------+ +| Public Keys | +| | +| | ++------------------------+ +``` -When wolfBoot uses the OTP area as a keystore, it reads the public keys from the OTP area at runtime. -The public keys are stored in the OTP area, after an initial 16-byte header that contains the number of -keys stored, the size of each key, and other information. +### Configuration -In order for wolfBoot to start authenticating the firmware images at boot and upon update, the public keys -must be provisioned to the OTP area in a separate step, as described in the next sections. +#### Build Options +```bash +# Enable OTP keystore +make FLASH_OTP_KEYSTORE=1 +``` + +#### Default Behavior +- OTP support disabled by default +- Keys embedded in wolfBoot binary +- Runtime key access when enabled +- Separate provisioning required Depending on the target device, you can either prepare a binary image of the OTP area content, or use `otp-keystore-primer` firmware to directly provision the keys on the target. -## Creating an image of the OTP area content +## Provisioning Methods -It is possible to create a binary image of the content for the OTP area. The resulting file (otp.bin) can be manually provisioned using any external tool that allows writing to the target OTP area. +### Method 1: Binary Image Generation -To compile the otp-keystore-gen tool using the current keystore content: - -```sh +#### Tool Usage +```bash +# Build OTP generator make otpgen -``` -And then, to create the image file `otp.bin`: - - -```sh +# Create OTP binary ./tools/keytools/otp/otp-keystore-gen ``` +#### Deployment +- Output: `otp.bin` +- Manual flashing required +- Use external programming tools +- Target-specific flash process -## Directly provisioning the public keys to the OTP area (primer) +### Method 2: Direct Provisioning -After enabling the `FLASH_OTP_KEYSTORE` option in your `.config` file, when you compile wolfBoot by running "make", -an additional application called `otp-keystore-primer` is generated under `tools/keytools/otp`. This application is used to -provision the public keys to the OTP area. By flashing this application to the microcontroller, the public keys contained -in your keystore (previously generated by `keygen`) are written to the OTP area. +#### Primer Application +```bash +# Build primer tool +make FLASH_OTP_KEYSTORE=1 +make otp -The `otp-keystore-primer` application is generated with the public keys embedded in it. The keys are retrieved from the `keystore.c` file, -generated by the `keygen` command. The `otp-keystore-primer` application reads the public keys from the `keystore.c` file and writes them to the OTP area. +# Result: tools/keytools/otp/otp-keystore-primer +``` -After generating a new `keystore.c` with the `keygen` application, you can generate the `otp-keystore-primer` application again, by running `make otp`. +#### Operation Flow +1. Generate keys (`keygen`) +2. Build primer +3. Flash primer +4. Auto-provision on boot -> [!WARNING] -> The `otp-keystore-primer` application is a one-time use application. Once the application runs on your target, the public keys are written to the OTP area, -> and it will be impossible to erase them. Therefore, it is important to ensure that the public keys are correct before provisioning them to the OTP area, -> and that the associated private keys are stored securely. Accidentally losing the private keys will render the public keys stored in the OTP area useless. +#### Key Source +- Keys from `keystore.c` +- Generated by `keygen` +- Embedded in primer +- Written to OTP on execution -> [!CAUTION] -> ** Be very careful when using the `otp-keystore-primer` application. Use it at your own risk. ** +⚠️ **Critical Warnings** + +1. **One-Time Operation** + - No undo capability + - Permanent key storage + - Verify before flashing + - Backup private keys + +2. **Security Implications** + - Keys cannot be changed + - Private key loss = unusable system + - Verify key correctness + - Secure key backup required ## Examples diff --git a/docs/flash_partitions.md b/docs/flash_partitions.md index 4ea51067..021cda62 100644 --- a/docs/flash_partitions.md +++ b/docs/flash_partitions.md @@ -1,89 +1,155 @@ -# Flash partitions +# Flash Memory Partitioning Guide -## Flash memory partitions +## Overview +This guide explains how to properly partition flash memory for wolfBoot integration, considering: +- Flash geometry requirements +- Sector alignment rules +- Partition size constraints +- Memory layout organization -To integrate wolfBoot you need to partition the flash into -separate areas (partitions), taking into account the geometry of the flash memory. +## Key Requirements -Images boundaries **must** be aligned to physical sectors, because the -bootloader erases all the flash sectors before storing a new firmware image, and -swaps the content of the two partitions, one sector at a time. +### Sector Alignment +- Image boundaries must align with physical sectors +- Required for: + - Clean firmware updates + - Reliable sector erasure + - Safe partition swapping -For this reason, before proceeding with partitioning on a target system, the -following aspects must be considered: +### Partition Sizing Rules +| Partition | Size Requirement | Purpose | +|-----------|-----------------|----------| +| BOOT | = UPDATE size | Active firmware | +| UPDATE | = BOOT size | Update staging | +| SWAP | ≥ largest sector | Safe updates | - - BOOT partition and UPDATE partition must have the same size, and be able to contain the running system - - SWAP partition must be as big as the largest sector in both BOOT and UPDATE partition. +## Memory Layout -The flash memory of the target is partitioned into the following areas: - - - Bootloader partition, at the beginning of the flash, generally very small (16-32KB) - - Primary slot (BOOT partition) starting at address `WOLFBOOT_PARTITION_BOOT_ADDRESS` - - Secondary slot (UPDATE partition) starting at address `WOLFBOOT_PARTITION_UPDATE_ADDRESS` - - both partitions share the same size, defined as `WOLFBOOT_PARTITION_SIZE` - - Swapping space (SWAP partition) starting at address `WOLFBOOT_PARTITION_SWAP_ADDRESS` - - the swap space size is defined as `WOLFBOOT_SECTOR_SIZE` and must be as big as the - largest sector used in either BOOT/UPDATE partitions. - -A proper partitioning configuration must be set up for the specific use, by setting -the values for offsets and sizes in [include/target.h](../include/target.h). - -### Bootloader partition - -This partition is usually very small, and only contains the bootloader code and data. -Public keys pre-authorized during factory image creations are automatically stored -as part of the firmware image. - -### BOOT partition - -This is the only partition from where it is possible to chain-load and execute a -firmware image. The firmware image must be linked so that its entry-point is at address -`WOLFBOOT_PARTITION_BOOT_ADDRESS + 256`. - -### UPDATE partition - -The running firmware is responsible for transferring a new firmware image through a secure channel, -and store it in the secondary slot. If an update is initiated, the bootloader will replace or swap -the firmware in the boot partition at the next reboot. - - -## Partition status and sector flags - -Partitions are used to store firmware images currently in use (BOOT) or ready to swap in (UPDATE). -In order to track the status of the firmware in each partition, a 1-Byte state field is stored at the end of -each partition space. This byte is initialized when the partition is erased and accessed for the first time. - -Possible states are: - - `IMG_STATE_NEW` (0xFF): The image was never staged for boot, or triggered for an update. If an image is present, no flags are active. - - `IMG_STATE_UPDATING` (0x70): Only valid in the UPDATE partition. The image is marked for update and should replace the current image in BOOT. - - `IMG_STATE_TESTING` (0x10): Only valid in the BOOT partition. The image has been just updated, and never completed its boot. If present after reboot, it means that the updated image failed to boot, despite being correctly verified. This particular situation triggers a rollback. - - `IMG_STATE_SUCCESS` (0x00): Only valid in the BOOT partition. The image stored in BOOT has been successfully staged at least once, and the update is now complete. - -Starting from the State byte and growing backwards, the bootloader keeps track of the state of each sector, using 4-bits per sector at the end of the UPDATE partition. Whenever an update is initiated, the firmware is transferred from UPDATE to BOOT one sector at a time, and storing a backup of the original firmware from BOOT to UPDATE. Each flash access operation correspond to a different value of the flags for the sector in the sector flags area, so that if the operation is interrupted, it can be resumed upon reboot. - -End of flash layout: - * 4-bits flag (sector 1) - * 4-bits flag (sector 0) - * 1-byte partition state - * 4-byte trailer "BOOT" - -If the `FLAGS_HOME` build option is used then all flags are placed at the end of the boot partition: - - ``` - / -12 /-8 /-4 / END - |Sn| ... |S2|S1|S0|PU| MAGIC |X|X|X|PB| MAGIC | - ^--sectors --^ ^--update ^---boot partition - flags partition flag - flag +``` +Flash Memory Map ++------------------------+ <- 0x00000000 +| Bootloader (16-32KB) | ++------------------------+ <- WOLFBOOT_PARTITION_BOOT_ADDRESS +| BOOT Partition | +| (Primary Slot) | ++------------------------+ <- WOLFBOOT_PARTITION_UPDATE_ADDRESS +| UPDATE Partition | +| (Secondary Slot) | ++------------------------+ <- WOLFBOOT_PARTITION_SWAP_ADDRESS +| SWAP Space | ++------------------------+ ``` -You can use the `CUSTOM_PARTITION_TRAILER` option to implement your own functions for: `get_trailer_at`, `set_trailer_at` and `set_partition_magic`. +### Configuration Parameters +| Parameter | Description | +|-----------|-------------| +| `WOLFBOOT_PARTITION_BOOT_ADDRESS` | Start of BOOT partition | +| `WOLFBOOT_PARTITION_UPDATE_ADDRESS` | Start of UPDATE partition | +| `WOLFBOOT_PARTITION_SWAP_ADDRESS` | Start of SWAP space | +| `WOLFBOOT_PARTITION_SIZE` | Size of BOOT/UPDATE partitions | +| `WOLFBOOT_SECTOR_SIZE` | Size of SWAP space | -To enable: -1) Add the `CUSTOM_PARTITION_TRAILER` build option to your `.config`: `CFLAGS_EXTRA+=--DCUSTOM_PARTITION_TRAILER` -2) Add your own .c file using `OBJS_EXTRA`. For example for your own `src/custom_trailer.c` add this to your `.config`: `OBJS_EXTRA=src/custom_trailer.o`. +## Partition Details + +### Configuration +All partition parameters are defined in [include/target.h](../include/target.h). + +### Bootloader Partition +- Size: 16-32KB typical +- Location: Start of flash +- Contents: + - Bootloader code + - Runtime data + - Factory keys (embedded) + +### BOOT Partition (Primary) +- Purpose: Active firmware execution +- Requirements: + - Only bootable partition + - Entry point = `BOOT_ADDRESS + 256` + - Sector-aligned boundaries +- Status: Always contains verified image + +### UPDATE Partition (Secondary) +- Purpose: Update staging area +- Operation: + 1. Receives new firmware + 2. Verifies signature + 3. Swaps with BOOT on update +- Security: Uses secure channel for updates -## Overview of the content of the FLASH partitions +## State Management +### Partition States +Each partition maintains a 1-byte state field at its end: + +| State | Value | Valid In | Description | +|-------|-------|----------|-------------| +| `IMG_STATE_NEW` | 0xFF | Both | Fresh/unused image | +| `IMG_STATE_UPDATING` | 0x70 | UPDATE | Pending update | +| `IMG_STATE_TESTING` | 0x10 | BOOT | Update verification | +| `IMG_STATE_SUCCESS` | 0x00 | BOOT | Update confirmed | + +### Sector Tracking +- Location: End of partition +- Format: 4-bits per sector +- Direction: Grows backwards +- Purpose: Update progress tracking + +### Update Process +1. Transfer firmware sector-by-sector +2. Track each sector's state +3. Store backup in UPDATE +4. Resume on interruption + +### State Flow +``` +NEW ──► UPDATING ──► TESTING ──► SUCCESS + │ + └──► ROLLBACK (if boot fails) +``` + +## Partition Trailer Format + +### Standard Layout +``` +End of Partition ++------------------------+ <- END +| "BOOT" Magic (4B) | +| Partition State (1B) | +| Sector 0 Flags (4b) | +| Sector 1 Flags (4b) | ++------------------------+ +``` + +### FLAGS_HOME Option +Consolidates all flags at boot partition end: +``` + / -12 /-8 /-4 / END + |Sn| ... |S2|S1|S0|PU| MAGIC |X|X|X|PB| MAGIC | + ^--sectors --^ ^--update ^---boot + flags state state +``` + +### Custom Implementation +Enable custom trailer handling: + +```make +# .config setup +CFLAGS_EXTRA+=--DCUSTOM_PARTITION_TRAILER +OBJS_EXTRA=src/custom_trailer.o +``` + +#### Required Functions +- `get_trailer_at` +- `set_trailer_at` +- `set_partition_magic` + +## Visual Overview ![wolfBoot partition](png/wolfboot_partition.png) + +## Related Documentation +- [Firmware Updates](firmware_update.md) +- [Build Configuration](compile.md) +- [Target Configuration](Targets.md) diff --git a/docs/keystore.md b/docs/keystore.md index b21d447b..d4578580 100644 --- a/docs/keystore.md +++ b/docs/keystore.md @@ -1,223 +1,323 @@ -# KeyStore structure: support for multiple public keys +# wolfBoot KeyStore Guide -## What is wolfBoot KeyStore +## Overview +The KeyStore system provides secure storage and management of public keys used for firmware authentication in wolfBoot. -KeyStore is the mechanism used by wolfBoot to store all the public keys used for -authenticating the signature of current firmware and updates. +### Key Features +- Multiple key support +- Flexible storage options +- Runtime key access +- Permission management +- HSM integration -wolfBoot's key generation tool can be used to generate one or more keys. By default, -when running `make` for the first time, a single key `wolfboot_signing_private_key.der` -is created, and added to the keystore module. This key should be used to sign any firmware -running on the target, as well as firmware update binaries. +## Basic Operation -Additionally, the `keygen` tool creates additional files with different representations -of the keystore - - A .c file (src/keystore.c) which can be used to deploy public keys as part - of the bootloader itself, by linking the keystore in `wolfboot.elf` - - A .bin file (keystore.bin) which contains the keystore that can be hosted - on a custom memory support. In order to access the keystore, a small driver is - required (see section "Interface API" below). - -## Default usage (built-in keystore) - -By default, the keystore object in `src/keystore.c` is accessed by wolfboot by including -its symbols in the build. -Once generated, this file contains an array of structures describing each public -key that will be available to wolfBoot on the target system. Additionally, there are a few -functions that connect to the wolfBoot keystore API to access the details and the -content of the public key slots. - -The public key is described by the following structure: - -``` - struct keystore_slot { - uint32_t slot_id; - uint32_t key_type; - uint32_t part_id_mask; - uint32_t pubkey_size; - uint8_t pubkey[KEYSTORE_PUBKEY_SIZE]; - }; +### Default Setup +```bash +# First build generates default key +make +# Results in: +wolfboot_signing_private_key.der # Signing key +src/keystore.c # Embedded keystore +keystore.bin # Binary keystore ``` -- `slot_id` is the incremental identifier for the key slot, starting from 0. +### Storage Options +| Format | File | Purpose | +|--------|------|---------| +| Source | src/keystore.c | Embedded in bootloader | +| Binary | keystore.bin | External storage support | +| DER | *.der | Key distribution | -- `key_type` describes the algorithm of the key, e.g. `AUTH_KEY_ECC256` or `AUTH_KEY_RSA3072` +### Integration Methods +1. **Built-in Storage** + - Linked with wolfboot.elf + - Direct memory access + - Default approach -- `mask` describes the permissions for the key. It's a bitmap of the partition ids for which this key can be used for verification +2. **External Storage** + - Custom memory support + - Driver required + - Flexible deployment -- `pubkey_size` the size of the public key buffer +## Built-in KeyStore Implementation -- `pubkey` the actual buffer containing the public key in its raw format +### Data Structure +```c +struct keystore_slot { + uint32_t slot_id; // Sequential ID (0-based) + uint32_t key_type; // Algorithm identifier + uint32_t part_id_mask; // Permission bitmap + uint32_t pubkey_size; // Key buffer size + uint8_t pubkey[KEYSTORE_PUBKEY_SIZE]; // Key data +}; +``` + +### Field Descriptions + +| Field | Type | Description | Example | +|-------|------|-------------|---------| +| slot_id | uint32_t | Sequential identifier | 0, 1, 2... | +| key_type | uint32_t | Crypto algorithm | AUTH_KEY_ECC256 | +| part_id_mask | uint32_t | Access permissions | KEY_VERIFY_ALL | +| pubkey_size | uint32_t | Key length | 32, 64, etc. | +| pubkey | uint8_t[] | Raw key data | Binary buffer | + +### Memory Layout +``` +KeyStore Memory ++------------------------+ +| Slot 0 | +| - Metadata | +| - Key Data | ++------------------------+ +| Slot 1 | +| - Metadata | +| - Key Data | ++------------------------+ +| ... | +``` When booting, wolfBoot will automatically select the public key associated to the signed firmware image, check that it matches the permission mask for the partition id where the verification is running and then attempts to authenticate the signature of the image using the selected public key slot. -### Creating multiple keys +## Key Management -`keygen` accepts multiple filenames for private keys. +### Key Generation -Two arguments: - - - `-g priv.der` generate new keypair, store the private key in priv.der, add the public key to the keystore - - `-i pub.der` import an existing public key and add it to the keystore - -Example of creation of a keystore with two ED25519 keys: - -`./tools/keytools/keygen --ed25519 -g first.der -g second.der` - -will create the following files: - - - `first.der` first private key - - `second.der` second private key - - `src/keystore.c` C keystore containing both public keys associated with `first.der` - and `second.der`. - -The `keystore.c` generated should look similar to this: +#### Command Options +```bash +# Generate new keypair +keygen -g priv.der +# Import existing key +keygen -i pub.der ``` + +#### Multiple Key Example +```bash +# Create two ED25519 keys +./tools/keytools/keygen \ + --ed25519 \ + -g first.der \ + -g second.der +``` + +#### Output Files +| File | Description | +|------|-------------| +| first.der | Private key 1 | +| second.der | Private key 2 | +| src/keystore.c | Generated keystore | + +### KeyStore Source Example +```c #define NUM_PUBKEYS 2 const struct keystore_slot PubKeys[NUM_PUBKEYS] = { - - /* Key associated to private key 'first.der' */ + /* Slot 0: first.der */ { .slot_id = 0, .key_type = AUTH_KEY_ED25519, .part_id_mask = KEY_VERIFY_ALL, .pubkey_size = KEYSTORE_PUBKEY_SIZE_ED25519, .pubkey = { - 0x21, 0x7B, 0x8E, 0x64, 0x4A, 0xB7, 0xF2, 0x2F, - 0x22, 0x5E, 0x9A, 0xC9, 0x86, 0xDF, 0x42, 0x14, - 0xA0, 0x40, 0x2C, 0x52, 0x32, 0x2C, 0xF8, 0x9C, - 0x6E, 0xB8, 0xC8, 0x74, 0xFA, 0xA5, 0x24, 0x84 + 0x21, 0x7B, /* ... */ 0x24, 0x84 }, }, - - /* Key associated to private key 'second.der' */ + /* Slot 1: second.der */ { .slot_id = 1, .key_type = AUTH_KEY_ED25519, .part_id_mask = KEY_VERIFY_ALL, .pubkey_size = KEYSTORE_PUBKEY_SIZE_ED25519, .pubkey = { - 0x41, 0xC8, 0xB6, 0x6C, 0xB5, 0x4C, 0x8E, 0xA4, - 0xA7, 0x15, 0x40, 0x99, 0x8E, 0x6F, 0xD9, 0xCF, - 0x00, 0xD0, 0x86, 0xB0, 0x0F, 0xF4, 0xA8, 0xAB, - 0xA3, 0x35, 0x40, 0x26, 0xAB, 0xA0, 0x2A, 0xD5 + 0x41, 0xC8, /* ... */ 0x2A, 0xD5 }, - }, - - + } }; +## Access Control + +### Permission System + +#### Partition Mask +``` +Bit Layout (32-bit mask) +31 3 2 1 0 ++--------------------------------+-+-+-+ +| Reserved |3|2|1|0| ++--------------------------------+-+-+-+ + | | | | + | | | +-- wolfBoot self-update + | | +---- Main firmware + | +------ Custom partition 2 + +-------- Custom partition 3 ``` -### Permissions +#### Default Access +- Mask: `KEY_VERIFY_ALL` +- Allows: All partition access +- Usage: General purpose keys -By default, when a new keystore is created, the permissions mask is set -to `KEY_VERIFY_ALL`, which means that the key can be used to verify a firmware -targeting any partition id. - -The `part_id_mask` value is a bitmask, where each bit represent a different partition. -The bit '0' is reserved for wolfBoot self-update, while typically the main firmware partition -is associated to id 1, so it requires a key with the bit '1' set. In other words, signing a -partition with `--id 3` would require turning on bit '3' in the mask, i.e. adding (1U << 3) to it. - -To restrict the permissions for single keys, it would be sufficient to change the value -of each key `part_id_mask`. This is done via the `--id` command line option for keygen. -Each generated or imported key can be associated with a number of partition by passing the -partition IDs in a comma-separated list, e.g.: - -``` -keygen --ecc256 -g generic.key --id 1,2,3 -g restricted.key +#### Restricted Access +```bash +# Create keys with specific permissions +keygen --ecc256 \ + -g generic.key \ # All access + --id 1,2,3 \ + -g restricted.key # Limited access ``` -Generates two keypairs, `generic.key` and `restricted.key`. The former assumes the -default mask `KEY_VERIFY_ALL`, which makes it possible to use it to authenticate any -of the system components. The latter instead, will carry a mask with only the bits -'1', '2', and '3' set (mask = b00001110 =0x000e), allowing the usage only with the assigned -partition IDs. +#### Permission Examples +| Key | Mask | Binary | Access | +|-----|------|--------|---------| +| generic.key | KEY_VERIFY_ALL | 11111111 | All partitions | +| restricted.key | 0x000E | 00001110 | Partitions 1,2,3 | -### Importing public keys +## Advanced Key Management -The "-i" option is used to import existing public keys into the keyvault. The usage is identical to the '-g' option, except that -the file provided must exist and contain a valid public key of the given algorithm and key size. +### Key Import +```bash +# Import existing public key +keygen -i existing_pub.der +``` -### Generating and importing keys of different types +### Universal KeyStore -By default, wolfBoot hardcodes the type of key used for all the signature verification operations into the keystore format. +#### Configuration +```bash +# Enable mixed key types +make WOLFBOOT_UNIVERSAL_KEYSTORE=1 +``` -Alternatively, wolfBoot can be compiled with the option `WOLFBOOT_UNIVERSAL_KEYSTORE=1`, which disables the check at compile -time and allows adding keys of different types to the keystore. For example, if we want to create two keypairs with different ECC curves, -and additionally store a pre-existing RSA2048 public key file `rsa-pub.der`, we could run the following: +#### Mixed Key Example +```bash +# Create multi-algorithm keystore +keygen \ + --ecc256 -g a.key \ # ECC-256 key + --ecc384 -g b.key \ # ECC-384 key + --rsa2048 -i rsa-pub.der # Import RSA-2048 +``` -`keygen --ecc256 -g a.key --ecc384 -g b.key --rsa2048 -i rsa-pub.der` +#### Supported Algorithms +| Type | Option | Key Size | +|------|---------|----------| +| ECC-256 | --ecc256 | 256-bit | +| ECC-384 | --ecc384 | 384-bit | +| RSA-2048 | --rsa2048 | 2048-bit | +| ED25519 | --ed25519 | 256-bit | -The command above generates a keystore with three public keys that are accessible by the bootloader at runtime. +**Note**: Additional algorithms require explicit inclusion via `SIGN=` option -Please note that by default wolfBoot does not include any public key algorithm implementations besides the one -selected via the option `SIGN=`, so usually this feature is reserved to specific use cases where other policies or components -in the chain-of-trust require to store different key types for different purposes. +### Key Export -### Exporting the public key to a file - -The `keygen` tool can also export the public key that corresponds to the private key generated with the `-g` option to a der file when -used with the `--exportpubkey` option. The `--exportpubkey` option only has an effect if used in conjunction with the `-g` option, -otherwise it is ignored. To generate a new ECC 256 keypair, with der files exported for both public and private keys, use: - -```sh +#### Export Command +```bash +# Generate and export keypair keygen --ecc256 --exportpubkey -g mykey.der ``` -The exported public key will have the same name as the input to the `-g` option, but with `_pub` appended to the string before -the first `.` character. Therefore, running the above command will result in the creation of the following two files: +#### Output Files +| File | Description | Format | +|------|-------------|---------| +| mykey.der | Private key | DER | +| mykey_pub.der | Public key | DER | -```sh -mykey.der # <-- the generated private key -mykey_pub.der # <-- the generated public key +#### Usage Notes +- Requires `-g` option +- Automatic name generation +- DER format output +- Suitable for HSM import + +## External KeyStore Integration + +### Overview +Support for external key storage: +- Hardware security modules +- External NVM +- Key vaults +- Custom storage solutions + +### API Reference + +#### Core Functions +```c +// Get total key count +int keystore_num_pubkeys(void); + +// Get key size for slot +int keystore_get_size(int id); + +// Access key buffer +uint8_t *keystore_get_buffer(int id); + +// Get permission mask +uint32_t keystore_get_mask(int id); ``` -## Using KeyStore with external Key Vaults, where keys are accessible +#### Function Details -It is possible to use an external NVM, a Key Vault or any generic support to -access the KeyStore. In this case, wolfBoot should not link the generated keystore.c directly, -but rather rely on an external interface, that exports the same API which -would be implemented by `keystore.c`. +| Function | Return Type | Description | Error Handling | +|----------|-------------|-------------|----------------| +| keystore_num_pubkeys | int | Total slots | Must be ≥ 1 | +| keystore_get_size | int | Key size | Negative on error | +| keystore_get_buffer | uint8_t* | Key data | NULL on error | +| keystore_get_mask | uint32_t | Permissions | 0 on error | -The API consists of a few functions described below. +#### Implementation Notes +- Sequential slot numbering +- Zero-based indexing +- Error checking required +- Thread-safe access -### Interface API +## HSM Integration -#### Number of keys in the keystore -`int keystore_num_pubkeys(void)` +### Overview +Support for Hardware Security Modules (HSMs): +- Secure key storage +- Cryptographic operations +- Runtime verification +- Field updates -Returns the number of slots in the keystore. At least one slot -should be populated if you want to authenticate your firmware today. -The interface assumes that the slots are numbered sequentially, from zero to -`keystore_num_pubkeys() - 1`. Accessing those slots through this API should always - return a valid public key. +### Architecture +``` +Application + ↓ +wolfBoot ←→ KeyStore + ↓ ↓ + HSM ←→ Metadata +``` -#### Size of the public key in a slot -`int keystore_get_size(int id)` +### Implementation -Returns the size of the public key stored in the slot `id`. -In case of error, return a negative value. +#### Key Generation +```bash +# Generate HSM-compatible keys +keygen --ecc256 \ + --nolocalkeys \ + --exportpubkey \ + -g hsm_key.der +``` -#### Actual public key buffer (mapped/copied in memory) +#### Features +| Feature | Description | +|---------|-------------| +| Zero-copy | No key material in keystore | +| Metadata | Size and type information | +| Field updates | No rebuild required | +| Security | Keys never exposed | -`uint8_t *keystore_get_buffer(int id)` +#### Requirements +- Compatible HSM (e.g., wolfHSM) +- Manual key loading +- Matching algorithms +- Proper key sizes -Returns a pointer to an accessible area in memory, containing the buffer with the -public key associated to the slot `id`. +### Security Benefits +- Keys never leave HSM +- Hardware-backed crypto +- Tamper resistance +- Secure key updates -#### Permissions mask - -`uint32_t keystore_get_mask(int id)` - -Returns the permissions mask, as a 32-bit word, for the public key stored in the slot `id`. - -### Using KeyStore with HSMs (inaccessible keys) - -wolfBoot supports certain platforms that contain connected HSMs (Hardware Security Modules) that can provide cryptographic services using keys that are not stored in the device NVM or readable by wolfBoot, for example, wolfHSM. In these scenarios, wolfBoot key tools should be used to generate the keys, which can then be manually loaded into the HSM (see [--exportpubkey](#exporting-the-public-key-to-a-file)). At runtime, wolfBoot will still use the keystore to obtain information about the public keys, specifically the size of the key and the key type, but does not need access to the actual key material. - -To support this mode of operation, the `keygen` tool supports the `--nolocalkeys` option, which instructs the tool to generate a keystore entry with a zeroed key material. It still generates the `.der` files for private and public keys, so the wolfBoot key tools can sign images, but the `keystore.c` file that is linked into wolfBoot will contain all zeros in the `pubkey` field. Because the key material isn't present in the keystore, the keypair used to sign the image and stored on the HSM for verification can be updated in the field without needing to rebuild wolfBoot against a new `keystore.c`, as long as the signature algorithm and key size does not change. Most targets that use this option will automatically add it to the key generation options or explicitly mention this step in the build documentation. +For detailed HSM setup, see [wolfHSM Documentation](wolfHSM.md) diff --git a/docs/lib.md b/docs/lib.md index a86e9010..7c63bb5a 100644 --- a/docs/lib.md +++ b/docs/lib.md @@ -1,125 +1,168 @@ -# Build wolfBoot as Library +# wolfBoot Library Integration Guide -Instead of building as standalone repository, wolfBoot can be built as -a secure-boot library and integrated in third party bootloaders, custom -staging solutions etc. +## Overview +wolfBoot can be integrated as a secure-boot library into: +- Third-party bootloaders +- Custom staging solutions +- Existing boot chains +- Verification modules +## Core API -## Library API - -The wolfBoot secure-boot image verification has a very simple interface. -The core object describing the image is a `struct wolfBoot_image`, which -is initialized when `wolfBoot_open_image_address()` is called. The signature is: - - -`int wolfBoot_open_image_address(struct wolfBoot_image* img, uint8_t* image)` - - -where `img` is a pointer to a local (uninitialized) structure of type `wolfBoot_image`, and -`image` is a pointer to where the signed image is mapped in memory, starting from the beginning -of the manifest header. - - -On success, zero is returned. If the image does not contain a valid 'magic number' at the beginning -of the manifest, or if the size of the image is bigger than `WOLFBOOT_PARTITION_SIZE`, -1 is returned. - - -If the `open_image_address` operation is successful, two other functions can be invoked: - - -- `int wolfBoot_verify_integrity(struct wolfBoot_image *img)` - - -This function verifies the integrity of the image, by calculating the SHA hash of the image content, -and comparing it with the digest stored in the manifest header. `img` is a pointer to -an object of type `wolfBoot_image`, previously initialized by `wolfBoot_open_image_address`. - - -0 is returned if the image integrity could be successfully verified, -1 otherwise. - - - -- `int wolfBoot_verify_authenticity(struct wolfBoot_image *img)` - - -This function verifies that the image content has been signed by a trusted -counterpart (i.e. that could be verified using one of the public keys available). - - -`0` is returned in case of successful authentication, `-1` if anything went wrong during the operation, -and `-2` if the signature could be found, but was not possible to authenticate against its public key. - -## Library mode: example application - -An example application is provided in `hal/library.c`. - -The application `test-lib` opens a file from a path passed as argument -from the command line, and verifies that the file contains a valid, signed -image that can be verified for integrity and authenticity using wolfBoot in library -mode. - -## Configuring and compiling the test-lib application - -Step 1: use the provided configuration to compile wolfBoot in library mode: +### Image Verification Interface +#### Key Components +```c +struct wolfBoot_image { + // Image metadata and state + // See wolfboot/include/image.h +}; ``` + +#### Opening Images +```c +int wolfBoot_open_image_address( + struct wolfBoot_image* img, // Uninitialized image struct + uint8_t* image // Pointer to manifest header +); +``` + +#### Return Values +| Value | Description | +|-------|-------------| +| 0 | Success | +| -1 | Invalid magic number or size | + +#### Size Constraints +- Maximum size: `WOLFBOOT_PARTITION_SIZE` +- Includes manifest header +- Enforced at runtime + + +### Verification Functions + +#### 1. Integrity Check +```c +int wolfBoot_verify_integrity( + struct wolfBoot_image *img // Initialized image struct +); +``` + +**Operation**: +- Calculates SHA hash +- Compares with manifest +- Verifies image content + +**Returns**: +| Value | Meaning | +|-------|---------| +| 0 | Integrity verified | +| -1 | Verification failed | + +#### 2. Authenticity Verification +```c +int wolfBoot_verify_authenticity( + struct wolfBoot_image *img // Initialized image struct +); +``` + +**Operation**: +- Verifies signature +- Checks against public keys +- Validates trust chain + +**Returns**: +| Value | Meaning | +|-------|---------| +| 0 | Authentication successful | +| -1 | Operation error | +| -2 | Invalid signature | + +## Example Implementation + +### Test Application +Location: `hal/library.c` + +#### Features +- Command-line interface +- File-based verification +- Integrity checking +- Signature validation + +### Build Instructions + +#### 1. Configuration Setup +```bash +# Copy library configuration cp config/examples/library.config .config ``` -Step 2: create a file `target.h` that only contains the following lines: - -``` -cat > include/target.h << EOF +#### 2. Target Configuration +Create `include/target.h`: +```c #ifndef H_TARGETS_TARGET_ #define H_TARGETS_TARGET_ +/* Disable partition support */ #define WOLFBOOT_NO_PARTITIONS -#define WOLFBOOT_SECTOR_SIZE 0x20000 -#define WOLFBOOT_PARTITION_SIZE 0x20000 +/* Configure memory layout */ +#define WOLFBOOT_SECTOR_SIZE 0x20000 +#define WOLFBOOT_PARTITION_SIZE 0x20000 #endif /* !H_TARGETS_TARGET_ */ - -EOF ``` -Change `WOLFBOOT_PARTITION_SIZE` accordingly. `wolfBoot_open_image_address()` will discard images larger than -`WOLFBOOT_PARTITION_SIZE` - `IMAGE_HEADER_SIZE`. +**Important**: Adjust `WOLFBOOT_PARTITION_SIZE` based on your requirements: +- Maximum image size = `PARTITION_SIZE - HEADER_SIZE` +- Oversized images rejected automatically -Step 3: compile keytools and create keys. +### Testing Process -``` +#### 1. Key Generation +```bash +# Build key tools make keytools -./tools/keytools/keygen --ed25519 -g wolfboot_signing_private_key.der + +# Generate ED25519 keypair +./tools/keytools/keygen \ + --ed25519 \ + -g wolfboot_signing_private_key.der ``` - -Step 4: Create an empty file and sign it using the private key. - -``` +#### 2. Image Signing +```bash +# Create test image touch empty -./tools/keytools/sign --ed25519 --sha256 empty wolfboot_signing_private_key.der 1 + +# Sign image +./tools/keytools/sign \ + --ed25519 \ + --sha256 \ + empty \ + wolfboot_signing_private_key.der \ + 1 ``` - -Step 5: compile the test-lib application, linked with wolfBoot in library mode, and the -public key from the keypair created at step 4. - -``` +#### 3. Build Test Application +```bash +# Compile with library support make test-lib ``` -Step 6: run the application with the signed image - -``` +#### 4. Verification Test +```bash +# Run verification ./test-lib empty_v1_signed.bin + +# Expected output: +# Firmware Valid +# booting 0x5609e3526590(actually exiting) ``` -If everything went right, the output should be similar to: - -``` -Firmware Valid -booting 0x5609e3526590(actually exiting) -``` +## Related Documentation +- [Firmware Format](firmware_image.md) +- [Signing Process](Signing.md) +- [API Reference](API.md) diff --git a/docs/measured_boot.md b/docs/measured_boot.md index f02d42a6..7f022d07 100644 --- a/docs/measured_boot.md +++ b/docs/measured_boot.md @@ -1,86 +1,145 @@ -# Measured Boot using wolfBoot +# Measured Boot with wolfBoot -wolfBoot offers a simplified measured boot implementation, a way to record and -track the state of the system boot process using a Trusted Platform Module(TPM). +## Overview +wolfBoot provides a secure measured boot implementation using TPM2.0 technology for system state verification and tamper detection. -This record is tamper-proofed by special registers in the TPM called Platform -Configuration Register. Then, the firmware application, RTOS or rich OS(Linux), -can access that log of information by reading the PCRs of the TPM. - -wolfBoot can interact with TPM2.0 chips thanks to its integration with wolfTPM. -wolfTPM has native support for Microsoft Windows and Linux, and can be used -standalone or together with wolfBoot. The combination of wolfBoot with wolfTPM -gives the developer a tamper-proof secure storage for protecting the system -during and after boot. - -## Concept - -Typically, systems use Secure Boot to guarantee that the correct and genuine -firmware is booted by verifying its signature. Afterwards, this knowledge is -unknown to the system. The application does not know if the system started in -a good known state. Sometimes, this guarantee is needed by the firmware itself. -To provide such mechanism the concept of Measured Boot exist. - -Measured Boot can be used to check every start-up component, including settings -and user information(user partition). The result of the checks is then stored -into special registers called PCR. This process is called PCR Extend and is -referred to as a TPM measurement. PCR registers can be reset only on TPM power-on. - -Having TPM measurements provide a way for the firmware or Operating System(OS), -like Windows or Linux, to know that the software loaded before it gained control -over system, is trustworthy and not modified. - -In wolfBoot the concept is simplified to measuring a single component, the main -firmware image. However, this can easily be extended by using more PCR registers. - -## Configuration - -To enable measured boot add `MEASURED_BOOT=1` setting in your wolfBoot config. - -It is also necessary to select the PCR (index) where the measurement will be stored. - -Selection is made using the `MEASURED_PCR_A=[index]` setting. Add this -setting in your wolfBoot config and replace `[index]` with a number between -0 and 23. Below you will find guidelines for selecting a PCR index. - -Any TPM has a minimum of 24 PCR registers. Their typical use is as follows: - -| Index | Typical use | Recommended to use with | -|----------|:-------------:|------:| -| 0 | Core Root of Trust and/or BIOS measurement | bare-metal, RTOS | -| 1 | measurement of Platform Configuration Data | bare-metal, RTOS | -| 2-3 | Option ROM Code measurement | bare-metal, RTOS | -| 4-5 | Master Boot Record measurement | bare-metal, RTOS | -| 6 | State Transitions | bare-metal, RTOS | -| 7 | Vendor specific | bare-metal, RTOS | -| 8-9 | Partition measurements | bera-metal, RTOS | -| 10 | measurement of the Boot Manager | bare-metal, RTOS | -| 11 | Typically used by Microsoft Bitlocker | bare-metal, RTOS | -| 12-15 | Available for any use | bare-metal, RTOS, Linux, Windows | -| 16 | DEBUG | Use only for test purposes | -| 17 | DRTM | Trusted Bootloader | -| 18-22 | Trusted OS | Trusted Execution Environment(TEE) | -| 23 | Application | Use only for temporary measurements | - -Recommendations for choosing a PCR index: - -- During development it is recommended to use PCR16 that is intended for testing. -- In production, if you are running a bare-metal firmware or RTOS, you could use -almost all PCRs(PCR0-15), except the one for DRTM and Trusted OS(PCR17-23). -- If you are running Linux or Windows, PCR12-15 can be chosen for production -ready firmware, in order to avoid conflict with other software that might be -using PCRs from within Linux, like the Linux IMA or Microsoft Bitlocker. - -Here is an example part of a wolfBoot .config during development: +### Key Features +- System state tracking +- TPM2.0 integration +- Tamper-proof logging +- Multi-platform support +- Runtime verification +### System Components ``` ++-------------+ +---------+ +----------+ +| wolfBoot | --> | wolfTPM | --> | TPM2.0 | ++-------------+ +---------+ +----------+ + ↓ ↓ + Measures Interfaces Stores PCRs +``` + +### Platform Support +| Platform | Support Level | +|----------|--------------| +| Windows | Native | +| Linux | Native | +| RTOS | Full | +| Bare Metal | Full | + +## Technical Overview + +### Secure vs. Measured Boot +| Feature | Secure Boot | Measured Boot | +|---------|-------------|---------------| +| Purpose | Verify firmware signature | Track system state | +| Timing | Boot-time only | Continuous | +| Storage | None after boot | Persistent in TPM | +| Access | Boot process only | Runtime accessible | + +### Measurement Process +1. Component verification +2. PCR extension (TPM measurement) +3. State recording +4. Runtime verification + +### TPM Integration +- PCR (Platform Configuration Register) + - Tamper-proof storage + - Power-cycle reset only + - Cryptographic extension + +### wolfBoot Implementation +- Single component focus + - Main firmware image + - Extensible design + - Additional PCR support +- Runtime verification + - OS/firmware access + - State validation + +## Configuration Guide + +### Basic Setup +```make +# Enable measured boot +MEASURED_BOOT=1 + +# Select PCR index +MEASURED_PCR_A=16 # Example for development +``` + +### PCR Index Selection + +#### PCR Register Map +| Index | Purpose | Platform Support | +|-------|---------|-----------------| +| 0 | Core Root of Trust/BIOS | Bare-metal, RTOS | +| 1 | Platform Config Data | Bare-metal, RTOS | +| 2-3 | Option ROM Code | Bare-metal, RTOS | +| 4-5 | Master Boot Record | Bare-metal, RTOS | +| 6 | State Transitions | Bare-metal, RTOS | +| 7 | Vendor Specific | Bare-metal, RTOS | +| 8-9 | Partition Data | Bare-metal, RTOS | +| 10 | Boot Manager | Bare-metal, RTOS | +| 11 | BitLocker Reserved | Windows Only | +| 12-15 | General Purpose | All Platforms | +| 16 | Debug/Development | Testing Only | +| 17 | DRTM | Trusted Boot | +| 18-22 | Trusted OS | TEE Only | +| 23 | Application | Temporary Use | + +#### Selection Guidelines +1. **Development** + - Use PCR16 (Debug) + - Unrestricted access + - No conflicts + +2. **Production - Bare Metal/RTOS** + - PCR0-15 available + - Avoid PCR17-23 + - Follow platform conventions + +3. **Production - Linux/Windows** + - Use PCR12-15 + - Avoid system PCRs + - Consider OS requirements + +### Example Configuration +Development setup in `.config`: +```make +# Enable measured boot MEASURED_BOOT?=1 + +# Use debug PCR MEASURED_PCR_A?=16 ``` -### Code +## Implementation Details -wolfBoot offers out-of-the-box solution. There is zero need of the developer to touch wolfBoot code -in order to use measured boot. If you would want to check the code, then look in `src/image.c` and -more specifically the `measure_boot()` function. There you would find several TPM2 native API calls -to wolfTPM. For more information about wolfTPM you can check its GitHub repository. +### Architecture +``` ++----------------+ +---------------+ +| Firmware Image | | TPM2.0 Device | ++----------------+ +---------------+ + ↓ ↓ + measure_boot() ----→ PCR Extension + ↓ ↓ + Verification State Preservation +``` + +### Key Components +- **src/image.c**: Core implementation +- **measure_boot()**: Main measurement function +- **wolfTPM API**: TPM2.0 interface + +### Features +- Zero-touch integration +- Automatic measurement +- TPM2.0 native calls +- Runtime verification + +## Related Documentation +- [wolfTPM Integration](https://github.com/wolfSSL/wolfTPM) +- [TPM Security](TPM.md) +- [Secure Boot](Signing.md) diff --git a/docs/remote_flash.md b/docs/remote_flash.md index 29919273..4c2883da 100644 --- a/docs/remote_flash.md +++ b/docs/remote_flash.md @@ -1,50 +1,96 @@ -## Remote External flash memory support via UART +# Remote Flash Support via UART -wolfBoot can emulate external partitions using UART communication with a neighbor system. This feature -is particularly useful in those asynchronous multi-process architectures, where updates can be stored -with the assistance of an external processing unit. +## Overview +wolfBoot supports external partition emulation through UART communication, enabling: +- Remote flash storage +- Asynchronous updates +- Multi-processor architectures +- External update staging -### Bootloader setup +## Configuration -The option to activate this feature is `UART_FLASH=1`. This configuration option depends on the -external flash API, which means that the option `EXT_FLASH=1` is also mandatory to compile the bootloader. - -The HAL of the target system must be expanded to include a simple UART driver, that will be used by the -bootloader to access the content of the remote flash using one of the UART controllers on board. - -Example UART drivers for a few of the supported platforms can be found in the [hal/uart](hal/uart) directory. - -The API exposed by the UART HAL extension for the supported targets is composed by the following functions: - -``` -int uart_init(uint32_t bitrate, uint8_t data, char parity, uint8_t stop); -int uart_tx(const uint8_t c); -int uart_rx(uint8_t *c); +### Build Options +```make +# Required settings +UART_FLASH=1 # Enable UART flash +EXT_FLASH=1 # Enable external flash API ``` -Consider implementing these three functions based on the provided examples if you want to use external flash memory -support on your platform, if not officially supported yet. +### UART Driver Integration + +#### Required HAL Functions +```c +/* Initialize UART with specified parameters */ +int uart_init( + uint32_t bitrate, // Communication speed + uint8_t data, // Data bits + char parity, // Parity mode + uint8_t stop // Stop bits +); + +/* Transmit single byte */ +int uart_tx( + const uint8_t c // Byte to send +); + +/* Receive single byte */ +int uart_rx( + uint8_t *c // Buffer for received byte +); +``` + +#### Implementation Notes +- Example drivers: [hal/uart](hal/uart) +- Platform-specific adaptations needed +- Simple interface design +- Minimal dependencies -### Host side: UART flash server +## Host Implementation -On the remote system hosting the external partition image for the target, a simple protocol can be implemented -on top of UART messages to serve flash-access specific calls. +### UART Flash Server +``` +Host System Target System ++----------------+ UART +----------------+ +| Flash Server | <------> | wolfBoot | +| - File storage | | - Remote flash | +| - RPC handler | | - Update mgmt | ++----------------+ +----------------+ +``` -An example uart-flash-server daemon, designed to run on a GNU/Linux host and emulate the external partition with -a local file on the filesystem, is available in [tools/uart-flash-server](tools/uart-flash-server). +#### Components +- Location: [tools/uart-flash-server](tools/uart-flash-server) +- Platform: GNU/Linux host +- Storage: Local file system +- Protocol: Custom UART messages +### Update Mechanism -### External flash update mechanism +#### Operation Model +| Operation | Implementation | +|-----------|---------------| +| Read | UART RPC → Host read | +| Write | UART RPC → Host write | +| Update | Standard wolfBoot flow | +| Rollback | Remote partition backup | -wolfBoot treats external UPDATE and SWAP partitions in the same way as when they are mapped on a local SPI flash. -Read and write operations are simply translated into remote procedure calls via UART, that can be interpreted by -the remote application and provide read and write access to actual storage elements which would only be accessible -by the host. +#### Key Features +- Transparent operation +- Standard update flow +- Remote storage support +- Automatic backup +- Rollback capability -This means that after a successful update, a copy of the previous firmware will be stored in the remote partition to -provide exactly the same update mechanism that is available in all the other use cases. The only difference consist -in the way of accessing the physical storage area, but all the mechanisms at a higher level stay the same. +#### Architecture Benefits +- Consistent API +- Flexible storage +- Reliable updates +- Host accessibility + +## Related Documentation +- [Firmware Updates](firmware_update.md) +- [External Flash](flash_partitions.md) +- [HAL Integration](HAL.md) diff --git a/docs/wolfHSM.md b/docs/wolfHSM.md index 0e3e6f02..a6d34ab1 100644 --- a/docs/wolfHSM.md +++ b/docs/wolfHSM.md @@ -1,147 +1,249 @@ -# wolfHSM Client Integration with wolfBoot +# wolfHSM Integration Guide -wolfBoot provides tight integration with wolfHSM when used on a select group of supported platforms. When used in this mode, wolfBoot acts as a wolfHSM client, with all cryptographic operations and key storage offloaded to the wolfHSM server as remote procedure calls (RPCs). +## Overview +wolfBoot provides secure cryptographic offloading through wolfHSM integration, enabling hardware-backed security features through Remote Procedure Calls (RPCs). -For an introduction to wolfHSM, please refer to the [wolfHSM Manual](https://wolfSSL.com/https://www.wolfssl.com/documentation/manuals/wolfhsm/) and [wolfHSM GitHub Repository](https://github.com/wolfssl/wolfHSM.git). +### Architecture +``` ++-------------+ +------------+ +-----------+ +| wolfBoot | --> | wolfHSM | --> | Hardware | +| (Client) | | (Server) | | HSM | ++-------------+ +------------+ +-----------+ + ↓ ↓ ↓ + Requests Operations Secure Keys +``` -## Key Features +### Key Features +| Feature | Description | +|---------|-------------| +| Key Storage | Secure HSM-backed storage | +| Crypto Ops | Remote operation execution | +| Key Rotation | Runtime key management | +| Isolation | Hardware security boundary | -1. Secure key storage: Keys used for authentication and encryption are stored securely on the wolfHSM server -2. Remote cryptographic operations: All cryptographic operations are performed on the wolfHSM server -3. Flexible key management: Keys can be updated or rotated on the wolfHSM server without requiring an update to wolfBoot +## Platform Support -## Supported Platforms +### Supported Targets +| Platform | Transport | Status | +|----------|-----------|---------| +| Simulator | POSIX TCP | ✓ Full | +| AURIX TC3xx | Shared Memory | ✓ Full | -wolfBoot supports using wolfHSM on the following platforms: +### Documentation +- [wolfHSM Manual](https://wolfSSL.com/https://www.wolfssl.com/documentation/manuals/wolfhsm/) +- [GitHub Repository](https://github.com/wolfssl/wolfHSM.git) +- Platform-specific guides in respective docs -- wolfBoot simulator (using wolfHSM POSIX TCP transport) -- AURIX TC3xx (shared memory transport) +## Cryptographic Support -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. +### Supported Algorithms -## Algorithm Support +#### Signature Verification +| Algorithm | Key Sizes | Notes | +|-----------|-----------|-------| +| RSA | 2048/3072/4096 | Image signatures | +| ECDSA | P-256/384/521 | Image signatures | +| ML-DSA | Level 2/3/5 | Platform dependent | +| SHA256 | N/A | Image integrity | -wolfBoot supports using wolfHSM for the following algorithms: +**Note**: Encrypted image support pending -- RSA with 2048, 3072, and 4096-bit keys for image signature verification -- ECDSA P-256, P-384, and P-521 for image signature verification -- ML-DSA security levels 2, 3, and 5 (depending on platform) for image signature verification -- SHA256 for image integrity verification +### Configuration -Encrypted images with wolfHSM is not yet supported in wolfBoot. Note that every HAL target may not support all of these algorithms. Consult the platform-specific wolfBoot documentation for details. +#### Basic Setup +```make +# Enable HSM client +WOLFBOOT_ENABLE_WOLFHSM_CLIENT=1 -## Configuration Options +# Use HSM key storage +WOLFBOOT_USE_WOLFHSM_PUBKEY_ID=1 +``` -This section describes the configuration options available for wolfHSM client integration. Note that these options should be configured automatically by the build system for each supported platform when wolfHSM support is enabled. Consult the platform-specific documentation for details on enabling wolfHSM support. +#### Key Management Modes -### `WOLFBOOT_ENABLE_WOLFHSM_CLIENT` +1. **HSM-Stored Keys** (Recommended) +```bash +# Generate keys without local storage +keygen --nolocalkeys ... -This option enables wolfHSM client support in wolfBoot. Without defining this option, support for wolfHSM is not compiled in and the remainder of the options have no effect. +# Configuration +WOLFBOOT_USE_WOLFHSM_PUBKEY_ID=1 +``` -### `WOLFBOOT_USE_WOLFHSM_PUBKEY_ID` +2. **Local Keys** (Debug/Testing) +```bash +# Generate standard keys +keygen ... -This option enables use of the reserved wolfHSM public key ID for firmware authentication, and is typically the desired behavior for using wolfHSM. When this option is defined, wolfBoot will use the reserved wolfHSM keyId defined by the HAL (`hsmClientKeyIdPubKey`). This option is meant to be used in conjunction with the `--nolocalkeys` keygen option, as the key material in the keystore will not be used. +# Configuration +# WOLFBOOT_USE_WOLFHSM_PUBKEY_ID not set +``` -If this option is not defined, cryptographic operations are still performed on the wolfHSM server, but wolfBoot assumes the key material is present in the keystore and NOT stored on the HSM. This means that wolfBoot will first load keys from the keystore, send the key material to the wolfHSM server at the time of use (cached as ephemeral keys), and finally evict the key from the HSM after usage. This behavior is typically only useful for debugging or testing scenarios, where the keys may not be pre-loaded onto the HSM. The keystore for use in this mode should not be generated with the `--nolocalkeys` option. +#### Operation Flow +``` +HSM-Stored Keys: +wolfBoot → HSM KeyId → Direct Operations -## HAL Implementations +Local Keys: +wolfBoot → Local Key → HSM Cache → Operations → Evict +``` -In addition to the standard wolfBoot HAL functions, wolfHSM-enabled platforms must also implement or instantiate the following wolfHSM-specific items in the platform HAL: +## HAL Integration -### HAL Global Variables +### Required Components -- `hsmClientCtx`: A global context for the wolfHSM client. This is initialized by the HAL and passed to wolfBoot, but should not be modified by wolfBoot. -- `hsmClientDevIdHash`: The HSM device ID for hash operations. This is used to identify the HSM device to wolfBoot. -- `hsmClientDevIdPubKey`: The HSM device ID for public key operations. This is used to identify the HSM device to wolfBoot. -- `hsmClientKeyIdPubKey`: The HSM key ID for public key operations. This is used to identify the key to use for public key operations. +#### Global Variables +| Variable | Type | Purpose | +|----------|------|---------| +| `hsmClientCtx` | Context | Client state | +| `hsmClientDevIdHash` | ID | Hash operations | +| `hsmClientDevIdPubKey` | ID | Public key ops | +| `hsmClientKeyIdPubKey` | ID | Key selection | -### HAL Functions +#### Function Interface +```c +/* Initialize HSM connection */ +int hal_hsm_init_connect(void); -- `hal_hsm_init_connect()`: Initializes the connection to the wolfHSM server. This is called by wolfBoot during initialization. This should initialize the HSM client context (`hsmClientCtx`) with a valid configuration and initialize the wolfHSM client API. -- `hal_hsm_disconnect()`: Disconnects from the wolfHSM server. This is called by wolfBoot during shutdown. This should clean up the HSM client context (`hsmClientCtx`) and invoke the wolfHSM client API's cleanup function, freeing any additional allocated resources. +/* Cleanup HSM connection */ +void hal_hsm_disconnect(void); +``` -## wolfBoot Simulator and wolfHSM +### Implementation Flow +``` +Initialization: ++----------------+ +------------------+ +| Boot Sequence | --> | hal_hsm_init | ++----------------+ +------------------+ + ↓ + +------------------+ + | Context Setup | + +------------------+ + ↓ + +------------------+ + | API Init | + +------------------+ -The wolfBoot simulator supports wolfHSM with the POSIX TCP transport. It expects to communicate with the [wolfHSM example POSIX TCP server](https://github.com/wolfSSL/wolfHSM-examples/tree/main/posix/tcp/wh_server_tcp) at `127.0.0.1:1234`. See the [wolfHSM-examples README](https://github.com/wolfSSL/wolfHSM-examples/blob/main/README.md) for more information on the example POSIX TCP server. +Shutdown: ++----------------+ +------------------+ +| System Cleanup | --> | hal_hsm_disc | ++----------------+ +------------------+ + ↓ + +------------------+ + | Context Cleanup | + +------------------+ + ↓ + +------------------+ + | Resource Free | + +------------------+ +``` -### Building the simulator with wolfHSM support +## Simulator Integration -The wolfBoot simulator supports using wolfHSM with all algorithms mentioned in [Algorithm Support](#algorithm-support). To build the simulator configured to use wolfHSM,, ensure you build with the `WOLFHSM_CLIENT=1` makefile option. This will automatically define `WOLFBOOT_USE_WOLFHSM_PUBKEY_ID`, and requires the public key corresponding to the private key that signed the image to be pre-loaded into the HSM at the keyId specified by `hsmClientKeyIdPubKey` in the simulator HAL (see the next section for details on loading keys into the HSM example server). +### Overview +The wolfBoot simulator provides a complete wolfHSM testing environment using POSIX TCP transport. -```sh -# Grab the HSM simulator configuration +### Network Configuration +``` ++----------------+ +----------------+ +| wolfBoot Sim | <-> | wolfHSM Server | +| 127.0.0.1 | | :1234 | ++----------------+ +----------------+ +``` + +### Build Instructions + +#### 1. Configuration +```bash +# Setup simulator config cp config/examples/sim-wolfHSM.config .config -# Build wolfBoot with the simulator HAL configured to use wolfHSM, automatically generating keys -make +# Enable HSM client +make WOLFHSM_CLIENT=1 +``` -# Build and sign the test applications used in the simulated update +#### 2. Test Application +```bash +# Build and sign test apps make test-sim-internal-flash-with-update -# The generated wolfBoot public key can be found at `wolfboot_signing_private_key_pub.der`, and -# should be loaded into the HSM at the keyId specified by `hsmClientKeyIdPubKey` as described -# in the next section +# Key location: +# wolfboot_signing_private_key_pub.der ``` -### Running the simulator against a wolfHSM server +#### Key Features +| Feature | Description | +|---------|-------------| +| Transport | POSIX TCP | +| Algorithms | Full support | +| Key Storage | HSM-backed | +| Testing | Automated | -First, build the wolfHSM POSIX TCP server, following the instructions in the [wolfHSM-examples README](https://github.com/wolfSSL/wolfHSM-examples/blob/main/README.md). +## Testing Guide -Next, in a new terminal window, run the wolfHSM POSIX TCP server, loading the public key generated by the wolfBoot build process (`wolfboot_signing_private_key_pub.der`) +### Server Setup -```sh -# Build the example server +#### 1. Build Server +```bash +# Get wolfHSM examples cd wolfHSM-examples/posix/tcp/wh_server_tcp + +# Build server make WOLFHSM_DIR=/path/to/wolfHSM/install - -# Run the server, loading the wolfBoot public key and using keyId 0xFF (or modify keyId to match value of `hsmClientKeyIdPubKey` in `hal/sim.c`) -./Build/wh_server_tcp.elf --key /path/to/wolfboot_signing_private_key_pub.der --id 0xFF - -# The server will now be waiting for connections ``` -Run the wolfBoot simulator against the server with the appropriate arguments to report the firmware version and stage an update +#### 2. Start Server +```bash +# Run with wolfBoot key +./Build/wh_server_tcp.elf \ + --key wolfboot_signing_private_key_pub.der \ + --id 0xFF # Match hsmClientKeyIdPubKey +``` -```sh -# in the wolfBoot terminal window +### Testing Process + +#### 1. Stage Update +```bash +# Trigger update ./wolfboot.elf update_trigger get_version -# The following output should indicate that the update was staged successfully -Simulator assigned ./internal_flash.dd to base 0x7f7fcbd80000 -Boot partition: 0x7f7fcbe00000 (size 745400, version 0x1) -Update partition: 0x7f7fcbf00000 (size 745400, version 0x2) -Boot partition: 0x7f7fcbe00000 (size 745400, version 0x1) -Booting version: 0x1 -Simulator assigned ./internal_flash.dd to base 0x7f6665679000 -hal_flash_erase addr 0x7f66658f7000 len 4091 -1 +# Expected Output: +# Boot partition: v1 +# Update partition: v2 +# Status: Update staged ``` -Restart the wolfHSM server with the same arguments, then rerun the wolfBoot simulator to boot the new firmware and verify the update. +#### 2. Verify Update +```bash +# Restart server first +./Build/wh_server_tcp.elf \ + --key wolfboot_signing_private_key_pub.der \ + --id 0xFF -```sh -# In the wolfHSM server terminal window -./Build/wh_server_tcp.elf --key /path/to/wolfboot_signing_private_key_pub.der --id 0xFF - -# In the wolfBoot terminal window, run the following to update the image and confirm the update +# Complete update ./wolfboot.elf success get_version -# The output should ultimately print the following, indicating the update was successful - -#... lots of output ... -# -Boot partition: 0x7f3a2f96b000 (size 745400, version 0x2) -Update partition: 0x7f3a2fa6b000 (size 745400, version 0x1) -Copy sector 254 (part 0->2) -hal_flash_erase addr 0x7f3a2fb6b000 len 4096 -hal_flash_erase addr 0x7f3a2fa69000 len 4096 -hal_flash_erase addr 0x7f3a2fa6a000 len 4096 -hal_flash_erase addr 0x7f3a2fa69000 len 4096 -hal_flash_erase addr 0x7f3a2fb6a000 len 4096 -Boot partition: 0x7f3a2f96b000 (size 745400, version 0x2) -Booting version: 0x2 -Simulator assigned ./internal_flash.dd to base 0x7fe902d2e000 -2 +# Verification Points +- Boot partition: v2 +- Update success +- Version increment ``` +### Update Flow +``` +Initial State: +Boot(v1) | Update(v2) + +After Stage: +Boot(v1) | Update(v2*) + +After Success: +Boot(v2) | Update(v1) +``` + +## Related Documentation +- [wolfHSM Examples](https://github.com/wolfSSL/wolfHSM-examples) +- [Firmware Updates](firmware_update.md) +- [Key Management](keystore.md) +