23static inline void put16(uint8_t *p, uint16_t v)
25 p[0] = (uint8_t)(v >> 8);
28static inline void put32(uint8_t *p, uint32_t v)
30 p[0] = (uint8_t)(v >> 24);
31 p[1] = (uint8_t)(v >> 16);
32 p[2] = (uint8_t)(v >> 8);
35static inline uint16_t get16(
const uint8_t *p)
37 return (uint16_t)(((uint16_t)p[0] << 8) | p[1]);
39static inline uint32_t get32(
const uint8_t *p)
41 return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3];
45static bool put_pl_hdr(uint8_t *buf,
size_t cap, IkePayloadType next_payload,
size_t total_len)
47 if (total_len > 0xFFFF || cap < total_len)
51 buf[0] = (uint8_t)next_payload;
53 put16(buf + 2, (uint16_t)total_len);
59size_t pc_ike_hdr_build(uint8_t *buf,
size_t cap,
const IkeHeader *h)
61 if (!buf || !h || cap < PC_IKE_HDR_LEN)
65 memcpy(buf, h->init_spi, PC_IKE_SPI_LEN);
66 memcpy(buf + 8, h->resp_spi, PC_IKE_SPI_LEN);
67 buf[16] = (uint8_t)h->next_payload;
69 buf[18] = (uint8_t)h->exchange;
71 put32(buf + 20, h->message_id);
72 put32(buf + 24, h->length);
73 return PC_IKE_HDR_LEN;
76bool pc_ike_hdr_parse(
const uint8_t *buf,
size_t len, IkeHeader *out)
82 memset(out, 0,
sizeof(*out));
83 if (!buf || len < PC_IKE_HDR_LEN)
87 memcpy(out->init_spi, buf, PC_IKE_SPI_LEN);
88 memcpy(out->resp_spi, buf + 8, PC_IKE_SPI_LEN);
89 out->next_payload = (IkePayloadType)buf[16];
90 out->version = buf[17];
91 out->exchange = (IkeExchange)buf[18];
93 out->message_id = get32(buf + 20);
94 out->length = get32(buf + 24);
98bool pc_ike_set_length(uint8_t *buf,
size_t buf_cap, uint32_t total_len)
100 if (!buf || buf_cap < PC_IKE_HDR_LEN)
104 put32(buf + 24, total_len);
110void pc_ike_payload_iter_init(IkePayloadIter *it, IkePayloadType first_type,
const uint8_t *area,
size_t area_len)
119 it->next_type = first_type;
122bool pc_ike_payload_next(IkePayloadIter *it, IkePayload *out)
128 out->type = IkePayloadType::IKE_PL_NONE;
129 out->next_payload = IkePayloadType::IKE_PL_NONE;
130 out->critical =
false;
133 if (!it || !it->area || it->next_type == IkePayloadType::IKE_PL_NONE)
137 if (it->off + PC_IKE_PAYLOAD_HDR_LEN > it->len)
141 const uint8_t *p = it->area + it->off;
143 bool critical = (p[1] & PC_IKE_CRITICAL) != 0;
144 uint16_t plen = get16(p + 2);
145 if (plen < PC_IKE_PAYLOAD_HDR_LEN || it->off + plen > it->len)
149 out->type = it->next_type;
150 out->next_payload = (IkePayloadType)next;
151 out->critical = critical;
152 out->body = p + PC_IKE_PAYLOAD_HDR_LEN;
153 out->body_len = (size_t)plen - PC_IKE_PAYLOAD_HDR_LEN;
154 it->next_type = (IkePayloadType)next;
159size_t pc_ike_payload_build(uint8_t *buf,
size_t cap, IkePayloadType next_payload,
bool critical,
const uint8_t *body,
162 if (!buf || (body_len && !body))
166 size_t total = PC_IKE_PAYLOAD_HDR_LEN + body_len;
167 if (total > 0xFFFF || cap < total)
171 buf[0] = (uint8_t)next_payload;
172 buf[1] = critical ? PC_IKE_CRITICAL : 0x00;
173 put16(buf + 2, (uint16_t)total);
176 memcpy(buf + PC_IKE_PAYLOAD_HDR_LEN, body, body_len);
183size_t pc_ike_sa_build(uint8_t *buf,
size_t cap, IkePayloadType next_payload, uint8_t proposal_num,
184 IkeProtocol protocol_id,
const uint8_t *spi, uint8_t spi_size,
const IkeTransform *transforms,
185 uint8_t num_transforms)
187 if (!buf || !transforms || num_transforms == 0)
191 if (spi_size && !spi)
196 const size_t prop_hdr = 8;
197 size_t off = PC_IKE_PAYLOAD_HDR_LEN + prop_hdr + spi_size;
204 for (uint8_t i = 0; i < num_transforms; i++)
206 bool has_key = transforms[i].key_length >= 0;
207 size_t tlen = 8 + (has_key ? 4 : 0);
208 if (off + tlen > cap)
212 buf[off + 0] = (i + 1 == num_transforms) ? 0 : 3;
214 put16(buf + off + 2, (uint16_t)tlen);
215 buf[off + 4] = (uint8_t)transforms[i].type;
217 put16(buf + off + 6, transforms[i].
id);
220 put16(buf + off + 8, (uint16_t)(0x8000u | IKE_ATTR_KEY_LENGTH));
221 put16(buf + off + 10, (uint16_t)transforms[i].key_length);
226 size_t prop_len = prop_hdr + spi_size + (off - tstart);
227 size_t sa_total = PC_IKE_PAYLOAD_HDR_LEN + prop_len;
228 if (prop_len > 0xFFFF || sa_total > 0xFFFF)
233 buf[0] = (uint8_t)next_payload;
235 put16(buf + 2, (uint16_t)sa_total);
236 uint8_t *pr = buf + PC_IKE_PAYLOAD_HDR_LEN;
239 put16(pr + 2, (uint16_t)prop_len);
240 pr[4] = proposal_num;
241 pr[5] = (uint8_t)protocol_id;
243 pr[7] = num_transforms;
246 memcpy(pr + prop_hdr, spi, spi_size);
251size_t pc_ike_ke_build(uint8_t *buf,
size_t cap, IkePayloadType next_payload, uint16_t dh_group,
const uint8_t *data,
254 if (!buf || (data_len && !data))
258 size_t total = PC_IKE_PAYLOAD_HDR_LEN + 4 + data_len;
259 if (!put_pl_hdr(buf, cap, next_payload, total))
263 put16(buf + 4, dh_group);
268 memcpy(buf + 8, data, data_len);
273size_t pc_ike_nonce_build(uint8_t *buf,
size_t cap, IkePayloadType next_payload,
const uint8_t *nonce,
size_t nonce_len)
275 if (!buf || (nonce_len && !nonce))
279 size_t total = PC_IKE_PAYLOAD_HDR_LEN + nonce_len;
280 if (!put_pl_hdr(buf, cap, next_payload, total))
286 memcpy(buf + 4, nonce, nonce_len);
291size_t pc_ike_id_build(uint8_t *buf,
size_t cap, IkePayloadType next_payload, IkeIdType id_type,
const uint8_t *data,
294 if (!buf || (data_len && !data))
298 size_t total = PC_IKE_PAYLOAD_HDR_LEN + 4 + data_len;
299 if (!put_pl_hdr(buf, cap, next_payload, total))
303 buf[4] = (uint8_t)id_type;
309 memcpy(buf + 8, data, data_len);
314size_t pc_ike_auth_build(uint8_t *buf,
size_t cap, IkePayloadType next_payload, IkeAuthMethod auth_method,
315 const uint8_t *data,
size_t data_len)
317 if (!buf || (data_len && !data))
321 size_t total = PC_IKE_PAYLOAD_HDR_LEN + 4 + data_len;
322 if (!put_pl_hdr(buf, cap, next_payload, total))
326 buf[4] = (uint8_t)auth_method;
332 memcpy(buf + 8, data, data_len);
337size_t pc_ike_cert_build(uint8_t *buf,
size_t cap, IkePayloadType next_payload, uint8_t cert_encoding,
338 const uint8_t *data,
size_t data_len)
340 if (!buf || (data_len && !data))
344 size_t total = PC_IKE_PAYLOAD_HDR_LEN + 1 + data_len;
345 if (!put_pl_hdr(buf, cap, next_payload, total))
349 buf[4] = cert_encoding;
352 memcpy(buf + 5, data, data_len);
357size_t pc_ike_notify_build(uint8_t *buf,
size_t cap, IkePayloadType next_payload, IkeProtocol protocol_id,
358 const uint8_t *spi, uint8_t spi_size, uint16_t notify_type,
const uint8_t *data,
361 if (!buf || (spi_size && !spi) || (data_len && !data))
365 size_t total = PC_IKE_PAYLOAD_HDR_LEN + 4 + spi_size + data_len;
366 if (!put_pl_hdr(buf, cap, next_payload, total))
370 buf[4] = (uint8_t)protocol_id;
372 put16(buf + 6, notify_type);
376 memcpy(buf + off, spi, spi_size);
381 memcpy(buf + off, data, data_len);
386size_t pc_ike_delete_build(uint8_t *buf,
size_t cap, IkePayloadType next_payload, IkeProtocol protocol_id,
387 uint8_t spi_size,
const uint8_t *spis, uint16_t num_spis)
393 size_t spis_len = (size_t)spi_size * num_spis;
394 if (spis_len && !spis)
398 size_t total = PC_IKE_PAYLOAD_HDR_LEN + 4 + spis_len;
399 if (!put_pl_hdr(buf, cap, next_payload, total))
403 buf[4] = (uint8_t)protocol_id;
405 put16(buf + 6, num_spis);
408 memcpy(buf + 8, spis, spis_len);
413size_t pc_ike_ts_build(uint8_t *buf,
size_t cap, IkePayloadType next_payload,
const IkeTrafficSelector *sels,
416 if (!buf || !sels || num == 0)
420 size_t off = PC_IKE_PAYLOAD_HDR_LEN + 4;
425 for (uint8_t i = 0; i < num; i++)
427 const IkeTrafficSelector *s = &sels[i];
428 if ((s->addr_len != 4 && s->addr_len != 16) || !s->start_addr || !s->end_addr)
432 size_t sel_len = 8 + 2 * s->addr_len;
433 if (off + sel_len > cap)
437 buf[off + 0] = (uint8_t)s->ts_type;
438 buf[off + 1] = s->ip_protocol;
439 put16(buf + off + 2, (uint16_t)sel_len);
440 put16(buf + off + 4, s->start_port);
441 put16(buf + off + 6, s->end_port);
442 memcpy(buf + off + 8, s->start_addr, s->addr_len);
443 memcpy(buf + off + 8 + s->addr_len, s->end_addr, s->addr_len);
450 buf[0] = (uint8_t)next_payload;
452 put16(buf + 2, (uint16_t)off);
460size_t pc_ike_cp_build(uint8_t *buf,
size_t cap, IkePayloadType next_payload, IkeCfgType cfg_type,
461 const IkeCfgAttr *attrs, uint8_t num_attrs)
463 if (!buf || (num_attrs && !attrs))
467 size_t attrs_len = 0;
468 for (uint8_t i = 0; i < num_attrs; i++)
470 if (attrs[i].value_len && !attrs[i].value)
474 attrs_len += 4 + attrs[i].value_len;
476 size_t total = PC_IKE_PAYLOAD_HDR_LEN + 4 + attrs_len;
477 if (!put_pl_hdr(buf, cap, next_payload, total))
481 buf[4] = (uint8_t)cfg_type;
486 for (uint8_t i = 0; i < num_attrs; i++)
488 put16(buf + off, (uint16_t)(attrs[i].type & 0x7FFF));
489 put16(buf + off + 2, attrs[i].value_len);
491 if (attrs[i].value_len)
493 memcpy(buf + off, attrs[i].value, attrs[i].value_len);
494 off += attrs[i].value_len;
500size_t pc_ike_sk_build(uint8_t *buf,
size_t cap, IkePayloadType next_payload,
const uint8_t *iv,
size_t iv_len,
501 const uint8_t *ciphertext,
size_t ct_len,
const uint8_t *icv,
size_t icv_len)
503 if (!buf || (iv_len && !iv) || (ct_len && !ciphertext) || (icv_len && !icv))
507 size_t total = PC_IKE_PAYLOAD_HDR_LEN + iv_len + ct_len + icv_len;
508 if (!put_pl_hdr(buf, cap, next_payload, total))
512 size_t off = PC_IKE_PAYLOAD_HDR_LEN;
515 memcpy(buf + off, iv, iv_len);
520 memcpy(buf + off, ciphertext, ct_len);
525 memcpy(buf + off, icv, icv_len);
532size_t pc_ike_skf_build(uint8_t *buf,
size_t cap, IkePayloadType next_payload, uint16_t frag_num, uint16_t total,
533 const uint8_t *iv,
size_t iv_len,
const uint8_t *ciphertext,
size_t ct_len,
const uint8_t *icv,
536 if (!buf || (iv_len && !iv) || (ct_len && !ciphertext) || (icv_len && !icv))
540 if (frag_num == 0 || total == 0 || frag_num > total)
544 size_t body = PC_IKE_PAYLOAD_HDR_LEN + 4 + iv_len + ct_len + icv_len;
545 if (!put_pl_hdr(buf, cap, next_payload, body))
549 put16(buf + PC_IKE_PAYLOAD_HDR_LEN, frag_num);
550 put16(buf + PC_IKE_PAYLOAD_HDR_LEN + 2, total);
551 size_t off = PC_IKE_PAYLOAD_HDR_LEN + 4;
554 memcpy(buf + off, iv, iv_len);
559 memcpy(buf + off, ciphertext, ct_len);
564 memcpy(buf + off, icv, icv_len);
569bool pc_ike_skf_parse(
const uint8_t *body,
size_t body_len, uint16_t *frag_num, uint16_t *total,
size_t iv_len,
570 size_t icv_len,
const uint8_t **iv,
const uint8_t **ct,
size_t *ct_len,
const uint8_t **icv)
597 if (!body || body_len < 4 + iv_len + icv_len)
601 uint16_t fn = get16(body);
602 uint16_t tf = get16(body + 2);
603 if (fn == 0 || tf == 0 || fn > tf)
621 *ct = body + 4 + iv_len;
625 *ct_len = body_len - 4 - iv_len - icv_len;
629 *icv = body + body_len - icv_len;
634void pc_ike_frag_reasm_init(IkeFragReasm *r, uint8_t *pool,
size_t pool_cap)
642 memset(r->present, 0,
sizeof(r->present));
644 r->pool_cap = pool_cap;
648bool pc_ike_frag_reasm_add(IkeFragReasm *r, uint16_t frag_num, uint16_t total,
const uint8_t *chunk,
size_t len)
650 if (!r || !r->pool || (len && !chunk))
654 if (frag_num == 0 || total == 0 || frag_num > total || total > PC_IKE_FRAG_MAX)
662 else if (r->total != total)
666 uint16_t idx = (uint16_t)(frag_num - 1);
671 if (len > r->pool_cap - r->pool_used)
677 memcpy(r->pool + r->pool_used, chunk, len);
679 r->off[idx] = r->pool_used;
681 r->present[idx] =
true;
687bool pc_ike_frag_reasm_complete(
const IkeFragReasm *r)
689 return r && r->total != 0 && r->count == r->total;
692size_t pc_ike_frag_reasm_assemble(
const IkeFragReasm *r, uint8_t *out,
size_t out_cap)
694 if (!pc_ike_frag_reasm_complete(r) || !out)
699 for (uint16_t i = 0; i < r->total; i++)
701 if (off + r->len[i] > out_cap)
707 memcpy(out + off, r->pool + r->off[i], r->len[i]);
716size_t pc_ike_cookie_compute(uint8_t version,
const uint8_t *secret,
size_t secret_len,
const uint8_t *ni,
717 size_t ni_len,
const uint8_t *ipi,
size_t ipi_len,
const uint8_t spii[PC_IKE_SPI_LEN],
718 uint8_t *out,
size_t out_cap)
720 if (!out || out_cap < PC_IKE_COOKIE_LEN || !spii)
724 if ((ni_len && !ni) || (ipi_len && !ipi) || (secret_len && !secret))
746 return PC_IKE_COOKIE_LEN;
749bool pc_ike_cookie_verify(
const uint8_t *cookie,
size_t cookie_len,
const uint8_t *secret,
size_t secret_len,
750 const uint8_t *ni,
size_t ni_len,
const uint8_t *ipi,
size_t ipi_len,
751 const uint8_t spii[PC_IKE_SPI_LEN])
753 if (!cookie || cookie_len != PC_IKE_COOKIE_LEN)
757 uint8_t expect[PC_IKE_COOKIE_LEN];
758 if (pc_ike_cookie_compute(cookie[0], secret, secret_len, ni, ni_len, ipi, ipi_len, spii, expect,
sizeof(expect)) !=
765 for (
size_t i = 0; i < PC_IKE_COOKIE_LEN; i++)
767 diff |= (uint8_t)(expect[i] ^ cookie[i]);
772size_t pc_ike_cookie_notify_build(uint8_t *buf,
size_t cap, IkePayloadType next_payload,
const uint8_t *cookie,
775 return pc_ike_notify_build(buf, cap, next_payload, IkeProtocol::IKE_PROTO_NONE,
nullptr, 0, PC_IKE_N_COOKIE, cookie,
781bool pc_ike_ke_parse(
const uint8_t *body,
size_t body_len, uint16_t *dh_group,
const uint8_t **data,
size_t *data_len)
795 if (!body || body_len < 4)
801 *dh_group = get16(body);
809 *data_len = body_len - 4;
814bool pc_ike_id_parse(
const uint8_t *body,
size_t body_len, IkeIdType *id_type,
const uint8_t **data,
size_t *data_len)
818 *id_type = IkeIdType::IKE_ID_RESERVED;
828 if (!body || body_len < 4)
834 *id_type = (IkeIdType)body[0];
842 *data_len = body_len - 4;
847bool pc_ike_auth_parse(
const uint8_t *body,
size_t body_len, IkeAuthMethod *auth_method,
const uint8_t **data,
852 *auth_method = IkeAuthMethod::IKE_AUTH_RESERVED;
862 if (!body || body_len < 4)
868 *auth_method = (IkeAuthMethod)body[0];
876 *data_len = body_len - 4;
881bool pc_ike_notify_parse(
const uint8_t *body,
size_t body_len, IkeProtocol *protocol_id, uint16_t *notify_type,
882 const uint8_t **spi, uint8_t *spi_size,
const uint8_t **data,
size_t *data_len)
886 *protocol_id = IkeProtocol::IKE_PROTO_NONE;
908 if (!body || body_len < 4)
912 uint8_t ss = body[1];
913 if (body_len < (
size_t)4 + ss)
919 *protocol_id = (IkeProtocol)body[0];
927 *notify_type = get16(body + 2);
931 *spi = ss ? body + 4 :
nullptr;
935 *data = body + 4 + ss;
939 *data_len = body_len - 4 - ss;
944bool pc_ike_delete_parse(
const uint8_t *body,
size_t body_len, IkeProtocol *protocol_id, uint8_t *spi_size,
945 uint16_t *num_spis,
const uint8_t **spis)
949 *protocol_id = IkeProtocol::IKE_PROTO_NONE;
963 if (!body || body_len < 4)
967 uint8_t ss = body[1];
968 uint16_t num = get16(body + 2);
969 if (body_len < (
size_t)4 + (
size_t)ss * num)
975 *protocol_id = (IkeProtocol)body[0];
987 *spis = (ss && num) ? body + 4 : nullptr;
992bool pc_ike_sk_parse(
const uint8_t *body,
size_t body_len,
size_t iv_len,
size_t icv_len,
const uint8_t **iv,
993 const uint8_t **ciphertext,
size_t *ct_len,
const uint8_t **icv)
1001 *ciphertext =
nullptr;
1011 if (!body || body_len < iv_len + icv_len)
1017 *iv = iv_len ? body :
nullptr;
1021 *ciphertext = body + iv_len;
1025 *ct_len = body_len - iv_len - icv_len;
1029 *icv = icv_len ? body + body_len - icv_len :
nullptr;
1036bool pc_ike_sa_first_proposal(
const uint8_t *body,
size_t body_len, IkeProposalRef *out)
1042 memset(out, 0,
sizeof(*out));
1043 if (!body || body_len < 8)
1047 uint16_t plen = get16(body + 2);
1048 uint8_t ss = body[6];
1049 if (plen < 8 || (
size_t)plen > body_len || (
size_t)8 + ss > plen)
1053 out->last = (body[0] == 0);
1054 out->proposal_num = body[4];
1055 out->protocol_id = (IkeProtocol)body[5];
1057 out->num_transforms = body[7];
1058 out->spi = ss ? body + 8 :
nullptr;
1059 out->transforms = body + 8 + ss;
1060 out->transforms_len = (size_t)plen - 8 - ss;
1064void pc_ike_transform_iter_init(IkeTransformIter *it,
const IkeProposalRef *p)
1070 it->area = p ? p->transforms :
nullptr;
1071 it->len = p ? p->transforms_len : 0;
1075bool pc_ike_transform_next(IkeTransformIter *it, IkeTransformRef *out)
1081 out->type = IkeTransformType::IKE_TRANSFORM_ENCR;
1083 out->key_length = -1;
1085 if (!it || !it->area || it->off + 8 > it->len)
1089 const uint8_t *t = it->area + it->off;
1090 uint16_t tlen = get16(t + 2);
1091 if (tlen < 8 || it->off + tlen > it->len)
1095 out->last = (t[0] == 0);
1096 out->type = (IkeTransformType)t[4];
1097 out->id = get16(t + 6);
1102 while (ao + 4 <= tlen)
1104 uint16_t af_type = get16(t + ao);
1105 uint16_t atype = af_type & 0x7FFF;
1106 if (af_type & 0x8000)
1108 if (atype == IKE_ATTR_KEY_LENGTH)
1110 out->key_length = get16(t + ao + 2);
1116 uint16_t alen = get16(t + ao + 2);
1117 ao += (size_t)4 + alen;
1126uint8_t pc_ike_ts_count(
const uint8_t *body,
size_t body_len)
1128 if (!body || body_len < 4)
1135bool pc_ike_ts_get(
const uint8_t *body,
size_t body_len, uint8_t index, IkeTrafficSelector *out)
1141 memset(out, 0,
sizeof(*out));
1142 if (!body || body_len < 4)
1146 uint8_t num = body[0];
1154 for (uint8_t i = 0; i < num; i++)
1156 if (off + 8 > body_len)
1160 uint16_t sel_len = get16(body + off + 2);
1161 if (sel_len < 8 || off + sel_len > body_len || ((sel_len - 8) % 2) != 0)
1167 size_t addr_len = (size_t)(sel_len - 8) / 2;
1168 out->ts_type = (IkeTsType)body[off];
1169 out->ip_protocol = body[off + 1];
1170 out->start_port = get16(body + off + 4);
1171 out->end_port = get16(body + off + 6);
1172 out->start_addr = body + off + 8;
1173 out->end_addr = body + off + 8 + addr_len;
1174 out->addr_len = addr_len;
1182bool pc_ike_cp_parse(
const uint8_t *body,
size_t body_len, IkeCfgType *cfg_type,
const uint8_t **attrs,
1187 *cfg_type = IkeCfgType::IKE_CFG_REQUEST;
1197 if (!body || body_len < 4)
1203 *cfg_type = (IkeCfgType)body[0];
1211 *attrs_len = body_len - 4;
1216void pc_ike_cp_attr_iter_init(IkeCfgAttrIter *it,
const uint8_t *attrs,
size_t attrs_len)
1223 it->len = attrs_len;
1227bool pc_ike_cp_attr_next(IkeCfgAttrIter *it, IkeCfgAttr *out)
1229 if (!it || !out || !it->area)
1233 if (it->off + 4 > it->len)
1237 const uint8_t *p = it->area + it->off;
1238 uint16_t vlen = get16(p + 2);
1239 if (it->off + 4 + vlen > it->len)
1243 out->type = get16(p) & 0x7FFF;
1244 out->value_len = vlen;
1245 out->value = vlen ? (p + 4) : nullptr;
1246 it->off += 4 + vlen;
1252bool pc_ike_prf_plus(
const uint8_t *key,
size_t key_len,
const uint8_t *seed,
size_t seed_len, uint8_t *out,
1255 if (!key || !seed || !out || out_len == 0)
1267 size_t produced = 0;
1268 uint8_t counter = 0;
1269 while (produced < out_len)
1283 size_t take = out_len - produced;
1288 memcpy(out + produced, t, take);
1295static size_t build_ni_nr_spi(uint8_t *s,
const uint8_t *ni,
size_t ni_len,
const uint8_t *nr,
size_t nr_len,
1296 const uint8_t *spi_i,
const uint8_t *spi_r)
1298 if (ni_len == 0 || ni_len > PC_IKE_NONCE_MAX || nr_len == 0 || nr_len > PC_IKE_NONCE_MAX)
1302 size_t nlen = ni_len + nr_len;
1303 memcpy(s, ni, ni_len);
1304 memcpy(s + ni_len, nr, nr_len);
1305 memcpy(s + nlen, spi_i, PC_IKE_SPI_LEN);
1306 memcpy(s + nlen + PC_IKE_SPI_LEN, spi_r, PC_IKE_SPI_LEN);
1307 return nlen + 2 * PC_IKE_SPI_LEN;
1312static bool sk_split_from_skeyseed(
const uint8_t skeyseed[PC_IKE_PRF_LEN],
const uint8_t *s,
size_t s_len,
1313 const IkeKeyLengths *lens, IkeKeyMaterial *out)
1317 if (lens->sk_d == 0 || lens->sk_d > PC_IKE_SK_MAX || lens->sk_a > PC_IKE_SK_MAX || lens->sk_e == 0 ||
1318 lens->sk_e > PC_IKE_SK_MAX || lens->sk_p == 0 || lens->sk_p > PC_IKE_SK_MAX)
1322 size_t total = lens->sk_d + 2 * lens->sk_a + 2 * lens->sk_e + 2 * lens->sk_p;
1323 uint8_t ks[7 * PC_IKE_SK_MAX];
1324 if (!pc_ike_prf_plus(skeyseed, PC_IKE_PRF_LEN, s, s_len, ks, total))
1330 memcpy(out->sk_d, ks + o, lens->sk_d);
1332 memcpy(out->sk_ai, ks + o, lens->sk_a);
1334 memcpy(out->sk_ar, ks + o, lens->sk_a);
1336 memcpy(out->sk_ei, ks + o, lens->sk_e);
1338 memcpy(out->sk_er, ks + o, lens->sk_e);
1340 memcpy(out->sk_pi, ks + o, lens->sk_p);
1342 memcpy(out->sk_pr, ks + o, lens->sk_p);
1343 out->sk_d_len = lens->sk_d;
1344 out->sk_a_len = lens->sk_a;
1345 out->sk_e_len = lens->sk_e;
1346 out->sk_p_len = lens->sk_p;
1350bool pc_ike_derive_keys(
const uint8_t *dh_secret,
size_t dh_len,
const uint8_t *ni,
size_t ni_len,
const uint8_t *nr,
1351 size_t nr_len,
const uint8_t *spi_i,
const uint8_t *spi_r,
const IkeKeyLengths *lens,
1352 IkeKeyMaterial *out)
1354 if (!dh_secret || !ni || !nr || !spi_i || !spi_r || !lens || !out)
1359 uint8_t s[2 * PC_IKE_NONCE_MAX + 2 * PC_IKE_SPI_LEN];
1360 size_t s_len = build_ni_nr_spi(s, ni, ni_len, nr, nr_len, spi_i, spi_r);
1366 uint8_t skeyseed[PC_IKE_PRF_LEN];
1368 return sk_split_from_skeyseed(skeyseed, s, s_len, lens, out);
1371bool pc_ike_rekey_derive_keys(
const uint8_t *sk_d_old,
size_t sk_d_old_len,
const uint8_t *dh_secret,
size_t dh_len,
1372 const uint8_t *ni,
size_t ni_len,
const uint8_t *nr,
size_t nr_len,
const uint8_t *spi_i,
1373 const uint8_t *spi_r,
const IkeKeyLengths *lens, IkeKeyMaterial *out)
1375 if (!sk_d_old || !dh_secret || !ni || !nr || !spi_i || !spi_r || !lens || !out)
1379 if (dh_len == 0 || dh_len > PC_IKE_X25519_LEN || ni_len > PC_IKE_NONCE_MAX || nr_len > PC_IKE_NONCE_MAX)
1385 uint8_t seed[PC_IKE_X25519_LEN + 2 * PC_IKE_NONCE_MAX];
1387 memcpy(seed, dh_secret, dh_len);
1389 memcpy(seed + sl, ni, ni_len);
1391 memcpy(seed + sl, nr, nr_len);
1393 uint8_t skeyseed[PC_IKE_PRF_LEN];
1397 uint8_t s[2 * PC_IKE_NONCE_MAX + 2 * PC_IKE_SPI_LEN];
1398 size_t s_len = build_ni_nr_spi(s, ni, ni_len, nr, nr_len, spi_i, spi_r);
1403 return sk_split_from_skeyseed(skeyseed, s, s_len, lens, out);
1409static void ike_gcm_nonce(uint8_t nonce[
PC_AESGCM_IV_LEN],
const uint8_t *salt,
const uint8_t *iv)
1411 memcpy(nonce, salt, PC_IKE_GCM_SALT_LEN);
1412 memcpy(nonce + PC_IKE_GCM_SALT_LEN, iv, PC_IKE_GCM_IV_LEN);
1415bool pc_ike_sk_aead_seal(
const uint8_t key[PC_IKE_AEAD_KEY_LEN],
const uint8_t salt[PC_IKE_GCM_SALT_LEN],
1416 const uint8_t iv[PC_IKE_GCM_IV_LEN],
const uint8_t *aad,
size_t aad_len,
const uint8_t *pt,
1417 size_t pt_len, uint8_t *out)
1419 if (!key || !salt || !iv || !out || (pt_len && !pt) || (aad_len && !aad))
1424 ike_gcm_nonce(nonce, salt, iv);
1433 pc_aesgcm_seal(gcm, nonce, aad, aad_len, pt, pt_len, out, out + pt_len);
1439bool pc_ike_sk_aead_open(
const uint8_t key[PC_IKE_AEAD_KEY_LEN],
const uint8_t salt[PC_IKE_GCM_SALT_LEN],
1440 const uint8_t iv[PC_IKE_GCM_IV_LEN],
const uint8_t *aad,
size_t aad_len,
const uint8_t *ct,
1441 size_t ct_len,
const uint8_t tag[PC_IKE_AEAD_ICV_LEN], uint8_t *out)
1443 if (!key || !salt || !iv || !tag || !out || (ct_len && !ct) || (aad_len && !aad))
1448 ike_gcm_nonce(nonce, salt, iv);
1456 ok =
pc_aesgcm_open(gcm, nonce, aad, aad_len, ct, ct_len, tag, out);
1464size_t pc_ike_dh_public(uint16_t group,
const uint8_t *our_priv,
size_t priv_len, uint8_t *out,
size_t out_cap)
1466 if (!our_priv || !out)
1470 if (group == IKE_DH_CURVE25519)
1472 if (priv_len != PC_IKE_X25519_LEN || out_cap < PC_IKE_X25519_LEN)
1477 return PC_IKE_X25519_LEN;
1482size_t pc_ike_dh_compute(uint16_t group,
const uint8_t *our_priv,
size_t priv_len,
const uint8_t *peer_pub,
1483 size_t pub_len, uint8_t *out,
size_t out_cap)
1485 if (!our_priv || !peer_pub || !out)
1489 if (group == IKE_DH_CURVE25519)
1491 if (priv_len != PC_IKE_X25519_LEN || pub_len != PC_IKE_X25519_LEN || out_cap < PC_IKE_X25519_LEN)
1496 return PC_IKE_X25519_LEN;
1503bool pc_ike_auth_psk(
const uint8_t *psk,
size_t psk_len,
const uint8_t *real_msg,
size_t real_len,
1504 const uint8_t *peer_nonce,
size_t nonce_len,
const uint8_t *sk_p,
size_t sk_p_len,
1505 const uint8_t *id_body,
size_t id_body_len, uint8_t out[PC_IKE_AUTH_LEN])
1507 if (!psk || !real_msg || !peer_nonce || !sk_p || !id_body || !out)
1513 uint8_t macid[PC_IKE_AUTH_LEN];
1517 uint8_t keypad[PC_IKE_AUTH_LEN];
1518 static const char pad[] = PC_IKE_PSK_PAD;
1519 pc_hmac_sha256(psk, psk_len, (
const uint8_t *)pad,
sizeof(pad) - 1, keypad);
1533size_t pc_ike_sa_init_build(uint8_t *buf,
size_t cap,
const uint8_t init_spi[PC_IKE_SPI_LEN],
1534 const uint8_t resp_spi[PC_IKE_SPI_LEN], uint32_t msg_id,
bool is_response,
1535 uint8_t proposal_num,
const IkeTransform *transforms, uint8_t num_transforms,
1536 uint16_t dh_group,
const uint8_t *ke_data,
size_t ke_len,
const uint8_t *nonce,
1539 if (!buf || !init_spi || !resp_spi || !transforms || num_transforms == 0 || (ke_len && !ke_data) ||
1540 (nonce_len && !nonce))
1546 memcpy(h.init_spi, init_spi, PC_IKE_SPI_LEN);
1547 memcpy(h.resp_spi, resp_spi, PC_IKE_SPI_LEN);
1548 h.next_payload = IkePayloadType::IKE_PL_SA;
1549 h.version = PC_IKE_VERSION;
1550 h.exchange = IkeExchange::IKE_SA_INIT;
1551 h.flags = is_response ? PC_IKE_FLAG_RESPONSE : PC_IKE_FLAG_INITIATOR;
1552 h.message_id = msg_id;
1555 size_t off = pc_ike_hdr_build(buf, cap, &h);
1561 size_t n = pc_ike_sa_build(buf + off, cap - off, IkePayloadType::IKE_PL_KE, proposal_num,
1562 IkeProtocol::IKE_PROTO_IKE,
nullptr, 0, transforms, num_transforms);
1569 n = pc_ike_ke_build(buf + off, cap - off, IkePayloadType::IKE_PL_NONCE, dh_group, ke_data, ke_len);
1576 n = pc_ike_nonce_build(buf + off, cap - off, IkePayloadType::IKE_PL_NONE, nonce, nonce_len);
1583 pc_ike_set_length(buf, cap, (uint32_t)off);
1587bool pc_ike_sa_init_parse(
const uint8_t *msg,
size_t len, IkeSaInitMsg *out)
1593 memset(out, 0,
sizeof(*out));
1596 if (!pc_ike_hdr_parse(msg, len, &h))
1600 if (h.exchange != IkeExchange::IKE_SA_INIT)
1604 if (h.length < PC_IKE_HDR_LEN || h.length > len)
1609 memcpy(out->init_spi, h.init_spi, PC_IKE_SPI_LEN);
1610 memcpy(out->resp_spi, h.resp_spi, PC_IKE_SPI_LEN);
1611 out->is_response = (h.flags & PC_IKE_FLAG_RESPONSE) != 0;
1614 pc_ike_payload_iter_init(&it, h.next_payload, msg + PC_IKE_HDR_LEN, h.length - PC_IKE_HDR_LEN);
1616 bool have_sa =
false, have_ke =
false, have_nonce =
false;
1617 while (pc_ike_payload_next(&it, &pl))
1619 if (pl.type == IkePayloadType::IKE_PL_SA && !have_sa)
1621 have_sa = pc_ike_sa_first_proposal(pl.body, pl.body_len, &out->proposal);
1623 else if (pl.type == IkePayloadType::IKE_PL_KE && !have_ke)
1625 have_ke = pc_ike_ke_parse(pl.body, pl.body_len, &out->dh_group, &out->ke_data, &out->ke_len);
1627 else if (pl.type == IkePayloadType::IKE_PL_NONCE && !have_nonce)
1629 out->nonce = pl.body;
1630 out->nonce_len = pl.body_len;
1634 return have_sa && have_ke && have_nonce;
1641static const size_t IKE_SK_HDR_OFF = PC_IKE_HDR_LEN;
1642static const size_t IKE_SK_IV_OFF = PC_IKE_HDR_LEN + PC_IKE_PAYLOAD_HDR_LEN;
1643static const size_t IKE_SK_CT_OFF = IKE_SK_IV_OFF + PC_IKE_GCM_IV_LEN;
1647static size_t sk_message_build(uint8_t *buf,
size_t cap,
const uint8_t *init_spi,
const uint8_t *resp_spi,
1648 uint32_t msg_id, IkeExchange exchange, uint8_t flags, IkePayloadType first_inner_type,
1649 const uint8_t *inner,
size_t inner_len,
const uint8_t *key,
const uint8_t *salt,
1652 if (!buf || !init_spi || !resp_spi || !key || !salt || !iv || (inner_len && !inner))
1657 size_t pt_len = inner_len + 1;
1658 size_t sk_len = PC_IKE_PAYLOAD_HDR_LEN + PC_IKE_GCM_IV_LEN + pt_len + PC_IKE_AEAD_ICV_LEN;
1659 size_t total = PC_IKE_HDR_LEN + sk_len;
1660 if (total > 0xFFFF || cap < total)
1666 memcpy(h.init_spi, init_spi, PC_IKE_SPI_LEN);
1667 memcpy(h.resp_spi, resp_spi, PC_IKE_SPI_LEN);
1668 h.next_payload = IkePayloadType::IKE_PL_SK;
1669 h.version = PC_IKE_VERSION;
1670 h.exchange = exchange;
1672 h.message_id = msg_id;
1673 h.length = (uint32_t)total;
1674 if (pc_ike_hdr_build(buf, cap, &h) == 0)
1680 buf[IKE_SK_HDR_OFF + 0] = (uint8_t)first_inner_type;
1681 buf[IKE_SK_HDR_OFF + 1] = 0;
1682 put16(buf + IKE_SK_HDR_OFF + 2, (uint16_t)sk_len);
1685 memcpy(buf + IKE_SK_IV_OFF, iv, PC_IKE_GCM_IV_LEN);
1688 memcpy(buf + IKE_SK_CT_OFF, inner, inner_len);
1690 buf[IKE_SK_CT_OFF + inner_len] = 0x00;
1693 pc_ike_sk_aead_seal(key, salt, iv, buf, IKE_SK_IV_OFF, buf + IKE_SK_CT_OFF, pt_len, buf + IKE_SK_CT_OFF);
1697size_t pc_ike_auth_msg_build(uint8_t *buf,
size_t cap,
const uint8_t init_spi[PC_IKE_SPI_LEN],
1698 const uint8_t resp_spi[PC_IKE_SPI_LEN], uint32_t msg_id,
bool is_response,
1699 IkePayloadType first_inner_type,
const uint8_t *inner,
size_t inner_len,
1700 const uint8_t key[PC_IKE_AEAD_KEY_LEN],
const uint8_t salt[PC_IKE_GCM_SALT_LEN],
1701 const uint8_t iv[PC_IKE_GCM_IV_LEN])
1705 uint8_t flags = is_response ? PC_IKE_FLAG_RESPONSE : PC_IKE_FLAG_INITIATOR;
1706 return sk_message_build(buf, cap, init_spi, resp_spi, msg_id, IkeExchange::IKE_AUTH, flags, first_inner_type, inner,
1707 inner_len, key, salt, iv);
1710bool pc_ike_auth_msg_open(uint8_t *msg,
size_t len,
const uint8_t key[PC_IKE_AEAD_KEY_LEN],
1711 const uint8_t salt[PC_IKE_GCM_SALT_LEN], IkePayloadType *first_inner_type,
1712 const uint8_t **inner_out,
size_t *inner_len_out)
1714 if (!msg || !key || !salt || !inner_out || !inner_len_out)
1718 if (first_inner_type)
1720 *first_inner_type = IkePayloadType::IKE_PL_NONE;
1722 *inner_out =
nullptr;
1726 if (!pc_ike_hdr_parse(msg, len, &h))
1730 if (h.next_payload != IkePayloadType::IKE_PL_SK)
1734 if (h.length < IKE_SK_CT_OFF || h.length > len)
1740 size_t sk_len = ((size_t)msg[IKE_SK_HDR_OFF + 2] << 8) | msg[IKE_SK_HDR_OFF + 3];
1741 if (sk_len < PC_IKE_PAYLOAD_HDR_LEN + PC_IKE_GCM_IV_LEN + 1 + PC_IKE_AEAD_ICV_LEN ||
1742 IKE_SK_HDR_OFF + sk_len > h.length)
1747 const uint8_t *ivp = msg + IKE_SK_IV_OFF;
1748 uint8_t *ct = msg + IKE_SK_CT_OFF;
1749 size_t ct_len = sk_len - PC_IKE_PAYLOAD_HDR_LEN - PC_IKE_GCM_IV_LEN - PC_IKE_AEAD_ICV_LEN;
1750 const uint8_t *tag = ct + ct_len;
1753 if (!pc_ike_sk_aead_open(key, salt, ivp, msg, IKE_SK_IV_OFF, ct, ct_len, tag, ct))
1759 uint8_t pad_len = ct[ct_len - 1];
1760 if ((
size_t)pad_len + 1 > ct_len)
1764 if (first_inner_type)
1766 *first_inner_type = (IkePayloadType)msg[IKE_SK_HDR_OFF];
1769 *inner_len_out = ct_len - 1 - pad_len;
1775size_t pc_ike_signed_octets(uint8_t *scratch,
size_t cap,
const uint8_t *real,
size_t real_len,
const uint8_t *nonce,
1776 size_t nonce_len,
const uint8_t *sk_p,
size_t sk_p_len,
const uint8_t *id_body,
1779 if (!scratch || !real || !nonce || !sk_p || !id_body)
1783 size_t total = real_len + nonce_len + PC_IKE_AUTH_LEN;
1788 memcpy(scratch, real, real_len);
1789 memcpy(scratch + real_len, nonce, nonce_len);
1790 pc_hmac_sha256(sk_p, sk_p_len, id_body, id_body_len, scratch + real_len + nonce_len);
1794bool pc_ike_auth_sign_ecdsa_p256(uint8_t sig[PC_IKE_ECDSA_P256_SIG_LEN],
const uint8_t priv[PC_IKE_ECDSA_P256_PRIV_LEN],
1795 uint8_t *scratch,
size_t scratch_cap,
const uint8_t *real,
size_t real_len,
1796 const uint8_t *nonce,
size_t nonce_len,
const uint8_t *sk_p,
size_t sk_p_len,
1797 const uint8_t *id_body,
size_t id_body_len)
1803 size_t n = pc_ike_signed_octets(scratch, scratch_cap, real, real_len, nonce, nonce_len, sk_p, sk_p_len, id_body,
1812bool pc_ike_auth_verify_ecdsa_p256(
const uint8_t pub[PC_IKE_ECDSA_P256_PUB_LEN],
1813 const uint8_t sig[PC_IKE_ECDSA_P256_SIG_LEN], uint8_t *scratch,
size_t scratch_cap,
1814 const uint8_t *real,
size_t real_len,
const uint8_t *nonce,
size_t nonce_len,
1815 const uint8_t *sk_p,
size_t sk_p_len,
const uint8_t *id_body,
size_t id_body_len)
1821 size_t n = pc_ike_signed_octets(scratch, scratch_cap, real, real_len, nonce, nonce_len, sk_p, sk_p_len, id_body,
1832bool pc_ike_suite_keylengths(
const IkeSuite *suite, IkeKeyLengths *out)
1838 if (suite->prf != IKE_PRF_HMAC_SHA2_256)
1843 out->sk_d = PC_IKE_PRF_LEN;
1844 out->sk_p = PC_IKE_PRF_LEN;
1847 if (suite->integ == 0)
1851 else if (suite->integ == IKE_INTEG_HMAC_SHA2_256_128)
1861 if (suite->encr_keylen <= 0 || (suite->encr_keylen % 8) != 0)
1865 size_t ek = (size_t)(suite->encr_keylen / 8);
1866 if (suite->encr == IKE_ENCR_AES_GCM_16)
1868 ek += PC_IKE_GCM_SALT_LEN;
1870 if (ek == 0 || ek > PC_IKE_SK_MAX)
1878bool pc_ike_sa_keys_from_init(IkeSa *sa,
const uint8_t *our_dh_priv,
size_t our_dh_priv_len,
const uint8_t *peer_ke,
1879 size_t peer_ke_len,
const uint8_t *ni,
size_t ni_len,
const uint8_t *nr,
size_t nr_len)
1881 if (!sa || !our_dh_priv || !peer_ke || !ni || !nr)
1886 if (!pc_ike_suite_keylengths(&sa->suite, &lens))
1891 uint8_t shared[PC_IKE_X25519_LEN];
1893 pc_ike_dh_compute(sa->suite.dh, our_dh_priv, our_dh_priv_len, peer_ke, peer_ke_len, shared,
sizeof(shared));
1899 return pc_ike_derive_keys(shared, sh, ni, ni_len, nr, nr_len, sa->init_spi, sa->resp_spi, &lens, &sa->keys);
1904size_t pc_ike_initiator_start(IkeHandshake *hs,
const uint8_t our_spi[PC_IKE_SPI_LEN],
1905 const uint8_t our_dh_priv[PC_IKE_X25519_LEN],
const uint8_t our_dh_pub[PC_IKE_X25519_LEN],
1906 const uint8_t *our_nonce,
size_t nonce_len,
const IkeSuite *suite,
1907 const IkeTransform *transforms, uint8_t num_transforms, uint8_t *out,
size_t out_cap)
1909 if (!hs || !our_spi || !our_dh_priv || !our_dh_pub || !our_nonce || !suite || !transforms || num_transforms == 0)
1913 if (nonce_len == 0 || nonce_len > PC_IKE_NONCE_MAX)
1918 memset(hs, 0,
sizeof(*hs));
1919 memcpy(hs->sa.init_spi, our_spi, PC_IKE_SPI_LEN);
1920 hs->sa.is_initiator =
true;
1921 hs->sa.suite = *suite;
1922 memcpy(hs->our_dh_priv, our_dh_priv, PC_IKE_X25519_LEN);
1923 memcpy(hs->our_nonce, our_nonce, nonce_len);
1924 hs->our_nonce_len = (uint16_t)nonce_len;
1926 uint8_t zero_spi[PC_IKE_SPI_LEN] = {0};
1927 size_t n = pc_ike_sa_init_build(out, out_cap, our_spi, zero_spi, 0,
false, 1, transforms,
1928 num_transforms, suite->dh, our_dh_pub, PC_IKE_X25519_LEN, our_nonce, nonce_len);
1929 if (n == 0 || n > PC_IKE_MSG_MAX)
1931 hs->state = IkeState::IKE_ST_FAILED;
1934 memcpy(hs->init_msg, out, n);
1935 hs->init_msg_len = (uint16_t)n;
1936 hs->state = IkeState::IKE_ST_SA_INIT_SENT;
1940bool pc_ike_initiator_on_sa_init(IkeHandshake *hs,
const uint8_t *resp,
size_t resp_len)
1942 if (!hs || !resp || hs->state != IkeState::IKE_ST_SA_INIT_SENT)
1948 if (!pc_ike_sa_init_parse(resp, resp_len, &m))
1950 hs->state = IkeState::IKE_ST_FAILED;
1954 if (!m.is_response || memcmp(m.init_spi, hs->sa.init_spi, PC_IKE_SPI_LEN) != 0 || m.dh_group != hs->sa.suite.dh)
1956 hs->state = IkeState::IKE_ST_FAILED;
1959 memcpy(hs->sa.resp_spi, m.resp_spi, PC_IKE_SPI_LEN);
1962 if (m.nonce_len == 0 || m.nonce_len > PC_IKE_NONCE_MAX)
1964 hs->state = IkeState::IKE_ST_FAILED;
1967 memcpy(hs->peer_nonce, m.nonce, m.nonce_len);
1968 hs->peer_nonce_len = (uint16_t)m.nonce_len;
1971 if (resp_len > PC_IKE_MSG_MAX)
1973 hs->state = IkeState::IKE_ST_FAILED;
1976 memcpy(hs->resp_msg, resp, resp_len);
1977 hs->resp_msg_len = (uint16_t)resp_len;
1980 if (!pc_ike_sa_keys_from_init(&hs->sa, hs->our_dh_priv, PC_IKE_X25519_LEN, m.ke_data, m.ke_len, hs->our_nonce,
1981 hs->our_nonce_len, m.nonce, m.nonce_len))
1983 hs->state = IkeState::IKE_ST_FAILED;
1986 hs->state = IkeState::IKE_ST_SA_INIT_DONE;
1990size_t pc_ike_initiator_build_auth_psk(IkeHandshake *hs, IkeIdType idi_type,
const uint8_t *idi_data,
size_t idi_len,
1991 const uint8_t *psk,
size_t psk_len,
const uint8_t iv[PC_IKE_GCM_IV_LEN],
1992 uint8_t *out,
size_t out_cap)
1994 if (!hs || !idi_data || !psk || !iv || !out)
1998 if (hs->state != IkeState::IKE_ST_SA_INIT_DONE)
2004 uint8_t inner[PC_IKE_MSG_MAX];
2005 size_t idn = pc_ike_id_build(inner,
sizeof(inner), IkePayloadType::IKE_PL_AUTH, idi_type, idi_data, idi_len);
2011 const uint8_t *idi_body = inner + PC_IKE_PAYLOAD_HDR_LEN;
2012 size_t idi_body_len = idn - PC_IKE_PAYLOAD_HDR_LEN;
2013 uint8_t auth[PC_IKE_AUTH_LEN];
2014 if (!pc_ike_auth_psk(psk, psk_len, hs->init_msg, hs->init_msg_len, hs->peer_nonce, hs->peer_nonce_len,
2015 hs->sa.keys.sk_pi, hs->sa.keys.sk_p_len, idi_body, idi_body_len, auth))
2019 size_t an = pc_ike_auth_build(inner + idn,
sizeof(inner) - idn, IkePayloadType::IKE_PL_NONE,
2020 IkeAuthMethod::IKE_AUTH_PSK, auth,
sizeof(auth));
2027 size_t n = pc_ike_auth_msg_build(out, out_cap, hs->sa.init_spi, hs->sa.resp_spi, 1,
false,
2028 IkePayloadType::IKE_PL_IDI, inner, idn + an, hs->sa.keys.sk_ei,
2029 hs->sa.keys.sk_ei + PC_IKE_AEAD_KEY_LEN, iv);
2034 hs->state = IkeState::IKE_ST_AUTH_SENT;
2038bool pc_ike_initiator_on_auth_psk(IkeHandshake *hs,
const uint8_t *resp,
size_t resp_len,
const uint8_t *psk,
2041 if (!hs || !resp || !psk || hs->state != IkeState::IKE_ST_AUTH_SENT)
2045 if (resp_len == 0 || resp_len > PC_IKE_MSG_MAX)
2047 hs->state = IkeState::IKE_ST_FAILED;
2052 uint8_t work[PC_IKE_MSG_MAX];
2053 memcpy(work, resp, resp_len);
2054 IkePayloadType first = IkePayloadType::IKE_PL_NONE;
2055 const uint8_t *inner =
nullptr;
2056 size_t inner_len = 0;
2057 if (!pc_ike_auth_msg_open(work, resp_len, hs->sa.keys.sk_er, hs->sa.keys.sk_er + PC_IKE_AEAD_KEY_LEN, &first,
2058 &inner, &inner_len))
2060 hs->state = IkeState::IKE_ST_FAILED;
2066 pc_ike_payload_iter_init(&it, first, inner, inner_len);
2068 const uint8_t *idr_body =
nullptr, *auth_body =
nullptr;
2069 size_t idr_body_len = 0, auth_body_len = 0;
2070 while (pc_ike_payload_next(&it, &pl))
2072 if (pl.type == IkePayloadType::IKE_PL_IDR && !idr_body)
2075 idr_body_len = pl.body_len;
2077 else if (pl.type == IkePayloadType::IKE_PL_AUTH && !auth_body)
2079 auth_body = pl.body;
2080 auth_body_len = pl.body_len;
2083 IkeAuthMethod method = IkeAuthMethod::IKE_AUTH_RESERVED;
2084 const uint8_t *authdata =
nullptr;
2085 size_t authdata_len = 0;
2086 if (!idr_body || !auth_body || !pc_ike_auth_parse(auth_body, auth_body_len, &method, &authdata, &authdata_len) ||
2087 method != IkeAuthMethod::IKE_AUTH_PSK || authdata_len != PC_IKE_AUTH_LEN)
2089 hs->state = IkeState::IKE_ST_FAILED;
2094 uint8_t expect[PC_IKE_AUTH_LEN];
2095 if (!pc_ike_auth_psk(psk, psk_len, hs->resp_msg, hs->resp_msg_len, hs->our_nonce, hs->our_nonce_len,
2096 hs->sa.keys.sk_pr, hs->sa.keys.sk_p_len, idr_body, idr_body_len, expect))
2098 hs->state = IkeState::IKE_ST_FAILED;
2103 for (
size_t i = 0; i < PC_IKE_AUTH_LEN; i++)
2105 diff |= (uint8_t)(expect[i] ^ authdata[i]);
2109 hs->state = IkeState::IKE_ST_FAILED;
2113 hs->state = IkeState::IKE_ST_ESTABLISHED;
2119size_t pc_ike_responder_on_sa_init(IkeHandshake *hs,
const uint8_t *req,
size_t req_len,
2120 const uint8_t our_spi[PC_IKE_SPI_LEN],
const uint8_t our_dh_priv[PC_IKE_X25519_LEN],
2121 const uint8_t our_dh_pub[PC_IKE_X25519_LEN],
const uint8_t *our_nonce,
2122 size_t nonce_len,
const IkeSuite *suite,
const IkeTransform *transforms,
2123 uint8_t num_transforms, uint8_t *out,
size_t out_cap)
2125 if (!hs || !req || !our_spi || !our_dh_priv || !our_dh_pub || !our_nonce || !suite || !transforms ||
2126 num_transforms == 0)
2130 if (nonce_len == 0 || nonce_len > PC_IKE_NONCE_MAX || req_len > PC_IKE_MSG_MAX)
2136 if (!pc_ike_sa_init_parse(req, req_len, &m))
2141 if (m.is_response || m.dh_group != suite->dh || m.nonce_len == 0 || m.nonce_len > PC_IKE_NONCE_MAX)
2146 memset(hs, 0,
sizeof(*hs));
2147 hs->sa.is_initiator =
false;
2148 hs->sa.suite = *suite;
2149 memcpy(hs->sa.init_spi, m.init_spi, PC_IKE_SPI_LEN);
2150 memcpy(hs->sa.resp_spi, our_spi, PC_IKE_SPI_LEN);
2151 memcpy(hs->our_dh_priv, our_dh_priv, PC_IKE_X25519_LEN);
2152 memcpy(hs->our_nonce, our_nonce, nonce_len);
2153 hs->our_nonce_len = (uint16_t)nonce_len;
2154 memcpy(hs->peer_nonce, m.nonce, m.nonce_len);
2155 hs->peer_nonce_len = (uint16_t)m.nonce_len;
2156 memcpy(hs->init_msg, req, req_len);
2157 hs->init_msg_len = (uint16_t)req_len;
2160 size_t n = pc_ike_sa_init_build(out, out_cap, m.init_spi, our_spi, 0,
true, 1, transforms,
2161 num_transforms, suite->dh, our_dh_pub, PC_IKE_X25519_LEN, our_nonce, nonce_len);
2162 if (n == 0 || n > PC_IKE_MSG_MAX)
2164 hs->state = IkeState::IKE_ST_FAILED;
2167 memcpy(hs->resp_msg, out, n);
2168 hs->resp_msg_len = (uint16_t)n;
2171 if (!pc_ike_sa_keys_from_init(&hs->sa, our_dh_priv, PC_IKE_X25519_LEN, m.ke_data, m.ke_len, hs->peer_nonce,
2172 hs->peer_nonce_len, hs->our_nonce, hs->our_nonce_len))
2174 hs->state = IkeState::IKE_ST_FAILED;
2177 hs->state = IkeState::IKE_ST_SA_INIT_DONE;
2182static bool ike_ct_eq32(
const uint8_t *a,
const uint8_t *b)
2185 for (
size_t i = 0; i < PC_IKE_AUTH_LEN; i++)
2187 diff |= (uint8_t)(a[i] ^ b[i]);
2193static bool ike_find_id_auth(IkePayloadType first,
const uint8_t *inner,
size_t inner_len, IkePayloadType id_type,
2194 const uint8_t **id_body,
size_t *id_body_len,
const uint8_t **authdata,
2195 size_t *authdata_len)
2198 pc_ike_payload_iter_init(&it, first, inner, inner_len);
2200 const uint8_t *auth_body =
nullptr;
2201 size_t auth_body_len = 0;
2204 while (pc_ike_payload_next(&it, &pl))
2206 if (pl.type == id_type && !*id_body)
2209 *id_body_len = pl.body_len;
2211 else if (pl.type == IkePayloadType::IKE_PL_AUTH && !auth_body)
2213 auth_body = pl.body;
2214 auth_body_len = pl.body_len;
2217 IkeAuthMethod method = IkeAuthMethod::IKE_AUTH_RESERVED;
2218 if (!*id_body || !auth_body || !pc_ike_auth_parse(auth_body, auth_body_len, &method, authdata, authdata_len) ||
2219 method != IkeAuthMethod::IKE_AUTH_PSK || *authdata_len != PC_IKE_AUTH_LEN)
2226size_t pc_ike_responder_on_auth_psk(IkeHandshake *hs,
const uint8_t *req,
size_t req_len,
const uint8_t *psk,
2227 size_t psk_len, IkeIdType idr_type,
const uint8_t *idr_data,
size_t idr_len,
2228 const uint8_t iv[PC_IKE_GCM_IV_LEN], uint8_t *out,
size_t out_cap)
2230 if (!hs || !req || !psk || !idr_data || !iv || !out)
2234 if (hs->state != IkeState::IKE_ST_SA_INIT_DONE || hs->sa.is_initiator)
2238 if (req_len == 0 || req_len > PC_IKE_MSG_MAX)
2240 hs->state = IkeState::IKE_ST_FAILED;
2245 uint8_t work[PC_IKE_MSG_MAX];
2246 memcpy(work, req, req_len);
2247 IkePayloadType first = IkePayloadType::IKE_PL_NONE;
2248 const uint8_t *inner =
nullptr;
2249 size_t inner_len = 0;
2250 const uint8_t *idi_body =
nullptr, *authdata =
nullptr;
2251 size_t idi_body_len = 0, authdata_len = 0;
2252 if (!pc_ike_auth_msg_open(work, req_len, hs->sa.keys.sk_ei, hs->sa.keys.sk_ei + PC_IKE_AEAD_KEY_LEN, &first, &inner,
2254 !ike_find_id_auth(first, inner, inner_len, IkePayloadType::IKE_PL_IDI, &idi_body, &idi_body_len, &authdata,
2257 hs->state = IkeState::IKE_ST_FAILED;
2262 uint8_t expect[PC_IKE_AUTH_LEN];
2263 if (!pc_ike_auth_psk(psk, psk_len, hs->init_msg, hs->init_msg_len, hs->our_nonce, hs->our_nonce_len,
2264 hs->sa.keys.sk_pi, hs->sa.keys.sk_p_len, idi_body, idi_body_len, expect) ||
2265 !ike_ct_eq32(expect, authdata))
2267 hs->state = IkeState::IKE_ST_FAILED;
2272 uint8_t rinner[PC_IKE_MSG_MAX];
2273 size_t ridn = pc_ike_id_build(rinner,
sizeof(rinner), IkePayloadType::IKE_PL_AUTH, idr_type, idr_data, idr_len);
2276 hs->state = IkeState::IKE_ST_FAILED;
2279 uint8_t rauth[PC_IKE_AUTH_LEN];
2280 if (!pc_ike_auth_psk(psk, psk_len, hs->resp_msg, hs->resp_msg_len, hs->peer_nonce, hs->peer_nonce_len,
2281 hs->sa.keys.sk_pr, hs->sa.keys.sk_p_len, rinner + PC_IKE_PAYLOAD_HDR_LEN,
2282 ridn - PC_IKE_PAYLOAD_HDR_LEN, rauth))
2284 hs->state = IkeState::IKE_ST_FAILED;
2287 size_t ran = pc_ike_auth_build(rinner + ridn,
sizeof(rinner) - ridn, IkePayloadType::IKE_PL_NONE,
2288 IkeAuthMethod::IKE_AUTH_PSK, rauth,
sizeof(rauth));
2291 hs->state = IkeState::IKE_ST_FAILED;
2295 size_t n = pc_ike_auth_msg_build(out, out_cap, hs->sa.init_spi, hs->sa.resp_spi, 1,
true,
2296 IkePayloadType::IKE_PL_IDR, rinner, ridn + ran, hs->sa.keys.sk_er,
2297 hs->sa.keys.sk_er + PC_IKE_AEAD_KEY_LEN, iv);
2300 hs->state = IkeState::IKE_ST_FAILED;
2303 hs->state = IkeState::IKE_ST_ESTABLISHED;
2311static size_t sk_send_build(
const IkeSa *sa,
bool is_response, uint32_t msg_id, IkeExchange exchange,
2312 IkePayloadType first_inner_type,
const uint8_t *inner,
size_t inner_len,
const uint8_t *iv,
2313 uint8_t *out,
size_t out_cap)
2315 if (!sa || !iv || !out)
2319 const uint8_t *key = sa->is_initiator ? sa->keys.sk_ei : sa->keys.sk_er;
2321 (uint8_t)((sa->is_initiator ? PC_IKE_FLAG_INITIATOR : 0) | (is_response ? PC_IKE_FLAG_RESPONSE : 0));
2322 return sk_message_build(out, out_cap, sa->init_spi, sa->resp_spi, msg_id, exchange, flags, first_inner_type, inner,
2323 inner_len, key, key + PC_IKE_AEAD_KEY_LEN, iv);
2326size_t pc_ike_informational_build(
const IkeSa *sa,
bool is_response, uint32_t msg_id, IkePayloadType first_inner_type,
2327 const uint8_t *inner,
size_t inner_len,
const uint8_t iv[PC_IKE_GCM_IV_LEN],
2328 uint8_t *out,
size_t out_cap)
2330 return sk_send_build(sa, is_response, msg_id, IkeExchange::IKE_INFORMATIONAL, first_inner_type, inner, inner_len,
2334size_t pc_ike_create_child_sa_build(
const IkeSa *sa,
bool is_response, uint32_t msg_id, IkePayloadType first_inner_type,
2335 const uint8_t *inner,
size_t inner_len,
const uint8_t iv[PC_IKE_GCM_IV_LEN],
2336 uint8_t *out,
size_t out_cap)
2338 return sk_send_build(sa, is_response, msg_id, IkeExchange::IKE_CREATE_CHILD_SA, first_inner_type, inner, inner_len,
2342bool pc_ike_child_keymat(
const uint8_t *sk_d,
size_t sk_d_len,
const uint8_t *dh_secret,
size_t dh_len,
2343 const uint8_t *ni,
size_t ni_len,
const uint8_t *nr,
size_t nr_len, uint8_t *out,
2346 if (!sk_d || !ni || !nr || !out || out_len == 0)
2350 if (ni_len > PC_IKE_NONCE_MAX || nr_len > PC_IKE_NONCE_MAX || dh_len > PC_IKE_X25519_LEN)
2356 uint8_t seed[PC_IKE_X25519_LEN + 2 * PC_IKE_NONCE_MAX];
2358 if (dh_secret && dh_len)
2360 memcpy(seed, dh_secret, dh_len);
2363 memcpy(seed + o, ni, ni_len);
2365 memcpy(seed + o, nr, nr_len);
2367 return pc_ike_prf_plus(sk_d, sk_d_len, seed, o, out, out_len);
2370bool pc_ike_informational_open(
const IkeSa *sa, uint8_t *msg,
size_t len, IkePayloadType *first_inner_type,
2371 const uint8_t **inner_out,
size_t *inner_len_out)
2378 const uint8_t *key = sa->is_initiator ? sa->keys.sk_er : sa->keys.sk_ei;
2379 return pc_ike_auth_msg_open(msg, len, key, key + PC_IKE_AEAD_KEY_LEN, first_inner_type, inner_out, inner_len_out);
2384bool pc_ike_auth_verify_rsa_sha256(
const uint8_t *n_be,
const uint8_t *e_be4,
const uint8_t *sig,
size_t sig_len,
2385 uint8_t *scratch,
size_t scratch_cap,
const uint8_t *real,
size_t real_len,
2386 const uint8_t *nonce,
size_t nonce_len,
const uint8_t *sk_p,
size_t sk_p_len,
2387 const uint8_t *id_body,
size_t id_body_len)
2389 if (!n_be || !e_be4 || !sig)
2393 size_t n = pc_ike_signed_octets(scratch, scratch_cap, real, real_len, nonce, nonce_len, sk_p, sk_p_len, id_body,
AES-256-GCM AEAD (RFC 5116) - stateless, detached-tag API.
#define PC_AESGCM_IV_LEN
GCM nonce length (bytes) = fixed_field(4) || invocation_counter(8).
A secure borrow whose acquire and release are one call each.
void pc_x25519(uint8_t out[32], const uint8_t scalar[32], const uint8_t point[32])
X25519 scalar multiplication: out = scalar * point (RFC 7748 §5).
void pc_x25519_base(uint8_t out[32], const uint8_t scalar[32])
X25519 with the standard base point u=9: out = scalar * G.
Curve25519 field arithmetic + X25519 (RFC 7748) for the curve25519-sha256 KEX.
bool pc_ecdsa_p256_verify(const uint8_t pub[PC_ECDSA_P256_PUB_LEN], const uint8_t *msg, size_t mlen, const uint8_t sig[PC_ECDSA_P256_SIG_LEN])
Verify a P-256 ECDSA signature (SHA-256) against an uncompressed public point.
bool pc_ecdsa_p256_sign(uint8_t sig[PC_ECDSA_P256_SIG_LEN], const uint8_t *msg, size_t mlen, const uint8_t priv[PC_ECDSA_P256_PRIV_LEN])
Sign mlen bytes of msg with a P-256 private key (ECDSA, SHA-256).
NIST P-256 primitives for SSH: ECDSA signatures and ECDH (RFC 5656 / FIPS 186-4).
void pc_hmac_sha256(const uint8_t *key, size_t key_len, const uint8_t *data, size_t len, uint8_t mac[PC_HMAC_SHA256_LEN])
Compute HMAC-SHA2-256 over a single contiguous buffer.
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.
IKEv2 (RFC 7296) message + payload codec (PC_ENABLE_IKEV2) - a zero-heap builder / parser for the Int...
bool pc_aesgcm_open(pc_aesgcm_key *k, const uint8_t nonce[PC_AESGCM_IV_LEN], const uint8_t *aad, size_t aad_len, const uint8_t *ct, size_t ct_len, const uint8_t tag[PC_AESGCM_TAG_LEN], uint8_t *out)
Open one record: verify tag over aad || ct in constant time, then (only on success) decrypt ct into o...
pc_aesgcm_key * pc_aesgcm_key_init(void *storage, const uint8_t key[PC_AESGCM_KEY_LEN])
Bind storage as a context keyed with key.
pc_cspan pc_aesgcm_seal(pc_aesgcm_key *k, const uint8_t nonce[PC_AESGCM_IV_LEN], const uint8_t *aad, size_t aad_len, const uint8_t *pt, size_t pt_len, uint8_t *ct_out, uint8_t tag_out[PC_AESGCM_TAG_LEN])
Seal one record under k and nonce.
void pc_aesgcm_key_wipe(pc_aesgcm_key *k)
Wipe the expanded schedule. Call on rekey and on close; the storage stays the caller's.
int pc_rsa_verify(const uint8_t n_be[PC_RSA_KEY_BYTES], const uint8_t e_be4[4], const uint8_t *msg, size_t msg_len, const uint8_t *sig, size_t sig_len, pc_rsa_hash hash)
Verify an RSA-2048 PKCS#1 v1.5 signature over msg.
RSA-2048 PKCS#1 v1.5 signature primitive (RFC 8017) - verify + software sign.
@ SHA256
RSASSA-PKCS1-v1.5 with SHA-256.
Secure pool accessor - borrows that hold key material.
PC_CRYPTO_HOT void pc_sha256_init(pc_sha256_ctx *ctx)
Initialize a streaming SHA-256 context (ctx must not be NULL).
void pc_sha256_final(pc_sha256_ctx *ctx, uint8_t digest[PC_SHA256_DIGEST_LEN])
Finalize the hash and write the 32-byte digest. The context is undefined afterwards; call init() agai...
void pc_sha256_update(pc_sha256_ctx *ctx, const uint8_t *data, size_t len)
Feed len bytes of data into the running hash.
SHA-256 (FIPS 180-4) - streaming context and one-shot API.
Streaming HMAC-SHA2-256 context.
Streaming SHA-256 context.