# RK3576 keys to create in Cloud KMS: boot key and TA key

For: Frank (and his agent). From: Wilber's rk_bake desk. Updated 2026-11-12 after an on-board test.
Scope: what to create, with which algorithm, size, name and file format. Nothing here burns OTP.

## Summary

| Key | Purpose | KMS algorithm | Size | Protection | Prod name | Dev name |
|---|---|---|---|---|---|---|
| RK boot key | signs SPL/idblock, loader, U-Boot FIT; its hash is burned into OTP | `RSA_SIGN_PSS_4096_SHA256` | 4096 | HSM | `rk-boot-prd-1` | `rk-boot-dev-1` |
| RK TA key | signs the OP-TEE trusted app (disk-key TA); BL32 carries its public half | `RSA_SIGN_PSS_2048_SHA256` | 2048 | HSM | `rk-ta-prd-1` | `rk-ta-dev-1` |

Both: purpose `ASYMMETRIC_SIGN`, public exponent 65537 (KMS default, cannot be changed), version 1, no rotation.

| | Prod | Dev |
|---|---|---|
| Project / location / key ring | `hw-prd-secrets` / `us` / `optisigns-os-efuse` | `sbx-secrets-488413` / `us` / `optisigns-os-efuse-dev` |
| Full path pattern | `projects/hw-prd-secrets/locations/us/keyRings/optisigns-os-efuse/cryptoKeys/<name>/cryptoKeyVersions/1` | same with the dev project and ring |

IAM for the build account, on these keys only: `roles/cloudkms.signer` and `roles/cloudkms.publicKeyViewer`.

Example (prod boot key):

```
gcloud kms keys create rk-boot-prd-1 --project hw-prd-secrets --location us --keyring optisigns-os-efuse \
  --purpose asymmetric-signing --default-algorithm rsa-sign-pss-4096-sha256 --protection-level hsm
gcloud kms keys create rk-ta-prd-1 --project hw-prd-secrets --location us --keyring optisigns-os-efuse \
  --purpose asymmetric-signing --default-algorithm rsa-sign-pss-2048-sha256 --protection-level hsm
```

## Key files (what lands in the repo)

Private keys never leave KMS; there is no private key file. Only the public half is committed.

| Key | Repo file | Format |
|---|---|---|
| Boot key | `rk/boot-sign/<id>.pub.pem` + a row in `rk/boot-sign/keys.json` (kms path, algorithm, pub, otp_sha256) | PEM, `-----BEGIN PUBLIC KEY-----` (X.509 SubjectPublicKeyInfo), exactly what `gcloud kms keys versions get-public-key` writes |
| TA key | `rk/ta-sign/<id>.pub.pem` | same PEM format |

Export the public half with:

```
gcloud kms keys versions get-public-key 1 --key <name> --keyring <ring> --location us --project <project> \
  --output-file <name>.pub.pem
```

Send me the two full key paths (and the PEMs, or I export them); I add the rows and check them.

## 1. Boot key details

- One key signs three things: the idblock/SPL and `loader.bin` (Rockchip `rk_sign_tool`, checked by the BootROM
  against the OTP hash) and the U-Boot FIT config (checked by the SPL).
- PSS with a 32-byte salt (the KMS default for PSS-SHA256); patch 0015 makes our SPL/U-Boot verify exactly that.
- RSA 2048/3072, PKCS#1 v1.5 and EC are not usable here.
- The OTP stores the hash of this key. **Never delete or destroy a prod boot key while any unit burned with it is
  in the field**: those units would never accept a new boot chain again.
- Today's prd rows are stand-ins borrowed from the OptiStick chain (`efuse-prod-c1-lvl1`, `efuse-prod-root-3`);
  `rk-boot-prd-1` replaces them. No unit has been burned with a prod key yet.

## 2. TA key details (tested 2026-11-12)

- The TA is `optisigns-ikm`, which derives the disk-encryption key from the chip's hardware key. BL32 (OP-TEE)
  loads it only if its signature verifies against the RSA public key inside BL32.
- Today BL32 holds Rockchip's SDK sample key, which is public: anyone can sign a TA that BL32 would load.
- **Why 2048:** BL32 has room for exactly one 2048-bit modulus; our build replaces those 256 bytes in place.
  4096 would need Rockchip to rebuild BL32, so we stay at 2048.
- Signature: `TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256` (salt 32), which is what KMS `RSA_SIGN_PSS_2048_SHA256` produces.
- BL32 cannot be changed by anyone else: it sits inside the U-Boot FIT, which is signed with the boot key, so on
  a burned unit only a boot-key holder can put a different TA key into BL32.
- On-board test (evt-01, dev OTP burned, image dbg805): a local 2048-bit test key was written into BL32 and used to
  sign the TA. The board booted (verified boot green), BL32 loaded the TA, and both encrypted partitions (state,
  home) unlocked from the chip key. Host check: the TA verifies with the new key and fails with the SDK key.
- Still to do on our side: the build signs the TA with a local key file today (`RK_TA_KEY`); switching it to KMS
  (digest → KMS sign → stitch, which Rockchip's `sign_encrypt.py` supports) follows once `rk-ta-dev-1` exists.
- Changing the TA key on a fielded unit is an ordinary signed update (new BL32 + newly signed TA together); there
  is no OTP involved. But a TA and a BL32 from different keys do not work together, so they always ship as a pair.

## 3. Not needed

- `rk-fit-dev-k1` (sandbox, created 2026-11-05 by Wilber's desk for a one-off test of a different signature type
  on U-Boot) is no longer used; it can be disabled.
- No separate FIT key, no new OTA key; the AVB (vbmeta) key is separate and not part of this request.
