> Markdown version of https://docs.laavat.io/usage/signing-encryption/spsdksigning/ from the LAAVAT PKI and Signing Platform documentation. All pages: https://docs.laavat.io/llms.txt

# SPSDK signing

SPSDK signing signs an NXP **AHAB** (Advanced High Assurance Boot) boot
container — the bootable image of an i.MX8QXP or i.MX9 device — so the device
will accept and boot it. The signing is performed by NXP's Secure Provisioning
SDK (SPSDK) inside the platform, using the keys stored with the product.

This is the `SignSPSDK` operation, and it is the recommended way to sign AHAB
images. (Older i.MX6, i.MX7 and i.MX8M devices use HAB instead, which is signed
with [CST signing](https://docs.laavat.io/usage/signing-encryption/cstsigning/) — NXP's Code Signing Tool, CST. AHAB signing
through CST still works for products created earlier, but it is being phased
out; use SPSDK for new products.)

> **Note**
> `SignSPSDK` signs a complete boot image. It is **not** the same as
> `SignAHAB`, which signs only a hash (digest) and returns a small signature
> rather than a signed image.

## Prerequisites

- A product that contains an AHAB key tree and the `SignSPSDK` operation
  (see [Product configuration](https://docs.laavat.io/usage/signing-encryption/spsdksigning/#product-configuration)).
- The image you want to sign, plus a small SPSDK configuration file that
  describes your chip and image layout.
- Permission to submit (and, where required, approve) signing requests for the
  product.

## Product configuration

To sign with SPSDK, create a product that has:

- **Four Super Root Key (SRK) certificates.** Each SRK is its own root
  certificate — there is no certificate authority (CA) above it — and all four
  use the same end-entity certificate profile. Unlike CST-based AHAB, an SPSDK
  product has **no subordinate SGK key**; SPSDK signs directly with one of the
  four SRKs.
- The configuration item **`FusemapType`** set to **`IMXAHAB`**, and an
  **`AHABDigest`** value (`sha256` or `sha512`).
- One **`SignSPSDK`** operation.

For the full product template and step-by-step instructions, see
[i.MX8QXP / i.MX9 based product](https://docs.laavat.io/usage/productguide/product/#imx8qxp-imx9-based-product).

## Choosing the SRK key type

The four SRK keys can be elliptic-curve (EC), RSA or ML-DSA. All are supported; the
choice affects which certificate profile you use for the SRKs, and ML-DSA needs a
device that supports it.

### EC keys (recommended)

Use `ECDSAP256`, `ECDSAP384` or `ECDSAP521` with a standard ECDSA end-entity
profile. This is the simplest option and the recommended one.

### RSA keys

Use `RSA2048`, `RSA3072` or `RSA4096`. For RSA, the SRK certificate profile
**must** use an RSA-PSS **Signature Algorithm** — one of:

- `13` — SHA256 with RSA-PSS
- `14` — SHA384 with RSA-PSS
- `15` — SHA512 with RSA-PSS

The profile also sets `KeyAlgorithm: 1` (RSA) and is an end-entity profile (not
a CA). A ready-made example profile is given in
[the PKI profile examples](https://docs.laavat.io/usage/productguide/pki-examples/#ahab-spsdk-srk-profile-for-rsa-pss-keys),
and a full walkthrough in
[the RSA example flow](https://docs.laavat.io/exampleflows/spsdk-ahab-rsa-signing/).

> **Warning**
> RSA SRKs require an RSA-PSS profile. If you use an ordinary (non-PSS) RSA
> profile by mistake, the SRK hash on the signed image will not match the one
> fused into the device, and the device will **reject the image**. Use the
> RSA-PSS profile only for SPSDK signing — the CST-based operations
> (`SignAHAB`, `SignHAB`) need the ordinary RSA profile instead.

### ML-DSA keys

Use `MLDSA65` or `MLDSA87` for post-quantum SRK keys on devices whose AHAB container supports them (container version 2,
for example i.MX95). `MLDSA44` is not supported for AHAB.

The SRK certificate profile is an end-entity profile with `KeyAlgorithm: 3` (ML-DSA) and the ML-DSA **Signature
Algorithm** of the key: `18` for `MLDSA65`, `19` for `MLDSA87`.

The hash that goes with the key is fixed by the key type, so it is not chosen in the product or the request: SHA-384 for
`MLDSA65` and SHA-512 for `MLDSA87`. In a version 2 container the signed image carries the public key of the SRK that
signed it and the hashes of all four, and the SRK hash to fuse is computed over that table.

## What you send to sign

The signing payload is a single compressed archive (`.tar.gz`), uploaded the
same way as any other image-signing request (see the
[signing overview](https://docs.laavat.io/usage/signing-encryption/signing-encryption/)). The archive contains three files:

```text
payload.tar.gz
├── request.json            # says which file is the image and which is the config
├── mimx9352-sign.yaml      # SPSDK configuration for your chip and image
└── imx-boot-imx93evk.bin   # the image to sign
```

> **Warning: Store the members by plain name**
> Every member must be stored under a bare file name, with no directory part.
> Name the files explicitly, as above. Building the archive from a directory
> instead, `tar czf payload.tar.gz .`, makes GNU tar store them as
> `./request.json`, `./mimx9352-sign.yaml` and so on, and the platform rejects
> any member whose name carries a path separator. The request then fails during
> extraction, before `request.json` is ever read.

**`request.json`** names the other two files and the signing mode:

```json
{ "mode": "ahab", "image": "imx-boot-imx93evk.bin", "config": "mimx9352-sign.yaml", "memType": "serial_downloader" }
```

| Field | Required | Meaning |
| --- | --- | --- |
| `mode` | no (default `ahab`) | Must be `ahab`; other values are rejected. |
| `image` | yes | The image file name inside the archive (just the name, no folders). |
| `config` | yes | The SPSDK configuration file name inside the archive (just the name, no folders). |
| `memType` | no | The target memory type, passed to SPSDK unchanged (for example `serial_downloader`). |

`request.json` must be 256 KiB or smaller.

### The SPSDK configuration file

You provide an SPSDK configuration file describing your chip and image. You only
fill in the build- and chip-specific fields; the platform fills in everything to
do with keys and SRK security, so a request cannot supply its own key or weaken
the SRK settings.

You write this file yourself — it is short. A minimal configuration for an
i.MX93 part is just the chip and build fields:

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

Adjust the values for your part. If you start from the full SPSDK template
(`spsdk nxpimage ahab get-template -f mimx9352`), keep only the fields below —
the platform supplies the rest.

| You provide | The platform fills in (you can leave these out) |
| --- | --- |
| `family`, `revision`, `fuse_version`, `sw_version`, `gdet_runtime_behavior` | `signer`, `srk_set`, `srk_revoke_mask`, `used_srk_id`, and the whole `srk_table` (the SRK certificates, their hash, and CA flag) |

Any other field you add to the configuration file is ignored.

## Choosing which SRK signs

A product has four SRK keys (SRK0–SRK3); by default SRK0 signs. To use a
different one, set the **signing key index** (`0`–`3`):

- with the reference signing client, add `--signingKeyIndex` to the `SignSPSDK`
  command;
- over the REST API, set `signingKeyIndex` in `optionalParameters`.

See the [API specification](https://docs.laavat.io/api/swagger/) (`ImageSigning POST`) for
details.

## Example

First build the archive, then submit it for signing. `test.ini` is the config of
a normal user and `approver.ini` that of a user who can approve requests.

> **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 @-`).

```bash
# 1. Build the archive (image + SPSDK config + request.json)
$ tar czf payload.tar.gz request.json mimx9352-sign.yaml imx-boot-imx93evk.bin

# 2. Submit the signing request (uses SRK0 by default)
(venv) $ signing-tool -n test.ini imagesigning add SignSPSDK \
    -N test -D test -P <productID> --operid <operationID> -F payload.tar.gz

# To sign with a different key, e.g. SRK1, add --signingKeyIndex 1:
(venv) $ signing-tool -n test.ini imagesigning add SignSPSDK \
    -N test -D test -P <productID> --operid <operationID> -F payload.tar.gz --signingKeyIndex 1

# 3. Approve the request (a user in the approver group)
(venv) $ signing-tool -n approver.ini imagesigning \
    approve -I <requestID>

# 4. Download the signed image
(venv) $ signing-tool -n test.ini imagesigning \
    get -I <requestID> -O /tmp/signed.bin
```

## Getting the result

Once the request is approved and processed, download the signed image with the
`get` command (step 4 above). The platform also records a checksum (SHA256) of
both the original and the signed image.

While testing, you can inspect a signed container with NXP's tools
`spsdk nxpimage ahab verify` or `ahab_image_verifier`. These are for
experimentation only — for real verification, follow NXP's secure-boot
procedure (for example `ahab_status` on the device).
