feat(protocol): add bounded DTLS endpoint probing - #25
Conversation
365a0f0 to
73dec53
Compare
73dec53 to
f014b06
Compare
|
Adversarial follow-up complete for exact head Validation: 101 passed on Python 3.14 / OpenSSL 3.6.3; 53 focused probe/endpoint/bridge tests passed; the system LibreSSL baseline is 99 passed with the 2 setup-certificate failures isolated to #22; build/import, Ruff, diff, and introduced-content safety checks passed. @codex review |
f014b06 to
dd453eb
Compare
Summary
This addresses the endpoint-discovery portion of #16 and #20. It deliberately does not claim that either report's authentication/setup path is solved.
Context
I now have several Samsung appliances working locally with code I have maintained in-house, including two Bespoke AI Laundry Combo units. I would like to contribute the reusable, sanitized lessons upstream as small, independently tested contracts. This PR is the endpoint/probe contract; authentication providers, PSK transport, and reviewed setup policy remain separate follow-ups.
Why these two reports matter
Issue #16 is the exact WD53 profile I tested
Issue #16 reports
WD53DBA900HZwith primary software20260416.215549. My two units identify as the full SKUWD53DBA900HZA1, familyAWM-US-M64-24-WD80, with the same software version and the same protocol behavior:unknown_ca;2and0xFF02are advertised; andThat makes #16 the same appliance/software profile for this library's purposes. This PR fixes the immediate fixed-port/IPv4-only discovery assumptions, but not its authentication boundary.
Issue #20 is related evidence on different hardware
Issue #20 reports a
WW11BB534DAWS6washer andDV90BB5245AWS6dryer. The washer evidence shows:owned:falseandisop:false;0xFF02; andhandshake_failurewhen the existing certificate path is attempted.That makes this PR's 5684-plus-dynamic-range discovery and explicit alert classification directly useful. It does not prove that the WD53 authorization profile applies: the TLS alert differs, the model-specific proof/timing/security payloads have not been validated, and the dryer has not supplied equivalent protocol evidence.
How the WD53 appliances were actually connected
The complete sanitized record is in docs/ocf-pki-laundry.md. The important sequence was:
Discover public OCF first.
GET /oic/reson UDP 5683 exposed a 72-href directory and the current secure endpoint. The secure endpoint can move after sleep/restart, so it must be rediscovered rather than fixed to one 4915x port.Classify AC14K_M failure correctly. RSA and ECDSA AC14K_M client chains both reached the server and were rejected with fatal
unknown_ca. Re-signing only the leaf, adding ciphers, or disabling verification cannot turn an untrusted authentication profile into authorization.Read public DOXM/PSTAT state. The units advertised OTM
2(oic.sec.doxm.mfgcert) and0xFF02(x.org.iotivity.conmfgcert), a per-read rotating four-byte nonce represented as eight hex characters, and additional-authorization-required state.Open the manufacturer window through the model's authorized path. During one-time idle research, the signed-in SmartThings Android path invoked the same-account transition. The installed
5.0.47stack checked the proofs in the appliance's order, which is the inverse of a newer helper's method naming:TriggerSerialHashRequest:SHA256(serial_hash_ascii || nonce_raw)with no account value;TriggerAutoResetHashRequest:SHA256(serial_hash_ascii || SHA256(user_id_ascii) || fresh_nonce_raw)using the raw inner digest and the ten-character same-account user ID.serial_hash_asciiis the 128-character lowercase hex SHA-512 digest of the ASCII registration serial. There are no delimiters. Only a fresh public DOXM/PSTAT read—not the missed application callback—was treated as proof that the unit entered manufacturer RFOTM.Use the correct manufacturer carrier. Inside that confirmed window, server-authenticated manufacturer DTLS succeeded with exactly
ECDHE-ECDSA-AES128-GCM-SHA256and no AC14K_M, TEST, or OneApp client identity leaf.Derive the per-appliance OwnerPSK exactly. IoTivity first expands the 48-byte master secret with TLS 1.2 SHA-256 P_hash using
key expansion || server_random || client_randomto the GCM suite's 120-byte key block. It then expands that key block with the selected method label, raw 16-byte owner UUID, and raw 16-byte appliance UUID to a 16-byte OwnerPSK.Stage, prove, then finalize. The credential was staged before security mutation, the reviewed CRED/ACL/DOXM/PSTAT transaction was applied, and a fresh ECDHE-PSK session had to prove the candidate before publication/finalization. The resulting runtime path returned 39 complete protected representations per unit. Low-risk setting/power changes had exact protected readback and were restored; the same changes remained visible in SmartThings for the tested transaction.
This was an explicit OCF ownership-changing setup operation, not a harmless discovery trick. SmartThings pairing survived on the two tested units, but the signed request authority and private account value are not public onboarding inputs. This PR contains no OTM implementation, credentials, security-resource writes, reset/takeover behavior, hardware I/O, or captured identifiers. Runtime after setup was LAN OwnerPSK only; Android was not a startup, polling, command, wake, or recovery dependency.
Probe contract
The production probe now:
ambiguousif multiple listeners answer unless a previously proven/configured port is explicitly preferred; andThe old
probe()result shape remains as a compatibility adapter. Stateful handshake research now has the explicitdiagnose_dtls_handshake()name and CLI--diagnosticopt-in; discovery and reconnect never feed the cookie response back to OpenSSL or send a cookie-bearing second ClientHello.Stack and scope
This branch is one commit on top of the small prerequisite branches:
Once #23 and #24 land, rebasing leaves only the single bounded-probe commit. The CI/package and LibreSSL fixes from #21 and #22 are now in upstream
main.Not included here: authenticated endpoint validation, certificate-provider abstraction, PSK sessions, Samsung server-profile verification, OCF security payload codecs, OwnerPSK code, or any automatic ownership decision.
Validation
PATH="/opt/homebrew/opt/openssl@3/bin:$PATH" python -m pytest -q— 116 passedF,I, andEchecks for the new probe/tests — passedgit diff --check— passedAll network fixtures are synthetic or documentation-reserved; no appliance, household, account, credential, UUID, address, packet capture, or raw exception data is included.