18void put_u64(uint8_t *p, uint64_t v)
20 for (
int i = 0; i < 8; i++)
21 p[i] = (uint8_t)(v >> (8 * (7 - i)));
24uint64_t get_u64(
const uint8_t *p)
27 for (
int i = 0; i < 8; i++)
33bool ct_equal(
const uint8_t *a,
const uint8_t *b,
size_t len)
36 for (
size_t i = 0; i < len; i++)
37 d |= (uint8_t)(a[i] ^ b[i]);
44int reasm_merge(DtlsHsReasm *r, uint32_t lo, uint32_t hi)
46 uint8_t n = r->range_count;
52 if (r->range_hi[i] < lo || r->range_lo[i] > hi)
57 if (r->range_lo[i] < lo)
59 if (r->range_hi[i] > hi)
61 for (uint8_t j = i; j + 1 < n; j++)
63 r->range_lo[j] = r->range_lo[j + 1];
64 r->range_hi[j] = r->range_hi[j + 1];
68 if (n >= DTLS_HS_REASM_MAX_RANGES)
71 while (k > 0 && r->range_lo[k - 1] > lo)
73 r->range_lo[k] = r->range_lo[k - 1];
74 r->range_hi[k] = r->range_hi[k - 1];
79 r->range_count = (uint8_t)(n + 1);
88size_t dtls_hs_header_parse(
const uint8_t *p,
size_t len, DtlsHsHeader *out)
90 if (len < DTLS_HS_HDR_LEN)
93 out->length = ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | p[3];
94 out->msg_seq = (uint16_t)(((uint16_t)p[4] << 8) | p[5]);
95 out->frag_offset = ((uint32_t)p[6] << 16) | ((uint32_t)p[7] << 8) | p[8];
96 out->frag_length = ((uint32_t)p[9] << 16) | ((uint32_t)p[10] << 8) | p[11];
97 if (out->frag_offset + out->frag_length > out->length)
99 if (DTLS_HS_HDR_LEN + out->frag_length > len)
101 out->fragment = p + DTLS_HS_HDR_LEN;
102 return DTLS_HS_HDR_LEN + out->frag_length;
105size_t dtls_hs_frag_build(uint8_t msg_type, uint16_t msg_seq, uint32_t full_len, uint32_t frag_offset,
106 const uint8_t *frag, uint32_t frag_len, uint8_t *out,
size_t out_cap)
108 if (full_len > 0xFFFFFF || frag_offset > 0xFFFFFF || frag_len > 0xFFFFFF)
110 if (frag_offset + frag_len > full_len)
112 size_t total = DTLS_HS_HDR_LEN + frag_len;
116 out[1] = (uint8_t)(full_len >> 16);
117 out[2] = (uint8_t)(full_len >> 8);
118 out[3] = (uint8_t)full_len;
119 out[4] = (uint8_t)(msg_seq >> 8);
120 out[5] = (uint8_t)msg_seq;
121 out[6] = (uint8_t)(frag_offset >> 16);
122 out[7] = (uint8_t)(frag_offset >> 8);
123 out[8] = (uint8_t)frag_offset;
124 out[9] = (uint8_t)(frag_len >> 16);
125 out[10] = (uint8_t)(frag_len >> 8);
126 out[11] = (uint8_t)frag_len;
128 memcpy(out + DTLS_HS_HDR_LEN, frag, frag_len);
136void dtls_hs_reasm_init(DtlsHsReasm *r, uint16_t msg_seq, uint8_t *buf,
size_t buf_cap)
141 r->msg_seq = msg_seq;
144 r->buf_cap = buf_cap;
148int dtls_hs_reasm_add(DtlsHsReasm *r,
const DtlsHsHeader *frag)
150 if (frag->msg_seq != r->msg_seq)
154 if (frag->length > r->buf_cap)
156 r->length = frag->length;
157 r->msg_type = frag->msg_type;
161 else if (frag->length != r->length)
165 uint32_t lo = frag->frag_offset;
166 uint32_t hi = frag->frag_offset + frag->frag_length;
171 if (frag->frag_length == 0)
173 memcpy(r->buf + lo, frag->fragment, frag->frag_length);
174 if (reasm_merge(r, lo, hi) < 0)
176 if (r->range_count == 1 && r->range_lo[0] == 0 && r->range_hi[0] >= r->length)
185size_t dtls_ack_build(
const DtlsRecordNumber *nums,
size_t count, uint8_t *out,
size_t out_cap)
187 size_t list_len = count * 16;
188 if (list_len > 0xFFFF)
190 size_t total = 2 + list_len;
193 out[0] = (uint8_t)(list_len >> 8);
194 out[1] = (uint8_t)list_len;
196 for (
size_t i = 0; i < count; i++)
198 put_u64(out + o, nums[i].epoch);
199 put_u64(out + o + 8, nums[i].seq);
205bool dtls_ack_parse(
const uint8_t *body,
size_t len, DtlsRecordNumber *out,
size_t out_cap,
size_t *out_count)
209 size_t list_len = ((size_t)body[0] << 8) | body[1];
210 if (list_len % 16 != 0 || 2 + list_len != len)
212 size_t n = list_len / 16;
216 for (
size_t i = 0; i < n; i++)
218 out[i].epoch = get_u64(body + o);
219 out[i].seq = get_u64(body + o + 8);
230size_t dtls_cookie_make(
const uint8_t hmac_key[32], uint64_t timestamp,
const uint8_t *payload,
size_t payload_len,
231 const uint8_t *client_addr,
size_t addr_len, uint8_t *out,
size_t out_cap)
233 if (payload_len > 0xFFFF)
235 size_t body = 1 + 8 + 2 + payload_len;
237 if (total > out_cap || total > DTLS_COOKIE_MAX)
240 put_u64(out + 1, timestamp);
241 out[9] = (uint8_t)(payload_len >> 8);
242 out[10] = (uint8_t)payload_len;
244 memcpy(out + 11, payload, payload_len);
256bool dtls_cookie_verify(
const uint8_t hmac_key[32], uint64_t now, uint64_t max_age,
const uint8_t *client_addr,
257 size_t addr_len,
const uint8_t *cookie,
size_t cookie_len, uint8_t *payload_out,
258 size_t payload_cap,
size_t *payload_len_out)
262 size_t payload_len = ((size_t)cookie[9] << 8) | cookie[10];
263 size_t body = 1 + 8 + 2 + payload_len;
266 if (payload_len > payload_cap)
279 uint64_t ts = get_u64(cookie + 1);
280 if (ts > now || now - ts > max_age)
284 memcpy(payload_out, cookie + 11, payload_len);
285 *payload_len_out = payload_len;
DTLS 1.3 handshake framing and reliability (RFC 9147 §5, §7).
void ssh_hmac_sha256_final(SshHmacCtx *ctx, uint8_t mac[SSH_HMAC_SHA256_LEN])
Finalize and write the 32-byte MAC.
void ssh_hmac_sha256_init(SshHmacCtx *ctx, const uint8_t *key, size_t key_len)
Initialize a streaming HMAC-SHA2-256 context.
void ssh_hmac_sha256_update(SshHmacCtx *ctx, const uint8_t *data, size_t len)
Feed len bytes into the running HMAC.
HMAC-SHA2-256 (RFC 2104 + FIPS 198-1).
#define SSH_HMAC_SHA256_LEN
HMAC-SHA2-256 output length in bytes.
Streaming HMAC-SHA2-256 context.