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
30 #include "isakmp-pkt.h"
31 #include "math_group.h"
34 void *xallocc(size_t x
)
37 result
= calloc(1, x
);
39 error(1, errno
, "malloc of %lu bytes failed", (unsigned long)x
);
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
)
58 f
->base
= malloc(new_len
);
60 f
->base
= realloc(f
->base
, new_len
);
62 error(1, errno
, "alloc of %lud bytes failed", (unsigned long)new_len
);
63 memset(f
->base
+ f
->len
, 0, new_len
- f
->len
);
71 static size_t flow_reserve(struct flow
*f
, size_t sz
)
73 uint8_t *p
= flow_reserve_p(f
, sz
);
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
)
92 flow_x(f
, dd
, sizeof(dd
));
95 static void flow_4(struct flow
*f
, uint32_t 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
)
114 case isakmp_attr_lots
:
116 flow_2(f
, p
->u
.lots
.length
);
117 flow_x(f
, p
->u
.lots
.data
, p
->u
.lots
.length
);
120 flow_2(f
, p
->type
| 0x8000);
121 flow_2(f
, p
->u
.attr_16
);
123 case isakmp_attr_2x8
:
124 flow_2(f
, p
->type
| 0x8000);
125 flow_x(f
, p
->u
.attr_2x8
, 2);
132 static void flow_payload(struct flow
*f
, struct isakmp_payload
*p
)
140 baselen
= f
->end
- f
->base
;
144 flow_1(f
, p
->next
->type
);
146 lpos
= flow_reserve(f
, 2);
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
);
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
)
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
);
167 case ISAKMP_PAYLOAD_T
:
168 flow_1(f
, p
->u
.t
.number
);
169 flow_1(f
, p
->u
.t
.id
);
171 flow_attribute(f
, p
->u
.t
.attributes
);
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
);
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
);
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
);
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
);
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) {
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
);
212 case ISAKMP_PAYLOAD_MODECFG_ATTR
:
213 flow_1(f
, p
->u
.modecfg
.type
);
215 flow_2(f
, p
->u
.modecfg
.id
);
216 flow_attribute(f
, p
->u
.modecfg
.attributes
);
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
)
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
;
240 flatten_isakmp_payloads(p
, result
, size
);
244 void flatten_isakmp_packet(struct isakmp_packet
*p
, uint8_t ** result
, size_t * size
, size_t blksz
)
247 size_t lpos
, sz
, padding
;
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
)
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
) {
264 sz
= (f
.end
- f
.base
) - ISAKMP_PAYLOAD_O
;
265 padding
= blksz
- (sz
% blksz
);
266 if (padding
== blksz
)
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
);
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
));
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
));
298 r
->af
= isakmp_attr_16
;
303 static void free_isakmp_attributes(struct isakmp_attribute
*attributes
)
305 struct isakmp_attribute
*att
, *nextatt
;
306 for (att
= attributes
; att
; att
= nextatt
) {
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
);
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
));
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
)
337 if (data_length
>= 16384)
341 result
->u
.ke
.length
= data_length
;
342 result
->u
.ke
.data
= xallocc(data_length
);
343 memcpy(result
->u
.ke
.data
, data
, data_length
);
347 static void free_isakmp_payload(struct isakmp_payload
*p
)
349 struct isakmp_payload
*nxt
;
355 case ISAKMP_PAYLOAD_SA
:
356 free_isakmp_payload(p
->u
.sa
.proposals
);
358 case ISAKMP_PAYLOAD_P
:
360 free_isakmp_payload(p
->u
.p
.transforms
);
362 case ISAKMP_PAYLOAD_T
:
363 free_isakmp_attributes(p
->u
.t
.attributes
);
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
:
374 case ISAKMP_PAYLOAD_ID
:
377 case ISAKMP_PAYLOAD_CERT
:
378 case ISAKMP_PAYLOAD_CR
:
379 free(p
->u
.cert
.data
);
381 case ISAKMP_PAYLOAD_N
:
384 free_isakmp_attributes(p
->u
.n
.attributes
);
386 case ISAKMP_PAYLOAD_D
:
389 for (i
= 0; i
< p
->u
.d
.num_spi
; i
++)
394 case ISAKMP_PAYLOAD_MODECFG_ATTR
:
395 free_isakmp_attributes(p
->u
.modecfg
.attributes
);
403 free_isakmp_payload(nxt
);
406 void free_isakmp_packet(struct isakmp_packet
*p
)
410 free_isakmp_payload(p
->payload
);
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
;
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
;
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
:
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
:
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
;
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])
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
;
493 r
= new_isakmp_attribute(0, NULL
);
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
)
506 DEBUG(3, printf("(not dumping xauth data)\n"));
508 hex_dump("t.attributes.u.attr_16", &r
->u
.attr_16
, DUMP_UINT16
,
509 attr_val_to_debug_strings(decode_proto
, r
->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
)
520 DEBUG(3, printf("(not dumping xauth data length)\n"));
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
;
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
;
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
);
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
)
556 DEBUG(3, printf("(not dumping xauth data)\n"));
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
);
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
;
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
);
583 if (type
<= ISAKMP_PAYLOAD_MODECFG_ATTR
) {
584 if (data_len
< min_payload_len
[type
]) {
585 *reject
= ISAKMP_N_PAYLOAD_MALFORMED
;
588 } else if (data_len
< 4) {
589 *reject
= ISAKMP_N_PAYLOAD_MALFORMED
;
593 r
= new_isakmp_payload(type
);
594 next_type
= fetch1();
595 hex_dump("next_type", &next_type
, DUMP_UINT8
, isakmp_payload_enum_array
);
597 *reject
= ISAKMP_N_PAYLOAD_MALFORMED
;
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
]))
605 *reject
= ISAKMP_N_PAYLOAD_MALFORMED
;
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
;
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
;
625 r
->u
.sa
.proposals
= parse_isakmp_payload(ISAKMP_PAYLOAD_P
, &data
, &length
, reject
, decode_proto
);
628 /* Allow trailing garbage at end of payload. */
629 data_len
-= olength
- 12;
632 case ISAKMP_PAYLOAD_P
:
633 if (next_type
!= ISAKMP_PAYLOAD_P
&& next_type
!= 0) {
634 *reject
= ISAKMP_N_INVALID_PAYLOAD_TYPE
;
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
;
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)
663 if (num_xform
!= 0) {
664 *reject
= ISAKMP_N_BAD_PROPOSAL_SYNTAX
;
668 /* Allow trailing garbage at end of payload. */
669 data_len
-= olength
- 8 - r
->u
.p
.spi_size
;
673 case ISAKMP_PAYLOAD_T
:
674 if (next_type
!= ISAKMP_PAYLOAD_T
&& next_type
!= 0) {
675 *reject
= ISAKMP_N_INVALID_PAYLOAD_TYPE
;
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
));
683 *reject
= ISAKMP_N_BAD_PROPOSAL_SYNTAX
;
687 r
->u
.t
.attributes
= parse_isakmp_attributes(&data
, length
, reject
, decode_proto
);
688 data_len
-= olength
- 8;
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
);
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
);
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
);
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
;
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
,
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
;
765 r
->u
.d
.spi
= xallocc(sizeof(uint8_t *) * r
->u
.d
.num_spi
);
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
);
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
);
779 *reject
= ISAKMP_N_PAYLOAD_MALFORMED
;
782 r
->u
.modecfg
.id
= fetch2();
783 hex_dump("modecfg.id", &r
->u
.modecfg
.id
, DUMP_UINT16
, NULL
);
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;
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
);
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
);
804 struct isakmp_packet
*parse_isakmp_packet(const uint8_t * data
, size_t data_len
, int * reject
)
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
;
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
);
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
;
833 reason
= ISAKMP_N_INVALID_MINOR_VERSION
;
837 r
->exchange_type
= fetch1();
838 hex_dump("exchange_type", &r
->exchange_type
, DUMP_UINT8
, isakmp_exchange_enum_array
);
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
;
853 r
->payload
= parse_isakmp_payload(payload
, &data
, &data_len
, &reason
, 0);
857 DEBUG(3, printf("PARSE_OK\n"));
861 free_isakmp_packet(r
);
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
901 struct isakmp_packet
*p
;
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)
910 free_isakmp_packet(p
);