Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,31 @@ sess.subscribe(["operational", "state", "vs", "0"], # OBSERVE
sess.close()
```

`connect()` uses a 12-second monotonic DTLS handshake deadline by default. A
caller that needs a shorter bounded attempt can pass a positive finite value
without changing later reader timeouts:

```python
sess.connect(timeout=4.0)
```

Connection attempts can also observe a `threading.Event` without changing the
normal two-second DTLS retry cadence:

```python
import threading

cancel_connect = threading.Event()
# A lifecycle or shutdown thread may call cancel_connect.set().
sess.connect(timeout=8.0, cancel=cancel_connect)
```

Setting the event stops that connection attempt and closes its temporary UDP
socket. `quiesce_for_close()` stops new session work, interrupts an in-progress
connection, and wakes requests waiting for responses while retaining an
established socket for `close()`. `abort()` additionally closes established
local I/O immediately. Interrupted operations raise `SessionClosedError`.

If the cert/key are minted at runtime and never written to disk (e.g. inside
an HA config flow), create the provider from memory instead:

Expand All @@ -56,6 +81,47 @@ auth = CertificateAuth.from_memory(cert_pem, key_pem)
sess = DtlsCoapSession("192.0.2.100", 49154, auth=auth)
```

Some newer OCF-PKI home appliances require an exact Samsung DTLS offer and
present a hardware certificate whose subject contains the appliance's OCF
UUID. When the caller already has an authorized client certificate and a
previously verified appliance UUID, opt in to both requirements explicitly:

```python
from smartthings_local.protocol.auth import (
CertificateAuth,
SamsungServerProfile,
)

server_profile = SamsungServerProfile.bound_device(
expected_device_uuid,
additional_ca_pem=additional_samsung_ca_pem,
)
auth = CertificateAuth.from_memory(
cert_pem,
key_pem,
server_profile=server_profile,
)
sess = DtlsCoapSession("192.0.2.100", 49154, auth=auth)
```

The profile limits the ClientHello to P-256,
`ECDHE-ECDSA-AES128-GCM-SHA256`, and the observed SHA-256/SHA-1 RSA/ECDSA
signature set, disables session tickets, preserves certificate-chain
verification, and requires the exact subject role
`C=KR, O=Samsung Electronics, OU=OCF HA Device` with a common name ending in
the expected UUID. `additional_ca_pem` is optional and accepts only a bounded
PEM CA-certificate chain; it is applied only to this profiled context. Without
a profile, `CertificateAuth` retains its existing verification behavior.

This API deliberately does not discover, mint, authorize, provision, rotate,
or persist credentials, and it performs no ownership transfer or OCF security
resource writes. In particular, an unowned vendor-OTM appliance such as the
one discussed in [issue #20](https://github.com/QuiteYellow/SmartThings-Local/issues/20)
does not become connectable merely by selecting this profile. The already-owned
new-PKI case in [issue #16](https://github.com/QuiteYellow/SmartThings-Local/issues/16)
still requires an authorized client identity before this connection profile
can be used.

For compatibility, the existing `cert_path` / `key_path` and `cert_pem` /
`key_pem` session arguments remain supported without a deprecation warning.
They are routed through `CertificateAuth` internally. Do not combine `auth`
Expand Down
Loading