proof-aware-crypto-tooling-.../src/pacta/signing.py
mrwulf d331ba17d9 Dogfood cryptography: pacta verifies signatures through the PROVEN code path
"Eat your own dogfood": pacta consumes certificates about a verified
Ed25519 implementation while checking those certificates' signatures
with OpenSSL. Now it can use the object of its own evidence:

- dogfood/pacta-verified-verify: a ~90-line Rust binary built against
  the PINNED proven source workspace (saymrwulf/curve25519-dalek-source
  at the exact commit the dalek certificates pin - the build records it:
  aa0f6ab...) with the serial backend pinned via RUSTFLAGS exactly as
  the verified extraction pins it. Cargo.toml is committed as a template
  ({{SOURCE}} placeholder) so no machine path is hardcoded; the rendered
  file, target/, and the built binary are gitignored.
- pacta dogfood-build --source <workspace>: renders, builds, installs
  to dogfood/state/, and writes a provenance sidecar (source commit,
  backend cfg, rustc, and an honest coverage note: the certificates
  cover verify_sha512, the extraction-refactored image of this verify
  path; SHA-512 and the wire glue remain the theorems' documented
  boundary). pacta dogfood-status reports the active backend.
- signing.verify_payload_ed25519_detailed: dispatch - the dogfood
  binary when present (backend "verified-dalek-serial"), OpenSSL
  fallback otherwise, and the backend that ACTUALLY ran is recorded in
  receipt signature statuses and attestation evidence. Fallback is
  never silent.
- --require-verified-verifier (receipt-verify + agent): policy fails
  closed when verification did not run on the certificate-covered
  path.
- ML-DSA is deliberately unchanged: no proven implementation exists,
  so the slot stays fail-closed "unavailable" - the honest hybrid-PQC
  posture is one proven-classical signature plus one required-but-
  unproven PQC slot, never a pretend backend.

Validated live: receipt verification through the proven verifier
(backend recorded), a corrupted signature bit rejected BY the proven
binary, tampered attestations rejected, and the policy failing closed
when the binary is absent. 49/49 tests green (incl. PEM-SPKI raw-key
cross-check against openssl, dispatch/backend recording with a stub,
and a real-binary roundtrip that skips gracefully where unbuilt).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 10:13:48 +02:00

168 lines
6.9 KiB
Python

from __future__ import annotations
import base64
import hashlib
import json
import shutil
import subprocess
import tempfile
from pathlib import Path
from typing import Any
class SignatureError(RuntimeError):
pass
def canonical_attestation_payload(attestation: dict[str, Any]) -> bytes:
unsigned = {key: value for key, value in attestation.items() if key != "signature"}
return canonical_json(unsigned)
def canonical_json(document: Any) -> bytes:
return json.dumps(document, sort_keys=True, separators=(",", ":"), ensure_ascii=False).encode("utf-8")
def payload_digest(attestation: dict[str, Any]) -> str:
return hashlib.sha256(canonical_attestation_payload(attestation)).hexdigest()
def public_key_fingerprint(public_key_path: str | Path) -> str:
data = Path(public_key_path).read_bytes()
return hashlib.sha256(data).hexdigest()
def generate_ed25519_keypair(private_key_path: str | Path, public_key_path: str | Path) -> None:
openssl = _openssl()
private_path = Path(private_key_path)
public_path = Path(public_key_path)
private_path.parent.mkdir(parents=True, exist_ok=True)
public_path.parent.mkdir(parents=True, exist_ok=True)
subprocess.run([openssl, "genpkey", "-algorithm", "ed25519", "-out", str(private_path)], check=True, timeout=30)
subprocess.run([openssl, "pkey", "-in", str(private_path), "-pubout", "-out", str(public_path)], check=True, timeout=30)
def sign_attestation(attestation: dict[str, Any], private_key_path: str | Path, public_key_path: str | Path | None = None) -> dict[str, Any]:
payload = canonical_attestation_payload(attestation)
signature_base64 = sign_payload_ed25519(payload, private_key_path)
signed = dict(attestation)
signed["signature"] = {
"scheme": "openssl-ed25519",
"status": "signed",
"payload_digest_sha256": hashlib.sha256(payload).hexdigest(),
"signature_base64": signature_base64,
}
if public_key_path:
signed["signature"]["public_key_fingerprint_sha256"] = public_key_fingerprint(public_key_path)
return signed
def verify_attestation_signature(attestation: dict[str, Any], public_key_path: str | Path) -> tuple[bool, str | None]:
ok, error, _backend = verify_attestation_signature_detailed(attestation, public_key_path)
return ok, error
def verify_attestation_signature_detailed(attestation: dict[str, Any], public_key_path: str | Path) -> tuple[bool, str | None, str]:
signature = attestation.get("signature") or {}
if signature.get("scheme") != "openssl-ed25519":
return False, f"Unsupported attestation signature scheme: {signature.get('scheme')}", "none"
encoded = signature.get("signature_base64")
if not encoded:
return False, "Attestation signature is missing signature_base64.", "none"
expected_digest = signature.get("payload_digest_sha256")
actual_digest = payload_digest(attestation)
if expected_digest and expected_digest != actual_digest:
return False, "Attestation payload digest does not match signature metadata.", "none"
expected_fingerprint = signature.get("public_key_fingerprint_sha256")
if expected_fingerprint:
actual_fingerprint = public_key_fingerprint(public_key_path)
if expected_fingerprint != actual_fingerprint:
return False, "Attestation public key fingerprint does not match signature metadata.", "none"
return verify_payload_ed25519_detailed(canonical_attestation_payload(attestation), encoded, public_key_path)
def sign_payload_ed25519(payload: bytes, private_key_path: str | Path) -> str:
openssl = _openssl()
with tempfile.TemporaryDirectory(prefix="pacta-sign-") as tmp:
payload_path = Path(tmp) / "payload.bin"
signature_path = Path(tmp) / "payload.sig"
payload_path.write_bytes(payload)
completed = subprocess.run(
[openssl, "pkeyutl", "-sign", "-inkey", str(private_key_path), "-rawin", "-in", str(payload_path), "-out", str(signature_path)],
check=False,
capture_output=True,
text=True,
timeout=30,
)
if completed.returncode != 0:
raise SignatureError((completed.stderr or completed.stdout or "openssl signing failed").strip())
signature_bytes = signature_path.read_bytes()
return base64.b64encode(signature_bytes).decode("ascii")
def verify_payload_ed25519(payload: bytes, signature_base64: str, public_key_path: str | Path) -> tuple[bool, str | None]:
ok, error, _backend = verify_payload_ed25519_detailed(payload, signature_base64, public_key_path)
return ok, error
def verify_payload_ed25519_detailed(
payload: bytes,
signature_base64: str,
public_key_path: str | Path,
) -> tuple[bool, str | None, str]:
"""Verify an Ed25519 signature, preferring pacta's DOGFOOD verifier -
a binary built from the pinned, certificate-covered dalek source with
the serial backend pinned - and falling back to OpenSSL when the
dogfood binary is unavailable. The third element names the backend that
actually ran so callers can record (and policies can require) the
verified path."""
from .dogfood import BACKEND_OPENSSL, BACKEND_VERIFIED, locate_verifier, verify_payload_dogfood
try:
signature_bytes = base64.b64decode(signature_base64, validate=True)
except ValueError as exc:
return False, f"Invalid base64 signature: {exc}", "none"
binary = locate_verifier()
if binary is not None:
ok, error = verify_payload_dogfood(payload, signature_bytes, public_key_path, binary)
return ok, error, BACKEND_VERIFIED
ok, error = _verify_payload_openssl(payload, signature_bytes, public_key_path)
return ok, error, BACKEND_OPENSSL
def _verify_payload_openssl(payload: bytes, signature_bytes: bytes, public_key_path: str | Path) -> tuple[bool, str | None]:
openssl = _openssl()
with tempfile.TemporaryDirectory(prefix="pacta-verify-") as tmp:
payload_path = Path(tmp) / "payload.bin"
signature_path = Path(tmp) / "payload.sig"
payload_path.write_bytes(payload)
signature_path.write_bytes(signature_bytes)
completed = subprocess.run(
[
openssl,
"pkeyutl",
"-verify",
"-pubin",
"-inkey",
str(public_key_path),
"-rawin",
"-in",
str(payload_path),
"-sigfile",
str(signature_path),
],
check=False,
capture_output=True,
text=True,
timeout=30,
)
if completed.returncode != 0:
return False, (completed.stderr or completed.stdout or "openssl verification failed").strip()
return True, None
def _openssl() -> str:
path = shutil.which("openssl")
if not path:
raise SignatureError("openssl is not available on PATH")
return path