Files
proxmox/scripts/omnl/verify-transaction-package-commitment.py

89 lines
2.7 KiB
Python
Raw Permalink Normal View History

#!/usr/bin/env python3
# SPDX-License-Identifier: Apache-2.0
"""Recompute content commitment vs 00_Cover/HASH_NOTARIZATION_ANCHOR.txt (matches build-transaction-package-zip.sh)."""
from __future__ import annotations
import hashlib
import os
import re
import sys
EXCLUDED_EXACT = frozenset(
{
"./00_Cover/HASH_NOTARIZATION_ANCHOR.txt",
"./00_Cover/audit_and_hashes.txt",
"./00_Cover/audit_manifest.json",
}
)
EXCLUDED_BASENAMES = frozenset(
{
"TSA_RFC3161_REQUEST.tsq",
"TSA_RFC3161_RESPONSE.tsr",
"TSA_RFC3161_RESPONSE.txt",
"TSA_RFC3161_VERIFY.txt",
"QES_CMS_ANCHOR_DETACHED.p7s",
"QES_CMS_VERIFY_LOG.txt",
}
)
def posix_rel(package_root: str, full_path: str) -> str:
rel = os.path.relpath(full_path, package_root).replace(os.sep, "/")
return rel if rel.startswith("./") else "./" + rel
def excluded(rel_posix: str) -> bool:
if rel_posix in EXCLUDED_EXACT:
return True
return os.path.basename(rel_posix) in EXCLUDED_BASENAMES
def recompute(package_root: str) -> str:
lines: list[str] = []
for dirpath, dirnames, filenames in os.walk(package_root):
dirnames.sort()
filenames.sort()
for fn in filenames:
if fn == ".DS_Store":
continue
full = os.path.join(dirpath, fn)
if not os.path.isfile(full):
continue
rel = posix_rel(package_root, full)
if excluded(rel):
continue
h = hashlib.sha256()
with open(full, "rb") as f:
for chunk in iter(lambda: f.read(1 << 20), b""):
h.update(chunk)
lines.append(f"{h.hexdigest().lower()}\t{rel}")
lines.sort(key=lambda s: s.encode("utf-8"))
return hashlib.sha256(("\n".join(lines) + "\n").encode("utf-8")).hexdigest().lower()
def main() -> int:
if len(sys.argv) != 2:
print("Usage: verify-transaction-package-commitment.py <unzipped-root>", file=sys.stderr)
return 2
root = os.path.abspath(sys.argv[1])
anchor = os.path.join(root, "00_Cover", "HASH_NOTARIZATION_ANCHOR.txt")
if not os.path.isfile(anchor):
print(f"ERROR: missing {anchor}", file=sys.stderr)
return 1
text = open(anchor, encoding="utf-8").read()
m = re.search(r"CONTENT COMMITMENT \(SHA-256, hex\):\s*([0-9a-fA-F]{64})", text)
if not m:
print("ERROR: bad anchor", file=sys.stderr)
return 1
exp = m.group(1).lower()
got = recompute(root)
if exp != got:
print(f"MISMATCH anchor={exp}\n actual={got}", file=sys.stderr)
return 1
print(f"OK: {got}")
return 0
if __name__ == "__main__":
sys.exit(main())