7.15 audit 3/6: recovery and entropy - #361
Conversation
|
CI queue note: this head was explicitly dispatched at https://github.com/BitHighlander/keepkey-firmware/actions/runs/31128231140 after the superseded 17-PR stack saturated the Actions queue. GitHub currently shows the jobs queued before runner assignment. The complete aggregate independently passed the CI-equivalent container suite locally: 405 firmware, 2 board, 18 crypto, and 7 Pallas constant-time tests, plus actionlint, gitleaks, the Pallas API-boundary gate, and git diff --check. |
Storage: - The PIN key-derivation function is versioned so its cost can be raised without breaking existing wallets, with the migration path documented in docs/security/pin-kdf-v19-migration.md. - A wallet created by bitcoin-only firmware is stamped, and multi-chain firmware refuses to touch it (storage_isBitcoinOnlyLocked) rather than silently operating on a wallet whose owner chose a reduced attack surface. - Storage layout reserves the clear-sign identity block and zeroes it on read and on wipe, so nothing there can outlive a factory reset. - Orchard key derivation and seed fingerprinting are reachable through storage with progress reporting, guarded by the privacy build flag. - docs/security/anti-rollback-security-epoch-rfc.md records the proposed security-epoch scheme; it is a design note, nothing here implements it. BIP-85: - GetBip85Mnemonic derives a child mnemonic and displays it under constant power, with PIN and initialization checks. Always available — it is a seed derivation, not a coin engine. Recovery and authenticator: - The cipher-recovery wordlist permutation now borrows the shared frame arena instead of another multi-kilobyte stack buffer. - wipeAuthData reports failure instead of always claiming success, a cancelled authenticator action is distinguishable from an error, and a cancelled passphrase prompt aborts the request instead of continuing without one.
…isplay RNG: - The RNG source selection is explicit and reportable, and a host can pull bulk samples for a health audit: a per-boot 64 KB budget replaces the press-per-kilobyte prompt that made auditing real hardware impossible. Scope is stated honestly in the code and docs — bulk output supports HEALTH testing (stuck/biased output, repeated buffers, transport caching, gross correlation), not a bound on the entropy of the generator's internal state. - On an uninitialized device, one press unlocks the bulk audit; on an initialized device the confirm still gates entropy after the budget is spent. - The emulator gets a real CSPRNG (lib/emulator/random.c, BCryptGenRandom on Windows) instead of libc random(), which CI now enforces. Dice: - ResetDevice can request on-device dice entropy: short press advances 1-6, long press confirms, undo is available, and the roll digest is confirmed before the seed is mixed. Pre-initialization only. - The abort path disarms EntropyAck, so an aborted reset can no longer leave the device accepting host-supplied entropy for the seed. - Evidence frames under docs/security/evidence/dice-entropy-reset, reproducible with scripts/emulator/capture-dice-flow.py. Internal entropy is no longer displayed or returned: it is seed pre-image material. display_random stays in the wire schema for host compatibility and is ignored.
Restores the RC18 invariant that fails the build if lib/rand/rng.c falls back to libc random(). It was previously declared in the foundation slice, three PRs before the emulatorRandom() implementation landed, so it only ever fired on code its own PR could not fix. Here it guards a change that is present in the same commit range, which is the whole point of a build-config invariant: the July 2026 COLDCARD loss came from a build selecting the wrong RNG silently, and a gate that cries wolf is one reviewers learn to skip.
53b14bb to
6c27e11
Compare
e3457e0 to
39555bd
Compare
|
Superseded by #364, which now carries the whole 7.15 stack against develop. Once the CI gate stopped short-circuiting the build (the libc-random() invariant was asserted three slices before the fix that satisfies it, so check-submodules failed and every build/test job was SKIPPED), these branches compiled for the first time — and none of them compile. The topic-based split cuts across at least three signature/caller pairs:
The dependency graph is a tangle, not a chain, so re-slicing it by build order means re-authoring the release. Only the complete set compiles, and #364 is green. No content is dropped. |
What changed
Why
These changes all govern seed creation, derivation, storage, and recovery. Keeping them together makes the secret-lifecycle audit continuous instead of splitting state transitions across PRs.
Validation
git diff --checkStack: 3 of 6. Review only the diff from
release/715-audit-02-clearsigning.