18void put_u64(uint8_t *p, uint64_t v)
20 for (
int i = 0; i < 8; i++)
22 p[i] = (uint8_t)(v >> (8 * (7 - i)));
26uint64_t get_u64(
const uint8_t *p)
29 for (
int i = 0; i < 8; i++)
37bool ct_equal(
const uint8_t *a,
const uint8_t *b,
size_t len)
40 for (
size_t i = 0; i < len; i++)
42 d |= (uint8_t)(a[i] ^ b[i]);
50int reasm_merge(DtlsHsReasm *r, uint32_t lo, uint32_t hi)
52 uint8_t n = r->range_count;
58 if (r->range_hi[i] < lo || r->range_lo[i] > hi)
63 if (r->range_lo[i] < lo)
67 if (r->range_hi[i] > hi)
71 for (uint8_t j = i; j + 1 < n; j++)
73 r->range_lo[j] = r->range_lo[j + 1];
74 r->range_hi[j] = r->range_hi[j + 1];
78 if (n >= PC_DTLS_HS_REASM_MAX_RANGES)
83 while (k > 0 && r->range_lo[k - 1] > lo)
85 r->range_lo[k] = r->range_lo[k - 1];
86 r->range_hi[k] = r->range_hi[k - 1];
91 r->range_count = (uint8_t)(n + 1);
100size_t pc_dtls_hs_header_parse(
const uint8_t *p,
size_t len, DtlsHsHeader *out)
102 if (len < PC_DTLS_HS_HDR_LEN)
106 out->msg_type = p[0];
107 out->length = ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | p[3];
108 out->msg_seq = (uint16_t)(((uint16_t)p[4] << 8) | p[5]);
109 out->frag_offset = ((uint32_t)p[6] << 16) | ((uint32_t)p[7] << 8) | p[8];
110 out->frag_length = ((uint32_t)p[9] << 16) | ((uint32_t)p[10] << 8) | p[11];
111 if (out->frag_offset + out->frag_length > out->length)
115 if (PC_DTLS_HS_HDR_LEN + out->frag_length > len)
119 out->fragment = p + PC_DTLS_HS_HDR_LEN;
120 return PC_DTLS_HS_HDR_LEN + out->frag_length;
123size_t pc_dtls_hs_frag_build(uint8_t msg_type, uint16_t msg_seq, uint32_t full_len, uint32_t frag_offset,
124 const uint8_t *frag, uint32_t frag_len, uint8_t *out,
size_t out_cap)
126 if (full_len > 0xFFFFFF || frag_offset > 0xFFFFFF || frag_len > 0xFFFFFF)
130 if (frag_offset + frag_len > full_len)
134 size_t total = PC_DTLS_HS_HDR_LEN + frag_len;
140 out[1] = (uint8_t)(full_len >> 16);
141 out[2] = (uint8_t)(full_len >> 8);
142 out[3] = (uint8_t)full_len;
143 out[4] = (uint8_t)(msg_seq >> 8);
144 out[5] = (uint8_t)msg_seq;
145 out[6] = (uint8_t)(frag_offset >> 16);
146 out[7] = (uint8_t)(frag_offset >> 8);
147 out[8] = (uint8_t)frag_offset;
148 out[9] = (uint8_t)(frag_len >> 16);
149 out[10] = (uint8_t)(frag_len >> 8);
150 out[11] = (uint8_t)frag_len;
153 memcpy(out + PC_DTLS_HS_HDR_LEN, frag, frag_len);
162void pc_dtls_hs_reasm_init(DtlsHsReasm *r, uint16_t msg_seq, uint8_t *buf,
size_t buf_cap)
167 r->msg_seq = msg_seq;
170 r->buf_cap = buf_cap;
174int pc_dtls_hs_reasm_add(DtlsHsReasm *r,
const DtlsHsHeader *frag)
176 if (frag->msg_seq != r->msg_seq)
182 if (frag->length > r->buf_cap)
186 r->length = frag->length;
187 r->msg_type = frag->msg_type;
191 else if (frag->length != r->length)
195 uint32_t lo = frag->frag_offset;
196 uint32_t hi = frag->frag_offset + frag->frag_length;
205 if (frag->frag_length == 0)
209 memcpy(r->buf + lo, frag->fragment, frag->frag_length);
210 if (reasm_merge(r, lo, hi) < 0)
214 if (r->range_count == 1 && r->range_lo[0] == 0 && r->range_hi[0] >= r->length)
225size_t pc_dtls_ack_build(
const DtlsRecordNumber *nums,
size_t count, uint8_t *out,
size_t out_cap)
227 size_t list_len = count * 16;
228 if (list_len > 0xFFFF)
232 size_t total = 2 + list_len;
237 out[0] = (uint8_t)(list_len >> 8);
238 out[1] = (uint8_t)list_len;
240 for (
size_t i = 0; i < count; i++)
242 put_u64(out + o, nums[i].epoch);
243 put_u64(out + o + 8, nums[i].seq);
249bool pc_dtls_ack_parse(
const uint8_t *body,
size_t len, DtlsRecordNumber *out,
size_t out_cap,
size_t *out_count)
255 size_t list_len = ((size_t)body[0] << 8) | body[1];
256 if (list_len % 16 != 0 || 2 + list_len != len)
260 size_t n = list_len / 16;
266 for (
size_t i = 0; i < n; i++)
268 out[i].epoch = get_u64(body + o);
269 out[i].seq = get_u64(body + o + 8);
280size_t pc_dtls_cookie_make(
const uint8_t pc_hmac_key[32], uint64_t timestamp,
const uint8_t *payload,
281 size_t payload_len,
const uint8_t *client_addr,
size_t addr_len, uint8_t *out,
284 if (payload_len > 0xFFFF)
288 size_t body = 1 + 8 + 2 + payload_len;
290 if (total > out_cap || total > PC_DTLS_COOKIE_MAX)
295 put_u64(out + 1, timestamp);
296 out[9] = (uint8_t)(payload_len >> 8);
297 out[10] = (uint8_t)payload_len;
300 memcpy(out + 11, payload, payload_len);
313bool pc_dtls_cookie_verify(
const uint8_t pc_hmac_key[32], uint64_t now, uint64_t max_age,
const uint8_t *client_addr,
314 size_t addr_len,
const uint8_t *cookie,
size_t cookie_len, uint8_t *payload_out,
315 size_t payload_cap,
size_t *payload_len_out)
321 size_t payload_len = ((size_t)cookie[9] << 8) | cookie[10];
322 size_t body = 1 + 8 + 2 + payload_len;
327 if (payload_len > payload_cap)
344 uint64_t ts = get_u64(cookie + 1);
345 if (ts > now || now - ts > max_age)
352 memcpy(payload_out, cookie + 11, payload_len);
354 *payload_len_out = payload_len;
void pc_hmac_sha256_update(pc_hmac_sha256_ctx *ctx, const uint8_t *data, size_t len)
Feed len bytes into the running HMAC.
void pc_hmac_sha256_init(pc_hmac_sha256_ctx *ctx, const uint8_t *key, size_t key_len)
Initialize a streaming HMAC-SHA2-256 context.
void pc_hmac_sha256_final(pc_hmac_sha256_ctx *ctx, uint8_t mac[PC_HMAC_SHA256_LEN])
Finalize and write the 32-byte MAC.
HMAC-SHA2-256 (RFC 2104 + FIPS 198-1) - streaming context and one-shot API.
#define PC_HMAC_SHA256_LEN
HMAC-SHA2-256 output length in bytes.
Streaming HMAC-SHA2-256 context.