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

# Xilinx Signing

> **Tip: Looking for the full Zynq UltraScale+ design?**
> This page documents the `SignBootgenImage` request and archive formats. For
> the complete secure boot design — the product with its PSK and SSK key
> operations, the PPK eFUSE values and which slot each one belongs to, and
> verification before shipping — see
> [Building CRA-ready Zynq UltraScale+ MPSoC gateways](https://docs.laavat.io/solutions/cra-ready-zynq-ultrascale/).

In order to do Xilinx boot.bin signing for Zynq UltraScale+ MPSoC devices following actions/configurations are required

* Product is created with a configuration which supports Xilinx boot image signing.
    * Product operation ***SignBootgenImage*** has been configured

### Product configuration

1. Create product with needed signing operations.
    1. Check [product](https://docs.laavat.io/usage/productguide/product/) for product configuration details.

### Input data for Xilinx signing

The input is a **tar.gz archive** containing a `request.json` descriptor and the binary component files referenced by it. The tar.gz payload must be **base64-encoded** before uploading to the platform.

#### Archive contents

The tar.gz archive must contain:

- `request.json`: describes the boot image structure (generated from the Xilinx BIF file)
- Binary component files (ELF and flat binary) referenced by `request.json`

#### request.json format

The `request.json` describes the Zynq UltraScale+ boot image layout. It corresponds to the Xilinx Bootgen BIF (Boot Image Format) file, with authentication-related fields removed (the platform handles key management and RSA authentication).

Example `request.json`:

```json
{
  "arch": "zynqmp",
  "ppk_select": 0,
  "spk_id": 0,
  "images": [{
    "output": "boot.bin",
    "fsbl_config": ["a53_x64"],
    "items": [
      {"filename": "pmufw.elf", "attributes": "pmufw_image"},
      {"filename": "fsbl.elf", "attributes": "bootloader, destination_cpu=a53-0"},
      {"filename": "mini.bit", "attributes": "destination_device=pl"},
      {"filename": "bl31.elf", "attributes": "destination_cpu=a53-0, exception_level=el-3, trustzone"},
      {"filename": "tee-pager_v2.bin", "attributes": "destination_cpu=a53-0, exception_level=el-1, trustzone, load=0x7e800000, startup=0x7e800000"},
      {"filename": "u-boot.elf", "attributes": "destination_cpu=a53-0, exception_level=el-2"}
    ]
  }]
}
```

> **Note**
> The `attributes` field corresponds to Xilinx Bootgen BIF attributes. Do **not** include `pskfile`, `sskfile`, or `authentication` attributes. The platform adds RSA authentication using its own PSK/SSK keys managed in the HSM.

> **Note**
> The platform supports different hash algorithms and key sizes. The values and component list shown above are examples. Configure them according to your product's requirements.

#### Key selection: `ppk_select` and `spk_id`

The PSK names carry AMD's PPK slot numbers:

| `arch` | `ppk_select` | Key operation | eFUSE value (product secrets) |
|---|---|---|---|
| `zynqmp` | 0 | `BootgenPSK0` | `EFusePPK0Bits` (PPK0 eFUSEs) |
| `zynqmp` | 1 | `BootgenPSK1` | `EFusePPK1Bits` (PPK1 eFUSEs) |
| `zynq` | 0 | `BootgenPSK` | `EFusePPKBits` |

`spk_id` is the value the boot ROM compares with the 32-bit SPK_ID eFUSE, so it is written into every authentication certificate. eFUSE bits can only be set, so each SPK revocation burns one more bit, and each step uses its own SSK:

| `spk_id` | 0 | 1 | 3 | 7 | 15 | 31 | 63 | 127 |
|---|---|---|---|---|---|---|---|---|
| SSK | `BootgenSSK` | `BootgenSSK2` | `BootgenSSK3` | `BootgenSSK4` | `BootgenSSK5` | `BootgenSSK6` | `BootgenSSK7` | `BootgenSSK8` |

Any other `spk_id` is refused. `spk_id` belongs at the top level of `request.json`; an `spk_id` inside an item's `attributes` is refused. `zynq` images use `ppk_select` 0 and `spk_id` 0. Only `SignBootgenImage` (signing) is supported.

#### Typical boot image components

A Zynq UltraScale+ boot image typically contains the following components:

| File | Description | Format |
|------|------------|--------|
| `pmufw.elf` | Platform Management Unit firmware | ELF |
| `fsbl.elf` | First Stage Boot Loader | ELF |
| `*.bit` | FPGA bitstream | Xilinx bitstream |
| `bl31.elf` | ARM Trusted Firmware (EL3) | ELF |
| `tee-pager*.bin` | OP-TEE secure OS (flat binary) | Raw binary |
| `u-boot.elf` | U-Boot bootloader | ELF |

#### Output

The platform returns a **tar.gz archive** (raw binary, not base64) containing `boot.bin` (filename is configured by 'output' field in request.json), the fully assembled and RSA-authenticated Zynq UltraScale+ boot image, as produced by Bootgen.

The archive also holds `primary.pub` (the PPK) and `secondary.pub` (the SPK). `bootgen -efuseppkbits` over `primary.pub` must give the eFUSE value from the product secrets for the `ppk_select` used.

The returned `boot.bin`:

- Is a valid ZynqMP boot image (boot ROM header at offset 0)
- Has RSA authentication on each component (equivalent to `[authentication=rsa]` in the BIF)
- Uses the product's PSK/SSK key pair for signing

### Developer example: preparing a Xilinx boot image for signing

#### 1. Start from the Bootgen BIF file

A typical Xilinx Bootgen BIF file (`boot.bif`) for a Zynq UltraScale+ design looks like:

```
the_ROM_image:
{
  [fsbl_config] a53_x64
  [pmufw_image] pmufw.elf
  [bootloader, destination_cpu=a53-0,
   authentication=rsa, pskfile=psk.pem, sskfile=ssk.pem] fsbl.elf
  [destination_device=pl,
   authentication=rsa, pskfile=psk.pem, sskfile=ssk.pem] mini.bit
  [destination_cpu=a53-0, exception_level=el-3, trustzone,
   authentication=rsa, pskfile=psk.pem, sskfile=ssk.pem] bl31.elf
  [destination_cpu=a53-0, exception_level=el-1, trustzone,
   load=0x7e800000, startup=0x7e800000,
   authentication=rsa, pskfile=psk.pem, sskfile=ssk.pem] tee-pager_v2.bin
  [destination_cpu=a53-0, exception_level=el-2,
   authentication=rsa, pskfile=psk.pem, sskfile=ssk.pem] u-boot.elf
}
```

> **Warning**
> When building the `request.json` for the LAAVAT Platform, strip the `authentication`, `pskfile`, and `sskfile` attributes from each item. The platform handles key management and adds RSA authentication using its own keys stored in the HSM.

#### 2. Generate request.json from the BIF

Convert the BIF to `request.json` by extracting the architecture, image items, and their attributes (without the authentication/key fields):

```json
{
  "arch": "zynqmp",
  "ppk_select": 0,
  "spk_id": 0,
  "images": [{
    "output": "boot.bin",
    "fsbl_config": ["a53_x64"],
    "items": [
      {"filename": "pmufw.elf", "attributes": "pmufw_image"},
      {"filename": "fsbl.elf", "attributes": "bootloader, destination_cpu=a53-0"},
      {"filename": "mini.bit", "attributes": "destination_device=pl"},
      {"filename": "bl31.elf", "attributes": "destination_cpu=a53-0, exception_level=el-3, trustzone"},
      {"filename": "tee-pager_v2.bin", "attributes": "destination_cpu=a53-0, exception_level=el-1, trustzone, load=0x7e800000, startup=0x7e800000"},
      {"filename": "u-boot.elf", "attributes": "destination_cpu=a53-0, exception_level=el-2"}
    ]
  }]
}
```

#### 3. Package the archive

Create a tar.gz archive containing `request.json` and all referenced binary files:

```bash
tar czf xilinx-payload.tar.gz request.json pmufw.elf fsbl.elf mini.bit bl31.elf tee-pager_v2.bin u-boot.elf
```

#### 4. Submit to the LAAVAT Platform

The tar.gz is base64-encoded and uploaded via the standard image signing flow. See the usage example below.

### PPK hash for eFuse programming

The boot ROM on the ZynqMP verifies `boot.bin` against the PPK hash burned into the PPK0 or PPK1 eFUSEs, chosen by `ppk_select`. The values are delivered with the product secrets as `EFusePPK0Bits` and `EFusePPK1Bits` (Zynq-7000: `EFusePPKBits`), see the table above.

For production:

- The PPK hash (SHA3-384 in AMD's Keccak form) must be programmed into the device eFuses during manufacturing
- The PPK hash is a one-time-programmable value. Once set, only boot images signed with the matching PPK can boot

For R&D/unfused devices, the `bh_auth_enable` BIF flag enables authentication without eFuses (for testing).

### Example usage with reference client package: Xilinx signing

The examples below use two config files created with `config-init`: `test.ini` for the regular user and `approver.ini` for a user in the approvers group. Each config holds a `token_file` reference rather than a literal token, so no token appears on the command line. See [Reference Client › Usage](https://docs.laavat.io/democlient/usage/) for how to create these configs and for the secure token-input forms (`-t @file`, `-t @-`).

```bash
(venv) $ signing-tool -n test.ini imagesigning add SignBootgenImage \
    -N test -D test2 -P adcb30d8-f009-438e-b1b2-96f507b306cb --operid 4add90e9-ffb3-4708-9554-ed2e82e8fd71 -F xilinx-payload.tar.gz

# Approve the signing request
(venv) $ signing-tool -n approver.ini imagesigning approve \
    -I a83081a6-1d3b-4117-a81b-0ebcfcf0669c

# Get the signed payload (a raw tar.gz: boot.bin, primary.pub, secondary.pub; --skipBase64 because it is not base64)
(venv) $ signing-tool -n test.ini imagesigning get \
    -I a83081a6-1d3b-4117-a81b-0ebcfcf0669c -O /tmp/signed-boot.tar.gz --wait --skipBase64
```
