From 229a06d3a2e49503f5d90059b393c17157b01746 Mon Sep 17 00:00:00 2001 From: matejcik Date: Mon, 25 Mar 2024 15:35:19 +0100 Subject: [PATCH] fix(core): store translation signatures directly into history section without messing with the "current" entry at all --- core/translations/cli.py | 93 +++++++++++++++---------------- core/translations/signatures.json | 1 - 2 files changed, 46 insertions(+), 48 deletions(-) diff --git a/core/translations/cli.py b/core/translations/cli.py index 2d6bea00f..18d96ae27 100644 --- a/core/translations/cli.py +++ b/core/translations/cli.py @@ -31,16 +31,22 @@ VERSION_H = HERE.parent / "embed" / "firmware" / "version.h" SIGNATURES_JSON = HERE / "signatures.json" -class SignatureInfo(t.TypedDict): +class SignedInfo(t.TypedDict): + merkle_root: str + signature: str + datetime: str + commit: str + + +class UnsignedInfo(t.TypedDict): merkle_root: str - signature: str | None datetime: str commit: str class SignatureFile(t.TypedDict): - current: SignatureInfo - history: list[SignatureInfo] + current: UnsignedInfo + history: list[SignedInfo] def _version_from_version_h() -> translations.VersionTuple: @@ -63,21 +69,22 @@ def _version_from_version_h() -> translations.VersionTuple: ) -def make_signature_info(merkle_root: bytes, signature: bytes | None) -> SignatureInfo: +def make_tree_info(merkle_root: bytes) -> UnsignedInfo: now = datetime.datetime.utcnow() commit = ( subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=HERE) .decode("ascii") .strip() ) - return SignatureInfo( - merkle_root=merkle_root.hex(), - signature=signature.hex() if signature is not None else None, - datetime=now.isoformat(), - commit=commit, + return UnsignedInfo( + merkle_root=merkle_root.hex(), datetime=now.isoformat(), commit=commit ) +def sign_info(info: UnsignedInfo, signature: bytes) -> SignedInfo: + return SignedInfo(signature=signature.hex(), **info) + + def update_merkle_root(signature_file: SignatureFile, merkle_root: bytes) -> bool: """Update signatures.json with the new Merkle root. @@ -89,16 +96,9 @@ def update_merkle_root(signature_file: SignatureFile, merkle_root: bytes) -> boo # Merkle root is already up to date return False - if current["signature"] is None: - # current content is not signed. just overwrite with a new one - signature_file["current"] = make_signature_info(merkle_root, None) - SIGNATURES_JSON.write_text(json.dumps(signature_file, indent=2)) - return True - - # move current to history - signature_file["history"].insert(0, current) - # create new current - signature_file["current"] = make_signature_info(merkle_root, None) + # overwrite with a new one + signature_file["current"] = make_tree_info(merkle_root) + SIGNATURES_JSON.write_text(json.dumps(signature_file, indent=2)) return True @@ -188,7 +188,8 @@ def cli() -> None: @cli.command() -def gen() -> None: +@click.option("--signed", is_flag=True, help="Generate signed blobs.") +def gen(signed: bool | None) -> None: """Generate all language blobs for all models. The generated blobs will be signed with the development keys. @@ -196,11 +197,25 @@ def gen() -> None: all_blobs = generate_all_blobs(rewrite_version=True) tree = merkle_tree.MerkleTree(b.header_bytes for b in all_blobs) root = tree.get_root_hash() + + signature_file: SignatureFile = json.loads(SIGNATURES_JSON.read_text()) + + if signed: + for entry in signature_file["history"]: + if entry["merkle_root"] == root.hex(): + signature_hex = entry["signature"] + signature_bytes = bytes.fromhex(signature_hex) + sigmask, signature = signature_bytes[0], signature_bytes[1:] + build_all_blobs(all_blobs, tree, sigmask, signature, production=True) + return + else: + raise click.ClickException( + "No matching signature found in signatures.json. Run `cli.py sign` first." + ) + signature = cosi.sign_with_privkeys(root, PRIVATE_KEYS_DEV) sigmask = 0b111 build_all_blobs(all_blobs, tree, sigmask, signature) - - signature_file = json.loads(SIGNATURES_JSON.read_text()) if update_merkle_root(signature_file, root): SIGNATURES_JSON.write_text(json.dumps(signature_file, indent=2) + "\n") click.echo("Updated signatures.json") @@ -228,13 +243,10 @@ def merkle_root() -> None: @cli.command() -@click.argument("signature_hex", required=False) -@click.option("--force", is_flag=True) -def sign(signature_hex: str | None, force: bool) -> None: - """Insert a signature into language blobs. - - If signature_hex is not provided, the signature will be located in signatures.json. - """ +@click.argument("signature_hex") +@click.option("--force", is_flag=True, help="Write even if the signature is invalid.") +def sign(signature_hex: str, force: bool | None) -> None: + """Insert a signature into language blobs.""" all_blobs = generate_all_blobs(rewrite_version=False) tree = merkle_tree.MerkleTree(b.header_bytes for b in all_blobs) root = tree.get_root_hash() @@ -247,23 +259,10 @@ def sign(signature_hex: str | None, force: bool) -> None: f"Stored in signatures.json: {signature_file['current']['merkle_root']}" ) - if signature_hex is None: - if signature_file["current"]["signature"] is None: - raise click.ClickException("Please provide a signature.") - signature_hex = signature_file["current"]["signature"] - elif ( - not force - and signature_file["current"]["signature"] is not None - and signature_file["current"]["signature"] != signature_hex - ): - raise click.ClickException( - "A different signature is already present in signatures.json\n" - "Use --force to overwrite it." - ) - else: - # Update signature file data. It will be written only if the signature verifies. - signature_file["current"]["signature"] = signature_hex - signature_file["current"]["datetime"] = datetime.datetime.utcnow().isoformat() + # Update signature file data. It will be written only if the signature verifies. + tree_info = make_tree_info(root) + signed_info = sign_info(tree_info, bytes.fromhex(signature_hex)) + signature_file["history"].insert(0, signed_info) signature_bytes = bytes.fromhex(signature_hex) sigmask, signature = signature_bytes[0], signature_bytes[1:] diff --git a/core/translations/signatures.json b/core/translations/signatures.json index 3a13783e9..ab305baa4 100644 --- a/core/translations/signatures.json +++ b/core/translations/signatures.json @@ -1,7 +1,6 @@ { "current": { "merkle_root": "d349550e9ad7be0b63b06fc43c6b764d008bf4497a8e1d0374cb92119b242160", - "signature": null, "datetime": "2024-03-25T14:23:51.859562", "commit": "ef11039a818bb0941191af49e0c9a0f7aae9324a" },