docs(readme): document SHA-1 crypto-policy handling + list dtls_probe

- Note the Fedora/RHEL SHA-1 crypto-policy block in Part 2 and how
  setup_cert.py auto-retries / the manual update-crypto-policies remedy.
- Add dtls_probe.py to the repo-layout tree (it was referenced in three
  places but missing from the file listing).
- Drop the .venv/ prefix from the Part 1 probe command so it runs against
  the pip-installed package before the Part 4 venv exists.
- Expand the tests parenthetical to name the probe, port-resolution, and
  cert-signing suites.
This commit is contained in:
Jack Nagy
2026-08-01 12:05:57 +01:00
parent a494e73e89
commit e5bd9456d4
+5 -2
View File
@@ -88,7 +88,7 @@ nmap's `open|filtered` can't tell a real DTLS server from a silent UDP port. Con
```sh
# Stateless liveness check: one ClientHello round trip, leaves no state on the device
.venv/bin/python -m smartthings_local.protocol.dtls_probe "$APPLIANCE_IP" 49153 49154 49155 49156 --stateless
python -m smartthings_local.protocol.dtls_probe "$APPLIANCE_IP" 49153 49154 49155 49156 --stateless
```
`live` means a DTLS server answered its `HelloVerifyRequest` (that's your control port); `dead` means silent / not DTLS. Once you have the client cert (Part 2), drop `--stateless` to run the default *diagnostic* drive, which reports `completed` (cert accepted) or `rejected` with the server's fatal alert. An `unsupported_certificate` / `unknown_ca` alert is the signature of a newer OCF-PKI device that won't accept the AC14K_M cert. The same probe gates the bridge's own reconnect loop and auto-discovers the port when `OCF_PORT` is unset.
@@ -171,6 +171,8 @@ Output in `./certs/`: `client_fullchain.pem` + `client.key`.
Neither the UUID nor the AC14K_M bundle is hardcoded in this repo; both are fetched live each run, so the script self-updates if upstream rotates. If either fetch fails, the script prints an inline workaround: supply the UUID via `UUID=<uuid>` env, or supply the AC14K_M bundle via `AC14K_M_CERT_BUNDLE=/path/to/cert.pem`. `BRAYSTORM_URL=<mirror>` points at a different bundle source.
On Fedora/RHEL (and other hardened OpenSSL 3.x builds) the default crypto policy blocks SHA-1 signing, which step 5 needs. The script detects this, retries the signing step once with SHA-1 force-enabled for just that command, and only fails if the retry also fails. If it does, it prints the remedy: `sudo update-crypto-policies --set DEFAULT:SHA1` (undo afterward with `sudo update-crypto-policies --set DEFAULT`).
### How durable is this?
Rotating the published UUID would require Samsung to re-issue TLS certs across their IoT cloud, push new ACLs to every device in the field, and update the on-device daemon identity: a multi-quarter change with a long backwards-compat tail. `AC14K_M` has been public for years and is still in 2026 firmware trust stores. Local access via this path is roughly as durable as cloud control of these appliances.
@@ -400,6 +402,7 @@ smartthings_local/ The installable library — `pip install sm
__init__.py
coap.py CoAP wire protocol: message encode/decode, token handling
dtls_session.py DTLS session: handshake, client-cert auth (file or in-memory PEM), Block2, liveness
dtls_probe.py DTLS ClientHello liveness probe (stateless gate + diagnostic mode)
ocf_root_ca.pem Samsung OCF root CA, bundled for handshake verification
ocf/ OCF resource + state layer (reusable)
__init__.py
@@ -426,7 +429,7 @@ mqtt_demo/ MQTT bridge demo (consumes smartthings_loca
.env.example Template — copy to .env, fill in
setup_cert.py One-shot cert minting script (live-fetches AC14K_M + UUID)
pyproject.toml Packaging — PyPI dist `smartthings-local`, hatch-vcs versioning
tests/ pytest suite (CoAP wire, state cache, import isolation, cert loading)
tests/ pytest suite (CoAP wire, state cache, import isolation, cert loading, DTLS probe, bridge port resolution, cert signing)
.github/workflows/publish.yml Build + PyPI Trusted Publishing on `v*` tags
```