Skip to content

MCUboot Signing

In order to do MCUboot signing/encryption following actions/configurations are required

  • Product is created with a configuration which supports MCUboot signing & encryption.

Input data for MCUboot signing

Input data is a gzipped tar file containing a configuration request.json file and other input files. Multiple images might be generated by a single signing operation. Most JSON fields are mandatory as they are always required for MCUboot imgtool.

Supported options from imgtool:

Option JSON data type Required Comment
align String Yes 1, 2, 4 or 8.
version String Yes Firmware version, for example 1.6.44+1628771740.
header_size String Yes Header size, for example 0x200.
slot_size String Yes Size of the slot. If the slots have different sizes, use the size of the secondary slot.
pad_header Boolean No Add header_size zeroed bytes at the beginning of the image.
security_counter String No Specify the value of security counter. Use the auto keyword to automatically generate it from the image version.
Option JSON data type Required Comment
boot_record String No Create CBOR encoded boot record TLV. The sw_type represents the role of the software component (e.g. CoFM for coprocessor firmware). [max. 12 characters].
public_key_format String No In what format to add the public key to the image manifest: full key or hash of the key. Allowed values [hash|full]. full is default.
pad Boolean No Pad image to slot_size bytes, adding trailer magic. Default value is true.
confirm Boolean No When padding the image, mark it as confirmed (implies pad).
max_sectors String No When padding allow for this amount of sectors (defaults to 128). String value is converted to integer value.
overwrite_only Boolean No Use overwrite-only instead of swap upgrade.
max_align String No Maximum flash alignment. Set if flash alignment of the primary and secondary slot differ and any of them is larger than 8. Allowed values [8|16|32].
save_enctlv Boolean No When upgrading, save encrypted key TLVs instead of plain keys. Enable when BOOT_SWAP_SAVE_ENCTLV config option was set.
load_addr String No Load address for image when it should run from RAM.
hex_addr String No Adjust address in hex output file.
encrypt Boolean No Encrypt the image with the AES key created in EncryptMcuBoot operation
encrypt_keylen String No Optional. When encrypting the image using AES this option can be used to override the token length. Only usefull if user wants to use first 128 bits from the 256 bit token. If token bit lenght is 256 and encrypt_keylen is 128 an error is returned. If this option is not present the actual token lenght is used. Allowed values [128|256].
clear Boolean No Output a non-encrypted image with encryption capabilities,so it can be installed in the primary slot, and encrypted when swapped to the secondary.

request.json:

{
  "images": [
  {
     "filename": "app-1-6-44-1628771740.hex",
     "output": "signed-app-1-6-44-1628771740.hex",
     "align": "4",
     "version": "1.6.44+1628771740",
     "header_size": "0x200",
     "slot_size": "0xea000",
     "pad_header": true
    },
    {
      "filename": "app-1-6-44-1628771740.hex",
      "output": "signed-app-1-6-44-1628771740-scauto.bin",
      "align": "4",
      "version": "1.6.44+1628771740",
      "header_size": "0x200",
      "slot_size": "0xea000",
      "pad_header": true,
      "security_counter": "auto"
    },
    {
      "filename": "app-1-6-44-1628771740.hex",
      "output": "signed-app-1-6-44-1628771740-sc.bin",
      "align": "4",
      "version": "1.6.44+1628771740",
      "header_size": "0x200",
      "slot_size": "0xea000",
      "pad_header": true,
      "security_counter": "0x3ff2"
    },
    {
      "filename": "app-1-6-44-1628771740.hex",
      "output": "signed-app-1-6-44-1628771740.bin",
      "align": "4",
      "version": "1.6.44+1628771740",
      "header_size": "0x200",
      "slot_size": "0xea000",
      "pad_header": true,
      "security_counter": "0x3ff2",
      "pad": false,
      "confirm": true,
      "overwrite_only": true,
      "max_align": "8",
      "public_key_format": "full",
      "boot_record": "SDE",
      "max_sectors": "128",
      "save_enctlv": true,
      "load_addr": "0x3ff2",
      "hex_addr": "0x3ff2",
      "erased_val": "0"
    },
    {
    "filename": "tfm_s_zephyr_ns.hex",
    "output": "tfm_s_zephyr_ns_encrypted.hex",
    "header_size": "0x400",
    "align": "16",
    "slot_size": "0x1a0000",
    "version": "0.1.0+1234567",
    "security_counter": "auto",
    "pad": true,
    "pad_header": true,
    "boot_record": "SPE",
    "public_key_format": "full",
    "encrypt": true,
    "encrypt_keylen": "256"
    }
  ]
}

Example of tfm_zephyr_mcuboot_enc payload

$ tar -tvf tfm_zephyr_mcuboot_enc.tar.gz
-rw-rw-r--  1 vagrant vagrant    1944 Apr 26  2024 request.json
-rwxrwxr-x  1 vagrant vagrant 2856046 Nov 20  2023 tfm_s_zephyr_ns.hex

Output data

The output download is already in binary format. See example below.

Example response with validation

The public key used for verification can be obtained using the client functionality

(venv) $ signing-tool -c -t $TOKEN -a https://app.laavat.io/<CustomerName>/api/v1/ \
  secrets get -P <Product ID> \
  -C client.private -O /tmp/prod.json
Full secret payload written to: /tmp/prod.json

Then extract the Public key of the signing operation

$ jq -r .tokenInfo[0].publicKey < /tmp/prod.json \ 
| base64 -d | openssl ec -pubin -inform der > /tmp/pub.pem

Check the signature:

$ mkdir -p /tmp/response
$ tar -xvf signingresponse.bin -C /tmp/response
$ ls /tmp/response
tfm_s_zephyr_ns_cleared.hex
tfm_s_zephyr_ns_encrypted.hex
tfm_s_zephyr_ns_signed.hex
tfm_s_zephyr_ns_confirmed.hex

$ imgtool verify --key /tmp/pub.pem /tmp/response/tfm_s_zephyr_ns_cleared.hex
Verifying: /tmp/response/tfm_s_zephyr_ns_cleared.hex
Image was correctly validated
Image version: 0.1.0+1234567
Image digest: b1bcbde83c90be004c9936efefb91234cc3dbd84b6841849b26b533e4ad9c0cb

$ imgtool verify --key /tmp/pub.pem /tmp/response/tfm_s_zephyr_ns_encrypted.hex
Verifying: /tmp/response/tfm_s_zephyr_ns_encrypted.hex
Image was correctly validated
Image version: 0.1.0+1234567
Image digest: b1bcbde83c90be004c9936efefb91234cc3dbd84b6841849b26b533e4ad9c0cb

$ imgtool verify --key /tmp/pub.pem/tmp/response/tfm_s_zephyr_ns_signed.hex
Verifying: /tmp/response/tfm_s_zephyr_ns_signed.hex
Image was correctly validated
Image version: 0.1.0+1234567
Image digest: b1bcbde83c90be004c9936efefb91234cc3dbd84b6841849b26b533e4ad9c0cb

$ imgtool verify --key /tmp/pub.pem /tmp/response/tfm_s_zephyr_ns_confirmed.hex
Verifying: /tmp/response/tfm_s_zephyr_ns_confirmed.hex
Image was correctly validated
Image version: 0.1.0+1234567
Image digest: b1bcbde83c90be004c9936efefb91234cc3dbd84b6841849b26b533e4ad9c0cb

Example usage with reference client package: MCUboot signing

MCUboot signing examples ($TOKEN contains the "regular" user token and $APPROVERTOKEN contains a token for a user that's in the approvers group):

(venv) $signing-tool -c -t $TOKEN -a https://app.laavat.io/<CustomerName>/api/v1 \ 
    imagesigning add MCUBoot \
    -N test -D test2 -P adcb30d8-f009-438e-b1b2-96f507b306cb \
    --operid 4add90e9-ffb3-4708-9554-ed2e82e8fd71 -F tfm_zephyr_mcuboot_enc.tar.g

# Approve the mcuboot signing request
(venv) $ signing-tool -c -t $APPROVERTOKEN -a https://app.laavat.io/<CustomerName>/api/v1 \
    imagesigning approve -I a83081a6-1d3b-4117-a81b-0ebcfcf0669c

# Get the signed payload
(venv) $ signing-tool -c -t $TOKEN -a https://app.laavat.io/<CustomerName>/api/v1 \
    imagesigning get -I a83081a6-1d3b-4117-a81b-0ebcfcf0669c -O /tmp/signingresponse.bin