Annotation of embedaddon/strongswan/src/libimcv/pa_tnc/pa_tnc_msg.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2011-2015 Andreas Steffen
        !             3:  * HSR Hochschule fuer Technik Rapperswil
        !             4:  *
        !             5:  * This program is free software; you can redistribute it and/or modify it
        !             6:  * under the terms of the GNU General Public License as published by the
        !             7:  * Free Software Foundation; either version 2 of the License, or (at your
        !             8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !             9:  *
        !            10:  * This program is distributed in the hope that it will be useful, but
        !            11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            13:  * for more details.
        !            14:  */
        !            15: 
        !            16: #include "imcv.h"
        !            17: #include "pa_tnc_msg.h"
        !            18: #include "ietf/ietf_attr_pa_tnc_error.h"
        !            19: 
        !            20: #include <bio/bio_writer.h>
        !            21: #include <bio/bio_reader.h>
        !            22: #include <collections/linked_list.h>
        !            23: #include <pen/pen.h>
        !            24: #include <utils/debug.h>
        !            25: 
        !            26: typedef struct private_pa_tnc_msg_t private_pa_tnc_msg_t;
        !            27: 
        !            28: /**
        !            29:  *   PA-TNC message header
        !            30:  *
        !            31:  *                        1                   2                   3
        !            32:  *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
        !            33:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            34:  *  |    Version    |                    Reserved                   |
        !            35:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            36:  *  |                       Message Identifier                      |
        !            37:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            38:  */
        !            39: 
        !            40: #define PA_TNC_RESERVED                0x000000
        !            41: 
        !            42: /**
        !            43:  * Private data of a pa_tnc_msg_t object.
        !            44:  *
        !            45:  */
        !            46: struct private_pa_tnc_msg_t {
        !            47: 
        !            48:        /**
        !            49:         * Public pa_tnc_msg_t interface.
        !            50:         */
        !            51:        pa_tnc_msg_t public;
        !            52: 
        !            53:        /**
        !            54:         * List of PA-TNC attributes
        !            55:         */
        !            56:        linked_list_t *attributes;
        !            57: 
        !            58:        /**
        !            59:         * linked list of PA-TNC error messages
        !            60:         */
        !            61:        linked_list_t *errors;
        !            62: 
        !            63:        /**
        !            64:         * Message identifier
        !            65:         */
        !            66:        uint32_t identifier;
        !            67: 
        !            68:        /**
        !            69:         * Current PA-TNC Message size
        !            70:         */
        !            71:        size_t msg_len;
        !            72: 
        !            73:        /**
        !            74:         * Maximum PA-TNC Message size
        !            75:         */
        !            76:        size_t max_msg_len;
        !            77: 
        !            78:        /**
        !            79:         * TRUE if attribute was extracted from data
        !            80:         */
        !            81:        bool from_data;
        !            82: 
        !            83:        /**
        !            84:         * Encoded message
        !            85:         */
        !            86:        chunk_t encoding;
        !            87: };
        !            88: 
        !            89: METHOD(pa_tnc_msg_t, get_encoding, chunk_t,
        !            90:        private_pa_tnc_msg_t *this)
        !            91: {
        !            92:        return this->encoding;
        !            93: }
        !            94: 
        !            95: METHOD(pa_tnc_msg_t, get_space, size_t,
        !            96:        private_pa_tnc_msg_t *this)
        !            97: {
        !            98:        return this->max_msg_len ? this->max_msg_len - this->msg_len : 0;
        !            99: }
        !           100: 
        !           101: METHOD(pa_tnc_msg_t, add_attribute, bool,
        !           102:        private_pa_tnc_msg_t *this, pa_tnc_attr_t *attr)
        !           103: {
        !           104:        chunk_t attr_value;
        !           105:        size_t attr_len;
        !           106: 
        !           107:        if (!this->from_data)
        !           108:        {
        !           109:                attr->build(attr);
        !           110:                attr_value = attr->get_value(attr);
        !           111:                attr_len = PA_TNC_ATTR_HEADER_SIZE + attr_value.len;
        !           112: 
        !           113:                if (this->max_msg_len && this->msg_len + attr_len > this->max_msg_len)
        !           114:                {
        !           115:                        /* attribute just does not fit into this message */
        !           116:                        return FALSE;
        !           117:                }
        !           118:                this->msg_len += attr_len;
        !           119:        }
        !           120:        this->attributes->insert_last(this->attributes, attr);
        !           121:        return TRUE;
        !           122: }
        !           123: 
        !           124: METHOD(pa_tnc_msg_t, build, bool,
        !           125:        private_pa_tnc_msg_t *this)
        !           126: {
        !           127:        bio_writer_t *writer;
        !           128:        enumerator_t *enumerator;
        !           129:        pa_tnc_attr_t *attr;
        !           130:        enum_name_t *pa_attr_names;
        !           131:        pen_type_t type;
        !           132:        uint8_t flags;
        !           133:        chunk_t value;
        !           134:        nonce_gen_t *ng;
        !           135: 
        !           136:        /* generate a nonce as a message identifier */
        !           137:        ng = lib->crypto->create_nonce_gen(lib->crypto);
        !           138:        if (!ng || !ng->get_nonce(ng, 4, (uint8_t*)&this->identifier))
        !           139:        {
        !           140:                DBG1(DBG_TNC, "failed to generate random PA-TNC message identifier");
        !           141:                DESTROY_IF(ng);
        !           142:                return FALSE;
        !           143:        }
        !           144:        ng->destroy(ng);
        !           145:        DBG1(DBG_TNC, "creating PA-TNC message with ID 0x%08x", this->identifier);
        !           146: 
        !           147:        /* build message header */
        !           148:        writer = bio_writer_create(this->msg_len);
        !           149:        writer->write_uint8 (writer, PA_TNC_VERSION);
        !           150:        writer->write_uint24(writer, PA_TNC_RESERVED);
        !           151:        writer->write_uint32(writer, this->identifier);
        !           152: 
        !           153:        /* append encoded value of PA-TNC attributes */
        !           154:        enumerator = this->attributes->create_enumerator(this->attributes);
        !           155:        while (enumerator->enumerate(enumerator, &attr))
        !           156:        {
        !           157:                type  = attr->get_type(attr);
        !           158:                value = attr->get_value(attr);
        !           159:                flags = attr->get_noskip_flag(attr) ? PA_TNC_ATTR_FLAG_NOSKIP :
        !           160:                                                                                          PA_TNC_ATTR_FLAG_NONE;
        !           161: 
        !           162:                pa_attr_names = imcv_pa_tnc_attributes->get_names(imcv_pa_tnc_attributes,
        !           163:                                                                                                                  type.vendor_id);
        !           164:                if (pa_attr_names)
        !           165:                {
        !           166:                        DBG2(DBG_TNC, "creating PA-TNC attribute type '%N/%N' "
        !           167:                                                  "0x%06x/0x%08x", pen_names, type.vendor_id,
        !           168:                                                   pa_attr_names, type.type, type.vendor_id, type.type);
        !           169:                }
        !           170:                else
        !           171:                {
        !           172:                        DBG2(DBG_TNC, "creating PA-TNC attribute type '%N' "
        !           173:                                                  "0x%06x/0x%08x", pen_names, type.vendor_id,
        !           174:                                                   type.vendor_id, type.type);
        !           175:                }
        !           176:                DBG3(DBG_TNC, "%B", &value);
        !           177: 
        !           178:                writer->write_uint8 (writer, flags);
        !           179:                writer->write_uint24(writer, type.vendor_id);
        !           180:                writer->write_uint32(writer, type.type);
        !           181:                writer->write_uint32(writer, PA_TNC_ATTR_HEADER_SIZE + value.len);
        !           182:                writer->write_data  (writer, value);
        !           183:        }
        !           184:        enumerator->destroy(enumerator);
        !           185: 
        !           186:        free(this->encoding.ptr);
        !           187:        this->encoding = writer->extract_buf(writer);
        !           188:        writer->destroy(writer);
        !           189: 
        !           190:        return TRUE;
        !           191: }
        !           192: 
        !           193: METHOD(pa_tnc_msg_t, process, status_t,
        !           194:        private_pa_tnc_msg_t *this)
        !           195: {
        !           196:        bio_reader_t *reader;
        !           197:        pa_tnc_attr_t *attr, *error;
        !           198:        pen_type_t attr_type;
        !           199:        chunk_t attr_value;
        !           200:        uint8_t version;
        !           201:        uint32_t reserved, offset, attr_offset;
        !           202:        pen_type_t error_code = { PEN_IETF, PA_ERROR_INVALID_PARAMETER };
        !           203: 
        !           204:        /* process message header */
        !           205:        if (this->encoding.len < PA_TNC_HEADER_SIZE)
        !           206:        {
        !           207:                DBG1(DBG_TNC, "%u bytes insufficient to parse PA-TNC message header",
        !           208:                                           this->encoding.len);
        !           209:                return FAILED;
        !           210:        }
        !           211:        reader = bio_reader_create(this->encoding);
        !           212:        reader->read_uint8 (reader, &version);
        !           213:        reader->read_uint24(reader, &reserved);
        !           214:        reader->read_uint32(reader, &this->identifier);
        !           215:        DBG1(DBG_TNC, "processing PA-TNC message with ID 0x%08x", this->identifier);
        !           216: 
        !           217:        if (version != PA_TNC_VERSION)
        !           218:        {
        !           219:                DBG1(DBG_TNC, "PA-TNC version %u not supported", version);
        !           220:                error_code = pen_type_create(PEN_IETF, PA_ERROR_VERSION_NOT_SUPPORTED);
        !           221:                error = ietf_attr_pa_tnc_error_create(error_code, this->encoding);
        !           222:                goto err;
        !           223:        }
        !           224: 
        !           225:        /* offset of the first PA-TNC attribute in the PA-TNC message */
        !           226:        offset = PA_TNC_HEADER_SIZE;
        !           227: 
        !           228:        /* pre-process PA-TNC attributes */
        !           229:        while (reader->remaining(reader) > 0)
        !           230:        {
        !           231:                attr = imcv_pa_tnc_attributes->create(imcv_pa_tnc_attributes,
        !           232:                                                        reader, FALSE, &offset, this->encoding, &error);
        !           233:                if (!attr)
        !           234:                {
        !           235:                        if (error)
        !           236:                        {
        !           237:                                goto err;
        !           238:                        }
        !           239:                        else
        !           240:                        {
        !           241:                                continue;
        !           242:                        }
        !           243:                }
        !           244:                attr_value = attr->get_value(attr);
        !           245:                attr_type  = attr->get_type(attr);
        !           246: 
        !           247:                if (attr->process(attr, &attr_offset) != SUCCESS)
        !           248:                {
        !           249:                        attr->destroy(attr);
        !           250: 
        !           251:                        if (attr_type.vendor_id == PEN_IETF &&
        !           252:                                attr_type.type == IETF_ATTR_PA_TNC_ERROR)
        !           253:                        {
        !           254:                                /* suppress error while processing a PA-TNC error attribute */
        !           255:                                offset += attr_value.len;
        !           256:                                continue;
        !           257:                        }
        !           258:                        error_code = pen_type_create(PEN_IETF, PA_ERROR_INVALID_PARAMETER);
        !           259:                        error = ietf_attr_pa_tnc_error_create_with_offset(error_code,
        !           260:                                                                        this->encoding, offset + attr_offset);
        !           261:                        goto err;
        !           262:                }
        !           263:                offset += attr_value.len;
        !           264:                this->attributes->insert_last(this->attributes, attr);
        !           265:        }
        !           266:        reader->destroy(reader);
        !           267:        return SUCCESS;
        !           268: 
        !           269: err:
        !           270:        reader->destroy(reader);
        !           271:        this->errors->insert_last(this->errors, error);
        !           272:        return VERIFY_ERROR;
        !           273: }
        !           274: 
        !           275: METHOD(pa_tnc_msg_t, process_ietf_std_errors, bool,
        !           276:        private_pa_tnc_msg_t *this, linked_list_t *non_fatal_types)
        !           277: {
        !           278:        enumerator_t *e1, *e2;
        !           279:        enum_name_t *pa_attr_names;
        !           280:        pa_tnc_attr_t *attr;
        !           281:        pen_type_t type, unsupported_type;
        !           282:        uint8_t flags;
        !           283:        bool fatal_error = FALSE;
        !           284: 
        !           285:        e1 = this->attributes->create_enumerator(this->attributes);
        !           286:        while (e1->enumerate(e1, &attr))
        !           287:        {
        !           288:                type = attr->get_type(attr);
        !           289: 
        !           290:                if (type.vendor_id == PEN_IETF && type.type == IETF_ATTR_PA_TNC_ERROR)
        !           291:                {
        !           292:                        ietf_attr_pa_tnc_error_t *error_attr;
        !           293:                        pen_type_t error_code, *non_fatal_type;
        !           294:                        chunk_t msg_info;
        !           295:                        uint32_t offset;
        !           296:                        bool fatal_current_error = TRUE;
        !           297: 
        !           298:                        error_attr = (ietf_attr_pa_tnc_error_t*)attr;
        !           299:                        error_code = error_attr->get_error_code(error_attr);
        !           300:                        msg_info = error_attr->get_msg_info(error_attr);
        !           301: 
        !           302:                        /* skip errors from non-IETF namespaces and non PA-TNC msg errors */
        !           303:                        if (error_code.vendor_id != PEN_IETF ||
        !           304:                                error_code.type > PA_ERROR_PA_TNC_MSG_ROOF)
        !           305:                        {
        !           306:                                continue;
        !           307:                        }
        !           308:                        DBG1(DBG_TNC, "received PA-TNC error '%N' concerning message "
        !           309:                                 "0x%08x/0x%08x", pa_tnc_error_code_names, error_code.type,
        !           310:                                 untoh32(msg_info.ptr), untoh32(msg_info.ptr + 4));
        !           311: 
        !           312:                        switch (error_code.type)
        !           313:                        {
        !           314:                                case PA_ERROR_INVALID_PARAMETER:
        !           315:                                        offset = error_attr->get_offset(error_attr);
        !           316:                                        DBG1(DBG_TNC, "  occurred at offset of %u bytes", offset);
        !           317:                                        break;
        !           318:                                case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
        !           319:                                        unsupported_type =
        !           320:                                                error_attr->get_unsupported_attr(error_attr, &flags);
        !           321:                                        pa_attr_names =
        !           322:                                                imcv_pa_tnc_attributes->get_names(imcv_pa_tnc_attributes,
        !           323:                                                                                                        unsupported_type.vendor_id);
        !           324:                                        if (pa_attr_names)
        !           325:                                        {
        !           326:                                                DBG1(DBG_TNC, "  unsupported attribute type '%N/%N' "
        !           327:                                                         "0x%06x/0x%08x, flags 0x%02x",
        !           328:                                                         pen_names, unsupported_type.vendor_id,
        !           329:                                                         pa_attr_names, unsupported_type.type,
        !           330:                                                         unsupported_type.vendor_id, unsupported_type.type,
        !           331:                                                         flags);
        !           332:                                        }
        !           333:                                        else
        !           334:                                        {
        !           335:                                                DBG1(DBG_TNC, "  unsupported attribute type '%N' "
        !           336:                                                         "0x%06x/0x%08x, flags 0x%02x",
        !           337:                                                         pen_names, unsupported_type.vendor_id,
        !           338:                                                         unsupported_type.vendor_id, unsupported_type.type,
        !           339:                                                         flags);
        !           340:                                        }
        !           341:                                        e2 = non_fatal_types->create_enumerator(non_fatal_types);
        !           342:                                        while (e2->enumerate(e2, &non_fatal_type))
        !           343:                                        {
        !           344:                                                if (pen_type_equals(unsupported_type, *non_fatal_type))
        !           345:                                                {
        !           346:                                                        fatal_current_error = FALSE;
        !           347:                                                        break;
        !           348:                                                }
        !           349:                                        }
        !           350:                                        e2->destroy(e2);
        !           351:                                        break;
        !           352:                                default:
        !           353:                                        break;
        !           354:                        }
        !           355:                        if (fatal_current_error)
        !           356:                        {
        !           357:                                fatal_error = TRUE;
        !           358:                        }
        !           359:                }
        !           360:        }
        !           361:        e1->destroy(e1);
        !           362: 
        !           363:        return fatal_error;
        !           364: }
        !           365: 
        !           366: METHOD(pa_tnc_msg_t, create_attribute_enumerator, enumerator_t*,
        !           367:        private_pa_tnc_msg_t *this)
        !           368: {
        !           369:        return this->attributes->create_enumerator(this->attributes);
        !           370: }
        !           371: 
        !           372: METHOD(pa_tnc_msg_t, create_error_enumerator, enumerator_t*,
        !           373:        private_pa_tnc_msg_t *this)
        !           374: {
        !           375:        return this->errors->create_enumerator(this->errors);
        !           376: }
        !           377: 
        !           378: METHOD(pa_tnc_msg_t, destroy, void,
        !           379:        private_pa_tnc_msg_t *this)
        !           380: {
        !           381:        this->attributes->destroy_offset(this->attributes,
        !           382:                                                                         offsetof(pa_tnc_attr_t, destroy));
        !           383:        this->errors->destroy_offset(this->errors,
        !           384:                                                                         offsetof(pa_tnc_attr_t, destroy));
        !           385:        free(this->encoding.ptr);
        !           386:        free(this);
        !           387: }
        !           388: 
        !           389: /**
        !           390:  * See header
        !           391:  */
        !           392: pa_tnc_msg_t *pa_tnc_msg_create(size_t max_msg_len)
        !           393: {
        !           394:        private_pa_tnc_msg_t *this;
        !           395: 
        !           396:        INIT(this,
        !           397:                .public = {
        !           398:                        .get_encoding = _get_encoding,
        !           399:                        .get_space = _get_space,
        !           400:                        .add_attribute = _add_attribute,
        !           401:                        .build = _build,
        !           402:                        .process = _process,
        !           403:                        .process_ietf_std_errors = _process_ietf_std_errors,
        !           404:                        .create_attribute_enumerator = _create_attribute_enumerator,
        !           405:                        .create_error_enumerator = _create_error_enumerator,
        !           406:                        .destroy = _destroy,
        !           407:                },
        !           408:                .attributes = linked_list_create(),
        !           409:                .errors = linked_list_create(),
        !           410:                .msg_len = PA_TNC_HEADER_SIZE,
        !           411:                .max_msg_len = max_msg_len,
        !           412:        );
        !           413: 
        !           414:        return &this->public;
        !           415: }
        !           416: 
        !           417: /**
        !           418:  * See header
        !           419:  */
        !           420: pa_tnc_msg_t *pa_tnc_msg_create_from_data(chunk_t data)
        !           421: {
        !           422:        private_pa_tnc_msg_t *this;
        !           423: 
        !           424:        INIT(this,
        !           425:                .public = {
        !           426:                        .get_encoding = _get_encoding,
        !           427:                        .get_space = _get_space,
        !           428:                        .add_attribute = _add_attribute,
        !           429:                        .build = _build,
        !           430:                        .process = _process,
        !           431:                        .process_ietf_std_errors = _process_ietf_std_errors,
        !           432:                        .create_attribute_enumerator = _create_attribute_enumerator,
        !           433:                        .create_error_enumerator = _create_error_enumerator,
        !           434:                        .destroy = _destroy,
        !           435:                },
        !           436:                .encoding = chunk_clone(data),
        !           437:                .attributes = linked_list_create(),
        !           438:                .errors = linked_list_create(),
        !           439:                .from_data = TRUE,
        !           440:        );
        !           441: 
        !           442:        return &this->public;
        !           443: }
        !           444: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>