OpenSourceCheck

OSC-2026-0005 · github.com/KeystoneHQ/keystone3-firmware

info clean-run claude-fable-5 2026-08-04 signed: nostr

Repository
github.com/KeystoneHQ/keystone3-firmware
Commit
31f1fa88a522f492b9ad6260c4c3e316bd209b32
Scope path
src/managers/keystore.c
Model
claude-fable-5
Harness
claude-code
Prompts
prompts/entropy-rng-audit-v1.md
Independent runs
1
Transcript sha256
a0f8d42e23dd7721e4677db6fa89235d85fda82682b1decc24b3359e1ef94780
Auditor
TheIcarusWings (theicaruswings)
Signature
nostr-schnorr · npub19tzp8lf3klmqj3dz9mz0qnuvjp7uyy9993gmljmyaxs8phztj7wsnujvq5

Scope. AMENDED 2026-08-04 (original in git history). Seed-entropy generation at HEAD 31f1fa88: GenerateEntropy (src/managers/keystore.c:75), the read path of the MH1903 TRNG driver (src/driver/drv_trng.c), and whether raw entropy can leak via debug output. In scope: number and independence of entropy sources, KDF mixing, error handling of the secure-element RNG calls, debug-gating, buffer clearing. EXPLICITLY NOT EXAMINED: the TRNG driver s status/attack-bit handling - TrngGet was read but its treatment of the MH1903 TRNG ATTACK status bit was not reviewed; a later independent audit (OSC-2026-0017) found it is never inspected, which I have since verified. Also not in scope: the rest of the firmware (PSBT/signing, USB/QR transport, secure-element provisioning, bootloader, vendored external/ libraries), the physical quality of the hardware RNGs, and the Rust components under rust/.

Findings

info OSC-2026-0005-F1 unreviewed

No weakness found in scope; the design specifically resists the Coldcard failure class. Seed entropy is derived from THREE independent hardware sources - the MCU TRNG (SE_GetTRng), the DS28S60 secure element, and the ATECC608B secure element - each folded in via a separate HKDF step with the running value chained forward, and seeded initially from a password-derived salt (HashWithSalt). Degrading or compromising any single source still leaves two independent hardware sources feeding the chain, which is exactly what Coldcard lacked. Raw entropy is never printed in production: every KEYSTORE_PRINT_ARRAY expands to nothing because KEYSTORE_DEBUG is hardcoded to 0 in source (keystore.c:36) rather than set by a build flag, so a build configuration cannot silently enable it - the inverse of the MICROPY_HW_ENABLE_RNG=0 build-flag failure. Working buffers are cleared via CLEAR_ARRAY on all paths. Observation (not a defect): error handling is asymmetric - SE_GetDS28S60Rng and SE_GetAtecc608bRng are checked with CHECK_ERRCODE_BREAK but SE_GetTRng's return value is unchecked, so a silent failure there would mix in a stale buffer. Not exploitable as written, since the two checked sources are still mixed in afterward; noted only because checking all three would make the 'at least N good sources' property explicit rather than incidental.

src/managers/keystore.c:75 (GenerateEntropy), src/managers/keystore.c:36 (KEYSTORE_DEBUG gate), src/driver/drv_trng.c:12 (TrngGet) · CWE-390