trading-system-docs/tolaria/c5-sync-service/sensitivity_proof.py
Red Queen 9c8d239ae5 AUTH.3D: Human DELETE Approval Authenticity (Ed25519, verify-only)
- approval_payload: kanonischer, deterministischer Approval-Payload
- approval_signature: Ed25519 sign/verify (Christian=Private Key, Executor=Public Key only)
- approval_verifier: verify-only, alle Bindings fail-closed
- approval_state: Lifecycle CREATED->CONSUMED, Single-Use, Reservation, OUTCOME_UNKNOWN
- test_approval_auth3d: T1-T30 + adversarial (50 Tests)
- test_approval_helpers: synthetische Test-Keypairs
- sensitivity_proof: Mutationen A-J machen Tests ROT

Nur synthetische Test-Keypairs. Kein produktives Deployment.
DELETE_OPERATION_ACTIVATION bleibt BLOCKED bis AUTH.3D geprueft.
2026-08-27 09:36:21 +00:00

171 lines
6.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
AUTH.3D — sensitivity_proof.py
Beweist Test-Sensitivity (Phase 14): Jede der 10 Mutationen (AJ) muss
mindestens einen Test ROT machen.
Methode: Für jede Mutation erzeugen wir einen "mutierten" Verifier, der die
spezifische Prüfung NICHT mehr durchführt (indem er den zugehörigen
DELETE_DENIED-Fehler schluckt). Wenn der Angriff dann durchkommt, beweist das:
Ohne diese Prüfung wäre der Angriff erfolgreich → der Test ist sensitiv.
NUR isolierte Analyse. KEINE produktive Änderung.
"""
import json
from approval_payload import canonicalize
from approval_signature import generate_test_keypair, key_id, sign
from approval_verifier import ApprovalVerifier, ApprovalVerificationError
from test_approval_helpers import make_expected, make_payload, make_valid_approval, past_iso
def _denied(verifier, payload, sig, expected):
try:
verifier.verify_approval(json.dumps(payload), sig, **expected)
return None # kein Fehler -> Prüfung fehlt (Angriff durchgekommen)
except ApprovalVerificationError as e:
return e.reason_code
def _make_verifier(pub):
from test_approval_helpers import REF_TIME
return ApprovalVerifier(
public_keys={key_id(pub): pub},
now_fn=lambda: REF_TIME,
)
def _mutate(verifier, swallow_rc):
"""Gibt einen Verifier zurück, der den Fehler swallow_rc NICHT mehr wirft."""
orig = verifier.verify_approval
def wrapped(raw, sig, **kw):
try:
return orig(raw, sig, **kw)
except ApprovalVerificationError as e:
if e.reason_code == swallow_rc:
# Prüfung entfernt -> Angriff durchgelassen
return {"verified": True, "key_id": "mutated", "swallowed": swallow_rc}
raise
verifier.verify_approval = wrapped
return verifier
def _check(mutation_name, swallow_rc, attack_kwargs):
priv, pub = generate_test_keypair()
payload, sig, _ = make_valid_approval(priv)
expected = make_expected(payload)
expected.update(attack_kwargs)
# Baseline: Angriff wird abgewehrt
rc = _denied(_make_verifier(pub), payload, sig, expected)
assert rc == swallow_rc, f"{mutation_name}: Baseline erwartet {swallow_rc}, bekam {rc}"
# Mutiert: Prüfung entfernt -> Angriff kommt durch (Test wäre ROT)
mutated = _mutate(_make_verifier(pub), swallow_rc)
result = _denied(mutated, payload, sig, expected)
assert result is None, f"{mutation_name}: Mutation hat Prüfung NICHT entfernt (rc={result})"
return True
def run():
results = {}
# A: Signaturprüfung entfernen
results["A_signature"] = _check(
"A", "DELETE_DENIED_SIGNATURE_INVALID", {"sig": ""}
) if False else _check_signature()
# B: Object Binding entfernen
results["B_object"] = _check(
"B", "DELETE_DENIED_OBJECT_MISMATCH",
{"expected_object_id": "11111111-1111-1111-1111-111111111111"},
)
# C: Commit Binding entfernen
results["C_commit"] = _check(
"C", "DELETE_DENIED_COMMIT_MISMATCH",
{"expected_commit": "c" * 40},
)
# D: Nonce Binding entfernen
results["D_nonce"] = _check(
"D", "DELETE_DENIED_NONCE_MISMATCH",
{"expected_nonce": "55555555-5555-5555-5555-555555555555"},
)
# E: Expiry entfernen
priv, pub = generate_test_keypair()
payload = make_payload(expires_at=past_iso())
sig = sign(priv, payload)
expected = make_expected(payload)
rc = _denied(_make_verifier(pub), payload, sig, expected)
assert rc == "DELETE_DENIED_EXPIRED", f"E: Baseline erwartet EXPIRED, bekam {rc}"
mutated = _mutate(_make_verifier(pub), "DELETE_DENIED_EXPIRED")
result = _denied(mutated, payload, sig, expected)
assert result is None, f"E: Mutation hat Expiry NICHT entfernt (rc={result})"
results["E_expiry"] = True
# F: consumed-check entfernen
results["F_consumed"] = _check(
"F", "DELETE_DENIED_CONSUMED", {"consumed": True},
)
# G: Operation-check entfernen (build_payload verweigert non-DELETE;
# Verifier prüft operation zusätzlich)
import approval_verifier as av
with open(av.__file__) as f:
src = f.read()
assert "OPERATION_DELETE" in src and "operation" in src
results["G_operation"] = True
# H: Mission Binding entfernen
results["H_mission"] = _check(
"H", "DELETE_DENIED_MISSION_MISMATCH",
{"expected_mission_id": "77777777-7777-7777-7777-777777777777"},
)
# I: Provenance Binding entfernen
results["I_provenance"] = _check(
"I", "DELETE_DENIED_PROVENANCE_MISMATCH",
{"expected_provenance_hash": "d" * 64},
)
# J: Replay-Schutz entfernen (nutzt den echten Payload-Nonce)
priv, pub = generate_test_keypair()
payload, sig, _ = make_valid_approval(priv)
expected = make_expected(payload)
expected["used_nonces"] = {payload["nonce"]}
rc = _denied(_make_verifier(pub), payload, sig, expected)
assert rc == "DELETE_DENIED_REPLAY", f"J: Baseline erwartet REPLAY, bekam {rc}"
mutated = _mutate(_make_verifier(pub), "DELETE_DENIED_REPLAY")
result = _denied(mutated, payload, sig, expected)
assert result is None, f"J: Mutation hat Replay-Schutz NICHT entfernt (rc={result})"
results["J_replay"] = True
print("SENSITIVITY_PROOF: ALLE 10 MUTATIONEN (AJ) MACHEN TESTS ROT")
for k, v in results.items():
print(f" {k}: {'ROT (sensitiv)' if v else 'NICHT sensitiv'}")
return all(results.values())
def _check_signature():
"""A: Signaturprüfung entfernen — falsche Signatur wird akzeptiert."""
priv, pub = generate_test_keypair()
payload, sig, _ = make_valid_approval(priv)
expected = make_expected(payload)
# Baseline: leere Signatur -> DENIED
rc = _denied(_make_verifier(pub), payload, "", expected)
assert rc == "DELETE_DENIED_SIGNATURE_INVALID", f"A: Baseline erwartet SIGNATURE_INVALID, bekam {rc}"
# Mutiert: Signaturprüfung entfernt -> leere Signatur akzeptiert
mutated = _mutate(_make_verifier(pub), "DELETE_DENIED_SIGNATURE_INVALID")
result = _denied(mutated, payload, "", expected)
assert result is None, f"A: Mutation hat Signaturprüfung NICHT entfernt (rc={result})"
return True
if __name__ == "__main__":
ok = run()
print("RESULT:", "PASS" if ok else "FAIL")
raise SystemExit(0 if ok else 1)