Skip to content

wolfBoot integration: SUIT manifest verification via wolfCOSE #22

@aidangarske

Description

@aidangarske

IETF SUIT (RFC 9124 / draft-moran-suit-manifest) defines a CBOR-serialized manifest authenticated with COSE that acts as the authoritative descriptor for an IoT firmware image. The bootloader verifies the manifest before executing — no transport layer involved; the image and manifest are already resident in flash after OTA delivery.

TF-M already ships a COSE-based update path (t_cose + PSA crypto). wolfBoot is the natural wolfSSL-ecosystem equivalent, and wolfCOSE handles the COSE layer we'd need.

Daniele's note says:

"SUIT recommends to use COSE for secure boot manifests... It would be nice to have an optional COSE parser for wolfBoot, which may become the standard for secure boot soon."


What this actually looks like

flash layout:
  [ COSE_Sign1 envelope ]
       |
       +-- protected header  (alg: ES256 / EdDSA)
       +-- payload           (CBOR-encoded SUIT manifest)
       +-- signature         (over protected || payload)

wolfBoot boot sequence:

  1. Read COSE_Sign1 blob from flash
  2. wolfCOSE: verify signature against provisioned public key
  3. Minimal CBOR walk: extract digest, size, component-id
  4. Compare image digest against actual flash contents
  5. Execute or reject

Implementation Plan

Phase 1 — wolfCOSE side (this repo)

  • Confirm wc_CoseSign1_Verify works against a SUIT-structured COSE_Sign1 (no API changes expected — just integration test)
  • Add examples/suit/ with a host-side test: generate a mock SUIT manifest, wrap it in COSE_Sign1, verify it, walk the payload CBOR
  • Document which COSE algorithms are SUIT-relevant (ES256, ES384, EdDSA — all already supported)

Phase 2 — Minimal SUIT manifest parser

A full SUIT parser is out of scope. We need only the fields wolfBoot cares about:

SUIT label Field Purpose
2 suit-manifest-sequence-number anti-rollback
3 suit-common contains digest + size
suit-integrated-payload raw image (if present)
  • wolfcose_suit.h / wolfcose_suit.c — zero-allocation CBOR walker that extracts digest (algorithm + bytes) and image size from the manifest payload bytes
  • Compile-time opt-in: WOLFCOSE_SUIT_MANIFEST — keeps binary size impact zero for non-SUIT builds
  • MISRA C:2023 compliant (consistent with rest of wolfCOSE)

Phase 3 — wolfBoot hook (wolfBoot repo, separate PR)

  • src/suit.c — thin glue layer calling into wolfCOSE verify + wolfcose_suit parser
  • Opt-in at wolfBoot config level: WOLFBOOT_USE_SUIT_MANIFEST
  • No dynamic allocation — all buffers statically sized against WOLFBOOT_PARTITION_SIZE
  • Key provisioning follows existing wolfBoot keystore pattern

Dependencies / Open Questions

  • CBOR parser scope: wolfBoot has no existing CBOR parser. The Phase 2 parser is the only new complexity — keep it minimal (map/bstr/uint only, no indefinite-length encoding required by SUIT).
  • Algorithm scope for v1: ES256 + EdDSA are sufficient. ML-DSA (PQ) can follow once draft-ietf-cose-dilithium stabilizes — the centralized alg dispatch in wolfCOSE already supports this path cleanly.
  • Manifest generation tooling: suit-tool (Python, from IETF SUIT WG) can generate test manifests. Worth including a scripts/gen_suit_manifest.py wrapper for CI.
  • wolfBoot existing manifest format: SUIT support should be additive — existing wolfBoot header format must still work when WOLFBOOT_USE_SUIT_MANIFEST is not defined.

References

  • RFC 9124 — SUIT manifest
  • RFC 9052 — COSE (obsoletes RFC 8152)
  • draft-moran-suit-manifest
  • TF-M SUIT implementation (reference for what a working COSE-based boot path looks like in practice)
  • aidangarske/wolfCOSE — this repo

Phases 1 and 2 are entirely self-contained in wolfCOSE. Phase 3 is a separate wolfBoot PR once Phase 2 is solid. Phase 1 is essentially free — it's just a targeted integration test confirming the existing API is sufficient, which it almost certainly is given that COSE_Sign1 is already the primary use case.

Here's a tight GitHub issue you can drop in as-is:

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions