S00-017: Validate SCRAM server-final before authenticated SASL completion
Changes: Add an isolated Stanza 12.22.1 SASL feature replacement using existing SCRAM crypto, exact dependency lock and MIT notices, 44 integrated fixture checks, proposed ADR and review handoff. Leave production adapters and the original library experiment unchanged. Validation: Fresh-cache npm ci and npm test passed on Node 24.21.0/npm 11.19.0; 44 tests cover RFC SHA-1/SHA-256 proofs and verified finals, stock defect reproduction, invalid/premature finals and async cleanup. make check passed 72 tooling tests. Pins/licenses/notices, unchanged vendor source and whitespace verified. Browser/WSS/server interoperability and constant-time assurance remain unverified; independent security review is pending. Task: S00-017 Agent: auto-protocol-599343cd9e3f Role: protocol Action: claim Status: review Task title: Establish fail-closed SCRAM server-final validation
This commit is contained in:
1 parent
c73d9cef45
commit
493fbaebe7
18 files changed
+1043
-8
No files matched your search
@@ -0,0 +1,112 @@
|
||||
# ADR 0002-SASL: Fail-closed SCRAM server-final experiment
|
||||
|
||||
- Status: proposed; requires independent security review of S00-017.
|
||||
- Task: S00-017, remediation for S00-003.
|
||||
- Date: 2026-10-15.
|
||||
- Owner: auto-protocol-599343cd9e3f (protocol).
|
||||
- Reviewer: assigned security role, decision pending.
|
||||
- Requirements: ACC-004, NET-003, NET-004; accepted ADR 0000/0001 preserved.
|
||||
|
||||
## Question and bounded result
|
||||
|
||||
Can the pinned StanzaJS candidate validate SCRAM server authentication before
|
||||
emitting success/restarting without modifying vendor source or implementing
|
||||
cryptographic primitives? Output is one isolated, runnable feature experiment,
|
||||
not selection of Stanza as the production library. S01 shared contracts remain
|
||||
unaccepted; no application adapter or interface is created here.
|
||||
|
||||
The original blocker is reproducible in 12.22.1: its SASL success branch marks
|
||||
negotiation/transport authenticated, emits auth:success and requests restart
|
||||
without processing additional-data or calling the SCRAM verifier. Empty and
|
||||
forged success before challenge/proof are accepted. The isolated tests retain
|
||||
this baseline reproduction and exercise the replacement through the real XML
|
||||
registry and feature dispatcher.
|
||||
|
||||
## Options and proposed decision
|
||||
|
||||
1. **Replace the named SASL feature through public APIs.** Chosen for this bounded
|
||||
experiment. `Client.use` and `registerFeature` are exposed in installed package
|
||||
declarations; the registry assigns handlers by name. SCRAM already exposes
|
||||
`processSuccess` and `finalize`. Keep all crypto in that existing implementation
|
||||
and add fail-closed ordering, strict fixture-profile input and cleanup.
|
||||
2. **Patch ignored vendor code or intercept success after emission.** Rejected:
|
||||
ignored patches are not reproducible deliverables, and a post-success listener
|
||||
cannot prevent earlier authenticated effects. No upstream patch is required.
|
||||
3. **Replace the entire client/mechanism stack.** Deferred to S00-003. The original
|
||||
evidence's xmpp.js source comparison also lacked server-final processing;
|
||||
no installed/tested alternative or maintenance/security superiority is claimed.
|
||||
|
||||
Install the proposed plugin on a fresh Client before connect/feature events;
|
||||
never permit the stock SASL handler to start first. The named registration
|
||||
replaces its callback without editing registry internals. The API appends an
|
||||
order entry; the actual dispatcher exits on restart/disconnect, with tests
|
||||
confirming one completion and successful later negotiation after reset.
|
||||
|
||||
Only after proof send completes does success data reach library `processSuccess`
|
||||
and `finalize`; both authenticated and mutuallyAuthenticated must be true before
|
||||
any authenticated flag, event or restart. Missing, forged, erroneous, duplicated,
|
||||
malformed or premature final is terminal failure. Reset removes attempt listeners
|
||||
and cancels asynchronous continuation. Proof/credential/send exceptions fail
|
||||
without logging credentials, peer data or crypto state. No cache is persisted.
|
||||
|
||||
## Sources, pins and licenses
|
||||
|
||||
Primary sources inspected on 2026-10-15:
|
||||
|
||||
- [RFC 5802 §5](https://www.rfc-editor.org/rfc/rfc5802.html#section-5): mutual
|
||||
authentication and SHA-1 exchange; the public user/pencil fixture is copied as
|
||||
test data, not used as an account. Invalid verifier must fail the exchange.
|
||||
- [RFC 7677 §3](https://www.rfc-editor.org/rfc/rfc7677.html#section-3): SHA-256
|
||||
exchange used as a second fixed primary-spec transcript.
|
||||
- [Stanza 12.22.1 registry record](https://registry.npmjs.org/stanza/12.22.1):
|
||||
exact package provenance location/license and locked tarball. Installed shipped
|
||||
`Client.js/.d.ts`, `plugins/features.js/.d.ts`, `plugins/sasl.js` and
|
||||
`lib/sasl/index.js/.d.ts` are the exact API/implementation evidence. Upstream
|
||||
[Client source](https://github.com/legastero/stanza/blob/master/src/Client.ts)
|
||||
corroborates plugin usage, but is not version-pinned acceptance evidence.
|
||||
|
||||
Dependency: stanza 12.22.1, MIT. Exact transitive pins: @types/node 22.20.5,
|
||||
@types/punycode 2.1.4, @types/ws 8.18.2, punycode 2.3.1, sdp 3.2.2,
|
||||
undici-types 6.21.0, ws 8.22.0; all MIT. Separate manifest/lock under
|
||||
`experiments/0002-xmpp-library/sasl-validation` does not alter the parent's
|
||||
unaccepted exploratory graph. Every locked package has HTTPS registry URL,
|
||||
SHA512 integrity and inspected installed license text; inventory and notices
|
||||
are preserved. Runtime stays Node 24.21.0/npm 11.19.0 from accepted ADR 0001.
|
||||
No new crypto dependency, crypto primitive or vendor-source edit is introduced.
|
||||
|
||||
## Runnable evidence and constraints
|
||||
|
||||
See experiment README and `state/evidence/S00-017-auto-protocol-599343cd9e3f.md`.
|
||||
Clean npm ci with an empty cache and npm test passed: 44 tests, including two
|
||||
RFC client proofs/verified finals, original insecure baseline, missing/forged/
|
||||
premature rejection, duplicate/out-of-order inputs, send/credential failure,
|
||||
asynchronous reset and replay rejection. Tests observe real feature-dispatcher
|
||||
restart/disconnect calls and transport/negotiation flags; they are local parsed
|
||||
XML integration tests with captured outbound effects, not WSS/server tests.
|
||||
|
||||
The experiment accepts only non-PLUS SHA-256/SHA-1, selecting the strongest of
|
||||
those offered and failing if neither is available. No plaintext fallback or
|
||||
invented browser TLS binding. SHA-512, complete mechanism policy and compatibility
|
||||
remain S00-003. Server-final is accepted only as success additional-data; separate
|
||||
final challenge, SCRAM extensions and extra challenge round trips are rejected.
|
||||
Decoded-data and iteration bounds (4096 bytes / 100000) are local experiment
|
||||
limits. A success racing a pending send is conservatively rejected. These
|
||||
restrictions can reduce availability and need explicit future integration review.
|
||||
|
||||
Node exercises Stanza's SCRAM composition and Node crypto primitives. Browser
|
||||
Stanza uses bundled synchronous hashing/HMAC, global crypto RNG, WebSocket and
|
||||
fetch; its backend/build is not tested in this task. No browser support matrix,
|
||||
constant-time comparison guarantee (Stanza compares verifier strings), advisory/
|
||||
provenance clearance, WSS/TLS/channel-binding test, independent-client/server
|
||||
interoperability or production readiness is implied. No live credentials,
|
||||
network authentication, certificate/CORS bypass or persisted secrets are used.
|
||||
|
||||
## Handoff and consequences
|
||||
|
||||
Independent security reviewer must reproduce the integrated positive/negative
|
||||
cases and assess extension API, cleanup, license/pin evidence and the stated
|
||||
restrictions. This ADR stays proposed until review. Reviewed acceptance permits
|
||||
a fresh S00-003 executor to evaluate this approach in its own experiment; it does
|
||||
not implement that original task or change the accepted stack/shared contracts.
|
||||
Any required broader policy/interface or vendor replacement is a separately
|
||||
scoped plan decision. Coordinator owns transition commits and fresh processes.
|
||||
Reference in new issue
Block a user