tagged release 0.3.2
[vpnc.git] / isakmp-pkt.c
blob7ab2496c20bebaccc532002bd1541e4276e84187
1 /* ISAKMP packing and unpacking routines.
2 Copyright (C) 2002 Geoffrey Keating
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include <assert.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <stdio.h>
25 #include "sysdep.h"
26 #include "config.h"
27 #include "isakmp-pkt.h"
29 void *xallocc(size_t x)
31 void *result;
32 result = calloc(1, x);
33 if (result == NULL)
34 error(1, errno, "malloc of %lu bytes failed", (unsigned long)x);
35 return result;
38 struct flow {
39 size_t len;
40 uint8_t *base;
41 uint8_t *end;
44 static uint8_t *flow_reserve_p(struct flow *f, size_t sz)
46 size_t l = f->end - f->base;
47 if (l + sz > f->len) {
48 size_t new_len = f->len == 0 ? 128 : f->len;
49 while (l + sz >= new_len)
50 new_len *= 2;
52 if (f->base == NULL)
53 f->base = malloc(new_len);
54 else
55 f->base = realloc(f->base, new_len);
56 if (f->base == NULL)
57 error(1, errno, "alloc of %lud bytes failed", (unsigned long)new_len);
58 memset(f->base + f->len, 0, new_len - f->len);
59 f->end = f->base + l;
60 f->len = new_len;
62 f->end += sz;
63 return f->end - sz;
66 static size_t flow_reserve(struct flow *f, size_t sz)
68 uint8_t *p = flow_reserve_p(f, sz);
69 return p - f->base;
72 static void flow_x(struct flow *f, uint8_t * data, size_t data_len)
74 memcpy(flow_reserve_p(f, data_len), data, data_len);
77 static void flow_1(struct flow *f, uint8_t d)
79 flow_reserve_p(f, 1)[0] = d;
82 static void flow_2(struct flow *f, uint16_t d)
84 uint8_t dd[2];
85 dd[0] = d >> 8;
86 dd[1] = d;
87 flow_x(f, dd, sizeof(dd));
90 static void flow_4(struct flow *f, uint32_t d)
92 uint8_t dd[4];
93 dd[0] = d >> 24;
94 dd[1] = d >> 16;
95 dd[2] = d >> 8;
96 dd[3] = d;
97 flow_x(f, dd, sizeof(dd));
100 static void init_flow(struct flow *f)
102 memset(f, 0, sizeof(*f));
105 static void flow_attribute(struct flow *f, struct isakmp_attribute *p)
107 for (; p; p = p->next)
108 switch (p->af) {
109 case isakmp_attr_lots:
110 flow_2(f, p->type);
111 flow_2(f, p->u.lots.length);
112 flow_x(f, p->u.lots.data, p->u.lots.length);
113 break;
114 case isakmp_attr_16:
115 flow_2(f, p->type | 0x8000);
116 flow_2(f, p->u.attr_16);
117 break;
118 case isakmp_attr_2x8:
119 flow_2(f, p->type | 0x8000);
120 flow_x(f, p->u.attr_2x8, 2);
121 break;
122 default:
123 abort();
127 static void flow_payload(struct flow *f, struct isakmp_payload *p)
129 size_t lpos;
130 size_t baselen;
132 if (p == NULL)
133 return;
135 baselen = f->end - f->base;
136 if (p->next == NULL)
137 flow_1(f, 0);
138 else
139 flow_1(f, p->next->type);
140 flow_1(f, 0);
141 lpos = flow_reserve(f, 2);
142 switch (p->type) {
143 case ISAKMP_PAYLOAD_SA:
144 flow_4(f, p->u.sa.doi);
145 flow_4(f, p->u.sa.situation);
146 flow_payload(f, p->u.sa.proposals);
147 break;
148 case ISAKMP_PAYLOAD_P:
149 flow_1(f, p->u.p.number);
150 flow_1(f, p->u.p.prot_id);
151 flow_1(f, p->u.p.spi_size);
153 uint8_t num_xform = 0;
154 struct isakmp_payload *xform;
155 for (xform = p->u.p.transforms; xform; xform = xform->next)
156 num_xform++;
157 flow_1(f, num_xform);
159 flow_x(f, p->u.p.spi, p->u.p.spi_size);
160 flow_payload(f, p->u.p.transforms);
161 break;
162 case ISAKMP_PAYLOAD_T:
163 flow_1(f, p->u.t.number);
164 flow_1(f, p->u.t.id);
165 flow_2(f, 0);
166 flow_attribute(f, p->u.t.attributes);
167 break;
168 case ISAKMP_PAYLOAD_KE:
169 case ISAKMP_PAYLOAD_HASH:
170 case ISAKMP_PAYLOAD_SIG:
171 case ISAKMP_PAYLOAD_NONCE:
172 case ISAKMP_PAYLOAD_VID:
173 case ISAKMP_PAYLOAD_NAT_D:
174 case ISAKMP_PAYLOAD_NAT_D_OLD:
175 flow_x(f, p->u.ke.data, p->u.ke.length);
176 break;
177 case ISAKMP_PAYLOAD_ID:
178 flow_1(f, p->u.id.type);
179 flow_1(f, p->u.id.protocol);
180 flow_2(f, p->u.id.port);
181 flow_x(f, p->u.id.data, p->u.id.length);
182 break;
183 case ISAKMP_PAYLOAD_CERT:
184 case ISAKMP_PAYLOAD_CR:
185 flow_1(f, p->u.cert.encoding);
186 flow_x(f, p->u.cert.data, p->u.cert.length);
187 break;
188 case ISAKMP_PAYLOAD_N:
189 flow_4(f, p->u.n.doi);
190 flow_1(f, p->u.n.protocol);
191 flow_1(f, p->u.n.spi_length);
192 flow_2(f, p->u.n.type);
193 flow_x(f, p->u.n.spi, p->u.n.spi_length);
194 flow_x(f, p->u.n.data, p->u.n.data_length);
195 break;
196 case ISAKMP_PAYLOAD_D:
197 flow_4(f, p->u.d.doi);
198 flow_1(f, p->u.d.protocol);
199 flow_1(f, p->u.d.spi_length);
200 flow_2(f, p->u.d.num_spi);
201 if (p->u.d.spi_length > 0) {
202 int i;
203 for (i = 0; i < p->u.d.num_spi; i++)
204 flow_x(f, p->u.d.spi[i], p->u.d.spi_length);
206 break;
207 case ISAKMP_PAYLOAD_MODECFG_ATTR:
208 flow_1(f, p->u.modecfg.type);
209 flow_1(f, 0);
210 flow_2(f, p->u.modecfg.id);
211 flow_attribute(f, p->u.modecfg.attributes);
212 break;
213 default:
214 abort();
216 f->base[lpos] = (f->end - f->base - baselen) >> 8;
217 f->base[lpos + 1] = (f->end - f->base - baselen);
218 flow_payload(f, p->next);
221 void flatten_isakmp_payload(struct isakmp_payload *p, uint8_t ** result, size_t * size)
223 struct flow f;
224 init_flow(&f);
225 flow_payload(&f, p);
226 *result = f.base;
227 *size = f.end - f.base;
230 void flatten_isakmp_packet(struct isakmp_packet *p, uint8_t ** result, size_t * size, size_t blksz)
232 struct flow f;
233 size_t lpos, sz, padding;
235 init_flow(&f);
236 flow_x(&f, p->i_cookie, ISAKMP_COOKIE_LENGTH);
237 flow_x(&f, p->r_cookie, ISAKMP_COOKIE_LENGTH);
238 if (p->payload == NULL)
239 flow_1(&f, 0);
240 else
241 flow_1(&f, p->payload->type);
242 flow_1(&f, p->isakmp_version);
243 flow_1(&f, p->exchange_type);
244 flow_1(&f, p->flags);
245 flow_4(&f, p->message_id);
246 lpos = flow_reserve(&f, 4);
247 flow_payload(&f, p->payload);
248 if (p->flags & ISAKMP_FLAG_E) {
249 assert(blksz != 0);
250 sz = (f.end - f.base) - ISAKMP_PAYLOAD_O;
251 padding = blksz - (sz % blksz);
252 if (padding == blksz)
253 padding = 0;
254 DEBUG(3, printf("size = %ld, blksz = %ld, padding = %ld\n",
255 (long)sz, (long)blksz, (long)padding));
256 flow_reserve(&f, padding);
258 f.base[lpos] = (f.end - f.base) >> 24;
259 f.base[lpos + 1] = (f.end - f.base) >> 16;
260 f.base[lpos + 2] = (f.end - f.base) >> 8;
261 f.base[lpos + 3] = (f.end - f.base);
262 *result = f.base;
263 *size = f.end - f.base;
264 /*DUMP*/ if (opt_debug >= 3) {
265 printf("\n sending: ========================>\n");
266 free_isakmp_packet(parse_isakmp_packet(f.base, f.end - f.base, NULL));
270 struct isakmp_attribute *new_isakmp_attribute(uint16_t type, struct isakmp_attribute *next)
272 struct isakmp_attribute *r = xallocc(sizeof(struct isakmp_attribute));
273 r->type = type;
274 r->next = next;
275 return r;
278 struct isakmp_attribute *new_isakmp_attribute_16(uint16_t type, uint16_t data,
279 struct isakmp_attribute *next)
281 struct isakmp_attribute *r = xallocc(sizeof(struct isakmp_attribute));
282 r->next = next;
283 r->type = type;
284 r->af = isakmp_attr_16;
285 r->u.attr_16 = data;
286 return r;
289 struct isakmp_packet *new_isakmp_packet(void)
291 return xallocc(sizeof(struct isakmp_packet));
294 struct isakmp_payload *new_isakmp_payload(uint8_t type)
296 struct isakmp_payload *result = xallocc(sizeof(struct isakmp_packet));
297 result->type = type;
298 return result;
301 struct isakmp_payload *new_isakmp_data_payload(uint8_t type, const void *data, size_t data_length)
303 struct isakmp_payload *result = xallocc(sizeof(struct isakmp_packet));
305 if (type != ISAKMP_PAYLOAD_KE && type != ISAKMP_PAYLOAD_HASH
306 && type != ISAKMP_PAYLOAD_SIG && type != ISAKMP_PAYLOAD_NONCE
307 && type != ISAKMP_PAYLOAD_VID && type != ISAKMP_PAYLOAD_NAT_D
308 && type != ISAKMP_PAYLOAD_NAT_D_OLD)
309 abort();
310 if (data_length >= 16384)
311 abort();
313 result->type = type;
314 result->u.ke.length = data_length;
315 result->u.ke.data = xallocc(data_length);
316 memcpy(result->u.ke.data, data, data_length);
317 return result;
320 void free_isakmp_payload(struct isakmp_payload *p)
322 struct isakmp_payload *nxt;
324 if (p == NULL)
325 return;
327 switch (p->type) {
328 case ISAKMP_PAYLOAD_SA:
329 free_isakmp_payload(p->u.sa.proposals);
330 break;
331 case ISAKMP_PAYLOAD_P:
332 free_isakmp_payload(p->u.p.transforms);
333 break;
334 case ISAKMP_PAYLOAD_T:
336 struct isakmp_attribute *att, *natt;
337 for (att = p->u.t.attributes; att; att = natt) {
338 natt = att->next;
339 if (att->af == isakmp_attr_lots)
340 free(att->u.lots.data);
341 free(att);
344 break;
345 case ISAKMP_PAYLOAD_KE:
346 case ISAKMP_PAYLOAD_HASH:
347 case ISAKMP_PAYLOAD_SIG:
348 case ISAKMP_PAYLOAD_NONCE:
349 case ISAKMP_PAYLOAD_VID:
350 case ISAKMP_PAYLOAD_NAT_D:
351 case ISAKMP_PAYLOAD_NAT_D_OLD:
352 free(p->u.ke.data);
353 break;
354 case ISAKMP_PAYLOAD_ID:
355 free(p->u.id.data);
356 break;
357 case ISAKMP_PAYLOAD_CERT:
358 case ISAKMP_PAYLOAD_CR:
359 free(p->u.cert.data);
360 break;
361 case ISAKMP_PAYLOAD_N:
362 free(p->u.n.spi);
363 free(p->u.n.data);
364 break;
365 case ISAKMP_PAYLOAD_D:
366 if (p->u.d.spi) {
367 int i;
368 for (i = 0; i < p->u.d.num_spi; i++)
369 free(p->u.d.spi[i]);
370 free(p->u.d.spi);
372 break;
373 case ISAKMP_PAYLOAD_MODECFG_ATTR:
375 struct isakmp_attribute *att, *natt;
376 for (att = p->u.modecfg.attributes; att; att = natt) {
377 natt = att->next;
378 if (att->af == isakmp_attr_lots)
379 free(att->u.lots.data);
380 free(att);
383 break;
384 default:
385 abort();
388 nxt = p->next;
389 free(p);
390 free_isakmp_payload(nxt);
393 void free_isakmp_packet(struct isakmp_packet *p)
395 if (p == NULL)
396 return;
397 free_isakmp_payload(p->payload);
398 free(p);
401 #define fetch4() \
402 (data += 4, data_len -= 4, \
403 (uint32_t)(data[-4]) << 24 | (uint32_t)(data[-3]) << 16 \
404 | (uint32_t)(data[-2]) << 8 | data[-1])
405 #define fetch2() \
406 (data += 2, data_len -= 2, \
407 (uint16_t)(data[-2]) << 8 | data[-1])
408 #define fetch1() (data_len--, *data++)
409 #define fetchn(d,n) \
410 (memcpy ((d), data, (n)), data += (n), data_len -= (n))
412 static struct isakmp_attribute *parse_isakmp_attributes(const uint8_t ** data_p,
413 size_t data_len, int * reject)
415 const uint8_t *data = *data_p;
416 struct isakmp_attribute *r;
417 uint16_t type, length;
419 if (data_len < 4)
420 return NULL;
422 r = new_isakmp_attribute(0, NULL);
423 type = fetch2();
424 length = fetch2();
425 if (type & 0x8000) {
426 r->type = type & ~0x8000;
427 hex_dump("t.attributes.type", &r->type, UINT16);
428 r->af = isakmp_attr_16;
429 r->u.attr_16 = length;
430 if ((ISAKMP_XAUTH_ATTRIB_TYPE <= r->type)
431 && (r->type <= ISAKMP_XAUTH_ATTRIB_ANSWER)
432 && (opt_debug < 99))
433 DEBUG(3, printf("(not dumping xauth data)\n"));
434 else
435 hex_dump("t.attributes.u.attr_16", &r->u.attr_16, UINT16);
436 } else {
437 r->type = type;
438 hex_dump("t.attributes.type", &r->type, UINT16);
439 r->af = isakmp_attr_lots;
440 r->u.lots.length = length;
441 if ((ISAKMP_XAUTH_ATTRIB_TYPE <= r->type) && (r->type <= ISAKMP_XAUTH_ATTRIB_ANSWER)
442 && (opt_debug < 99))
443 DEBUG(3, printf("(not dumping xauth data length)\n"));
444 else
445 hex_dump("t.attributes.u.lots.length", &r->u.lots.length, UINT16);
446 if (data_len < length) {
447 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
448 return r;
450 r->u.lots.data = xallocc(length);
451 fetchn(r->u.lots.data, length);
452 if ((ISAKMP_XAUTH_ATTRIB_TYPE <= type) && (type <= ISAKMP_XAUTH_ATTRIB_ANSWER)
453 && (opt_debug < 99))
454 DEBUG(3, printf("(not dumping xauth data)\n"));
455 else
456 hex_dump("t.attributes.u.lots.data", r->u.lots.data, r->u.lots.length);
458 r->next = parse_isakmp_attributes(&data, data_len, reject);
459 *data_p = data;
460 return r;
463 static struct isakmp_payload *parse_isakmp_payload(uint8_t type,
464 const uint8_t ** data_p, size_t * data_len_p, int * reject)
466 const uint8_t *data = *data_p;
467 size_t data_len = *data_len_p;
468 struct isakmp_payload *r;
469 uint8_t next_type;
470 size_t length, olength;
472 static const uint16_t min_payload_len[ISAKMP_PAYLOAD_MODECFG_ATTR + 1] = {
473 4, 12, 8, 8, 4, 8, 5, 5, 4, 4, 4, 12, 12, 4, 8
476 hex_dump("PARSING PAYLOAD type", &type, UINT8);
477 if (type == 0)
478 return NULL;
479 if (type <= ISAKMP_PAYLOAD_MODECFG_ATTR) {
480 if (data_len < min_payload_len[type]) {
481 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
482 return NULL;
484 } else if (data_len < 4) {
485 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
486 return NULL;
489 r = new_isakmp_payload(type);
490 next_type = fetch1();
491 hex_dump("next_type", &next_type, UINT8);
492 if (fetch1() != 0) {
493 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
494 return r;
496 length = fetch2();
497 hex_dump("length", &length, UINT16);
498 if (length > data_len + 4
499 || ((type <= ISAKMP_PAYLOAD_MODECFG_ATTR)&&(length < min_payload_len[type]))
500 || (length < 4)) {
501 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
502 return r;
504 olength = length;
505 switch (type) {
506 case ISAKMP_PAYLOAD_SA:
507 r->u.sa.doi = fetch4();
508 hex_dump("sa.doi", &r->u.sa.doi, UINT32);
509 if (r->u.sa.doi != ISAKMP_DOI_IPSEC) {
510 *reject = ISAKMP_N_DOI_NOT_SUPPORTED;
511 return r;
513 r->u.sa.situation = fetch4();
514 hex_dump("sa.situation", &r->u.sa.situation, UINT32);
515 if (r->u.sa.situation != ISAKMP_IPSEC_SIT_IDENTITY_ONLY) {
516 *reject = ISAKMP_N_SITUATION_NOT_SUPPORTED;
517 return r;
519 *reject = 0;
520 length -= 12;
521 r->u.sa.proposals = parse_isakmp_payload(ISAKMP_PAYLOAD_P, &data, &length, reject);
522 if (*reject != 0)
523 return r;
524 /* Allow trailing garbage at end of payload. */
525 data_len -= olength - 12;
526 break;
528 case ISAKMP_PAYLOAD_P:
529 if (next_type != ISAKMP_PAYLOAD_P && next_type != 0) {
530 *reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
531 return r;
534 uint8_t num_xform;
535 struct isakmp_payload *xform;
537 r->u.p.number = fetch1();
538 hex_dump("p.number", &r->u.p.number, UINT8);
539 r->u.p.prot_id = fetch1();
540 hex_dump("p.prot_id", &r->u.p.prot_id, UINT8);
541 r->u.p.spi_size = fetch1();
542 hex_dump("p.spi_size", &r->u.p.spi_size, UINT8);
543 num_xform = fetch1();
544 hex_dump("length", &num_xform, UINT8);
546 if (data_len < r->u.p.spi_size) {
547 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
548 return r;
550 r->u.p.spi = xallocc(r->u.p.spi_size);
551 fetchn(r->u.p.spi, r->u.p.spi_size);
552 hex_dump("p.spi", r->u.p.spi, r->u.p.spi_size);
553 length -= 8 + r->u.p.spi_size;
554 r->u.p.transforms = parse_isakmp_payload(ISAKMP_PAYLOAD_T,
555 &data, &length, reject);
556 for (xform = r->u.p.transforms; xform; xform = xform->next)
557 if (num_xform-- == 0)
558 break;
559 if (num_xform != 0) {
560 *reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
561 return r;
564 /* Allow trailing garbage at end of payload. */
565 data_len -= olength - 8 - r->u.p.spi_size;
567 break;
569 case ISAKMP_PAYLOAD_T:
570 if (next_type != ISAKMP_PAYLOAD_T && next_type != 0) {
571 *reject = ISAKMP_N_INVALID_PAYLOAD_TYPE;
572 return r;
574 r->u.t.number = fetch1();
575 hex_dump("t.number", &r->u.t.number, UINT8);
576 r->u.t.id = fetch1();
577 hex_dump("t.id", &r->u.t.id, UINT8);
578 if (fetch2() != 0) {
579 *reject = ISAKMP_N_BAD_PROPOSAL_SYNTAX;
580 return r;
582 length -= 8;
583 r->u.t.attributes = parse_isakmp_attributes(&data, length, reject);
584 data_len -= olength - 8;
585 break;
587 case ISAKMP_PAYLOAD_KE:
588 case ISAKMP_PAYLOAD_HASH:
589 case ISAKMP_PAYLOAD_SIG:
590 case ISAKMP_PAYLOAD_NONCE:
591 case ISAKMP_PAYLOAD_VID:
592 case ISAKMP_PAYLOAD_NAT_D:
593 case ISAKMP_PAYLOAD_NAT_D_OLD:
594 r->u.ke.length = length - 4;
595 r->u.ke.data = xallocc(r->u.ke.length);
596 fetchn(r->u.ke.data, r->u.ke.length);
597 hex_dump("ke.data", r->u.ke.data, r->u.ke.length);
598 break;
599 case ISAKMP_PAYLOAD_ID:
600 r->u.id.type = fetch1();
601 hex_dump("id.type", &r->u.id.type, UINT8);
602 r->u.id.protocol = fetch1();
603 hex_dump("id.protocol", &r->u.id.protocol, UINT8);
604 r->u.id.port = fetch2();
605 hex_dump("id.port", &r->u.id.port, sizeof(r->u.id.port));
606 r->u.id.length = length - 8;
607 r->u.id.data = xallocc(r->u.id.length);
608 fetchn(r->u.id.data, r->u.id.length);
609 hex_dump("id.data", r->u.id.data, r->u.id.length);
610 break;
611 case ISAKMP_PAYLOAD_CERT:
612 case ISAKMP_PAYLOAD_CR:
613 r->u.cert.encoding = fetch1();
614 hex_dump("cert.encoding", &r->u.cert.encoding, UINT8);
615 r->u.cert.length = length - 5;
616 fetchn(r->u.cert.data, r->u.cert.length);
617 hex_dump("cert.data", r->u.cert.data, r->u.cert.length);
618 break;
619 case ISAKMP_PAYLOAD_N:
620 r->u.n.doi = fetch4();
621 hex_dump("n.doi", &r->u.n.doi, UINT32);
622 r->u.n.protocol = fetch1();
623 hex_dump("n.protocol", &r->u.n.protocol, UINT8);
624 r->u.n.spi_length = fetch1();
625 hex_dump("n.spi_length", &r->u.n.spi_length, UINT8);
626 r->u.n.type = fetch2();
627 hex_dump("n.type", &r->u.n.type, UINT16);
628 if (r->u.n.spi_length + 12u > length) {
629 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
630 return r;
632 r->u.n.spi = xallocc(r->u.n.spi_length);
633 fetchn(r->u.n.spi, r->u.n.spi_length);
634 hex_dump("n.spi", r->u.n.spi, r->u.n.spi_length);
635 r->u.n.data_length = length - 12 - r->u.n.spi_length;
636 r->u.n.data = xallocc(r->u.n.data_length);
637 fetchn(r->u.n.data, r->u.n.data_length);
638 hex_dump("n.data", r->u.n.data, r->u.n.data_length);
639 break;
640 case ISAKMP_PAYLOAD_D:
641 r->u.n.doi = fetch4(); /*FIXME: huuuh? */
642 hex_dump("n.doi", &r->u.n.doi, UINT32);
643 r->u.n.protocol = fetch1();
644 hex_dump("n.protocol", &r->u.n.protocol, UINT8);
645 r->u.n.spi_length = fetch1();
646 hex_dump("n.spi_length", &r->u.n.spi_length, UINT8);
647 r->u.d.num_spi = fetch2();
648 hex_dump("d.num_spi", &r->u.d.num_spi, UINT16);
649 if (r->u.d.num_spi * r->u.n.spi_length + 12u != length) {
650 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
651 return r;
653 r->u.d.spi = xallocc(sizeof(uint8_t *) * r->u.d.num_spi);
655 int i;
656 for (i = 0; i < r->u.d.num_spi; i++) {
657 r->u.d.spi[i] = xallocc(r->u.d.spi_length);
658 fetchn(r->u.d.spi[i], r->u.d.spi_length);
659 hex_dump("d.spi", r->u.d.spi[i], r->u.d.spi_length);
662 break;
663 case ISAKMP_PAYLOAD_MODECFG_ATTR:
664 r->u.modecfg.type = fetch1();
665 hex_dump("modecfg.type", &r->u.modecfg.type, UINT8);
666 if (fetch1() != 0) {
667 *reject = ISAKMP_N_PAYLOAD_MALFORMED;
668 return r;
670 r->u.t.id = fetch2();
671 hex_dump("t.id", &r->u.t.id, UINT16);
672 length -= 8;
673 r->u.t.attributes = parse_isakmp_attributes(&data, length, reject);
674 data_len -= olength - 8;
675 break;
677 default:
678 r->u.ke.length = length - 4;
679 r->u.ke.data = xallocc(r->u.ke.length);
680 fetchn(r->u.ke.data, r->u.ke.length);
681 hex_dump("UNKNOWN.data", r->u.ke.data, r->u.ke.length);
682 break;
684 *data_p = data;
685 *data_len_p = data_len;
686 hex_dump("DONE PARSING PAYLOAD type", &type, UINT8);
687 r->next = parse_isakmp_payload(next_type, data_p, data_len_p, reject);
688 return r;
691 struct isakmp_packet *parse_isakmp_packet(const uint8_t * data, size_t data_len, int * reject)
693 int reason = 0;
694 uint8_t payload;
695 struct isakmp_packet *r = new_isakmp_packet();
696 size_t o_data_len = data_len;
697 size_t isakmp_data_len;
699 if (data_len < ISAKMP_PAYLOAD_O) {
700 DEBUG(2, printf("packet to short: len = %d < min = %d\n", data_len, ISAKMP_PAYLOAD_O));
701 reason = ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS;
702 goto error;
705 DEBUG(3, printf("\nBEGIN_PARSE\n"));
706 fetchn(r->i_cookie, ISAKMP_COOKIE_LENGTH);
707 hex_dump("i_cookie", r->i_cookie, ISAKMP_COOKIE_LENGTH);
708 fetchn(r->r_cookie, ISAKMP_COOKIE_LENGTH);
709 hex_dump("r_cookie", r->r_cookie, ISAKMP_COOKIE_LENGTH);
710 payload = fetch1();
711 hex_dump("payload", &payload, UINT8);
713 r->isakmp_version = fetch1();
714 hex_dump("isakmp_version", &r->isakmp_version, UINT8);
715 if (r->isakmp_version > ISAKMP_VERSION) {
716 if ((r->isakmp_version & 0xF0) >= (ISAKMP_VERSION & 0xF0))
717 reason = ISAKMP_N_INVALID_MAJOR_VERSION;
718 else
719 reason = ISAKMP_N_INVALID_MINOR_VERSION;
720 goto error;
723 r->exchange_type = fetch1();
724 hex_dump("exchange_type", &r->exchange_type, UINT8);
725 r->flags = fetch1();
726 hex_dump("flags", &r->flags, UINT8);
727 r->message_id = fetch4();
728 hex_dump("message_id", &r->message_id, sizeof(r->message_id));
730 isakmp_data_len = fetch4();
731 hex_dump("len", &isakmp_data_len, UINT32);
732 if (o_data_len != isakmp_data_len) {
733 DEBUG(2, printf("isakmp length does not match packet length: isakmp = %d != datalen = %d\n",
734 isakmp_data_len, o_data_len));
735 reason = ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS;
736 goto error;
739 r->payload = parse_isakmp_payload(payload, &data, &data_len, &reason);
740 if (reason != 0)
741 goto error;
743 DEBUG(3, printf("PARSE_OK\n\n"));
744 return r;
746 error:
747 free_isakmp_packet(r);
748 if (reject)
749 *reject = reason;
750 return NULL;
753 const char *isakmp_notify_to_error(uint16_t notify)
755 static const struct {
756 uint16_t id;
757 const char *name;
758 } data[] = {
759 { ISAKMP_N_INVALID_PAYLOAD_TYPE, "INVALID_PAYLOAD_TYPE"},
760 { ISAKMP_N_DOI_NOT_SUPPORTED, "DOI_NOT_SUPPORTED"},
761 { ISAKMP_N_SITUATION_NOT_SUPPORTED, "SITUATION_NOT_SUPPORTED"},
762 { ISAKMP_N_INVALID_COOKIE, "INVALID_COOKIE"},
763 { ISAKMP_N_INVALID_MAJOR_VERSION, "INVALID_MAJOR_VERSION"},
764 { ISAKMP_N_INVALID_MINOR_VERSION, "INVALID_MINOR_VERSION"},
765 { ISAKMP_N_INVALID_EXCHANGE_TYPE, "INVALID_EXCHANGE_TYPE"},
766 { ISAKMP_N_INVALID_FLAGS, "INVALID_FLAGS"},
767 { ISAKMP_N_INVALID_MESSAGE_ID, "INVALID_MESSAGE_ID"},
768 { ISAKMP_N_INVALID_PROTOCOL_ID, "INVALID_PROTOCOL_ID"},
769 { ISAKMP_N_INVALID_SPI, "INVALID_SPI"},
770 { ISAKMP_N_INVALID_TRANSFORM_ID, "INVALID_TRANSFORM_ID"},
771 { ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED, "ATTRIBUTES_NOT_SUPPORTED"},
772 { ISAKMP_N_NO_PROPOSAL_CHOSEN, "NO_PROPOSAL_CHOSEN"},
773 { ISAKMP_N_BAD_PROPOSAL_SYNTAX, "BAD_PROPOSAL_SYNTAX"},
774 { ISAKMP_N_PAYLOAD_MALFORMED, "PAYLOAD_MALFORMED"},
775 { ISAKMP_N_INVALID_KEY_INFORMATION, "INVALID_KEY_INFORMATION"},
776 { ISAKMP_N_INVALID_ID_INFORMATION, "INVALID_ID_INFORMATION"},
777 { ISAKMP_N_INVALID_CERT_ENCODING, "INVALID_CERT_ENCODING"},
778 { ISAKMP_N_INVALID_CERTIFICATE, "INVALID_CERTIFICATE"},
779 { ISAKMP_N_CERT_TYPE_UNSUPPORTED, "CERT_TYPE_UNSUPPORTED"},
780 { ISAKMP_N_INVALID_CERT_AUTHORITY, "INVALID_CERT_AUTHORITY"},
781 { ISAKMP_N_INVALID_HASH_INFORMATION, "INVALID_HASH_INFORMATION"},
782 { ISAKMP_N_AUTHENTICATION_FAILED, "AUTHENTICATION_FAILED"},
783 { ISAKMP_N_INVALID_SIGNATURE, "INVALID_SIGNATURE"},
784 { ISAKMP_N_ADDRESS_NOTIFICATION, "ADDRESS_NOTIFICATION"},
785 { ISAKMP_N_NOTIFY_SA_LIFETIME, "NOTIFY_SA_LIFETIME"},
786 { ISAKMP_N_CERTIFICATE_UNAVAILABLE, "CERTIFICATE_UNAVAILABLE"},
787 { ISAKMP_N_UNSUPPORTED_EXCHANGE_TYPE, "UNSUPPORTED_EXCHANGE_TYPE"},
788 { ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS, "UNEQUAL_PAYLOAD_LENGTHS"}
790 size_t i;
791 static char number[10];
793 for (i = 0; i < sizeof(data) / sizeof(data[0]); i++)
794 if (data[i].id == notify)
795 return data[i].name;
796 sprintf(number, "%d", notify);
797 return number;
800 void test_pack_unpack(void)
802 static const uint8_t pack[] = {
803 0x7f, 0xba, 0x51, 0x29, 0x11, 0x9e, 0x76, 0xf7, 0x9a, 0x71, 0xee, 0x70,
804 0xaa, 0x82, 0xb9, 0x7f, 0x01, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
805 0x00, 0x00, 0x01, 0x4c, 0x04, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01,
806 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x01, 0x01, 0x00, 0x01,
807 0x00, 0x00, 0x00, 0x18, 0x00, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x05,
808 0x80, 0x02, 0x00, 0x01, 0x80, 0x04, 0x00, 0x02, 0x80, 0x03, 0x00, 0x01,
809 0x0a, 0x00, 0x00, 0x84, 0x1b, 0x1d, 0x4b, 0x29, 0x0e, 0x29, 0xb9, 0x6f,
810 0x18, 0x34, 0xd1, 0x2d, 0xba, 0x92, 0x7c, 0x53, 0x35, 0x76, 0x0e, 0x3b,
811 0x25, 0x92, 0x4f, 0x7c, 0x1e, 0x31, 0x41, 0x8c, 0xb9, 0xe3, 0xda, 0xf7,
812 0x53, 0xd3, 0x22, 0x8e, 0xff, 0xeb, 0xed, 0x5b, 0x95, 0x56, 0x8d, 0xba,
813 0xa8, 0xe3, 0x2a, 0x9b, 0xb4, 0x04, 0x5c, 0x90, 0xf0, 0xfe, 0x92, 0xc8,
814 0x57, 0xa2, 0xc6, 0x0c, 0x85, 0xbb, 0x56, 0xe8, 0x1c, 0xa7, 0x2c, 0x57,
815 0x04, 0xb6, 0xe0, 0x43, 0x82, 0xe1, 0x9f, 0x0b, 0xa6, 0x8b, 0xce, 0x7f,
816 0x9b, 0x75, 0xbb, 0xd3, 0xff, 0x0e, 0x89, 0x19, 0xaf, 0xc6, 0x2e, 0xf6,
817 0x92, 0x06, 0x46, 0x4f, 0xc7, 0x97, 0x22, 0xf4, 0xa6, 0xf9, 0x26, 0x34,
818 0x04, 0x33, 0x89, 0x34, 0xa9, 0x2f, 0x81, 0x92, 0xd3, 0x21, 0x4f, 0x45,
819 0xbe, 0x38, 0x12, 0x26, 0xec, 0x87, 0x45, 0xdd, 0x10, 0x1c, 0xd6, 0x16,
820 0x05, 0x00, 0x00, 0x18, 0x77, 0xdf, 0x37, 0x3c, 0x03, 0x02, 0xe2, 0xc8,
821 0xe1, 0x2f, 0x92, 0xf0, 0x2e, 0xa2, 0xa6, 0x00, 0x17, 0x8f, 0xdf, 0xb4,
822 0x08, 0x00, 0x00, 0x0c, 0x01, 0x11, 0x01, 0xf4, 0xcd, 0xb4, 0x53, 0x6d,
823 0x0d, 0x00, 0x00, 0x14, 0x07, 0x47, 0x8d, 0xa7, 0x0b, 0xd6, 0xd1, 0x66,
824 0x7a, 0xaf, 0x2e, 0x61, 0x2a, 0x91, 0x80, 0x94, 0x0d, 0x00, 0x00, 0x14,
825 0x12, 0xf5, 0xf2, 0x8c, 0x45, 0x71, 0x68, 0xa9, 0x70, 0x2d, 0x9f, 0xe2,
826 0x74, 0xcc, 0x01, 0x00, 0x0d, 0x00, 0x00, 0x0c, 0x09, 0x00, 0x26, 0x89,
827 0xdf, 0xd6, 0xb7, 0x12, 0x0d, 0x00, 0x00, 0x14, 0xaf, 0xca, 0xd7, 0x13,
828 0x68, 0xa1, 0xf1, 0xc9, 0x6b, 0x86, 0x96, 0xfc, 0x77, 0x57, 0x01, 0x00,
829 0x00, 0x00, 0x00, 0x14, 0x1f, 0x07, 0xf7, 0x0e, 0xaa, 0x65, 0x14, 0xd3,
830 0xb0, 0xfa, 0x96, 0x54, 0x2a, 0x50, 0x03, 0x05
832 uint8_t *unpack;
833 size_t unpack_len;
834 struct isakmp_packet *p;
835 int reject;
837 p = parse_isakmp_packet(pack, sizeof(pack), &reject);
838 flatten_isakmp_packet(p, &unpack, &unpack_len, 8);
839 if (unpack_len != sizeof(pack)
840 || memcmp(unpack, pack, sizeof(pack)) != 0)
841 abort();
842 free(unpack);
843 free_isakmp_packet(p);