ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
dtls_record.h File Reference

DTLS 1.3 record layer (RFC 9147 §4). More...

#include "protocore_config.h"

Go to the source code of this file.

Classes

struct  DtlsRecordKeys
 One direction's record-protection keys for one epoch (RFC 9147 §4). More...
 
struct  DtlsPlaintext
 Parsed view of a DTLSPlaintext record (fields point into the caller's buffer). More...
 
struct  DtlsCiphertext
 Result of a successful protocore_dtls_ciphertext_unprotect. More...
 
struct  DtlsReplayWindow
 64-record sliding replay window over the highest sequence number accepted in an epoch. More...
 
struct  DtlsRecordNs
 Dispatch table. Addressed by offset, so the layout is asserted below. More...
 

Macros

#define PROTOCORE_DTLS_LEGACY_VERSION   0xFEFD
 DTLSPlaintext legacy_version on the wire: DTLS 1.2 (RFC 9147 §4).
 
#define PROTOCORE_DTLS_PLAINTEXT_HDR_LEN   13
 DTLSPlaintext header length: type(1) + version(2) + epoch(2) + seq(6) + length(2).
 
#define PROTOCORE_DTLS_TAG_LEN   16
 AEAD tag length (all supported suites: 16 bytes).
 
#define PROTOCORE_DTLS_CID_MAX   8
 Largest connection id carried in a DTLSCiphertext header (RFC 9146 / RFC 9147 §9). The CID is not length-prefixed on the wire, so the receiver must know its length from negotiation; 8 bytes is ample routing entropy and bounds the fixed header-scratch buffers.
 
Record content types (RFC 8446 §5 / RFC 9147 §4).

Shared by the DTLSPlaintext type field and the DTLSInnerPlaintext trailing content type.

#define PROTOCORE_DTLS_CT_CHANGE_CIPHER_SPEC   20
 
#define PROTOCORE_DTLS_CT_ALERT   21
 
#define PROTOCORE_DTLS_CT_HANDSHAKE   22
 
#define PROTOCORE_DTLS_CT_APPLICATION_DATA   23
 
#define PROTOCORE_DTLS_CT_ACK   26
 DTLS 1.3 acknowledgement (RFC 9147 §7)
 

Typedefs

typedef enum PROTO_ENUM_PACKED DtlsCipher
 Record-layer AEAD suites (phase 1: AEAD_AES_128_GCM with SHA-256).
 

Enumerations

enum  PROTO_ENUM_PACKED { DTLS_CIPHER_AES_128_GCM_SHA256 = 0 }
 Record-layer AEAD suites (phase 1: AEAD_AES_128_GCM with SHA-256). More...
 

Functions

 PROTOCORE_NS_LAYOUT (DtlsRecordNs, keys_derive, plaintext_build, plaintext_parse, protect, unprotect, replay_init, replay_check, replay_mark)
 
void protocore_dtls_record_keys_derive (uint8_t *work, DtlsRecordKeys *out, DtlsCipher cipher, uint16_t epoch, const uint8_t *secret)
 Derive one direction's record keys from a 32-byte TLS 1.3 traffic .
 
size_t protocore_dtls_record_plaintext_build (uint8_t *work, uint8_t content_type, uint16_t epoch, uint64_t seq, const uint8_t *fragment, size_t frag_len, uint8_t *out, size_t out_cap)
 A DTLSPlaintext record; bytes written (13 + frag_len), or 0 on .
 
size_t protocore_dtls_record_plaintext_parse (uint8_t *work, const uint8_t *rec, size_t rec_len, DtlsPlaintext *out)
 The same record back, validating legacy_version and the length .
 
size_t protocore_dtls_record_protect (uint8_t *work, DtlsRecordKeys *keys, uint64_t seq, uint8_t content_type, const uint8_t *plaintext, size_t pt_len, uint8_t *out, size_t out_cap, const uint8_t *cid, size_t cid_len)
 Seal one record (RFC 9147 sec 4.2): the unified header, the .
 
proto_bool protocore_dtls_record_unprotect (uint8_t *work, DtlsRecordKeys *keys, uint64_t next_seq, const uint8_t *rec, size_t rec_len, uint8_t *out, size_t out_cap, DtlsCiphertext *info, const uint8_t *expected_cid, size_t expected_cid_len)
 Open one received record: decrypt the sequence number, rebuild the .
 
void protocore_dtls_record_replay_init (uint8_t *work, DtlsReplayWindow *w)
 Reset a replay window to empty.
 
proto_bool protocore_dtls_record_replay_check (uint8_t *work, const DtlsReplayWindow *w, uint64_t seq)
 Whether seq is new and inside the window, rather than a replay or .
 
void protocore_dtls_record_replay_mark (uint8_t *work, DtlsReplayWindow *w, uint64_t seq)
 Record seq as accepted and advance the window; only after a .
 

Variables

PROTOCORE_NS DtlsRecordNs DtlsRecord PROTOCORE_UNUSED
 Module namespace.
 

Detailed Description

DTLS 1.3 record layer (RFC 9147 §4).

The datagram counterpart to the TLS 1.3 record layer: it protects and unprotects individual UDP-carried records. This is the transport-specific half of DTLS 1.3; the handshake it carries reuses the TLS 1.3 crypto that already backs HTTP/3 (protocore_tls13_*, protocore_hkdf, aes128gcm).

Two record shapes (RFC 9147 §4):

  • DTLSPlaintext - the classic 13-byte header (type, legacy_version, epoch, 48-bit sequence number, length, fragment). Used unencrypted for the first handshake flight and for alerts sent in epoch 0.
  • DTLSCiphertext - the compact "unified header" plus an AEAD-sealed body, used once record keys exist. The record's sequence number is itself encrypted (RFC 9147 §4.2.3), and the AEAD nonce is the TLS 1.3 construction over the full 64-bit sequence number (§4.2.2, epoch excluded).

─ Reuse ─ AEAD (AEAD_AES_128_GCM) and the AES-128 block used for sequence-number encryption come from aes128gcm; key/iv/sn derivation from protocore_hkdf (HKDF-Expand-Label). Phase 1 supports the one cipher suite the whole hand-rolled TLS 1.3 stack uses: TLS_AES_128_GCM_SHA256.

Pure, zero heap, host-tested. Not the mbedTLS TCP-TLS engine (network_drivers/tls) - this is the self-contained datagram record layer.

work is bytes the CALLER holds. This module reads none of them: it carries nothing between calls, so there is no state to keep and nothing to wipe. The parameter is there so a caller drives every namespace the same way.

Author
Douglas Quigg (dstroy0)
Date
2026

Definition in file dtls_record.h.

Macro Definition Documentation

◆ PROTOCORE_DTLS_CT_CHANGE_CIPHER_SPEC

#define PROTOCORE_DTLS_CT_CHANGE_CIPHER_SPEC   20

Definition at line 50 of file dtls_record.h.

◆ PROTOCORE_DTLS_CT_ALERT

#define PROTOCORE_DTLS_CT_ALERT   21

Definition at line 51 of file dtls_record.h.

◆ PROTOCORE_DTLS_CT_HANDSHAKE

#define PROTOCORE_DTLS_CT_HANDSHAKE   22

Definition at line 52 of file dtls_record.h.

◆ PROTOCORE_DTLS_CT_APPLICATION_DATA

#define PROTOCORE_DTLS_CT_APPLICATION_DATA   23

Definition at line 53 of file dtls_record.h.

◆ PROTOCORE_DTLS_CT_ACK

#define PROTOCORE_DTLS_CT_ACK   26

DTLS 1.3 acknowledgement (RFC 9147 §7)

Definition at line 54 of file dtls_record.h.

◆ PROTOCORE_DTLS_LEGACY_VERSION

#define PROTOCORE_DTLS_LEGACY_VERSION   0xFEFD

DTLSPlaintext legacy_version on the wire: DTLS 1.2 (RFC 9147 §4).

Definition at line 58 of file dtls_record.h.

◆ PROTOCORE_DTLS_PLAINTEXT_HDR_LEN

#define PROTOCORE_DTLS_PLAINTEXT_HDR_LEN   13

DTLSPlaintext header length: type(1) + version(2) + epoch(2) + seq(6) + length(2).

Definition at line 61 of file dtls_record.h.

◆ PROTOCORE_DTLS_TAG_LEN

#define PROTOCORE_DTLS_TAG_LEN   16

AEAD tag length (all supported suites: 16 bytes).

Definition at line 64 of file dtls_record.h.

◆ PROTOCORE_DTLS_CID_MAX

#define PROTOCORE_DTLS_CID_MAX   8

Largest connection id carried in a DTLSCiphertext header (RFC 9146 / RFC 9147 §9). The CID is not length-prefixed on the wire, so the receiver must know its length from negotiation; 8 bytes is ample routing entropy and bounds the fixed header-scratch buffers.

Definition at line 69 of file dtls_record.h.

Typedef Documentation

◆ DtlsCipher

Record-layer AEAD suites (phase 1: AEAD_AES_128_GCM with SHA-256).

Enumeration Type Documentation

◆ PROTO_ENUM_PACKED

Record-layer AEAD suites (phase 1: AEAD_AES_128_GCM with SHA-256).

Enumerator
DTLS_CIPHER_AES_128_GCM_SHA256 

Definition at line 72 of file dtls_record.h.

Function Documentation

◆ PROTOCORE_NS_LAYOUT()

PROTOCORE_NS_LAYOUT ( DtlsRecordNs  ,
keys_derive  ,
plaintext_build  ,
plaintext_parse  ,
protect  ,
unprotect  ,
replay_init  ,
replay_check  ,
replay_mark   
)

◆ protocore_dtls_record_keys_derive()

void protocore_dtls_record_keys_derive ( uint8_t *  work,
DtlsRecordKeys *  out,
DtlsCipher  cipher,
uint16_t  epoch,
const uint8_t *  secret 
)

Derive one direction's record keys from a 32-byte TLS 1.3 traffic .

Parameters
workPROTOCORE_DTLS_RECORD_BORROW bytes the caller took. Not held past the call.
outOut
cipherCipher
epochEpoch
secret32 bytes

◆ protocore_dtls_record_plaintext_build()

size_t protocore_dtls_record_plaintext_build ( uint8_t *  work,
uint8_t  content_type,
uint16_t  epoch,
uint64_t  seq,
const uint8_t *  fragment,
size_t  frag_len,
uint8_t *  out,
size_t  out_cap 
)

A DTLSPlaintext record; bytes written (13 + frag_len), or 0 on .

Parameters
workPROTOCORE_DTLS_RECORD_BORROW bytes the caller took. Not held past the call.
content_typeContent type
epochEpoch
seqSeq
fragmentFragment
frag_lenFrag len
outOut
out_capOut cap
Returns
The size_t.

◆ protocore_dtls_record_plaintext_parse()

size_t protocore_dtls_record_plaintext_parse ( uint8_t *  work,
const uint8_t *  rec,
size_t  rec_len,
DtlsPlaintext *  out 
)

The same record back, validating legacy_version and the length .

Parameters
workPROTOCORE_DTLS_RECORD_BORROW bytes the caller took. Not held past the call.
recRec
rec_lenRec len
outOut
Returns
The size_t.

◆ protocore_dtls_record_protect()

size_t protocore_dtls_record_protect ( uint8_t *  work,
DtlsRecordKeys *  keys,
uint64_t  seq,
uint8_t  content_type,
const uint8_t *  plaintext,
size_t  pt_len,
uint8_t *  out,
size_t  out_cap,
const uint8_t *  cid,
size_t  cid_len 
)

Seal one record (RFC 9147 sec 4.2): the unified header, the .

Parameters
workPROTOCORE_DTLS_RECORD_BORROW bytes the caller took. Not held past the call.
keysKeys
seqSeq
content_typeContent type
plaintextPlaintext
pt_lenPt len
outOut
out_capOut cap
cidCid
cid_lenCid len
Returns
The size_t.

◆ protocore_dtls_record_unprotect()

proto_bool protocore_dtls_record_unprotect ( uint8_t *  work,
DtlsRecordKeys *  keys,
uint64_t  next_seq,
const uint8_t *  rec,
size_t  rec_len,
uint8_t *  out,
size_t  out_cap,
DtlsCiphertext *  info,
const uint8_t *  expected_cid,
size_t  expected_cid_len 
)

Open one received record: decrypt the sequence number, rebuild the .

Parameters
workPROTOCORE_DTLS_RECORD_BORROW bytes the caller took. Not held past the call.
keysKeys
next_seqNext seq
recRec
rec_lenRec len
outOut
out_capOut cap
infoInfo
expected_cidExpected cid
expected_cid_lenExpected cid len
Returns
PROTO_TRUE on success.

◆ protocore_dtls_record_replay_init()

void protocore_dtls_record_replay_init ( uint8_t *  work,
DtlsReplayWindow *  w 
)

Reset a replay window to empty.

Parameters
workPROTOCORE_DTLS_RECORD_BORROW bytes the caller took. Not held past the call.
wW

◆ protocore_dtls_record_replay_check()

proto_bool protocore_dtls_record_replay_check ( uint8_t *  work,
const DtlsReplayWindow *  w,
uint64_t  seq 
)

Whether seq is new and inside the window, rather than a replay or .

Parameters
workPROTOCORE_DTLS_RECORD_BORROW bytes the caller took. Not held past the call.
wW
seqSeq
Returns
PROTO_TRUE on success.

◆ protocore_dtls_record_replay_mark()

void protocore_dtls_record_replay_mark ( uint8_t *  work,
DtlsReplayWindow *  w,
uint64_t  seq 
)

Record seq as accepted and advance the window; only after a .

Parameters
workPROTOCORE_DTLS_RECORD_BORROW bytes the caller took. Not held past the call.
wW
seqSeq

Variable Documentation

◆ PROTOCORE_UNUSED

PROTOCORE_NS DtlsRecordNs DtlsRecord PROTOCORE_UNUSED
Initial value:
void protocore_dtls_record_replay_mark(uint8_t *work, DtlsReplayWindow *w, uint64_t seq)
Record seq as accepted and advance the window; only after a .
void protocore_dtls_record_replay_init(uint8_t *work, DtlsReplayWindow *w)
Reset a replay window to empty.
size_t protocore_dtls_record_protect(uint8_t *work, DtlsRecordKeys *keys, uint64_t seq, uint8_t content_type, const uint8_t *plaintext, size_t pt_len, uint8_t *out, size_t out_cap, const uint8_t *cid, size_t cid_len)
Seal one record (RFC 9147 sec 4.2): the unified header, the .
size_t protocore_dtls_record_plaintext_build(uint8_t *work, uint8_t content_type, uint16_t epoch, uint64_t seq, const uint8_t *fragment, size_t frag_len, uint8_t *out, size_t out_cap)
A DTLSPlaintext record; bytes written (13 + frag_len), or 0 on .
proto_bool protocore_dtls_record_replay_check(uint8_t *work, const DtlsReplayWindow *w, uint64_t seq)
Whether seq is new and inside the window, rather than a replay or .
proto_bool protocore_dtls_record_unprotect(uint8_t *work, DtlsRecordKeys *keys, uint64_t next_seq, const uint8_t *rec, size_t rec_len, uint8_t *out, size_t out_cap, DtlsCiphertext *info, const uint8_t *expected_cid, size_t expected_cid_len)
Open one received record: decrypt the sequence number, rebuild the .
size_t protocore_dtls_record_plaintext_parse(uint8_t *work, const uint8_t *rec, size_t rec_len, DtlsPlaintext *out)
The same record back, validating legacy_version and the length .
void protocore_dtls_record_keys_derive(uint8_t *work, DtlsRecordKeys *out, DtlsCipher cipher, uint16_t epoch, const uint8_t *secret)
Derive one direction's record keys from a 32-byte TLS 1.3 traffic .

Module namespace.

Definition at line 228 of file dtls_record.h.