|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Root-of-trust signed-image verifier (SHA-256 + ECDSA-P256, default-deny). More...
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_t * | ra8_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). | |
Root-of-trust signed-image verifier (SHA-256 + ECDSA-P256, default-deny).
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.
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:
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.
The whole root of trust is gated behind the RA8_ENABLE_ROOT_OF_TRUST build flag (default OFF), mirroring RA8_BOOT_ENABLE_CACHE_MPU:
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.
Definition in file ra8_rot.h.
| 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). |
| 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). |
| 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.
| [out] | out_key | Receives a pointer to the embedded key bytes; non-NULL. |
| [out] | out_len | Receives the key length in bytes; non-NULL. |
| k_ra8_ok | *out_key / *out_len populated. |
| k_ra8_err_null_ptr | out_key or out_len is NULL. |
References RA8_TEST_HELPER.
| 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.
| [in] | image_base | Base of the signed image (its body); non-NULL. |
| [in] | body_len | Body length in bytes; (0, k_ra8_rot_body_max]. |
| non-NULL | image_base + body_len reinterpreted as a trailer. |
| nullptr | image_base is NULL or body_len is out of range. |
Referenced by internal_ns_verify_or_deny(), rot_genuine_ok(), and rot_tamper_rejected().
|
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.
| [in] | body | Pointer to the image body's first byte; non-NULL. |
| [in] | body_len | Body length in bytes; (0, k_ra8_rot_body_max] and equal to trailer->body_len. |
| [in] | trailer | Authenticity trailer that follows the body; non-NULL. |
| k_ra8_ok | Image is authentic – launch is permitted. |
| k_ra8_err_null_ptr | body or trailer is NULL (missing trailer -> deny). |
| k_ra8_err_validation_failed | Trailer magic / version wrong (malformed trailer -> deny). |
| k_ra8_err_invalid_size | body_len out of range, mismatched against the trailer, or sig_len invalid. |
| k_ra8_err_checksum_mismatch | Re-computed digest differs from the trailer digest (tampered body -> deny). |
| k_ra8_err_crc_mismatch | Signature did not verify (forged / mis-signed -> deny). |
| k_ra8_err_hw_error | Underlying hash / verify engine fault. |
Referenced by internal_ns_verify_or_deny(), rot_genuine_ok(), and rot_tamper_rejected().