Files
LumaWeb/experiments/0002-xmpp-library/sasl-validation/README.md
T
wt 493fbaebe7 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
2026-10-15 02:17:46 +07:00

77 lines
4.4 KiB
Markdown

# SCRAM server-final validation experiment
S00-017 fixture-only remediation of S00-003. No network connection or production
adapter. Public RFC example credentials are used only in memory. Requires the
accepted Node 24.21.0 / npm 11.19.0 runtime; installs enforce exact engines and TLS.
From the project root, use the isolated runtime already verified by S00-002:
```sh
export PATH=/private/tmp/luma-stack-runtime/node-v24.21.0-darwin-arm64/bin:$PATH
node --version
npm --version
npm ci --prefix experiments/0002-xmpp-library/sasl-validation --ignore-scripts --no-audit --no-fund --cache /private/tmp/luma-sasl-review-cache --fetch-retries=0 --fetch-timeout=15000
npm test --prefix experiments/0002-xmpp-library/sasl-validation
```
On another host, obtain the official exact Node runtime with verified HTTPS and
checksum; do not change system configuration or disable certificates. Use a fresh
cache directory for an independent clean-install check. The original parent
experiment manifest remains incomplete and is not used by these commands.
The 44 tests use Stanza's actual Client, XML parse/registry, named SASL feature
handler, feature negotiation dispatcher and SCRAM implementation. Outgoing sends,
restart and disconnect are captured fixture effects, not server evidence. Tests
first reproduce stock 12.22.1 accepting missing/forged premature success, then
verify rejection with the replacement. RFC 5802 §5 / RFC 7677 §3 client-first,
client-proof and verified server-final are checked byte-for-byte for SHA-1/256.
No real credentials or key material are printed. A passing stock reproduction
means the defect was observed, not safe authentication.
`validated-sasl.mjs` installs through the public plugin and feature APIs:
```js
// Illustrative integration for a fresh Client, BEFORE any connect/features.
client.use(validatedSasl);
```
The plugin calls `registerFeature('sasl', 100, handler)`. Stanza's feature registry
uses one handler per name, so this replaces the stock callback. Registration also
adds another order entry; the real dispatcher exits on restart/disconnect, and
our integrated tests verify only one negotiation/completion, including after
reset. Do not install after authentication has started or alongside another SASL
replacement. The stock handler must never have an active event listener.
State is bounded to initial credentials/send, server-first, proof send,
server-final and closed. Success is allowed only after completed proof send,
strict final syntax, `processSuccess` and `finalize` reporting both authenticated
and mutuallyAuthenticated. Invalid input disconnects once, removes listeners
and never requests authenticated restart. Reset closes the old attempt before
awaited work resumes. Crypto remains entirely in the installed library, backed
by Node crypto in this run; no hash, HMAC, KDF or proof implementation is authored.
No credential cache/update is persisted by the replacement.
This is a deliberately limited non-PLUS SHA-256/SHA-1 experiment. It rejects
other mechanisms, supplied TLS binding bytes, extensions, extra challenges and
server-final delivered separately as a challenge. It accepts only server-final
additional-data on success. It checks nonce extension and bounds decoded data
at 4096 bytes and iterations at 100000; these are experiment limits, not shared
contracts/product policy. Racing success before a send promise resolves is
rejected conservatively. A final timeout/lifecycle policy belongs to the original
integration; this experiment does not claim one.
Exact dependency graph and preserved licenses: LICENSE_INVENTORY.md and
THIRD_PARTY_NOTICES.md. All eight locked packages are MIT; lock entries retain
HTTPS registry URLs and SHA512 integrity. Node/npm notices stay with their runtime.
Security review must inspect the state transitions and actual library calls,
repeat clean install/tests, check the diff, licenses and executor evidence, then
approve/reject through the task workflow. No browser build/execution, live WSS,
independent server, parser resource-limit certification, TLS channel binding,
constant-time verification audit, advisory/provenance audit, production SASL
policy or release readiness is claimed. Stanza's verifier uses ordinary string
equality; these tests prove rejection correctness, not a timing guarantee.
Browser Stanza uses its bundled synchronous hash/HMAC code and browser RNG/WS;
that backend is not exercised here. S00-003 retains its library selection,
browser/WSS/parser/extension experiment and stronger-mechanism policy work.