ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
rot_patch_pubkey.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# SPDX-License-Identifier: MIT
3# Copyright (c) 2026 Brighton Sikarskie
4"""Provision a root-of-trust public key into ra8_rot.c.
5
6Rewrites the single `s_rot_root_pubkey[...]` initialiser in ra8_rot.c from a C
7header emitted by `scripts/secrets/rot_sign.py keygen --pubkey-c`. The provisioning
8ceremony (scripts/secrets/rot_provision.sh) and the re-key flow (scripts/secrets/rot_keystore.py
9rekey) both call this, so the patch logic lives in exactly one place -- two
10copies of it drifting is how a board gets provisioned with a key that does not
11match the one images are signed with.
12
13The rewrite is in place and unconditional: ra8_rot.c is overwritten with no
14backup, and the array it replaces is matched by a regex on the exact
15declaration text. Renaming or reformatting that declaration in ra8_rot.c makes
16the match fail rather than silently patch the wrong thing.
17
18Usage:
19 python3 scripts/secrets/rot_patch_pubkey.py <ra8_rot.c> <pubkey-c-header>
20"""
21
22from __future__ import annotations
23
24import re
25import sys
26from pathlib import Path
27
28_ARGC = 3
29_ARRAY_RE = re.compile(
30 r"static const uint8_t s_rot_root_pubkey\‍[k_ra8_rot_pubkey_bytes\‍] = \{.*?\n\};",
31 re.DOTALL,
32)
33
34
35def patch(rot_c: str, header: str) -> None:
36 """Replace the s_rot_root_pubkey array in rot_c with the header's bytes."""
37 lines = Path(header).read_text(encoding="ascii").splitlines()
38 body = "\n".join(line for line in lines if line.strip().startswith("0x"))
39 if not body:
40 sys.exit(f"no 0x.. byte lines found in {header}")
41 new_array = (
42 "static const uint8_t s_rot_root_pubkey[k_ra8_rot_pubkey_bytes] = {\n" + body + "\n};"
43 )
44 src = Path(rot_c).read_text(encoding="ascii")
45 patched, n = _ARRAY_RE.subn(new_array, src, count=1)
46 if n != 1:
47 sys.exit(f"expected exactly one s_rot_root_pubkey definition, found {n}")
48 Path(rot_c).write_text(patched, encoding="ascii")
49 print(f"patched {rot_c}")
50
51
52def main(argv: list[str]) -> int:
53 """CLI entry: patch(argv[1] = ra8_rot.c, argv[2] = pubkey-c header)."""
54 if len(argv) != _ARGC:
55 sys.stderr.write("usage: rot_patch_pubkey.py <ra8_rot.c> <pubkey-c-header>\n")
56 return 2
57 patch(argv[1], argv[2])
58 return 0
59
60
61if __name__ == "__main__":
62 sys.exit(main(sys.argv))
void main(void)
The application entry point Reset_Handler hands control to.
Definition main.c:298