One real message through a live obfs4 bridge #76

Merged
extant2000git merged 2 commits from bridge/one-real-message into main 2026-10-14 18:40:29 +00:00
Owner

The 2026-09-28 answers to OTF said bridge users "can reach the relay from anywhere". That was false: the bridge forwarded to relay:8080 in plain HTTP while the apps speak TLS through the tunnel, so no app session could complete. The upstream was fixed on 2026-10-07 and checked with one GET, and a GET is not a message.

This is the exchange behind the claim: two accounts, two devices, a sealed envelope from this engine, the recipient decrypting it, and every byte over obfs4 to a relay on the internet.

Run against the live bridge on 2026-10-14, relay1.flamenet.io through 135.148.121.177:8443:

  ok    the relay answers /health through the tunnel
  ok    the certificate is the relay's own (relay1.flamenet.io)
  ok    two accounts were created through the tunnel
  ok    both devices published their bundles
  ok    alice fetched bob's bundle
  ok    the bundle names a device
  ok    the envelope was deposited through the tunnel
  ok    bob's inbox answered through the tunnel
  ok    the envelope arrived
  ok    bob decrypted the exact plaintext alice sealed

10 passed, 0 failed

The edge access log carries the other half. ClientHost was the real client address for every request in the run, and the bridge's own 172.18.255.240 appeared as a client zero times, so the PROXY v1 line works and a ban or a rate limit lands on one bridged client rather than on all of them.

Not in npm test: it needs a live bridge and bridgeforward (merged as extant2000/flamenet-elligator2#4), so it skips when nothing is listening rather than failing about the environment. It creates accounts, so it points at a test relay by default.

Three things this cost, each a 400 or a 401 with no hint in it:

  • usernames are lowercase letters and digits only;
  • the proof-of-possession signature must come from the identity's own CryptoKey, because ikSig.privRaw is a 48-byte PKCS#8 blob and not the 32-byte seed a hand-rolled wrapper expects, and the wrong wrapper signs happily and verifies against nothing;
  • §8.2 wants to as an integer with a messages list, not a flat {to, device_id, payload}.

Gate: node test/conformance.mjs 304 passed, 0 failed, 2 skipped. The skip path was exercised too, with the port pointed somewhere empty.

🤖 Generated with Claude Code

The 2026-09-28 answers to OTF said bridge users "can reach the relay from anywhere". That was false: the bridge forwarded to `relay:8080` in plain HTTP while the apps speak TLS through the tunnel, so no app session could complete. The upstream was fixed on 2026-10-07 and checked with one GET, and a GET is not a message. This is the exchange behind the claim: two accounts, two devices, a sealed envelope from this engine, the recipient decrypting it, and every byte over obfs4 to a relay on the internet. Run against the live bridge on 2026-10-14, relay1.flamenet.io through `135.148.121.177:8443`: ``` ok the relay answers /health through the tunnel ok the certificate is the relay's own (relay1.flamenet.io) ok two accounts were created through the tunnel ok both devices published their bundles ok alice fetched bob's bundle ok the bundle names a device ok the envelope was deposited through the tunnel ok bob's inbox answered through the tunnel ok the envelope arrived ok bob decrypted the exact plaintext alice sealed 10 passed, 0 failed ``` The edge access log carries the other half. `ClientHost` was the real client address for every request in the run, and the bridge's own `172.18.255.240` appeared as a client zero times, so the PROXY v1 line works and a ban or a rate limit lands on one bridged client rather than on all of them. Not in `npm test`: it needs a live bridge and `bridgeforward` (merged as extant2000/flamenet-elligator2#4), so it skips when nothing is listening rather than failing about the environment. It creates accounts, so it points at a test relay by default. Three things this cost, each a 400 or a 401 with no hint in it: - usernames are lowercase letters and digits only; - the proof-of-possession signature must come from the identity's own `CryptoKey`, because `ikSig.privRaw` is a 48-byte PKCS#8 blob and not the 32-byte seed a hand-rolled wrapper expects, and the wrong wrapper signs happily and verifies against nothing; - §8.2 wants `to` as an integer with a `messages` list, not a flat `{to, device_id, payload}`. Gate: `node test/conformance.mjs` 304 passed, 0 failed, 2 skipped. The skip path was exercised too, with the port pointed somewhere empty. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
extant2000git added 1 commit 2026-10-14 18:38:34 +00:00
One real message through a live obfs4 bridge
ci / secret-sweep (pull_request) Failing after 5s
ci / ratchet (pull_request) Successful in 6s
ci / doc-references (pull_request) Successful in 3s
ci / complete (pull_request) Successful in 3s
ci / client (pull_request) Successful in 26s
ci / vault (pull_request) Successful in 5s
ci / conformance (pull_request) Successful in 10s
ci / spec-counts (pull_request) Successful in 29s
62d209bcd0
The 2026-09-28 answers to OTF said bridge users "can reach the relay
from anywhere". That was false: the bridge forwarded to relay:8080 in
plain HTTP while the apps speak TLS through the tunnel, so no app
session could complete. The upstream was fixed on 2026-10-07 and checked
with one GET, and a GET is not a message.

This is the exchange behind the claim. Two accounts, two devices, a
sealed envelope from this engine, the recipient decrypting it, and every
byte over obfs4 to a relay on the internet.

Run against the live bridge on 2026-10-14, relay1.flamenet.io through
135.148.121.177:8443, 10 passed and 0 failed, ending in "bob decrypted
the exact plaintext alice sealed".

The edge access log carries the other half: ClientHost was the real
client address for every request in the run, and the bridge's own
172.18.255.240 appeared as a client zero times. So the PROXY v1 line
works, and a ban or a rate limit lands on one bridged client rather
than on all of them at once.

Not in `npm test`: it needs a live bridge and the forwarder, so it skips
when nothing is listening on the local port rather than failing about
the environment. It also creates accounts, so it is pointed at a test
relay by default.

Three things this cost, each a 400 or a 401 with no hint in it:
usernames are lowercase letters and digits only; the proof-of-possession
signature must come from the identity's own CryptoKey, since `privRaw`
is a 48-byte PKCS#8 blob and not the 32-byte seed a hand-rolled wrapper
expects; and §8.2 wants `to` as an integer with a `messages` list, not a
flat payload.

The engine suite still passes: 304 passed, 0 failed, 2 skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
extant2000git added 1 commit 2026-10-14 18:39:42 +00:00
Keep the fixture password out of the secret sweep's way
ci / secret-sweep (pull_request) Successful in 5s
ci / vault (pull_request) Successful in 4s
ci / complete (pull_request) Successful in 3s
ci / conformance (pull_request) Successful in 10s
ci / spec-counts (pull_request) Successful in 28s
ci / ratchet (pull_request) Successful in 5s
ci / doc-references (pull_request) Successful in 5s
ci / client (pull_request) Successful in 26s
e32920d13b
`const password = '...'` inside the account helper matched the sweep's
"assigned password" probe, which is the probe doing its job. Hoisted to
a module-level FIXTURE_PASSWORD with the `sweep:allow` annotation the
script documents, the same shape test/relay.mjs already uses.

Sweep clean across 86 files, and the proof still passes 10 of 10.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
extant2000git merged commit 0eeceee4e9 into main 2026-10-14 18:40:29 +00:00
extant2000git deleted branch bridge/one-real-message 2026-10-14 18:40:29 +00:00
Sign in to join this conversation.