55 lines
1.8 KiB
Python
55 lines
1.8 KiB
Python
#!/usr/bin/env python3
|
|
import argparse
|
|
import base64
|
|
import copy
|
|
import json
|
|
import subprocess
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
from cezen_license import utcnow_iso
|
|
|
|
|
|
def canonical_payload(payload):
|
|
clean = copy.deepcopy(payload)
|
|
clean.pop("signature", None)
|
|
clean.pop("signature_status", None)
|
|
return json.dumps(clean, sort_keys=True, separators=(",", ":"), ensure_ascii=True).encode()
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Sign a Nexus One AI license or override artifact")
|
|
parser.add_argument("--input", required=True, help="Unsigned JSON artifact")
|
|
parser.add_argument("--private-key", required=True, help="PEM private key path")
|
|
parser.add_argument("--output", required=True, help="Signed JSON output path")
|
|
parser.add_argument("--alg", default="rsa-sha256")
|
|
args = parser.parse_args()
|
|
|
|
payload = json.loads(Path(args.input).read_text())
|
|
payload["issued_at"] = payload.get("issued_at") or utcnow_iso()
|
|
payload["signature_alg"] = args.alg
|
|
body = canonical_payload(payload)
|
|
|
|
with tempfile.NamedTemporaryFile(delete=False) as data_file, tempfile.NamedTemporaryFile(delete=False) as sig_file:
|
|
data_file.write(body)
|
|
data_file.flush()
|
|
data_path = data_file.name
|
|
sig_path = sig_file.name
|
|
try:
|
|
subprocess.run(
|
|
["openssl", "dgst", "-sha256", "-sign", args.private_key, "-out", sig_path, data_path],
|
|
check=True,
|
|
)
|
|
signature = base64.b64encode(Path(sig_path).read_bytes()).decode()
|
|
finally:
|
|
Path(data_path).unlink(missing_ok=True)
|
|
Path(sig_path).unlink(missing_ok=True)
|
|
|
|
payload["signature"] = signature
|
|
payload["signature_status"] = "signed"
|
|
Path(args.output).write_text(json.dumps(payload, indent=2))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|