diff options
Diffstat (limited to 'src/libstrongswan/asn1/asn1_parser.c')
-rw-r--r-- | src/libstrongswan/asn1/asn1_parser.c | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/src/libstrongswan/asn1/asn1_parser.c b/src/libstrongswan/asn1/asn1_parser.c new file mode 100644 index 000000000..7a2028fc3 --- /dev/null +++ b/src/libstrongswan/asn1/asn1_parser.c @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2006 Martin Will + * Copyright (C) 2000-2008 Andreas Steffen + * + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id: asn1_parser.c 3894 2008-04-28 18:44:21Z andreas $ + */ + +#include <stdio.h> +#include <string.h> +#include <time.h> + +#include <library.h> +#include <debug.h> + +#include "asn1.h" +#include "asn1_parser.h" + +#define ASN1_MAX_LEVEL 10 + +typedef struct private_asn1_parser_t private_asn1_parser_t; + +/** + * Private data of an asn1_cxt_t object. + */ +struct private_asn1_parser_t { + /** + * Public interface. + */ + asn1_parser_t public; + + /** + * Syntax definition of ASN.1 object + */ + asn1Object_t const *objects; + + /** + * Current syntax definition line + */ + int line; + + /** + * Current stat of the parsing operation + */ + bool success; + + /** + * Declare object data as private - use debug level 4 to log it + */ + bool private; + + /** + * Top-most type is implicit - ignore it + */ + bool implicit; + + /** + * Top-most parsing level - defaults to 0 + */ + u_int level0; + + /** + * Jump back address for loops for each level + */ + int loopAddr[ASN1_MAX_LEVEL + 1]; + + /** + * Current parsing pointer for each level + */ + chunk_t blobs[ASN1_MAX_LEVEL + 2]; +}; + +/** + * Implementation of asn1_parser_t.iterate + */ +static bool iterate(private_asn1_parser_t *this, int *objectID, chunk_t *object) +{ + chunk_t *blob, *blob1; + u_char *start_ptr; + u_int level; + asn1Object_t obj; + + *object = chunk_empty; + + /* Advance to the next object syntax definition line */ + obj = this->objects[++(this->line)]; + + /* Terminate if the end of the object syntax definition has been reached */ + if (obj.flags & ASN1_EXIT) + { + return FALSE; + } + + if (obj.flags & ASN1_END) /* end of loop or option found */ + { + if (this->loopAddr[obj.level] && this->blobs[obj.level+1].len > 0) + { + this->line = this->loopAddr[obj.level]; /* another iteration */ + obj = this->objects[this->line]; + } + else + { + this->loopAddr[obj.level] = 0; /* exit loop or option*/ + goto end; + } + } + + level = this->level0 + obj.level; + blob = this->blobs + obj.level; + blob1 = blob + 1; + start_ptr = blob->ptr; + + /* handle ASN.1 defaults values */ + if ((obj.flags & ASN1_DEF) && (blob->len == 0 || *start_ptr != obj.type) ) + { + /* field is missing */ + DBG2("L%d - %s:", level, obj.name); + if (obj.type & ASN1_CONSTRUCTED) + { + this->line++ ; /* skip context-specific tag */ + } + goto end; + } + + /* handle ASN.1 options */ + + if ((obj.flags & ASN1_OPT) + && (blob->len == 0 || *start_ptr != obj.type)) + { + /* advance to end of missing option field */ + do + { + this->line++; + } + while (!((this->objects[this->line].flags & ASN1_END) && + (this->objects[this->line].level == obj.level))); + goto end; + } + + /* an ASN.1 object must possess at least a tag and length field */ + + if (blob->len < 2) + { + DBG1("L%d - %s: ASN.1 object smaller than 2 octets", + level, obj.name); + this->success = FALSE; + goto end; + } + + blob1->len = asn1_length(blob); + + if (blob1->len == ASN1_INVALID_LENGTH || blob->len < blob1->len) + { + DBG1("L%d - %s: length of ASN.1 object invalid or too large", + level, obj.name); + this->success = FALSE; + } + + blob1->ptr = blob->ptr; + blob->ptr += blob1->len; + blob->len -= blob1->len; + + /* return raw ASN.1 object without prior type checking */ + + if (obj.flags & ASN1_RAW) + { + DBG2("L%d - %s:", level, obj.name); + object->ptr = start_ptr; + object->len = (size_t)(blob->ptr - start_ptr); + goto end; + } + + if (*start_ptr != obj.type && !(this->implicit && this->line == 0)) + { + DBG1("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x", + level, obj.name, obj.type, *start_ptr); + DBG3("%b", start_ptr, (u_int)(blob->ptr - start_ptr)); + this->success = FALSE; + goto end; + } + + DBG2("L%d - %s:", level, obj.name); + + /* In case of "SEQUENCE OF" or "SET OF" start a loop */ + if (obj.flags & ASN1_LOOP) + { + if (blob1->len > 0) + { + /* at least one item, start the loop */ + this->loopAddr[obj.level] = this->line + 1; + } + else + { + /* no items, advance directly to end of loop */ + do + { + this->line++; + } + while (!((this->objects[this->line].flags & ASN1_END) && + (this->objects[this->line].level == obj.level))); + goto end; + } + } + + if (obj.flags & ASN1_OBJ) + { + object->ptr = start_ptr; + object->len = (size_t)(blob->ptr - start_ptr); + if (this->private) + { + DBG4("%B", object); + } + else + { + DBG3("%B", object); + } + } + else if (obj.flags & ASN1_BODY) + { + *object = *blob1; + asn1_debug_simple_object(*object, obj.type, this->private); + } + +end: + *objectID = this->line; + return this->success; +} + +/** + * Implementation of asn1_parser_t.get_level + */ +static u_int get_level(private_asn1_parser_t *this) +{ + return this->level0 + this->objects[this->line].level; +} + +/** + * Implementation of asn1_parser_t.set_top_level + */ +static void set_top_level(private_asn1_parser_t *this, u_int level0) +{ + this->level0 = level0; +} + +/** + * Implementation of asn1_parser_t.set_flags + */ +static void set_flags(private_asn1_parser_t *this, bool implicit, bool private) +{ + this->implicit = implicit; + this->private = private; +} + +/** + * Implementation of asn1_parser_t.success + */ +static bool success(private_asn1_parser_t *this) +{ + return this->success; +} + +/** + * Implementation of asn1_parser_t.destroy + */ +static void destroy(private_asn1_parser_t *this) +{ + free(this); +} + +/** + * Defined in header. + */ +asn1_parser_t* asn1_parser_create(asn1Object_t const *objects, chunk_t blob) +{ + private_asn1_parser_t *this = malloc_thing(private_asn1_parser_t); + + memset(this, '\0', sizeof(private_asn1_parser_t)); + this->objects = objects; + this->blobs[0] = blob; + this->line = -1; + this->success = TRUE; + + this->public.iterate = (bool (*)(asn1_parser_t*, int*, chunk_t*))iterate; + this->public.get_level = (u_int (*)(asn1_parser_t*))get_level; + this->public.set_top_level = (void (*)(asn1_parser_t*, u_int))set_top_level; + this->public.set_flags = (void (*)(asn1_parser_t*, bool, bool))set_flags; + this->public.success = (bool (*)(asn1_parser_t*))success; + this->public.destroy = (void (*)(asn1_parser_t*))destroy; + + return &this->public; +} |