fix(python): fix BootloaderV2Image verify [no changelog]
What changed, and why it matters
This commit fixes the verification logic for Trezor bootloader version 2 images in the Python firmware library. Previously, the code checked the elliptic-curve (EC) signature against only the Merkle root digest. The fix now hashes that digest together with the post-quantum (SLH) signature first, matching the actual signing procedure. Without this fix, a valid-looking bootloader signature could be accepted even if the SLH signature was wrong or missing, weakening the dual-signature security check.
Treat this as a security-relevant correctness fix. Update the trezorlib Python package and any tools that validate or flash Trezor bootloader v2 images. Review whether firmware images signed under the old verification behavior could have been accepted inappropriately, and consider whether a security advisory is warranted for downstream users of trezorlib.
Security signals we found
firmware signature verification bypass risk
cryptographic verification logic corrected
dual-signature scheme (EC + post-quantum) not enforced before patch
post-quantum signature not included in EC signed digest prior to fix
Evidence from the diff
In BootloaderV2Image.verify(), the EC signature verification was changed from _ed25519.checkvalid(sig, digest, key) to _ed25519.checkvalid(sig, hash_fn(digest + slh_signature).digest(), key). The SLH (post-quantum) signature is now mixed into the signed message, so the EC signature is only valid if it was produced over the combined digest. This aligns EC verification with the signing scheme and prevents the EC signature alone from authenticating a firmware image whose SLH signature is invalid or absent.
Changed components
python/src/trezorlib/_internal/firmware_headers.pyBootloaderV2Image.verify()Trezor Python firmware libraryInspect captured patch +6 / −1
diff --git a/python/src/trezorlib/_internal/firmware_headers.py b/python/src/trezorlib/_internal/firmware_headers.py
index 35078602..17417b04 100644
--- a/python/src/trezorlib/_internal/firmware_headers.py
+++ b/python/src/trezorlib/_internal/firmware_headers.py
@@ -484,8 +484,13 @@ class BootloaderV2Image(firmware.BootableImage):
def verify(self, dev_keys: bool = False) -> None:
digest = self.merkle_root()
+ hash_fn = self.get_hash_params().hash_function
+
for idx, key in enumerate(self.public_ec_keys(dev_keys)):
- if not _ed25519.checkvalid(self.unauth.ec_signatures[idx], digest, key):
+ ext_digest = hash_fn(digest + self.unauth.slh_signatures[idx]).digest()
+ try:
+ _ed25519.checkvalid(self.unauth.ec_signatures[idx], ext_digest, key)
+ except _ed25519.SignatureMismatch:
raise firmware.InvalidSignatureError("Invalid bootloader signature")
for idx, key in enumerate(self.public_pq_keys(dev_keys)):
Why this scored 57/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.