MCUboot usage example¶
This example shows how to create a product which creates operations to sign and encrypt MCUboot based binaries. Also example signing operation is performed and the result is also verified.
This example uses the reference python client and the UI to perform different actions.
The example is divided to following stages:
- How to get authentication token
- Creating product
- Signing MCUboot binaries
- Verifying MCUboot binaries
Authentication¶
In order to use the reference python client a valid JWT token is needed. How to obtain one is explained in more detail in the authentication chapter. New token must be requested if the current token expires. ( roughly 1 hour of validity)
(venv) $ az login --allow-no-subscriptions --only-show-error
A web browser has been opened at https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize. Please continue the login in the web browser. If no web browser is available or if the web browser fails to open, use device code flow with `az login --use-device-code`.
[1] N/A(tenant level account) <redacted> <redacted>
The default is marked with an *; the default tenant is '<redacted>' and subscription is 'N/A(tenant level account)' (<redacted>).
Select a subscription and tenant (Type a number or Enter for no changes): 1
Tenant: <redacted>
Subscription: N/A(tenant level account) (<redacted>)
(venv) $ az account get-access-token --resource api://<redacted>
{
"accessToken": "<redacted>",
"expiresOn": "2025-06-04 15:18:10.000000",
"expires_on": 1749039490,
"subscription": "<redacted>",
"tenant": "<redacted>",
"tokenType": "Bearer"
}
(venv) $ export TOKEN=<redacted>
Create product¶
Here is the used product template.
In the approval rule it was decided that entities in the $WRITERGROUP were able to make MCUBoot signing requests. And entities in the $APPROVERGROUP group would be able to approve those. Autoapproval was not used.
$WRITERGROUP and $APPROVERGROUP were replaced with the corresponding Group Object ID from Microsoft Entra.
The template was saved as product.json.
More information about rules can be found from approval rules.
Product was created using the python tool
(venv) $ signing-tool -c -t $TOKEN \
-a https://app.laavat.io/<CustomerName>/api/v1/ product add -T product.json
Product:
{
"ca_info": [],
"description": "nRF91 based product with support for MCUboot encryption and signing",
"enabled": true,
"external_request_id": null,
"id": null,
"name": "nRF91",
"product_config_items": null,
"product_operations": [
{
"approval_rule": null,
"ca_use_case": null,
"description": "Generation only",
"id": null,
"name": "nRF encryption key",
"operation_type": "EncryptMcuBoot",
"profile_id": null,
"token": {
"description": "Encryption key for nRF",
"extractable": true,
"key_override_id": null,
"key_type": "AES256",
"name": "MCUboot encryption",
"public_key": null
}
},
{
"approval_rule": {
"allowed_groups": [
"b716abb1-2e3b-47a9-bca5-a3669faa50a6"
],
"approval_groups": [
"f65a3ea9-60db-47a4-9ad8-c6915735ec5f"
],
"blanket_groups": [],
"description": "Rule used for testing for nRF91",
"name": "Test rule"
},
"ca_use_case": null,
"description": "Sign nRF with MCUboot",
"id": null,
"name": "nRF signing",
"operation_type": "SignMcuBoot",
"profile_id": null,
"token": {
"description": "Signing key for nRF",
"extractable": null,
"key_override_id": null,
"key_type": "ECDSAP256",
"name": "MCUboot sign",
"public_key": null
}
}
],
"product_type": "Production",
"rnd_keys": [],
"state": null
}
Is product ok(Y/N): y
{
"ca_info": [],
"description": "nRF91 based product with support for MCUboot encryption and signing",
"enabled": null,
"external_request_id": null,
"id": "2ba194ab-bde6-40de-bd0d-5baae65d72ea",
"name": "nRF91",
"product_config_items": null,
"product_operations": [],
"product_type": null,
"rnd_keys": [],
"state": 2
}
Product Add request sent. Request ID: 2ba194ab-bde6-40de-bd0d-5baae65d72ea state: ApprovalRequired
Approve product¶
The product was approved using the GUI.
Then with the python tool the state was checked ( state is 16 for ready product) and the product ID and operation ID was obtained.
- productID = 2ba194ab-bde6-40de-bd0d-5baae65d72ea
- operation ID for MCUboot signing = 54a09100-2d3b-4092-b280-71e9482a00f5
- operation ID for EncryptMcuBoot ( generation only ) = a414edf0-0ab3-4827-a525-25f0f6f749e1
(venv) $ signing-tool -c -t $TOKEN \
-a https://app.laavat.io/<CustomerName>/api/v1/ product getall
{
"count": 1,
"items": [
{
"description": "nRF91 based product with support for MCUboot encryption and signing",
"id": "2ba194ab-bde6-40de-bd0d-5baae65d72ea",
"name": "nRF91",
"state": 16
},
],
"next": "/products/?page=1",
"pages": 1,
"prev": "/products/?page=1"
}
(venv) $ signing-tool -c -t $TOKEN \
-a https://app.laavat.io/<CustomerName>/api/v1/ product \
get -I 2ba194ab-bde6-40de-bd0d-5baae65d72ea
{
"ca_info": [],
"description": "nRF91 based product with support for MCUboot encryption and signing",
"enabled": null,
"external_request_id": "b13944f8-9783-6e18-3341-37a46ce98437",
"id": "2ba194ab-bde6-40de-bd0d-5baae65d72ea",
"name": "nRF91",
"product_config_items": [],
"product_operations": [
{
"approval_rule": {
"allowed_groups": [
"b716abb1-2e3b-47a9-bca5-a3669faa50a6"
],
"approval_groups": [
"f65a3ea9-60db-47a4-9ad8-c6915735ec5f"
],
"blanket_groups": [
""
],
"description": "Rule used for testing for nRF91",
"name": "Test rule"
},
"ca_use_case": null,
"description": "Sign nRF with MCUboot",
"id": "54a09100-2d3b-4092-b280-71e9482a00f5",
"name": "nRF signing",
"operation_type": "SignMcuBoot",
"profile_id": "00000000-0000-0000-0000-000000000000",
"token": {
"description": "Signing key for nRF",
"extractable": null,
"key_override_id": null,
"key_type": "ECDSAP256",
"name": "MCUboot sign",
"public_key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0nXRAzsQUABY4eoLGGwXM0a38gt6qj6/aoKwJhlU7awoVmfFXIy8BXfvUGSbRJw51+hR77GeB0hyEqeGmtZODQ=="
}
},
{
"approval_rule": null,
"ca_use_case": null,
"description": "Generation only",
"id": "a414edf0-0ab3-4827-a525-25f0f6f749e1",
"name": "nRF encryption key",
"operation_type": "EncryptMcuBoot",
"profile_id": "00000000-0000-0000-0000-000000000000",
"token": {
"description": "Encryption key for nRF",
"extractable": null,
"key_override_id": null,
"key_type": "AES256",
"name": "MCUboot encryption",
"public_key": null
}
}
],
"product_type": "Production",
"rnd_keys": [],
"state": 16
}
Getting the sensitive items¶
In manufacturing there are some sensitive items which are needed. Here a client is registered which can obtain e.g., certificates.
(venv) $ signing-tool -c -t $TOKEN \
-a https://app.laavat.io/<CustomerName>/api/v1/ client add -N Manufacturing -D "Get sensitive information" \
-K client.public -U "oid:<your-object-id>" -T ProductionPC -p 2ba194ab-bde6-40de-bd0d-5baae65d72ea
{
"client_type": "ProductionPC",
"description": "Get sensitive information",
"id": "5235da30-6c2b-493c-bfec-937b70dc6742",
"id_product": "2ba194ab-bde6-40de-bd0d-5baae65d72ea",
"name": "Manufacturing",
"state": 2
}
Client Add request sent. Request ID: 5235da30-6c2b-493c-bfec-937b70dc6742 state: ApprovalRequired
Approve the client from UI
Now the product sensitive items can be fetched.
(venv) $ signing-tool -c -t $TOKEN \
-a https://app.laavat.io/<CustomerName>/api/v1/ secrets get \
-P 51ec9ce9-3956-4e12-bea3-e994ed6a2395 -C client.private -O /tmp/prod.json
SRKHASH written to: /tmp/prod.jsonSRKHASH
SRKTABLE written to: /tmp/prod.jsonSRKTABLE
KEKIV written to: /tmp/prod.jsonKEKIV
Full secret payload written to: /tmp/prod.json
The /tmp/prod.json contains all the items in one file. All the Certificates can be seen in that file.
More info can be found from client usage.
MCUboot signing¶
See more information about MCUboot packages.
The tfm_zephyr_mcuboot_enc.tar.gz was used for signing. request.json was same as in documentation
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
(venv) $ signing-tool -c -t $TOKEN \
-a https://app.laavat.io/<CustomerName>/api/v1/ imagesigning add MCUBoot \
-P 51ec9ce9-3956-4e12-bea3-e994ed6a2395 \
--operid e007176c-6b29-4640-9f6e-7cee6abb6c0a \
-N TEST -D TEST -F tfm_zephyr_mcuboot_enc.tar.gz
{
"call_back_url": null,
"description": "TEST",
"id": "8a0bcafc-df97-48c9-a60a-b06e5f0b169d",
"id_product": "51ec9ce9-3956-4e12-bea3-e994ed6a2395",
"id_product_operation": "e007176c-6b29-4640-9f6e-7cee6abb6c0a",
"name": "TEST",
"payload": {
"id": null,
"metadata": [
{
"name": "first",
"value": "val"
}
],
"modified_sha256": null,
"name": "tfm_zephyr_mcuboot_enc.tar.gz",
"original_sha256": null,
"s3_url": null,
"service_provided_parameters": null
},
"state": 1
}
Request sent. Request ID: 8a0bcafc-df97-48c9-a60a-b06e5f0b169d, state: Created
The operation created ID "8a0bcafc-df97-48c9-a60a-b06e5f0b169d" which is then used when querying/downloading the signed content.
Approve signing request¶
Request was approved from the GUI.
Download signed content¶
After approval the request is processed and it can be queried. If the state is 16 then the signing is complete and the content is downloaded.
(venv) $ signing-tool -c -t $TOKEN \
-a https://app.laavat.io/<CustomerName>/api/v1/ imagesigning get \
-I 8a0bcafc-df97-48c9-a60a-b06e5f0b169d -O /tmp/test.bin --skipBase64
{
"call_back_url": null,
"description": "TEST",
"id": "8a0bcafc-df97-48c9-a60a-b06e5f0b169d",
"id_product": "51ec9ce9-3956-4e12-bea3-e994ed6a2395",
"id_product_operation": "e007176c-6b29-4640-9f6e-7cee6abb6c0a",
"name": "TEST",
"payload": {
"id": "750b4ae9-a324-487f-9109-8bbfe408ba3e",
"metadata": [
{
"name": "first",
"value": "val"
}
],
"modified_sha256": null,
"name": "tfm_zephyr_mcuboot_enc.tar.gzz",
"original_sha256": null,
"s3_url": "<redacted>",
"service_provided_parameters": []
},
"state": 16
}
Downloading signed binary to: /tmp/test.bin
File Downloaded
Verify the signed contents¶
See example response with validation
In production scenarios the trustpoint is downloaded securely using a registered client.