2 * Copyright (C) 2005-2009 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 #include <arpa/inet.h>
25 #include <utils/linked_list.h>
26 #include <encoding/payloads/encodings.h>
27 #include <encoding/payloads/payload.h>
28 #include <encoding/payloads/sa_payload.h>
29 #include <encoding/payloads/proposal_substructure.h>
30 #include <encoding/payloads/transform_substructure.h>
31 #include <encoding/payloads/transform_attribute.h>
32 #include <encoding/payloads/ke_payload.h>
33 #include <encoding/payloads/nonce_payload.h>
34 #include <encoding/payloads/id_payload.h>
35 #include <encoding/payloads/notify_payload.h>
36 #include <encoding/payloads/encryption_payload.h>
37 #include <encoding/payloads/auth_payload.h>
38 #include <encoding/payloads/cert_payload.h>
39 #include <encoding/payloads/certreq_payload.h>
40 #include <encoding/payloads/ts_payload.h>
41 #include <encoding/payloads/delete_payload.h>
42 #include <encoding/payloads/vendor_id_payload.h>
43 #include <encoding/payloads/cp_payload.h>
44 #include <encoding/payloads/configuration_attribute.h>
45 #include <encoding/payloads/eap_payload.h>
46 #include <encoding/payloads/unknown_payload.h>
49 typedef struct private_parser_t private_parser_t
;
52 * Private data stored in a context.
54 * Contains pointers and counters to store current state.
56 struct private_parser_t
{
58 * Public members, see parser_t.
63 * Current bit for reading in input data.
68 * Current byte for reading in input data.
73 * Input data to parse.
78 * Roof of input, used for length-checking.
83 * Set of encoding rules for this parsing session.
85 encoding_rule_t
*rules
;
91 static status_t
parse_payload(private_parser_t
*this,
92 payload_type_t payload_type
, payload_t
**payload
);
95 * Log invalid length error
97 static bool short_input(private_parser_t
*this, int number
)
99 DBG1(DBG_ENC
, " not enough input to parse rule %d %N",
100 number
, encoding_type_names
, this->rules
[number
].type
);
105 * Log unaligned rules
107 static bool bad_bitpos(private_parser_t
*this, int number
)
109 DBG1(DBG_ENC
, " found rule %d %N on bitpos %d",
110 number
, encoding_type_names
, this->rules
[number
].type
, this->bit_pos
);
115 * Parse a 4-Bit unsigned integer from the current parsing position.
117 static bool parse_uint4(private_parser_t
*this, int rule_number
,
118 u_int8_t
*output_pos
)
120 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
122 return short_input(this, rule_number
);
124 switch (this->bit_pos
)
129 *output_pos
= *(this->byte_pos
) >> 4;
136 *output_pos
= *(this->byte_pos
) & 0x0F;
142 return bad_bitpos(this, rule_number
);
146 DBG3(DBG_ENC
, " => %d", *output_pos
);
152 * Parse a 8-Bit unsigned integer from the current parsing position.
154 static bool parse_uint8(private_parser_t
*this, int rule_number
,
155 u_int8_t
*output_pos
)
157 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
159 return short_input(this, rule_number
);
163 return bad_bitpos(this, rule_number
);
167 *output_pos
= *(this->byte_pos
);
168 DBG3(DBG_ENC
, " => %d", *output_pos
);
175 * Parse a 15-Bit unsigned integer from the current parsing position.
177 static bool parse_uint15(private_parser_t
*this, int rule_number
,
178 u_int16_t
*output_pos
)
180 if (this->byte_pos
+ sizeof(u_int16_t
) > this->input_roof
)
182 return short_input(this, rule_number
);
184 if (this->bit_pos
!= 1)
186 return bad_bitpos(this, rule_number
);
190 memcpy(output_pos
, this->byte_pos
, sizeof(u_int16_t
));
191 *output_pos
= ntohs(*output_pos
) & ~0x8000;
192 DBG3(DBG_ENC
, " => %d", *output_pos
);
194 this->byte_pos
+= sizeof(u_int16_t
);
200 * Parse a 16-Bit unsigned integer from the current parsing position.
202 static bool parse_uint16(private_parser_t
*this, int rule_number
,
203 u_int16_t
*output_pos
)
205 if (this->byte_pos
+ sizeof(u_int16_t
) > this->input_roof
)
207 return short_input(this, rule_number
);
211 return bad_bitpos(this, rule_number
);
215 memcpy(output_pos
, this->byte_pos
, sizeof(u_int16_t
));
216 *output_pos
= ntohs(*output_pos
);
217 DBG3(DBG_ENC
, " => %d", *output_pos
);
219 this->byte_pos
+= sizeof(u_int16_t
);
223 * Parse a 32-Bit unsigned integer from the current parsing position.
225 static bool parse_uint32(private_parser_t
*this, int rule_number
,
226 u_int32_t
*output_pos
)
228 if (this->byte_pos
+ sizeof(u_int32_t
) > this->input_roof
)
230 return short_input(this, rule_number
);
234 return bad_bitpos(this, rule_number
);
238 memcpy(output_pos
, this->byte_pos
, sizeof(u_int32_t
));
239 *output_pos
= ntohl(*output_pos
);
240 DBG3(DBG_ENC
, " => %d", *output_pos
);
242 this->byte_pos
+= sizeof(u_int32_t
);
247 * Parse a given amount of bytes and writes them to a specific location
249 static bool parse_bytes(private_parser_t
*this, int rule_number
,
250 u_int8_t
*output_pos
, size_t bytes
)
252 if (this->byte_pos
+ bytes
> this->input_roof
)
254 return short_input(this, rule_number
);
258 return bad_bitpos(this, rule_number
);
262 memcpy(output_pos
, this->byte_pos
, bytes
);
263 DBG3(DBG_ENC
, " => %b", output_pos
, bytes
);
265 this->byte_pos
+= bytes
;
270 * Parse a single Bit from the current parsing position
272 static bool parse_bit(private_parser_t
*this, int rule_number
,
275 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
277 return short_input(this, rule_number
);
282 mask
= 0x01 << (7 - this->bit_pos
);
283 *output_pos
= *this->byte_pos
& mask
;
286 { /* set to a "clean", comparable true */
289 DBG3(DBG_ENC
, " => %d", *output_pos
);
291 this->bit_pos
= (this->bit_pos
+ 1) % 8;
292 if (this->bit_pos
== 0)
300 * Parse substructures in a list.
302 static bool parse_list(private_parser_t
*this, int rule_number
,
303 linked_list_t
**output_pos
, payload_type_t payload_type
, size_t length
)
305 linked_list_t
*list
= *output_pos
;
309 return short_input(this, rule_number
);
313 return bad_bitpos(this, rule_number
);
317 u_int8_t
*pos_before
= this->byte_pos
;
320 DBG2(DBG_ENC
, " %d bytes left, parsing recursively %N",
321 length
, payload_type_names
, payload_type
);
323 if (parse_payload(this, payload_type
, &payload
) != SUCCESS
)
325 DBG1(DBG_ENC
, " parsing of a %N substructure failed",
326 payload_type_names
, payload_type
);
329 list
->insert_last(list
, payload
);
330 length
-= this->byte_pos
- pos_before
;
337 * Parse data from current parsing position in a chunk.
339 static bool parse_chunk(private_parser_t
*this, int rule_number
,
340 chunk_t
*output_pos
, size_t length
)
342 if (this->byte_pos
+ length
> this->input_roof
)
344 return short_input(this, rule_number
);
348 return bad_bitpos(this, rule_number
);
352 *output_pos
= chunk_alloc(length
);
353 memcpy(output_pos
->ptr
, this->byte_pos
, length
);
354 DBG3(DBG_ENC
, " => %b", output_pos
->ptr
, length
);
356 this->byte_pos
+= length
;
361 * Implementation of parser_t.parse_payload.
363 static status_t
parse_payload(private_parser_t
*this,
364 payload_type_t payload_type
, payload_t
**payload
)
368 size_t rule_count
, payload_length
= 0, spi_size
= 0, attribute_length
= 0;
369 u_int16_t ts_type
= 0;
370 bool attribute_format
= FALSE
;
372 encoding_rule_t
*rule
;
374 /* create instance of the payload to parse */
375 pld
= payload_create(payload_type
);
377 DBG2(DBG_ENC
, "parsing %N payload, %d bytes left",
378 payload_type_names
, payload_type
, this->input_roof
- this->byte_pos
);
380 DBG3(DBG_ENC
, "parsing payload from %b",
381 this->byte_pos
, this->input_roof
- this->byte_pos
);
383 if (pld
->get_type(pld
) == UNKNOWN_PAYLOAD
)
385 DBG1(DBG_ENC
, " payload type %d is unknown, handling as %N",
386 payload_type
, payload_type_names
, UNKNOWN_PAYLOAD
);
389 /* base pointer for output, avoids casting in every rule */
392 /* parse the payload with its own rulse */
393 pld
->get_encoding_rules(pld
, &(this->rules
), &rule_count
);
394 for (rule_number
= 0; rule_number
< rule_count
; rule_number
++)
396 rule
= &(this->rules
[rule_number
]);
397 DBG2(DBG_ENC
, " parsing rule %d %N",
398 rule_number
, encoding_type_names
, rule
->type
);
403 if (!parse_uint4(this, rule_number
, output
+ rule
->offset
))
412 if (!parse_uint8(this, rule_number
, output
+ rule
->offset
))
421 if (!parse_uint16(this, rule_number
, output
+ rule
->offset
))
430 if (!parse_uint32(this, rule_number
, output
+ rule
->offset
))
439 if (!parse_bytes(this, rule_number
, output
+ rule
->offset
, 8))
448 if (!parse_bit(this, rule_number
, NULL
))
457 if (!parse_uint8(this, rule_number
, NULL
))
466 if (!parse_bit(this, rule_number
, output
+ rule
->offset
))
475 if (!parse_uint16(this, rule_number
, output
+ rule
->offset
))
480 /* parsed u_int16 should be aligned */
481 payload_length
= *(u_int16_t
*)(output
+ rule
->offset
);
482 if (payload_length
< UNKNOWN_PAYLOAD_HEADER_LENGTH
)
491 if (!parse_uint32(this, rule_number
, output
+ rule
->offset
))
500 if (!parse_uint8(this, rule_number
, output
+ rule
->offset
))
505 spi_size
= *(u_int8_t
*)(output
+ rule
->offset
);
510 if (!parse_chunk(this, rule_number
, output
+ rule
->offset
,
520 if (payload_length
< SA_PAYLOAD_HEADER_LENGTH
||
521 !parse_list(this, rule_number
, output
+ rule
->offset
,
522 PROPOSAL_SUBSTRUCTURE
,
523 payload_length
- SA_PAYLOAD_HEADER_LENGTH
))
533 spi_size
+ PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH
||
534 !parse_list(this, rule_number
, output
+ rule
->offset
,
535 TRANSFORM_SUBSTRUCTURE
, payload_length
- spi_size
-
536 PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH
))
543 case TRANSFORM_ATTRIBUTES
:
545 if (payload_length
< TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH
||
546 !parse_list(this, rule_number
, output
+ rule
->offset
,
548 payload_length
- TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH
))
555 case CONFIGURATION_ATTRIBUTES
:
557 if (payload_length
< CP_PAYLOAD_HEADER_LENGTH
||
558 !parse_list(this, rule_number
, output
+ rule
->offset
,
559 CONFIGURATION_ATTRIBUTE
,
560 payload_length
- CP_PAYLOAD_HEADER_LENGTH
))
567 case ATTRIBUTE_FORMAT
:
569 if (!parse_bit(this, rule_number
, output
+ rule
->offset
))
574 attribute_format
= *(bool*)(output
+ rule
->offset
);
579 if (!parse_uint15(this, rule_number
, output
+ rule
->offset
))
586 case CONFIGURATION_ATTRIBUTE_LENGTH
:
588 if (!parse_uint16(this, rule_number
, output
+ rule
->offset
))
593 attribute_length
= *(u_int16_t
*)(output
+ rule
->offset
);
596 case ATTRIBUTE_LENGTH_OR_VALUE
:
598 if (!parse_uint16(this, rule_number
, output
+ rule
->offset
))
603 attribute_length
= *(u_int16_t
*)(output
+ rule
->offset
);
606 case ATTRIBUTE_VALUE
:
608 if (attribute_format
== FALSE
&&
609 !parse_chunk(this, rule_number
, output
+ rule
->offset
,
619 if (payload_length
< NONCE_PAYLOAD_HEADER_LENGTH
||
620 !parse_chunk(this, rule_number
, output
+ rule
->offset
,
621 payload_length
- NONCE_PAYLOAD_HEADER_LENGTH
))
630 if (payload_length
< ID_PAYLOAD_HEADER_LENGTH
||
631 !parse_chunk(this, rule_number
, output
+ rule
->offset
,
632 payload_length
- ID_PAYLOAD_HEADER_LENGTH
))
641 if (payload_length
< AUTH_PAYLOAD_HEADER_LENGTH
||
642 !parse_chunk(this, rule_number
, output
+ rule
->offset
,
643 payload_length
- AUTH_PAYLOAD_HEADER_LENGTH
))
652 if (payload_length
< CERT_PAYLOAD_HEADER_LENGTH
||
653 !parse_chunk(this, rule_number
, output
+ rule
->offset
,
654 payload_length
- CERT_PAYLOAD_HEADER_LENGTH
))
663 if (payload_length
< CERTREQ_PAYLOAD_HEADER_LENGTH
||
664 !parse_chunk(this, rule_number
, output
+ rule
->offset
,
665 payload_length
- CERTREQ_PAYLOAD_HEADER_LENGTH
))
674 if (payload_length
< EAP_PAYLOAD_HEADER_LENGTH
||
675 !parse_chunk(this, rule_number
, output
+ rule
->offset
,
676 payload_length
- EAP_PAYLOAD_HEADER_LENGTH
))
685 if (payload_length
< DELETE_PAYLOAD_HEADER_LENGTH
||
686 !parse_chunk(this, rule_number
, output
+ rule
->offset
,
687 payload_length
- DELETE_PAYLOAD_HEADER_LENGTH
))
696 if (payload_length
< VENDOR_ID_PAYLOAD_HEADER_LENGTH
||
697 !parse_chunk(this, rule_number
, output
+ rule
->offset
,
698 payload_length
- VENDOR_ID_PAYLOAD_HEADER_LENGTH
))
705 case CONFIGURATION_ATTRIBUTE_VALUE
:
707 if (!parse_chunk(this, rule_number
, output
+ rule
->offset
,
715 case KEY_EXCHANGE_DATA
:
717 if (payload_length
< KE_PAYLOAD_HEADER_LENGTH
||
718 !parse_chunk(this, rule_number
, output
+ rule
->offset
,
719 payload_length
- KE_PAYLOAD_HEADER_LENGTH
))
726 case NOTIFICATION_DATA
:
728 if (payload_length
< NOTIFY_PAYLOAD_HEADER_LENGTH
+ spi_size
||
729 !parse_chunk(this, rule_number
, output
+ rule
->offset
,
730 payload_length
- NOTIFY_PAYLOAD_HEADER_LENGTH
- spi_size
))
739 if (payload_length
< ENCRYPTION_PAYLOAD_HEADER_LENGTH
||
740 !parse_chunk(this, rule_number
, output
+ rule
->offset
,
741 payload_length
- ENCRYPTION_PAYLOAD_HEADER_LENGTH
))
750 if (!parse_uint8(this, rule_number
, output
+ rule
->offset
))
755 ts_type
= *(u_int8_t
*)(output
+ rule
->offset
);
760 size_t address_length
= (ts_type
== TS_IPV4_ADDR_RANGE
) ?
4 : 16;
762 if (!parse_chunk(this, rule_number
, output
+ rule
->offset
,
770 case TRAFFIC_SELECTORS
:
772 if (payload_length
< TS_PAYLOAD_HEADER_LENGTH
||
773 !parse_list(this, rule_number
, output
+ rule
->offset
,
774 TRAFFIC_SELECTOR_SUBSTRUCTURE
,
775 payload_length
- TS_PAYLOAD_HEADER_LENGTH
))
784 if (payload_length
< UNKNOWN_PAYLOAD_HEADER_LENGTH
||
785 !parse_chunk(this, rule_number
, output
+ rule
->offset
,
786 payload_length
- UNKNOWN_PAYLOAD_HEADER_LENGTH
))
795 DBG1(DBG_ENC
, " no rule to parse rule %d %N",
796 rule_number
, encoding_type_names
, rule
->type
);
801 /* process next rulue */
806 DBG2(DBG_ENC
, "parsing %N payload finished",
807 payload_type_names
, payload_type
);
812 * Implementation of parser_t.get_remaining_byte_count.
814 static int get_remaining_byte_count (private_parser_t
*this)
816 return this->input_roof
- this->byte_pos
;
820 * Implementation of parser_t.reset_context.
822 static void reset_context (private_parser_t
*this)
824 this->byte_pos
= this->input
;
829 * Implementation of parser_t.destroy.
831 static void destroy(private_parser_t
*this)
837 * Described in header.
839 parser_t
*parser_create(chunk_t data
)
841 private_parser_t
*this = malloc_thing(private_parser_t
);
843 this->public.parse_payload
= (status_t(*)(parser_t
*,payload_type_t
,payload_t
**))parse_payload
;
844 this->public.reset_context
= (void(*)(parser_t
*)) reset_context
;
845 this->public.get_remaining_byte_count
= (int (*) (parser_t
*))get_remaining_byte_count
;
846 this->public.destroy
= (void(*)(parser_t
*)) destroy
;
848 this->input
= data
.ptr
;
849 this->byte_pos
= data
.ptr
;
851 this->input_roof
= data
.ptr
+ data
.len
;
853 return &this->public;