Stefan Seyfried <seife+obs@b1-systems.com>
[vpnc.git] / isakmp-pkt.c
blobf4913623f2b5c3f4f07b0692a3be4e260f9078f8
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 struct isakmp_packet *new_isakmp_packet(void)
305 return xallocc(sizeof(struct isakmp_packet));
308 struct isakmp_payload *new_isakmp_payload(uint8_t type)
310 struct isakmp_payload *result = xallocc(sizeof(struct isakmp_payload));
311 result->type = type;
312 return result;
315 struct isakmp_payload *new_isakmp_data_payload(uint8_t type, const void *data, size_t data_length)
317 struct isakmp_payload *result = xallocc(sizeof(struct isakmp_payload));
319 if (type != ISAKMP_PAYLOAD_KE && type != ISAKMP_PAYLOAD_HASH
320 && type != ISAKMP_PAYLOAD_SIG && type != ISAKMP_PAYLOAD_NONCE
321 && type != ISAKMP_PAYLOAD_VID && type != ISAKMP_PAYLOAD_NAT_D
322 && type != ISAKMP_PAYLOAD_NAT_D_OLD)
323 abort();
324 if (data_length >= 16384)
325 abort();
327 result->type = type;
328 result->u.ke.length = data_length;
329 result->u.ke.data = xallocc(data_length);
330 memcpy(result->u.ke.data, data, data_length);
331 return result;
334 static void free_isakmp_payload(struct isakmp_payload *p)
336 struct isakmp_payload *nxt;
338 if (p == NULL)
339 return;
341 switch (p->type) {
342 case ISAKMP_PAYLOAD_SA:
343 free_isakmp_payload(p->u.sa.proposals);
344 break;
345 case ISAKMP_PAYLOAD_P:
346 free(p->u.p.spi);
347 free_isakmp_payload(p->u.p.transforms);
348 break;
349 case ISAKMP_PAYLOAD_T:
351 struct isakmp_attribute *att, *natt;
352 for (att = p->u.t.attributes; att; att = natt) {
353 natt = att->next;
354 if (att->af == isakmp_attr_lots)
355 free(att->u.lots.data);
356 free(att);
359 break;
360 case ISAKMP_PAYLOAD_KE:
361 case ISAKMP_PAYLOAD_HASH:
362 case ISAKMP_PAYLOAD_SIG:
363 case ISAKMP_PAYLOAD_NONCE:
364 case ISAKMP_PAYLOAD_VID:
365 case ISAKMP_PAYLOAD_NAT_D:
366 case ISAKMP_PAYLOAD_NAT_D_OLD:
367 free(p->u.ke.data);
368 break;
369 case ISAKMP_PAYLOAD_ID:
370 free(p->u.id.data);
371 break;
372 case ISAKMP_PAYLOAD_CERT:
373 case ISAKMP_PAYLOAD_CR:
374 free(p->u.cert.data);
375 break;
376 case ISAKMP_PAYLOAD_N:
377 free(p->u.n.spi);
378 free(p->u.n.data);
379 break;
380 case ISAKMP_PAYLOAD_D:
381 if (p->u.d.spi) {
382 int i;
383 for (i = 0; i < p->u.d.num_spi; i++)
384 free(p->u.d.spi[i]);
385 free(p->u.d.spi);
387 break;
388 case ISAKMP_PAYLOAD_MODECFG_ATTR:
390 struct isakmp_attribute *att, *natt;
391 for (att = p->u.modecfg.attributes; att; att = natt) {
392 natt = att->next;
393 if (att->af == isakmp_attr_lots)
394 free(att->u.lots.data);
395 if (att->af == isakmp_attr_acl)
396 free(att->u.acl.acl_ent);
397 free(att);
400 break;
401 default:
402 abort();
405 nxt = p->next;
406 free(p);
407 free_isakmp_payload(nxt);
410 void free_isakmp_packet(struct isakmp_packet *p)
412 if (p == NULL)
413 return;
414 free_isakmp_payload(p->payload);
415 free(p);
418 static const struct debug_strings *transform_id_to_debug_strings(enum isakmp_ipsec_proto_enum decode_proto)
420 switch (decode_proto) {
421 case ISAKMP_IPSEC_PROTO_ISAKMP:
422 return isakmp_ipsec_key_enum_array;
423 case ISAKMP_IPSEC_PROTO_IPSEC_AH:
424 return isakmp_ipsec_ah_enum_array;
425 case ISAKMP_IPSEC_PROTO_IPSEC_ESP:
426 return isakmp_ipsec_esp_enum_array;
427 case ISAKMP_IPSEC_PROTO_IPCOMP:
428 return isakmp_ipsec_ipcomp_enum_array;
429 default:
430 return NULL;
434 static const struct debug_strings *attr_type_to_debug_strings(enum isakmp_ipsec_proto_enum decode_proto)
436 switch (decode_proto) {
437 case ISAKMP_IPSEC_PROTO_ISAKMP:
438 return ike_attr_enum_array;
439 case ISAKMP_IPSEC_PROTO_IPSEC_AH:
440 case ISAKMP_IPSEC_PROTO_IPSEC_ESP:
441 return isakmp_ipsec_attr_enum_array;
442 case ISAKMP_IPSEC_PROTO_MODECFG:
443 return isakmp_modecfg_attrib_enum_array;
444 default:
445 return NULL;
449 static const struct debug_strings *attr_val_to_debug_strings(enum isakmp_ipsec_proto_enum decode_proto, uint16_t type)
451 switch (decode_proto) {
452 case ISAKMP_IPSEC_PROTO_ISAKMP:
453 switch (type) {
454 case IKE_ATTRIB_ENC: return ike_enc_enum_array;
455 case IKE_ATTRIB_HASH: return ike_hash_enum_array;
456 case IKE_ATTRIB_AUTH_METHOD: return ike_auth_enum_array;
457 case IKE_ATTRIB_GROUP_DESC: return ike_group_enum_array;
458 case IKE_ATTRIB_GROUP_TYPE: return ike_group_type_enum_array;
459 case IKE_ATTRIB_LIFE_TYPE: return ike_life_enum_array;
460 default: return NULL;
462 case ISAKMP_IPSEC_PROTO_IPSEC_AH:
463 case ISAKMP_IPSEC_PROTO_IPSEC_ESP:
464 switch (type) {
465 case ISAKMP_IPSEC_ATTRIB_SA_LIFE_TYPE: return ipsec_life_enum_array;
466 case ISAKMP_IPSEC_ATTRIB_ENCAP_MODE: return ipsec_encap_enum_array;
467 case ISAKMP_IPSEC_ATTRIB_AUTH_ALG: return ipsec_auth_enum_array;
468 default: return NULL;
470 default:
471 return NULL;
475 #define fetch4() \
476 (data += 4, data_len -= 4, \
477 (uint32_t)(data[-4]) << 24 | (uint32_t)(data[-3]) << 16 \
478 | (uint32_t)(data[-2]) << 8 | data[-1])
479 #define fetch2() \
480 (data += 2, data_len -= 2, \
481 (uint16_t)(data[-2]) << 8 | data[-1])
482 #define fetch1() (data_len--, *data++)
483 #define fetchn(d,n) \
484 (memcpy ((d), data, (n)), data += (n), data_len -= (n))
486 static struct isakmp_attribute *parse_isakmp_attributes(const uint8_t ** data_p,
487 size_t data_len, int * reject, enum isakmp_ipsec_proto_enum decode_proto)
489 const uint8_t *data = *data_p;
490 struct isakmp_attribute *r;
491 uint16_t type, length;
492 int i;
494 if (data_len < 4)
495 return NULL;
497 r = new_isakmp_attribute(0, NULL);
498 type = fetch2();
499 length = fetch2();
500 if (type & 0x8000) {
501 r->type = type & ~0x8000;
502 hex_dump("t.attributes.type", &r->type, DUMP_UINT16, attr_type_to_debug_strings(decode_proto));
503 r->af = isakmp_attr_16;
504 r->u.attr_16 = length;
505 if ((ISAKMP_XAUTH_06_ATTRIB_TYPE <= r->type)
506 && (r->type <= ISAKMP_XAUTH_06_ATTRIB_ANSWER)
507 && (r->type != ISAKMP_XAUTH_06_ATTRIB_STATUS)
508 && (length > 0)
509 && (opt_debug < 99))
510 DEBUG(3, printf("(not dumping xauth data)\n"));
511 else
512 hex_dump("t.attributes.u.attr_16", &r->u.attr_16, DUMP_UINT16,
513 attr_val_to_debug_strings(decode_proto, r->type));
514 } else {
515 r->type = type;
516 hex_dump("t.attributes.type", &r->type, DUMP_UINT16, attr_type_to_debug_strings(decode_proto));
517 r->af = isakmp_attr_lots;
518 r->u.lots.length = length;
519 if ((ISAKMP_XAUTH_06_ATTRIB_TYPE <= r->type)
520 && (r->type <= ISAKMP_XAUTH_06_ATTRIB_ANSWER)
521 && (r->type != ISAKMP_XAUTH_06_ATTRIB_STATUS)
522 && (length > 0)
523 && (opt_debug < 99))
524 DEBUG(3, printf("(not dumping xauth data length)\n"));
525 else
526 hex_dump("t.attributes.u.lots.length", &r->u.lots.length, DUMP_UINT16, NULL);
527 if (data_len < length) {
528 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
529 return r;
531 if (r->type == ISAKMP_MODECFG_ATTRIB_CISCO_SPLIT_INC) {
532 r->af = isakmp_attr_acl;
533 r->u.acl.count = length / (4+4+2+2+2);
534 if (r->u.acl.count * (4+4+2+2+2) != length) {
535 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
536 return r;
538 r->u.acl.acl_ent = xallocc(r->u.acl.count * sizeof(struct acl_ent_s));
540 for (i = 0; i < r->u.acl.count; i++) {
541 fetchn(&r->u.acl.acl_ent[i].addr.s_addr, 4);
542 fetchn(&r->u.acl.acl_ent[i].mask.s_addr, 4);
543 r->u.acl.acl_ent[i].protocol = fetch2();
544 r->u.acl.acl_ent[i].sport = fetch2();
545 r->u.acl.acl_ent[i].dport = fetch2();
546 hex_dump("t.attributes.u.acl.addr", &r->u.acl.acl_ent[i].addr.s_addr, 4, NULL);
547 hex_dump("t.attributes.u.acl.mask", &r->u.acl.acl_ent[i].mask.s_addr, 4, NULL);
548 hex_dump("t.attributes.u.acl.protocol", &r->u.acl.acl_ent[i].protocol, DUMP_UINT16, NULL);
549 hex_dump("t.attributes.u.acl.sport", &r->u.acl.acl_ent[i].sport, DUMP_UINT16, NULL);
550 hex_dump("t.attributes.u.acl.dport", &r->u.acl.acl_ent[i].dport, DUMP_UINT16, NULL);
552 } else {
553 r->u.lots.data = xallocc(length);
554 fetchn(r->u.lots.data, length);
555 if ((ISAKMP_XAUTH_06_ATTRIB_TYPE <= type)
556 && (type <= ISAKMP_XAUTH_06_ATTRIB_ANSWER)
557 && (r->type != ISAKMP_XAUTH_06_ATTRIB_STATUS)
558 && (length > 0)
559 && (opt_debug < 99))
560 DEBUG(3, printf("(not dumping xauth data)\n"));
561 else
562 hex_dump("t.attributes.u.lots.data", r->u.lots.data, r->u.lots.length, NULL);
565 r->next = parse_isakmp_attributes(&data, data_len, reject, decode_proto);
566 *data_p = data;
567 return r;
570 static struct isakmp_payload *parse_isakmp_payload(uint8_t type,
571 const uint8_t ** data_p, size_t * data_len_p, int * reject, enum isakmp_ipsec_proto_enum decode_proto)
573 const uint8_t *data = *data_p, *tmpdata;
574 size_t data_len = *data_len_p;
575 struct isakmp_payload *r;
576 uint8_t next_type;
577 size_t length, olength;
579 static const uint16_t min_payload_len[ISAKMP_PAYLOAD_MODECFG_ATTR + 1] = {
580 4, 12, 8, 8, 4, 8, 5, 5, 4, 4, 4, 12, 12, 4, 8
583 DEBUG(3, printf("\n"));
584 hex_dump("PARSING PAYLOAD type", &type, DUMP_UINT8, isakmp_payload_enum_array);
585 if (type == 0)
586 return NULL;
587 if (type <= ISAKMP_PAYLOAD_MODECFG_ATTR) {
588 if (data_len < min_payload_len[type]) {
589 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
590 return NULL;
592 } else if (data_len < 4) {
593 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
594 return NULL;
597 r = new_isakmp_payload(type);
598 next_type = fetch1();
599 hex_dump("next_type", &next_type, DUMP_UINT8, isakmp_payload_enum_array);
600 if (fetch1() != 0) {
601 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
602 return r;
604 length = fetch2();
605 hex_dump("length", &length, DUMP_UINT16, NULL);
606 if (length > data_len + 4
607 || ((type <= ISAKMP_PAYLOAD_MODECFG_ATTR)&&(length < min_payload_len[type]))
608 || (length < 4)) {
609 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
610 return r;
612 olength = length;
613 switch (type) {
614 case ISAKMP_PAYLOAD_SA:
615 r->u.sa.doi = fetch4();
616 hex_dump("sa.doi", &r->u.sa.doi, DUMP_UINT32, isakmp_doi_enum_array);
617 if (r->u.sa.doi != ISAKMP_DOI_IPSEC) {
618 *reject = ISAKMP_N_DOI_NOT_SUPPORTED;
619 return r;
621 r->u.sa.situation = fetch4();
622 hex_dump("sa.situation", &r->u.sa.situation, DUMP_UINT32, isakmp_ipsec_sit_enum_array);
623 if (r->u.sa.situation != ISAKMP_IPSEC_SIT_IDENTITY_ONLY) {
624 *reject = ISAKMP_N_SITUATION_NOT_SUPPORTED;
625 return r;
627 *reject = 0;
628 length -= 12;
629 r->u.sa.proposals = parse_isakmp_payload(ISAKMP_PAYLOAD_P, &data, &length, reject, decode_proto);
630 if (*reject != 0)
631 return r;
632 /* Allow trailing garbage at end of payload. */
633 data_len -= olength - 12;
634 break;
636 case ISAKMP_PAYLOAD_P:
637 if (next_type != ISAKMP_PAYLOAD_P && next_type != 0) {
638 *reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
639 return r;
642 uint8_t num_xform;
643 struct isakmp_payload *xform;
645 r->u.p.number = fetch1();
646 hex_dump("p.number", &r->u.p.number, DUMP_UINT8, NULL);
647 r->u.p.prot_id = fetch1();
648 hex_dump("p.prot_id", &r->u.p.prot_id, DUMP_UINT8, isakmp_ipsec_proto_enum_array);
649 r->u.p.spi_size = fetch1();
650 hex_dump("p.spi_size", &r->u.p.spi_size, DUMP_UINT8, NULL);
651 num_xform = fetch1();
652 hex_dump("length", &num_xform, DUMP_UINT8, NULL);
654 if (data_len < r->u.p.spi_size) {
655 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
656 return r;
658 r->u.p.spi = xallocc(r->u.p.spi_size);
659 fetchn(r->u.p.spi, r->u.p.spi_size);
660 hex_dump("p.spi", r->u.p.spi, r->u.p.spi_size, NULL);
661 length -= 8 + r->u.p.spi_size;
662 r->u.p.transforms = parse_isakmp_payload(ISAKMP_PAYLOAD_T,
663 &data, &length, reject, r->u.p.prot_id);
664 for (xform = r->u.p.transforms; xform; xform = xform->next)
665 if (num_xform-- == 0)
666 break;
667 if (num_xform != 0) {
668 *reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
669 return r;
672 /* Allow trailing garbage at end of payload. */
673 data_len -= olength - 8 - r->u.p.spi_size;
675 break;
677 case ISAKMP_PAYLOAD_T:
678 if (next_type != ISAKMP_PAYLOAD_T && next_type != 0) {
679 *reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
680 return r;
682 r->u.t.number = fetch1();
683 hex_dump("t.number", &r->u.t.number, DUMP_UINT8, NULL);
684 r->u.t.id = fetch1();
685 hex_dump("t.id", &r->u.t.id, DUMP_UINT8, transform_id_to_debug_strings(decode_proto));
686 if (fetch2() != 0) {
687 *reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
688 return r;
690 length -= 8;
691 r->u.t.attributes = parse_isakmp_attributes(&data, length, reject, decode_proto);
692 data_len -= olength - 8;
693 break;
695 case ISAKMP_PAYLOAD_KE:
696 case ISAKMP_PAYLOAD_HASH:
697 case ISAKMP_PAYLOAD_SIG:
698 case ISAKMP_PAYLOAD_NONCE:
699 case ISAKMP_PAYLOAD_VID:
700 case ISAKMP_PAYLOAD_NAT_D:
701 case ISAKMP_PAYLOAD_NAT_D_OLD:
702 r->u.ke.length = length - 4;
703 r->u.ke.data = xallocc(r->u.ke.length);
704 fetchn(r->u.ke.data, r->u.ke.length);
705 hex_dump("ke.data", r->u.ke.data, r->u.ke.length, NULL);
706 if (type == ISAKMP_PAYLOAD_VID)
707 print_vid(r->u.ke.data, r->u.ke.length);
708 break;
709 case ISAKMP_PAYLOAD_ID:
710 r->u.id.type = fetch1();
711 hex_dump("id.type", &r->u.id.type, DUMP_UINT8, isakmp_ipsec_id_enum_array);
712 r->u.id.protocol = fetch1();
713 hex_dump("id.protocol", &r->u.id.protocol, DUMP_UINT8, NULL); /* IP protocol nr */
714 r->u.id.port = fetch2();
715 hex_dump("id.port", &r->u.id.port, DUMP_UINT16, NULL);
716 r->u.id.length = length - 8;
717 r->u.id.data = xallocc(r->u.id.length);
718 fetchn(r->u.id.data, r->u.id.length);
719 hex_dump("id.data", r->u.id.data, r->u.id.length, NULL);
720 break;
721 case ISAKMP_PAYLOAD_CERT:
722 case ISAKMP_PAYLOAD_CR:
723 r->u.cert.encoding = fetch1();
724 hex_dump("cert.encoding", &r->u.cert.encoding, DUMP_UINT8, NULL);
725 r->u.cert.length = length - 5;
726 r->u.cert.data = xallocc(r->u.cert.length);
727 fetchn(r->u.cert.data, r->u.cert.length);
728 hex_dump("cert.data", r->u.cert.data, r->u.cert.length, NULL);
729 break;
730 case ISAKMP_PAYLOAD_N:
731 r->u.n.doi = fetch4();
732 hex_dump("n.doi", &r->u.n.doi, DUMP_UINT32, isakmp_doi_enum_array);
733 r->u.n.protocol = fetch1();
734 hex_dump("n.protocol", &r->u.n.protocol, DUMP_UINT8, isakmp_ipsec_proto_enum_array);
735 r->u.n.spi_length = fetch1();
736 hex_dump("n.spi_length", &r->u.n.spi_length, DUMP_UINT8, NULL);
737 r->u.n.type = fetch2();
738 hex_dump("n.type", &r->u.n.type, DUMP_UINT16, isakmp_notify_enum_array);
739 if (r->u.n.spi_length + 12u > length) {
740 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
741 return r;
743 r->u.n.spi = xallocc(r->u.n.spi_length);
744 fetchn(r->u.n.spi, r->u.n.spi_length);
745 hex_dump("n.spi", r->u.n.spi, r->u.n.spi_length, NULL);
746 r->u.n.data_length = length - 12 - r->u.n.spi_length;
747 r->u.n.data = xallocc(r->u.n.data_length);
748 fetchn(r->u.n.data, r->u.n.data_length);
749 hex_dump("n.data", r->u.n.data, r->u.n.data_length, NULL);
750 if ((r->u.n.doi == ISAKMP_DOI_IPSEC)&&(r->u.n.type == ISAKMP_N_IPSEC_RESPONDER_LIFETIME)) {
751 tmpdata = r->u.n.data;
752 r->u.n.attributes = parse_isakmp_attributes(&tmpdata, r->u.n.data_length, reject,
753 r->u.n.protocol);
755 break;
756 case ISAKMP_PAYLOAD_D:
757 r->u.d.doi = fetch4();
758 hex_dump("d.doi", &r->u.d.doi, DUMP_UINT32, isakmp_doi_enum_array);
759 r->u.d.protocol = fetch1();
760 hex_dump("d.protocol", &r->u.d.protocol, DUMP_UINT8, isakmp_ipsec_proto_enum_array);
761 r->u.d.spi_length = fetch1();
762 hex_dump("d.spi_length", &r->u.d.spi_length, DUMP_UINT8, NULL);
763 r->u.d.num_spi = fetch2();
764 hex_dump("d.num_spi", &r->u.d.num_spi, DUMP_UINT16, NULL);
765 if (r->u.d.num_spi * r->u.d.spi_length + 12u != length) {
766 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
767 return r;
769 r->u.d.spi = xallocc(sizeof(uint8_t *) * r->u.d.num_spi);
771 int i;
772 for (i = 0; i < r->u.d.num_spi; i++) {
773 r->u.d.spi[i] = xallocc(r->u.d.spi_length);
774 fetchn(r->u.d.spi[i], r->u.d.spi_length);
775 hex_dump("d.spi", r->u.d.spi[i], r->u.d.spi_length, NULL);
778 break;
779 case ISAKMP_PAYLOAD_MODECFG_ATTR:
780 r->u.modecfg.type = fetch1();
781 hex_dump("modecfg.type", &r->u.modecfg.type, DUMP_UINT8, isakmp_modecfg_cfg_enum_array);
782 if (fetch1() != 0) {
783 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
784 return r;
786 r->u.modecfg.id = fetch2();
787 hex_dump("modecfg.id", &r->u.modecfg.id, DUMP_UINT16, NULL);
788 length -= 8;
789 r->u.modecfg.attributes = parse_isakmp_attributes(&data, length, reject,
790 ISAKMP_IPSEC_PROTO_MODECFG); /* this "proto" is a hack for simplicity */
791 data_len -= olength - 8;
792 break;
794 default:
795 r->u.ke.length = length - 4;
796 r->u.ke.data = xallocc(r->u.ke.length);
797 fetchn(r->u.ke.data, r->u.ke.length);
798 hex_dump("UNKNOWN.data", r->u.ke.data, r->u.ke.length, NULL);
799 break;
801 *data_p = data;
802 *data_len_p = data_len;
803 hex_dump("DONE PARSING PAYLOAD type", &type, DUMP_UINT8, isakmp_payload_enum_array);
804 r->next = parse_isakmp_payload(next_type, data_p, data_len_p, reject, decode_proto);
805 return r;
808 struct isakmp_packet *parse_isakmp_packet(const uint8_t * data, size_t data_len, int * reject)
810 int reason = 0;
811 uint8_t payload;
812 struct isakmp_packet *r = new_isakmp_packet();
813 size_t o_data_len = data_len;
814 size_t isakmp_data_len;
816 if (data_len < ISAKMP_PAYLOAD_O) {
817 DEBUG(2, printf("packet to short: len = %lld < min = %lld\n", (long long) data_len, (long long)ISAKMP_PAYLOAD_O));
818 reason = ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS;
819 goto error;
822 DEBUG(3, printf("BEGIN_PARSE\n"));
823 DEBUG(3, printf("Recieved Packet Len: %zu\n", data_len));
824 fetchn(r->i_cookie, ISAKMP_COOKIE_LENGTH);
825 hex_dump("i_cookie", r->i_cookie, ISAKMP_COOKIE_LENGTH, NULL);
826 fetchn(r->r_cookie, ISAKMP_COOKIE_LENGTH);
827 hex_dump("r_cookie", r->r_cookie, ISAKMP_COOKIE_LENGTH, NULL);
828 payload = fetch1();
829 hex_dump("payload", &payload, DUMP_UINT8, isakmp_payload_enum_array);
831 r->isakmp_version = fetch1();
832 hex_dump("isakmp_version", &r->isakmp_version, DUMP_UINT8, NULL);
833 if (r->isakmp_version > ISAKMP_VERSION) {
834 if ((r->isakmp_version & 0xF0) >= (ISAKMP_VERSION & 0xF0))
835 reason = ISAKMP_N_INVALID_MAJOR_VERSION;
836 else
837 reason = ISAKMP_N_INVALID_MINOR_VERSION;
838 goto error;
841 r->exchange_type = fetch1();
842 hex_dump("exchange_type", &r->exchange_type, DUMP_UINT8, isakmp_exchange_enum_array);
843 r->flags = fetch1();
844 hex_dump("flags", &r->flags, DUMP_UINT8, NULL);
845 r->message_id = fetch4();
846 hex_dump("message_id", &r->message_id, sizeof(r->message_id), NULL);
848 isakmp_data_len = fetch4();
849 hex_dump("len", &isakmp_data_len, DUMP_UINT32, NULL);
850 if (o_data_len != isakmp_data_len) {
851 DEBUG(2, printf("isakmp length does not match packet length: isakmp = %lld != datalen = %lld\n",
852 (long long)isakmp_data_len, (long long)o_data_len));
853 reason = ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS;
854 goto error;
857 r->payload = parse_isakmp_payload(payload, &data, &data_len, &reason, 0);
858 if (reason != 0)
859 goto error;
861 DEBUG(3, printf("PARSE_OK\n"));
862 return r;
864 error:
865 free_isakmp_packet(r);
866 if (reject)
867 *reject = reason;
868 return NULL;
871 void test_pack_unpack(void)
873 static const uint8_t pack[] = {
874 0x7f, 0xba, 0x51, 0x29, 0x11, 0x9e, 0x76, 0xf7, 0x9a, 0x71, 0xee, 0x70,
875 0xaa, 0x82, 0xb9, 0x7f, 0x01, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
876 0x00, 0x00, 0x01, 0x4c, 0x04, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01,
877 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x01, 0x01, 0x00, 0x01,
878 0x00, 0x00, 0x00, 0x18, 0x00, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x05,
879 0x80, 0x02, 0x00, 0x01, 0x80, 0x04, 0x00, 0x02, 0x80, 0x03, 0x00, 0x01,
880 0x0a, 0x00, 0x00, 0x84, 0x1b, 0x1d, 0x4b, 0x29, 0x0e, 0x29, 0xb9, 0x6f,
881 0x18, 0x34, 0xd1, 0x2d, 0xba, 0x92, 0x7c, 0x53, 0x35, 0x76, 0x0e, 0x3b,
882 0x25, 0x92, 0x4f, 0x7c, 0x1e, 0x31, 0x41, 0x8c, 0xb9, 0xe3, 0xda, 0xf7,
883 0x53, 0xd3, 0x22, 0x8e, 0xff, 0xeb, 0xed, 0x5b, 0x95, 0x56, 0x8d, 0xba,
884 0xa8, 0xe3, 0x2a, 0x9b, 0xb4, 0x04, 0x5c, 0x90, 0xf0, 0xfe, 0x92, 0xc8,
885 0x57, 0xa2, 0xc6, 0x0c, 0x85, 0xbb, 0x56, 0xe8, 0x1c, 0xa7, 0x2c, 0x57,
886 0x04, 0xb6, 0xe0, 0x43, 0x82, 0xe1, 0x9f, 0x0b, 0xa6, 0x8b, 0xce, 0x7f,
887 0x9b, 0x75, 0xbb, 0xd3, 0xff, 0x0e, 0x89, 0x19, 0xaf, 0xc6, 0x2e, 0xf6,
888 0x92, 0x06, 0x46, 0x4f, 0xc7, 0x97, 0x22, 0xf4, 0xa6, 0xf9, 0x26, 0x34,
889 0x04, 0x33, 0x89, 0x34, 0xa9, 0x2f, 0x81, 0x92, 0xd3, 0x21, 0x4f, 0x45,
890 0xbe, 0x38, 0x12, 0x26, 0xec, 0x87, 0x45, 0xdd, 0x10, 0x1c, 0xd6, 0x16,
891 0x05, 0x00, 0x00, 0x18, 0x77, 0xdf, 0x37, 0x3c, 0x03, 0x02, 0xe2, 0xc8,
892 0xe1, 0x2f, 0x92, 0xf0, 0x2e, 0xa2, 0xa6, 0x00, 0x17, 0x8f, 0xdf, 0xb4,
893 0x08, 0x00, 0x00, 0x0c, 0x01, 0x11, 0x01, 0xf4, 0xcd, 0xb4, 0x53, 0x6d,
894 0x0d, 0x00, 0x00, 0x14, 0x07, 0x47, 0x8d, 0xa7, 0x0b, 0xd6, 0xd1, 0x66,
895 0x7a, 0xaf, 0x2e, 0x61, 0x2a, 0x91, 0x80, 0x94, 0x0d, 0x00, 0x00, 0x14,
896 0x12, 0xf5, 0xf2, 0x8c, 0x45, 0x71, 0x68, 0xa9, 0x70, 0x2d, 0x9f, 0xe2,
897 0x74, 0xcc, 0x01, 0x00, 0x0d, 0x00, 0x00, 0x0c, 0x09, 0x00, 0x26, 0x89,
898 0xdf, 0xd6, 0xb7, 0x12, 0x0d, 0x00, 0x00, 0x14, 0xaf, 0xca, 0xd7, 0x13,
899 0x68, 0xa1, 0xf1, 0xc9, 0x6b, 0x86, 0x96, 0xfc, 0x77, 0x57, 0x01, 0x00,
900 0x00, 0x00, 0x00, 0x14, 0x1f, 0x07, 0xf7, 0x0e, 0xaa, 0x65, 0x14, 0xd3,
901 0xb0, 0xfa, 0x96, 0x54, 0x2a, 0x50, 0x03, 0x05
903 uint8_t *unpack;
904 size_t unpack_len;
905 struct isakmp_packet *p;
906 int reject;
908 p = parse_isakmp_packet(pack, sizeof(pack), &reject);
909 flatten_isakmp_packet(p, &unpack, &unpack_len, 8);
910 if (unpack_len != sizeof(pack)
911 || memcmp(unpack, pack, sizeof(pack)) != 0)
912 abort();
913 free(unpack);
914 free_isakmp_packet(p);