Skip to content

Commit 4d95f8c

Browse files
committed
docs(transport): document the TLS trust hook
1 parent fc2eaa4 commit 4d95f8c

2 files changed

Lines changed: 54 additions & 0 deletions

File tree

README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,42 @@ val config = MqttConfig(
332332

333333
Log levels from most to least verbose: `TRACE``DEBUG``INFO``WARN``ERROR``NONE`.
334334

335+
### Custom TLS trust
336+
337+
By default the TCP transport validates the broker certificate against the platform CA store. To
338+
reach a broker behind a private or self-signed CA, pass a TLS customisation lambda to
339+
`TcpTransportFactory`. It runs against ktor's `TLSConfigBuilder`:
340+
341+
```kotlin
342+
import org.meshtastic.mqtt.transport.tcp.TcpTransportFactory
343+
344+
val client = MqttClient("my-client") {
345+
transportFactory = TcpTransportFactory { trustManager = myPrivateCaTrustManager }
346+
}
347+
client.connect(MqttEndpoint.parse("mqtts://broker.internal:8883"))
348+
```
349+
350+
The hook is applied after the SNI server name is resolved and before platform trust is configured.
351+
On Android that ordering matters: your trust manager is *wrapped* by the hostname-aware trust
352+
manager rather than replacing it, so certificate hostname verification still happens.
353+
354+
This scopes the extra trust to the MQTT connection alone. It replaces the app-wide workaround of
355+
adding `<certificates src="user"/>` to `network_security_config.xml`, which would affect every
356+
HTTPS connection the app makes.
357+
358+
The hook composes with transport selection as usual:
359+
360+
```kotlin
361+
transportFactory = TcpTransportFactory { trustManager = myPrivateCaTrustManager } +
362+
WebSocketTransportFactory()
363+
```
364+
365+
`TLSConfigBuilder` comes from `io.ktor:ktor-network-tls`, exposed transitively by
366+
`mqtt-client-transport-tcp` — no extra dependency needed. The WebSocket transport has no equivalent
367+
hook yet. `trustManager` specifically is available on the JVM and Android actuals of
368+
`TLSConfigBuilder`; on Apple, Linux, and Windows targets the hook still runs, but `TLSConfigBuilder`
369+
exposes a different set of properties there.
370+
335371
## Android / KMP Integration
336372

337373
The library is designed as a drop-in MQTT client for KMP projects. Consumer ProGuard/R8 rules are bundled automatically.

transport-tcp/Module.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,23 @@ val client = MqttClient("sensor") {
1212
client.connect(MqttEndpoint.Tcp("broker.example.com", port = 8883, tls = true))
1313
```
1414

15+
### Trusting a private CA
16+
17+
If the broker's certificate is issued by a private or self-signed CA that is not in the platform
18+
trust store, pass a TLS customisation lambda. It receives ktor's `TLSConfigBuilder`:
19+
20+
```kotlin
21+
val client = MqttClient("sensor") {
22+
transportFactory = TcpTransportFactory { trustManager = myTrustManager }
23+
}
24+
```
25+
26+
The lambda is applied after the SNI server name is set and before platform trust configuration, so
27+
on Android a trust manager installed here is still wrapped in the hostname-aware delegate rather
28+
than replacing it. The added trust applies only to this MQTT connection — unlike Android's
29+
app-wide `network_security_config.xml` trust anchors. `trustManager` itself is available on the
30+
JVM and Android actuals of `TLSConfigBuilder`; on Apple, Linux, and Windows the lambda still runs,
31+
but `TLSConfigBuilder` exposes a different set of properties there.
32+
1533
Available on JVM, Android, iOS, macOS, Linux, and Windows. Not available on the browser (wasmJs) —
1634
use `mqtt-client-transport-ws` there.

0 commit comments

Comments
 (0)