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>