TLS Lite — WIA-TLS-LITE — Author: Dr. Yeon Sam-heum
Traditional TLS 1.3 (RFC 8446) is engineered to run over TCP, but IoT, LPWAN, and industrial sensor networks cannot afford TCP's connection-keeping cost: a three-way SYN/SYN-ACK/ACK handshake, sliding window state, and FIN-driven teardown. RFC 7228 Class 0 devices (no more than 10 KiB RAM and 100 KiB Flash) routinely exhaust their memory budget on TCP state machines alone. The IETF therefore standardised DTLS (Datagram TLS) on top of UDP, and RFC 9147 brings TLS 1.3's security properties to the datagram setting as DTLS 1.3.1
This chapter covers the second architectural layer of the TLS Lite (WIA-TLS-LITE) standard: DTLS 1.3 over CoAP. CoAP (Constrained Application Protocol, RFC 7252) is the IoT-targeted application-layer protocol that compresses HTTP's REST semantics into UDP. CoAP itself permits a NoSec mode, but RFC 7252 §9 mandates DTLS as the secure mode. In practice, DTLS 1.3 over CoAP is the de-facto secure stack for IoT, and TLS Lite aligns the option matrix so that Class 1 and Class 2 devices can implement it within the octet budget available to them.2
An operator typically arrives at this chapter from one of these scenarios. First, a gateway that bridges LTE-M, NB-IoT, or Wi-Fi 6 to the public Internet, with BLE, LoRa, Thread, or Zigbee sensors hanging beneath it. Second, sensor nodes running on Class 1 microcontrollers such as ESP32-C3, nRF52840, or STM32L4, embedding mbedTLS, wolfSSL, or tinydtls as the cryptographic stack. Third, nodes that emit PUT, POST, or GET requests to cloud-side CoAP resource servers through that gateway, with every byte of traffic sealed under DTLS 1.3.
The critical design decisions in this scenario are (a) key-exchange mode, (b) connection_id length, (c) whether 0-RTT/early_data is permitted, (d) record sequence number compression, (e) HelloRetryRequest avoidance, and (f) the mapping between CoAP message types (CON/NON) and DTLS records. The chapter walks each decision in turn and presents the normative requirements of RFC 9147, 9146, 7252, 8323, and 8613 together with TLS Lite's recommended option matrix across six tables.
TLS 1.3 standardised the 1-RTT handshake, and DTLS 1.3 preserves that target. The datagram setting nevertheless adds machinery to cope with UDP's unordered, lossy delivery: message sequence numbers (MSN), handshake-message fragmentation (fragment_offset and fragment_length), retransmission timers with exponential backoff, and a new ACK record (RFC 9147 §7).3
Table 2-1 summarises the round-trip cost for each key-exchange mode. PSK_KE (pre-shared key only, no ECDHE) is 1-RTT in both TLS 1.3 and DTLS 1.3. PSK_DHE_KE (PSK plus ECDHE forward secrecy) is also 1-RTT but adds ECDHE cost. The 0-RTT/early_data mode is exactly zero round-trip but introduces an anti-replay trade-off.
| Key-exchange mode | TLS 1.3 RTT | DTLS 1.3 RTT | Forward secrecy | Recommended use |
|---|---|---|---|---|
| PSK_KE | 1-RTT | 1-RTT (+ MSN recovery) | No | Factory-provisioned PSK on closed networks |
| PSK_DHE_KE | 1-RTT | 1-RTT (+ ECDHE cost) | Yes | Default recommended for Class 1 and 2 devices |
| DHE_KE (cert) | 1-RTT | 1-RTT (+ X.509 verification) | Yes | Class 2 gateways, cloud-side endpoints |
| 0-RTT/early_data | 0-RTT | 0-RTT | Limited | Idempotent PUT/GET only — anti-replay required |
| RPK (RFC 7250) | 1-RTT | 1-RTT | Yes | When avoiding certificate-chain overhead |
TLS Lite recommends PSK_DHE_KE as the default. The pre-shared key is injected at manufacturing time into a Secure Element (SE) or derived from a PUF (Physically Unclonable Function), and forward secrecy is delivered at runtime by X25519 ECDHE. ECDHE curve selection accepts both P-256 (NIST FIPS 186-5) and X25519 (RFC 7748), but on low-power cores such as ARM Cortex-M0+, X25519's constant-time implementation gives better side-channel immunity at lower code size.
CoAP defines four message types (RFC 7252 §4). Confirmable (CON) requests reliable delivery and demands an ACK or RST in response. Non-confirmable (NON) is fire-and-forget and tolerates loss. Acknowledgement (ACK) is the explicit response to a CON. Reset (RST) signals that the recipient rejects the message.4
When CoAP runs over DTLS 1.3, CoAP's reliability machinery (CON/ACK) and DTLS's record-sequence machinery are orthogonal. Application-layer recovery in CoAP is independent of record-layer recovery in DTLS. In operation, the two timer regimes must nevertheless be coordinated. RFC 7252 §4.8.2 sets CoAP's default ACK_TIMEOUT to 2 s with ACK_RANDOM_FACTOR 1.5 and MAX_RETRANSMIT 4. RFC 9147 §7.7 sets the DTLS 1.3 handshake initial RTO to 1 s with exponential backoff. TLS Lite recommends following both, and additionally requires that CoAP traffic be deferred until the DTLS handshake has completed so the two timers do not interleave on a single node.
| CoAP type | Reliability | DTLS record type | Recommended scenario | Loss behaviour |
|---|---|---|---|---|
| CON | Reliable | application_data (23) | Control commands, firmware update trigger | CoAP ACK_TIMEOUT retransmit |
| NON | Unreliable | application_data (23) | Periodic telemetry, sensor stream | Application layer ignores |
| ACK | Response | application_data (23) | Acknowledging CON (piggyback or separate) | Triggers CON retransmit |
| RST | Rejection | application_data (23) | Unknown token, malformed Observe | Sender correction |
IoT devices are frequently reassigned an IP address and port behind NAT: LTE-M devices return from sleep mode, NB-IoT devices exit PSM (Power Saving Mode), and Wi-Fi devices renew DHCP. Each event mutates the device's external 4-tuple. Classical DTLS identified sessions by the (src_ip, src_port, dst_ip, dst_port) 4-tuple, so any change in that tuple forced a handshake from scratch. RFC 9146 connection_id (CID) solves this problem.5
A CID is a variable-length identifier of 0–255 octets, negotiated bidirectionally during the handshake and carried in every subsequent application_data record header. Receivers look up the session by CID, so the session survives a 4-tuple change. TLS Lite recommends 4 octets for Class 1 devices (64-bit collision resistance security margin) and 8 octets for Class 2 gateways.
| CID length (octets) | Collision resistance | Header overhead | NAT rebinding | Recommended class |
|---|---|---|---|---|
| 0 (CID disabled) | N/A | 0 octets | Not supported (4-tuple) | Closed-network Class 0 only |
| 2 | 16 bits (weak) | +2 octets | Possible, collision risk | Class 0 experimental |
| 4 | 32 bits | +4 octets | Possible, generally safe | Class 1 recommended |
| 8 | 64 bits | +8 octets | Possible, collision-safe | Class 2 gateway recommended |
| 16 | 128 bits | +16 octets | Possible, overkill | Large cloud endpoints |
The most octet-budget-relevant addition in DTLS 1.3 is record sequence number (SN) compression. DTLS 1.2 transmitted the 64-bit SN in plaintext, whereas DTLS 1.3 §4.2.2 masks the SN with the record-protection key and compresses it to 8 or 16 bits. A 16-bit SN allows 65,536 records per epoch, so a device emitting 17 telemetry messages per hour exhausts an epoch after roughly 4,096 hours (170 days), aligned with typical firmware-update cycles.6
SN compression delivers two benefits. First, the record header shrinks from 13 octets to 5–7 octets. Second, SN masking complicates traffic analysis. TLS Lite recommends an 8-bit SN for Class 1 devices (256 records per epoch, mandating short epoch rotation) and a 16-bit SN for Class 2 devices by default.
RFC 9147 §4 defines two record-header forms: the unified header (1-octet type field) and the ciphertext header (carrying epoch, SN, and CID). The unified header's type octet encodes, bit-by-bit: bits 7–5 = 001 (fixed prefix), bit 4 = CID present, bit 3 = SN length (0 = 8-bit, 1 = 16-bit), bit 2 = length field present, bits 1–0 = epoch low 2 bits.
This 1-octet type encoding is the central octet-saving mechanism in RFC 9147 §4.1. Transmitting a 16-octet payload (a CoAP GET response with a single option) under classical DTLS 1.2 costs 13 (header) + 16 (payload) + 16 (AEAD tag) = 45 octets. Under DTLS 1.3 with the short header, the same payload costs 7 (header) + 16 (payload) + 16 (AEAD tag) = 39 octets — a 13% reduction. Given that LoRaWAN SF12 (spreading factor 12) caps a single frame payload at 51 octets, this 13% determines whether the response fits a single airtime slot.
// DTLS 1.3 unified header — pseudo-code (RFC 9147 §4.1)
struct DtlsCiphertext {
uint8_t type; // 1 octet: 001 C S L E E (bit field)
// C = CID present (1 bit)
// S = SN length (0=8bit, 1=16bit)
// L = length present (1 bit)
// E = epoch low 2 bits
opaque connection_id[CID_LEN]; // optional (when C=1)
uint8_t sequence_number[1 or 2]; // 1 or 2 octets per S
uint16_t length; // optional (when L=1)
opaque encrypted_record[length]; // AEAD-protected payload + tag
};
// Minimum header: 1 (type) + 1 (SN) = 2 octets
// Maximum header: 1 + 8 (CID) + 2 (SN) + 2 (length) = 13 octets
DTLS 1.3 supports 0-RTT in the same shape as TLS 1.3. The client uses a PSK from a previous session (or from a fresh NewSessionTicket) to send application_data alongside the ClientHello in the early_data extension. The absolute appeal is zero round-trips. The trade-off is that anti-replay guarantees weaken.7
RFC 8446 §8 and RFC 9147 §7.1 recommend two anti-replay mechanisms for 0-RTT traffic. (a) Single-use tokens: the NewSessionTicket's ticket_age_add carves an acceptance window, and early_data outside this window is rejected. (b) Idempotent operations only: 0-RTT carries GET and idempotent PUT, while POST and non-idempotent PUT are rejected. TLS Lite permits 0-RTT for IoT scenarios only on GET (telemetry polling) and idempotent PUT (state toggles).
| Scenario | 0-RTT permitted | Replay risk | Mitigation | Recommended rating |
|---|---|---|---|---|
| GET polling (sensor read) | Yes | Low (idempotent) | ticket_age_add window ±10 s | OK |
| Idempotent PUT (switch ON/OFF) | Conditional | Medium | nonce + single-use token | Caution |
| POST (event log) | No | High (duplicate record) | 1-RTT required | Forbidden |
| Firmware update trigger | No | Very high | 1-RTT + signed payload | Forbidden |
| Credential issue/renewal | No | Critical | 1-RTT + nonce | Forbidden |
The attack vectors commonly cited against DTLS 1.3 over CoAP fall into five categories: replay, downgrade, DoS amplification, KRACK-style nonce reuse, and side-channel leakage. Each can be mitigated either intrinsically in DTLS 1.3 or by operational option choice.
Replay attacks resend ciphertext records to repeat the underlying action. The first line of defence is the anti-replay window in DTLS 1.3 §4.5.1 (default 64, recommended 128), and the second line is the AEAD per-record nonce. Downgrade attacks coerce a weaker cipher_suite during the handshake; RFC 8446 §4.1.3's random downgrade sentinel (the server marks ServerHello.random's last 8 bytes with a fixed pattern when delivering TLS 1.3) detects the attempt. DoS amplification spoofs the source IP in ClientHello to make the server emit a large ServerHello/Certificate; HelloRetryRequest with a cookie (RFC 9147 §5.1) is the primary mitigation.
| Attack vector | RFC reference | Primary mitigation | Secondary mitigation | Class 0 feasibility |
|---|---|---|---|---|
| Replay (record resend) | RFC 9147 §4.5.1 | Anti-replay window (64+) | AEAD per-record nonce | Feasible |
| Downgrade (cipher weakening) | RFC 8446 §4.1.3 | Random downgrade sentinel | SignatureScheme whitelist | Feasible |
| DoS amplification (spoofed Hello) | RFC 9147 §5.1 | HelloRetryRequest cookie | Rate limit per CID/IP | Limited |
| KRACK nonce reuse | RFC 8446 §5.3 | Per-record nonce uniqueness | Mandatory epoch rotation | Feasible |
| Side-channel (timing/power) | NIST SP 800-90B | Constant-time ECDHE | X25519 recommended | Limited |
HelloRetryRequest (HRR) is the server's reply when the client failed to guess the server's preferred curve and key_share. HRR turns a 1-RTT handshake into 2-RTT. In IoT scenarios where wake/sleep duty cycles are tight, frequent HRR is expensive. TLS Lite recommends two avoidance strategies. First, the client offers key_share for every curve the server is likely to accept (X25519 and P-256 simultaneously). Second, the server pre-announces its preferred curve through the client cache (a KEM hint inside the NewSessionTicket).8
Empirically, an mbedTLS 3.5 client on ESP32-C3 that offers X25519 and P-256 key_shares concurrently sees a 0% HRR rate, while offering only X25519 to a server that mandates P-256 causes 100% HRR, and matching X25519 on both ends yields 0% HRR. These figures are captured in §B.7 of the TLS Lite conformance suite.
| Option | Class 0 (≤10K RAM) | Class 1 (≤50K RAM) | Class 2 (≤250K RAM) | Rationale |
|---|---|---|---|---|
| Key exchange | PSK_KE | PSK_DHE_KE (X25519) | PSK_DHE_KE + cert | RAM/Flash budget |
| cipher_suite | TLS_AES_128_CCM_8_SHA256 | TLS_AES_128_GCM_SHA256 | TLS_AES_128_GCM_SHA256 or TLS_CHACHA20_POLY1305_SHA256 | AEAD standard |
| connection_id | Disabled (closed network) | 4 octets | 8 octets | NAT rebinding |
| SN compression | 8-bit | 16-bit | 16-bit | Octet budget |
| 0-RTT | Disabled | Idempotent only | Idempotent only + replay window | RFC 8446 §8 |
| OSCORE binding | Optional | Recommended (app-layer defence) | Recommended + DTLS endpoint | RFC 8613 |
| Authentication | PSK only | PSK + RPK | PSK + RPK + X.509 | Key management cost |
| Epoch rotation | Daily | Hourly | Per request | Nonce-collision avoidance |
Every option combination discussed in this chapter is demonstrable in the reference simulator. Opening Simulator Panel 1 (DTLS handshake trace) visualises every record from the moment the client sends ClientHello with TLS_AES_128_GCM_SHA256 and X25519 key_share until the server Finished. Panel 0 (procedure overview) walks the operator checklist step by step, and Panel 2 (CoAP CON/ACK pairing) visualises the CoAP request flow.
// CoAP GET over DTLS 1.3 — record sequence
// Client → Server
DTLS_record(type=app_data, epoch=2, SN=0x0001, CID=0xAB12CD34):
encrypted(
CoAP {
ver=01, type=0 (CON), token_len=2, code=0.01 (GET),
message_id=0x1234, token=0x5678,
options: [Uri-Path: "sensor"; Accept: 60 (cbor)],
payload:
}
) || AEAD_tag(16)
// Server → Client (piggyback ACK)
DTLS_record(type=app_data, epoch=2, SN=0x0001, CID=0xEF56AB78):
encrypted(
CoAP {
ver=01, type=2 (ACK), token_len=2, code=2.05 (Content),
message_id=0x1234, token=0x5678,
options: [Content-Format: 60 (cbor)],
payload: CBOR(temperature=22.5, humidity=45)
}
) || AEAD_tag(16)
The Korean edition of this chapter (chapter-02.html under /ebook/ko/) carries an additional section, Korean IoT and CoAP infrastructure alignment, that maps RFC 7252 and RFC 9147 onto Korea-specific frameworks: the Information and Communications Network Act (정보통신망법) Article 45-2, the KISA IoT Security Certification Programme, TTA standard TTAK.OT-12.0148/R1, the KCMVP cryptographic-module validation regime, KS X ISO/IEC 29167-19, ETRI reference implementations, the NIPA Smart City Integrated Platform v2.0, and operational profiles on the SK Telecom, KT, and LG U+ LTE-M and NB-IoT networks. International readers can skip this section without losing the normative argument, since the recommendations in Tables 2-1 through 2-6 are presented in jurisdiction-neutral form throughout the rest of the chapter.
The DTLS 1.3 over CoAP layer is the operational bridge between TLS Lite Phase 1 (envelope) and Phase 3 (federation handshake). When an operator adopts the recommended option matrix in this chapter, the same device can reuse the credential store of WIA-OMNI-API, the runtime trust list of WIA-AIR-SHIELD, and the workload intent declaration of WIA-INTENT without a second handshake. The TLS Lite design lets one operator federate across many standards with one signing-key chain and one audit transport because IoT-class memory and power budgets cannot tolerate per-standard re-implementation.
The conformance suite for this chapter is specified in §B.2 through §B.7 of https://github.com/WIA-Official/wia-tls-lite-conformance. The suite automatically verifies that the operator's firmware satisfies every recommended option in Tables 2-1 through 2-6. Firmware that clears the suite earns the WIA Standards Conformance Mark (WIA-CM).