Skip to content

feat(d3): D-1 Acceptance-Gate Phase A (did:moltrust JWS verification)#129

Merged
MoltyCel merged 2 commits into
mainfrom
feat/d1-acceptance-gate-phase-a
Jun 3, 2026
Merged

feat(d3): D-1 Acceptance-Gate Phase A (did:moltrust JWS verification)#129
MoltyCel merged 2 commits into
mainfrom
feat/d1-acceptance-gate-phase-a

Conversation

@MoltyCel

@MoltyCel MoltyCel commented Jun 3, 2026

Copy link
Copy Markdown
Owner

D-1 Acceptance-Gate, Phase A (did:moltrust-only) — verifiziert die Issuer-Signatur am submit-Gate (AAE draft-04 §5 Step 1+2), fail-closed. Schließt die Lücke: Komponente 1 speicherte issuer_did/envelope_signature, prüfte sie nie. Verweist Brief #128 (+ Review-Härtung). Phase B (did:web) = Follow-on (egress-proxy).

app/enforcement/acceptance_gate.pyverify_aae_jws

  • compact-JWS-verify mit explizitem algorithms=["EdDSA"]-Allowlist (PyJWT PyJWS, kein neues dep) — header-alg nie vertraut (alg=none/HS*/RS* → reject).
  • kid strikt (W3C DID-URL, path-traversal/look-alike-Schutz) VOR signing-DID-Extraktion.
  • did:moltrust → agents.public_key_hex (assertionMethod {did}#key-1); did:web → NotImplementedError (Phase B).
  • signing-authority: signing-DID == VC issuer (non-delegated).
  • canonicalization: raw_canonical = exakte base64url-decoded payload-bytes (NIE re-serialize); JSON nur für Schema, mit object_pairs_hook gegen duplicate-keys.
  • Step 2: cty:"aae+json", VC-Schema, credentialSubject.aae={mandate,constraints,validity}.

Weitere Änderungen

  • Migration 013 issuer_trust_tier (additive, trusted/unverified_issuer) + fork-ci.
  • aae_submit → Contract {aae_jws}, verify VOR persist, fail-closed reject, rate-limit (replay/DoS).
  • persist_envelope nimmt jetzt raw_canonical (bytes) + issuer_trust_tier (statt server-gebautes raw_envelope).
  • Altes split-field test_aae_endpoint.py entfernt (Contract abgelöst).

Tests (server-venv, 58 grün — D-1 + Regression store/evaluator/evaluate-endpoint)

verify_aae_jws: valid-accept (+ exakte-bytes), alg=none/HS256→reject, kid-path-traversal→reject, wrong-kid-fragment→reject, signing-DID≠issuer→reject, key-substitution→reject, cty-wrong→reject, duplicate-JSON-keys→reject, unregistered-DID→reject, did:web→NotImplemented. Endpoint: accept (issuer_trust_tier=trusted), auth-missing→401, invalid→422, replay→409.

Konformität

§3.1 + §3.2 ✅. NICHT auf Live — Code+Migration+CI; 013 wurde für den Test transient angewandt + revertet (live-Schema unverändert). CI validiert 013 gegen frische Postgres.

NEXT

Security-Code-Review von acceptance_gate.py (JWS-Verifikations-Präzision). did:web = Phase B.

🤖 Generated with Claude Code

Lars Kroehl added 2 commits June 3, 2026 08:09
acceptance_gate.verify_aae_jws: AAE draft-04 §5 Step1+2 (signature+signing-authority+payload/schema/cty), fail-closed. Hardened: explicit algorithms=[EdDSA] allowlist (no header-alg trust), strict kid DID-URL parsing (path-traversal/look-alike), raw_canonical = exact b64url-decoded payload bytes (never re-serialize), object_pairs_hook duplicate-key reject. did:moltrust resolved via agents.public_key_hex (assertionMethod {did}#key-1); did:web = Phase B NotImplemented. Migration 013 issuer_trust_tier (additive). aae_submit -> {aae_jws} contract, verify before persist, rate-limit. persist_envelope takes raw_canonical bytes + issuer_trust_tier. Removed old split-field test_aae_endpoint.py.

Per brief #128. Code+migration+CI only — NOT applied to live.
…on (design-only)

verify_aae_jws: DoS size-caps (JWS<=16KB, payload-b64url<=11000 ~8KB) BEFORE base64-decode/parse/verify; explicit options={verify_signature:True} on PyJWS decode (no library-default trust); pass validated kid var (not header[kid] re-access). Scope-note: temporal exp/nbf = Evaluator (Komponente 2, §5 Step 3), by-design not D-1. Crypto core was review-validated; these are peripheral hardenings.
@MoltyCel MoltyCel merged commit 720561a into main Jun 3, 2026
8 of 12 checks passed
MoltyCel added a commit that referenced this pull request Jun 3, 2026
…#130)

app/enforcement/acceptance_gate.py imports jwt (PyJWT) but it was only in the server venv, not requirements.txt -> CI fresh-install + import smoke broke after #129. PyJWT>=2.12.0 added. Live service unaffected (venv already has it).

Co-authored-by: Lars Kroehl <kersten.kroehl@cryptokri.ch>
MoltyCel added a commit that referenced this pull request Jun 3, 2026
requests is imported directly in 13 places (requests_oauthlib for X/Twitter, agents/traffic_monitor.py, smoke), but was only present transitively via web3/stripe -> fresh-install/CI fragile (same class as the PyJWT #129 red). Declared requests>=2.33.0. redis NOT added: 0 direct imports in app/scripts/agents (installed-but-unused = not a code dependency). After this, no production-used package is undeclared.

Co-authored-by: Lars Kroehl <kersten.kroehl@cryptokri.ch>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant