fix(tools): add key type validation and tighten test assertions in sign_firmware
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""Sign a firmware binary with ECDSA P-256. Outputs a raw 64-byte r||s .sig file."""
|
"""Sign a firmware binary with ECDSA P-256. Outputs a raw 64-byte r||s .sig file."""
|
||||||
import argparse
|
import argparse
|
||||||
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from cryptography.hazmat.primitives.asymmetric import ec
|
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:
|
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:
|
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()
|
data = firmware_path.read_bytes()
|
||||||
sig_der = key.sign(data, ec.ECDSA(hashes.SHA256()))
|
sig_der = key.sign(data, ec.ECDSA(hashes.SHA256()))
|
||||||
r, s = decode_dss_signature(sig_der)
|
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')
|
return r.to_bytes(32, 'big') + s.to_bytes(32, 'big')
|
||||||
|
|
||||||
|
|
||||||
@@ -32,7 +39,11 @@ def main() -> None:
|
|||||||
key_path = Path(args.key)
|
key_path = Path(args.key)
|
||||||
out_path = Path(args.out) if args.out else firmware.with_suffix(".bin.sig")
|
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)
|
out_path.write_bytes(sig)
|
||||||
print(f"Signed {firmware.name} → {out_path} ({len(sig)} bytes)")
|
print(f"Signed {firmware.name} → {out_path} ({len(sig)} bytes)")
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import os, sys, tempfile
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from cryptography.exceptions import InvalidSignature
|
||||||
from cryptography.hazmat.primitives.asymmetric import ec
|
from cryptography.hazmat.primitives.asymmetric import ec
|
||||||
from cryptography.hazmat.primitives import hashes, serialization
|
from cryptography.hazmat.primitives import hashes, serialization
|
||||||
from cryptography.hazmat.primitives.asymmetric.utils import decode_dss_signature
|
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
|
from cryptography.hazmat.primitives.asymmetric.utils import encode_dss_signature
|
||||||
sig_der = encode_dss_signature(r, s)
|
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()))
|
other_key.public_key().verify(sig_der, b"firmware", ec.ECDSA(hashes.SHA256()))
|
||||||
|
|||||||
Reference in New Issue
Block a user