7.15 audit 2/6: authenticated clear-signing - #360
Conversation
|
CI queue note: this head was explicitly dispatched at https://github.com/BitHighlander/keepkey-firmware/actions/runs/31128230883 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. |
Adds the signed-metadata engine: a host may supply a description of what an EVM transaction does (contract alias, method, argument labels), and the device displays it only if the blob carries a signature from a trust anchor it already holds. Unsigned or wrongly signed metadata is ignored — it can never turn a blind-signing prompt into a friendly one. - Anchor verification over secp256k1 with the schema bound to the request, so a signature captured from one transaction cannot dress up another. - Runtime signer table only; nothing is persisted to public flash. A rogue entry surviving a reboot would suppress the raw-data screen, which is exactly the failure this design refuses. - tiny-json gains the bounds needed to parse metadata safely on device. - unittests/firmware/signed_metadata.cpp covers the accept/reject matrix, including malformed blobs and signature/schema mismatches. Message plumbing and the Ethereum call sites arrive in the clear-sign EVM branch; this commit is the engine and its tests only.
…hemas Solana signing moves from "confirm this blob" to describing the actual instructions, using schemas that are signed once and reused: - v0 (versioned) transactions and address-table lookups are parsed, and the instruction set is rendered per program: transfers, token transfers, memo bodies and offchain messages. - A schema describes a program's instruction layout (discriminator, argument types and labels) and carries a signature with no transaction hash bound to it, so one blob covers every call of that shape instead of needing a fresh signature per transaction. - x402 payment requests are clear-signed through the same path: the payment amount, asset and recipient are shown from schema-described fields rather than trusting host-supplied text. - Anything without a verified schema still reaches the raw-data screen. - unittests/firmware/solana.cpp covers v0 parsing, schema decode, argument rendering and the reject paths for malformed or unsigned schemas.
Uses the signed-metadata engine on the Ethereum path so a user sees what a contract call actually does instead of a hex blob: - EthereumTxMetadata carries the signed description and EthereumMetadataAck acknowledges it; LoadClearsignSigner installs a trust anchor for the current session only. Metadata that fails verification is dropped and the transaction falls back to raw display — it never degrades to a friendlier screen. - EIP-712 typed data: domain/primary-type handling is corrected, the policy gate decides when a typed hash may be signed at all, and the recursion and length limits are enforced rather than assumed. - EIP-7702 authorization lists are recognised and shown. - ERC-20 and the bundled contract decoders (THORChain router, liquidity and swap proxies) check the selector against the argument shape before claiming to know what a call means. - A factory reset clears loaded signers. - unittests/firmware/eip712.cpp and the extended ethereum.cpp cover the typed data limits, selector mismatches and the metadata accept/reject paths.
Adds messages 1700-1703 so a KeepKey can issue the schema signatures the clear-sign path verifies, instead of every schema having to come from an offline signing ceremony. - ClearsignAttestorGetPublicKey exports the attestor key; ClearsignAttestorSign signs a schema after showing the user what they are attesting to — program identity, discriminator, and each argument label with its type and width. - Self-service attestation is gated behind advanced mode, so a default device cannot be talked into minting trust for an attacker's schema. - The signed variant ships the built-in anchor table, so schemas issued this way verify on a stock device with nothing loaded. - scripts/emulator/capture-clearsign-attestor.py reproduces the OLED sequence, and docs/security/evidence/7.15.0-rc21-clearsign-attestor holds the captured frames including the 44-character program id and 16-character label bounds.
53b14bb to
6c27e11
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 features share one trust boundary: host-provided descriptions are useful only when the device can authenticate their schema and bind every displayed value to the signed payload.
Validation
git diff --checkStack: 2 of 6. Review only the diff from
release/715-audit-01-foundation.