fix(python): remove ecdsa dependency, use cryptography
What changed, and why it matters
This commit swaps out the 'ecdsa' Python library for the more widely used 'cryptography' library when verifying digital signatures on Trezor legacy firmware updates. It is a maintenance-style dependency change. There is no direct evidence in the commit that it fixes an active security vulnerability, but moving away from the older 'ecdsa' package reduces long-term supply-chain and implementation risk.
Treat as a routine hardening/maintenance patch. Review the new verification logic for equivalence with the old behavior, ensure test coverage for valid, invalid, and malformed legacy firmware signatures, and monitor the 'cryptography' dependency for future security advisories.
Security signals we found
Dependency replacement: ecdsa -> cryptography
Explicit signature length check added (64 bytes required)
Explicit public-key parsing with ValueError handling
Cryptographic verification path changed for legacy firmware signatures
Evidence from the diff
The patch removes the ‘ecdsa>=0.9’ dependency from python/pyproject.toml and rewrites the signature verification in python/src/trezorlib/firmware/legacy.py to use cryptography.hazmat.primitives.asymmetric.ec with SECP256K1 and ECDSA with Prehashed SHA-256. It also adds explicit public-key parsing and signature-length checks that were implicit in the previous implementation. The change affects how the Python trezorlib validates firmware signatures for legacy devices.
Changed components
python/src/trezorlib/firmware/legacy.pypython/pyproject.tomlInspect captured patch +23 / −8
diff --git a/python/pyproject.toml b/python/pyproject.toml
index 39d2df8c..9a57e8ef 100644
--- a/python/pyproject.toml
+++ b/python/pyproject.toml
@@ -20,7 +20,6 @@ classifiers = [
]
requires-python = ">=3.9"
dependencies = [
- "ecdsa>=0.9",
"mnemonic>=0.20",
"shamir-mnemonic>=0.3.0",
"slip10>=1.0.1",
diff --git a/python/src/trezorlib/firmware/legacy.py b/python/src/trezorlib/firmware/legacy.py
index 1e62e1e8..e03f591e 100644
--- a/python/src/trezorlib/firmware/legacy.py
+++ b/python/src/trezorlib/firmware/legacy.py
@@ -21,8 +21,10 @@ import typing as t
from dataclasses import field
import construct as c
-import ecdsa
from construct_classes import Struct, subcon
+from cryptography import exceptions as crypto_exceptions
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.asymmetric import ec, utils
from . import consts, models, util
from .core import FirmwareImage
@@ -68,14 +70,28 @@ def check_sig_v1(
# unknown pubkey
raise util.InvalidSignatureError(f"Unknown key in slot {i}")
- verify = ecdsa.VerifyingKey.from_string(
- public_keys[key_idx],
- curve=ecdsa.curves.SECP256k1,
- hashfunc=hashlib.sha256,
+ try:
+ verify = ec.EllipticCurvePublicKey.from_encoded_point(
+ ec.SECP256K1(),
+ public_keys[key_idx],
+ )
+ except ValueError as e:
+ raise util.InvalidSignatureError(f"Invalid public key in slot {i}") from e
+
+ if len(signature) != 64:
+ raise util.InvalidSignatureError(f"Invalid signature length in slot {i}")
+
+ der_signature = utils.encode_dss_signature(
+ int.from_bytes(signature[:32], "big"),
+ int.from_bytes(signature[32:], "big"),
)
try:
- verify.verify_digest(signature, digest)
- except ecdsa.BadSignatureError as e:
+ verify.verify(
+ der_signature,
+ digest,
+ ec.ECDSA(utils.Prehashed(hashes.SHA256())),
+ )
+ except crypto_exceptions.InvalidSignature as e:
raise util.InvalidSignatureError(f"Invalid signature in slot {i}") from e
Why this scored 32/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.