cryptoadvance / cryptoadvance/specter-diy

Planning and executing the v1.10.5 Security Hardening Release

Open
#407 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
585
Forks
108
Avg merge
6d 1h
Merged PRs (30d)
5

Description

# Context

This issue coordinates the **Specter DIY Security Hardening Release v1.10.5**.

The previous published GitHub release is v1.10.3. A `v1.10.4` tag already exists
as a test/update version, so that number is skipped for the public release.

**Status: release built, signed and hardware-tested by a second maintainer.
Publication pending (tag + `sha256.signed.txt` + release page).** See
_Release build results_ below.

## Release scope decisions

* **No release-signing key rotation.** Production signer/key set and threshold
unchanged (verified — see below).
* **No signing-key / bootloader-key changes.** Bootloader submodule is identical
to v1.10.3 (`b97192322c32f3fc54a93c2049b800e9c21f27c0`).
* Ship the review-ready security-hardening / transaction-verification / entropy
fixes; defer everything still in review to the next release. Fast release was
prioritised over pulling in more surface.
* **Full-card SD-card secure erase/format feature and related SD-card management
UI are not in this release.**

# PR merge / review tracker

## Merged into the v1.10.5 release (commit `b2d87e5`)

* [x] **#373 – docs: add SECURITY.md disclosure policy, refresh security model docs** — https://github.com/cryptoadvance/specter-diy/pull/373 — `4139dbd`
* [x] **#345 – docs: link udev/README.md in mkdocs** — https://github.com/cryptoadvance/specter-diy/pull/345 — `3f3c831`
* [x] **#372 – Reject dead-TRNG output in get_random_bytes** (fixes #370) — https://github.com/cryptoadvance/specter-diy/pull/372 — `65fcb98` — Reviews: ✅ 4 independent
* [x] **#376 – Update embit to v0.8.2** — https://github.com/cryptoadvance/specter-diy/pull/376 — `2ff670c` — Reviews: ✅ 3 independent
* [x] **#382 – Re-add mixed-inputs warning for multi-wallet transactions** — https://github.com/cryptoadvance/specter-diy/pull/382 — `7223458` — Reviews: ✅ 1 independent · ☑️ 1 Schnuartz self-review
* [x] **#387 – Verify change-output classification cryptographically** — https://github.com/cryptoadvance/specter-diy/pull/387 — `fc0e32d` — Reviews: ✅ 3 independent · final re-review by @maggo83 on 2026-09-02
* [x] **#412 – Fix reproducible build** (fixes #371) — https://github.com/cryptoadvance/specter-diy/pull/412 — `e4266c1`

## Not in v1.10.5 — deferred to the next release (still open)

* [ ] **#380 – Fix device wipe on final PIN attempt** — https://github.com/cryptoadvance/specter-diy/pull/380 — Reviews: ✅ 2 independent · ☑️ 1 Schnuartz self-review
* [ ] **#396 – Fix incomplete secure wipe of QSPI flash** — https://github.com/cryptoadvance/specter-diy/pull/396 — Reviews: ✅ 2 independent · ☑️ 1 Schnuartz self-review — supersedes accidentally closed #386
* [ ] **#388 – Constant-time MAC/PIN comparisons** — https://github.com/cryptoadvance/specter-diy/pull/388 — Reviews: ✅ 2 independent · ☑️ 1 Schnuartz self-review
* [ ] **#392 – Warn on disproportionately high transaction fees** — https://github.com/cryptoadvance/specter-diy/pull/392 — Reviews: ✅ 1 independent · ☑️ 1 Schnuartz self-review — resolve the open Liquid-scope/design comment before merge
* [ ] **#399 – Preserve SIGHASH.DEFAULT (0) for Taproot signatures** — https://github.com/cryptoadvance/specter-diy/pull/399 — Reviews: ✅ 0 independent · ☑️ 1 Schnuartz self-review
* [ ] **#405 – Derive Taproot single-sig wallets from BIP86 and preserve legacy recovery** — https://github.com/cryptoadvance/specter-diy/pull/405 — Reviews: ✅ 0 independent
* [ ] **#403 – refactor: remove dead experimental.taproot config** — https://github.com/cryptoadvance/specter-diy/pull/403
* [ ] **#379 – Secure file deletion + mnemonic-deletion error propagation** — https://github.com/cryptoadvance/specter-diy/pull/379 — release gate: split/reduce before merge; full-card SD erase/format out of scope
* [ ] **#381 – Require on-device confirmation for host XPUB requests** — https://github.com/cryptoadvance/specter-diy/pull/381 — waits for a Specter Desktop release + HWW testing

## Explicitly out of scope (SD-card management / full-format — later release)

* #378 – BitBox02 SD backup/import/export + SD management
* #391 – SD-card transaction/descriptor deletion UI
* #404 – Delete files and format the card from the SD file picker
* full-card SD erase/format portion currently bundled into #379

Companion-version note for the release changelog: none of the deferred PRs are
required for v1.10.5 to function; no minimum companion versions apply.

# Review and merge gates

* [x] Every merged security PR has at least one independent human review after its final security-relevant changes (#372: 4, #376: 3, #387: 3, #382: 1 + self-review)
* [x] No unresolved `CHANGES_REQUESTED` review on a merged release PR
* [x] Correctness/security review threads on merged PRs resolved or dispositioned
* [x] CI green on every merged PR against `master`
* [x] Selected PRs merged into `master`
* [x] Full native test suite on final `master` — `python3 test/run_native_tests.py` → **80 passed**
* [ ] Build/test the Unix simulator on final `master`
* [x] Build STM32 firmware with the final pinned submodules (`bootloader b97192322c`, `f469-disco 9dd8515aaa`)
* [x] `python3 -m compileall src test` → OK (pre-existing `flash.py:287` SyntaxWarning only)

# Version freeze and release build

* [x] Release commit frozen: `b2d87e55338289a258ee985b26c7b064d5b49132`
* [x] Firmware version bumped to **v1.10.5** (`0101000599`)
* [ ] Create the `v1.10.5` tag from `b2d87e5`
* [x] Confirmed no signing-key changes vs the current production key set
* [x] Built from the frozen commit via the reproducible-build flow (pinned `diy` Docker image, `linux/amd64`, `SPECTER_REPRODUCIBLE_BUILD=1`, production pubkeys, bootloader `READ_PROTECTION=1 WRITE_PROTECTION=1`)
* [x] Two maintainers independently reproduce the build and compare message/hash — reference build reproduced bit-identical; **Marco Kruse reproduced the build independently and the signature/message/hash match**
* [x] Vendor signatures added with the existing production keys and threshold (k9ert + Mike)
* [x] Bootloader introspection run on the final `specter_upgrade.bin` (`upgrade-generator.py dump`); bootloader on-device also checked with STM32CubeProgrammer (Marco Kruse) — matches previous firmwares
* [x] Signature threshold and signer identities verified — 2 / 2, k9ert `c8638d869d056ce1b18677e2b0bfaa60` + Mike `cf0239e7708148c0fe2bc1ff485d950e`, both cryptographically valid over the signing message
* [x] Embedded production keys verified: `k9ert`, `Mike`, `Stepan`, `Backup m/99h`; `main_fw_sig_threshold = 2`, `bootloader_sig_threshold = 2`
* [x] Versions verified: firmware `1.10.5`; bootloader unchanged since v1.10.3. Upgrade is **firmware-only** (no `boot` section — message has no `b…` prefix, unlike v1.10.3)
* [x] SHA-256 generated for all binary artifacts (see below)

# Final release verification

* [x] Test the final **signed** binary, not only pre-sign builds — Marco Kruse built with the signatures, updated an existing device and re-ran #387 and #382; warnings as expected
* [x] Repeat the upgrade test from v1.10.3 with the final signed binary — flashed v1.10.3 (with bootloader), applied `specter_upgrade_v1.10.5.bin` via SD card → upgrade succeeded, #387 / #382 / #335 test vectors unchanged
* [x] Repeat a fresh-board initial flash with the final binary — installed `initial_firmware_v1.10.5.bin` (signed) on a clean board, bootloader present and correct; re-ran #387 and #376 (incl. internal, non-public test QRs) → as expected
* [x] Confirmed no unexpected files/commits after the freeze (`git log v1.10.3..b2d87e5` = 8 commits, all mapped to the PRs above)
* [x] Release changelog prepared with a security-impact line per security PR
* [ ] Review the changelog
* [ ] Produce/sign `sha256.signed.txt` with the current Specter release-signing GPG key
* [ ] Create the GitHub release page
* [ ] Upload the final binaries, hashes/signatures and verification info
* [ ] Publish v1.10.5

# Release build results

| Item | Value |
|---|---|
| Release commit | `b2d87e55338289a258ee985b26c7b064d5b49132` |
| `bootloader` submodule | `b97192322c32f3fc54a93c2049b800e9c21f27c0` (= v1.10.3) |
| `f469-disco` submodule | `9dd8515aaa0de80cf5d2ae1499de14beb33f863a` |
| Build env | Docker `diy` (python:3.9.15, ARM GCC 9-2020-q2), `linux/amd64` |
| Upgrade type | firmware only, no bootloader section |
| Signing message | `1.10.5-1fychyfccs5a0l4xhgskqutqzmkpfga7fd49waatccalglpecxr5qkm92z0` |
| Signatures | k9ert `c8638d86…aa60`, Mike `cf0239e7…d950e` — 2 / 2 threshold met |

SHA-256 of the release assets:

```
fcd23591cd990cc7973861916e5d398ddd8f3f4dea226035d236ffe0e30bb0ea specter_upgrade_v1.10.5.bin
d207f6d3750e3aacbc98080581934b8d0ebe52eb833f341e0e249d96c0c711d6 specter_upgrade_unsigned_v1.10.5.bin
b46b6b3ea256bc9f9d4da4250c0d6ffdfc1800cbb44a8845810e045c5e8cae01 initial_firmware_v1.10.5.bin
```

Component hashes (cross-check): `bin/specter-diy.hex`
`b40f676ffce5dde9d1d108164b2c6f669a233eb89a775375d7d89aea71a503b9` ·
`bootloader.hex` `0869e02baa58c6f8c63ad0e570fbf1283d8aaacec3956bf0fc94fea65ab9caeb` ·
`startup.hex` `14dc7181e98999230c63b40b7613d08d671e783da98381870246141d25db8f49`

## Remaining before publish

1. Final changelog review.
2. `gpg --digest-algo SHA512 --clearsign -o sha256.signed.txt sha256.txt` with the release-signing GPG key.
3. `git tag v1.10.5 b2d87e55338289a258ee985b26c7b064d5b49132 && git push origin v1.10.5`.
4. Create the GitHub release on the tag, upload `specter_upgrade_v1.10.5.bin`, `specter_upgrade_unsigned_v1.10.5.bin`, `initial_firmware_v1.10.5.bin`, `sha256.signed.txt`, paste the changelog, publish.

Done: reference + independent (Marco Kruse) reproduction match; final signed
binary tested on device — SD-card upgrade from v1.10.3 and clean-board initial
flash, with #387 / #382 / #376 / #335 test vectors re-verified; bootloader
inspected with STM32CubeProgrammer.

## Release-workflow note (PR #414)

PR #414's `assemble` step currently builds `specter_upgrade.bin` **with** the
bootloader section (`b1.0.2`), which produces a *different* signing message. The
v1.10.5 signatures target the **main-firmware-only** upgrade, which is what the
published `specter_upgrade.bin` contains. #414 must be reconciled with the
firmware-only upgrade flow before it is used to drive a release; the initial
firmware still bundles the production bootloader as before.

# Notes

This release is deliberately **security hardening, not feature expansion**. The
wipe/PIN/constant-time PRs (#380, #388, #396) and the fee-warning / Taproot PRs
(#392, #399, #405) were not review-complete at freeze time and move to the next
release.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with the remaining publication checklist, the prepared release changelog, sha256.txt, and the PR #414 assemble step. Verify the firmware-only signing flow and final artifacts, then complete the tag, signed hash file, GitHub release upload, and publication; done means v1.10.5 is publicly released with the listed binaries and verification information.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, git, github, python
Domain
build-system, devops, embedded-iot, release, security
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.