ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_rot.h File Reference

Root-of-trust signed-image verifier (SHA-256 + ECDSA-P256, default-deny). More...

#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_err.h"
Include dependency graph for ra8_rot.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ra8_rot_trailer_t
 Authenticity trailer appended after a signed image body. More...

Enumerations

enum  ra8_rot_size_t : uint8_t {
  k_ra8_rot_digest_bytes = 32U ,
  k_ra8_rot_sig_bytes = 64U ,
  k_ra8_rot_pubkey_bytes = 65U
}
 Fixed byte-lengths of the cryptographic fields in a signed image. More...
enum  ra8_rot_const_t : uint32_t {
  k_ra8_rot_trailer_magic = 0x524F5431U ,
  k_ra8_rot_version = 0x00000001U ,
  k_ra8_rot_body_max = 0x00100000U
}
 Trailer magic / version and the body-length sanity cap. More...

Functions

ra8_err_t ra8_rot_verify_image (const uint8_t *body, uint32_t body_len, const ra8_rot_trailer_t *trailer)
 Authenticate a signed image: SHA-256 + ECDSA-P256, default-deny.
const ra8_rot_trailer_tra8_rot_trailer_after (const void *image_base, uint32_t body_len)
 Locate the trailer that immediately follows a signed image body.
ra8_err_t ra8_rot_root_public_key (const uint8_t **out_key, uint32_t *out_len)
 Expose the provisioned root public key (host / test only).

Detailed Description

Root-of-trust signed-image verifier (SHA-256 + ECDSA-P256, default-deny).

Tag
[Ring 4 / Service] {World: S}

The shared authenticity gate placed at the firmware's two trust boundaries:

Historically both boundaries trusted a CRC32 only (integrity, not authenticity): a CRC-correct image of any origin would launch. This module adds the missing authenticity check – a digital signature anchored to a public key provisioned into the Secure firmware – and enforces default-deny: any failure (missing trailer, wrong format, hash mismatch, or an invalid signature) returns an error and the caller must NOT launch.

Signed-image format

A signed image is [ body (body_len bytes) ] [ ra8_rot_trailer_t ]. The trailer carries the SHA-256 digest of the body and an ECDSA-P256 signature (raw r || s) over that digest. The verifier:

  1. confirms the trailer magic + version (missing / malformed trailer -> deny);
  2. re-computes SHA-256 over the body (the RSIP hardware hash on target, the ra8_psa software hash in RA8_OFF_TARGET);
  3. confirms the freshly-computed digest equals the trailer digest (tampered body -> deny); and
  4. verifies the ECDSA-P256 signature over the freshly-computed digest against the provisioned root public key (forged / mis-signed -> deny).

The signature – not the digest field and not any CRC – is the authority: step 4 verifies over the re-computed digest, so a matching trailer digest is never sufficient on its own.

Enabling (opt-in, default OFF)

The whole root of trust is gated behind the RA8_ENABLE_ROOT_OF_TRUST build flag (default OFF), mirroring RA8_BOOT_ENABLE_CACHE_MPU:

  • Flag OFF (default): ra8_rot.c compiles to nothing and pulls in no crypto libraries; the launch boundaries do NOT verify. Existing apps – including unsigned images (dfu_copy_to_run, dfu_bootloader, and the current Non-Secure images) – are unchanged and launch as before.
  • Flag ON: the app opts in via target_compile_definitions(<app> PRIVATE RA8_ENABLE_ROOT_OF_TRUST) and MUST then also (a) link ra8_psa_crypto + the RSIP HAL, and (b) sign its DFU / Non-Secure images with an ra8_rot_trailer_t – otherwise every launch default-denies.

The declarations below are always visible (they reference no external symbols, so a flag-off translation unit has zero extra link dependencies); only the implementation in ra8_rot.c is flag-gated.

Note
On silicon, the ECDSA-P256 + SHA-256 known-answer tests pass on the M85 (hil_needs_revalidation/psa_crypto_hil, rsip_sha256_kat), the real root public key is provisioned (see ra8_rot.c), and RoT enforcement is proven end-to-end by hw_validated/hil/secure_boot_hil. The host unit tests enable the flag and exercise the gate's decision logic against the RA8_OFF_TARGET crypto stand-ins; the remaining production step is to sign each shipped image and enable the flag on the boot path.
See also
ROT1 – The Root-of-Trust Signed-Image Trailer – the full ROT1 wire-format specification (rationale, algorithms, worked example, failure modes).

Definition in file ra8_rot.h.

Enumeration Type Documentation

◆ ra8_rot_const_t

enum ra8_rot_const_t : uint32_t

Trailer magic / version and the body-length sanity cap.

The 1 MiB body cap comfortably exceeds both the largest DFU slot image (k_ra8_dfu_img_max ~= 448 KiB) and the Non-Secure MRAM partition (512 KiB), while bounding the hash loop so a corrupt body_len cannot drive an unbounded read (NASA Rule 2).

Enumerator
k_ra8_rot_trailer_magic 

ASCII "ROT1" – signed-image marker.

k_ra8_rot_version 

Trailer format version.

k_ra8_rot_body_max 

Max signable body length (1 MiB cap).

Definition at line 116 of file ra8_rot.h.

◆ ra8_rot_size_t

enum ra8_rot_size_t : uint8_t

Fixed byte-lengths of the cryptographic fields in a signed image.

SHA-256 produces a 32-byte digest (FIPS 180-4). An ECDSA-P256 signature is the raw concatenation r || s of two 32-byte field elements = 64 bytes (FIPS 186-4). An uncompressed NIST P-256 public key is the 65-byte string 0x04 || X(32) || Y(32) (SEC1 v2 Sec 2.3.3).

Enumerator
k_ra8_rot_digest_bytes 

SHA-256 digest length (FIPS 180-4).

k_ra8_rot_sig_bytes 

ECDSA-P256 raw r||s signature length.

k_ra8_rot_pubkey_bytes 

Uncompressed P-256 public key (0x04||X||Y).

Definition at line 100 of file ra8_rot.h.

Function Documentation

◆ ra8_rot_root_public_key()

ra8_err_t ra8_rot_root_public_key ( const uint8_t ** out_key,
uint32_t * out_len )

Expose the provisioned root public key (host / test only).

Host-only accessor: lets the unit tests forge a correctly-signed trailer using the same key bytes the verifier trusts, so the gate's decision logic can be driven end-to-end against the RA8_OFF_TARGET crypto stand-ins. The key is a public value, so exposing it leaks nothing.

Parameters
[out]out_keyReceives a pointer to the embedded key bytes; non-NULL.
[out]out_lenReceives the key length in bytes; non-NULL.
Returns
ra8_err_t Error code.
Return values
k_ra8_ok*out_key / *out_len populated.
k_ra8_err_null_ptrout_key or out_len is NULL.
Precondition
out_key and out_len are non-NULL.
The caller is a host unit test (the symbol is a test helper).
Postcondition
*out_len == k_ra8_rot_pubkey_bytes on success.
No state is mutated.
Note
Test-only helper; production code never reads the key through this accessor.
Since
0.1.0

References RA8_TEST_HELPER.

◆ ra8_rot_trailer_after()

const ra8_rot_trailer_t * ra8_rot_trailer_after ( const void * image_base,
uint32_t body_len )

Locate the trailer that immediately follows a signed image body.

For the [ body ] [ trailer ] layout the trailer begins at image_base + body_len. A thin, side-effect-free helper so the copy-to-run path expresses the layout contract explicitly rather than with an inline pointer cast.

Parameters
[in]image_baseBase of the signed image (its body); non-NULL.
[in]body_lenBody length in bytes; (0, k_ra8_rot_body_max].
Returns
Pointer to the trailer that follows the body.
Return values
non-NULLimage_base + body_len reinterpreted as a trailer.
nullptrimage_base is NULL or body_len is out of range.
Precondition
image_base addresses at least body_len + sizeof(ra8_rot_trailer_t) readable bytes.
body_len is the length recorded in the image's DFU header.
Postcondition
No state is mutated; the result depends only on the inputs.
The returned pointer, when non-NULL, lies at image_base + body_len.
Note
Thread-safe (pure; no statics).
See also
ra8_rot_verify_image
Since
0.1.0

Referenced by internal_ns_verify_or_deny(), rot_genuine_ok(), and rot_tamper_rejected().

◆ ra8_rot_verify_image()

ra8_err_t ra8_rot_verify_image ( const uint8_t * body,
uint32_t body_len,
const ra8_rot_trailer_t * trailer )
nodiscard

Authenticate a signed image: SHA-256 + ECDSA-P256, default-deny.

The shared root-of-trust gate for both the copy-to-run and BLXNS boundaries. Re-computes SHA-256 over [body, body + body_len) (ra8_rsip_sha256 on target, ra8_psa_hash_compute under RA8_OFF_TARGET), cross-checks it against trailer->digest, then verifies trailer->sig over the freshly-computed digest against the provisioned root public key via ra8_psa_verify_hash (algorithm k_ra8_psa_alg_ecdsa_sha_256). The signature is the authority; the trailer digest is only a fast pre-check.

Any failure returns a non-k_ra8_ok error – the caller MUST treat that as DENY and not launch / not branch.

Parameters
[in]bodyPointer to the image body's first byte; non-NULL.
[in]body_lenBody length in bytes; (0, k_ra8_rot_body_max] and equal to trailer->body_len.
[in]trailerAuthenticity trailer that follows the body; non-NULL.
Returns
ra8_err_t Error code.
Return values
k_ra8_okImage is authentic – launch is permitted.
k_ra8_err_null_ptrbody or trailer is NULL (missing trailer -> deny).
k_ra8_err_validation_failedTrailer magic / version wrong (malformed trailer -> deny).
k_ra8_err_invalid_sizebody_len out of range, mismatched against the trailer, or sig_len invalid.
k_ra8_err_checksum_mismatchRe-computed digest differs from the trailer digest (tampered body -> deny).
k_ra8_err_crc_mismatchSignature did not verify (forged / mis-signed -> deny).
k_ra8_err_hw_errorUnderlying hash / verify engine fault.
Precondition
body addresses at least body_len readable bytes.
trailer addresses a readable ra8_rot_trailer_t.
Postcondition
On any non-k_ra8_ok return the caller must NOT launch the image.
No image bytes are modified; the verifier is read-only over its input.
Note
Not thread-safe: imports + destroys a transient PSA verify key in the shared static key pool. Call from the single-threaded boot path.
On-silicon ECDSA-P256 KAT (hil_needs_revalidation/psa_crypto_hil) and root-key provisioning are done; enforcement is proven by hw_validated/hil/secure_boot_hil.
See also
ra8_rot_trailer_after
ra8_psa_verify_hash
Since
0.1.0

Referenced by internal_ns_verify_or_deny(), rot_genuine_ok(), and rot_tamper_rejected().