Skip to content

Services

github-actions[bot] edited this page Oct 2, 2026 · 4 revisions

Services

The STM32H563 manifest describes connection-based FF-M 1.0 IPC services. The default image contains six Secure services; CONFIG_VNET=y selects a manifest with a seventh service.

Service registry

Service SID Non-secure clients Purpose
SERVICE_ATTEST 0x1000 Yes PSA Initial Attestation token generation
SERVICE_VAULT 0x1002 No Secure-only persistent objects, sealing, and randomness
SERVICE_ITS 0x1003 Yes PSA Internal Trusted Storage
SERVICE_PS 0x1004 Yes PSA Protected Storage
SERVICE_FWU 0x1005 Yes PSA Firmware Update staging for wolfBoot
SERVICE_HSM 0x1006 Yes Copied request relay for the selected native or wolfHSM crypto engine, plus the attestation partition's signing door
SERVICE_VNET 0x1007 Yes, optional Secure virtual Ethernet switch implemented by wolfTrust for optional Non-secure wolfIP guests

All service versions are 1. ITS and Protected Storage declare a dependency on the Secure-only vault. The default manifest is port/stm32h563/manifest.json; the network variant is port/stm32h563/manifest-vnet.json.

Runtime model

Every service loop is a scheduled unprivileged Secure coroutine. It waits for its signal, obtains one message, reads copied input, writes copied output, and replies. Each thread receives shared Secure text plus its own stack and manifest-declared data. Privileged hardware operations are performed by narrow SVC gates that verify which partition issued the request.

Crypto engines and PSA Crypto

Zephyr and FreeRTOS reference guests expose wolfPSA's PSA Crypto API. The WT_ENGINE build selector chooses how those guests and SERVICE_HSM are wired. Both engines use one input and one output vector, bounded to 384 bytes, through the same copied FF-M call.

With the default native engine, wolfPSA and wolfCrypt execute in the Non-secure guest. DRBG seed requests use the native client to reach the Secure vault RNG. The native wire also exposes explicit vault-backed P-256 and AES-256 key operations, random generation, and SHA-256. Vault key objects are namespaced by the SPM-stamped client ID and stored SENSITIVE and NONEXPORTABLE.

With the wolfHSM engine, wolfPSA uses a wolfHSM client transport that places one complete wolfHSM packet in the FF-M call. The relay maps guest N to its dedicated server, forces server client ID N + 1, and rejects guest-facing wolfHSM NVM message groups. The reference build executes the server with software wolfCrypt; deployments can configure wolfHSM's external-HSM path.

The reference cryptographic profile is controlled by each guest's wolfCrypt user_settings.h. Consult the vendored lib/wolfPSA/wolfpsa/psa/crypto.h and the active guest configuration before assuming a particular algorithm is available. See Crypto Engines for the protocol, key-protection, and footprint differences.

Vault

SERVICE_VAULT is inaccessible to Non-secure clients. It provides backing operations for the storage front ends, a Secure randomness operation, and the crypto partition's keystore object door. Each storage object is indexed by:

(calling Secure Partition, delegated end-client, UID)

This lets ITS and Protected Storage forward a guest's stamped client ID without allowing either front end to escape its own vault namespace.

The vault uses the wolfHSM NVM object-store library and checked operations for write-once and object-metadata policy in both engines. Storage calls cannot create, read, or overwrite the reserved key-object type. The vault also serves a keystore object door (WT_VAULT_OP_NVM_*) to the crypto partition alone: the crypto engine's persistent key objects live in the vault's store, but the crypto partition reaches them only through this FF-M service, which admits only wolfHSM keystore ids and key-flagged vault objects and never the directory, seal key, rollback table, or a storage front end's objects. The crypto partition is confined to that door: every other vault request from it (storage, WT_VAULT_OP_KEY_*, RANDOM) returns PSA_ERROR_NOT_PERMITTED, and keys are managed behind SERVICE_HSM.

Internal Trusted Storage

SERVICE_ITS implements PSA ITS 1.0:

  • psa_its_set
  • psa_its_get
  • psa_its_get_info
  • psa_its_remove

UID zero is invalid. The current public client shim limits each write, and therefore every ITS object it creates, to 512 bytes. The underlying Secure vault uses a 1024-byte object buffer, and its 24-byte request header caps one copied vault response at 1000 bytes. A client can use data_offset when its own output buffer is smaller than the object. The write-once flag is enforced by both the front end and checked NVM metadata. ITS data is held in Secure-only storage, but ITS does not add the Protected Storage sealing flag.

The current storage path always enforces PSA_STORAGE_FLAG_WRITE_ONCE, including during PSA_ROT_PROVISIONING. This differs from PSA Secure Storage 1.0, which requires the flag not to be enforced in that lifecycle state. The same deviation applies to Protected Storage objects created with the flag.

Protected Storage

SERVICE_PS implements the core PSA Protected Storage 1.0 set/get/get-info/remove operations. psa_ps_get_support() returns 0; psa_ps_create and psa_ps_set_extended return PSA_ERROR_NOT_SUPPORTED.

Every Protected Storage object created through the public shim is likewise limited to 512 bytes. The underlying Secure vault still uses a 1024-byte object buffer and caps one copied vault response at 1000 bytes.

Every stored object is AES-256-GCM sealed in the vault under a device-local non-exportable key in the shared NVM store. A persisted write counter supplies the nonce and the object label is authenticated data. Confidentiality and replay-protection hint flags do not weaken storage: Protected Storage still seals and counter-binds the object. The current psa_ps_get_info() behavior echoes the requested flags instead of reporting the stronger protection actually applied, which differs from the PSA Secure Storage 1.0 recommendation.

Initial Attestation

SERVICE_ATTEST implements the token and exact-size API operations from PSA Initial Attestation 1.0. It accepts a 32-, 48-, or 64-byte challenge and returns a tagged COSE_Sign1 token signed with ES256 through an external signer backed by the selected engine's protected attestation key. wolfCOSE performs the COSE encoding.

The emitted token is derived from RFC 9783 but is not conformant with its advertised tag:psacertified.org,2023:psa#tfm profile. Its boot seed is deterministic across equivalent boots, its software-component measurement type and description values are reversed, its signer ID hashes the literal name wolfBoot rather than identifying the signing key, and its implementation ID hashes a software label rather than identifying the immutable PSA RoT hardware assembly. TF-M Compatibility records these token-profile and API deviations.

The EAT/PSA claim set binds:

  • the challenge;
  • device and implementation identifiers;
  • the SPM-stamped client ID;
  • authenticated lifecycle state;
  • the measured wolfTrust boot; and
  • one software component for each guest that passed launch verification.

The service also supports internal call types for exact token-size and uncompressed P-256 public-key queries. The attestation partition holds no key material: every signature and the public key come from SERVICE_HSM's attestation door (WT_HSM_OP_ATTEST_SIGN, WT_HSM_OP_ATTEST_PUBLIC_KEY), which serves the attestation partition alone and refuses every other client. SERVICE_HSM's ordinary crypto wire (PSA_IPC_CALL) serves Non-secure clients only, so the attestation partition cannot use it. The private attestation key is never exported.

Firmware Update

SERVICE_FWU exposes a single-component subset of PSA Firmware Update 1.0. It pads an unaligned block size to the backend write alignment and returns PSA_ERROR_INVALID_ARGUMENT rather than PSA_ERROR_DOES_NOT_EXIST for an unknown component ID. The normal flow is:

READY -> WRITING -> CANDIDATE -> STAGED -> authenticated reboot

Writes are copied, bounded, offset-aligned, padded with erased-flash bytes when needed, and staged in the wolfBoot update partition. Finish validates the image header and binds the candidate version. Install checks the candidate again against the persistent version floor loaded when the Firmware Update partition started, then writes the wolfBoot update trigger. A reboot request is allowed only for the client that owns an armed staged update.

The integration commits the installed image at authenticated reboot and does not persist a trial state. psa_fwu_accept() therefore returns PSA_ERROR_NOT_SUPPORTED. Cancel, reject, and clean disarm or reset eligible pre-reboot state. A successful psa_fwu_start() sets the owner timer. While the session remains active, any owner operation other than psa_fwu_query() or psa_fwu_start() that reaches dispatch refreshes the timer, even if the operation fails or is unsupported. After 30,000 scheduler ticks without such a refresh, the next well-formed request from a different client reclaims the session. Ownership does not expire autonomously.

Optional virtual network

CONFIG_VNET=y adds SERVICE_VNET and a Secure virtual Ethernet switch. Guests open a port, optionally set a MAC address, transmit a copied frame, fetch a copied received frame, and acknowledge the virtual receive interrupt through FF-M operations.

Port selection comes from the stamped caller identity. Secure pool tokens and generation counters do not cross into a guest. The mediated PSA transport MTU is 1000 bytes so a frame and receive metadata fit the copied-transfer budget.

See API Reference for client signatures and Macros for service build controls.

Clone this wiki locally