Files
LumaWeb/experiments/0002-xmpp-library/sha512-validation/README.md
T
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

104 lines
6.3 KiB
Markdown

# 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:
```sh
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.
```sh
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.