updated todo list
[vpnc.git] / isakmp-pkt.c
blob7311dcba429c050d30c1502c3fa05d41b5ef5915
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, uint16_t * 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, uint16_t * 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, uint16_t * reject)
693 uint16_t reason = 0;
694 uint8_t payload;
695 struct isakmp_packet *r = new_isakmp_packet();
696 size_t o_data_len = data_len;
698 if (data_len < ISAKMP_PAYLOAD_O) {
699 reason = ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS;
700 goto error;
703 DEBUG(3, printf("\nBEGIN_PARSE\n"));
704 fetchn(r->i_cookie, ISAKMP_COOKIE_LENGTH);
705 hex_dump("i_cookie", r->i_cookie, ISAKMP_COOKIE_LENGTH);
706 fetchn(r->r_cookie, ISAKMP_COOKIE_LENGTH);
707 hex_dump("r_cookie", r->r_cookie, ISAKMP_COOKIE_LENGTH);
708 payload = fetch1();
709 hex_dump("payload", &payload, UINT8);
711 r->isakmp_version = fetch1();
712 hex_dump("isakmp_version", &r->isakmp_version, UINT8);
713 if (r->isakmp_version > ISAKMP_VERSION) {
714 if ((r->isakmp_version & 0xF0) >= (ISAKMP_VERSION & 0xF0))
715 reason = ISAKMP_N_INVALID_MAJOR_VERSION;
716 else
717 reason = ISAKMP_N_INVALID_MINOR_VERSION;
718 goto error;
721 r->exchange_type = fetch1();
722 hex_dump("exchange_type", &r->exchange_type, UINT8);
723 r->flags = fetch1();
724 hex_dump("flags", &r->flags, UINT8);
725 r->message_id = fetch4();
726 hex_dump("message_id", &r->message_id, sizeof(r->message_id));
728 if (fetch4() != o_data_len) {
729 reason = ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS;
730 goto error;
732 hex_dump("len", &o_data_len, UINT32);
734 r->payload = parse_isakmp_payload(payload, &data, &data_len, &reason);
735 if (reason != 0)
736 goto error;
738 DEBUG(3, printf("PARSE_OK\n\n"));
739 return r;
741 error:
742 free_isakmp_packet(r);
743 if (reject)
744 *reject = reason;
745 return NULL;
748 const char *isakmp_notify_to_error(uint16_t notify)
750 static const struct {
751 uint16_t id;
752 const char *name;
753 } data[] = {
754 { ISAKMP_N_INVALID_PAYLOAD_TYPE, "INVALID_PAYLOAD_TYPE"},
755 { ISAKMP_N_DOI_NOT_SUPPORTED, "DOI_NOT_SUPPORTED"},
756 { ISAKMP_N_SITUATION_NOT_SUPPORTED, "SITUATION_NOT_SUPPORTED"},
757 { ISAKMP_N_INVALID_COOKIE, "INVALID_COOKIE"},
758 { ISAKMP_N_INVALID_MAJOR_VERSION, "INVALID_MAJOR_VERSION"},
759 { ISAKMP_N_INVALID_MINOR_VERSION, "INVALID_MINOR_VERSION"},
760 { ISAKMP_N_INVALID_EXCHANGE_TYPE, "INVALID_EXCHANGE_TYPE"},
761 { ISAKMP_N_INVALID_FLAGS, "INVALID_FLAGS"},
762 { ISAKMP_N_INVALID_MESSAGE_ID, "INVALID_MESSAGE_ID"},
763 { ISAKMP_N_INVALID_PROTOCOL_ID, "INVALID_PROTOCOL_ID"},
764 { ISAKMP_N_INVALID_SPI, "INVALID_SPI"},
765 { ISAKMP_N_INVALID_TRANSFORM_ID, "INVALID_TRANSFORM_ID"},
766 { ISAKMP_N_ATTRIBUTES_NOT_SUPPORTED, "ATTRIBUTES_NOT_SUPPORTED"},
767 { ISAKMP_N_NO_PROPOSAL_CHOSEN, "NO_PROPOSAL_CHOSEN"},
768 { ISAKMP_N_BAD_PROPOSAL_SYNTAX, "BAD_PROPOSAL_SYNTAX"},
769 { ISAKMP_N_PAYLOAD_MALFORMED, "PAYLOAD_MALFORMED"},
770 { ISAKMP_N_INVALID_KEY_INFORMATION, "INVALID_KEY_INFORMATION"},
771 { ISAKMP_N_INVALID_ID_INFORMATION, "INVALID_ID_INFORMATION"},
772 { ISAKMP_N_INVALID_CERT_ENCODING, "INVALID_CERT_ENCODING"},
773 { ISAKMP_N_INVALID_CERTIFICATE, "INVALID_CERTIFICATE"},
774 { ISAKMP_N_CERT_TYPE_UNSUPPORTED, "CERT_TYPE_UNSUPPORTED"},
775 { ISAKMP_N_INVALID_CERT_AUTHORITY, "INVALID_CERT_AUTHORITY"},
776 { ISAKMP_N_INVALID_HASH_INFORMATION, "INVALID_HASH_INFORMATION"},
777 { ISAKMP_N_AUTHENTICATION_FAILED, "AUTHENTICATION_FAILED"},
778 { ISAKMP_N_INVALID_SIGNATURE, "INVALID_SIGNATURE"},
779 { ISAKMP_N_ADDRESS_NOTIFICATION, "ADDRESS_NOTIFICATION"},
780 { ISAKMP_N_NOTIFY_SA_LIFETIME, "NOTIFY_SA_LIFETIME"},
781 { ISAKMP_N_CERTIFICATE_UNAVAILABLE, "CERTIFICATE_UNAVAILABLE"},
782 { ISAKMP_N_UNSUPPORTED_EXCHANGE_TYPE, "UNSUPPORTED_EXCHANGE_TYPE"},
783 { ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS, "UNEQUAL_PAYLOAD_LENGTHS"}
785 size_t i;
786 static char number[10];
788 for (i = 0; i < sizeof(data) / sizeof(data[0]); i++)
789 if (data[i].id == notify)
790 return data[i].name;
791 sprintf(number, "%d", notify);
792 return number;
795 void test_pack_unpack(void)
797 static const uint8_t pack[] = {
798 0x7f, 0xba, 0x51, 0x29, 0x11, 0x9e, 0x76, 0xf7, 0x9a, 0x71, 0xee, 0x70,
799 0xaa, 0x82, 0xb9, 0x7f, 0x01, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
800 0x00, 0x00, 0x01, 0x4c, 0x04, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01,
801 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x01, 0x01, 0x00, 0x01,
802 0x00, 0x00, 0x00, 0x18, 0x00, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x05,
803 0x80, 0x02, 0x00, 0x01, 0x80, 0x04, 0x00, 0x02, 0x80, 0x03, 0x00, 0x01,
804 0x0a, 0x00, 0x00, 0x84, 0x1b, 0x1d, 0x4b, 0x29, 0x0e, 0x29, 0xb9, 0x6f,
805 0x18, 0x34, 0xd1, 0x2d, 0xba, 0x92, 0x7c, 0x53, 0x35, 0x76, 0x0e, 0x3b,
806 0x25, 0x92, 0x4f, 0x7c, 0x1e, 0x31, 0x41, 0x8c, 0xb9, 0xe3, 0xda, 0xf7,
807 0x53, 0xd3, 0x22, 0x8e, 0xff, 0xeb, 0xed, 0x5b, 0x95, 0x56, 0x8d, 0xba,
808 0xa8, 0xe3, 0x2a, 0x9b, 0xb4, 0x04, 0x5c, 0x90, 0xf0, 0xfe, 0x92, 0xc8,
809 0x57, 0xa2, 0xc6, 0x0c, 0x85, 0xbb, 0x56, 0xe8, 0x1c, 0xa7, 0x2c, 0x57,
810 0x04, 0xb6, 0xe0, 0x43, 0x82, 0xe1, 0x9f, 0x0b, 0xa6, 0x8b, 0xce, 0x7f,
811 0x9b, 0x75, 0xbb, 0xd3, 0xff, 0x0e, 0x89, 0x19, 0xaf, 0xc6, 0x2e, 0xf6,
812 0x92, 0x06, 0x46, 0x4f, 0xc7, 0x97, 0x22, 0xf4, 0xa6, 0xf9, 0x26, 0x34,
813 0x04, 0x33, 0x89, 0x34, 0xa9, 0x2f, 0x81, 0x92, 0xd3, 0x21, 0x4f, 0x45,
814 0xbe, 0x38, 0x12, 0x26, 0xec, 0x87, 0x45, 0xdd, 0x10, 0x1c, 0xd6, 0x16,
815 0x05, 0x00, 0x00, 0x18, 0x77, 0xdf, 0x37, 0x3c, 0x03, 0x02, 0xe2, 0xc8,
816 0xe1, 0x2f, 0x92, 0xf0, 0x2e, 0xa2, 0xa6, 0x00, 0x17, 0x8f, 0xdf, 0xb4,
817 0x08, 0x00, 0x00, 0x0c, 0x01, 0x11, 0x01, 0xf4, 0xcd, 0xb4, 0x53, 0x6d,
818 0x0d, 0x00, 0x00, 0x14, 0x07, 0x47, 0x8d, 0xa7, 0x0b, 0xd6, 0xd1, 0x66,
819 0x7a, 0xaf, 0x2e, 0x61, 0x2a, 0x91, 0x80, 0x94, 0x0d, 0x00, 0x00, 0x14,
820 0x12, 0xf5, 0xf2, 0x8c, 0x45, 0x71, 0x68, 0xa9, 0x70, 0x2d, 0x9f, 0xe2,
821 0x74, 0xcc, 0x01, 0x00, 0x0d, 0x00, 0x00, 0x0c, 0x09, 0x00, 0x26, 0x89,
822 0xdf, 0xd6, 0xb7, 0x12, 0x0d, 0x00, 0x00, 0x14, 0xaf, 0xca, 0xd7, 0x13,
823 0x68, 0xa1, 0xf1, 0xc9, 0x6b, 0x86, 0x96, 0xfc, 0x77, 0x57, 0x01, 0x00,
824 0x00, 0x00, 0x00, 0x14, 0x1f, 0x07, 0xf7, 0x0e, 0xaa, 0x65, 0x14, 0xd3,
825 0xb0, 0xfa, 0x96, 0x54, 0x2a, 0x50, 0x03, 0x05
827 uint8_t *unpack;
828 size_t unpack_len;
829 struct isakmp_packet *p;
830 uint16_t reject;
832 p = parse_isakmp_packet(pack, sizeof(pack), &reject);
833 flatten_isakmp_packet(p, &unpack, &unpack_len, 8);
834 if (unpack_len != sizeof(pack)
835 || memcmp(unpack, pack, sizeof(pack)) != 0)
836 abort();
837 free(unpack);
838 free_isakmp_packet(p);