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 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
));
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
)
324 if (data_length
>= 16384)
328 result
->u
.ke
.length
= data_length
;
329 result
->u
.ke
.data
= xallocc(data_length
);
330 memcpy(result
->u
.ke
.data
, data
, data_length
);
334 static void free_isakmp_payload(struct isakmp_payload
*p
)
336 struct isakmp_payload
*nxt
;
342 case ISAKMP_PAYLOAD_SA
:
343 free_isakmp_payload(p
->u
.sa
.proposals
);
345 case ISAKMP_PAYLOAD_P
:
347 free_isakmp_payload(p
->u
.p
.transforms
);
349 case ISAKMP_PAYLOAD_T
:
351 struct isakmp_attribute
*att
, *natt
;
352 for (att
= p
->u
.t
.attributes
; att
; att
= natt
) {
354 if (att
->af
== isakmp_attr_lots
)
355 free(att
->u
.lots
.data
);
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
:
369 case ISAKMP_PAYLOAD_ID
:
372 case ISAKMP_PAYLOAD_CERT
:
373 case ISAKMP_PAYLOAD_CR
:
374 free(p
->u
.cert
.data
);
376 case ISAKMP_PAYLOAD_N
:
380 case ISAKMP_PAYLOAD_D
:
383 for (i
= 0; i
< p
->u
.d
.num_spi
; i
++)
388 case ISAKMP_PAYLOAD_MODECFG_ATTR
:
390 struct isakmp_attribute
*att
, *natt
;
391 for (att
= p
->u
.modecfg
.attributes
; att
; att
= natt
) {
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
);
407 free_isakmp_payload(nxt
);
410 void free_isakmp_packet(struct isakmp_packet
*p
)
414 free_isakmp_payload(p
->payload
);
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
;
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
;
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
:
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
:
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
;
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])
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
;
497 r
= new_isakmp_attribute(0, NULL
);
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
)
510 DEBUG(3, printf("(not dumping xauth data)\n"));
512 hex_dump("t.attributes.u.attr_16", &r
->u
.attr_16
, DUMP_UINT16
,
513 attr_val_to_debug_strings(decode_proto
, r
->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
)
524 DEBUG(3, printf("(not dumping xauth data length)\n"));
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
;
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
;
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
);
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
)
560 DEBUG(3, printf("(not dumping xauth data)\n"));
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
);
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
;
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
);
587 if (type
<= ISAKMP_PAYLOAD_MODECFG_ATTR
) {
588 if (data_len
< min_payload_len
[type
]) {
589 *reject
= ISAKMP_N_PAYLOAD_MALFORMED
;
592 } else if (data_len
< 4) {
593 *reject
= ISAKMP_N_PAYLOAD_MALFORMED
;
597 r
= new_isakmp_payload(type
);
598 next_type
= fetch1();
599 hex_dump("next_type", &next_type
, DUMP_UINT8
, isakmp_payload_enum_array
);
601 *reject
= ISAKMP_N_PAYLOAD_MALFORMED
;
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
]))
609 *reject
= ISAKMP_N_PAYLOAD_MALFORMED
;
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
;
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
;
629 r
->u
.sa
.proposals
= parse_isakmp_payload(ISAKMP_PAYLOAD_P
, &data
, &length
, reject
, decode_proto
);
632 /* Allow trailing garbage at end of payload. */
633 data_len
-= olength
- 12;
636 case ISAKMP_PAYLOAD_P
:
637 if (next_type
!= ISAKMP_PAYLOAD_P
&& next_type
!= 0) {
638 *reject
= ISAKMP_N_INVALID_PAYLOAD_TYPE
;
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
;
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)
667 if (num_xform
!= 0) {
668 *reject
= ISAKMP_N_BAD_PROPOSAL_SYNTAX
;
672 /* Allow trailing garbage at end of payload. */
673 data_len
-= olength
- 8 - r
->u
.p
.spi_size
;
677 case ISAKMP_PAYLOAD_T
:
678 if (next_type
!= ISAKMP_PAYLOAD_T
&& next_type
!= 0) {
679 *reject
= ISAKMP_N_INVALID_PAYLOAD_TYPE
;
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
));
687 *reject
= ISAKMP_N_BAD_PROPOSAL_SYNTAX
;
691 r
->u
.t
.attributes
= parse_isakmp_attributes(&data
, length
, reject
, decode_proto
);
692 data_len
-= olength
- 8;
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
);
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
);
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
);
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
;
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
,
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
;
769 r
->u
.d
.spi
= xallocc(sizeof(uint8_t *) * r
->u
.d
.num_spi
);
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
);
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
);
783 *reject
= ISAKMP_N_PAYLOAD_MALFORMED
;
786 r
->u
.modecfg
.id
= fetch2();
787 hex_dump("modecfg.id", &r
->u
.modecfg
.id
, DUMP_UINT16
, NULL
);
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;
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
);
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
);
808 struct isakmp_packet
*parse_isakmp_packet(const uint8_t * data
, size_t data_len
, int * reject
)
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
;
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
);
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
;
837 reason
= ISAKMP_N_INVALID_MINOR_VERSION
;
841 r
->exchange_type
= fetch1();
842 hex_dump("exchange_type", &r
->exchange_type
, DUMP_UINT8
, isakmp_exchange_enum_array
);
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
;
857 r
->payload
= parse_isakmp_payload(payload
, &data
, &data_len
, &reason
, 0);
861 DEBUG(3, printf("PARSE_OK\n"));
865 free_isakmp_packet(r
);
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
905 struct isakmp_packet
*p
;
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)
914 free_isakmp_packet(p
);