Wiki / Protocols

TLS

The transport security layer under HTTPS, MQTTS and most everything else. On embedded devices it is usually present and usually misconfigured in one of four predictable ways.

The TLS handshake
1 ClientHello (versions, ciphers)
2 ServerHello + Certificate
3 Client validates the certificate
4 Key exchange
5 Encrypted application data
Step 3, server authentication, is the one embedded clients most often skip: encryption without it stops nothing against an active attacker, who simply terminates the connection and presents their own certificate.

TLS provides confidentiality, integrity and server authentication for a byte stream. It is what the S adds to HTTPS, MQTTS and CoAPS. The cryptography itself is sound and rarely the problem; on embedded devices, the failures are almost always in how it is configured and validated.

What the handshake establishes

Client                                    Server
  |-- ClientHello (versions, ciphers) ------->|
  |<------- ServerHello + Certificate --------|
  |   [client validates the certificate]      |
  |-- key exchange ------------------------->|
  |<================ encrypted =============>|

Three separate things happen, and they are worth keeping apart because devices routinely get one right and another wrong:

  1. Key agreement. Both sides derive a shared session key. Modern suites use ephemeral Diffie-Hellman so recording the traffic and later stealing the server key does not decrypt it.
  2. Server authentication. The server presents an X.509 certificate chaining to a CA the client trusts, and proves it holds the matching private key. This is the step that stops a machine-in-the-middle, and it is the step embedded clients skip.
  3. Record protection. Everything after is encrypted and integrity-protected.

Encryption without step 2 is worthless against an active attacker: they terminate your TLS, present their own certificate, and open a second TLS connection onwards. Both legs are properly encrypted, and they read everything.

Certificate validation, in full

A client that validates properly checks all of these. A client that checks some of them is not validating:

  • the chain reaches a trusted root;
  • every signature in the chain verifies;
  • the leaf is not expired and not yet-valid;
  • the hostname matches the certificate's SAN (not just the deprecated CN);
  • the certificate is not revoked, where revocation checking is feasible;
  • intermediate certificates carry the CA basic constraint.

The four failures you actually find

  • Validation disabled. verify=False, CURLOPT_SSL_VERIFYPEER 0, MQTT_SSL_VERIFY_NONE, an esp_http_client_config_t with no cert_pem. Common because it makes a development error disappear, and it ships.
  • Hostname not checked. The chain verifies, so it looks like validation works, but any valid certificate for any name is accepted. Any attacker with a legitimate certificate for a domain they own is now a valid man in the middle.
  • A single private key across the fleet. The certificate and its key are in the firmware. Dump one device and you can impersonate the server, or any device, everywhere. This is endemic in consumer IoT.
  • A trust store frozen in firmware. Roots expire. A device shipped in 2015 with a hardcoded CA bundle either stops connecting or has validation quietly turned off in a later update.

Pinning

Certificate pinning narrows trust from "any CA" to "this specific certificate or public key". It is the right default for a device that only ever talks to one vendor endpoint, because it removes the entire public CA system from the attack surface, including a compromised or coerced CA.

The tradeoff is operational: rotating the pinned key requires a firmware update, and a pin that expires before the fleet updates bricks the connection. Pinning the intermediate CA or the public key rather than the leaf certificate is the usual compromise. For an analyst, pinning is also exactly what stops mitmproxy from working, and unpinning by patching the firmware is a routine step.

Mutual TLS

In mTLS the client also presents a certificate, so the server authenticates the device. It is the strongest option for device-to-cloud and the reason per-device provisioning matters: mTLS with one shared client certificate across the fleet authenticates the model, not the unit.

Pitfalls

  • TLS protects the transport, not the payload or the endpoints. An authenticated update over TLS is still unsafe if the image itself is unsigned.
  • Devices with no reliable clock cannot check certificate validity dates, and firmware often works around it by ignoring them.
  • TLS 1.0 and 1.1 are dead but still appear on long-lived devices. Check the negotiated version, not the marketing.
  • Seeing TLS on the wire tells you nothing about whether the client validates. That has to be tested by presenting a bad certificate and watching whether it connects anyway.

What it pairs with

mitmproxy is how you inspect and break it, wireshark shows the handshake, ota-update depends on it, and hardcoded-secrets covers finding the fleet-wide key in the firmware.

Further reading