Annotation of embedaddon/strongswan/src/libimcv/seg/seg_contract.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2014-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 "seg_contract.h"
        !            17: #include "seg_env.h"
        !            18: #include "ietf/ietf_attr_pa_tnc_error.h"
        !            19: #include "tcg/seg/tcg_seg_attr_seg_env.h"
        !            20: 
        !            21: #include <utils/debug.h>
        !            22: #include <bio/bio_writer.h>
        !            23: 
        !            24: #include <tncif_pa_subtypes.h>
        !            25: 
        !            26: typedef struct private_seg_contract_t private_seg_contract_t;
        !            27: 
        !            28: /**
        !            29:  * Private data of a seg_contract_t object.
        !            30:  */
        !            31: struct private_seg_contract_t {
        !            32: 
        !            33:        /**
        !            34:         * Public seg_contract_t interface.
        !            35:         */
        !            36:        seg_contract_t public;
        !            37: 
        !            38:        /**
        !            39:         * PA-TNC message type
        !            40:         */
        !            41:        pen_type_t msg_type;
        !            42: 
        !            43:        /**
        !            44:         * Maximum PA-TNC attribute size
        !            45:         */
        !            46:        uint32_t max_attr_size;
        !            47: 
        !            48:        /**
        !            49:         * Maximum PA-TNC attribute segment size
        !            50:         */
        !            51:        uint32_t max_seg_size;
        !            52: 
        !            53:        /**
        !            54:         * Maximum PA-TNC attribute segment size
        !            55:         */
        !            56:        uint32_t last_base_attr_id;
        !            57: 
        !            58:        /**
        !            59:         * List of attribute segment envelopes
        !            60:         */
        !            61: 
        !            62:        linked_list_t *seg_envs;
        !            63: 
        !            64:        /**
        !            65:         * Is this a null contract?
        !            66:         */
        !            67:        bool is_null;
        !            68: 
        !            69:        /**
        !            70:         * Contract role
        !            71:         */
        !            72:        bool is_issuer;
        !            73: 
        !            74:        /**
        !            75:         * Issuer ID (either IMV or IMC ID)
        !            76:         */
        !            77:        TNC_UInt32 issuer_id;
        !            78: 
        !            79:        /**
        !            80:         * Responder ID (either IMC or IMV ID)
        !            81:         */
        !            82:        TNC_UInt32 responder_id;
        !            83: 
        !            84:        /**
        !            85:         * IMC/IMV role
        !            86:         */
        !            87:        bool is_imc;
        !            88: 
        !            89: };
        !            90: 
        !            91: METHOD(seg_contract_t, get_msg_type, pen_type_t,
        !            92:        private_seg_contract_t *this)
        !            93: {
        !            94:        return this->msg_type;
        !            95: }
        !            96: 
        !            97: METHOD(seg_contract_t, set_max_size, void,
        !            98:        private_seg_contract_t *this, uint32_t max_attr_size, uint32_t max_seg_size)
        !            99: {
        !           100:        this->max_attr_size = max_attr_size;
        !           101:        this->max_seg_size = max_seg_size;
        !           102:        this->is_null = max_attr_size == SEG_CONTRACT_MAX_SIZE_VALUE &&
        !           103:                                        max_seg_size  == SEG_CONTRACT_MAX_SIZE_VALUE;
        !           104: }
        !           105: 
        !           106: METHOD(seg_contract_t, get_max_size, void,
        !           107:        private_seg_contract_t *this, uint32_t *max_attr_size, uint32_t *max_seg_size)
        !           108: {
        !           109:        if (max_attr_size)
        !           110:        {
        !           111:                *max_attr_size = this->max_attr_size;
        !           112:        }
        !           113:        if (max_seg_size)
        !           114:        {
        !           115:                *max_seg_size = this->max_seg_size;
        !           116:        }
        !           117: }
        !           118: 
        !           119: METHOD(seg_contract_t, check_size, bool,
        !           120:        private_seg_contract_t *this, pa_tnc_attr_t *attr, bool *oversize)
        !           121: {
        !           122:        chunk_t attr_value;
        !           123:        size_t attr_len;
        !           124: 
        !           125:        *oversize = FALSE;
        !           126: 
        !           127:        if (this->is_null)
        !           128:        {
        !           129:                /* null segmentation contract */
        !           130:                return FALSE;
        !           131:        }
        !           132:        attr->build(attr);
        !           133:        attr_value = attr->get_value(attr);
        !           134:        attr_len = PA_TNC_ATTR_HEADER_SIZE + attr_value.len;
        !           135: 
        !           136:        if (attr_len > this->max_attr_size)
        !           137:        {
        !           138:                /* oversize attribute */
        !           139:                *oversize = TRUE;
        !           140:                return FALSE;
        !           141:        }
        !           142:        if (this->max_seg_size == SEG_CONTRACT_NO_FRAGMENTATION)
        !           143:        {
        !           144:                /* no fragmentation wanted */
        !           145:                return FALSE;
        !           146:        }
        !           147:        return attr_value.len > this->max_seg_size + TCG_SEG_ATTR_SEG_ENV_HEADER;
        !           148: }
        !           149: 
        !           150: METHOD(seg_contract_t, first_segment, pa_tnc_attr_t*,
        !           151:        private_seg_contract_t *this, pa_tnc_attr_t *attr, size_t max_attr_len)
        !           152: {
        !           153:        seg_env_t *seg_env;
        !           154: 
        !           155:        seg_env = seg_env_create(++this->last_base_attr_id, attr,
        !           156:                                                         this->max_seg_size);
        !           157:        if (!seg_env)
        !           158:        {
        !           159:                return NULL;
        !           160:        }
        !           161:        this->seg_envs->insert_last(this->seg_envs, seg_env);
        !           162: 
        !           163:        return seg_env->first_segment(seg_env, max_attr_len);
        !           164: }
        !           165: 
        !           166: METHOD(seg_contract_t, next_segment, pa_tnc_attr_t*,
        !           167:        private_seg_contract_t *this, uint32_t base_attr_id)
        !           168: {
        !           169:        pa_tnc_attr_t *seg_env_attr = NULL;
        !           170:        seg_env_t *seg_env;
        !           171:        bool last_segment = FALSE;
        !           172:        enumerator_t *enumerator;
        !           173: 
        !           174:        enumerator = this->seg_envs->create_enumerator(this->seg_envs);
        !           175:        while (enumerator->enumerate(enumerator, &seg_env))
        !           176:        {
        !           177:                if (seg_env->get_base_attr_id(seg_env) == base_attr_id)
        !           178:                {
        !           179:                        seg_env_attr = seg_env->next_segment(seg_env, &last_segment);
        !           180:                        if (!seg_env_attr)
        !           181:                        {
        !           182:                                break;
        !           183:                        }
        !           184:                        if (last_segment)
        !           185:                        {
        !           186:                                this->seg_envs->remove_at(this->seg_envs, enumerator);
        !           187:                                seg_env->destroy(seg_env);
        !           188:                        }
        !           189:                        break;
        !           190:                }
        !           191:        }
        !           192:        enumerator->destroy(enumerator);
        !           193: 
        !           194:        return seg_env_attr;
        !           195: }
        !           196: 
        !           197: METHOD(seg_contract_t, add_segment, pa_tnc_attr_t*,
        !           198:        private_seg_contract_t *this, pa_tnc_attr_t *attr, pa_tnc_attr_t **error,
        !           199:        bool *more)
        !           200: {
        !           201:        tcg_seg_attr_seg_env_t *seg_env_attr;
        !           202:        seg_env_t *current, *seg_env = NULL;
        !           203:        pa_tnc_attr_t *base_attr;
        !           204:        pen_type_t error_code;
        !           205:        uint32_t base_attr_id;
        !           206:        uint8_t flags;
        !           207:        chunk_t segment_data, msg_info;
        !           208:        enumerator_t *enumerator;
        !           209: 
        !           210:        seg_env_attr = (tcg_seg_attr_seg_env_t*)attr;
        !           211:        base_attr_id = seg_env_attr->get_base_attr_id(seg_env_attr);
        !           212:        segment_data = seg_env_attr->get_segment(seg_env_attr, &flags);
        !           213:        *more = flags & SEG_ENV_FLAG_MORE;
        !           214:        *error = NULL;
        !           215: 
        !           216:        enumerator = this->seg_envs->create_enumerator(this->seg_envs);
        !           217:        while (enumerator->enumerate(enumerator, &current))
        !           218:        {
        !           219:                if (current->get_base_attr_id(current) == base_attr_id)
        !           220:                {
        !           221:                        seg_env = current;
        !           222:                        this->seg_envs->remove_at(this->seg_envs, enumerator);
        !           223:                        break;
        !           224:                }
        !           225:        }
        !           226:        enumerator->destroy(enumerator);
        !           227: 
        !           228:        if (flags & SEG_ENV_FLAG_START)
        !           229:        {
        !           230:                if (seg_env)
        !           231:                {
        !           232:                        DBG1(DBG_TNC, "base attribute ID %d is already in use",
        !           233:                                                   base_attr_id);
        !           234:                        this->seg_envs->insert_last(this->seg_envs, seg_env);
        !           235:                        return NULL;
        !           236:                }
        !           237:                DBG2(DBG_TNC, "received first segment for base attribute ID %d "
        !           238:                                          "(%d bytes)", base_attr_id, segment_data.len);
        !           239:                seg_env = seg_env_create_from_data(base_attr_id, segment_data,
        !           240:                                                                                   this->max_seg_size, error);
        !           241:                if (!seg_env)
        !           242:                {
        !           243:                        return NULL;
        !           244:                }
        !           245:        }
        !           246:        else
        !           247:        {
        !           248:                if (!seg_env)
        !           249:                {
        !           250:                        DBG1(DBG_TNC, "base attribute ID %d not found", base_attr_id);
        !           251:                        return NULL;
        !           252:                }
        !           253:                DBG2(DBG_TNC, "received %s segment for base attribute ID %d "
        !           254:                                          "(%d bytes)", (*more) ? "next" : "last", base_attr_id,
        !           255:                                           segment_data.len);
        !           256:                if (!seg_env->add_segment(seg_env, segment_data, error))
        !           257:                {
        !           258:                        seg_env->destroy(seg_env);
        !           259:                        return NULL;
        !           260:                }
        !           261:        }
        !           262:        base_attr = seg_env->get_base_attr(seg_env);
        !           263: 
        !           264:        if (*more)
        !           265:        {
        !           266:                /* reinsert into list since more segments are to come */
        !           267:                this->seg_envs->insert_last(this->seg_envs, seg_env);
        !           268:        }
        !           269:        else
        !           270:        {
        !           271:                /* added the last segment */
        !           272:                if (!base_attr)
        !           273:                {
        !           274:                        /* base attribute waits for more data */
        !           275:                        DBG1(DBG_TNC, "insufficient bytes for PA-TNC attribute value");
        !           276:                        msg_info = seg_env->get_base_attr_info(seg_env);
        !           277:                        error_code = pen_type_create(PEN_IETF, PA_ERROR_INVALID_PARAMETER);
        !           278:                        *error = ietf_attr_pa_tnc_error_create_with_offset(error_code,
        !           279:                                                                                msg_info, PA_TNC_ATTR_INFO_SIZE);
        !           280:                }
        !           281:                seg_env->destroy(seg_env);
        !           282:        }
        !           283:        return base_attr;
        !           284: }
        !           285: 
        !           286: METHOD(seg_contract_t, is_issuer, bool,
        !           287:        private_seg_contract_t *this)
        !           288: {
        !           289:        return this->is_issuer;
        !           290: }
        !           291: 
        !           292: METHOD(seg_contract_t, is_null, bool,
        !           293:        private_seg_contract_t *this)
        !           294: {
        !           295:        return this->is_null;
        !           296: }
        !           297: 
        !           298: METHOD(seg_contract_t, set_responder, void,
        !           299:        private_seg_contract_t *this, TNC_UInt32 responder_id)
        !           300: {
        !           301:        this->responder_id = responder_id;
        !           302: }
        !           303: 
        !           304: METHOD(seg_contract_t, get_responder, TNC_UInt32,
        !           305:        private_seg_contract_t *this)
        !           306: {
        !           307:        return this->responder_id;
        !           308: }
        !           309: 
        !           310: METHOD(seg_contract_t, get_issuer, TNC_UInt32,
        !           311:        private_seg_contract_t *this)
        !           312: {
        !           313:        return this->issuer_id;
        !           314: }
        !           315: 
        !           316: METHOD(seg_contract_t, clone_, seg_contract_t*,
        !           317:        private_seg_contract_t *this)
        !           318: {
        !           319:        private_seg_contract_t *clone;
        !           320: 
        !           321:        clone = malloc_thing(private_seg_contract_t);
        !           322:        memcpy(clone, this, sizeof(private_seg_contract_t));
        !           323:        clone->seg_envs = linked_list_create();
        !           324: 
        !           325:        return &clone->public;
        !           326: }
        !           327: 
        !           328: METHOD(seg_contract_t, get_info_string, void,
        !           329:        private_seg_contract_t *this, char *buf, size_t len, bool request)
        !           330: {
        !           331:        enum_name_t *pa_subtype_names;
        !           332:        uint32_t msg_vid, msg_subtype;
        !           333:        char *pos = buf;
        !           334:        int written;
        !           335: 
        !           336:        /* nul-terminate the string buffer */
        !           337:        buf[--len] = '\0';
        !           338: 
        !           339:        if (this->is_issuer && request)
        !           340:        {
        !           341:                written = snprintf(pos, len, "%s %lu requests",
        !           342:                                                  this->is_imc ? "IMC" : "IMV", this->issuer_id);
        !           343:        }
        !           344:        else
        !           345:        {
        !           346:                written = snprintf(pos, len, "%s %lu received",
        !           347:                                                   this->is_imc ? "IMC" : "IMV",
        !           348:                                                   this->is_issuer ? this->issuer_id :
        !           349:                                                                                         this->responder_id);
        !           350:        }
        !           351:        if (written < 0 || written > len)
        !           352:        {
        !           353:                return;
        !           354:        }
        !           355:        pos += written;
        !           356:        len -= written;
        !           357: 
        !           358:        written = snprintf(pos, len, " a %ssegmentation contract%s ",
        !           359:                                           this->is_null ? "null" : "", request ?
        !           360:                                          (this->is_issuer ? "" : " request") : " response");
        !           361:        if (written < 0 || written > len)
        !           362:        {
        !           363:                return;
        !           364:        }
        !           365:        pos += written;
        !           366:        len -= written;
        !           367: 
        !           368:        if ((!this->is_issuer && this->issuer_id != TNC_IMVID_ANY) ||
        !           369:                ( this->is_issuer && this->responder_id != TNC_IMVID_ANY))
        !           370:        {
        !           371:                written = snprintf(pos, len, "from %s %lu ",
        !           372:                                                   this->is_imc ? "IMV" : "IMC",
        !           373:                                                   this->is_issuer ? this->responder_id :
        !           374:                                                                                         this->issuer_id);
        !           375:                if (written < 0 || written > len)
        !           376:                {
        !           377:                        return;
        !           378:                }
        !           379:                pos += written;
        !           380:                len -= written;
        !           381:        }
        !           382: 
        !           383:        msg_vid     = this->msg_type.vendor_id;
        !           384:        msg_subtype = this->msg_type.type;
        !           385:        pa_subtype_names = get_pa_subtype_names(msg_vid);
        !           386:        if (pa_subtype_names)
        !           387:        {
        !           388:                written = snprintf(pos, len, "for PA message type '%N/%N' "
        !           389:                                                   "0x%06x/0x%08x", pen_names, msg_vid,
        !           390:                                                   pa_subtype_names, msg_subtype, msg_vid,
        !           391:                                                   msg_subtype);
        !           392:        }
        !           393:        else
        !           394:        {
        !           395:                written = snprintf(pos, len, "for PA message type '%N' "
        !           396:                                                   "0x%06x/0x%08x", pen_names, msg_vid,
        !           397:                                                   msg_vid, msg_subtype);
        !           398:        }
        !           399:        if (written < 0 || written > len)
        !           400:        {
        !           401:                return;
        !           402:        }
        !           403:        pos += written;
        !           404:        len -= written;
        !           405: 
        !           406:        if (!this->is_null)
        !           407:        {
        !           408:                written = snprintf(pos, len, "\n  maximum attribute size of %u bytes "
        !           409:                                                   "with ", this->max_attr_size);
        !           410:                if (written < 0 || written > len)
        !           411:                {
        !           412:                        return;
        !           413:                }
        !           414:                pos += written;
        !           415:                len -= written;
        !           416: 
        !           417:                if (this->max_seg_size == SEG_CONTRACT_MAX_SIZE_VALUE)
        !           418:                {
        !           419:                        written = snprintf(pos, len, "no segmentation");
        !           420:                }
        !           421:                else
        !           422:                {
        !           423:                        written = snprintf(pos, len, "maximum segment size of %u bytes",
        !           424:                                                           this->max_seg_size);
        !           425:                }
        !           426:        }
        !           427: }
        !           428: 
        !           429: METHOD(seg_contract_t, destroy, void,
        !           430:        private_seg_contract_t *this)
        !           431: {
        !           432:        this->seg_envs->destroy_offset(this->seg_envs, offsetof(seg_env_t, destroy));
        !           433:        free(this);
        !           434: }
        !           435: 
        !           436: /**
        !           437:  * See header
        !           438:  */
        !           439: seg_contract_t *seg_contract_create(pen_type_t msg_type,
        !           440:                                                                    uint32_t max_attr_size,
        !           441:                                                                        uint32_t max_seg_size,
        !           442:                                                                        bool is_issuer, TNC_UInt32 issuer_id,
        !           443:                                                                        bool is_imc)
        !           444: {
        !           445:        private_seg_contract_t *this;
        !           446: 
        !           447:        INIT(this,
        !           448:                .public = {
        !           449:                        .get_msg_type = _get_msg_type,
        !           450:                        .set_max_size = _set_max_size,
        !           451:                        .get_max_size = _get_max_size,
        !           452:                        .check_size = _check_size,
        !           453:                        .first_segment = _first_segment,
        !           454:                        .next_segment = _next_segment,
        !           455:                        .add_segment = _add_segment,
        !           456:                        .is_issuer = _is_issuer,
        !           457:                        .is_null = _is_null,
        !           458:                        .set_responder = _set_responder,
        !           459:                        .get_responder = _get_responder,
        !           460:                        .get_issuer = _get_issuer,
        !           461:                        .clone = _clone_,
        !           462:                        .get_info_string = _get_info_string,
        !           463:                        .destroy = _destroy,
        !           464:                },
        !           465:                .msg_type = msg_type,
        !           466:                .max_attr_size = max_attr_size,
        !           467:                .max_seg_size = max_seg_size,
        !           468:                .seg_envs = linked_list_create(),
        !           469:                .is_issuer = is_issuer,
        !           470:                .issuer_id = issuer_id,
        !           471:                .responder_id = is_imc ? TNC_IMVID_ANY : TNC_IMCID_ANY,
        !           472:                .is_imc = is_imc,
        !           473:                .is_null = max_attr_size == SEG_CONTRACT_MAX_SIZE_VALUE &&
        !           474:                                   max_seg_size  == SEG_CONTRACT_MAX_SIZE_VALUE,
        !           475:        );
        !           476: 
        !           477:        return &this->public;
        !           478: }
        !           479: 

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