Skip to content

attester: add PRoT software component reporting the OP-TEE OS version#3

Open
mmxsrup wants to merge 9 commits into
mainfrom
pr/prot-os-version
Open

attester: add PRoT software component reporting the OP-TEE OS version#3
mmxsrup wants to merge 9 commits into
mainfrom
pr/prot-os-version

Conversation

@mmxsrup

@mmxsrup mmxsrup commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a second PSA software component (measurement-type: "PRoT") reporting the OP-TEE OS version, alongside the existing ARoT (TA) component. implementation-id and signer-id are unchanged.

  • hash.c: get_hash_tee_memory() — SHA-256 of the core .text + .rodata (mirrors the upstream attestation PTA).
  • cbor.{c,h}: software components passed as an array; optional version (attester: add RA_PERF performance measurement logging #4) field emitted.
  • remote_attestation.c: OS version taken from core_v_str (e.g. "4.6.0"); builds ARoT + PRoT.

Reference values: computed offline, registered per build

  • provisoning/compute-prot-refval.py tee.elf — PRoT. Build-specific (the build timestamp is part of the hashed .rodata), so recompute per release. Yocto builds are reproducible (bit-identical tee.elf for the same source), so same-source rebuilds keep the value valid.
  • provisoning/compute-arot-refval.py <uuid>.ta — ARoT (ELF-header page + read-only PT_LOAD segments, smallest-first). No first device run needed; required on i.MX production builds, which print no core trace.

Both verified on QEMU: script output == runtime measurement.

Verification (QEMU E2E)

  • ear.status: affirming, executables: 2, components [ARoT, PRoT(version="4.6.0-dev")].
  • PRoT matching active: correct reference value → affirming; wrong value (simulated build change) → warning.

Scope

Based on pr/psa-claims-rfc9783, so this PR also carries that branch's commits. New here: the PRoT component, the offline reference-value scripts and registered i.MX values, and docs.

mmxsrup and others added 6 commits February 20, 2026 08:57
- Measurement Type: "PRoT" → "ARoT" (TA is an ARoT component)
- Implementation ID: move from TA to PTA, platform-specific values
  (imx8mp-optee-ra-... / qemu-optee-ra-...)
- Client ID: derive from caller TA UUID instead of hardcoded value
- Signer ID: read SRK hash from OCOTP fuses on i.MX8MP, test fallback on QEMU
- Lifecycle: determine from fuse state on i.MX8MP, 0x3000 fallback on QEMU

Platform-specific code gated by CFG_NXP_CAAM.
Verified on QEMU with CBOR decode of all 5 claims.
Update comid-psa-refval-imx.json and comid-psa-ta.json with actual
device values:
- signer-id: SRK hash read from OCOTP fuses
- measurement-value: TA memory hash from real hardware
- impl-id: platform-specific implementation ID
- instance-id and verification key: CAAM-generated keypair
- Fix instance-id and comid-psa-ta.json references across all READMEs
- Separate English and Japanese into dedicated files
  (README.md / README-j.md, provisoning/README.md / provisoning/README-j.md)
Emit a second PSA software component (measurement-type "PRoT") for the OP-TEE OS itself, alongside the existing "ARoT" component for the TA.

hash.c: add get_hash_tee_memory(), a runtime SHA-256 over the core's immutable .text + .rodata (mirrors the upstream attestation PTA cmd_hash_tee_memory). The hashed range excludes relocated data (.data.rel.ro/.got live outside __rodata_start..__rodata_end), so it is reproducible across boots even with CFG_CORE_ASLR=y.

cbor.{c,h}: generalize encode_evidence_to_cbor() to take an array of psa_sw_component and emit the optional version field (#4).

remote_attestation.c: derive the OP-TEE OS version from core_v_str (e.g. "4.6.0") and build ARoT + PRoT components; signer-id stays the SRK hash and implementation-id is unchanged. A debug line logs the PRoT measurement in base64 for capturing the Veraison reference value.

Verification stays affirming with no provisioning change: the existing ARoT reference value still matches, and the new PRoT component is ignored until a "PRoT" reference value is provisioned.
The i.MX secure-boot output dir holds multi-hundred-MB WIC images and CST private keys owned by another user, which break and bloat the QEMU attester docker build context. It is not needed for that build.
Show the PRoT entry in the verification-result example (README.md / README-j.md) and explain that the OP-TEE OS is identified by the stable version field. Its measurement-value is a build-specific runtime hash (OP-TEE embeds the build timestamp in core_v_str, part of the hashed .rodata), so it is not provisioned as a reference value; the verifier ignores the PRoT component and ear.status stays affirming. OS integrity is rooted in HAB/SRK secure boot.
mmxsrup added 3 commits June 11, 2026 00:48
The client confirmed that the PRoT measurement-value changing on every
build is acceptable, so the PRoT component is now verified by Veraison
instead of being left unprovisioned: register the build's reference
value and a matching build stays affirming while a different OP-TEE
build (or modified code) is flagged as warning.

Add provisoning/compute-prot-refval.py, the offline equivalent of the
PTA's get_hash_tee_memory(): it computes the PRoT measurement-value
from the tee.elf build artifact (same VA spans, same order), so the
reference value can be obtained without booting the image or raising
the core log level (i.MX production builds compile out all core trace).
Verified on QEMU: the script output is identical to the runtime
measurement reported by the PTA.

Register the PRoT reference value of the current signed i.MX8MP build
in comid-psa-refval-imx.json, and update the README note to describe
the per-build provisioning flow. Note that Yocto optee-os builds are
reproducible (SOURCE_DATE_EPOCH is set and the build counter resets on
clean builds — confirmed: two cleansstate builds of identical source
produce bit-identical tee.elf), so rebuilding the same source does not
invalidate the registered value; QEMU container builds are not
reproducible and need a fresh value per build.
The ARoT measurement (get_hash_ta_memory) hashes the TA's read-only
regions as mapped by ldelf: the ELF-header page (ldelf maps file offset
0, one page, read-only — see init_elf()) plus every read-only PT_LOAD
segment zero-padded to its page-rounded memsz, hashed smallest-first
(ties by content, matching the runtime cmp_regions() ASLR-stable
ordering). Since TA text/rodata contain no load-base-dependent bytes
(all relocations target the writable segment), this can be reproduced
from the build artifact alone.

Add provisoning/compute-arot-refval.py implementing exactly that;
verified on QEMU that its output is identical to the runtime
measurement, both from the TA ELF and from the signed .ta (the signed
header is skipped automatically). The script warns if a relocation
targets a read-only segment, in which case the offline value may not
match the runtime one.

Update comid-psa-refval-imx.json with the ARoT value computed from the
current signed i.MX8MP build (replacing the stale value from an older
build), so both ARoT and PRoT reference values can now be provisioned
from build artifacts without a first device run, and document the
script in the READMEs.
Update the new-TA registration steps (section 6.2) to recommend
computing the ARoT measurement-value offline from the build artifact
with provisoning/compute-arot-refval.py instead of capturing the debug
output of a first run; the run-capture method remains documented as an
alternative for debug builds, with a note that it is unavailable on
i.MX production builds (core log level 0). Add an offline-computation
section to the provisioning READMEs covering both scripts (ARoT and
PRoT), when each value changes, and the pyelftools requirement.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant