> Markdown version of https://docs.laavat.io/exampleflows/ahabsigning/ from the LAAVAT PKI and Signing Platform documentation. All pages: https://docs.laavat.io/llms.txt

# AHAB usage example

This example shows how to create a product that signs an NXP **AHAB** boot
container for an i.MX9 device with the `SignSPSDK` operation, and then signs a
container. It uses the reference python client and the UI.

The example is divided into the following stages:

- Getting an authentication token
- Adding the SRK certificate profile
- Creating the product
- Approving the product
- Getting the SRK table and SRK hash
- Building the signing payload
- Signing the AHAB container
- Downloading and verifying the signed container

This example uses elliptic-curve (EC) keys. For RSA keys, see the
[SPSDK signing](https://docs.laavat.io/usage/signing-encryption/spsdksigning/) page. The older
CST-based AHAB signing is being phased out — see
[CST signing](https://docs.laavat.io/usage/signing-encryption/cstsigning/).

## 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.](https://docs.laavat.io/api/authentication/)
New token must be requested if the current token expires. ( roughly 1 hour of validity)

```bash
(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`.

(venv) $ az account get-access-token --resource api://<redacted>
{
  "accessToken": "<redacted>",
  "expiresOn": "2025-06-04 15:18:10.000000",
  "tokenType": "Bearer"
}
(venv) $ export TOKEN=<redacted>
```

## Add the SRK certificate profile

> **Note: Token handling in these examples**
> The `signing-tool` commands below use `-n test.ini` — a config file created with `config-init` that references
> a `token_file` rather than embedding a token, so no token appears on the command line. See [Reference Client ›
> Usage](https://docs.laavat.io/democlient/usage/) for how to create it and for the secure token-input forms (`-t @file`, `-t @-`).

An SPSDK product has four Super Root Key (SRK) certificates. Each one is a root
certificate (there is no certificate authority above it) and they all use the
same end-entity certificate profile. For EC keys this is a standard ECDSA
end-entity profile; an example is given in
[(A)HAB End-Entity profile for ECDSA keys](https://docs.laavat.io/usage/productguide/pki-examples/#ahab-end-entity-profile-for-ecdsa-keys).

Add the profile and note the returned profile ID:

```bash
(venv) $ signing-tool -n test.ini profile \
    add -F srk-endentity.yaml -N "AHAB SPSDK SRK Profile" -T END
{
    "id": "b58d7902-5fec-4fa5-90b0-7b6c70a23d6f",
    "profile_name": "AHAB SPSDK SRK Profile",
    "profile_type": 1,
    "profile_yaml": "<base64 of the profile yaml>"
}
Profile added. Profile ID: b58d7902-5fec-4fa5-90b0-7b6c70a23d6f
```

## Create the product

The product has four SRK certificates and one `SignSPSDK` operation. Unlike the
CST-based AHAB product, it has **no subordinate SGK key** — SPSDK signs directly
with one of the four SRKs.

Use the [SPSDK product template](https://docs.laavat.io/usage/productguide/product/#imx8qxp-imx9-based-product)
and replace `$ENDPROFILEID` with the profile ID from the previous step. The four
SRK certificates are root certificates (`certificateType: ROOT`) that point at
the SRK profile, and the product carries the `FusemapType` (`IMXAHAB`) and
`AHABDigest` configuration items.

```json
{
    "name": "TEST for i.mx9",
    "description": "AHAB SPSDK signing product",
    "productType": "Production",
    "enabled": true,
    "caInfo": [
        { "CN": "SRK0", "description": "SRK for i.MX9 AHAB", "useCase": "HABCA", "profileID": "$ENDPROFILEID", "keyType": "ECDSAP521", "certificateType": "ROOT" },
        { "CN": "SRK1", "description": "SRK for i.MX9 AHAB", "useCase": "HABCA", "profileID": "$ENDPROFILEID", "keyType": "ECDSAP521", "certificateType": "ROOT" },
        { "CN": "SRK2", "description": "SRK for i.MX9 AHAB", "useCase": "HABCA", "profileID": "$ENDPROFILEID", "keyType": "ECDSAP521", "certificateType": "ROOT" },
        { "CN": "SRK3", "description": "SRK for i.MX9 AHAB", "useCase": "HABCA", "profileID": "$ENDPROFILEID", "keyType": "ECDSAP521", "certificateType": "ROOT" }
    ],
    "productConfigItems": [
        { "name": "FusemapType", "value": "IMXAHAB" },
        { "name": "AHABDigest", "value": "sha256" }
    ],
    "productOperations": [
        {
            "name": "AHAB SPSDK signing",
            "description": "AHAB image signing via SPSDK",
            "operationType": "SignSPSDK",
            "approvalRule": {
                "name": "Test rule",
                "description": "Rule used for the TEST product",
                "allowedGroups": ["$WRITERGROUP"],
                "approvalGroups": ["$APPROVERGROUP"],
                "blanketGroups": []
            }
        }
    ]
}
```

`$WRITERGROUP` and `$APPROVERGROUP` are the Microsoft Entra group object IDs that
are allowed to submit and to approve signing requests. More information about
rules is in [approval rules](https://docs.laavat.io/usage/productguide/product/#approval-rules).

Save the file as `product.json` and create the product:

```bash
(venv) $ signing-tool -n test.ini product add -T product.json
...
Product Add request sent. Request ID: 608fdff6-2a06-4186-8267-94a84e7da88c state: ApprovalRequired
```

This product generates four ECDSAP521 key pairs in the CloudHSM (one per SRK).

## Approve the product

The product was approved using the GUI. Then the product ID and the operation ID
were read with the python tool (state is 16 for a ready product).

- productID = 608fdff6-2a06-4186-8267-94a84e7da88c
- operation ID for the SignSPSDK operation = 42b5da24-d2fc-4776-8aa1-a9cf0acf734b

```bash
(venv) $ signing-tool -n test.ini product getall
{
    "count": 1,
    "items": [
        {
            "description": "AHAB SPSDK signing product",
            "id": "608fdff6-2a06-4186-8267-94a84e7da88c",
            "name": "TEST for i.mx9",
            "state": 16
        }
    ]
}
```

## Getting the SRK table and SRK hash

During manufacturing the SRK table and SRK hash are needed (the SRK hash is fused
into the device). Register a client that can read them, approve it from the UI,
then fetch the values:

```bash
(venv) $ signing-tool -n test.ini client add -N Manufacturing -D "Get sensitive information" \
     -K client.public -U "oid:<your-object-id>" -T ProductionPC -p 608fdff6-2a06-4186-8267-94a84e7da88c
Client Add request sent. state: ApprovalRequired

(venv) $ signing-tool -n test.ini secrets get \
    -P 608fdff6-2a06-4186-8267-94a84e7da88c -C client.private -O /tmp/prod.json
SRKHASH written to: /tmp/prod.jsonSRKHASH
SRKTABLE written to: /tmp/prod.jsonSRKTABLE
Full secret payload written to: /tmp/prod.json
```

The `oid:` form above names a person. A manufacturing client driven by a CI
pipeline or a factory script authenticates as a service principal instead, so
register that one with `-U "appid:<application-id>"` - see
[which identity form to register](https://docs.laavat.io/usage/clientguide/clients/#which-identity-form-to-register).

More info can be found from [client usage](https://docs.laavat.io/usage/clientguide/clients/).

## Building the signing payload

The `SignSPSDK` operation takes a single compressed archive containing the image,
an SPSDK configuration file describing the chip and image, and a `request.json`
that names them.

`request.json`:

```json
{ "mode": "ahab", "image": "imx9-container.bin", "config": "mimx9352-sign.yaml" }
```

The SPSDK configuration file (`mimx9352-sign.yaml`) is short — you only fill in
the chip- and build-specific fields, and the platform fills in everything to do
with keys and SRK security:

```yaml
family: mimx9352
revision: latest
fuse_version: 0
sw_version: 0
```

See [the SPSDK configuration file](https://docs.laavat.io/usage/signing-encryption/spsdksigning/#the-spsdk-configuration-file)
for which fields you own. Build the archive:

```bash
tar czf payload.tar.gz request.json mimx9352-sign.yaml imx9-container.bin
```

Name the three files explicitly, as above. `tar czf payload.tar.gz .` stores them
as `./request.json` and so on, and the platform rejects any member whose name
carries a path separator.

## Signing the AHAB container

Submit the archive with the `SignSPSDK` operation:

```bash
(venv) $ signing-tool -n test.ini imagesigning add SignSPSDK \
    -P 608fdff6-2a06-4186-8267-94a84e7da88c \
    --operid 42b5da24-d2fc-4776-8aa1-a9cf0acf734b \
    -N TEST -D TEST -F payload.tar.gz
Request sent. Request ID: 91b9f3bf-fb75-4294-8826-df3fc13e7332, state: Created
```

By default SRK0 signs. To sign with a different SRK, add `--signingKeyIndex`
(`0`–`3`) to the command. See the
[API specification](https://docs.laavat.io/api/swagger/) `ImageSigning POST` endpoint for details.

## Approve the signing request

The request was approved from the GUI.

## Download the signed container

After approval the request is processed. When its state is 16 the signing is
complete and the signed container can be downloaded:

```bash
(venv) $ signing-tool -n test.ini imagesigning get \
    -I 91b9f3bf-fb75-4294-8826-df3fc13e7332 -O /tmp/signed.bin
Downloading signed binary to: /tmp/signed.bin
File Downloaded
```

## Verifying the signed container

While testing, the signed image can be inspected with the NXP `ahab_image_verifier`
tool (part of the NXP CST package). This is for experimentation and debugging
only — for real verification follow NXP's secure-boot procedure (for example
`ahab_status` on the device).

```bash
$ ahab_image_verifier /tmp/signed.bin
Notice: ahab_image_verifier is intended solely for experimentation and debugging purposes.

File: /tmp/signed.bin

Container #0 - offset: 0x0
Header:
  Tag: Container (0x87)
  Flags: 0x1
    SRK Set: OEM SRK
    SRK Selection: SRK 0 is used
  Number of Images: 1
  ...
```
