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
104 lines
6.3 KiB
Markdown
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.
|