Files
wt 07c9967d02 S00-019: Validate browser SCRAM-SHA-512 through public mechanism composition
Changes: Add an isolated pinned mechanism wrapper using Stanza's public constructor and factory APIs, preserve the SCRAM-SHA-512 wire name and fail-closed final guard, and document the proposed ADR, browser bundle evidence, independent Scramp vectors, notices and limits. Leave parent selection, dependency experiments, specs and shared contracts unchanged.
Validation: Fresh-cache npm ci and Vite browser build pass; 87 focused tests pass, including RFC HMAC vectors, original defect reproduction, independent full SHA-512 exchanges and rejected invalid finals/order/reset paths. Hashed Scramp oracle fixture comparison passes. Dependency check verifies 49 locked entries, 25 installed pins/licenses and 340 unmodified Stanza files. make check passes 72 tooling tests. Native browsers, WSS/live server interoperability and production readiness are untested; independent security review remains pending.

Task: S00-019
Agent: auto-crypto-c68801170fa4
Role: crypto
Action: claim
Status: review

Task title: Validate browser-compatible SCRAM-SHA-512 through a public mechanism API
2026-10-15 02:48:39 +07:00
..

Isolated browser SCRAM-SHA-512 validation

S00-019 fixture experiment, proposed for independent security review. No live account/transport or parent library selection. Node executes the browser-built backend, not Stanza's Node crypto. This is browser bundle/backend evidence, not an actual Chrome/Firefox/Safari execution or WSS interoperability result.

Reproduce

Use accepted Node 24.21.0 / npm 11.19.0. Existing reviewed macOS ARM64 runtime:

export PATH=/private/tmp/luma-stack-runtime/node-v24.21.0-darwin-arm64/bin:$PATH
npm ci --prefix experiments/0002-xmpp-library/sha512-validation --ignore-scripts --no-audit --no-fund --cache /private/tmp/luma-sha512-review-cache --fetch-retries=0 --fetch-timeout=15000
npm test --prefix experiments/0002-xmpp-library/sha512-validation
python3 experiments/0002-xmpp-library/sha512-validation/check-dependencies.py

Use a new empty cache for independent clean-install evidence. The dependency check also reads the original installed candidate at the parent node_modules for byte comparison; it does not modify it. If unavailable, reproduce its pinned install under the parent task's authority or compare Stanza against its locked tarball separately; do not change the parent from this task.

npm test builds before running 87 checks. Vite's default browser resolution selects stanza/platform/browser. events 3.3.0 is the explicit browser EventEmitter polyfill. Build fails if module IDs show Node backend/builtins/browser externals or no browser HMAC. Output dist/modules.json lists resolved modules; dist/browser.mjs is a self-contained ESM bundle. Backend tests inspect graph, no runtime imports/require, and exported platform name browser. All integrated exchanges import this artifact, never Node source. Node crypto is an independent primitive oracle in tests only; the integration suite has no Node crypto import. The native RNG path uses host getRandomValues, not a fabricated success value.

Independent full-exchange oracle

The checked-in test/scramp-vectors.json is fixed output from Scramp 1.4.6 client and server (Python test-only MIT-0 dependency, asn1crypto 1.5.1 MIT). Both client proof and server-final are independently verified. Inputs combine public RFC 7677 nonce/salt/4096-iteration data with SHA-512 and synthetic passwords pencil, 131 A characters and péncil. These SHA-512 transcripts are independently derived vectors, not a claim that RFC 7677 specifies SHA-512 examples.

python3 -m venv /private/tmp/luma-sha512-review-oracle
/private/tmp/luma-sha512-review-oracle/bin/python -m pip install --require-hashes --only-binary=:all: --no-cache-dir -r experiments/0002-xmpp-library/sha512-validation/oracle-requirements.txt
/private/tmp/luma-sha512-review-oracle/bin/python experiments/0002-xmpp-library/sha512-validation/oracle.py

Python >=3.8; each wheel version/hash is exact. Default oracle mode compares existing fixed fixtures; it does not rewrite them. --write is an explicit fixture-generation operation. Scramp is excluded from the app/browser graph. 1.4.6 supports the available Python 3.9 host and the documented APIs; no current release or supply-chain/advisory clearance is inferred. Notices are preserved.

Public mechanism path

Sha512Mechanism composes Stanza's exported SCRAM using its public string constructor with SCRAM-SHA512, selecting the existing documented-by-shipped-code sha512 alias. Its separate Mechanism.name is always SCRAM-SHA-512. Internal alias never goes on the wire. Public Factory.disable/register installs that constructor. No Stanza private field is read/changed, no subclass/private-method hook or vendor/bundler crypto patch. Actual cryptographic primitives, PBKDF-style SCRAM composition, SASLprep and verifier stay in unmodified Stanza library code. This is version-specific public API composition, not an upstream endorsement of a future stable alias contract; pins and full vectors are mandatory safeguards.

The isolated feature handler is copied from reviewed S00-017, narrowed to SHA-512 and 88-character base64 verifier, and registers the new mechanism. Install via Client.use on a fresh Client before any negotiation; never install after stock SASL begins. Mechanism priorities filter to SHA-512 even alongside PLUS/256/1/PLAIN offers; unsupported-only offers fail. Complete product fallback policy stays with S00-003. No real channel binding exists; tlsUnique input fails rather than creating PLUS or a fabricated binding. Initial GS2 is n,, and c=biws.

Guard requires completed proof send before success, strict bounded first/final syntax, then real processSuccess/finalize with both authenticated flags. Missing, forged, malformed, premature/duplicate/racing final and replay fail without auth or restart. Async reset/send failures discard continuation. No derived cache is persisted/emitted and no raw credentials/peer data is logged by authored code. Captured send/transport/disconnect effects are explicit fixtures; actual Client, registry/XML parser, feature dispatcher, mechanism and crypto run.

Limits

Only server-final in success additional-data, no SCRAM extensions/separate final challenge. Limits 4096 decoded bytes and 100000 iterations are fixture policy. Synchronous library PBKDF work can block the UI; no worker/performance acceptance. No constant-time claim: Stanza compares verifier strings. No timeout is added; server silence stays unauthenticated until external reset/cancellation. No arbitrary Unicode/SASLprep conformance certification beyond the fixed case. Native browser engine/RNG execution, WSS/TLS, independent live server/client, parent bounded-ingress integration, complete mechanism policy and release readiness remain outside this experiment. No TLS/certificate/CORS bypass or plaintext downgrade. Browser syntax floors match accepted Vite targets Chrome/Edge 111, Firefox 114, Safari 16.4; API requirements include crypto RNG, fetch and WebSocket. These are build floors, not a certified product matrix.

Licenses: full locked graph in LICENSE_INVENTORY.md, installed notices including Stanza browser crypto ancestry in THIRD_PARTY_NOTICES.md; oracle notices separate. Vite/build native components are not browser runtime crypto. events maintenance has few contributors per upstream; Stanza crypto is reviewed here with vectors, not newly audited. Dependency/advisory/provenance review remains release work.