Annotation of embedaddon/strongswan/src/libtls/tls_eap.c, revision 1.1.1.2

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (C) 2010 Martin Willi
                      4:  * Copyright (C) 2010 revosec AG
                      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 "tls_eap.h"
                     18: 
                     19: #include "tls.h"
                     20: 
                     21: #include <utils/debug.h>
                     22: #include <library.h>
                     23: 
                     24: /**
                     25:  * Size limit for a TLS message allowing for worst-case protection overhead
                     26:  * according to section 6.2.3. "Payload Protection" of RFC 5246 TLS 1.2
                     27:  */
                     28: #define TLS_MAX_MESSAGE_LEN            4 * (TLS_MAX_FRAGMENT_LEN + 2048)
                     29: 
                     30: typedef struct private_tls_eap_t private_tls_eap_t;
                     31: 
                     32: /**
                     33:  * Private data of an tls_eap_t object.
                     34:  */
                     35: struct private_tls_eap_t {
                     36: 
                     37:        /**
                     38:         * Public tls_eap_t interface.
                     39:         */
                     40:        tls_eap_t public;
                     41: 
                     42:        /**
                     43:         * Type of EAP method, EAP-TLS, EAP-TTLS, or EAP-TNC
                     44:         */
                     45:        eap_type_t type;
                     46: 
                     47:        /**
                     48:         * Current value of EAP identifier
                     49:         */
                     50:        uint8_t identifier;
                     51: 
                     52:        /**
                     53:         * TLS stack
                     54:         */
                     55:        tls_t *tls;
                     56: 
                     57:        /**
                     58:         * Role
                     59:         */
                     60:        bool is_server;
                     61: 
                     62:        /**
                     63:         * Supported version of the EAP tunnel protocol
                     64:         */
                     65:        uint8_t supported_version;
                     66: 
                     67:        /**
                     68:         * If FALSE include the total length of an EAP message
                     69:         * in the first fragment of fragmented messages only.
                     70:         * If TRUE also include the length in non-fragmented messages.
                     71:         */
                     72:        bool include_length;
                     73: 
                     74:        /**
                     75:         * First fragment of a multi-fragment record?
                     76:         */
                     77:        bool first_fragment;
                     78: 
                     79:        /**
                     80:         * Maximum size of an outgoing EAP-TLS fragment
                     81:         */
                     82:        size_t frag_size;
                     83: 
                     84:        /**
                     85:         * Number of EAP messages/fragments processed so far
                     86:         */
                     87:        int processed;
                     88: 
                     89:        /**
                     90:         * Maximum number of processed EAP messages/fragments
                     91:         */
                     92:        int max_msg_count;
                     93: };
                     94: 
                     95: /**
                     96:  * Flags of an EAP-TLS/TTLS/TNC message
                     97:  */
                     98: typedef enum {
                     99:        EAP_TLS_LENGTH = (1<<7),                /* shared with EAP-TTLS/TNC/PEAP */
                    100:        EAP_TLS_MORE_FRAGS = (1<<6),    /* shared with EAP-TTLS/TNC/PEAP */
                    101:        EAP_TLS_START = (1<<5),                 /* shared with EAP-TTLS/TNC/PEAP */
                    102:        EAP_TTLS_VERSION = (0x07),              /* shared with EAP-TNC/PEAP/PT-EAP */
                    103:        EAP_PT_START = (1<<7)                   /* PT-EAP only */
                    104: } eap_tls_flags_t;
                    105: 
                    106: #define EAP_TTLS_SUPPORTED_VERSION             0
                    107: #define EAP_TNC_SUPPORTED_VERSION              1
                    108: #define EAP_PEAP_SUPPORTED_VERSION             0
                    109: #define EAP_PT_EAP_SUPPORTED_VERSION   1
                    110: 
                    111: /**
                    112:  * EAP-TLS/TTLS packet format
                    113:  */
                    114: typedef struct __attribute__((packed)) {
                    115:        uint8_t code;
                    116:        uint8_t identifier;
                    117:        uint16_t length;
                    118:        uint8_t type;
                    119:        uint8_t flags;
                    120: } eap_tls_packet_t;
                    121: 
                    122: METHOD(tls_eap_t, initiate, status_t,
                    123:        private_tls_eap_t *this, chunk_t *out)
                    124: {
                    125:        if (this->is_server)
                    126:        {
                    127:                eap_tls_packet_t pkt = {
                    128:                        .type = this->type,
                    129:                        .code = EAP_REQUEST,
                    130:                        .flags = this->supported_version
                    131:                };
                    132:                switch (this->type)
                    133:                {
                    134:                        case EAP_TLS:
                    135:                        case EAP_TTLS:
                    136:                        case EAP_TNC:
                    137:                        case EAP_PEAP:
                    138:                                pkt.flags |= EAP_TLS_START;
                    139:                                break;
                    140:                        case EAP_PT_EAP:
                    141:                                pkt.flags |= EAP_PT_START;
                    142:                                break;
                    143:                        default:
                    144:                                break;
                    145:                }
                    146:                htoun16(&pkt.length, sizeof(eap_tls_packet_t));
                    147:                pkt.identifier = this->identifier;
                    148: 
                    149:                *out = chunk_clone(chunk_from_thing(pkt));
                    150:                DBG2(DBG_TLS, "sending %N start packet (%u bytes)",
                    151:                         eap_type_names, this->type, sizeof(eap_tls_packet_t));
                    152:                DBG3(DBG_TLS, "%B", out);
                    153:                return NEED_MORE;
                    154:        }
                    155:        return FAILED;
                    156: }
                    157: 
                    158: /**
                    159:  * Process a received packet
                    160:  */
                    161: static status_t process_pkt(private_tls_eap_t *this, eap_tls_packet_t *pkt)
                    162: {
                    163:        uint8_t version;
                    164:        uint16_t pkt_len;
                    165:        uint32_t msg_len;
                    166:        size_t msg_len_offset = 0;
                    167: 
                    168:        /* EAP-TLS doesn't have a version field */
                    169:        if (this->type != EAP_TLS)
                    170:        {
                    171:                version = pkt->flags & EAP_TTLS_VERSION;
                    172:                if (version != this->supported_version)
                    173:                {
                    174:                        DBG1(DBG_TLS, "received %N packet with unsupported version v%u",
                    175:                        eap_type_names, this->type, version);
                    176:                        return FAILED;
                    177:                }
                    178:        }
                    179:        pkt_len = untoh16(&pkt->length);
                    180: 
                    181:        if (this->type != EAP_PT_EAP && (pkt->flags & EAP_TLS_LENGTH))
                    182:        {
                    183:                if (pkt_len < sizeof(eap_tls_packet_t) + sizeof(msg_len))
                    184:                {
                    185:                        DBG1(DBG_TLS, "%N packet too short", eap_type_names, this->type);
                    186:                        return FAILED;
                    187:                }
                    188:                msg_len = untoh32(pkt + 1);
                    189:                if (msg_len < pkt_len - sizeof(eap_tls_packet_t) - sizeof(msg_len) ||
                    190:                        msg_len > TLS_MAX_MESSAGE_LEN)
                    191:                {
                    192:                        DBG1(DBG_TLS, "invalid %N packet length (%u bytes)", eap_type_names,
                    193:                                 this->type, msg_len);
                    194:                        return FAILED;
                    195:                }
                    196:                msg_len_offset = sizeof(msg_len);
                    197:        }
                    198: 
                    199:        return this->tls->process(this->tls, (char*)(pkt + 1) + msg_len_offset,
                    200:                                           pkt_len - sizeof(eap_tls_packet_t) - msg_len_offset);
                    201: }
                    202: 
                    203: /**
                    204:  * Build a packet to send
                    205:  */
                    206: static status_t build_pkt(private_tls_eap_t *this, chunk_t *out)
                    207: {
                    208:        char buf[this->frag_size];
                    209:        eap_tls_packet_t *pkt;
                    210:        size_t len, reclen, msg_len_offset;
                    211:        status_t status;
                    212:        char *kind;
                    213: 
                    214:        if (this->is_server)
                    215:        {
                    216:                this->identifier++;
                    217:        }
                    218:        pkt = (eap_tls_packet_t*)buf;
                    219:        pkt->code = this->is_server ? EAP_REQUEST : EAP_RESPONSE;
                    220:        pkt->identifier = this->identifier;
                    221:        pkt->type = this->type;
                    222:        pkt->flags = this->supported_version;
                    223: 
                    224:        if (this->first_fragment)
                    225:        {
                    226:                len = sizeof(buf) - sizeof(eap_tls_packet_t) - sizeof(uint32_t);
                    227:                msg_len_offset = sizeof(uint32_t);
                    228:        }
                    229:        else
                    230:        {
                    231:                len = sizeof(buf) - sizeof(eap_tls_packet_t);
                    232:                msg_len_offset = 0;
                    233:        }
                    234:        status = this->tls->build(this->tls, buf + sizeof(eap_tls_packet_t) +
                    235:                                                                                 msg_len_offset, &len, &reclen);
                    236: 
                    237:        switch (status)
                    238:        {
                    239:                case NEED_MORE:
                    240:                        pkt->flags |= EAP_TLS_MORE_FRAGS;
                    241:                        kind = "further fragment";
                    242:                        if (this->first_fragment)
                    243:                        {
                    244:                                pkt->flags |= EAP_TLS_LENGTH;
                    245:                                this->first_fragment = FALSE;
                    246:                                kind = "first fragment";
                    247:                        }
                    248:                        break;
                    249:                case ALREADY_DONE:
                    250:                        if (this->first_fragment)
                    251:                        {
                    252:                                if (this->include_length)
                    253:                                {
                    254:                                        pkt->flags |= EAP_TLS_LENGTH;
                    255:                                }
                    256:                                kind = "packet";
                    257:                        }
                    258:                        else if (this->type != EAP_TNC && this->type != EAP_PT_EAP)
                    259:                        {
                    260:                                this->first_fragment = TRUE;
                    261:                                kind = "final fragment";
                    262:                        }
                    263:                        else
                    264:                        {
                    265:                                kind = "packet";
                    266:                        }
                    267:                        break;
                    268:                default:
                    269:                        return status;
                    270:        }
                    271:        if (reclen)
                    272:        {
                    273:                if (pkt->flags & EAP_TLS_LENGTH)
                    274:                {
                    275:                        htoun32(pkt + 1, reclen);
                    276:                        len += sizeof(uint32_t);
                    277:                        pkt->flags |= EAP_TLS_LENGTH;
                    278:                }
                    279:                else
                    280:                {
                    281:                        /* get rid of the reserved length field */
                    282:                        memmove(buf + sizeof(eap_tls_packet_t),
                    283:                                        buf + sizeof(eap_tls_packet_t) + sizeof(uint32_t), len);
                    284:                }
                    285:        }
                    286:        len += sizeof(eap_tls_packet_t);
                    287:        htoun16(&pkt->length, len);
                    288:        *out = chunk_clone(chunk_create(buf, len));
                    289:        DBG2(DBG_TLS, "sending %N %s (%u bytes)",
                    290:                 eap_type_names, this->type, kind, len);
                    291:        DBG3(DBG_TLS, "%B", out);
                    292:        return NEED_MORE;
                    293: }
                    294: 
                    295: /**
                    296:  * Send an ack to request next fragment
                    297:  */
                    298: static chunk_t create_ack(private_tls_eap_t *this)
                    299: {
                    300:        eap_tls_packet_t pkt = {
                    301:                .code = this->is_server ? EAP_REQUEST : EAP_RESPONSE,
                    302:                .type = this->type,
                    303:        };
                    304: 
                    305:        if (this->is_server)
                    306:        {
                    307:                this->identifier++;
                    308:        }
                    309:        pkt.identifier = this->identifier;
                    310:        htoun16(&pkt.length, sizeof(pkt));
                    311: 
                    312:        switch (this->type)
                    313:        {
                    314:                case EAP_TTLS:
                    315:                        pkt.flags |= EAP_TTLS_SUPPORTED_VERSION;
                    316:                        break;
                    317:                case EAP_TNC:
                    318:                        pkt.flags |= EAP_TNC_SUPPORTED_VERSION;
                    319:                        break;
                    320:                case EAP_PEAP:
                    321:                        pkt.flags |= EAP_PEAP_SUPPORTED_VERSION;
                    322:                        break;
                    323:                default:
                    324:                        break;
                    325:        }
                    326:        DBG2(DBG_TLS, "sending %N acknowledgement packet",
                    327:                 eap_type_names, this->type);
                    328:        return chunk_clone(chunk_from_thing(pkt));
                    329: }
                    330: 
                    331: METHOD(tls_eap_t, process, status_t,
                    332:        private_tls_eap_t *this, chunk_t in, chunk_t *out)
                    333: {
                    334:        eap_tls_packet_t *pkt;
                    335:        status_t status;
                    336: 
                    337:        if (this->max_msg_count && ++this->processed > this->max_msg_count)
                    338:        {
                    339:                DBG1(DBG_TLS, "%N packet count exceeded (%d > %d)",
                    340:                         eap_type_names, this->type,
                    341:                         this->processed, this->max_msg_count);
                    342:                return FAILED;
                    343:        }
                    344: 
                    345:        pkt = (eap_tls_packet_t*)in.ptr;
                    346:        if (in.len < sizeof(eap_tls_packet_t) || untoh16(&pkt->length) != in.len)
                    347:        {
                    348:                DBG1(DBG_TLS, "invalid %N packet length", eap_type_names, this->type);
                    349:                return FAILED;
                    350:        }
                    351: 
                    352:        /* update EAP identifier */
                    353:        if (!this->is_server)
                    354:        {
                    355:                this->identifier = pkt->identifier;
                    356:        }
                    357:        DBG3(DBG_TLS, "%N payload %B", eap_type_names, this->type, &in);
                    358: 
                    359:        if ((this->type == EAP_PT_EAP && (pkt->flags & EAP_PT_START)) ||
                    360:         (pkt->flags & EAP_TLS_START))
                    361:        {
                    362:                if (this->type == EAP_TTLS || this->type == EAP_TNC ||
                    363:                        this->type == EAP_PEAP || this->type == EAP_PT_EAP)
                    364:                {
                    365:                        DBG1(DBG_TLS, "%N version is v%u", eap_type_names, this->type,
                    366:                                 pkt->flags & EAP_TTLS_VERSION);
                    367:                }
                    368:        }
                    369:        else
                    370:        {
                    371:                if (in.len == sizeof(eap_tls_packet_t))
                    372:                {
                    373:                        DBG2(DBG_TLS, "received %N acknowledgement packet",
                    374:                                 eap_type_names, this->type);
                    375:                        status = build_pkt(this, out);
                    376:                        if (status == INVALID_STATE && this->tls->is_complete(this->tls))
                    377:                        {
                    378:                                return SUCCESS;
                    379:                        }
                    380:                        return status;
                    381:                }
                    382:                status = process_pkt(this, pkt);
                    383:                switch (status)
                    384:                {
                    385:                        case NEED_MORE:
                    386:                                break;
                    387:                        case SUCCESS:
                    388:                                return this->tls->is_complete(this->tls) ? SUCCESS : FAILED;
                    389:                        default:
                    390:                                return status;
                    391:                }
                    392:        }
                    393:        status = build_pkt(this, out);
                    394:        switch (status)
                    395:        {
                    396:                case INVALID_STATE:
1.1.1.2 ! misho     397:                        if (this->is_server && this->tls->is_complete(this->tls))
        !           398:                        {
        !           399:                                return SUCCESS;
        !           400:                        }
1.1       misho     401:                        *out = create_ack(this);
                    402:                        return NEED_MORE;
                    403:                case FAILED:
                    404:                        if (!this->is_server)
                    405:                        {
                    406:                                *out = create_ack(this);
                    407:                                return NEED_MORE;
                    408:                        }
                    409:                        return FAILED;
                    410:                default:
                    411:                        return status;
                    412:        }
                    413: }
                    414: 
                    415: METHOD(tls_eap_t, get_msk, chunk_t,
                    416:        private_tls_eap_t *this)
                    417: {
                    418:        return this->tls->get_eap_msk(this->tls);
                    419: }
                    420: 
                    421: METHOD(tls_eap_t, get_identifier, uint8_t,
                    422:        private_tls_eap_t *this)
                    423: {
                    424:        return this->identifier;
                    425: }
                    426: 
                    427: METHOD(tls_eap_t, set_identifier, void,
                    428:        private_tls_eap_t *this, uint8_t identifier)
                    429: {
                    430:        this->identifier = identifier;
                    431: }
                    432: 
                    433: METHOD(tls_eap_t, get_auth, auth_cfg_t*,
                    434:        private_tls_eap_t *this)
                    435: {
                    436:        return this->tls->get_auth(this->tls);
                    437: }
                    438: 
                    439: METHOD(tls_eap_t, destroy, void,
                    440:        private_tls_eap_t *this)
                    441: {
                    442:        this->tls->destroy(this->tls);
                    443:        free(this);
                    444: }
                    445: 
                    446: /**
                    447:  * See header
                    448:  */
                    449: tls_eap_t *tls_eap_create(eap_type_t type, tls_t *tls, size_t frag_size,
                    450:                                                  int max_msg_count, bool include_length)
                    451: {
                    452:        private_tls_eap_t *this;
                    453: 
                    454:        if (!tls)
                    455:        {
                    456:                return NULL;
                    457:        }
                    458: 
                    459:        INIT(this,
                    460:                .public = {
                    461:                        .initiate = _initiate,
                    462:                        .process = _process,
                    463:                        .get_msk = _get_msk,
                    464:                        .get_identifier = _get_identifier,
                    465:                        .set_identifier = _set_identifier,
                    466:                        .get_auth = _get_auth,
                    467:                        .destroy = _destroy,
                    468:                },
                    469:                .type = type,
                    470:                .is_server = tls->is_server(tls),
                    471:                .first_fragment = (type != EAP_TNC && type != EAP_PT_EAP),
                    472:                .frag_size = frag_size,
                    473:                .max_msg_count = max_msg_count,
                    474:                .include_length = include_length,
                    475:                .tls = tls,
                    476:        );
                    477: 
                    478:        switch (type)
                    479:        {
                    480:                case EAP_TTLS:
                    481:                        this->supported_version = EAP_TTLS_SUPPORTED_VERSION;
                    482:                        break;
                    483:                case EAP_TNC:
                    484:                        this->supported_version = EAP_TNC_SUPPORTED_VERSION;
                    485:                        break;
                    486:                case EAP_PEAP:
                    487:                        this->supported_version = EAP_PEAP_SUPPORTED_VERSION;
                    488:                        break;
                    489:                case EAP_PT_EAP:
                    490:                        this->supported_version = EAP_PT_EAP_SUPPORTED_VERSION;
                    491:                        break;
                    492:                default:
                    493:                        break;
                    494:        }
                    495: 
                    496:        if (this->is_server)
                    497:        {
                    498:                do
                    499:                {       /* start with non-zero random identifier */
                    500:                        this->identifier = random();
                    501:                }
                    502:                while (!this->identifier);
                    503:        }
                    504: 
                    505:        return &this->public;
                    506: }

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