mirror of https://github.com/wolfSSL/wolfBoot.git
552 lines
27 KiB
Markdown
552 lines
27 KiB
Markdown
# Compiling wolfBoot
|
|
|
|
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.
|
|
|
|
To enable specific compile options, use environment variables while calling make, e.g.
|
|
|
|
`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.:
|
|
|
|
`WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x14000`
|
|
|
|
## Generate a new configuration
|
|
|
|
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 `[]`.
|
|
|
|
Once a .config file is in place, it will change the default compile-time options when running `make`
|
|
without parameters.
|
|
|
|
.config can be modified with a text editor to alter the default options later on.
|
|
|
|
## Platform selection
|
|
|
|
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.
|
|
|
|
For a list of the platforms currently supported, see the [HAL documentation](./HAL.md).
|
|
|
|
To add a new platform, simply create the corresponding HAL driver and linker script file
|
|
in the [hal](../hal) directory.
|
|
|
|
Default option if none specified: `TARGET=stm32f4`
|
|
|
|
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:
|
|
|
|
`CORTEX_M0=1`
|
|
|
|
### Speed vs. size
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
#### Example: ECC256 + SHA256 on STM32H7
|
|
|
|
Benchmark footprint vs. boot time SHA of 100KB image + signature verification
|
|
|
|
| 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 |
|
|
|
|
|
|
### Flash partitions
|
|
|
|
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:
|
|
|
|
- `WOLFBOOT_SECTOR_SIZE`
|
|
|
|
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 partitions. The size is the same for both partitions unless using the monolithic
|
|
self-update mode, in which case the UPDATE partition can optionally be sized independently.
|
|
|
|
- `WOLFBOOT_PARTITION_UPDATE_SIZE`
|
|
|
|
Optional. Sizes the UPDATE partition independently of BOOT; defaults to
|
|
`WOLFBOOT_PARTITION_SIZE`. A different value is only allowed together with
|
|
`SELF_UPDATE_MONOLITHIC=1`, so the UPDATE partition can stage a monolithic
|
|
payload (bootloader region + application) without inflating the BOOT
|
|
partition. The staged payload also needs `IMAGE_HEADER_SIZE` plus one
|
|
trailer sector of room on top — see the sizing guide in
|
|
[firmware_update.md](firmware_update.md#independent-partition-sizing).
|
|
Not supported with `ENCRYPT` or `PULL_LINKER_DEFINES`.
|
|
|
|
## 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.
|
|
|
|
### Auxiliary crypto algorithms
|
|
|
|
Some features need crypto algorithms beyond the ones selected with `SIGN` and
|
|
`HASH`: certificate-chain verification may meet CA certificates signed with a
|
|
different algorithm than the leaf, and TPM support needs ECC or RSA for its
|
|
primary key and parameter encryption even when `SIGN` is a post-quantum or
|
|
Ed25519/Ed448 algorithm.
|
|
|
|
`AUX_PK_ALGOS` and `AUX_HASH_ALGOS` compile extra wolfCrypt algorithms into
|
|
wolfBoot for those uses. Both take a comma-separated, case-insensitive list
|
|
(no spaces):
|
|
|
|
```sh
|
|
make SIGN=ECC256 AUX_PK_ALGOS=rsa2048,ecc384 AUX_HASH_ALGOS=sha384
|
|
```
|
|
|
|
Valid `AUX_PK_ALGOS` entries: `ecc256`, `ecc384`, `ecc521`, `rsa2048`,
|
|
`rsa3072`, `rsa4096`, `rsapss2048`, `rsapss3072`, `rsapss4096`, `ed25519`,
|
|
`ed448`. Valid `AUX_HASH_ALGOS` entries: `sha256`, `sha384`, `sha512`,
|
|
`sha3`. Post-quantum algorithms (ML-DSA, LMS, XMSS) are not yet supported as
|
|
auxiliary algorithms.
|
|
|
|
Auxiliary algorithms are never used to verify the firmware image signature;
|
|
that remains bound to `SIGN` (and `SIGN_SECONDARY` for hybrid mode). Each
|
|
entry defines a `WOLFBOOT_AUX_PK_<ALGO>` or `WOLFBOOT_AUX_HASH_<ALGO>` macro
|
|
and links the matching wolfCrypt objects; entries already covered by
|
|
`SIGN`/`SIGN_SECONDARY` are no-ops.
|
|
|
|
Notes:
|
|
|
|
- Not compatible with `WOLFBOOT_SMALL_STACK=1`: the static memory pools are
|
|
sized for the primary `SIGN` algorithm only.
|
|
- `STACK_USAGE` is not adjusted automatically. If an auxiliary algorithm with
|
|
larger stack needs (e.g. `rsa4096`) is actually exercised, consider
|
|
`WOLFBOOT_HUGE_STACK=1` (the RSA4096 cert-chain configurations already do).
|
|
- When `WOLFTPM=1` and neither `SIGN`, `SIGN_SECONDARY`, nor `AUX_PK_ALGOS`
|
|
provides an ECC or RSA algorithm, `ecc256` is added automatically so the
|
|
TPM SRK and parameter encryption work.
|
|
- With `CERT_CHAIN_VERIFY=1`, the generated dummy chain's CA algorithms
|
|
(`CERT_CHAIN_GEN_CA_ALGO`/`CERT_CHAIN_GEN_CA_HASH`) are bridged into these
|
|
lists automatically. Users providing `USER_CERT_CHAIN` must list their
|
|
chain's algorithms here themselves.
|
|
|
|
### 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`.
|
|
|
|
### One-shot hash verification
|
|
|
|
By default, wolfBoot hashes firmware images in blocks of `WOLFBOOT_SHA_BLOCK_SIZE` bytes during
|
|
verification. This block-by-block approach is required when firmware resides in external flash or
|
|
other non-memory-mapped storage, where data must be read through intermediate buffers.
|
|
|
|
When firmware images are stored in directly memory-mapped flash (e.g. internal flash with
|
|
execute-in-place support), the block-by-block overhead can be eliminated by enabling
|
|
`WOLFBOOT_IMG_HASH_ONESHOT=1`. With this option, the entire image buffer is passed to the wolfCrypt
|
|
hash function in a single call, which can improve verification performance.
|
|
|
|
**warning** This option assumes that `fw_base` pointers are directly dereferenceable for the full
|
|
firmware size. It is incompatible with `EXT_FLASH=1` configurations where partitions reside on
|
|
external SPI or UART flash. Only use `WOLFBOOT_IMG_HASH_ONESHOT=1` when all firmware partitions are
|
|
in directly addressable, memory-mapped flash.
|
|
|
|
### 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. This also removes the
|
|
power-fail-safe swap behavior: if power is lost while the update is being copied into the BOOT partition, the original
|
|
firmware may already be partially overwritten and the device can be left unrecoverable.
|
|
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.
|
|
|
|
### Require an authenticated device tree (raw-DTB targets)
|
|
|
|
On non-FIT MMU targets that load a raw device tree from flash, wolfBoot authenticates the DTB against the `HDR_DEVICE_TREE_DIGEST` TLV bound to the signed kernel (`sign --dts <board.dtb>`, see `docs/Signing.md`). A DTB carrying the digest is always verified; a raw DTB with no digest only warns and boots by default. Compile with `WOLFBOOT_REQUIRE_SIGNED_DTB=1` to make a missing digest a hard failure (fail-closed) once every raw-DTB payload is signed with `--dts`.
|
|
|
|
### 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.
|
|
|
|
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
|
|
|
|
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 functions, instead, must be defined. Example SPI drivers are available for multiple platforms in the [hal/spi](../hal/spi) directory.
|
|
|
|
#### UART bridge towards neighbor systems
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
For more details, see the manual page [Remote External flash memory support via UART](remote_flash.md)
|
|
|
|
#### Encryption support for external partitions
|
|
|
|
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.
|
|
|
|
For more details about this optional feature, please refer to the [Encrypted external partitions](encrypted_partitions.md) manual page.
|
|
|
|
|
|
### Executing flash access code from RAM
|
|
|
|
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.
|
|
|
|
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).
|
|
|
|
### Enable Dual-bank hardware-assisted swapping
|
|
|
|
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.
|
|
|
|
|
|
### Store UPDATE partition flags in a sector in the BOOT partition
|
|
|
|
By default, wolfBoot keeps track of the status of the update procedure to the single sectors in a specific area at the end of each partition, dedicated
|
|
to store and retrieve a set of flags associated to the partition itself.
|
|
|
|
In some cases it might be helpful to store the status flags related to the UPDATE partition and its sectors in the internal flash, alongside with
|
|
the same set of flags used for the BOOT partition. By compiling wolfBoot with the `FLAGS_HOME=1` makefile option, the flags
|
|
associated to the UPDATE partition are stored in the BOOT partition itself.
|
|
|
|
While on one hand this option slightly reduces the space available in the BOOT partition to store the firmware image, it keeps all the flags in
|
|
the BOOT partition.
|
|
|
|
### Flash Erase value / Flag logic inversion
|
|
|
|
By default, most NVMs set the content of erased pages to `0xFF` (all ones).
|
|
|
|
Some FLASH memory models use inverted logic for erased page, setting the content to `0x00` (all zeroes) after erase.
|
|
|
|
For these special cases, the option `FLAGS_INVERT = 1` can be used to modify the logic of the partition/sector flags used in wolfBoot.
|
|
|
|
You can also manually override the fill bytes using `FILL_BYTE=` at build-time. It default to `0xFF`, but will use `0x00` if `FLAGS_INVERT` is set.
|
|
|
|
Note: if you are using an external FLASH (e.g. SPI) in combination with a flash with inverted logic, ensure that you store all the flags in one partition, by using the `FLAGS_HOME=1` option described above.
|
|
|
|
### Using One-time programmable (OTP) flash as keystore
|
|
|
|
By default, keys are directly incorporated in the firmware image. To store the keys in a separate, one-time programmable (OTP) flash memory, use the `FLASH_OTP_KEYSTORE=1` option.
|
|
For more information, see [/docs/OTP-keystore.md](/docs/OTP-keystore.md).
|
|
|
|
### Prefer multi-sector flash erase operations
|
|
|
|
wolfBoot HAL flash erase function must be able to handle erase lengths larger than `WOLFBOOT_SECTOR_SIZE`, even if the underlying flash controller does not. However, in some cases, wolfBoot defaults to
|
|
iterating over a range of flash sectors and erasing them one at a time. Setting the `FLASH_MULTI_SECTOR_ERASE=1` config option prevents this behavior when possible, configuring wolfBoot to instead prefer a
|
|
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.
|
|
|
|
### Building with the ARM Compiler for Embedded (armclang)
|
|
|
|
wolfBoot can be built with the [ARM Compiler for Embedded](https://developer.arm.com/Tools%20and%20Software/Arm%20Compiler%20for%20Embedded)
|
|
(AC6: `armclang`, `armlink`, `armar`, `fromelf`), the toolchain used by Keil
|
|
MDK. No tool from the GNU or LLVM toolchains is required.
|
|
|
|
At the moment, the only supported and tested target is the STM32U5
|
|
(`config/examples/{stm32u5.config,stm32u5-wolfcrypt-tz.config}`).
|
|
|
|
To use this, either have the AC6 tools in your `PATH` or set `ARMCLANG_PATH` to
|
|
their location (including a trailing slash). Then build with USE_ARMCLANG=1:
|
|
|
|
```
|
|
cp config/examples/stm32u5.config .config
|
|
make USE_ARMCLANG=1
|
|
```
|
|
|
|
Alternatively, append `USE_ARMCLANG=1` and/or `ARMCLANG_PATH` to your `.config`.
|
|
|
|
### Using Mac OS/X
|
|
|
|
If you see 0xC3 0xBF (C3BF) repeated in your factory.bin then your OS is using Unicode characters.
|
|
|
|
The "tr" command for assembling the 0xFF padding between `"bootloader" ... 0xFF ... "application" = factory.bin`, which requires the "C" locale.
|
|
|
|
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=
|
|
```
|
|
|
|
Then run the normal `make` steps.
|
|
|
|
### Building Against Alternate Library Dependency Versions
|
|
|
|
wolfBoot includes its internal dependencies (all official wolfSSL projects) as git submodules under `lib/`, ensuring known-compatible versions. You may override these paths with `WOLFBOOT_LIB_XXX` environment variables to point to local copies of the libraries.
|
|
|
|
Note that all paths MUST be supplied to the Makefiles as absolute paths.
|
|
|
|
Available overrides:
|
|
|
|
- `WOLFBOOT_LIB_WOLFSSL`: Path to the [wolfSSL](https://github.com/wolfSSL/wolfssl) library source code
|
|
- `WOLFBOOT_LIB_WOLFTPM`: Path to the [wolfTPM](https://github.com/wolfSSL/wolfTPM) library source code
|
|
- `WOLFBOOT_LIB_WOLFPKCS11`: Path to the [wolfPKCS11](https://github.com/wolfssl/wolfpkcs11) library source code
|
|
- `WOLFBOOT_LIB_WOLFPSA`: Path to the wolfPSA library source code
|
|
- `WOLFBOOT_LIB_WOLFHSM`: Path to the [wolfHSM](https://github.com/wolfSSL/wolfHSM) library source code
|
|
|
|
## Key Generation and Signing
|
|
|
|
### Default Key Behavior
|
|
|
|
When building wolfBoot for the first time, the build system automatically generates the cryptographic keys needed for firmware signing and verification.
|
|
|
|
- **Private Key**: `wolfboot_signing_private_key.der` - Used to sign firmware images
|
|
- **Keystore**: `src/keystore.c` - Contains the public key embedded in the bootloader
|
|
|
|
The key algorithm is determined by the `SIGN` variable (e.g., `SIGN=ECC256`, `SIGN=RSA2048`).
|
|
|
|
For most targets, the makefile also builds the wolfBoot test app and signs it with the aforementioned key.
|
|
|
|
### Pre-existing Local Keys for Test App Builds
|
|
|
|
The `USER_*` Makefile variables provide a convenience for building the test app with your own locally-managed keys, avoiding the need to manually run `keygen -i` and place key files before building.
|
|
|
|
**Note:** If your private key is managed by a third party (e.g., HSM-as-a-service, Azure KeyVault) and you only have access to the public key, use the `keygen -i` option instead. See [Signing.md](Signing.md#keygen-tool) and [Manual Key Management](#manual-key-management) below.
|
|
|
|
The following variables are available:
|
|
|
|
- `USER_PRIVATE_KEY`: Path to your private signing key (DER format)
|
|
- `USER_PUBLIC_KEY`: Path to your public key (DER format)
|
|
|
|
**Usage:**
|
|
|
|
```sh
|
|
make USER_PRIVATE_KEY=/path/to/my-signing-key.der \
|
|
USER_PUBLIC_KEY=/path/to/my-public-key.der
|
|
```
|
|
|
|
#### Requirements
|
|
|
|
- Both `USER_PRIVATE_KEY` and `USER_PUBLIC_KEY` must be provided together
|
|
- Keys must be in DER format appropriate for the selected `SIGN` algorithm
|
|
|
|
When these variables are specified, the build:
|
|
|
|
1. Skips auto-generation of `wolfboot_signing_private_key.der`
|
|
2. Generates the keystore (`src/keystore.c`) from your public key via `keygen -i`
|
|
3. Uses your private key to sign the test app
|
|
|
|
This is primarily useful when you want a single `make` invocation to build wolfBoot and a signed test app using keys you've generated externally. For wolfBoot-only builds (without the test app), the main benefit is automating the `keygen -i` step for simple single-key keystores. If you need multiple keys in the keystore then you must invoke `keygen -i` manually before building wolfBoot.
|
|
|
|
### Pre-existing Certificate Chain for Test App Builds
|
|
|
|
When building the test app using certificate chain verification (`CERT_CHAIN_VERIFY=1`), you can provide your own certificate chain:
|
|
|
|
- `USER_CERT_CHAIN`: Path to your certificate chain (DER format, leaf cert last)
|
|
|
|
**Usage:**
|
|
|
|
```sh
|
|
make CERT_CHAIN_VERIFY=1 \
|
|
USER_PRIVATE_KEY=/path/to/leaf-signing-key.der \
|
|
USER_PUBLIC_KEY=/path/to/leaf-public-key.der \
|
|
USER_CERT_CHAIN=/path/to/my-cert-chain.der
|
|
```
|
|
|
|
**Requirements:**
|
|
|
|
- `USER_CERT_CHAIN` requires both `USER_PRIVATE_KEY` and `USER_PUBLIC_KEY`
|
|
- The private and public keys must correspond to the leaf certificate identity in the chain
|
|
|
|
When `CERT_CHAIN_VERIFY=1` is set without `USER_CERT_CHAIN`, the build auto-generates a dummy 3-tier certificate hierarchy in `test-dummy-ca/` for testing. This also applies to wolfHSM NVM image generation when applicable.
|
|
|
|
### Manual Key Management
|
|
|
|
For advanced scenarios (multiple keys, mixed algorithms, partition-restricted keys, or third-party managed private keys), use the `keygen` tool directly instead of the `USER_*` variables.
|
|
|
|
**Importing a public key (when private key is externally managed):**
|
|
|
|
```sh
|
|
./tools/keytools/keygen --ecc256 -i my-public-key.der
|
|
```
|
|
|
|
This creates `src/keystore.c` from your public key. Signing must then be performed in two steps following the steps outlined in [Signing.md](./Signing.md#signing-firmware-with-external-private-key-hsm)
|
|
|
|
|
|
**Using locally-managed keys without `USER_XXX` variables:**
|
|
|
|
1. Import your public key to generate the keystore:
|
|
```sh
|
|
./tools/keytools/keygen --ecc256 -i my-public-key.der
|
|
```
|
|
|
|
2. Place your signing key at the expected location:
|
|
```sh
|
|
cp my-private-key.der wolfboot_signing_private_key.der
|
|
```
|
|
|
|
Now the build system detects existing files and skips auto-generation when building wolfBoot and the test app.
|
|
|
|
**Multiple keys and advanced keystores:**
|
|
|
|
The `keygen` tool supports multiple `-g` (generate) and `-i` (import) arguments, mixed key algorithms, and partition ID restrictions. See [keystore.md](keystore.md) for full details on keystore capabilities. When using these advanced features, image signing via the `sign` tool must also be performed manually.
|