Signature keys
A signature key can be used by nRF Secure Immutable Bootloader to validate the next image in the boot chain. Dedicated host tools like Image tool can be used to sign application update images.
When you use nRF Secure Immutable Bootloader, a private/public key pair is by default generated during the build when you are Adding a custom signature key file. You can use the methods described in the following sections to explicitly define how the key pair is to be generated.
When you use MCUboot or you are Adding MCUboot as an upgradable bootloader, MCUboot uses keys that were generated once and are stored in the public MCUboot Git repository by default.
Note
These key pairs should only be used during development. See Using development keys for more details.
Generating private keys
The nRF Connect SDK supports the following most common ways to generate private/public key pairs:
Caution
The security of the firmware update process depends on the secrecy of the private key. You must prevent unauthorized access to the private key.
Using OpenSSL to generate keys
OpenSSL is installed by default with some packages and programs, such as Git.
It supports many different types of keys, but not all of them are supported by nRF Secure Immutable Bootloader and MCUboot.
To see a complete list of the key types supported by OpenSSL, call openssl help
and openssl <key type> -help
from a terminal.
For a complete list of the key types supported by each bootloader, see the following table:
Bootloader |
Supported key types |
---|---|
nRF Secure Immutable Bootloader |
ECDSA-P256 |
MCUboot |
RSA-2048, RSA-3072, ECDSA-P256, ED25519 |
Examples of using OpenSSL to create some commonly used key types:
openssl ecparam -name prime256v1 -genkey -noout -out priv.pem
openssl genrsa -out priv.pem 2048
Note
priv.pem
, priv_*.pem
, and pub_*.pem
are keys named arbitrarily and used as an example in this documentation.
You can name private and public keys used with Zephyr and the nRF Connect SDK as you prefer, as long as the files are in the .pem
format.
Using Imgtool to generate keys
Image tool is a Python tool maintained by MCUboot that handles public/private key pairs.
It is also available as a PyPI package that you can install using pip
.
However, when working within the nRF Connect SDK framework, it is recommended to use the script that is included in the fork of MCUboot used by the nRF Connect SDK.
Examples of imgtool used to create some commonly used key types:
python3 bootloader/mcuboot/scripts/imgtool.py keygen -t ecdsa-p256 -k priv.pem
python3 bootloader/mcuboot/scripts/imgtool.py keygen -t rsa-2048 -k priv.pem
For a full list of supported types, use the --help
argument with the tool or any of its commands.
Using development keys
When testing the bootloader chain, you can optionally generate and use custom signing keys. If you do not provide your own keys through Kconfig options, the build system automatically creates debug keys, depending on the bootloaders compiled into the application.
Caution
Keys that are automatically used or generated by bootloaders for image signature validation are intended for development or debug use only.
You should never send applications into production when they are not protected by secure keys. You must always create and store these keys in a safe location, not only to protect the security of the application but also to ensure that the hardware can receive firmware updates throughout the project lifecycle.
While the default keys for MCUboot are tracked in its repository and are therefore publicly visible, the development/debug keys autogenerated by nRF Secure Immutable Bootloader change whenever the build directory is removed and rebuilt from scratch. If you are not programming the nRF Secure Immutable Bootloader when this happens, relying on the default ECDSA key to sign an application or an upgradable second-stage bootloader image results in a failed boot chain validation.
You can avoid this issue by storing a custom private key outside of the build directory during development.
Revoking private keys
The nRF Secure Immutable Bootloader allows you to revoke public verification keys used to validate the next image in the secure boot chain. Key revocation can be a useful security measure for devices that have already been deployed to the field. If a private key has been compromised or lost, you can invalidate its public key by uploading a new firmware image signed by another key known to the bootloader.
These keys are kept internally by the bootloader, so the list of available public keys cannot change once it is deployed.
See CONFIG_SB_PUBLIC_KEY_FILES
for details on how this mechanism is implemented.
You can add this feature to your own project and check its functionality as follows:
Generate two or more private keys for the application and extract a public key for each one (for example, using OpenSSL).
Compile the application and bootloader with the relevant configurations, using only absolute paths:
CONFIG_SECURE_BOOT=y CONFIG_SB_SIGNING_KEY_FILE="/path/to/priv_a.pem" CONFIG_SB_PUBLIC_KEY_FILES="/path/to/pub_b.pem,/path/to/pub_c.pem"
Caution
The public key associated with the original private signing key must not be included in the public key list.
Program the application to the target development kit and check its console output. With the first firmware version,
priv_a.pem
andpub_a.pem
are used for signing and validating the image.*** Booting Zephyr OS build ... *** Attempting to boot slot 0. Attempting to boot from address 0x9000. Verifying signature against key 0. Hash: 0xda...4f Firmware signature verified. Firmware version 1 *** Booting Zephyr OS build ... *** ...
To revoke keys, rebuild the application modifying the configuration setting to use the private key associated with a key listed after the currently used key in the list.
CONFIG_BUILD_S1_VARIANT=y CONFIG_SB_SIGNING_KEY_FILE="/path/to/priv_c.pem" CONFIG_FW_INFO_FIRMWARE_VERSION=2
In this example, when compiling with the
priv_c.pem
key, images signed withpriv_a.pem
orpriv_b.pem
no longer boot when uploaded into an image slot. Additionally, a firmware version higher than the previous one has been set.Deploy the firmware update.
Observe the bootloader checking the hashes of the public keys against the new image, then invalidating the earlier keys:
*** Booting Zephyr OS build ... *** Attempting to boot slot 1. Attempting to boot from address 0x84800. Verifying signature against key 0. Hash: 0xda...4f Public key didn't match, try next. Verifying signature against key 1. Hash: 0x5c...f5 Public key didn't match, try next. Verifying signature against key 2. Hash: 0x19...73 Invalidating key 0. Invalidating key 1. Firmware signature verified. Firmware version 2 Setting monotonic counter (version: 2, slot: 1) *** Booting Zephyr OS build ... *** ...
To test that the bootloader no longer boots images signed with the earlier keys, upload an image signed with one of them.
Recompile the application with the following options:
CONFIG_SB_SIGNING_KEY_FILE="/path/to/priv_b.pem" CONFIG_FW_INFO_FIRMWARE_VERSION=3
To facilitate testing, use nrfjprog to program this image directly into a slot:
nrfjprog -f nRF52 -r --verify --program build/zephyr/signed_by_b0_s0_image.hex --sectorerase
Observe the bootloader skipping the invalid image and booting the valid image in the other slot:
*** Booting Zephyr OS build ... *** Attempting to boot slot 0. Attempting to boot from address 0x9000. Key 0 has been invalidated, try next. Key 1 has been invalidated, try next. Verifying signature against key 2. Hash: 0x19...73 Public key didn't match, try next. Failed to validate signature. Failed to validate, permanently invalidating! Attempting to boot slot 1. Attempting to boot from address 0x84800. Key 0 has been invalidated, try next. Key 1 has been invalidated, try next. Verifying signature against key 2. Hash: 0x19...73 Invalidating key 0. Invalidating key 1. Firmware signature verified. Firmware version 2 *** Booting Zephyr OS build ... *** ...
Recompile with priv_c.pem
and the incremented firmware version to correctly boot the new image.