Annotation of embedaddon/strongswan/src/libstrongswan/asn1/asn1_parser.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2006 Martin Will
! 3: * Copyright (C) 2000-2017 Andreas Steffen
! 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 <stdio.h>
! 18: #include <string.h>
! 19: #include <time.h>
! 20:
! 21: #include <utils/debug.h>
! 22:
! 23: #include "asn1.h"
! 24: #include "asn1_parser.h"
! 25:
! 26: #define ASN1_MAX_LEVEL 10
! 27:
! 28: typedef struct private_asn1_parser_t private_asn1_parser_t;
! 29:
! 30: /**
! 31: * Private data of an asn1_cxt_t object.
! 32: */
! 33: struct private_asn1_parser_t {
! 34: /**
! 35: * Public interface.
! 36: */
! 37: asn1_parser_t public;
! 38:
! 39: /**
! 40: * Syntax definition of ASN.1 object
! 41: */
! 42: asn1Object_t const *objects;
! 43:
! 44: /**
! 45: * Current syntax definition line
! 46: */
! 47: int line;
! 48:
! 49: /**
! 50: * Current stat of the parsing operation
! 51: */
! 52: bool success;
! 53:
! 54: /**
! 55: * Declare object data as private - use debug level 4 to log it
! 56: */
! 57: bool private;
! 58:
! 59: /**
! 60: * Top-most type is implicit - ignore it
! 61: */
! 62: bool implicit;
! 63:
! 64: /**
! 65: * Top-most parsing level - defaults to 0
! 66: */
! 67: u_int level0;
! 68:
! 69: /**
! 70: * Jump back address for loops for each level
! 71: */
! 72: int loopAddr[ASN1_MAX_LEVEL + 1];
! 73:
! 74: /**
! 75: * Current parsing pointer for each level
! 76: */
! 77: chunk_t blobs[ASN1_MAX_LEVEL + 2];
! 78:
! 79: /**
! 80: * Parsing a CHOICE on the current level ?
! 81: */
! 82: bool choice[ASN1_MAX_LEVEL + 2];
! 83:
! 84: };
! 85:
! 86: METHOD(asn1_parser_t, iterate, bool,
! 87: private_asn1_parser_t *this, int *objectID, chunk_t *object)
! 88: {
! 89: chunk_t *blob, *blob1, blob_ori;
! 90: u_char *start_ptr;
! 91: u_int level;
! 92: asn1Object_t obj;
! 93:
! 94: *object = chunk_empty;
! 95:
! 96: /* Advance to the next object syntax definition line */
! 97: obj = this->objects[++(this->line)];
! 98:
! 99: /* Terminate if the end of the object syntax definition has been reached */
! 100: if (obj.flags & ASN1_EXIT)
! 101: {
! 102: return FALSE;
! 103: }
! 104:
! 105: if (obj.flags & ASN1_END) /* end of loop or choice or option found */
! 106: {
! 107: if (this->loopAddr[obj.level] && this->blobs[obj.level+1].len > 0)
! 108: {
! 109: this->line = this->loopAddr[obj.level]; /* another iteration */
! 110: obj = this->objects[this->line];
! 111: }
! 112: else
! 113: {
! 114: this->loopAddr[obj.level] = 0; /* exit loop */
! 115:
! 116: if (obj.flags & ASN1_CHOICE) /* end of choices */
! 117: {
! 118: if (this->choice[obj.level+1])
! 119: {
! 120: DBG1(DBG_ASN, "L%d - %s: incorrect choice encoding",
! 121: this->level0 + obj.level, obj.name);
! 122: this->success = FALSE;
! 123: goto end;
! 124: }
! 125: }
! 126:
! 127: if (obj.flags & ASN1_CH) /* end of choice */
! 128: {
! 129: /* parsed a valid choice */
! 130: this->choice[obj.level] = FALSE;
! 131:
! 132: /* advance to end of choices */
! 133: do
! 134: {
! 135: this->line++;
! 136: }
! 137: while (!((this->objects[this->line].flags & ASN1_END) &&
! 138: (this->objects[this->line].flags & ASN1_CHOICE) &&
! 139: (this->objects[this->line].level == obj.level-1)));
! 140: this->line--;
! 141: }
! 142:
! 143: goto end;
! 144: }
! 145: }
! 146:
! 147: level = this->level0 + obj.level;
! 148: blob = this->blobs + obj.level;
! 149: blob_ori = *blob;
! 150: blob1 = blob + 1;
! 151: start_ptr = blob->ptr;
! 152:
! 153: /* handle ASN.1 defaults values */
! 154: if ((obj.flags & ASN1_DEF) && (blob->len == 0 || *start_ptr != obj.type) )
! 155: {
! 156: /* field is missing */
! 157: DBG2(DBG_ASN, "L%d - %s:", level, obj.name);
! 158: if (obj.type & ASN1_CONSTRUCTED)
! 159: {
! 160: this->line++ ; /* skip context-specific tag */
! 161: }
! 162: goto end;
! 163: }
! 164:
! 165: /* handle ASN.1 options */
! 166: if ((obj.flags & ASN1_OPT)
! 167: && (blob->len == 0 || *start_ptr != obj.type))
! 168: {
! 169: /* advance to end of missing option field */
! 170: do
! 171: {
! 172: this->line++;
! 173: }
! 174: while (!((this->objects[this->line].flags & ASN1_END) &&
! 175: (this->objects[this->line].level == obj.level)));
! 176: goto end;
! 177: }
! 178:
! 179: /* an ASN.1 object must possess at least a tag and length field */
! 180: if (blob->len < 2)
! 181: {
! 182: DBG1(DBG_ASN, "L%d - %s: ASN.1 object smaller than 2 octets",
! 183: level, obj.name);
! 184: this->success = FALSE;
! 185: goto end;
! 186: }
! 187:
! 188: blob1->len = asn1_length(blob);
! 189:
! 190: if (blob1->len == ASN1_INVALID_LENGTH)
! 191: {
! 192: DBG1(DBG_ASN, "L%d - %s: length of ASN.1 object invalid or too large",
! 193: level, obj.name);
! 194: this->success = FALSE;
! 195: goto end;
! 196: }
! 197:
! 198: blob1->ptr = blob->ptr;
! 199: blob->ptr += blob1->len;
! 200: blob->len -= blob1->len;
! 201:
! 202: /* handle ASN.1 choice without explicit context encoding */
! 203: if ((obj.flags & ASN1_CHOICE) && obj.type == ASN1_EOC)
! 204: {
! 205: DBG2(DBG_ASN, "L%d - %s:", level, obj.name);
! 206: this->choice[obj.level+1] = TRUE;
! 207: *blob1 = blob_ori;
! 208: goto end;
! 209: }
! 210:
! 211: /* return raw ASN.1 object without prior type checking */
! 212: if (obj.flags & ASN1_RAW)
! 213: {
! 214: DBG2(DBG_ASN, "L%d - %s:", level, obj.name);
! 215: object->ptr = start_ptr;
! 216: object->len = (size_t)(blob->ptr - start_ptr);
! 217: goto end;
! 218: }
! 219:
! 220: if (*start_ptr != obj.type && !(this->implicit && this->line == 0))
! 221: {
! 222: DBG2(DBG_ASN, "L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
! 223: level, obj.name, obj.type, *start_ptr);
! 224: DBG3(DBG_ASN, "%b", start_ptr, (u_int)(blob->ptr - start_ptr));
! 225: this->success = FALSE;
! 226: goto end;
! 227: }
! 228:
! 229: DBG2(DBG_ASN, "L%d - %s:", level, obj.name);
! 230:
! 231: /* In case of "SEQUENCE OF" or "SET OF" start a loop */
! 232: if (obj.flags & ASN1_LOOP)
! 233: {
! 234: if (blob1->len > 0)
! 235: {
! 236: /* at least one item, start the loop */
! 237: this->loopAddr[obj.level] = this->line + 1;
! 238: }
! 239: else
! 240: {
! 241: /* no items, advance directly to end of loop */
! 242: do
! 243: {
! 244: this->line++;
! 245: }
! 246: while (!((this->objects[this->line].flags & ASN1_END) &&
! 247: (this->objects[this->line].level == obj.level)));
! 248: goto end;
! 249: }
! 250: }
! 251:
! 252: /* In case of a "CHOICE" start to scan for exactly one valid choice */
! 253: if (obj.flags & ASN1_CHOICE)
! 254: {
! 255: if (blob1->len == 0)
! 256: {
! 257: DBG1(DBG_ASN, "L%d - %s: contains no choice", level, obj.name);
! 258: this->success = FALSE;
! 259: goto end;
! 260: }
! 261: this->choice[obj.level+1] = TRUE;
! 262: }
! 263:
! 264: if (obj.flags & ASN1_OBJ)
! 265: {
! 266: object->ptr = start_ptr;
! 267: object->len = (size_t)(blob->ptr - start_ptr);
! 268: if (this->private)
! 269: {
! 270: DBG4(DBG_ASN, "%B", object);
! 271: }
! 272: else
! 273: {
! 274: DBG3(DBG_ASN, "%B", object);
! 275: }
! 276: }
! 277: else if (obj.flags & ASN1_BODY)
! 278: {
! 279: *object = *blob1;
! 280: asn1_debug_simple_object(*object, obj.type, this->private);
! 281: }
! 282:
! 283: end:
! 284: *objectID = this->line;
! 285: return this->success;
! 286: }
! 287:
! 288: METHOD(asn1_parser_t, get_level, u_int,
! 289: private_asn1_parser_t *this)
! 290: {
! 291: return this->level0 + this->objects[this->line].level;
! 292: }
! 293:
! 294: METHOD(asn1_parser_t, set_top_level, void,
! 295: private_asn1_parser_t *this, u_int level0)
! 296: {
! 297: this->level0 = level0;
! 298: }
! 299:
! 300: METHOD(asn1_parser_t, set_flags, void,
! 301: private_asn1_parser_t *this, bool implicit, bool private)
! 302: {
! 303: this->implicit = implicit;
! 304: this->private = private;
! 305: }
! 306:
! 307: METHOD(asn1_parser_t, success, bool,
! 308: private_asn1_parser_t *this)
! 309: {
! 310: return this->success;
! 311: }
! 312:
! 313: METHOD(asn1_parser_t, destroy, void,
! 314: private_asn1_parser_t *this)
! 315: {
! 316: free(this);
! 317: }
! 318:
! 319: /**
! 320: * Defined in header.
! 321: */
! 322: asn1_parser_t* asn1_parser_create(asn1Object_t const *objects, chunk_t blob)
! 323: {
! 324: private_asn1_parser_t *this;
! 325:
! 326: INIT(this,
! 327: .public = {
! 328: .iterate = _iterate,
! 329: .get_level = _get_level,
! 330: .set_top_level = _set_top_level,
! 331: .set_flags = _set_flags,
! 332: .success = _success,
! 333: .destroy = _destroy,
! 334: },
! 335: .objects = objects,
! 336: .blobs[0] = blob,
! 337: .line = -1,
! 338: .success = TRUE,
! 339: );
! 340:
! 341: return &this->public;
! 342: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>