1. Today’s topic

Today we examine secure device-to-server communication:

text
TCP
→ TLS handshake
→ server certificate verification
→ optional client certificate
→ encrypted MQTT/HTTPS

The central idea: TLS protects a connection only when the device checks not merely that encryption exists, but server authenticity, hostname, and certificate validity.

2. Why this matters in your projects

LTE carries phase events, fault snapshots, settings, OTA manifests, and control commands. Without correct TLS verification, a device may connect to a fake broker and accept a harmful command. For OTA, a CA/hostname error may enable image substitution or prevent the whole fleet from updating. For STM32 with Ethernet/Wi-Fi/PPP, the architecture is similar:

text
LwIP / NetX Duo
→ Mbed TLS
→ CA store
→ optional mTLS
→ MQTT/HTTPS

3. Theory

7.3.1 3.1. What TLS protects

text
Confidentiality:
  outsiders cannot read the payload.
Integrity:
  a packet cannot be changed unnoticed.
Authentication:
  the client verifies that the server is genuine.

With mTLS, the server also verifies the device certificate.

7.3.2 3.2. Ordinary TLS and mTLS

Ordinary TLS:

text
ESP32 → ClientHello + SNI → Broker
ESP32 ← server certificate chain ← Broker
ESP32 verifies CA, hostname, time

mTLS:

text
the device verifies the server certificate
the server verifies the device client certificate

7.3.3 3.3. Certificate chain

text
Root CA
  └── Intermediate CA
        └── mqtt.example.com

The device usually stores a Root CA or a limited CA set rather than the broker’s leaf certificate.

7.3.4 3.4. CA bundle or a private CA

A CA bundle is convenient for public endpoints but trusts many CAs and consumes Flash. A private CA narrows the trust boundary but requires a protected CA private key and issuance, rotation, and revocation procedures.

7.3.5 3.5. Hostname verification and SNI

CA verification asks:

text
was the certificate signed by a trusted CA?

Hostname verification asks:

text
was the certificate issued specifically for mqtt.example.com?

Do not disable hostname verification in production.

7.3.6 3.6. TLS depends on time

X.509 certificates have Not Before and Not After. Therefore the device needs sufficiently plausible UTC. Bootstrap strategy:

text
1. Load last-known-good UTC from RTC/NVS.
2. Do not reduce it below the last confirmed value.
3. Use EC25 network time only as a hint.
4. Check a reasonable year/range.
5. Establish TLS.
6. Obtain more reliable synchronization.
7. Update last-known-good time.

7.3.7 3.7. Where TLS terminates: ESP32 or EC25

TLS on ESP32 through PPPoS:

text
EC25 → PPP → lwIP → ESP-TLS/Mbed TLS → MQTT/HTTPS

Advantages: one TLS stack, better diagnostics, a single CA store, and less dependence on AT firmware. Disadvantages: ESP32 RAM/CPU use and UART PPP load. TLS inside EC25:

text
ESP32 → AT commands → EC25 TLS/MQTT stack → broker

Advantages: the modem performs TLS computation and uses less ESP32 heap. Disadvantages: more complex certificate management, diagnostics, and rotation, plus dependence on modem firmware.

7.3.8 3.8. Certificate lifecycle

c
typedef enum {
    CERT_STATE_EMPTY = 0,
    CERT_STATE_STAGED,
    CERT_STATE_ACTIVE,
    CERT_STATE_RENEWAL_REQUIRED,
    CERT_STATE_REVOKED,
    CERT_STATE_EXPIRED,
} certificate_state_t;
typedef struct {
    uint32_t generation;
    certificate_state_t state;
    int64_t not_before_utc;
    int64_t not_after_utc;
    uint8_t fingerprint_sha256[32];
    uint32_t connect_success_count;
    uint32_t connect_fail_count;
} certificate_status_t;

7.3.9 3.9. CA rotation

Safe:

text
CA_OLD
→ firmware trusts CA_OLD + CA_NEW
→ the server switches to CA_NEW
→ the fleet confirms connection
→ remove CA_OLD later

Dangerous:

text
the server switched to CA_NEW
→ old devices know only CA_OLD
→ the fleet is offline

7.3.10 3.10. TLS diagnostics

c
typedef enum {
    TLS_STAGE_NONE = 0,
    TLS_STAGE_DNS,
    TLS_STAGE_TCP_CONNECT,
    TLS_STAGE_CLIENT_HELLO,
    TLS_STAGE_CERT_VERIFY,
    TLS_STAGE_CLIENT_AUTH,
    TLS_STAGE_ESTABLISHED,
} tls_stage_t;
typedef struct {
    tls_stage_t last_stage;
    int32_t last_tls_error;
    int32_t last_verify_flags;
    uint32_t handshake_ok;
    uint32_t handshake_failed;
    uint32_t hostname_failed;
    uint32_t time_failed;
    uint32_t client_auth_failed;
    uint32_t max_handshake_ms;
    uint32_t min_free_heap_during_handshake;
    uint32_t certificate_generation;
} tls_diag_t;

4. Common mistakes

text
1. Disabling server verification.
2. Checking CA but disabling hostname.
3. One client certificate for the entire fleet.
4. No time available before TLS.
5. Permanently embedding the server leaf certificate.
6. Switching server CA before device OTA.
7. Storing a private key in Git.
8. Printing PEM/DER in a debug log.
9. Ignoring certificate-buffer lifetime.
10. Confusing TLS termination: ESP32 and EC25 simultaneously.
11. Not measuring peak heap during TLS handshake.

5. Practical assignment for 30-60 minutes

Create TLS_PKI_POLICY.md:

markdown
# TLS / PKI policy
1. All external MQTT and OTA connections use TLS.
2. Server certificate and hostname are always verified.
3. Insecure verification is forbidden in production.
4. Each device has a unique identity.
5. Private keys are never stored in Git or logs.
6. UTC quality is checked before certificate validation.
7. CA rotation uses an old+new overlap window.
8. Client certificate rotation is transactional.
9. TLS errors are classified, not retried blindly.
10. Certificate expiry is monitored before deployment.

Inventory endpoints:

markdown
| Endpoint | Protocol | Authentication | Trust source |
|---|---|---|---|
| mqtt.example.com | MQTT/TLS | mTLS | private CA |
| ota.example.com | HTTPS | server TLS | CA bundle |
| api.example.com | HTTPS | token + TLS | CA bundle |

Add a tls probe CLI that checks DNS/TCP/TLS/hostname/time/heap without sending application secrets.

6. Further reading

  • ESP-TLS, X.509 Certificate Bundle, and ESP-MQTT TLS examples.
  • Quectel EC25 SSL/MQTT/HTTP(S) application notes.
  • STM32 Mbed TLS integration and STSAFE.

Brief recap

text
external endpoint
→ DNS
→ TCP
→ TLS handshake
→ CA chain verification
→ hostname/SNI verification
→ optional client certificate
→ encrypted MQTT/HTTPS
→ monitored certificate lifecycle

Exercise

A server certificate chains to a trusted CA but belongs to a different hostname. State the required connection decision and the diagnostic information that may be logged safely.

Self-check criteria: Keep hostname verification enabled and distinguish authentication failure from TCP or DNS failure.

Show the supplied answer

Reject the connection because CA trust does not establish the intended hostname. Record a bounded verification category, endpoint identity, time quality, and handshake status without logging private keys, PEM/DER material, or application secrets.

Exercise

Plan a CA_OLD to CA_NEW migration for devices that may remain offline during deployment. Define the ordering that preserves an authenticated update path.

Self-check criteria: Describe evidence at each stage and the offline-device recovery path; never solve rotation by disabling verification.

Show the supplied answer

First deploy firmware that trusts both CA_OLD and CA_NEW and verify device adoption. Then switch the server to CA_NEW and monitor connections; remove CA_OLD only later through a controlled policy after accounting for devices that missed the transition.