wolfBoot Key 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.
C or Python
The tools are distributed in two versions, using the same command line syntax, for portability reasons.
By default, C keytools are compiled. The makefiles and scripts in this repository will use the C tools.
C Key Tools
A standalone C version of the key tools is available in: ./tools/keytools.
These can be built in tools/keytools using make or from the wolfBoot root using make keytools.
If the C version of the key tools exists they will be used by wolfBoot's makefile and scripts.
Windows Visual Studio
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.
Python key tools
Please note that the Python tools are deprecated and will be removed in future versions.
In order to use the python key tools, ensure that the wolfcrypt package is
installed in your python environment. In most systems it's sufficient to run a
command similar to:
pip install wolfcrypt
to ensure that the dependencies are met.
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.
Two options are supported:
-g privkey.derto generate a new keypair, add the public key to the keystore and save the private key in a new fileprivkey.der-i existing.derto import an existing public key fromexisting.der--dersave generated private key in DER format.
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.imgthat can be used to provision the public keys through an alternative storage - The private key, for each 
-goption provided from command line 
For more information about the keystore mechanism, see Appendix D.
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
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.
- 
--ed25519Use ED25519 for signing the firmware. Assume that the given KEY.DER file is in this format. - 
--ed448Use ED448 for signing the firmware. Assume that the given KEY.DER file is in this format. - 
--ecc256Use ecc256 for signing the firmware. Assume that the given KEY.DER file is in this format. - 
--ecc384Use ecc384 for signing the firmware. Assume that the given KEY.DER file is in this format. - 
--ecc521Use ecc521 for signing the firmware. Assume that the given KEY.DER file is in this format. - 
--rsa2048Use rsa2048 for signing the firmware. Assume that the given KEY.DER file is in this format. - 
--rsa3072Use rsa3072 for signing the firmware. Assume that the given KEY.DER file is in this format. - 
--rsa4096Use rsa4096 for signing the firmware. Assume that the given KEY.DER file is in this format. - 
--lmsUse LMS/HSS for signing the firmware. Assume that the given KEY.DER file is in this format. - 
--xmssUse XMSS/XMSS^MT for signing the firmware. Assume that the given KEY.DER file is in this format. - 
--no-signDisable 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.
- 
--sha256Use sha256 for digest calculation on binary images and public keys. - 
--sha348Use sha384 for digest calculation on binary images and public keys. - 
--sha3Use 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 NSet image partition id to "N". - 
--wolfboot-updateIndicate 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.BINuse the file SHAREKEY.BIN to encrypt the image.
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.
See options below.
- 
--chachaUse 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. - 
--aes128Use 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. - 
--aes256Use 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. 
Delta updates (incremental updates from a known version)
An incremental update is created using the sign tool when the following option is provided:
--delta BASE_SIGNED_IMG.BINThis option creates a binary diff file betweenBASE_SIGNED_IMG.BINand the new image signed starting fromIMAGE.BIN. The result is stored in a file ending in_signed_diff.bin.
The compression scheme used is Bentley–McIlroy.
Policy signing (for sealing/unsealing with a TPM)
Provides a PCR mask and digest to be signed and included in the header. The signing key is used to sign the digest.
--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-signthen the file should contain the 4-byte PCR mask and signature. The PCR mask and signature will be included in theHDR_POLICY_SIGNATUREheader tag. A copy of the final signed policy (including 4 byte PCR mask) will be output to[inputname].sig. Note: This may require increasing theIMAGE_HEADER_SIZEas two signatures will be stored in the header.
Adding custom fields to the manifest header
Provides a value to be set with a custom tag
- 
--custom-tlv tag len val: Adds a TLV entry to the manifest header, corresponding to the type identified bytag, with lengthlenbytes, and assigns the valueval. 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 bytag, and assigns the valuevalue. 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 AABBCCDDEEwill 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 bytag, and assigns the value ofascii-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 theascii-string.ascii-stringargument 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-onlyWhen 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.binis 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-signWhen 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, soIMAGE_SIGNATURE.SIG 
For a real-life example, see the section below.
Examples
Signing Firmware
- Load the private key to use for signing into 
./wolfboot_signing_private_key.der - Run the signing tool with asymmetric algorithm, hash algorithm, file to sign, key and version.
 
./tools/keytools/sign --rsa2048 --sha256 test-app/image.bin wolfboot_signing_private_key.der 1
Note: The last argument is the “version” number.
Signing Firmware with External Private Key (HSM)
Steps for manually signing firmware using an external key source.
# Create file with Public Key
openssl rsa -inform DER -outform DER -in my_key.der -out rsa2048_pub.der -pubout
# Add the public key to the wolfBoot keystore using `keygen -i`
./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
# 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
# Generate final signed binary
./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
Signing Firmware with Azure Key Vault
See Appendix B.