feat: user-provisioned metadata signing keys — slots 4-6 + storage v18#213
Closed
BitHighlander wants to merge 6 commits into
Closed
feat: user-provisioned metadata signing keys — slots 4-6 + storage v18#213BitHighlander wants to merge 6 commits into
BitHighlander wants to merge 6 commits into
Conversation
Owner
Author
|
Pre-existing CI note
The format issues there are pre-existing and not introduced by this PR. Either fixing them up here as a one-line follow-on or in a separate alpha-cleanup PR is fine — happy to do whichever you prefer. |
2 tasks
Lets KeepKey owners add their own secp256k1 signing keys at runtime so
companies / DAOs can publish their own clear-signing descriptor sets
that members verify on their own device, without firmware updates.
- 3 user slots (4..6) persisted in Storage.pub.metadata_keys, plus
STORAGE_VERSION bump 17 -> 18 with explicit V17->V18 migration that
zero-inits the new key array on existing devices.
- AddMetadataKey, RemoveMetadataKey, ListMetadataKeys handlers in
fsm_msg_metadata.h. Add: 2-step confirm (slot+label, then SHA-256
fingerprint), then PIN. Remove: confirm shows fingerprint of the key
being removed (defends against stealth removal on a briefly-unlocked
device). Slots 0..3 remain firmware-baked and cannot be overwritten.
- signed_metadata.c moves from a hardcoded METADATA_PUBKEYS lookup to a
unified metadata_get_pubkey() that resolves slot 0..3 from the static
firmware table and slot 4..6 from storage. Verification confirm screen
now shows the matching label ("Insight Verified" for slot 0,
"<label> Verified" for user slots).
- Pulls in device-protocol c7a824d which adds MetadataKeyType + the four
new wire messages.
BitHighlander
force-pushed
the
feat/user-metadata-keys
branch
from
April 25, 2026 03:32
e0071aa to
b1dbdd5
Compare
…fset (1541) The expected_flash had a hardcoded 0x11 at flash[1541] (encrypted_sec_version LE u32 byte 0). Bumping STORAGE_VERSION 17->18 made that mismatch — fixed by using the STORAGE_VERSION macro like the test does at flash[44] and [508], and updated the printf substitution loop so future bumps stay green.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Lets KeepKey owners add their own secp256k1 signing keys at runtime so companies / DAOs can publish their own clear-signing descriptor sets that members verify on their own device, without a firmware update.
Storage.pub.metadata_keysSTORAGE_VERSION17 → 18 with explicit V17→V18 migration that zero-inits the new key array on existing devicesAddMetadataKey/RemoveMetadataKey/ListMetadataKeyshandlers infsm_msg_metadata.hsigned_metadata.cmoved from a hardcodedMETADATA_PUBKEYSlookup to a unifiedmetadata_get_pubkey()that resolves slot 0-3 from the static firmware table and slot 4-6 from storage"Insight Verified"for slot 0,"<label> Verified"for user slotsDepends on
BitHighlander/device-protocol#26 — pulls submodule pin to that branch's tip.
Trust model
"Insight"(KeepKey-managed)Add/remove require PIN entry + 2 confirms (1 for label/slot, 1 for fingerprint). The fingerprint is SHA-256 of the pubkey, first 4 bytes (8 hex chars) — small enough for the OLED, stable enough to verify against a company-published value out-of-band.
Storage layout
V18 uses the V17 reserved region at offset 501 in the plaintext block:
metadata_keys_count(u32 LE){ used(1) + pubkey(33) + label(17 nul-padded) }V17 storage on disk reads cleanly —
storage_fromFlashzeros the new fields explicitly on the V17 case (memzero(dst) at entry already does it; explicit reset documents the invariant).Test plan
"<label> Verified"Future / not in this PR
MetadataKeysListfor full visibilityunittests/firmware/signed_metadata.cpp(need the build toolchain re-installed locally — leaving for follow-up)