Annotation of embedaddon/strongswan/src/libcharon/plugins/eap_ttls/eap_ttls_server.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2010-2014 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_server.h"
                     17: #include "eap_ttls_avp.h"
                     18: 
                     19: #include <utils/debug.h>
                     20: #include <daemon.h>
                     21: 
                     22: #include <sa/eap/eap_method.h>
                     23: #include <sa/eap/eap_inner_method.h>
                     24: 
                     25: typedef struct private_eap_ttls_server_t private_eap_ttls_server_t;
                     26: 
                     27: /**
                     28:  * Private data of an eap_ttls_server_t object.
                     29:  */
                     30: struct private_eap_ttls_server_t {
                     31: 
                     32:        /**
                     33:         * Public eap_ttls_server_t interface.
                     34:         */
                     35:        eap_ttls_server_t public;
                     36: 
                     37:        /**
                     38:         * Server identity
                     39:         */
                     40:        identification_t *server;
                     41: 
                     42:        /**
                     43:         * Peer identity
                     44:         */
                     45:        identification_t *peer;
                     46: 
                     47:        /**
                     48:         * Current EAP-TTLS phase2 state
                     49:         */
                     50:        bool start_phase2;
                     51: 
                     52:        /**
                     53:         * Current EAP-TTLS phase2 TNC state
                     54:         */
                     55:        bool start_phase2_tnc;
                     56: 
                     57:        /**
                     58:      * Current phase 2 EAP method
                     59:         */
                     60:        eap_method_t *method;
                     61: 
                     62:        /**
                     63:      * Pending outbound EAP message
                     64:         */
                     65:        eap_payload_t *out;
                     66: 
                     67:        /**
                     68:         * AVP handler
                     69:         */
                     70:        eap_ttls_avp_t *avp;
                     71: };
                     72: 
                     73: /**
                     74:  * Start EAP client authentication protocol
                     75:  */
                     76: static status_t start_phase2_auth(private_eap_ttls_server_t *this)
                     77: {
                     78:        char *eap_type_str;
                     79:        eap_type_t type;
                     80: 
                     81:        eap_type_str = lib->settings->get_str(lib->settings,
                     82:                                                                        "%s.plugins.eap-ttls.phase2_method", "md5",
                     83:                                                                        lib->ns);
                     84:        type = eap_type_from_string(eap_type_str);
                     85:        if (type == 0)
                     86:        {
                     87:                DBG1(DBG_IKE, "unrecognized phase2 method \"%s\"", eap_type_str);
                     88:                return FAILED;
                     89:        }
                     90:        DBG1(DBG_IKE, "phase2 method %N selected", eap_type_names, type);
                     91:                this->method = charon->eap->create_instance(charon->eap, type, 0,
                     92:                                                                EAP_SERVER, this->server, this->peer);
                     93:        if (this->method == NULL)
                     94:        {
                     95:                DBG1(DBG_IKE, "%N method not available", eap_type_names, type);
                     96:                return FAILED;
                     97:        }
                     98:        if (this->method->initiate(this->method, &this->out) == NEED_MORE)
                     99:        {
                    100:                return NEED_MORE;
                    101:        }
                    102:        else
                    103:        {
                    104:                DBG1(DBG_IKE, "%N method failed", eap_type_names, type);
                    105:                        return FAILED;
                    106:        }
                    107: }
                    108: 
                    109: /**
                    110:  * If configured, start PT-EAP or legacy EAP-TNC protocol
                    111:  */
                    112: static status_t start_phase2_tnc(private_eap_ttls_server_t *this,
                    113:                                                                 eap_type_t auth_type)
                    114: {
                    115:        eap_inner_method_t *inner_method;
                    116:        eap_type_t type;
                    117:        char *eap_type_str;
                    118: 
                    119:        if (this->start_phase2_tnc && lib->settings->get_bool(lib->settings,
                    120:                                                        "%s.plugins.eap-ttls.phase2_tnc", FALSE, lib->ns))
                    121:        {
                    122:                eap_type_str = lib->settings->get_str(lib->settings,
                    123:                                                        "%s.plugins.eap-ttls.phase2_tnc_method", "pt",
                    124:                                                        lib->ns);
                    125:                type = eap_type_from_string(eap_type_str);
                    126:                if (type == 0)
                    127:                {
                    128:                        DBG1(DBG_IKE, "unrecognized phase2 EAP TNC method \"%s\"",
                    129:                                                   eap_type_str);
                    130:                        return FAILED;
                    131:                }
                    132:                DBG1(DBG_IKE, "phase2 method %N selected", eap_type_names, type);
                    133:                this->method = charon->eap->create_instance(charon->eap, type,
                    134:                                                                        0, EAP_SERVER, this->server, this->peer);
                    135:                if (this->method == NULL)
                    136:                {
                    137:                        DBG1(DBG_IKE, "%N method not available", eap_type_names, type);
                    138:                        return FAILED;
                    139:                }
                    140:                inner_method = (eap_inner_method_t *)this->method;
                    141:                inner_method->set_auth_type(inner_method, auth_type);
                    142: 
                    143:                this->start_phase2_tnc = FALSE;
                    144:                if (this->method->initiate(this->method, &this->out) == NEED_MORE)
                    145:                {
                    146:                        return NEED_MORE;
                    147:                }
                    148:                else
                    149:                {
                    150:                        DBG1(DBG_IKE, "%N method failed", eap_type_names, type);
                    151:                        return FAILED;
                    152:                }
                    153:        }
                    154:        return SUCCESS;
                    155: }
                    156: 
                    157: METHOD(tls_application_t, process, status_t,
                    158:        private_eap_ttls_server_t *this, bio_reader_t *reader)
                    159: {
                    160:        chunk_t data = chunk_empty;
                    161:        status_t status;
                    162:        payload_t *payload;
                    163:        eap_payload_t *in;
                    164:        eap_code_t code;
                    165:        eap_type_t type = EAP_NAK, received_type;
                    166:        uint32_t vendor, received_vendor;
                    167: 
                    168:        status = this->avp->process(this->avp, reader, &data);
                    169:        switch (status)
                    170:        {
                    171:                case SUCCESS:
                    172:                        break;
                    173:                case NEED_MORE:
                    174:                        return NEED_MORE;
                    175:                case FAILED:
                    176:                default:
                    177:                        return FAILED;
                    178:        }
                    179:        in = eap_payload_create_data(data);
                    180:        chunk_free(&data);
                    181:        payload = (payload_t*)in;
                    182: 
                    183:        if (payload->verify(payload) != SUCCESS)
                    184:        {
                    185:                in->destroy(in);
                    186:                return FAILED;
                    187:        }
                    188:        code = in->get_code(in);
                    189:        received_type = in->get_type(in, &received_vendor);
                    190:        DBG1(DBG_IKE, "received tunneled EAP-TTLS AVP [EAP/%N/%N]",
                    191:                                                        eap_code_short_names, code,
                    192:                                                        eap_type_short_names, received_type);
                    193:        if (code != EAP_RESPONSE)
                    194:        {
                    195:                DBG1(DBG_IKE, "%N expected", eap_code_names, EAP_RESPONSE);
                    196:                in->destroy(in);
                    197:                return FAILED;
                    198:        }
                    199: 
                    200:        if (this->method)
                    201:        {
                    202:                type = this->method->get_type(this->method, &vendor);
                    203: 
                    204:                if (type != received_type || vendor != received_vendor)
                    205:                {
                    206:                        if (received_vendor == 0 && received_type == EAP_NAK)
                    207:                        {
                    208:                                DBG1(DBG_IKE, "peer does not support %N", eap_type_names, type);
                    209:                        }
                    210:                        else
                    211:                        {
                    212:                                DBG1(DBG_IKE, "received invalid EAP response");
                    213:                        }
                    214:                        in->destroy(in);
                    215:                        return FAILED;
                    216:                }
                    217:        }
                    218: 
                    219:        if (!received_vendor && received_type == EAP_IDENTITY)
                    220:        {
                    221:                chunk_t eap_id;
                    222: 
                    223:                if (this->method == NULL)
                    224:                {
                    225:                        /* Received an EAP Identity response without a matching request */
                    226:                        this->method = charon->eap->create_instance(charon->eap,
                    227:                                                                                         EAP_IDENTITY, 0, EAP_SERVER,
                    228:                                                                                         this->server, this->peer);
                    229:                        if (this->method == NULL)
                    230:                        {
                    231:                                DBG1(DBG_IKE, "%N method not available",
                    232:                                                           eap_type_names, EAP_IDENTITY);
                    233:                                return FAILED;
                    234:                        }
                    235:                }
                    236: 
                    237:                if (this->method->process(this->method, in, &this->out) != SUCCESS)
                    238:                {
                    239: 
                    240:                        DBG1(DBG_IKE, "%N method failed", eap_type_names, EAP_IDENTITY);
                    241:                        return FAILED;
                    242:                }
                    243: 
                    244:                if (this->method->get_msk(this->method, &eap_id) == SUCCESS)
                    245:                {
                    246:                        this->peer->destroy(this->peer);
                    247:                        this->peer = identification_create_from_data(eap_id);
                    248:                        DBG1(DBG_IKE, "received EAP identity '%Y'", this->peer);
                    249:                }
                    250: 
                    251:                in->destroy(in);
                    252:                this->method->destroy(this->method);
                    253:                this->method = NULL;
                    254: 
                    255:                /* Start Phase 2 of EAP-TTLS authentication */
                    256:                if (lib->settings->get_bool(lib->settings,
                    257:                                        "%s.plugins.eap-ttls.request_peer_auth", FALSE, lib->ns))
                    258:                {
                    259:                        return start_phase2_tnc(this, EAP_TLS);
                    260:                }
                    261:                else
                    262:                {
                    263:                        return start_phase2_auth(this);
                    264:                }
                    265:        }
                    266: 
                    267:        if (this->method == 0)
                    268:        {
                    269:                DBG1(DBG_IKE, "no %N phase2 method installed", eap_type_names, EAP_TTLS);
                    270:                in->destroy(in);
                    271:                return FAILED;
                    272:        }
                    273: 
                    274:        status = this->method->process(this->method, in, &this->out);
                    275:        in->destroy(in);
                    276: 
                    277:        switch (status)
                    278:        {
                    279:                case SUCCESS:
                    280:                        DBG1(DBG_IKE, "%N phase2 authentication of '%Y' with %N successful",
                    281:                                                        eap_type_names, EAP_TTLS, this->peer,
                    282:                                                        eap_type_names, type);
                    283:                        this->method->destroy(this->method);
                    284:                        this->method = NULL;
                    285: 
                    286:                        /* continue phase2 with EAP-TNC? */
                    287:                        return start_phase2_tnc(this, type);
                    288:                case NEED_MORE:
                    289:                        break;
                    290:                case FAILED:
                    291:                default:
                    292:                        if (vendor)
                    293:                        {
                    294:                                DBG1(DBG_IKE, "vendor specific EAP method %d-%d failed",
                    295:                                                           type, vendor);
                    296:                        }
                    297:                        else
                    298:                        {
                    299:                                DBG1(DBG_IKE, "%N method failed", eap_type_names, type);
                    300:                        }
                    301:                        return FAILED;
                    302:        }
                    303:        return status;
                    304: }
                    305: 
                    306: METHOD(tls_application_t, build, status_t,
                    307:        private_eap_ttls_server_t *this, bio_writer_t *writer)
                    308: {
                    309:        chunk_t data;
                    310:        eap_code_t code;
                    311:        eap_type_t type;
                    312:        uint32_t vendor;
                    313: 
                    314:        if (this->method == NULL && this->start_phase2 &&
                    315:                lib->settings->get_bool(lib->settings,
                    316:                                        "%s.plugins.eap-ttls.phase2_piggyback", FALSE, lib->ns))
                    317:        {
                    318:                /* generate an EAP Identity request which will be piggybacked right
                    319:                 * onto the TLS Finished message thus initiating EAP-TTLS phase2
                    320:                 */
                    321:                this->method = charon->eap->create_instance(charon->eap, EAP_IDENTITY,
                    322:                                                                 0,     EAP_SERVER, this->server, this->peer);
                    323:                if (this->method == NULL)
                    324:                {
                    325:                        DBG1(DBG_IKE, "%N method not available",
                    326:                                 eap_type_names, EAP_IDENTITY);
                    327:                        return FAILED;
                    328:                }
                    329:                this->method->initiate(this->method, &this->out);
                    330:                this->start_phase2 = FALSE;
                    331:        }
                    332: 
                    333:        if (this->out)
                    334:        {
                    335:                code = this->out->get_code(this->out);
                    336:                type = this->out->get_type(this->out, &vendor);
                    337:                DBG1(DBG_IKE, "sending tunneled EAP-TTLS AVP [EAP/%N/%N]",
                    338:                                                eap_code_short_names, code, eap_type_short_names, type);
                    339: 
                    340:                /* get the raw EAP message data */
                    341:                data = this->out->get_data(this->out);
                    342:                this->avp->build(this->avp, writer, data);
                    343: 
                    344:                this->out->destroy(this->out);
                    345:                this->out = NULL;
                    346:        }
                    347:        return INVALID_STATE;
                    348: }
                    349: 
                    350: METHOD(tls_application_t, destroy, void,
                    351:        private_eap_ttls_server_t *this)
                    352: {
                    353:        this->server->destroy(this->server);
                    354:        this->peer->destroy(this->peer);
                    355:        DESTROY_IF(this->method);
                    356:        DESTROY_IF(this->out);
                    357:        this->avp->destroy(this->avp);
                    358:        free(this);
                    359: }
                    360: 
                    361: /**
                    362:  * See header
                    363:  */
                    364: eap_ttls_server_t *eap_ttls_server_create(identification_t *server,
                    365:                                                                                  identification_t *peer)
                    366: {
                    367:        private_eap_ttls_server_t *this;
                    368: 
                    369:        INIT(this,
                    370:                .public = {
                    371:                        .application = {
                    372:                                .process = _process,
                    373:                                .build = _build,
                    374:                                .destroy = _destroy,
                    375:                        },
                    376:                },
                    377:                .server = server->clone(server),
                    378:                .peer = peer->clone(peer),
                    379:                .start_phase2 = TRUE,
                    380:                .start_phase2_tnc = TRUE,
                    381:                .avp = eap_ttls_avp_create(),
                    382:        );
                    383: 
                    384:        return &this->public;
                    385: }

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