DTLS
Algorithm
DTLS (Datagram TLS) reuses TLS cipher suites and handshake transcripts over UDP (or similar datagram transports). Compared to stream TLS it adds:
- Explicit record framing so each datagram can be parsed independently (13-byte record headers in this implementation).
- Epoch and sequence numbers per record so keys can rotate and replays can be rejected within an epoch.
- Handshake fragmentation (DTLS 1.2 style) so large
Certificate/CertificateVerifychains fit under the path MTU. - Retransmission and flight logic at the application or connection layer, because datagrams are not reliably delivered.
NoxTLS implements DTLS-oriented record encoding/decoding, DTLS 1.2 handshake fragment helpers, replay windows, flight retransmit tracking, DTLS 1.3 RFC-core unified-header record seal/open helpers, ACK range handling, and Connection datagram-driver APIs for DTLS 1.3 application data, ACK processing, and retransmit polling. Wire compatibility against external peers should still be validated for your target profile (see TLS).
Purpose
Use these APIs when you integrate noxtls on a datagram transport: build or parse DTLS records, bound handshake reassembly, apply anti-replay checks, size AEAD packets, and tune retransmit / flight timeouts on a Connection configured for TlsVersion::Dtls12 or TlsVersion::Dtls13.
Rust API
- Crate:
noxtls(types and functions are re-exported from the crate root). - Module path (implementation):
noxtls::protocol(seeprotocol/dtls.rsand DTLS fields onConnectioninprotocol/connection.rs).
Record layer (DTLS 1.2 / 1.3 framing)
| Symbol | Role |
|---|---|
DtlsRecordHeader | Parsed or built header: content_type, version ([u8; 2], e.g. DTLS 1.2 0xFEFD, DTLS 1.3 0xFEFC), epoch, sequence (48-bit, must be ≤ (1<<48)-1), length (payload length). |
noxtls_encode_dtls_record_header(header) -> Result<[u8; 13]> | Serializes one header; errors if sequence is out of range. |
noxtls_parse_dtls_record_header(input) -> Result<(DtlsRecordHeader, &[u8])> | Requires at least 13 bytes; rejects unknown RecordContentType. |
noxtls_encode_dtls_record_packet(content_type, version, epoch, sequence, payload) -> Result<Vec<u8>> | header || payload; payload length must fit in u16 (same on-the-wire limit as TLS record length). |
noxtls_parse_dtls_record_packet(input) -> Result<(DtlsRecordHeader, Vec<u8>)> | Parses header then checks body.len() == header.length (mitigates length-desync attacks). |
DTLS 1.2 handshake fragmentation
| Symbol | Role |
|---|---|
DtlsHandshakeFragment | Structured view of one fragment: handshake_type, 24-bit message_len, message_seq, fragment_offset, fragment_len, fragment_body. |
noxtls_encode_dtls12_handshake_fragments(handshake_type, message_seq, body, max_fragment_len) -> Result<Vec<Vec<u8>>> | Splits a full handshake body into ordered fragment records (each 12-byte fragment header + body). max_fragment_len must be > 0; total message length must fit in 24 bits. |
noxtls_parse_dtls12_handshake_fragment(input) -> Result<DtlsHandshakeFragment> | Validates header/body consistency and that offset + len ≤ message_len. |
noxtls_reassemble_dtls12_handshake_fragments(fragments, max_message_len) -> Result<(u8, u16, Vec<u8>)> | Verifies all fragments share type, message_seq, and message_len, allocates message_len bytes, copies ranges, and requires every byte filled (gap/overlap detection via a filled bitmap). max_message_len caps allocation (anti-amplification style bound). |
DTLS 1.3 RFC-core records and ACKs
| Symbol | Role |
|---|---|
Dtls13RecordHeader | RFC-core unified-header view without Connection ID: low epoch bits, 1- or 2-byte sequence number, and explicit payload length. |
noxtls_encode_dtls13_record_header / noxtls_parse_dtls13_record_header | Encode/decode DTLS 1.3 unified headers. CID-bearing headers are rejected with an explicit unsupported error in the RFC-core profile. |
noxtls_seal_dtls13_unified_aes128gcm_record / noxtls_open_dtls13_unified_aes128gcm_record | Seal/open DTLS 1.3 unified-header AES-128-GCM records with replay checks and header AAD. |
Dtls13AckRange, noxtls_encode_dtls13_ack, noxtls_parse_dtls13_ack, noxtls_apply_dtls13_ack_ranges | Encode/decode ACK ranges and apply ACKs to retransmit tracking. |
| Legacy helpers | noxtls_seal_dtls13_aes128gcm_record and noxtls_open_dtls13_aes128gcm_record remain for compatibility with existing 13-byte DTLS-style harnesses; new endpoint code should prefer the unified helpers. |
DTLS 1.3 Connection datagram driver
| Symbol | Role |
|---|---|
process_dtls13_datagram(input, now_ms) | Opens one inbound DTLS 1.3 datagram and emits Dtls13TransportEvent::{Handshake,Ack,Alert,ApplicationData,DatagramIgnored}. |
poll_dtls13(now_ms) | Emits generated ACK packets and due active-flight retransmits. |
write_dtls13_application_data(plaintext, now_ms) | Seals application data after HandshakeState::Finished. |
read_dtls13_application_data(datagram, now_ms) | Processes a datagram and returns only application-data plaintext records. |
Replay and retransmit primitives
| Symbol | Role |
|---|---|
DtlsReplayWindow | 64-sequence sliding bitmap vs latest_sequence (check_and_mark returns false on replay or stale sequences). snapshot / restore_from_snapshot for persistence. |
DtlsEpochReplayTracker | Tracks current and previous epoch windows; check_and_mark(epoch, sequence) accepts replays only in allowed epochs. |
DtlsFlightRetransmitTracker | Stores outbound packets by (epoch, sequence) with bounded history (default cap 256 in Connection), ACK marking, exponential backoff on collect_due_retransmit_packets, and pruning. |
DtlsFlightRecord | One tracked outbound datagram and its retransmit schedule. |
Connection policy (timers)
| Symbol | Role |
|---|---|
DtlsOperationalPolicy | retransmit_initial_timeout_ms, max_retransmit_attempts, active_flight_timeout_ms. Zeros are clamped to 1 when applied. |
DtlsOperationalProfile | Conservative, LanLowLatency, LossyNetwork — preset triples mapped through set_dtls_operational_policy. |
Connection::set_dtls_operational_policy / apply_dtls_operational_profile | Require version.is_dtls() (internal gate is named ensure_dtls12_mode but applies to any DTLS profile; StateError if the connection is stream TLS). active_flight_timeout_ms is also used for DTLS 1.3 active-flight timers. |
Connection::dtls_operational_policy | Returns Some(policy) only when version.is_dtls(); None for stream TLS. |
Feature flags and policy
noxtls-core:feature-dtlsmust be enabled for DTLS profile types in core configs. It is included inprofile-defaultandprofile-tls-server-pki, but not inprofile-minimal-tls-clientorprofile-crypto-only(see Build configuration).feature-dtlsrequiresfeature-tls(enforced at compile time innoxtls-core).noxtls: Enable thenoxtls-coreprofile that includes DTLS if you strip default features; otherwise DTLS-specificTlsVersionpaths may be unavailable.
Examples
use noxtls::{noxtls_encode_dtls_record_packet, noxtls_parse_dtls_record_packet, RecordContentType};
// DTLS 1.2 record version bytes (example only).
let packet = noxtls_encode_dtls_record_packet(
RecordContentType::ApplicationData,
[0xfe, 0xfd],
1,
42,
b"hello",
)
.unwrap();
let (_header, payload) = noxtls_parse_dtls_record_packet(&packet).unwrap();
assert_eq!(payload, b"hello");
See also repository examples/dtls_client.rs and examples/dtls_server.rs for end-to-end usage patterns.
Security and compatibility
- Length checks: Always use
noxtls_parse_dtls_record_packet(or header parse + explicit bound) so advertisedlengthcannot drive unbounded reads off one UDP payload. - Handshake reassembly: Pass a
max_message_lenaligned with your MTU / amplification policy;noxtls_reassemble_dtls12_handshake_fragmentsrejects oversizedmessage_lenand incomplete coverage. - Replay: Use
DtlsEpochReplayTracker(or equivalent) for inbound records per epoch; datagram duplication is common on the public Internet. - Retransmit:
DtlsFlightRetransmitTrackercaps stored flights; tunemax_recordsandmax_retransmit_attemptsso memory and retry storms stay bounded. - AEAD: DTLS 1.3 record helpers assume AES-128-GCM with the 12-byte static IV layout used in the implementation; confirm nonce/AAD rules match your interoperability profile.