Annotation of embedaddon/strongswan/src/libtnccs/plugins/tnccs_20/tnccs_20.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2010 Sansar Choinyambuu
        !             3:  * Copyright (C) 2010-2015 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 "tnccs_20.h"
        !            18: #include "tnccs_20_handler.h"
        !            19: #include "tnccs_20_server.h"
        !            20: #include "tnccs_20_client.h"
        !            21: #include "batch/pb_tnc_batch.h"
        !            22: #include "messages/pb_tnc_msg.h"
        !            23: #include "messages/ietf/pb_pa_msg.h"
        !            24: 
        !            25: #include <tncif_names.h>
        !            26: #include <tncif_pa_subtypes.h>
        !            27: 
        !            28: #include <utils/debug.h>
        !            29: 
        !            30: typedef struct private_tnccs_20_t private_tnccs_20_t;
        !            31: 
        !            32: /**
        !            33:  * Private data of a tnccs_20_t object.
        !            34:  */
        !            35: struct private_tnccs_20_t {
        !            36: 
        !            37:        /**
        !            38:         * Public tnccs_t interface.
        !            39:         */
        !            40:        tnccs_t public;
        !            41: 
        !            42:        /**
        !            43:         * TNCC if TRUE, TNCS if FALSE
        !            44:         */
        !            45:        bool is_server;
        !            46: 
        !            47:        /**
        !            48:         * Server identity
        !            49:         */
        !            50:        identification_t *server_id;
        !            51: 
        !            52:        /**
        !            53:         * Client identity
        !            54:         */
        !            55:        identification_t *peer_id;
        !            56: 
        !            57:        /**
        !            58:         * Server IP address
        !            59:         */
        !            60:        host_t *server_ip;
        !            61: 
        !            62:        /**
        !            63:         * Client IP address
        !            64:         */
        !            65:        host_t *peer_ip;
        !            66: 
        !            67:        /**
        !            68:         * Underlying TNC IF-T transport protocol
        !            69:         */
        !            70:        tnc_ift_type_t transport;
        !            71: 
        !            72:        /**
        !            73:         *  TNC IF-T transport protocol for EAP methods
        !            74:         */
        !            75:        bool eap_transport;
        !            76: 
        !            77:        /**
        !            78:         * Type of TNC client authentication
        !            79:         */
        !            80:        uint32_t auth_type;
        !            81: 
        !            82:        /**
        !            83:         * Mutual PB-TNC protocol enabled
        !            84:         */
        !            85:        bool mutual;
        !            86: 
        !            87:        /**
        !            88:         * Direction the next batch will go to
        !            89:         */
        !            90:        bool to_server;
        !            91: 
        !            92:        /**
        !            93:         * TNC Server
        !            94:         */
        !            95:        tnccs_20_handler_t *tnc_server;
        !            96: 
        !            97:        /**
        !            98:         * TNC Client
        !            99:         */
        !           100:        tnccs_20_handler_t *tnc_client;
        !           101: 
        !           102:        /**
        !           103:         * Active TNCSS handler
        !           104:         */
        !           105:        tnccs_20_handler_t *tnccs_handler;
        !           106: 
        !           107:        /**
        !           108:         * Maximum PB-TNC batch size
        !           109:         */
        !           110:        size_t max_batch_len;
        !           111: 
        !           112:        /**
        !           113:         * Maximum PA-TNC message size
        !           114:         */
        !           115:        size_t max_msg_len;
        !           116: 
        !           117:        /**
        !           118:         * Callback function to communicate recommendation (TNC Server only)
        !           119:         */
        !           120:        tnccs_cb_t callback;
        !           121: 
        !           122:        /**
        !           123:         * reference count
        !           124:         */
        !           125:        refcount_t ref;
        !           126: 
        !           127: };
        !           128: 
        !           129: METHOD(tls_t, is_complete, bool,
        !           130:        private_tnccs_20_t *this)
        !           131: {
        !           132:        TNC_IMV_Action_Recommendation rec;
        !           133:        TNC_IMV_Evaluation_Result eval;
        !           134:        tnccs_20_server_t *tnc_server;
        !           135: 
        !           136:        if (this->tnc_server)
        !           137:        {
        !           138:                tnc_server = (tnccs_20_server_t*)this->tnc_server;
        !           139:                if (tnc_server->have_recommendation(tnc_server, &rec, &eval))
        !           140:                {
        !           141:                        return this->callback ? this->callback(rec, eval) : TRUE;
        !           142:                }
        !           143:        }
        !           144:        return FALSE;
        !           145: }
        !           146: 
        !           147: METHOD(tnccs_t, send_msg, TNC_Result,
        !           148:        private_tnccs_20_t* this, TNC_IMCID imc_id, TNC_IMVID imv_id,
        !           149:                                                          TNC_UInt32 msg_flags,
        !           150:                                                          TNC_BufferReference msg,
        !           151:                                                          TNC_UInt32 msg_len,
        !           152:                                                          TNC_VendorID msg_vid,
        !           153:                                                          TNC_MessageSubtype msg_subtype)
        !           154: {
        !           155:        pb_tnc_msg_t *pb_tnc_msg;
        !           156:        enum_name_t *pa_subtype_names;
        !           157:        bool excl;
        !           158: 
        !           159:        if (!this->tnccs_handler->get_send_flag(this->tnccs_handler))
        !           160:        {
        !           161:                DBG1(DBG_TNC, "%s %u not allowed to call SendMessage()",
        !           162:                                           this->to_server ? "IMC" : "IMV",
        !           163:                                           this->to_server ? imc_id : imv_id);
        !           164: 
        !           165:                return TNC_RESULT_ILLEGAL_OPERATION;
        !           166:        }
        !           167:        excl = (msg_flags & TNC_MESSAGE_FLAGS_EXCLUSIVE) != 0;
        !           168: 
        !           169:        pb_tnc_msg = pb_pa_msg_create(msg_vid, msg_subtype, imc_id, imv_id,
        !           170:                                                                  excl, chunk_create(msg, msg_len));
        !           171: 
        !           172:        pa_subtype_names = get_pa_subtype_names(msg_vid);
        !           173:        if (pa_subtype_names)
        !           174:        {
        !           175:                DBG2(DBG_TNC, "creating PB-PA message type '%N/%N' 0x%06x/0x%08x",
        !           176:                                           pen_names, msg_vid, pa_subtype_names, msg_subtype,
        !           177:                                           msg_vid, msg_subtype);
        !           178:        }
        !           179:        else
        !           180:        {
        !           181:                DBG2(DBG_TNC, "creating PB-PA message type '%N' 0x%06x/0x%08x",
        !           182:                                           pen_names, msg_vid, msg_vid, msg_subtype);
        !           183:        }
        !           184:        this->tnccs_handler->add_msg(this->tnccs_handler, pb_tnc_msg);
        !           185: 
        !           186:        return TNC_RESULT_SUCCESS;
        !           187: }
        !           188: 
        !           189: METHOD(tls_t, process, status_t,
        !           190:        private_tnccs_20_t *this, void *buf, size_t buflen)
        !           191: {
        !           192:        pb_tnc_batch_t *batch;
        !           193:        bool from_server, fatal_header_error = FALSE;
        !           194:        status_t status;
        !           195:        chunk_t data;
        !           196: 
        !           197:        /* On arrival of first batch from TNC client create TNC server */
        !           198:        if (this->is_server && !this->tnc_server)
        !           199:        {
        !           200:                this->tnc_server = tnccs_20_server_create(&this->public, _send_msg,
        !           201:                                                                        this->max_batch_len, this->max_msg_len,
        !           202:                                                                        this->eap_transport);
        !           203:                if (!this->tnc_server)
        !           204:                {
        !           205:                        return FAILED;
        !           206:                }
        !           207:                this->tnccs_handler = this->tnc_server;
        !           208:                this->tnccs_handler->begin_handshake(this->tnccs_handler, FALSE);
        !           209:        }
        !           210: 
        !           211:        data = chunk_create(buf, buflen);
        !           212:        DBG1(DBG_TNC, "received TNCCS batch (%u bytes)", data.len);
        !           213:        DBG3(DBG_TNC, "%B", &data);
        !           214: 
        !           215:        /* Parse the header of the received PB-TNC batch */
        !           216:        batch = pb_tnc_batch_create_from_data(data);
        !           217:        status = batch->process_header(batch, !this->mutual, this->is_server,
        !           218:                                                                   &from_server);
        !           219:        if (status == FAILED)
        !           220:        {
        !           221:                fatal_header_error = TRUE;
        !           222:                status = VERIFY_ERROR;
        !           223:        }
        !           224:        this->to_server = this->mutual ? from_server : !this->is_server;
        !           225: 
        !           226:        /* In the mutual case, first batch from TNC server requires a TNC client */
        !           227:        if (this->to_server && !this->tnc_client)
        !           228:        {
        !           229:                this->tnc_client = tnccs_20_client_create(&this->public, _send_msg,
        !           230:                                                                        this->max_batch_len, this->max_msg_len);
        !           231:                if (!this->tnc_client)
        !           232:                {
        !           233:                        batch->destroy(batch);
        !           234:                        return FAILED;
        !           235:                }
        !           236:                this->tnccs_handler = this->tnc_client;
        !           237:                this->tnccs_handler->begin_handshake(this->tnccs_handler, this->mutual);
        !           238:        }
        !           239:        else
        !           240:        {
        !           241:                /* Set active TNCCS handler for processing */
        !           242:                this->tnccs_handler = this->to_server ? this->tnc_client :
        !           243:                                                                                                this->tnc_server;
        !           244:        }
        !           245:        DBG2(DBG_TNC, "TNC %s is handling inbound connection",
        !           246:                                   this->to_server ? "client" : "server");
        !           247: 
        !           248:        if (status == SUCCESS)
        !           249:        {
        !           250:                status = this->tnccs_handler->process(this->tnccs_handler, batch);
        !           251:        }
        !           252:        if (status == VERIFY_ERROR)
        !           253:        {
        !           254:                this->tnccs_handler->handle_errors(this->tnccs_handler, batch,
        !           255:                                                                                   fatal_header_error);
        !           256:                status = NEED_MORE;
        !           257:        }
        !           258:        batch->destroy(batch);
        !           259: 
        !           260:        /* Has a mutual connection been established? */
        !           261:        this->mutual = this->is_server ?
        !           262:                                   this->tnc_server->get_mutual(this->tnc_server) :
        !           263:                                   this->tnc_client->get_mutual(this->tnc_client);
        !           264: 
        !           265:        if (this->mutual && !this->is_server)
        !           266:        {
        !           267:                pb_tnc_state_t client_state, server_state;
        !           268: 
        !           269:                client_state = !this->tnc_client ? PB_STATE_INIT :
        !           270:                                                this->tnc_client->get_state(this->tnc_client);
        !           271:                server_state = !this->tnc_server ? PB_STATE_INIT :
        !           272:                                                this->tnc_server->get_state(this->tnc_server);
        !           273: 
        !           274:                /* In half-duplex mutual mode toggle the direction on the client side */
        !           275:                if ((!this->to_server && client_state != PB_STATE_DECIDED) ||
        !           276:                        ( this->to_server && server_state != PB_STATE_END))
        !           277:                {
        !           278:                        this->to_server = !this->to_server;
        !           279:                }
        !           280:                else if (client_state == PB_STATE_DECIDED &&
        !           281:                                 server_state == PB_STATE_END)
        !           282:                {
        !           283:                        /* Cause the final CLOSE batch to be sent to the TNC server */
        !           284:                        this->to_server = TRUE;
        !           285:                }
        !           286: 
        !           287:                /* Suppress a successful CLOSE batch coming from the TNC server */
        !           288:                if (status == SUCCESS)
        !           289:                {
        !           290:                        is_complete(this);
        !           291:                        status = NEED_MORE;
        !           292:                }
        !           293:        }
        !           294: 
        !           295:        return status;
        !           296: }
        !           297: 
        !           298: METHOD(tls_t, build, status_t,
        !           299:        private_tnccs_20_t *this, void *buf, size_t *buflen, size_t *msglen)
        !           300: {
        !           301:        if (this->to_server)
        !           302:        {
        !           303:                DBG2(DBG_TNC, "TNC client is handling outbound connection");
        !           304: 
        !           305:                /* Before sending the first PB-TNC batch create TNC client */
        !           306:                if (this->tnc_client)
        !           307:                {
        !           308:                        this->tnccs_handler = this->tnc_client;
        !           309:                }
        !           310:                else
        !           311:                {
        !           312:                        this->tnc_client = tnccs_20_client_create(&this->public, _send_msg,
        !           313:                                                                                                          this->max_batch_len,
        !           314:                                                                                                          this->max_msg_len);
        !           315:                        if (!this->tnc_client)
        !           316:                        {
        !           317:                                return FAILED;
        !           318:                        }
        !           319:                        this->tnccs_handler = this->tnc_client;
        !           320:                        this->tnccs_handler->begin_handshake(this->tnccs_handler,
        !           321:                                                                                                 this->mutual);
        !           322:                }
        !           323:        }
        !           324:        else
        !           325:        {
        !           326:                DBG2(DBG_TNC, "TNC server is handling outbound connection");
        !           327: 
        !           328:                /* Before sending the first PB-TNC batch create TNC server */
        !           329:                if (this->tnc_server)
        !           330:                {
        !           331:                        this->tnccs_handler = this->tnc_server;
        !           332:                }
        !           333:                else
        !           334:                {
        !           335:                        this->tnc_server = tnccs_20_server_create(&this->public, _send_msg,
        !           336:                                                                                this->max_batch_len, this->max_msg_len,
        !           337:                                                                                this->eap_transport);
        !           338:                        if (!this->tnc_server)
        !           339:                        {
        !           340:                                return FAILED;
        !           341:                        }
        !           342:                        this->tnccs_handler = this->tnc_server;
        !           343:                        this->tnccs_handler->begin_handshake(this->tnccs_handler,
        !           344:                                                                                                 this->mutual);
        !           345:                }
        !           346:        }
        !           347:        return this->tnccs_handler->build(this->tnccs_handler, buf, buflen, msglen);
        !           348: }
        !           349: 
        !           350: METHOD(tls_t, is_server, bool,
        !           351:        private_tnccs_20_t *this)
        !           352: {
        !           353:        return this->is_server;
        !           354: }
        !           355: 
        !           356: METHOD(tls_t, get_server_id, identification_t*,
        !           357:        private_tnccs_20_t *this)
        !           358: {
        !           359:        return this->server_id;
        !           360: }
        !           361: 
        !           362: METHOD(tls_t, set_peer_id, void,
        !           363:        private_tnccs_20_t *this, identification_t *id)
        !           364: {
        !           365:        DESTROY_IF(this->peer_id);
        !           366:        this->peer_id = id->clone(id);
        !           367: }
        !           368: 
        !           369: METHOD(tls_t, get_peer_id, identification_t*,
        !           370:        private_tnccs_20_t *this)
        !           371: {
        !           372:        return this->peer_id;
        !           373: }
        !           374: 
        !           375: METHOD(tls_t, get_purpose, tls_purpose_t,
        !           376:        private_tnccs_20_t *this)
        !           377: {
        !           378:        return TLS_PURPOSE_EAP_TNC;
        !           379: }
        !           380: 
        !           381: METHOD(tls_t, get_eap_msk, chunk_t,
        !           382:        private_tnccs_20_t *this)
        !           383: {
        !           384:        return chunk_empty;
        !           385: }
        !           386: 
        !           387: METHOD(tls_t, destroy, void,
        !           388:        private_tnccs_20_t *this)
        !           389: {
        !           390:        if (ref_put(&this->ref))
        !           391:        {
        !           392:                DESTROY_IF(this->tnc_server);
        !           393:                DESTROY_IF(this->tnc_client);
        !           394:                this->server_id->destroy(this->server_id);
        !           395:                this->peer_id->destroy(this->peer_id);
        !           396:                this->server_ip->destroy(this->server_ip);
        !           397:                this->peer_ip->destroy(this->peer_ip);
        !           398:                free(this);
        !           399:        }
        !           400: }
        !           401: 
        !           402: METHOD(tnccs_t, get_server_ip, host_t*,
        !           403:        private_tnccs_20_t *this)
        !           404: {
        !           405:        return this->server_ip;
        !           406: }
        !           407: 
        !           408: METHOD(tnccs_t, get_peer_ip, host_t*,
        !           409:        private_tnccs_20_t *this)
        !           410: {
        !           411:        return this->peer_ip;
        !           412: }
        !           413: 
        !           414: METHOD(tnccs_t, get_transport, tnc_ift_type_t,
        !           415:        private_tnccs_20_t *this)
        !           416: {
        !           417:        return this->transport;
        !           418: }
        !           419: 
        !           420: METHOD(tnccs_t, set_transport, void,
        !           421:        private_tnccs_20_t *this, tnc_ift_type_t transport)
        !           422: {
        !           423:        this->transport = transport;
        !           424: }
        !           425: 
        !           426: METHOD(tnccs_t, get_auth_type, uint32_t,
        !           427:        private_tnccs_20_t *this)
        !           428: {
        !           429:        return this->auth_type;
        !           430: }
        !           431: 
        !           432: METHOD(tnccs_t, set_auth_type, void,
        !           433:        private_tnccs_20_t *this, uint32_t auth_type)
        !           434: {
        !           435:        this->auth_type = auth_type;
        !           436: }
        !           437: 
        !           438: METHOD(tnccs_t, get_pdp_server, chunk_t,
        !           439:        private_tnccs_20_t *this, uint16_t *port)
        !           440: {
        !           441:        if (this->tnc_client)
        !           442:        {
        !           443:                tnccs_20_client_t *tnc_client;
        !           444: 
        !           445:                tnc_client = (tnccs_20_client_t*)this->tnc_client;
        !           446: 
        !           447:                return tnc_client->get_pdp_server(tnc_client, port);
        !           448:        }
        !           449:        else
        !           450:        {
        !           451:                *port = 0;
        !           452:                return chunk_empty;
        !           453:        }
        !           454: }
        !           455: 
        !           456: METHOD(tnccs_t, get_ref, tnccs_t*,
        !           457:        private_tnccs_20_t *this)
        !           458: {
        !           459:        ref_get(&this->ref);
        !           460:        return &this->public;
        !           461: }
        !           462: 
        !           463: /**
        !           464:  * See header
        !           465:  */
        !           466: tnccs_t* tnccs_20_create(bool is_server, identification_t *server_id,
        !           467:                                                 identification_t *peer_id, host_t *server_ip,
        !           468:                                                 host_t *peer_ip, tnc_ift_type_t transport,
        !           469:                                                 tnccs_cb_t cb)
        !           470: {
        !           471:        private_tnccs_20_t *this;
        !           472:        size_t max_batch_size, default_max_batch_size;
        !           473:        size_t max_message_size, default_max_message_size;
        !           474: 
        !           475:        /* Determine the maximum PB-TNC batch size and PA-TNC message size */
        !           476:        switch (transport)
        !           477:        {
        !           478:                case TNC_IFT_TLS_2_0:
        !           479:                case TNC_IFT_TLS_1_0:
        !           480:                        default_max_batch_size = 128 * TLS_MAX_FRAGMENT_LEN - 16;
        !           481:                        break;
        !           482:                case TNC_IFT_EAP_2_0:
        !           483:                case TNC_IFT_EAP_1_1:
        !           484:                case TNC_IFT_EAP_1_0:
        !           485:                case TNC_IFT_UNKNOWN:
        !           486:                default:
        !           487:                        default_max_batch_size =   4 * TLS_MAX_FRAGMENT_LEN - 14;
        !           488:                        break;
        !           489:        }
        !           490: 
        !           491:        max_batch_size = min(default_max_batch_size,
        !           492:                                                lib->settings->get_int(lib->settings,
        !           493:                                                                "%s.plugins.tnccs-20.max_batch_size",
        !           494:                                                                 default_max_batch_size, lib->ns));
        !           495: 
        !           496:        default_max_message_size = max_batch_size - PB_TNC_BATCH_HEADER_SIZE
        !           497:                                                                                          - PB_TNC_MSG_HEADER_SIZE
        !           498:                                                                                          - PB_PA_MSG_HEADER_SIZE;
        !           499: 
        !           500:        max_message_size = min(default_max_message_size,
        !           501:                                                        lib->settings->get_int(lib->settings,
        !           502:                                                                "%s.plugins.tnccs-20.max_message_size",
        !           503:                                                                 default_max_message_size, lib->ns));
        !           504: 
        !           505:        INIT(this,
        !           506:                .public = {
        !           507:                        .tls = {
        !           508:                                .process = _process,
        !           509:                                .build = _build,
        !           510:                                .is_server = _is_server,
        !           511:                                .get_server_id = _get_server_id,
        !           512:                                .set_peer_id = _set_peer_id,
        !           513:                                .get_peer_id = _get_peer_id,
        !           514:                                .get_purpose = _get_purpose,
        !           515:                                .is_complete = _is_complete,
        !           516:                                .get_eap_msk = _get_eap_msk,
        !           517:                                .destroy = _destroy,
        !           518:                        },
        !           519:                        .get_server_ip = _get_server_ip,
        !           520:                        .get_peer_ip = _get_peer_ip,
        !           521:                        .get_transport = _get_transport,
        !           522:                        .set_transport = _set_transport,
        !           523:                        .get_auth_type = _get_auth_type,
        !           524:                        .set_auth_type = _set_auth_type,
        !           525:                        .get_pdp_server = _get_pdp_server,
        !           526:                        .get_ref = _get_ref,
        !           527:                },
        !           528:                .is_server = is_server,
        !           529:                .to_server = !is_server,
        !           530:                .server_id = server_id->clone(server_id),
        !           531:                .peer_id = peer_id->clone(peer_id),
        !           532:                .server_ip = server_ip->clone(server_ip),
        !           533:                .peer_ip = peer_ip->clone(peer_ip),
        !           534:                .transport = transport,
        !           535:                .eap_transport = transport == TNC_IFT_EAP_1_1 ||
        !           536:                                                 transport == TNC_IFT_EAP_2_0,
        !           537:                .callback = cb,
        !           538:                .max_batch_len = max_batch_size,
        !           539:                .max_msg_len = max_message_size,
        !           540:                .ref = 1,
        !           541:        );
        !           542: 
        !           543:        return &this->public;
        !           544: }

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