Annotation of embedaddon/strongswan/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2010 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 "eap_ttls_peer.h"
        !            17: #include "eap_ttls_avp.h"
        !            18: 
        !            19: #include <utils/debug.h>
        !            20: #include <daemon.h>
        !            21: #include <radius_message.h>
        !            22: #include <sa/eap/eap_method.h>
        !            23: 
        !            24: typedef struct private_eap_ttls_peer_t private_eap_ttls_peer_t;
        !            25: 
        !            26: /**
        !            27:  * Private data of an eap_ttls_peer_t object.
        !            28:  */
        !            29: struct private_eap_ttls_peer_t {
        !            30: 
        !            31:        /**
        !            32:         * Public eap_ttls_peer_t interface.
        !            33:         */
        !            34:        eap_ttls_peer_t public;
        !            35: 
        !            36:        /**
        !            37:         * Server identity
        !            38:         */
        !            39:        identification_t *server;
        !            40: 
        !            41:        /**
        !            42:         * Peer identity
        !            43:         */
        !            44:        identification_t *peer;
        !            45: 
        !            46:        /**
        !            47:         * Current EAP-TTLS state
        !            48:         */
        !            49:        bool start_phase2;
        !            50: 
        !            51:        /**
        !            52:      * Current phase 2 EAP method
        !            53:         */
        !            54:        eap_method_t *method;
        !            55: 
        !            56:        /**
        !            57:      * Pending outbound EAP message
        !            58:         */
        !            59:        eap_payload_t *out;
        !            60: 
        !            61:        /**
        !            62:         * AVP handler
        !            63:         */
        !            64:        eap_ttls_avp_t *avp;
        !            65: };
        !            66: 
        !            67: METHOD(tls_application_t, process, status_t,
        !            68:        private_eap_ttls_peer_t *this, bio_reader_t *reader)
        !            69: {
        !            70:        chunk_t avp_data = chunk_empty;
        !            71:        chunk_t eap_data = chunk_empty;
        !            72:        status_t status;
        !            73:        payload_t *payload;
        !            74:        eap_payload_t *in;
        !            75:        eap_packet_t *pkt;
        !            76:        eap_code_t code;
        !            77:        eap_type_t type, received_type;
        !            78:        uint32_t vendor, received_vendor;
        !            79:        uint16_t eap_len;
        !            80:        size_t eap_pos = 0;
        !            81:        bool concatenated = FALSE;
        !            82: 
        !            83:        do
        !            84:        {
        !            85:                status = this->avp->process(this->avp, reader, &avp_data);
        !            86:                switch (status)
        !            87:                {
        !            88:                        case SUCCESS:
        !            89:                                break;
        !            90:                        case NEED_MORE:
        !            91:                                DBG1(DBG_IKE, "need more AVP data");
        !            92:                                return NEED_MORE;
        !            93:                        case FAILED:
        !            94:                        default:
        !            95:                                return FAILED;
        !            96:                }
        !            97: 
        !            98:                if (eap_data.len == 0)
        !            99:                {
        !           100:                        if (avp_data.len < 4)
        !           101:                        {
        !           102:                                DBG1(DBG_IKE, "AVP size to small to contain EAP header");
        !           103:                                chunk_free(&avp_data);
        !           104:                                return FAILED;
        !           105:                        }
        !           106:                        pkt = (eap_packet_t*)avp_data.ptr;
        !           107:                        eap_len = untoh16(&pkt->length);
        !           108: 
        !           109:                        if (eap_len <= avp_data.len)
        !           110:                        {
        !           111:                                /* standard:  EAP packet contained in a single AVP */
        !           112:                                eap_data = avp_data;
        !           113:                                break;
        !           114:                        }
        !           115:                        else if (eap_len > reader->remaining(reader) + avp_data.len)
        !           116:                        {
        !           117:                                /* rough size check, ignoring AVP headers in remaining data */
        !           118:                                DBG1(DBG_IKE, "EAP packet too large for EAP-TTLS AVP(s)");
        !           119:                                chunk_free(&avp_data);
        !           120:                                return FAILED;
        !           121:                        }
        !           122:                        else if (avp_data.len == MAX_RADIUS_ATTRIBUTE_SIZE)
        !           123:                        {
        !           124:                                /* non-standard: EAP packet segmented into multiple AVPs */
        !           125:                                eap_data = chunk_alloc(eap_len);
        !           126:                                concatenated = TRUE;
        !           127:                        }
        !           128:                        else
        !           129:                        {
        !           130:                                DBG1(DBG_IKE, "non-radius segmentation of EAP packet into AVPs");
        !           131:                                chunk_free(&avp_data);
        !           132:                                return FAILED;
        !           133:                        }
        !           134:                }
        !           135: 
        !           136:                if (avp_data.len > eap_data.len - eap_pos)
        !           137:                {
        !           138:                        DBG1(DBG_IKE, "AVP size too large to fit into EAP packet");
        !           139:                        chunk_free(&avp_data);
        !           140:                        chunk_free(&eap_data);
        !           141:                        return FAILED;
        !           142:                }
        !           143:                memcpy(eap_data.ptr + eap_pos, avp_data.ptr, avp_data.len);
        !           144:                eap_pos += avp_data.len;
        !           145:                chunk_free(&avp_data);
        !           146:        }
        !           147:        while (eap_pos < eap_data.len);
        !           148: 
        !           149:        in = eap_payload_create_data(eap_data);
        !           150:        chunk_free(&eap_data);
        !           151:        payload = (payload_t*)in;
        !           152: 
        !           153:        if (payload->verify(payload) != SUCCESS)
        !           154:        {
        !           155:                in->destroy(in);
        !           156:                return FAILED;
        !           157:        }
        !           158:        code = in->get_code(in);
        !           159:        received_type = in->get_type(in, &received_vendor);
        !           160:        DBG1(DBG_IKE, "received tunneled EAP-TTLS AVP%s [EAP/%N/%N]",
        !           161:                                                        concatenated ? "s" : "",
        !           162:                                                        eap_code_short_names, code,
        !           163:                                                        eap_type_short_names, received_type);
        !           164:        if (code != EAP_REQUEST)
        !           165:        {
        !           166:                DBG1(DBG_IKE, "%N expected", eap_code_names, EAP_REQUEST);
        !           167:                in->destroy(in);
        !           168:                return FAILED;
        !           169:        }
        !           170: 
        !           171:        /* yet another phase2 authentication? */
        !           172:        if (this->method)
        !           173:        {
        !           174:                type = this->method->get_type(this->method, &vendor);
        !           175: 
        !           176:                if (type != received_type || vendor != received_vendor)
        !           177:                {
        !           178:                        this->method->destroy(this->method);
        !           179:                        this->method = NULL;
        !           180:                }
        !           181:        }
        !           182: 
        !           183:        if (this->method == NULL)
        !           184:        {
        !           185:                if (received_vendor)
        !           186:                {
        !           187:                        DBG1(DBG_IKE, "server requested vendor specific EAP method %d-%d "
        !           188:                                                  "(id 0x%02X)", received_type, received_vendor,
        !           189:                                                   in->get_identifier(in));
        !           190:                }
        !           191:                else
        !           192:                {
        !           193:                        DBG1(DBG_IKE, "server requested %N authentication (id 0x%02X)",
        !           194:                                 eap_type_names, received_type, in->get_identifier(in));
        !           195:                }
        !           196:                this->method = charon->eap->create_instance(charon->eap,
        !           197:                                                                        received_type, received_vendor,
        !           198:                                                                        EAP_PEER, this->server, this->peer);
        !           199:                if (!this->method)
        !           200:                {
        !           201:                        DBG1(DBG_IKE, "EAP method not supported");
        !           202:                        this->out = eap_payload_create_nak(in->get_identifier(in), 0, 0,
        !           203:                                                                                           in->is_expanded(in));
        !           204:                        in->destroy(in);
        !           205:                        return NEED_MORE;
        !           206:                }
        !           207:                type = this->method->get_type(this->method, &vendor);
        !           208:                this->start_phase2 = FALSE;
        !           209:        }
        !           210: 
        !           211:        status = this->method->process(this->method, in, &this->out);
        !           212:        in->destroy(in);
        !           213: 
        !           214:        switch (status)
        !           215:        {
        !           216:                case SUCCESS:
        !           217:                        this->method->destroy(this->method);
        !           218:                        this->method = NULL;
        !           219:                        /* fall through to NEED_MORE */
        !           220:                case NEED_MORE:
        !           221:                        return NEED_MORE;
        !           222:                case FAILED:
        !           223:                default:
        !           224:                        if (vendor)
        !           225:                        {
        !           226:                                DBG1(DBG_IKE, "vendor specific EAP method %d-%d failed",
        !           227:                                                           type, vendor);
        !           228:                        }
        !           229:                        else
        !           230:                        {
        !           231:                                DBG1(DBG_IKE, "%N method failed", eap_type_names, type);
        !           232:                        }
        !           233:                        return FAILED;
        !           234:        }
        !           235: }
        !           236: 
        !           237: METHOD(tls_application_t, build, status_t,
        !           238:        private_eap_ttls_peer_t *this, bio_writer_t *writer)
        !           239: {
        !           240:        chunk_t data;
        !           241:        eap_code_t code;
        !           242:        eap_type_t type;
        !           243:        uint32_t vendor;
        !           244: 
        !           245:        if (this->method == NULL && this->start_phase2)
        !           246:        {
        !           247:                /* generate an EAP Identity response */
        !           248:                this->method = charon->eap->create_instance(charon->eap, EAP_IDENTITY,
        !           249:                                                                 0,     EAP_PEER, this->server, this->peer);
        !           250:                if (this->method == NULL)
        !           251:                {
        !           252:                        DBG1(DBG_IKE, "EAP_IDENTITY method not available");
        !           253:                        return FAILED;
        !           254:                }
        !           255:                this->method->process(this->method, NULL, &this->out);
        !           256:                this->method->destroy(this->method);
        !           257:                this->method = NULL;
        !           258:                this->start_phase2 = FALSE;
        !           259:        }
        !           260: 
        !           261:        if (this->out)
        !           262:        {
        !           263:                code = this->out->get_code(this->out);
        !           264:                type = this->out->get_type(this->out, &vendor);
        !           265:                DBG1(DBG_IKE, "sending tunneled EAP-TTLS AVP [EAP/%N/%N]",
        !           266:                                                eap_code_short_names, code, eap_type_short_names, type);
        !           267: 
        !           268:                /* get the raw EAP message data */
        !           269:                data = this->out->get_data(this->out);
        !           270:                this->avp->build(this->avp, writer, data);
        !           271: 
        !           272:                this->out->destroy(this->out);
        !           273:                this->out = NULL;
        !           274:        }
        !           275:        return INVALID_STATE;
        !           276: }
        !           277: 
        !           278: METHOD(tls_application_t, destroy, void,
        !           279:        private_eap_ttls_peer_t *this)
        !           280: {
        !           281:        this->server->destroy(this->server);
        !           282:        this->peer->destroy(this->peer);
        !           283:        DESTROY_IF(this->method);
        !           284:        DESTROY_IF(this->out);
        !           285:        this->avp->destroy(this->avp);
        !           286:        free(this);
        !           287: }
        !           288: 
        !           289: /**
        !           290:  * See header
        !           291:  */
        !           292: eap_ttls_peer_t *eap_ttls_peer_create(identification_t *server,
        !           293:                                                                          identification_t *peer)
        !           294: {
        !           295:        private_eap_ttls_peer_t *this;
        !           296: 
        !           297:        INIT(this,
        !           298:                .public = {
        !           299:                        .application = {
        !           300:                                .process = _process,
        !           301:                                .build = _build,
        !           302:                                .destroy = _destroy,
        !           303:                        },
        !           304:                },
        !           305:                .server = server->clone(server),
        !           306:                .peer = peer->clone(peer),
        !           307:                .start_phase2 = TRUE,
        !           308:                .avp = eap_ttls_avp_create(),
        !           309:        );
        !           310: 
        !           311:        return &this->public;
        !           312: }

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