i.MX RT1170 MCUboot-Custom ECDSA Keys and Direct-XIP OTA Validation Abstract This article uses the MIMXRT1170-EVKB platform to demonstrate how to generate a custom ECDSA-P256 key pair for MCUboot, replace the default public key in the mcuboot_opensource project, and re-sign application images with the new private key. It then uses the Shell and XMODEM functions provided by ota_mcuboot_basic to transfer a candidate image to the Secondary Slot. MCUboot performs signature verification, image-state checks, and version selection, and uses Flash Remap to support Direct-XIP execution. The results show that an image signed with the old key cannot be verified by the new public key, while a higher-version LED image signed with the new private key can be written to the Secondary Slot and started directly through Flash Remap. Important: The addresses, slot sizes, and commands in this article apply to the RT1170 example project used in this validation. Before porting the procedure to another project, verify the linker script, Flash partitioning, and MCUboot configuration.
1. Why Replace the Default Signing Key?
The MCUboot example key included in the NXP MCUXpresso SDK is intended for development and validation only. Because it is publicly available, it is not suitable for production releases.
For production, the release owner should securely protect the private key and compile only the corresponding public key into the bootloader.
After the public key is replaced, images signed with the old private key should fail signature verification, confirming that the new key has taken effect.
Signature verification, version management, and image confirmation serve different purposes—ensuring a trusted source, selecting an upgrade image, and managing runtime state, respectively—and cannot replace one another.
2. Platform Configuration and Scope
mayliu1_0-1788425630240.png
3. Flash Layout
mayliu1_1-1788425733701.png
Each signed image contains a 0x400-byte MCUboot header that records boot metadata such as the image size and version. At power-on, MCUboot checks the images in both slots, parses the header and TLV area, verifies image integrity and the ECDSA signature, and evaluates image state and version. In the test configuration used here, images are generated with --confirm. Among images that satisfy the signature and state requirements, MCUboot selects the higher version that complies with the upgrade policy. This behavior applies only to this test configuration and does not represent every MCUboot state or upgrade policy. In DIRECT-XIP + FLASH REMAP mode, if the selected image is stored in the non-default mapped slot, MCUboot configures Flash Remap before jumping to the application. This maps the image's physical storage region to the logical execution address expected by the application, allowing in-place execution without copying or swapping images.
4. MCUboot Signature Verification Fundamentals
mayliu1_2-1788425782498.png mayliu1_3-1788425834698.png
Important: A hash detects content changes; a digital signature verifies image origin and integrity; the version number identifies and compares image releases; and the Confirm state determines whether a test image is retained permanently.
5. Generate an ECDSA-P256 Private Key in the scripts Directory
imgtool.py is located in the middleware\mcuboot_opensource\scripts directory of the MCUXpresso SDK. Change to this directory before running the key-generation command. Replace <SDK_INSTALL_PATH> with the actual SDK installation path on your computer:
<SDK_INSTALL_PATH>\middleware\mcuboot_opensource\scripts
python imgtool.py keygen ^ -k my_priv.pem ^ -t ecdsa-p256
dir my_priv.pem
keygen: Generates a new key.
-k my_priv.pem: Specifies the output key file.
-t ecdsa-p256: Selects the ECDSA-P256 algorithm.
After the command completes successfully, the private key is generated as middleware\mcuboot_opensource\scripts\my_priv.pem.
Security reminder: In a production project, never compile the private key into the bootloader, program it into the MCU, commit it to a regular Git repository, or distribute it with the SDK project. Store only the public key in the bootloader.
6. Export and Replace the MCUboot Public Key
python imgtool.py getpub -k my_priv.pem
python imgtool.py getpub -k my_priv.pem > my_pub.c
mayliu1_4-1788425906827.png
The command outputs a C array that can be compiled by MCUboot. The key symbols are:
const unsigned char ecdsa_pub_key[] = { 0x30, 0x59, ... }; const unsigned int ecdsa_pub_key_len = 91;
The public-key source file replaced in this article is:
evkbmimxrt1170_mcuboot_opensource_cm7\bootutil\nxp_port\keys\sign-ecdsa-p256-pub.c
mayliu1_5-1788425939863.png
Back up the original public-key file, and do not include the backup copy in the project build.
Replace the original public-key array with the output from getpub.
Keep the ecdsa_pub_key and ecdsa_pub_key_len symbol names consistent with the project references.
Clean and rebuild evkbmimxrt1170_mcuboot_opensource_cm7.
Program the new bootloader at 0x30000000.
7. Negative Validation: Images Signed with the Old Key Are Rejected
Replace only the signature-verification public key in MCUboot, rebuild and program the updated bootloader, and leave the existing application image in Flash without re-signing it with the new private key. Because the image is still signed with the old private key while MCUboot now verifies it with the new public key, the key pair does not match. The image therefore fails signature verification and is classified as invalid. In the project configuration used here, the bootloader then erases the invalid image. This negative test confirms that the new public key has been compiled into MCUboot correctly and is actively used during boot verification.
If the image signed with the old key is classified as invalid, the new public key has been compiled correctly and is being used for MCUboot verification.
Successfully parsing the image header and reading the version only proves that the image structure is recognizable; it does not mean signature verification passed.
A digital signature generated with the old private key cannot be verified by a nonmatching new public key.
The version number is used only for image identification and upgrade selection. It cannot replace signature verification; even an image with a correct or higher version will not boot if signature verification fails.
mayliu1_6-1788425987887.png
8. Sign the ota_mcuboot_basic Image with the New Private Key
python imgtool.py sign ^ --key my_priv.pem ^ --align 4 ^ --version 1.4.0 ^ --slot-size 0x200000 ^ --header-size 0x400 ^ --pad-header ^ --pad ^ --confirm ^ evkbmimxrt1170_ota_mcuboot_basic_cm7.bin ^ ota_mcuboot_basic_1_4_0_confirmed.SIGNED.bin
evkbmimxrt1170_ota_mcuboot_basic_cm7.bin is the raw application image generated by the Basic project. In this example, --confirm is added so that the image is generated with the Confirmed state.
Note the following:
Notes on --confirm and Production Deployment
The README states that an initial image manually programmed together with the bootloader requires the additional --pad and --confirm options. Otherwise, the bootloader may reject the image because the trailer lacks the required state information.
mayliu1_15-1788426931903.png
--pad pads the image to the size specified by --slot-size and creates the slot trailer required by MCUboot. --confirm presets the image_ok flag in the trailer to the confirmed state while the image is generated. MCUboot therefore treats the initial image as a confirmed valid image at boot.
Production recommendation: This usage is intended mainly for the initial image manually programmed together with the bootloader. It is not recommended for production OTA images. Pre-confirming an update image with --confirm bypasses MCUboot's test boot → image confirmation → failure rollback flow. If the new image cannot boot, fails peripheral initialization, or encounters a critical application error, MCUboot cannot use the unconfirmed state to roll back automatically, which may leave the device unrecoverable.
The MCUboot bootloader primarily reads the image_ok flag in the trailer and uses it for image-state evaluation, version selection, and rollback handling. It does not proactively write the confirmation flag on behalf of the application. The running application should explicitly confirm the image at an appropriate time. For example, after the candidate application completes its startup self-test, peripheral initialization, and critical functional checks, it can call boot_set_confirmed(). An application with Shell support, such as ota_mcuboot_basic, can also be confirmed manually with the image accept command. This preserves MCUboot's test-boot and failure-rollback capabilities and prevents a faulty image from being marked permanently valid too early.
python imgtool.py dumpinfo ota_mcuboot_basic_1_4_0_confirmed.SIGNED.bin
Check the magic, hdr_size, img_size, version, and TLV information in the output. The TLV area should contain SHA256, KEYHASH, and ECDSASIG, which represent the image digest, public-key identifier, and ECDSA signature respectively.
mayliu1_7-1788426037161.png
mayliu1_8-1788426047750.png
9. Program the Signed ota_mcuboot_basic Image into the Primary Slot
This article uses ota_mcuboot_basic_1_4_0_confirmed.SIGNED.bin, generated in the previous section, as the initial image in the Primary Slot. ota_mcuboot_basic provides the Shell and XMODEM image-receive functions. After it starts, the application can transfer subsequent candidate images to the Secondary Slot. Program the signed image containing the complete MCUboot header, application payload, and signature TLV—not the raw BIN generated directly by the application project.
File to program: ota_mcuboot_basic_1_4_0_confirmed.SIGNED.bin Programming address: 0x30040000
Program the complete signed image at the Primary Slot start address, 0x30040000.
Reset the device and inspect the MCUboot log to confirm that signature verification succeeds and the version is read correctly.
Confirm that the device enters the ota_mcuboot_basic Shell and that image info reports the image state.
mayliu1_9-1788426071107.png mayliu1_10-1788426078668.png
10. Generate a Candidate Signed Image for the Secondary Slot
This article creates an LED application project and uses it as the candidate image for the Secondary Slot. The image is signed with the newly generated private key, my_priv.pem, and assigned a version later than the currently running image. In DIRECT-XIP + FLASH REMAP mode, both the LED and ota_mcuboot_basic projects are linked to the same logical addresses: the signed image begins logically at 0x30040000, and the application vector table is at 0x30040400. The signed LED image is physically written to the Secondary Slot at 0x30240000, with its vector table physically located at 0x30240400. When MCUboot selects this image, Flash Remap maps the Secondary Slot to the logical execution address expected by the application.
Therefore, the Secondary Slot identifies the image's physical storage location, while the application still executes using the logical addresses associated with the Primary Slot.
mayliu1_11-1788426129177.png
python imgtool.py sign ^ --key my_priv.pem ^ --align 4 ^ --version 1.5.0 ^ --slot-size 0x200000 ^ --header-size 0x400 ^ --pad-header ^ --pad ^ --confirm ^ evkbmimxrt1170_igpio_led_output_cm7_second_app.bin ^ ota_led_output_second_app_1_5_0_confirmed.SIGNED.bin
--key my_priv.pem: Uses the private key paired with the public key currently trusted by MCUboot.
--version 1.5.0: Sets the candidate image version, which must be later than the currently running version 1.4.0.
--slot-size 0x200000: Matches the slot size in the current Flash partition layout.
--header-size 0x400 and --pad-header: Reserve and populate the 0x400-byte MCUboot header area at the beginning of the image.
--pad: Pads the output to the full size specified by --slot-size and reserves the image trailer area. Whether the image is pre-confirmed is controlled by --confirm.
--confirm: Generates the candidate image in the Confirmed state.
python imgtool.py dumpinfo ota_led_output_second_app_1_5_0_confirmed.SIGNED.bin
Before transfer, verify that the output reports valid magic, hdr_size, img_size, version, and TLV information. In particular, confirm that the version is 1.5.0+0 and that the TLV area contains SHA256, KEYHASH, and ECDSASIG. After the checks pass, use the complete ota_led_output_second_app_1_5_0_confirmed.SIGNED.bin file in the next section. The ota_mcuboot_basic application transfers it to the Secondary Slot through XMODEM.
11. Transfer the Signed Image to the Secondary Slot Using XMODEM
Start the development board, enter the Basic Shell, and run the xmodem command.
In the serial terminal, select File → Transfer → XMODEM, select ota_led_output_second_app_1_5_0_confirmed.SIGNED.bin, and start the transfer.
After the transfer completes, run image info and verify the version and image state in the Secondary Slot.
mayliu1_12-1788426170015.png
12. Inspect the Candidate Image and Validate Version Switching
image info reboot
After reboot, inspect the MCUboot log for the Primary and Secondary versions, confirmation states, and selected boot slot. In the test configuration used here, the candidate image is pre-confirmed with --confirm. It must pass signature verification, satisfy the Confirmed-state requirements, and have a later version that complies with the upgrade policy. A valid signature means only that the image source is trusted and the content is intact; it does not guarantee that the image will be selected. Once all conditions are met, MCUboot boots the candidate image. In Direct-XIP + Flash Remap mode, the image can execute in place from the Secondary Slot without being copied or swapped.
mayliu1_13-1788426200879.png
mayliu1_14-1788426207996.png
13. Summary
Generate and securely store a project-specific ECDSA-P256 private key, and compile the corresponding public key into the MCUboot project.
Confirm that key replacement is effective by verifying that images signed with the old key fail while images signed with the new private key pass.
Use the signed ota_mcuboot_basic image as the initial Primary Slot image and the later-version signed LED image as the Secondary Slot update image.
Transfer the complete signed image to the Secondary Slot through XMODEM and validate the MCUboot flow that starts the update image through Flash Remap.
For production OTA, remove --confirm and have the application write image_ok by calling boot_set_confirmed() after successful self-tests, preserving MCUboot's automatic rollback capability.
記事全体を表示