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