Annotation of embedaddon/strongswan/src/libimcv/pa_tnc/pa_tnc_msg.c, revision 1.1.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>