Set route to VPN gateway before configuring tunnel
[vpnc.git] / isakmp-pkt.c
blobc85dfb31068e16b86b661ac0d163d63e6c690dcf
1 /* ISAKMP packing and unpacking routines.
2 Copyright (C) 2002 Geoffrey Keating
3 Copyright (C) 2003-2005 Maurice Massar
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 $Id$
22 #include <assert.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <stdio.h>
28 #include "sysdep.h"
29 #include "config.h"
30 #include "isakmp-pkt.h"
31 #include "math_group.h"
32 #include "vpnc.h"
34 void *xallocc(size_t x)
36 void *result;
37 result = calloc(1, x);
38 if (result == NULL)
39 error(1, errno, "malloc of %lu bytes failed", (unsigned long)x);
40 return result;
43 struct flow {
44 size_t len;
45 uint8_t *base;
46 uint8_t *end;
49 static uint8_t *flow_reserve_p(struct flow *f, size_t sz)
51 size_t l = f->end - f->base;
52 if (l + sz > f->len) {
53 size_t new_len = f->len == 0 ? 128 : f->len;
54 while (l + sz >= new_len)
55 new_len *= 2;
57 if (f->base == NULL)
58 f->base = malloc(new_len);
59 else
60 f->base = realloc(f->base, new_len);
61 if (f->base == NULL)
62 error(1, errno, "alloc of %lud bytes failed", (unsigned long)new_len);
63 memset(f->base + f->len, 0, new_len - f->len);
64 f->end = f->base + l;
65 f->len = new_len;
67 f->end += sz;
68 return f->end - sz;
71 static size_t flow_reserve(struct flow *f, size_t sz)
73 uint8_t *p = flow_reserve_p(f, sz);
74 return p - f->base;
77 static void flow_x(struct flow *f, uint8_t * data, size_t data_len)
79 memcpy(flow_reserve_p(f, data_len), data, data_len);
82 static void flow_1(struct flow *f, uint8_t d)
84 flow_reserve_p(f, 1)[0] = d;
87 static void flow_2(struct flow *f, uint16_t d)
89 uint8_t dd[2];
90 dd[0] = d >> 8;
91 dd[1] = d;
92 flow_x(f, dd, sizeof(dd));
95 static void flow_4(struct flow *f, uint32_t d)
97 uint8_t dd[4];
98 dd[0] = d >> 24;
99 dd[1] = d >> 16;
100 dd[2] = d >> 8;
101 dd[3] = d;
102 flow_x(f, dd, sizeof(dd));
105 static void init_flow(struct flow *f)
107 memset(f, 0, sizeof(*f));
110 static void flow_attribute(struct flow *f, struct isakmp_attribute *p)
112 for (; p; p = p->next)
113 switch (p->af) {
114 case isakmp_attr_lots:
115 flow_2(f, p->type);
116 flow_2(f, p->u.lots.length);
117 flow_x(f, p->u.lots.data, p->u.lots.length);
118 break;
119 case isakmp_attr_16:
120 flow_2(f, p->type | 0x8000);
121 flow_2(f, p->u.attr_16);
122 break;
123 case isakmp_attr_2x8:
124 flow_2(f, p->type | 0x8000);
125 flow_x(f, p->u.attr_2x8, 2);
126 break;
127 default:
128 abort();
132 static void flow_payload(struct flow *f, struct isakmp_payload *p)
134 size_t lpos;
135 size_t baselen;
137 if (p == NULL)
138 return;
140 baselen = f->end - f->base;
141 if (p->next == NULL)
142 flow_1(f, 0);
143 else
144 flow_1(f, p->next->type);
145 flow_1(f, 0);
146 lpos = flow_reserve(f, 2);
147 switch (p->type) {
148 case ISAKMP_PAYLOAD_SA:
149 flow_4(f, p->u.sa.doi);
150 flow_4(f, p->u.sa.situation);
151 flow_payload(f, p->u.sa.proposals);
152 break;
153 case ISAKMP_PAYLOAD_P:
154 flow_1(f, p->u.p.number);
155 flow_1(f, p->u.p.prot_id);
156 flow_1(f, p->u.p.spi_size);
158 uint8_t num_xform = 0;
159 struct isakmp_payload *xform;
160 for (xform = p->u.p.transforms; xform; xform = xform->next)
161 num_xform++;
162 flow_1(f, num_xform);
164 flow_x(f, p->u.p.spi, p->u.p.spi_size);
165 flow_payload(f, p->u.p.transforms);
166 break;
167 case ISAKMP_PAYLOAD_T:
168 flow_1(f, p->u.t.number);
169 flow_1(f, p->u.t.id);
170 flow_2(f, 0);
171 flow_attribute(f, p->u.t.attributes);
172 break;
173 case ISAKMP_PAYLOAD_KE:
174 case ISAKMP_PAYLOAD_HASH:
175 case ISAKMP_PAYLOAD_SIG:
176 case ISAKMP_PAYLOAD_NONCE:
177 case ISAKMP_PAYLOAD_VID:
178 case ISAKMP_PAYLOAD_NAT_D:
179 case ISAKMP_PAYLOAD_NAT_D_OLD:
180 flow_x(f, p->u.ke.data, p->u.ke.length);
181 break;
182 case ISAKMP_PAYLOAD_ID:
183 flow_1(f, p->u.id.type);
184 flow_1(f, p->u.id.protocol);
185 flow_2(f, p->u.id.port);
186 flow_x(f, p->u.id.data, p->u.id.length);
187 break;
188 case ISAKMP_PAYLOAD_CERT:
189 case ISAKMP_PAYLOAD_CR:
190 flow_1(f, p->u.cert.encoding);
191 flow_x(f, p->u.cert.data, p->u.cert.length);
192 break;
193 case ISAKMP_PAYLOAD_N:
194 flow_4(f, p->u.n.doi);
195 flow_1(f, p->u.n.protocol);
196 flow_1(f, p->u.n.spi_length);
197 flow_2(f, p->u.n.type);
198 flow_x(f, p->u.n.spi, p->u.n.spi_length);
199 flow_x(f, p->u.n.data, p->u.n.data_length);
200 break;
201 case ISAKMP_PAYLOAD_D:
202 flow_4(f, p->u.d.doi);
203 flow_1(f, p->u.d.protocol);
204 flow_1(f, p->u.d.spi_length);
205 flow_2(f, p->u.d.num_spi);
206 if (p->u.d.spi_length > 0) {
207 int i;
208 for (i = 0; i < p->u.d.num_spi; i++)
209 flow_x(f, p->u.d.spi[i], p->u.d.spi_length);
211 break;
212 case ISAKMP_PAYLOAD_MODECFG_ATTR:
213 flow_1(f, p->u.modecfg.type);
214 flow_1(f, 0);
215 flow_2(f, p->u.modecfg.id);
216 flow_attribute(f, p->u.modecfg.attributes);
217 break;
218 default:
219 abort();
221 f->base[lpos] = (f->end - f->base - baselen) >> 8;
222 f->base[lpos + 1] = (f->end - f->base - baselen);
223 flow_payload(f, p->next);
226 void flatten_isakmp_payloads(struct isakmp_payload *p, uint8_t ** result, size_t * size)
228 struct flow f;
229 init_flow(&f);
230 flow_payload(&f, p);
231 *result = f.base;
232 *size = f.end - f.base;
235 void flatten_isakmp_payload(struct isakmp_payload *p, uint8_t ** result, size_t * size)
237 struct isakmp_payload *next;
238 next = p->next;
239 p->next = NULL;
240 flatten_isakmp_payloads(p, result, size);
241 p->next = next;
244 void flatten_isakmp_packet(struct isakmp_packet *p, uint8_t ** result, size_t * size, size_t blksz)
246 struct flow f;
247 size_t lpos, sz, padding;
249 init_flow(&f);
250 flow_x(&f, p->i_cookie, ISAKMP_COOKIE_LENGTH);
251 flow_x(&f, p->r_cookie, ISAKMP_COOKIE_LENGTH);
252 if (p->payload == NULL)
253 flow_1(&f, 0);
254 else
255 flow_1(&f, p->payload->type);
256 flow_1(&f, p->isakmp_version);
257 flow_1(&f, p->exchange_type);
258 flow_1(&f, p->flags);
259 flow_4(&f, p->message_id);
260 lpos = flow_reserve(&f, 4);
261 flow_payload(&f, p->payload);
262 if (p->flags & ISAKMP_FLAG_E) {
263 assert(blksz != 0);
264 sz = (f.end - f.base) - ISAKMP_PAYLOAD_O;
265 padding = blksz - (sz % blksz);
266 if (padding == blksz)
267 padding = 0;
268 DEBUG(3, printf("size = %ld, blksz = %ld, padding = %ld\n",
269 (long)sz, (long)blksz, (long)padding));
270 flow_reserve(&f, padding);
272 f.base[lpos] = (f.end - f.base) >> 24;
273 f.base[lpos + 1] = (f.end - f.base) >> 16;
274 f.base[lpos + 2] = (f.end - f.base) >> 8;
275 f.base[lpos + 3] = (f.end - f.base);
276 *result = f.base;
277 *size = f.end - f.base;
278 /*DUMP*/ if (opt_debug >= 3) {
279 printf("\n sending: ========================>\n");
280 free_isakmp_packet(parse_isakmp_packet(f.base, f.end - f.base, NULL));
284 struct isakmp_attribute *new_isakmp_attribute(uint16_t type, struct isakmp_attribute *next)
286 struct isakmp_attribute *r = xallocc(sizeof(struct isakmp_attribute));
287 r->type = type;
288 r->next = next;
289 return r;
292 struct isakmp_attribute *new_isakmp_attribute_16(uint16_t type, uint16_t data,
293 struct isakmp_attribute *next)
295 struct isakmp_attribute *r = xallocc(sizeof(struct isakmp_attribute));
296 r->next = next;
297 r->type = type;
298 r->af = isakmp_attr_16;
299 r->u.attr_16 = data;
300 return r;
303 static void free_isakmp_attributes(struct isakmp_attribute *attributes)
305 struct isakmp_attribute *att, *nextatt;
306 for (att = attributes; att; att = nextatt) {
307 nextatt = att->next;
308 if (att->af == isakmp_attr_lots)
309 free(att->u.lots.data);
310 if (att->af == isakmp_attr_acl)
311 free(att->u.acl.acl_ent);
312 free(att);
316 struct isakmp_packet *new_isakmp_packet(void)
318 return xallocc(sizeof(struct isakmp_packet));
321 struct isakmp_payload *new_isakmp_payload(uint8_t type)
323 struct isakmp_payload *result = xallocc(sizeof(struct isakmp_payload));
324 result->type = type;
325 return result;
328 struct isakmp_payload *new_isakmp_data_payload(uint8_t type, const void *data, size_t data_length)
330 struct isakmp_payload *result = xallocc(sizeof(struct isakmp_payload));
332 if (type != ISAKMP_PAYLOAD_KE && type != ISAKMP_PAYLOAD_HASH
333 && type != ISAKMP_PAYLOAD_SIG && type != ISAKMP_PAYLOAD_NONCE
334 && type != ISAKMP_PAYLOAD_VID && type != ISAKMP_PAYLOAD_NAT_D
335 && type != ISAKMP_PAYLOAD_NAT_D_OLD)
336 abort();
337 if (data_length >= 16384)
338 abort();
340 result->type = type;
341 result->u.ke.length = data_length;
342 result->u.ke.data = xallocc(data_length);
343 memcpy(result->u.ke.data, data, data_length);
344 return result;
347 static void free_isakmp_payload(struct isakmp_payload *p)
349 struct isakmp_payload *nxt;
351 if (p == NULL)
352 return;
354 switch (p->type) {
355 case ISAKMP_PAYLOAD_SA:
356 free_isakmp_payload(p->u.sa.proposals);
357 break;
358 case ISAKMP_PAYLOAD_P:
359 free(p->u.p.spi);
360 free_isakmp_payload(p->u.p.transforms);
361 break;
362 case ISAKMP_PAYLOAD_T:
363 free_isakmp_attributes(p->u.t.attributes);
364 break;
365 case ISAKMP_PAYLOAD_KE:
366 case ISAKMP_PAYLOAD_HASH:
367 case ISAKMP_PAYLOAD_SIG:
368 case ISAKMP_PAYLOAD_NONCE:
369 case ISAKMP_PAYLOAD_VID:
370 case ISAKMP_PAYLOAD_NAT_D:
371 case ISAKMP_PAYLOAD_NAT_D_OLD:
372 free(p->u.ke.data);
373 break;
374 case ISAKMP_PAYLOAD_ID:
375 free(p->u.id.data);
376 break;
377 case ISAKMP_PAYLOAD_CERT:
378 case ISAKMP_PAYLOAD_CR:
379 free(p->u.cert.data);
380 break;
381 case ISAKMP_PAYLOAD_N:
382 free(p->u.n.spi);
383 free(p->u.n.data);
384 free_isakmp_attributes(p->u.n.attributes);
385 break;
386 case ISAKMP_PAYLOAD_D:
387 if (p->u.d.spi) {
388 int i;
389 for (i = 0; i < p->u.d.num_spi; i++)
390 free(p->u.d.spi[i]);
391 free(p->u.d.spi);
393 break;
394 case ISAKMP_PAYLOAD_MODECFG_ATTR:
395 free_isakmp_attributes(p->u.modecfg.attributes);
396 break;
397 default:
398 abort();
401 nxt = p->next;
402 free(p);
403 free_isakmp_payload(nxt);
406 void free_isakmp_packet(struct isakmp_packet *p)
408 if (p == NULL)
409 return;
410 free_isakmp_payload(p->payload);
411 free(p);
414 static const struct debug_strings *transform_id_to_debug_strings(enum isakmp_ipsec_proto_enum decode_proto)
416 switch (decode_proto) {
417 case ISAKMP_IPSEC_PROTO_ISAKMP:
418 return isakmp_ipsec_key_enum_array;
419 case ISAKMP_IPSEC_PROTO_IPSEC_AH:
420 return isakmp_ipsec_ah_enum_array;
421 case ISAKMP_IPSEC_PROTO_IPSEC_ESP:
422 return isakmp_ipsec_esp_enum_array;
423 case ISAKMP_IPSEC_PROTO_IPCOMP:
424 return isakmp_ipsec_ipcomp_enum_array;
425 default:
426 return NULL;
430 static const struct debug_strings *attr_type_to_debug_strings(enum isakmp_ipsec_proto_enum decode_proto)
432 switch (decode_proto) {
433 case ISAKMP_IPSEC_PROTO_ISAKMP:
434 return ike_attr_enum_array;
435 case ISAKMP_IPSEC_PROTO_IPSEC_AH:
436 case ISAKMP_IPSEC_PROTO_IPSEC_ESP:
437 return isakmp_ipsec_attr_enum_array;
438 case ISAKMP_IPSEC_PROTO_MODECFG:
439 return isakmp_modecfg_attrib_enum_array;
440 default:
441 return NULL;
445 static const struct debug_strings *attr_val_to_debug_strings(enum isakmp_ipsec_proto_enum decode_proto, uint16_t type)
447 switch (decode_proto) {
448 case ISAKMP_IPSEC_PROTO_ISAKMP:
449 switch (type) {
450 case IKE_ATTRIB_ENC: return ike_enc_enum_array;
451 case IKE_ATTRIB_HASH: return ike_hash_enum_array;
452 case IKE_ATTRIB_AUTH_METHOD: return ike_auth_enum_array;
453 case IKE_ATTRIB_GROUP_DESC: return ike_group_enum_array;
454 case IKE_ATTRIB_GROUP_TYPE: return ike_group_type_enum_array;
455 case IKE_ATTRIB_LIFE_TYPE: return ike_life_enum_array;
456 default: return NULL;
458 case ISAKMP_IPSEC_PROTO_IPSEC_AH:
459 case ISAKMP_IPSEC_PROTO_IPSEC_ESP:
460 switch (type) {
461 case ISAKMP_IPSEC_ATTRIB_SA_LIFE_TYPE: return ipsec_life_enum_array;
462 case ISAKMP_IPSEC_ATTRIB_ENCAP_MODE: return ipsec_encap_enum_array;
463 case ISAKMP_IPSEC_ATTRIB_AUTH_ALG: return ipsec_auth_enum_array;
464 default: return NULL;
466 default:
467 return NULL;
471 #define fetch4() \
472 (data += 4, data_len -= 4, \
473 (uint32_t)(data[-4]) << 24 | (uint32_t)(data[-3]) << 16 \
474 | (uint32_t)(data[-2]) << 8 | data[-1])
475 #define fetch2() \
476 (data += 2, data_len -= 2, \
477 (uint16_t)(data[-2]) << 8 | data[-1])
478 #define fetch1() (data_len--, *data++)
479 #define fetchn(d,n) \
480 (memcpy ((d), data, (n)), data += (n), data_len -= (n))
482 static struct isakmp_attribute *parse_isakmp_attributes(const uint8_t ** data_p,
483 size_t data_len, int * reject, enum isakmp_ipsec_proto_enum decode_proto)
485 const uint8_t *data = *data_p;
486 struct isakmp_attribute *r;
487 uint16_t type, length;
488 int i;
490 if (data_len < 4)
491 return NULL;
493 r = new_isakmp_attribute(0, NULL);
494 type = fetch2();
495 length = fetch2();
496 if (type & 0x8000) {
497 r->type = type & ~0x8000;
498 hex_dump("t.attributes.type", &r->type, DUMP_UINT16, attr_type_to_debug_strings(decode_proto));
499 r->af = isakmp_attr_16;
500 r->u.attr_16 = length;
501 if ((ISAKMP_XAUTH_06_ATTRIB_TYPE <= r->type)
502 && (r->type <= ISAKMP_XAUTH_06_ATTRIB_ANSWER)
503 && (r->type != ISAKMP_XAUTH_06_ATTRIB_STATUS)
504 && (length > 0)
505 && (opt_debug < 99))
506 DEBUG(3, printf("(not dumping xauth data)\n"));
507 else
508 hex_dump("t.attributes.u.attr_16", &r->u.attr_16, DUMP_UINT16,
509 attr_val_to_debug_strings(decode_proto, r->type));
510 } else {
511 r->type = type;
512 hex_dump("t.attributes.type", &r->type, DUMP_UINT16, attr_type_to_debug_strings(decode_proto));
513 r->af = isakmp_attr_lots;
514 r->u.lots.length = length;
515 if ((ISAKMP_XAUTH_06_ATTRIB_TYPE <= r->type)
516 && (r->type <= ISAKMP_XAUTH_06_ATTRIB_ANSWER)
517 && (r->type != ISAKMP_XAUTH_06_ATTRIB_STATUS)
518 && (length > 0)
519 && (opt_debug < 99))
520 DEBUG(3, printf("(not dumping xauth data length)\n"));
521 else
522 hex_dump("t.attributes.u.lots.length", &r->u.lots.length, DUMP_UINT16, NULL);
523 if (data_len < length) {
524 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
525 return r;
527 if (r->type == ISAKMP_MODECFG_ATTRIB_CISCO_SPLIT_INC) {
528 r->af = isakmp_attr_acl;
529 r->u.acl.count = length / (4+4+2+2+2);
530 if (r->u.acl.count * (4+4+2+2+2) != length) {
531 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
532 return r;
534 r->u.acl.acl_ent = xallocc(r->u.acl.count * sizeof(struct acl_ent_s));
536 for (i = 0; i < r->u.acl.count; i++) {
537 fetchn(&r->u.acl.acl_ent[i].addr.s_addr, 4);
538 fetchn(&r->u.acl.acl_ent[i].mask.s_addr, 4);
539 r->u.acl.acl_ent[i].protocol = fetch2();
540 r->u.acl.acl_ent[i].sport = fetch2();
541 r->u.acl.acl_ent[i].dport = fetch2();
542 hex_dump("t.attributes.u.acl.addr", &r->u.acl.acl_ent[i].addr.s_addr, 4, NULL);
543 hex_dump("t.attributes.u.acl.mask", &r->u.acl.acl_ent[i].mask.s_addr, 4, NULL);
544 hex_dump("t.attributes.u.acl.protocol", &r->u.acl.acl_ent[i].protocol, DUMP_UINT16, NULL);
545 hex_dump("t.attributes.u.acl.sport", &r->u.acl.acl_ent[i].sport, DUMP_UINT16, NULL);
546 hex_dump("t.attributes.u.acl.dport", &r->u.acl.acl_ent[i].dport, DUMP_UINT16, NULL);
548 } else {
549 r->u.lots.data = xallocc(length);
550 fetchn(r->u.lots.data, length);
551 if ((ISAKMP_XAUTH_06_ATTRIB_TYPE <= type)
552 && (type <= ISAKMP_XAUTH_06_ATTRIB_ANSWER)
553 && (r->type != ISAKMP_XAUTH_06_ATTRIB_STATUS)
554 && (length > 0)
555 && (opt_debug < 99))
556 DEBUG(3, printf("(not dumping xauth data)\n"));
557 else
558 hex_dump("t.attributes.u.lots.data", r->u.lots.data, r->u.lots.length, NULL);
561 r->next = parse_isakmp_attributes(&data, data_len, reject, decode_proto);
562 *data_p = data;
563 return r;
566 static struct isakmp_payload *parse_isakmp_payload(uint8_t type,
567 const uint8_t ** data_p, size_t * data_len_p, int * reject, enum isakmp_ipsec_proto_enum decode_proto)
569 const uint8_t *data = *data_p, *tmpdata;
570 size_t data_len = *data_len_p;
571 struct isakmp_payload *r;
572 uint8_t next_type;
573 size_t length, olength;
575 static const uint16_t min_payload_len[ISAKMP_PAYLOAD_MODECFG_ATTR + 1] = {
576 4, 12, 8, 8, 4, 8, 5, 5, 4, 4, 4, 12, 12, 4, 8
579 DEBUG(3, printf("\n"));
580 hex_dump("PARSING PAYLOAD type", &type, DUMP_UINT8, isakmp_payload_enum_array);
581 if (type == 0)
582 return NULL;
583 if (type <= ISAKMP_PAYLOAD_MODECFG_ATTR) {
584 if (data_len < min_payload_len[type]) {
585 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
586 return NULL;
588 } else if (data_len < 4) {
589 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
590 return NULL;
593 r = new_isakmp_payload(type);
594 next_type = fetch1();
595 hex_dump("next_type", &next_type, DUMP_UINT8, isakmp_payload_enum_array);
596 if (fetch1() != 0) {
597 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
598 return r;
600 length = fetch2();
601 hex_dump("length", &length, DUMP_UINT16, NULL);
602 if (length > data_len + 4
603 || ((type <= ISAKMP_PAYLOAD_MODECFG_ATTR)&&(length < min_payload_len[type]))
604 || (length < 4)) {
605 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
606 return r;
608 olength = length;
609 switch (type) {
610 case ISAKMP_PAYLOAD_SA:
611 r->u.sa.doi = fetch4();
612 hex_dump("sa.doi", &r->u.sa.doi, DUMP_UINT32, isakmp_doi_enum_array);
613 if (r->u.sa.doi != ISAKMP_DOI_IPSEC) {
614 *reject = ISAKMP_N_DOI_NOT_SUPPORTED;
615 return r;
617 r->u.sa.situation = fetch4();
618 hex_dump("sa.situation", &r->u.sa.situation, DUMP_UINT32, isakmp_ipsec_sit_enum_array);
619 if (r->u.sa.situation != ISAKMP_IPSEC_SIT_IDENTITY_ONLY) {
620 *reject = ISAKMP_N_SITUATION_NOT_SUPPORTED;
621 return r;
623 *reject = 0;
624 length -= 12;
625 r->u.sa.proposals = parse_isakmp_payload(ISAKMP_PAYLOAD_P, &data, &length, reject, decode_proto);
626 if (*reject != 0)
627 return r;
628 /* Allow trailing garbage at end of payload. */
629 data_len -= olength - 12;
630 break;
632 case ISAKMP_PAYLOAD_P:
633 if (next_type != ISAKMP_PAYLOAD_P && next_type != 0) {
634 *reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
635 return r;
638 uint8_t num_xform;
639 struct isakmp_payload *xform;
641 r->u.p.number = fetch1();
642 hex_dump("p.number", &r->u.p.number, DUMP_UINT8, NULL);
643 r->u.p.prot_id = fetch1();
644 hex_dump("p.prot_id", &r->u.p.prot_id, DUMP_UINT8, isakmp_ipsec_proto_enum_array);
645 r->u.p.spi_size = fetch1();
646 hex_dump("p.spi_size", &r->u.p.spi_size, DUMP_UINT8, NULL);
647 num_xform = fetch1();
648 hex_dump("length", &num_xform, DUMP_UINT8, NULL);
650 if (data_len < r->u.p.spi_size) {
651 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
652 return r;
654 r->u.p.spi = xallocc(r->u.p.spi_size);
655 fetchn(r->u.p.spi, r->u.p.spi_size);
656 hex_dump("p.spi", r->u.p.spi, r->u.p.spi_size, NULL);
657 length -= 8 + r->u.p.spi_size;
658 r->u.p.transforms = parse_isakmp_payload(ISAKMP_PAYLOAD_T,
659 &data, &length, reject, r->u.p.prot_id);
660 for (xform = r->u.p.transforms; xform; xform = xform->next)
661 if (num_xform-- == 0)
662 break;
663 if (num_xform != 0) {
664 *reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
665 return r;
668 /* Allow trailing garbage at end of payload. */
669 data_len -= olength - 8 - r->u.p.spi_size;
671 break;
673 case ISAKMP_PAYLOAD_T:
674 if (next_type != ISAKMP_PAYLOAD_T && next_type != 0) {
675 *reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
676 return r;
678 r->u.t.number = fetch1();
679 hex_dump("t.number", &r->u.t.number, DUMP_UINT8, NULL);
680 r->u.t.id = fetch1();
681 hex_dump("t.id", &r->u.t.id, DUMP_UINT8, transform_id_to_debug_strings(decode_proto));
682 if (fetch2() != 0) {
683 *reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
684 return r;
686 length -= 8;
687 r->u.t.attributes = parse_isakmp_attributes(&data, length, reject, decode_proto);
688 data_len -= olength - 8;
689 break;
691 case ISAKMP_PAYLOAD_KE:
692 case ISAKMP_PAYLOAD_HASH:
693 case ISAKMP_PAYLOAD_SIG:
694 case ISAKMP_PAYLOAD_NONCE:
695 case ISAKMP_PAYLOAD_VID:
696 case ISAKMP_PAYLOAD_NAT_D:
697 case ISAKMP_PAYLOAD_NAT_D_OLD:
698 r->u.ke.length = length - 4;
699 r->u.ke.data = xallocc(r->u.ke.length);
700 fetchn(r->u.ke.data, r->u.ke.length);
701 hex_dump("ke.data", r->u.ke.data, r->u.ke.length, NULL);
702 if (type == ISAKMP_PAYLOAD_VID)
703 print_vid(r->u.ke.data, r->u.ke.length);
704 break;
705 case ISAKMP_PAYLOAD_ID:
706 r->u.id.type = fetch1();
707 hex_dump("id.type", &r->u.id.type, DUMP_UINT8, isakmp_ipsec_id_enum_array);
708 r->u.id.protocol = fetch1();
709 hex_dump("id.protocol", &r->u.id.protocol, DUMP_UINT8, NULL); /* IP protocol nr */
710 r->u.id.port = fetch2();
711 hex_dump("id.port", &r->u.id.port, DUMP_UINT16, NULL);
712 r->u.id.length = length - 8;
713 r->u.id.data = xallocc(r->u.id.length);
714 fetchn(r->u.id.data, r->u.id.length);
715 hex_dump("id.data", r->u.id.data, r->u.id.length, NULL);
716 break;
717 case ISAKMP_PAYLOAD_CERT:
718 case ISAKMP_PAYLOAD_CR:
719 r->u.cert.encoding = fetch1();
720 hex_dump("cert.encoding", &r->u.cert.encoding, DUMP_UINT8, NULL);
721 r->u.cert.length = length - 5;
722 r->u.cert.data = xallocc(r->u.cert.length);
723 fetchn(r->u.cert.data, r->u.cert.length);
724 hex_dump("cert.data", r->u.cert.data, r->u.cert.length, NULL);
725 break;
726 case ISAKMP_PAYLOAD_N:
727 r->u.n.doi = fetch4();
728 hex_dump("n.doi", &r->u.n.doi, DUMP_UINT32, isakmp_doi_enum_array);
729 r->u.n.protocol = fetch1();
730 hex_dump("n.protocol", &r->u.n.protocol, DUMP_UINT8, isakmp_ipsec_proto_enum_array);
731 r->u.n.spi_length = fetch1();
732 hex_dump("n.spi_length", &r->u.n.spi_length, DUMP_UINT8, NULL);
733 r->u.n.type = fetch2();
734 hex_dump("n.type", &r->u.n.type, DUMP_UINT16, isakmp_notify_enum_array);
735 if (r->u.n.spi_length + 12u > length) {
736 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
737 return r;
739 r->u.n.spi = xallocc(r->u.n.spi_length);
740 fetchn(r->u.n.spi, r->u.n.spi_length);
741 hex_dump("n.spi", r->u.n.spi, r->u.n.spi_length, NULL);
742 r->u.n.data_length = length - 12 - r->u.n.spi_length;
743 r->u.n.data = xallocc(r->u.n.data_length);
744 fetchn(r->u.n.data, r->u.n.data_length);
745 hex_dump("n.data", r->u.n.data, r->u.n.data_length, NULL);
746 if ((r->u.n.doi == ISAKMP_DOI_IPSEC)&&(r->u.n.type == ISAKMP_N_IPSEC_RESPONDER_LIFETIME)) {
747 tmpdata = r->u.n.data;
748 r->u.n.attributes = parse_isakmp_attributes(&tmpdata, r->u.n.data_length, reject,
749 r->u.n.protocol);
751 break;
752 case ISAKMP_PAYLOAD_D:
753 r->u.d.doi = fetch4();
754 hex_dump("d.doi", &r->u.d.doi, DUMP_UINT32, isakmp_doi_enum_array);
755 r->u.d.protocol = fetch1();
756 hex_dump("d.protocol", &r->u.d.protocol, DUMP_UINT8, isakmp_ipsec_proto_enum_array);
757 r->u.d.spi_length = fetch1();
758 hex_dump("d.spi_length", &r->u.d.spi_length, DUMP_UINT8, NULL);
759 r->u.d.num_spi = fetch2();
760 hex_dump("d.num_spi", &r->u.d.num_spi, DUMP_UINT16, NULL);
761 if (r->u.d.num_spi * r->u.d.spi_length + 12u != length) {
762 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
763 return r;
765 r->u.d.spi = xallocc(sizeof(uint8_t *) * r->u.d.num_spi);
767 int i;
768 for (i = 0; i < r->u.d.num_spi; i++) {
769 r->u.d.spi[i] = xallocc(r->u.d.spi_length);
770 fetchn(r->u.d.spi[i], r->u.d.spi_length);
771 hex_dump("d.spi", r->u.d.spi[i], r->u.d.spi_length, NULL);
774 break;
775 case ISAKMP_PAYLOAD_MODECFG_ATTR:
776 r->u.modecfg.type = fetch1();
777 hex_dump("modecfg.type", &r->u.modecfg.type, DUMP_UINT8, isakmp_modecfg_cfg_enum_array);
778 if (fetch1() != 0) {
779 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
780 return r;
782 r->u.modecfg.id = fetch2();
783 hex_dump("modecfg.id", &r->u.modecfg.id, DUMP_UINT16, NULL);
784 length -= 8;
785 r->u.modecfg.attributes = parse_isakmp_attributes(&data, length, reject,
786 ISAKMP_IPSEC_PROTO_MODECFG); /* this "proto" is a hack for simplicity */
787 data_len -= olength - 8;
788 break;
790 default:
791 r->u.ke.length = length - 4;
792 r->u.ke.data = xallocc(r->u.ke.length);
793 fetchn(r->u.ke.data, r->u.ke.length);
794 hex_dump("UNKNOWN.data", r->u.ke.data, r->u.ke.length, NULL);
795 break;
797 *data_p = data;
798 *data_len_p = data_len;
799 hex_dump("DONE PARSING PAYLOAD type", &type, DUMP_UINT8, isakmp_payload_enum_array);
800 r->next = parse_isakmp_payload(next_type, data_p, data_len_p, reject, decode_proto);
801 return r;
804 struct isakmp_packet *parse_isakmp_packet(const uint8_t * data, size_t data_len, int * reject)
806 int reason = 0;
807 uint8_t payload;
808 struct isakmp_packet *r = new_isakmp_packet();
809 size_t o_data_len = data_len;
810 size_t isakmp_data_len;
812 if (data_len < ISAKMP_PAYLOAD_O) {
813 DEBUG(2, printf("packet to short: len = %lld < min = %lld\n", (long long) data_len, (long long)ISAKMP_PAYLOAD_O));
814 reason = ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS;
815 goto error;
818 DEBUG(3, printf("BEGIN_PARSE\n"));
819 DEBUG(3, printf("Recieved Packet Len: %zu\n", data_len));
820 fetchn(r->i_cookie, ISAKMP_COOKIE_LENGTH);
821 hex_dump("i_cookie", r->i_cookie, ISAKMP_COOKIE_LENGTH, NULL);
822 fetchn(r->r_cookie, ISAKMP_COOKIE_LENGTH);
823 hex_dump("r_cookie", r->r_cookie, ISAKMP_COOKIE_LENGTH, NULL);
824 payload = fetch1();
825 hex_dump("payload", &payload, DUMP_UINT8, isakmp_payload_enum_array);
827 r->isakmp_version = fetch1();
828 hex_dump("isakmp_version", &r->isakmp_version, DUMP_UINT8, NULL);
829 if (r->isakmp_version > ISAKMP_VERSION) {
830 if ((r->isakmp_version & 0xF0) >= (ISAKMP_VERSION & 0xF0))
831 reason = ISAKMP_N_INVALID_MAJOR_VERSION;
832 else
833 reason = ISAKMP_N_INVALID_MINOR_VERSION;
834 goto error;
837 r->exchange_type = fetch1();
838 hex_dump("exchange_type", &r->exchange_type, DUMP_UINT8, isakmp_exchange_enum_array);
839 r->flags = fetch1();
840 hex_dump("flags", &r->flags, DUMP_UINT8, NULL);
841 r->message_id = fetch4();
842 hex_dump("message_id", &r->message_id, sizeof(r->message_id), NULL);
844 isakmp_data_len = fetch4();
845 hex_dump("len", &isakmp_data_len, DUMP_UINT32, NULL);
846 if (o_data_len != isakmp_data_len) {
847 DEBUG(2, printf("isakmp length does not match packet length: isakmp = %lld != datalen = %lld\n",
848 (long long)isakmp_data_len, (long long)o_data_len));
849 reason = ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS;
850 goto error;
853 r->payload = parse_isakmp_payload(payload, &data, &data_len, &reason, 0);
854 if (reason != 0)
855 goto error;
857 DEBUG(3, printf("PARSE_OK\n"));
858 return r;
860 error:
861 free_isakmp_packet(r);
862 if (reject)
863 *reject = reason;
864 return NULL;
867 void test_pack_unpack(void)
869 static const uint8_t pack[] = {
870 0x7f, 0xba, 0x51, 0x29, 0x11, 0x9e, 0x76, 0xf7, 0x9a, 0x71, 0xee, 0x70,
871 0xaa, 0x82, 0xb9, 0x7f, 0x01, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
872 0x00, 0x00, 0x01, 0x4c, 0x04, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01,
873 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x01, 0x01, 0x00, 0x01,
874 0x00, 0x00, 0x00, 0x18, 0x00, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x05,
875 0x80, 0x02, 0x00, 0x01, 0x80, 0x04, 0x00, 0x02, 0x80, 0x03, 0x00, 0x01,
876 0x0a, 0x00, 0x00, 0x84, 0x1b, 0x1d, 0x4b, 0x29, 0x0e, 0x29, 0xb9, 0x6f,
877 0x18, 0x34, 0xd1, 0x2d, 0xba, 0x92, 0x7c, 0x53, 0x35, 0x76, 0x0e, 0x3b,
878 0x25, 0x92, 0x4f, 0x7c, 0x1e, 0x31, 0x41, 0x8c, 0xb9, 0xe3, 0xda, 0xf7,
879 0x53, 0xd3, 0x22, 0x8e, 0xff, 0xeb, 0xed, 0x5b, 0x95, 0x56, 0x8d, 0xba,
880 0xa8, 0xe3, 0x2a, 0x9b, 0xb4, 0x04, 0x5c, 0x90, 0xf0, 0xfe, 0x92, 0xc8,
881 0x57, 0xa2, 0xc6, 0x0c, 0x85, 0xbb, 0x56, 0xe8, 0x1c, 0xa7, 0x2c, 0x57,
882 0x04, 0xb6, 0xe0, 0x43, 0x82, 0xe1, 0x9f, 0x0b, 0xa6, 0x8b, 0xce, 0x7f,
883 0x9b, 0x75, 0xbb, 0xd3, 0xff, 0x0e, 0x89, 0x19, 0xaf, 0xc6, 0x2e, 0xf6,
884 0x92, 0x06, 0x46, 0x4f, 0xc7, 0x97, 0x22, 0xf4, 0xa6, 0xf9, 0x26, 0x34,
885 0x04, 0x33, 0x89, 0x34, 0xa9, 0x2f, 0x81, 0x92, 0xd3, 0x21, 0x4f, 0x45,
886 0xbe, 0x38, 0x12, 0x26, 0xec, 0x87, 0x45, 0xdd, 0x10, 0x1c, 0xd6, 0x16,
887 0x05, 0x00, 0x00, 0x18, 0x77, 0xdf, 0x37, 0x3c, 0x03, 0x02, 0xe2, 0xc8,
888 0xe1, 0x2f, 0x92, 0xf0, 0x2e, 0xa2, 0xa6, 0x00, 0x17, 0x8f, 0xdf, 0xb4,
889 0x08, 0x00, 0x00, 0x0c, 0x01, 0x11, 0x01, 0xf4, 0xcd, 0xb4, 0x53, 0x6d,
890 0x0d, 0x00, 0x00, 0x14, 0x07, 0x47, 0x8d, 0xa7, 0x0b, 0xd6, 0xd1, 0x66,
891 0x7a, 0xaf, 0x2e, 0x61, 0x2a, 0x91, 0x80, 0x94, 0x0d, 0x00, 0x00, 0x14,
892 0x12, 0xf5, 0xf2, 0x8c, 0x45, 0x71, 0x68, 0xa9, 0x70, 0x2d, 0x9f, 0xe2,
893 0x74, 0xcc, 0x01, 0x00, 0x0d, 0x00, 0x00, 0x0c, 0x09, 0x00, 0x26, 0x89,
894 0xdf, 0xd6, 0xb7, 0x12, 0x0d, 0x00, 0x00, 0x14, 0xaf, 0xca, 0xd7, 0x13,
895 0x68, 0xa1, 0xf1, 0xc9, 0x6b, 0x86, 0x96, 0xfc, 0x77, 0x57, 0x01, 0x00,
896 0x00, 0x00, 0x00, 0x14, 0x1f, 0x07, 0xf7, 0x0e, 0xaa, 0x65, 0x14, 0xd3,
897 0xb0, 0xfa, 0x96, 0x54, 0x2a, 0x50, 0x03, 0x05
899 uint8_t *unpack;
900 size_t unpack_len;
901 struct isakmp_packet *p;
902 int reject;
904 p = parse_isakmp_packet(pack, sizeof(pack), &reject);
905 flatten_isakmp_packet(p, &unpack, &unpack_len, 8);
906 if (unpack_len != sizeof(pack)
907 || memcmp(unpack, pack, sizeof(pack)) != 0)
908 abort();
909 free(unpack);
910 free_isakmp_packet(p);