20const uint8_t DTLS_UH_FIXED = 0x20;
21const uint8_t DTLS_UH_FIXED_MASK = 0xE0;
22const uint8_t DTLS_UH_CID = 0x10;
23const uint8_t DTLS_UH_SEQ16 = 0x08;
24const uint8_t DTLS_UH_LENGTH = 0x04;
25const uint8_t DTLS_UH_EPOCH_MASK = 0x03;
29void build_nonce(
const uint8_t iv[12], uint64_t seq, uint8_t nonce[12])
31 memcpy(nonce, iv, 12);
32 for (
int i = 0; i < 8; i++)
33 nonce[11 - i] ^= (uint8_t)(seq >> (8 * i));
38uint64_t seq_decode(uint64_t expected, uint64_t truncated,
unsigned bits)
40 if (bits == 0 || bits >= 64)
42 uint64_t win = (uint64_t)1 << bits;
43 uint64_t hwin = win >> 1;
44 uint64_t mask = win - 1;
45 uint64_t candidate = (expected & ~mask) | (truncated & mask);
46 if (candidate + hwin <= expected && candidate + win > candidate)
47 return candidate + win;
48 if (candidate > expected + hwin && candidate >= win)
49 return candidate - win;
54void dtls_record_keys_derive(DtlsRecordKeys *out, DtlsCipher cipher, uint16_t epoch,
const uint8_t secret[32])
60 tls13_kdf_expand_label(&DTLS13_KDF, secret,
"key", out->key,
sizeof(out->key));
61 tls13_kdf_expand_label(&DTLS13_KDF, secret,
"iv", out->iv,
sizeof(out->iv));
62 tls13_kdf_expand_label(&DTLS13_KDF, secret,
"sn", out->sn_key,
sizeof(out->sn_key));
69size_t dtls_plaintext_build(uint8_t content_type, uint16_t epoch, uint64_t seq,
const uint8_t *fragment,
70 size_t frag_len, uint8_t *out,
size_t out_cap)
72 size_t total = DTLS_PLAINTEXT_HDR_LEN + frag_len;
73 if (total > out_cap || frag_len > 0xFFFF)
75 out[0] = content_type;
76 out[1] = (uint8_t)(DTLS_LEGACY_VERSION >> 8);
77 out[2] = (uint8_t)DTLS_LEGACY_VERSION;
78 out[3] = (uint8_t)(epoch >> 8);
79 out[4] = (uint8_t)epoch;
80 out[5] = (uint8_t)(seq >> 40);
81 out[6] = (uint8_t)(seq >> 32);
82 out[7] = (uint8_t)(seq >> 24);
83 out[8] = (uint8_t)(seq >> 16);
84 out[9] = (uint8_t)(seq >> 8);
85 out[10] = (uint8_t)seq;
86 out[11] = (uint8_t)(frag_len >> 8);
87 out[12] = (uint8_t)frag_len;
89 memcpy(out + DTLS_PLAINTEXT_HDR_LEN, fragment, frag_len);
93size_t dtls_plaintext_parse(
const uint8_t *rec,
size_t rec_len, DtlsPlaintext *out)
95 if (rec_len < DTLS_PLAINTEXT_HDR_LEN)
97 if (rec[1] != (uint8_t)(DTLS_LEGACY_VERSION >> 8) || rec[2] != (uint8_t)DTLS_LEGACY_VERSION)
99 out->content_type = rec[0];
100 out->epoch = (uint16_t)(((uint16_t)rec[3] << 8) | rec[4]);
101 out->seq = ((uint64_t)rec[5] << 40) | ((uint64_t)rec[6] << 32) | ((uint64_t)rec[7] << 24) |
102 ((uint64_t)rec[8] << 16) | ((uint64_t)rec[9] << 8) | (uint64_t)rec[10];
103 size_t length = ((size_t)rec[11] << 8) | rec[12];
104 if (DTLS_PLAINTEXT_HDR_LEN + length > rec_len)
106 out->fragment = rec + DTLS_PLAINTEXT_HDR_LEN;
107 out->frag_len = length;
108 return DTLS_PLAINTEXT_HDR_LEN + length;
115size_t dtls_ciphertext_protect(
const DtlsRecordKeys *keys, uint64_t seq, uint8_t content_type,
const uint8_t *plaintext,
116 size_t pt_len, uint8_t *out,
size_t out_cap,
const uint8_t *cid,
size_t cid_len)
118 if (keys->cipher != DtlsCipher::AES_128_GCM_SHA256)
120 if (cid_len > DTLS_CID_MAX || (cid_len && !cid))
124 const size_t hdr_len = 1 + cid_len + 2 + 2;
125 size_t inner_len = pt_len + 1;
126 size_t enc_len = inner_len + DTLS_TAG_LEN;
127 size_t total = hdr_len + enc_len;
131 uint8_t flags = (uint8_t)(DTLS_UH_FIXED | DTLS_UH_SEQ16 | DTLS_UH_LENGTH | (keys->epoch & DTLS_UH_EPOCH_MASK));
133 flags |= DTLS_UH_CID;
136 memcpy(out + 1, cid, cid_len);
137 size_t seq_off = 1 + cid_len;
138 out[seq_off] = (uint8_t)(seq >> 8);
139 out[seq_off + 1] = (uint8_t)seq;
140 out[seq_off + 2] = (uint8_t)(enc_len >> 8);
141 out[seq_off + 3] = (uint8_t)enc_len;
144 memcpy(out + hdr_len, plaintext, pt_len);
145 out[hdr_len + pt_len] = content_type;
148 build_nonce(keys->iv, seq, nonce);
151 quic_aes128_gcm_seal(keys->key, nonce, out, hdr_len, out + hdr_len, inner_len, out + hdr_len);
156 quic_aes128_init(&sn, keys->sn_key);
158 quic_aes128_encrypt_block(&sn, out + hdr_len, mask);
159 quic_aes128_wipe(&sn);
160 out[seq_off] ^= mask[0];
161 out[seq_off + 1] ^= mask[1];
165bool dtls_ciphertext_unprotect(
const DtlsRecordKeys *keys, uint64_t next_seq,
const uint8_t *rec,
size_t rec_len,
166 uint8_t *out,
size_t out_cap, DtlsCiphertext *info,
const uint8_t *expected_cid,
167 size_t expected_cid_len)
169 if (keys->cipher != DtlsCipher::AES_128_GCM_SHA256 || rec_len < 1)
171 if (expected_cid_len > DTLS_CID_MAX)
174 if ((b0 & DTLS_UH_FIXED_MASK) != DTLS_UH_FIXED)
176 if ((b0 & DTLS_UH_EPOCH_MASK) != (keys->epoch & DTLS_UH_EPOCH_MASK))
180 if (b0 & DTLS_UH_CID)
184 if (expected_cid_len == 0 || off + expected_cid_len > rec_len ||
185 memcmp(rec + off, expected_cid, expected_cid_len) != 0)
187 off += expected_cid_len;
189 else if (expected_cid_len != 0)
194 size_t seq_len = (b0 & DTLS_UH_SEQ16) ? 2 : 1;
195 if (off + seq_len > rec_len)
197 size_t seq_off = off;
201 if (b0 & DTLS_UH_LENGTH)
203 if (off + 2 > rec_len)
205 enc_len = ((size_t)rec[off] << 8) | rec[off + 1];
210 enc_len = rec_len - off;
212 if (off + enc_len > rec_len || enc_len < 16 || enc_len < DTLS_TAG_LEN + 1)
215 const uint8_t *enc = rec + off;
216 size_t hdr_len = off;
219 uint8_t hdr[1 + DTLS_CID_MAX + 4];
220 memcpy(hdr, rec, hdr_len);
224 quic_aes128_init(&sn, keys->sn_key);
226 quic_aes128_encrypt_block(&sn, enc, mask);
227 quic_aes128_wipe(&sn);
229 for (
size_t i = 0; i < seq_len; i++)
231 hdr[seq_off + i] ^= mask[i];
232 trunc = (trunc << 8) | hdr[seq_off + i];
234 uint64_t full_seq = seq_decode(next_seq, trunc, (
unsigned)(seq_len * 8));
236 size_t inner_len = enc_len - DTLS_TAG_LEN;
237 if (inner_len > out_cap)
241 build_nonce(keys->iv, full_seq, nonce);
242 if (!quic_aes128_gcm_open(keys->key, nonce, hdr, hdr_len, enc, enc_len, out))
246 size_t n = inner_len;
247 while (n > 0 && out[n - 1] == 0)
251 info->content_type = out[n - 1];
252 info->pt_len = n - 1;
253 info->seq = full_seq;
254 info->epoch = keys->epoch;
262void dtls_replay_init(DtlsReplayWindow *w)
269bool dtls_replay_check(
const DtlsReplayWindow *w, uint64_t seq)
271 if (!w->seeded || seq > w->highest)
273 uint64_t diff = w->highest - seq;
276 return ((w->bitmap >> diff) & 1u) == 0;
279void dtls_replay_mark(DtlsReplayWindow *w, uint64_t seq)
288 if (seq > w->highest)
290 uint64_t shift = seq - w->highest;
291 w->bitmap = (shift >= 64) ? 1u : ((w->bitmap << shift) | 1u);
295 uint64_t diff = w->highest - seq;
297 w->bitmap |= ((uint64_t)1 << diff);
DTLS 1.3 record layer (RFC 9147 §4).
AES-128 block cipher and AEAD_AES_128_GCM (RFC 5116 / NIST SP 800-38D).
TLS 1.3 key schedule (RFC 8446 sec 7.1) for the QUIC handshake.