Annotation of embedaddon/strongswan/src/libcharon/encoding/parser.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2005-2009 Martin Willi
! 3: * Copyright (C) 2005 Jan Hutter
! 4: * HSR Hochschule fuer Technik Rapperswil
! 5: *
! 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>.
! 10: *
! 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
! 14: * for more details.
! 15: */
! 16:
! 17: #include <stdlib.h>
! 18: #include <string.h>
! 19:
! 20: #include "parser.h"
! 21:
! 22: #include <library.h>
! 23: #include <daemon.h>
! 24: #include <collections/linked_list.h>
! 25: #include <encoding/payloads/encodings.h>
! 26: #include <encoding/payloads/payload.h>
! 27: #include <encoding/payloads/sa_payload.h>
! 28: #include <encoding/payloads/proposal_substructure.h>
! 29: #include <encoding/payloads/transform_substructure.h>
! 30: #include <encoding/payloads/transform_attribute.h>
! 31: #include <encoding/payloads/ke_payload.h>
! 32: #include <encoding/payloads/nonce_payload.h>
! 33: #include <encoding/payloads/id_payload.h>
! 34: #include <encoding/payloads/notify_payload.h>
! 35: #include <encoding/payloads/encrypted_payload.h>
! 36: #include <encoding/payloads/auth_payload.h>
! 37: #include <encoding/payloads/cert_payload.h>
! 38: #include <encoding/payloads/certreq_payload.h>
! 39: #include <encoding/payloads/ts_payload.h>
! 40: #include <encoding/payloads/delete_payload.h>
! 41: #include <encoding/payloads/vendor_id_payload.h>
! 42: #include <encoding/payloads/cp_payload.h>
! 43: #include <encoding/payloads/configuration_attribute.h>
! 44: #include <encoding/payloads/eap_payload.h>
! 45: #include <encoding/payloads/unknown_payload.h>
! 46:
! 47:
! 48: typedef struct private_parser_t private_parser_t;
! 49:
! 50: /**
! 51: * Private data stored in a context.
! 52: *
! 53: * Contains pointers and counters to store current state.
! 54: */
! 55: struct private_parser_t {
! 56: /**
! 57: * Public members, see parser_t.
! 58: */
! 59: parser_t public;
! 60:
! 61: /**
! 62: * major IKE version
! 63: */
! 64: uint8_t major_version;
! 65:
! 66: /**
! 67: * Current bit for reading in input data.
! 68: */
! 69: uint8_t bit_pos;
! 70:
! 71: /**
! 72: * Current byte for reading in input data.
! 73: */
! 74: uint8_t *byte_pos;
! 75:
! 76: /**
! 77: * Input data to parse.
! 78: */
! 79: uint8_t *input;
! 80:
! 81: /**
! 82: * Roof of input, used for length-checking.
! 83: */
! 84: uint8_t *input_roof;
! 85:
! 86: /**
! 87: * Set of encoding rules for this parsing session.
! 88: */
! 89: encoding_rule_t *rules;
! 90: };
! 91:
! 92: /**
! 93: * Log invalid length error
! 94: */
! 95: static bool short_input(private_parser_t *this, int number)
! 96: {
! 97: DBG1(DBG_ENC, " not enough input to parse rule %d %N",
! 98: number, encoding_type_names, this->rules[number].type);
! 99: return FALSE;
! 100: }
! 101:
! 102: /**
! 103: * Log unaligned rules
! 104: */
! 105: static bool bad_bitpos(private_parser_t *this, int number)
! 106: {
! 107: DBG1(DBG_ENC, " found rule %d %N on bitpos %d",
! 108: number, encoding_type_names, this->rules[number].type, this->bit_pos);
! 109: return FALSE;
! 110: }
! 111:
! 112: /**
! 113: * Parse a 4-Bit unsigned integer from the current parsing position.
! 114: */
! 115: static bool parse_uint4(private_parser_t *this, int rule_number,
! 116: uint8_t *output_pos)
! 117: {
! 118: if (this->byte_pos + sizeof(uint8_t) > this->input_roof)
! 119: {
! 120: return short_input(this, rule_number);
! 121: }
! 122: switch (this->bit_pos)
! 123: {
! 124: case 0:
! 125: if (output_pos)
! 126: {
! 127: *output_pos = *(this->byte_pos) >> 4;
! 128: }
! 129: this->bit_pos = 4;
! 130: break;
! 131: case 4:
! 132: if (output_pos)
! 133: {
! 134: *output_pos = *(this->byte_pos) & 0x0F;
! 135: }
! 136: this->bit_pos = 0;
! 137: this->byte_pos++;
! 138: break;
! 139: default:
! 140: return bad_bitpos(this, rule_number);
! 141: }
! 142: if (output_pos)
! 143: {
! 144: DBG3(DBG_ENC, " => %hhu", *output_pos);
! 145: }
! 146: return TRUE;
! 147: }
! 148:
! 149: /**
! 150: * Parse a 8-Bit unsigned integer from the current parsing position.
! 151: */
! 152: static bool parse_uint8(private_parser_t *this, int rule_number,
! 153: uint8_t *output_pos)
! 154: {
! 155: if (this->byte_pos + sizeof(uint8_t) > this->input_roof)
! 156: {
! 157: return short_input(this, rule_number);
! 158: }
! 159: if (this->bit_pos)
! 160: {
! 161: return bad_bitpos(this, rule_number);
! 162: }
! 163: if (output_pos)
! 164: {
! 165: *output_pos = *(this->byte_pos);
! 166: DBG3(DBG_ENC, " => %hhu", *output_pos);
! 167: }
! 168: this->byte_pos++;
! 169: return TRUE;
! 170: }
! 171:
! 172: /**
! 173: * Parse a 15-Bit unsigned integer from the current parsing position.
! 174: */
! 175: static bool parse_uint15(private_parser_t *this, int rule_number,
! 176: uint16_t *output_pos)
! 177: {
! 178: if (this->byte_pos + sizeof(uint16_t) > this->input_roof)
! 179: {
! 180: return short_input(this, rule_number);
! 181: }
! 182: if (this->bit_pos != 1)
! 183: {
! 184: return bad_bitpos(this, rule_number);
! 185: }
! 186: if (output_pos)
! 187: {
! 188: memcpy(output_pos, this->byte_pos, sizeof(uint16_t));
! 189: *output_pos = ntohs(*output_pos) & ~0x8000;
! 190: DBG3(DBG_ENC, " => %hu", *output_pos);
! 191: }
! 192: this->byte_pos += sizeof(uint16_t);
! 193: this->bit_pos = 0;
! 194: return TRUE;
! 195: }
! 196:
! 197: /**
! 198: * Parse a 16-Bit unsigned integer from the current parsing position.
! 199: */
! 200: static bool parse_uint16(private_parser_t *this, int rule_number,
! 201: uint16_t *output_pos)
! 202: {
! 203: if (this->byte_pos + sizeof(uint16_t) > this->input_roof)
! 204: {
! 205: return short_input(this, rule_number);
! 206: }
! 207: if (this->bit_pos)
! 208: {
! 209: return bad_bitpos(this, rule_number);
! 210: }
! 211: if (output_pos)
! 212: {
! 213: memcpy(output_pos, this->byte_pos, sizeof(uint16_t));
! 214: *output_pos = ntohs(*output_pos);
! 215: DBG3(DBG_ENC, " => %hu", *output_pos);
! 216: }
! 217: this->byte_pos += sizeof(uint16_t);
! 218: return TRUE;
! 219: }
! 220: /**
! 221: * Parse a 32-Bit unsigned integer from the current parsing position.
! 222: */
! 223: static bool parse_uint32(private_parser_t *this, int rule_number,
! 224: uint32_t *output_pos)
! 225: {
! 226: if (this->byte_pos + sizeof(uint32_t) > this->input_roof)
! 227: {
! 228: return short_input(this, rule_number);
! 229: }
! 230: if (this->bit_pos)
! 231: {
! 232: return bad_bitpos(this, rule_number);
! 233: }
! 234: if (output_pos)
! 235: {
! 236: memcpy(output_pos, this->byte_pos, sizeof(uint32_t));
! 237: *output_pos = ntohl(*output_pos);
! 238: DBG3(DBG_ENC, " => %u", *output_pos);
! 239: }
! 240: this->byte_pos += sizeof(uint32_t);
! 241: return TRUE;
! 242: }
! 243:
! 244: /**
! 245: * Parse a given amount of bytes and writes them to a specific location
! 246: */
! 247: static bool parse_bytes(private_parser_t *this, int rule_number,
! 248: uint8_t *output_pos, int bytes)
! 249: {
! 250: if (this->byte_pos + bytes > this->input_roof)
! 251: {
! 252: return short_input(this, rule_number);
! 253: }
! 254: if (this->bit_pos)
! 255: {
! 256: return bad_bitpos(this, rule_number);
! 257: }
! 258: if (output_pos)
! 259: {
! 260: memcpy(output_pos, this->byte_pos, bytes);
! 261: DBG3(DBG_ENC, " %b", output_pos, bytes);
! 262: }
! 263: this->byte_pos += bytes;
! 264: return TRUE;
! 265: }
! 266:
! 267: /**
! 268: * Parse a single Bit from the current parsing position
! 269: */
! 270: static bool parse_bit(private_parser_t *this, int rule_number,
! 271: bool *output_pos)
! 272: {
! 273: if (this->byte_pos + sizeof(uint8_t) > this->input_roof)
! 274: {
! 275: return short_input(this, rule_number);
! 276: }
! 277: if (output_pos)
! 278: {
! 279: uint8_t mask;
! 280: mask = 0x01 << (7 - this->bit_pos);
! 281: *output_pos = *this->byte_pos & mask;
! 282:
! 283: if (*output_pos)
! 284: { /* set to a "clean", comparable true */
! 285: *output_pos = TRUE;
! 286: }
! 287: DBG3(DBG_ENC, " => %d", *output_pos);
! 288: }
! 289: this->bit_pos = (this->bit_pos + 1) % 8;
! 290: if (this->bit_pos == 0)
! 291: {
! 292: this->byte_pos++;
! 293: }
! 294: return TRUE;
! 295: }
! 296:
! 297: /**
! 298: * Parse substructures in a list.
! 299: */
! 300: static bool parse_list(private_parser_t *this, int rule_number,
! 301: linked_list_t **output_pos, payload_type_t payload_type, int length)
! 302: {
! 303: linked_list_t *list = *output_pos;
! 304:
! 305: if (length < 0)
! 306: {
! 307: return short_input(this, rule_number);
! 308: }
! 309: if (this->bit_pos)
! 310: {
! 311: return bad_bitpos(this, rule_number);
! 312: }
! 313: while (length > 0)
! 314: {
! 315: uint8_t *pos_before = this->byte_pos;
! 316: payload_t *payload;
! 317:
! 318: DBG2(DBG_ENC, " %d bytes left, parsing recursively %N",
! 319: length, payload_type_names, payload_type);
! 320:
! 321: if (this->public.parse_payload(&this->public, payload_type,
! 322: &payload) != SUCCESS)
! 323: {
! 324: DBG1(DBG_ENC, " parsing of a %N substructure failed",
! 325: payload_type_names, payload_type);
! 326: return FALSE;
! 327: }
! 328: list->insert_last(list, payload);
! 329: length -= this->byte_pos - pos_before;
! 330: }
! 331: if (length != 0)
! 332: { /* must yield exactly to zero */
! 333: DBG1(DBG_ENC, " length of %N substructure list invalid",
! 334: payload_type_names, payload_type);
! 335: return FALSE;
! 336: }
! 337: *output_pos = list;
! 338: return TRUE;
! 339: }
! 340:
! 341: /**
! 342: * Parse data from current parsing position in a chunk.
! 343: */
! 344: static bool parse_chunk(private_parser_t *this, int rule_number,
! 345: chunk_t *output_pos, int length)
! 346: {
! 347: if (this->byte_pos + length > this->input_roof)
! 348: {
! 349: return short_input(this, rule_number);
! 350: }
! 351: if (this->bit_pos)
! 352: {
! 353: return bad_bitpos(this, rule_number);
! 354: }
! 355: if (output_pos)
! 356: {
! 357: *output_pos = chunk_alloc(length);
! 358: memcpy(output_pos->ptr, this->byte_pos, length);
! 359: DBG3(DBG_ENC, " %b", output_pos->ptr, length);
! 360: }
! 361: this->byte_pos += length;
! 362: return TRUE;
! 363: }
! 364:
! 365: METHOD(parser_t, parse_payload, status_t,
! 366: private_parser_t *this, payload_type_t payload_type, payload_t **payload)
! 367: {
! 368: payload_t *pld;
! 369: void *output;
! 370: int payload_length = 0, spi_size = 0, attribute_length = 0, header_length;
! 371: uint16_t ts_type = 0;
! 372: bool attribute_format = FALSE;
! 373: int rule_number, rule_count;
! 374: encoding_rule_t *rule;
! 375:
! 376: /* create instance of the payload to parse */
! 377: if (payload_is_known(payload_type, this->major_version))
! 378: {
! 379: pld = payload_create(payload_type);
! 380: }
! 381: else
! 382: {
! 383: pld = (payload_t*)unknown_payload_create(payload_type);
! 384: }
! 385:
! 386: DBG2(DBG_ENC, "parsing %N payload, %d bytes left",
! 387: payload_type_names, payload_type, this->input_roof - this->byte_pos);
! 388:
! 389: DBG3(DBG_ENC, "parsing payload from %b",
! 390: this->byte_pos, (u_int)(this->input_roof - this->byte_pos));
! 391:
! 392: /* base pointer for output, avoids casting in every rule */
! 393: output = pld;
! 394: /* parse the payload with its own rules */
! 395: rule_count = pld->get_encoding_rules(pld, &this->rules);
! 396: for (rule_number = 0; rule_number < rule_count; rule_number++)
! 397: {
! 398: /* update header length for each rule, as it is dynamic (SPIs) */
! 399: header_length = pld->get_header_length(pld);
! 400:
! 401: rule = &(this->rules[rule_number]);
! 402: DBG2(DBG_ENC, " parsing rule %d %N",
! 403: rule_number, encoding_type_names, rule->type);
! 404: switch ((int)rule->type)
! 405: {
! 406: case U_INT_4:
! 407: {
! 408: if (!parse_uint4(this, rule_number, output + rule->offset))
! 409: {
! 410: pld->destroy(pld);
! 411: return PARSE_ERROR;
! 412: }
! 413: break;
! 414: }
! 415: case U_INT_8:
! 416: case RESERVED_BYTE:
! 417: {
! 418: if (!parse_uint8(this, rule_number, output + rule->offset))
! 419: {
! 420: pld->destroy(pld);
! 421: return PARSE_ERROR;
! 422: }
! 423: break;
! 424: }
! 425: case U_INT_16:
! 426: {
! 427: if (!parse_uint16(this, rule_number, output + rule->offset))
! 428: {
! 429: pld->destroy(pld);
! 430: return PARSE_ERROR;
! 431: }
! 432: break;
! 433: }
! 434: case U_INT_32:
! 435: case HEADER_LENGTH:
! 436: {
! 437: if (!parse_uint32(this, rule_number, output + rule->offset))
! 438: {
! 439: pld->destroy(pld);
! 440: return PARSE_ERROR;
! 441: }
! 442: break;
! 443: }
! 444: case IKE_SPI:
! 445: {
! 446: if (!parse_bytes(this, rule_number, output + rule->offset, 8))
! 447: {
! 448: pld->destroy(pld);
! 449: return PARSE_ERROR;
! 450: }
! 451: break;
! 452: }
! 453: case RESERVED_BIT:
! 454: case FLAG:
! 455: {
! 456: if (!parse_bit(this, rule_number, output + rule->offset))
! 457: {
! 458: pld->destroy(pld);
! 459: return PARSE_ERROR;
! 460: }
! 461: break;
! 462: }
! 463: case PAYLOAD_LENGTH:
! 464: {
! 465: if (!parse_uint16(this, rule_number, output + rule->offset))
! 466: {
! 467: pld->destroy(pld);
! 468: return PARSE_ERROR;
! 469: }
! 470: /* parsed u_int16 should be aligned */
! 471: payload_length = *(uint16_t*)(output + rule->offset);
! 472: /* all payloads must have at least 4 bytes header */
! 473: if (payload_length < 4)
! 474: {
! 475: pld->destroy(pld);
! 476: return PARSE_ERROR;
! 477: }
! 478: break;
! 479: }
! 480: case SPI_SIZE:
! 481: {
! 482: if (!parse_uint8(this, rule_number, output + rule->offset))
! 483: {
! 484: pld->destroy(pld);
! 485: return PARSE_ERROR;
! 486: }
! 487: spi_size = *(uint8_t*)(output + rule->offset);
! 488: break;
! 489: }
! 490: case SPI:
! 491: {
! 492: if (!parse_chunk(this, rule_number, output + rule->offset,
! 493: spi_size))
! 494: {
! 495: pld->destroy(pld);
! 496: return PARSE_ERROR;
! 497: }
! 498: break;
! 499: }
! 500: case PAYLOAD_LIST + PLV2_PROPOSAL_SUBSTRUCTURE:
! 501: case PAYLOAD_LIST + PLV1_PROPOSAL_SUBSTRUCTURE:
! 502: case PAYLOAD_LIST + PLV2_TRANSFORM_SUBSTRUCTURE:
! 503: case PAYLOAD_LIST + PLV1_TRANSFORM_SUBSTRUCTURE:
! 504: case PAYLOAD_LIST + PLV2_TRANSFORM_ATTRIBUTE:
! 505: case PAYLOAD_LIST + PLV1_TRANSFORM_ATTRIBUTE:
! 506: case PAYLOAD_LIST + PLV2_CONFIGURATION_ATTRIBUTE:
! 507: case PAYLOAD_LIST + PLV1_CONFIGURATION_ATTRIBUTE:
! 508: case PAYLOAD_LIST + PLV2_TRAFFIC_SELECTOR_SUBSTRUCTURE:
! 509: {
! 510: if (payload_length < header_length ||
! 511: !parse_list(this, rule_number, output + rule->offset,
! 512: rule->type - PAYLOAD_LIST,
! 513: payload_length - header_length))
! 514: {
! 515: pld->destroy(pld);
! 516: return PARSE_ERROR;
! 517: }
! 518: break;
! 519: }
! 520: case CHUNK_DATA:
! 521: {
! 522: if (payload_length < header_length ||
! 523: !parse_chunk(this, rule_number, output + rule->offset,
! 524: payload_length - header_length))
! 525: {
! 526: pld->destroy(pld);
! 527: return PARSE_ERROR;
! 528: }
! 529: break;
! 530: }
! 531: case ENCRYPTED_DATA:
! 532: {
! 533: if (!parse_chunk(this, rule_number, output + rule->offset,
! 534: this->input_roof - this->byte_pos))
! 535: {
! 536: pld->destroy(pld);
! 537: return PARSE_ERROR;
! 538: }
! 539: break;
! 540: }
! 541: case ATTRIBUTE_FORMAT:
! 542: {
! 543: if (!parse_bit(this, rule_number, output + rule->offset))
! 544: {
! 545: pld->destroy(pld);
! 546: return PARSE_ERROR;
! 547: }
! 548: attribute_format = *(bool*)(output + rule->offset);
! 549: break;
! 550: }
! 551: case ATTRIBUTE_TYPE:
! 552: {
! 553: if (!parse_uint15(this, rule_number, output + rule->offset))
! 554: {
! 555: pld->destroy(pld);
! 556: return PARSE_ERROR;
! 557: }
! 558: break;
! 559: }
! 560: case ATTRIBUTE_LENGTH:
! 561: {
! 562: if (!parse_uint16(this, rule_number, output + rule->offset))
! 563: {
! 564: pld->destroy(pld);
! 565: return PARSE_ERROR;
! 566: }
! 567: attribute_length = *(uint16_t*)(output + rule->offset);
! 568: break;
! 569: }
! 570: case ATTRIBUTE_LENGTH_OR_VALUE:
! 571: {
! 572: if (!parse_uint16(this, rule_number, output + rule->offset))
! 573: {
! 574: pld->destroy(pld);
! 575: return PARSE_ERROR;
! 576: }
! 577: attribute_length = *(uint16_t*)(output + rule->offset);
! 578: break;
! 579: }
! 580: case ATTRIBUTE_VALUE:
! 581: {
! 582: if (attribute_format == FALSE &&
! 583: !parse_chunk(this, rule_number, output + rule->offset,
! 584: attribute_length))
! 585: {
! 586: pld->destroy(pld);
! 587: return PARSE_ERROR;
! 588: }
! 589: break;
! 590: }
! 591: case TS_TYPE:
! 592: {
! 593: if (!parse_uint8(this, rule_number, output + rule->offset))
! 594: {
! 595: pld->destroy(pld);
! 596: return PARSE_ERROR;
! 597: }
! 598: ts_type = *(uint8_t*)(output + rule->offset);
! 599: break;
! 600: }
! 601: case ADDRESS:
! 602: {
! 603: int address_length = (ts_type == TS_IPV4_ADDR_RANGE) ? 4 : 16;
! 604:
! 605: if (!parse_chunk(this, rule_number, output + rule->offset,
! 606: address_length))
! 607: {
! 608: pld->destroy(pld);
! 609: return PARSE_ERROR;
! 610: }
! 611: break;
! 612: }
! 613: default:
! 614: {
! 615: DBG1(DBG_ENC, " no rule to parse rule %d %N",
! 616: rule_number, encoding_type_names, rule->type);
! 617: pld->destroy(pld);
! 618: return PARSE_ERROR;
! 619: }
! 620: }
! 621: /* process next rule */
! 622: rule++;
! 623: }
! 624:
! 625: *payload = pld;
! 626: DBG2(DBG_ENC, "parsing %N payload finished",
! 627: payload_type_names, payload_type);
! 628: return SUCCESS;
! 629: }
! 630:
! 631: METHOD(parser_t, get_remaining_byte_count, int,
! 632: private_parser_t *this)
! 633: {
! 634: return this->input_roof - this->byte_pos;
! 635: }
! 636:
! 637: METHOD(parser_t, reset_context, void,
! 638: private_parser_t *this)
! 639: {
! 640: this->byte_pos = this->input;
! 641: this->bit_pos = 0;
! 642: }
! 643:
! 644: METHOD(parser_t, set_major_version, void,
! 645: private_parser_t *this, uint8_t major_version)
! 646: {
! 647: this->major_version = major_version;
! 648: }
! 649:
! 650: METHOD(parser_t, destroy, void,
! 651: private_parser_t *this)
! 652: {
! 653: free(this);
! 654: }
! 655:
! 656: /*
! 657: * Described in header.
! 658: */
! 659: parser_t *parser_create(chunk_t data)
! 660: {
! 661: private_parser_t *this;
! 662:
! 663: INIT(this,
! 664: .public = {
! 665: .parse_payload = _parse_payload,
! 666: .reset_context = _reset_context,
! 667: .set_major_version = _set_major_version,
! 668: .get_remaining_byte_count = _get_remaining_byte_count,
! 669: .destroy = _destroy,
! 670: },
! 671: .input = data.ptr,
! 672: .byte_pos = data.ptr,
! 673: .input_roof = data.ptr + data.len,
! 674: );
! 675:
! 676: return &this->public;
! 677: }
! 678:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>