diff --git a/tools/sign_firmware.py b/tools/sign_firmware.py index 2556028..039c04b 100644 --- a/tools/sign_firmware.py +++ b/tools/sign_firmware.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 """Sign a firmware binary with ECDSA P-256. Outputs a raw 64-byte r||s .sig file.""" import argparse +import sys from pathlib import Path from cryptography.hazmat.primitives.asymmetric import ec @@ -9,7 +10,12 @@ from cryptography.hazmat.primitives.asymmetric.utils import decode_dss_signature def load_private_key(key_path: Path) -> ec.EllipticCurvePrivateKey: - return serialization.load_pem_private_key(key_path.read_bytes(), password=None) + key = serialization.load_pem_private_key(key_path.read_bytes(), password=None) + if not isinstance(key, ec.EllipticCurvePrivateKey): + raise ValueError("Key must be an EC private key") + if not isinstance(key.curve, ec.SECP256R1): + raise ValueError(f"Key must use SECP256R1 curve, got {key.curve.name}") + return key def sign_firmware(firmware_path: Path, key_path: Path) -> bytes: @@ -17,6 +23,7 @@ def sign_firmware(firmware_path: Path, key_path: Path) -> bytes: data = firmware_path.read_bytes() sig_der = key.sign(data, ec.ECDSA(hashes.SHA256())) r, s = decode_dss_signature(sig_der) + # Returns raw 64-byte r‖s (not DER) — mbedtls_ecdsa_verify expects this layout return r.to_bytes(32, 'big') + s.to_bytes(32, 'big') @@ -32,7 +39,11 @@ def main() -> None: key_path = Path(args.key) out_path = Path(args.out) if args.out else firmware.with_suffix(".bin.sig") - sig = sign_firmware(firmware, key_path) + try: + sig = sign_firmware(firmware, key_path) + except (FileNotFoundError, ValueError) as e: + print(f"Error: {e}", file=sys.stderr) + raise SystemExit(1) out_path.write_bytes(sig) print(f"Signed {firmware.name} → {out_path} ({len(sig)} bytes)") diff --git a/tools/test_sign_firmware.py b/tools/test_sign_firmware.py index 987131d..4a70cdb 100644 --- a/tools/test_sign_firmware.py +++ b/tools/test_sign_firmware.py @@ -1,7 +1,8 @@ -import os, sys, tempfile +import sys from pathlib import Path import pytest +from cryptography.exceptions import InvalidSignature from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric.utils import decode_dss_signature @@ -59,5 +60,5 @@ def test_wrong_key_fails_verification(keypair, tmp_path): from cryptography.hazmat.primitives.asymmetric.utils import encode_dss_signature sig_der = encode_dss_signature(r, s) - with pytest.raises(Exception): + with pytest.raises(InvalidSignature): other_key.public_key().verify(sig_der, b"firmware", ec.ECDSA(hashes.SHA256()))