S00-003: Evaluate Stanza with verified SCRAM and bounded WSS ingress

Changes: Propose the pinned XMPP library decision and add an isolated browser-built selection spike combining reviewed public SASL, SHA-512 and parser seams. Exercise TLS/xmpp handshake, strongest compatible non-PLUS authentication, rejected unsafe paths and extension mappings; document duplicate-body export projection and remaining limits. Preserve dependency notices, evidence and QA handoff.
Validation: Clean-cache pinned npm ci succeeded; npm test passed 112 checks; check-dependencies.py verified 51 locked entries, 26 installed packages and 340 unchanged vendor files; make check passed 72 tooling tests. No actual browser runtime, independent full XMPP server/client or production encryption/release readiness claim.

Task: S00-003
Agent: auto-protocol-f474114f0168
Role: protocol
Action: claim
Status: review

Task title: Проверить XMPP WSS/auth библиотеку
This commit is contained in:
wt committed 2026-10-15 18:20:05 +07:00
1 parent e08c0ab590
commit 51a414d386
28 files changed
+6709 -32

No files matched your search

+127
View File
@@ -0,0 +1,127 @@
# ADR 0002: XMPP library and required browser integration seams
- Status: proposed; S00-003 independent QA review pending.
- Date: 2026-10-15. Owner: auto-protocol-f474114f0168 (protocol).
- Reviewer role: qa; no acceptance claimed by executor.
- Requirements: ACC-004, NET-003, NET-004.
- Prerequisites: accepted scope/stack ADRs and bounded SASL, parser, SHA-512
experiments (S00-017/018/019); independently reviewed Linux environment S00-020.
## Question and decision
Select Stanza 12.22.1 (MIT), with the three reviewed public integration seams
mandatory before connect: bounded transport, fail-closed SASL feature, and the
SHA-512 mechanism composition. Stock Stanza alone is unsuitable for this profile.
Its stock SASL handler does not verify server-final, its browser hyphenated
SHA-512 HMAC is wrong, and its persistent parser has no finite resource budgets.
The accompanying spike proves the composed candidate; it creates no production
adapter, shared contract, crypto implementation or provider deployment.
| Option | Evidence and tradeoff |
| --- | --- |
| Stanza 12.22.1 plus reviewed extensions | Selected: actual browser bundle, public Client/Factory/Registry/Transport APIs, verified fixed SCRAM transcripts, loopback WSS and extension fixtures. JSON models and built-in MAM/MUC/Jingle/upload mappings fit the planned adapter boundary. Exact-version alias and replacement plugins require regression checks on upgrades. |
| Stock Stanza | Rejected: the accepted remediation experiments reproduce security/framing defects. Installing the package alone does not meet this decision. |
| xmpp.js | Viable alternative with browser WebSocket and modular packages; its primary README documents MIT and client/component modules. Not installed or executed here; no superiority/security finding or exact pin is claimed. It would require a separate equivalent integration experiment, rather than assuming its SASL/parser meet the profile. |
## One runnable selection experiment
`experiments/0002-xmpp-library/selection-spike` combines unchanged reviewed
bounded-ingress and SHA-512 alias source with the ordering guard extended to
non-PLUS SHA-512/256/1. Existing library crypto implements all hashes, HMAC,
SCRAM and SASLprep. No vendor file, private field or primitive is changed.
The real Client.connect, XML registry, feature dispatcher, queue and browser
SCRAM backend run against a synthetic loopback HTTPS/WebSocket peer. Its
self-signed certificate is generated temporarily by OpenSSL, trusted explicitly
by the test socket only, and hostname/certificate checks remain enabled. No
system trust store is changed. An uninjected native WebSocket rejects the same
untrusted certificate; a plaintext endpoint is rejected before a socket exists.
The trusted peer observes TLS plus the xmpp subprotocol, framing open, exact
proof and a second open only after a valid server-final. Forged/premature finals
never authenticate or restart. This is a real WSS handshake with a fixture peer,
not interoperability with a deployed independent XMPP server.
Mechanism policy filters PLUS because browser TLS binding is unavailable,
selects SHA-512 then SHA-256 then SHA-1 independent of offer order, and disables
all other fallbacks. NET-003 permits a configured protected fallback; this
selection enables none. PLUS-only/PLAIN-only/empty offers fail. Diagnostics
contain selected mechanism, `channelBinding: unavailable`, and disabled fallback;
no credential, nonce, proof or peer payload. Synthetic tlsUnique is rejected.
GS2 n,, and c=biws are verified. A future platform with real binding must add a
separately reviewed implementation before offering PLUS.
Parser experiment ceilings are preserved: 4096 UTF-8 bytes, depth 8, 32 elements,
16 attributes, 1024 aggregate attribute units, 128 name units and 256 attribute
value units. Standalone complete text XML is preflighted by saxes before JXT
import. Oversized and split XML fail on the actual WSS path. These numbers are
local experiment limits, not a production message/media-size contract.
Registry fixtures import/export MAM forwarded IDs, MUC join, Jingle terminate,
HTTP upload URLs and legacy opaque OMEMO bytes. An explicitly invented opaque
namespace demonstrates Client.use/Registry.define extension and namespace
isolation. It is not an OMEMO2 implementation or encrypted messaging claim.
Imported messages expose both selected `body` and `alternateLanguageBodies`;
exporting both concatenates text in this version. A regression records it;
the MAM fixture exports only the language collection. Future adapters must
construct deliberate outbound shapes rather than echo imported objects.
## Reproduction, versions and licenses
Follow the experiment README. Exact Node 24.21.0/npm 11.19.0 and Vite 8.3.4 remain
from accepted ADR 0001. Stanza 12.22.1, saxes 6.0.0, events 3.3.0 and test peer
ws 8.22.0 have exact direct pins; lock v3 includes all optional hosts. These are
already reviewed package families, not a new stack. MIT/ISC runtime notices,
Stanza bundled ancestry, and build MIT/ISC/BSD/Apache/MPL notices are preserved
in inventory/notices; saxes' omitted package license is preserved from the
reviewed versioned upstream copy. MPL build code is unmodified. Dependency
monitoring, provenance and advisory clearance remain continuing release work.
Browser syntax floors are the accepted Chrome/Edge 111, Firefox 114, Safari 16.4
build targets, not a product support certification. Bundle graph excludes Node
platform/crypto and unresolved builtins; events is explicitly bundled. Native
WebSocket, secure RNG, URL and TextEncoder are required. Server/test tooling
Node crypto is only an independent oracle; it does not replace browser crypto.
## Primary sources inspected on 2026-10-15
- [RFC 7395](https://www.rfc-editor.org/rfc/rfc7395.html), sections 3.1–3.4,
3.7 and 3.9: subprotocol, complete text XML, framing, restart and TLS.
- [RFC 5802](https://www.rfc-editor.org/rfc/rfc5802.html#section-5) and
[RFC 7677](https://www.rfc-editor.org/rfc/rfc7677.html#section-3): fixed SHA-1/256
exchange vectors and server verification. SHA-512 independent Scramp fixtures
and RFC 4231 primitive vectors retain their accepted S00-019 provenance.
- [Stanza upstream](https://github.com/legastero/stanza) and
[xmpp.js upstream](https://github.com/xmppjs/xmpp.js): candidate APIs, browser
positioning and licenses. Exact installed Stanza 12.22.1 Client.d.ts/.js,
lib/sasl, plugins/features, jxt/Registry and protocol modules are authoritative
for shipped extension behavior; all 340 files match the independently installed
S00-020 vendor graph. Upstream branches do not establish version guarantees.
- [XEP-0313](https://xmpp.org/extensions/xep-0313.html),
[XEP-0045](https://xmpp.org/extensions/xep-0045.html),
[XEP-0166](https://xmpp.org/extensions/xep-0166.html),
[XEP-0363](https://xmpp.org/extensions/xep-0363.html): fixture namespaces and
envelope/extension shapes. Shipped protocol comments identify older revisions;
a passing simple fixture does not establish complete current-XEP coverage.
## Consequences, limits and review
The spike is sufficient input for bounded selection review. Production still
requires S01 contracts and its own implementations/tests. The minimal transport
omits complete stream sequencing, error/close negotiation, redirect and keepalive
policies. Queue/rate/network-allocation bounds, worker/CPU performance, timeout,
full SASL extensions/final-challenge compatibility and constant-time verifier
assurance are not established. Library verifier uses string equality. Strict
success-only final layout and conservative send-race rejection reduce availability.
No Chrome/Firefox/Safari runtime execution, independent XMPP server/client,
real account, OMEMO encryption, production feature semantics, full browser matrix
or release readiness was verified. Browser-built code runs in Node with host web
APIs; socket injection adds fixture CA trust, not a browser channel-binding API.
Old accepted experiment source is unchanged; shared interfaces/specs/stack and
network/TLS/CORS policies remain unchanged. Any API incompatibility on upgrade
requires a new bounded decision, not a private patch or silent downgrade.
QA should reproduce clean install/build/tests and dependency checks, inspect the
stock defect controls, explicit extension projection and scope, then record an
independent decision. Evidence: `state/evidence/S00-003-auto-protocol-f474114f0168.md`.
Coordinator owns transition commits; this ADR remains proposed until review.