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

1.1       misho       1: /*
                      2:  * Copyright (C) 2010 Martin Willi
                      3:  * Copyright (C) 2010 revosec AG
                      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 "tls_fragmentation.h"
                     17: 
                     18: #include <bio/bio_reader.h>
                     19: #include <utils/debug.h>
                     20: 
                     21: /**
                     22:  * Maximum size of a TLS handshake message we accept
                     23:  */
                     24: #define TLS_MAX_HANDSHAKE_LEN  65536
                     25: 
                     26: typedef struct private_tls_fragmentation_t private_tls_fragmentation_t;
                     27: 
                     28: /**
                     29:  * Alert state
                     30:  */
                     31: typedef enum {
                     32:        /* no alert received/sent */
                     33:        ALERT_NONE,
                     34:        /* currently sending an alert */
                     35:        ALERT_SENDING,
                     36:        /* alert sent and out */
                     37:        ALERT_SENT,
                     38: } alert_state_t;
                     39: 
                     40: /**
                     41:  * Private data of an tls_fragmentation_t object.
                     42:  */
                     43: struct private_tls_fragmentation_t {
                     44: 
                     45:        /**
                     46:         * Public tls_fragmentation_t interface.
                     47:         */
                     48:        tls_fragmentation_t public;
                     49: 
                     50:        /**
                     51:         * Upper layer handshake protocol
                     52:         */
                     53:        tls_handshake_t *handshake;
                     54: 
                     55:        /**
                     56:         * TLS alert handler
                     57:         */
                     58:        tls_alert_t *alert;
                     59: 
                     60:        /**
                     61:         * State of alert handling
                     62:         */
                     63:        alert_state_t state;
                     64: 
                     65:        /**
                     66:         * Did the application layer complete successfully?
                     67:         */
                     68:        bool application_finished;
                     69: 
                     70:        /**
                     71:         * Handshake input buffer
                     72:         */
                     73:        chunk_t input;
                     74: 
                     75:        /**
                     76:         * Position in input buffer
                     77:         */
                     78:        size_t inpos;
                     79: 
                     80:        /**
                     81:         * Currently processed handshake message type
                     82:         */
                     83:        tls_handshake_type_t type;
                     84: 
                     85:        /**
                     86:         * Handshake output buffer
                     87:         */
                     88:        chunk_t output;
                     89: 
                     90:        /**
                     91:         * Type of data in output buffer
                     92:         */
                     93:        tls_content_type_t output_type;
                     94: 
                     95:        /**
                     96:         * Upper layer application data protocol
                     97:         */
                     98:        tls_application_t *application;
                     99: 
                    100:        /**
                    101:         * Type of context this TLS instance runs in
                    102:         */
                    103:        tls_purpose_t purpose;
                    104: };
                    105: 
                    106: /**
                    107:  * Check if we should send a close notify once the application finishes
                    108:  */
                    109: static bool send_close_notify(private_tls_fragmentation_t *this)
                    110: {
                    111:        switch (this->purpose)
                    112:        {
                    113:                case TLS_PURPOSE_EAP_TLS:
                    114:                case TLS_PURPOSE_EAP_TTLS:
                    115:                case TLS_PURPOSE_EAP_PEAP:
                    116:                        /* not for TLS-in-EAP, as we indicate completion with EAP-SUCCCESS.
                    117:                         * Windows does not like close notifies, and hangs/disconnects. */
                    118:                        return FALSE;
                    119:                default:
                    120:                        return TRUE;
                    121:        }
                    122: }
                    123: 
                    124: /**
                    125:  * Process a TLS alert
                    126:  */
                    127: static status_t process_alert(private_tls_fragmentation_t *this,
                    128:                                                          bio_reader_t *reader)
                    129: {
                    130:        uint8_t level, description;
                    131: 
                    132:        if (!reader->read_uint8(reader, &level) ||
                    133:                !reader->read_uint8(reader, &description))
                    134:        {
                    135:                this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
                    136:                return NEED_MORE;
                    137:        }
                    138:        return this->alert->process(this->alert, level, description);
                    139: }
                    140: 
                    141: /**
                    142:  * Process TLS handshake protocol data
                    143:  */
                    144: static status_t process_handshake(private_tls_fragmentation_t *this,
                    145:                                                                  bio_reader_t *reader)
                    146: {
                    147:        while (reader->remaining(reader))
                    148:        {
                    149:                bio_reader_t *msg;
                    150:                uint8_t type;
                    151:                uint32_t len;
                    152:                status_t status;
                    153:                chunk_t data;
                    154: 
                    155:                if (reader->remaining(reader) > TLS_MAX_FRAGMENT_LEN)
                    156:                {
                    157:                        DBG1(DBG_TLS, "TLS fragment has invalid length");
                    158:                        this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
                    159:                        return NEED_MORE;
                    160:                }
                    161: 
                    162:                if (this->input.len == 0)
                    163:                {       /* new handshake message */
                    164:                        if (!reader->read_uint8(reader, &type) ||
                    165:                                !reader->read_uint24(reader, &len))
                    166:                        {
                    167:                                DBG1(DBG_TLS, "TLS handshake header invalid");
                    168:                                this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
                    169:                                return NEED_MORE;
                    170:                        }
                    171:                        this->type = type;
                    172:                        if (len > TLS_MAX_HANDSHAKE_LEN)
                    173:                        {
                    174:                                DBG1(DBG_TLS, "TLS handshake exceeds maximum length");
                    175:                                this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
                    176:                                return NEED_MORE;
                    177:                        }
                    178:                        chunk_free(&this->input);
                    179:                        this->inpos = 0;
                    180:                        if (len)
                    181:                        {
                    182:                                this->input = chunk_alloc(len);
                    183:                        }
                    184:                }
                    185: 
                    186:                len = min(this->input.len - this->inpos, reader->remaining(reader));
                    187:                if (!reader->read_data(reader, len, &data))
                    188:                {
                    189:                        DBG1(DBG_TLS, "TLS fragment has invalid length");
                    190:                        this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
                    191:                        return NEED_MORE;
                    192:                }
                    193:                memcpy(this->input.ptr + this->inpos, data.ptr, len);
                    194:                this->inpos += len;
                    195: 
                    196:                if (this->input.len == this->inpos)
                    197:                {       /* message completely defragmented, process */
                    198:                        msg = bio_reader_create(this->input);
                    199:                        DBG2(DBG_TLS, "received TLS %N handshake (%u bytes)",
                    200:                                 tls_handshake_type_names, this->type, this->input.len);
                    201:                        status = this->handshake->process(this->handshake, this->type, msg);
                    202:                        msg->destroy(msg);
                    203:                        chunk_free(&this->input);
                    204:                        if (status != NEED_MORE)
                    205:                        {
                    206:                                return status;
                    207:                        }
                    208:                }
                    209:                if (this->alert->fatal(this->alert))
                    210:                {
                    211:                        break;
                    212:                }
                    213:        }
                    214:        return NEED_MORE;
                    215: }
                    216: 
                    217: /**
                    218:  * Process TLS application data
                    219:  */
                    220: static status_t process_application(private_tls_fragmentation_t *this,
                    221:                                                                        bio_reader_t *reader)
                    222: {
                    223:        if (!this->handshake->finished(this->handshake))
                    224:        {
                    225:                DBG1(DBG_TLS, "received TLS application data, "
                    226:                         "but handshake not finished");
                    227:                return FAILED;
                    228:        }
                    229:        while (reader->remaining(reader))
                    230:        {
                    231:                status_t status;
                    232:                chunk_t data;
                    233: 
                    234:                if (reader->remaining(reader) > TLS_MAX_FRAGMENT_LEN)
                    235:                {
                    236:                        DBG1(DBG_TLS, "TLS fragment has invalid length");
                    237:                        this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
                    238:                        return NEED_MORE;
                    239:                }
                    240:                data = reader->peek(reader);
                    241:                DBG3(DBG_TLS, "%B", &data);
                    242:                status = this->application->process(this->application, reader);
                    243:                switch (status)
                    244:                {
                    245:                        case NEED_MORE:
                    246:                                continue;
                    247:                        case SUCCESS:
                    248:                                this->application_finished = TRUE;
                    249:                                if (!send_close_notify(this))
                    250:                                {
                    251:                                        return SUCCESS;
                    252:                                }
                    253:                                /* FALL */
                    254:                        case FAILED:
                    255:                        default:
                    256:                                this->alert->add(this->alert, TLS_FATAL, TLS_CLOSE_NOTIFY);
                    257:                                return NEED_MORE;
                    258:                }
                    259:        }
                    260:        return NEED_MORE;
                    261: }
                    262: 
                    263: METHOD(tls_fragmentation_t, process, status_t,
                    264:        private_tls_fragmentation_t *this, tls_content_type_t type, chunk_t data)
                    265: {
                    266:        bio_reader_t *reader;
                    267:        status_t status;
                    268: 
                    269:        switch (this->state)
                    270:        {
                    271:                case ALERT_SENDING:
                    272:                case ALERT_SENT:
                    273:                        /* don't accept more input, fatal error occurred */
                    274:                        return NEED_MORE;
                    275:                case ALERT_NONE:
                    276:                        break;
                    277:        }
                    278:        reader = bio_reader_create(data);
                    279:        switch (type)
                    280:        {
                    281:                case TLS_CHANGE_CIPHER_SPEC:
                    282:                        if (this->handshake->cipherspec_changed(this->handshake, TRUE))
                    283:                        {
                    284:                                this->handshake->change_cipherspec(this->handshake, TRUE);
                    285:                                status = NEED_MORE;
                    286:                                break;
                    287:                        }
                    288:                        status = FAILED;
                    289:                        break;
                    290:                case TLS_ALERT:
                    291:                        status = process_alert(this, reader);
                    292:                        break;
                    293:                case TLS_HANDSHAKE:
                    294:                        status = process_handshake(this, reader);
1.1.1.2 ! misho     295:                        if (!this->handshake->finished(this->handshake))
        !           296:                        {
        !           297:                                break;
        !           298:                        }
        !           299:                        /* fall-through */
1.1       misho     300:                case TLS_APPLICATION_DATA:
                    301:                        status = process_application(this, reader);
                    302:                        break;
                    303:                default:
                    304:                        DBG1(DBG_TLS, "received unknown TLS content type %d, ignored", type);
                    305:                        status = NEED_MORE;
                    306:                        break;
                    307:        }
                    308:        reader->destroy(reader);
                    309:        return status;
                    310: }
                    311: 
                    312: /**
                    313:  * Check if alerts are pending
                    314:  */
                    315: static bool check_alerts(private_tls_fragmentation_t *this, chunk_t *data)
                    316: {
                    317:        tls_alert_level_t level;
                    318:        tls_alert_desc_t desc;
                    319:        bio_writer_t *writer;
                    320: 
                    321:        if (this->alert->get(this->alert, &level, &desc))
                    322:        {
                    323:                writer = bio_writer_create(2);
                    324: 
                    325:                writer->write_uint8(writer, level);
                    326:                writer->write_uint8(writer, desc);
                    327: 
                    328:                *data = chunk_clone(writer->get_buf(writer));
                    329:                writer->destroy(writer);
                    330:                return TRUE;
                    331:        }
                    332:        return FALSE;
                    333: }
                    334: 
                    335: /**
                    336:  * Build handshake message
                    337:  */
                    338: static status_t build_handshake(private_tls_fragmentation_t *this)
                    339: {
                    340:        bio_writer_t *hs, *msg;
                    341:        tls_handshake_type_t type;
                    342:        status_t status;
                    343: 
                    344:        msg = bio_writer_create(64);
                    345:        while (TRUE)
                    346:        {
                    347:                hs = bio_writer_create(64);
                    348:                status = this->handshake->build(this->handshake, &type, hs);
                    349:                switch (status)
                    350:                {
                    351:                        case NEED_MORE:
                    352:                                if (this->alert->fatal(this->alert))
                    353:                                {
                    354:                                        break;
                    355:                                }
                    356:                                msg->write_uint8(msg, type);
                    357:                                msg->write_data24(msg, hs->get_buf(hs));
                    358:                                DBG2(DBG_TLS, "sending TLS %N handshake (%u bytes)",
                    359:                                         tls_handshake_type_names, type, hs->get_buf(hs).len);
1.1.1.2 ! misho     360:                                if (type != TLS_FINISHED &&
        !           361:                                        type != TLS_KEY_UPDATE &&
        !           362:                                        !this->handshake->cipherspec_changed(this->handshake, FALSE))
1.1       misho     363:                                {
                    364:                                        hs->destroy(hs);
                    365:                                        continue;
                    366:                                }
                    367:                                /* FALL */
                    368:                        case INVALID_STATE:
                    369:                                this->output_type = TLS_HANDSHAKE;
                    370:                                this->output = chunk_clone(msg->get_buf(msg));
                    371:                                break;
                    372:                        default:
                    373:                                break;
                    374:                }
                    375:                hs->destroy(hs);
                    376:                break;
                    377:        }
                    378:        msg->destroy(msg);
                    379:        return status;
                    380: }
                    381: 
                    382: /**
                    383:  * Build TLS application data
                    384:  */
                    385: static status_t build_application(private_tls_fragmentation_t *this)
                    386: {
                    387:        bio_writer_t *msg;
                    388:        status_t status;
                    389: 
                    390:        msg = bio_writer_create(64);
                    391:        while (TRUE)
                    392:        {
                    393:                status = this->application->build(this->application, msg);
                    394:                switch (status)
                    395:                {
                    396:                        case NEED_MORE:
                    397:                                continue;
                    398:                        case INVALID_STATE:
                    399:                                this->output_type = TLS_APPLICATION_DATA;
                    400:                                this->output = chunk_clone(msg->get_buf(msg));
                    401:                                break;
                    402:                        case SUCCESS:
                    403:                                this->application_finished = TRUE;
                    404:                                if (!send_close_notify(this))
                    405:                                {
                    406:                                        break;
                    407:                                }
                    408:                                /* FALL */
                    409:                        case FAILED:
                    410:                        default:
                    411:                                this->alert->add(this->alert, TLS_FATAL, TLS_CLOSE_NOTIFY);
                    412:                                break;
                    413:                }
                    414:                break;
                    415:        }
                    416:        msg->destroy(msg);
                    417:        return status;
                    418: }
                    419: 
                    420: METHOD(tls_fragmentation_t, build, status_t,
                    421:        private_tls_fragmentation_t *this, tls_content_type_t *type, chunk_t *data)
                    422: {
                    423:        status_t status = INVALID_STATE;
                    424: 
                    425:        switch (this->state)
                    426:        {
                    427:                case ALERT_SENDING:
                    428:                        this->state = ALERT_SENT;
                    429:                        return INVALID_STATE;
                    430:                case ALERT_SENT:
                    431:                        if (this->application_finished)
                    432:                        {
                    433:                                return SUCCESS;
                    434:                        }
                    435:                        return FAILED;
                    436:                case ALERT_NONE:
                    437:                        break;
                    438:        }
                    439:        if (check_alerts(this, data))
                    440:        {
                    441:                this->state = ALERT_SENDING;
                    442:                *type = TLS_ALERT;
                    443:                return NEED_MORE;
                    444:        }
                    445:        if (!this->output.len)
                    446:        {
                    447:                if (this->handshake->cipherspec_changed(this->handshake, FALSE))
                    448:                {
                    449:                        this->handshake->change_cipherspec(this->handshake, FALSE);
                    450:                        *type = TLS_CHANGE_CIPHER_SPEC;
                    451:                        *data = chunk_clone(chunk_from_chars(0x01));
                    452:                        return NEED_MORE;
                    453:                }
                    454:                if (!this->handshake->finished(this->handshake))
                    455:                {
                    456:                        status = build_handshake(this);
                    457:                }
                    458:                else if (this->application)
                    459:                {
                    460:                        status = build_application(this);
                    461:                }
                    462:                if (check_alerts(this, data))
                    463:                {
                    464:                        this->state = ALERT_SENDING;
                    465:                        *type = TLS_ALERT;
                    466:                        return NEED_MORE;
                    467:                }
                    468:        }
                    469:        if (this->output.len)
                    470:        {
                    471:                *type = this->output_type;
                    472:                if (this->output.len <= TLS_MAX_FRAGMENT_LEN)
                    473:                {
                    474:                        *data = this->output;
                    475:                        this->output = chunk_empty;
                    476:                        return NEED_MORE;
                    477:                }
                    478:                *data = chunk_create(this->output.ptr, TLS_MAX_FRAGMENT_LEN);
                    479:                this->output = chunk_clone(chunk_skip(this->output, TLS_MAX_FRAGMENT_LEN));
                    480:                return NEED_MORE;
                    481:        }
                    482:        return status;
                    483: }
                    484: 
                    485: METHOD(tls_fragmentation_t, application_finished, bool,
                    486:        private_tls_fragmentation_t *this)
                    487: {
                    488:        return this->application_finished;
                    489: }
                    490: 
                    491: METHOD(tls_fragmentation_t, destroy, void,
                    492:        private_tls_fragmentation_t *this)
                    493: {
                    494:        free(this->input.ptr);
                    495:        free(this->output.ptr);
                    496:        free(this);
                    497: }
                    498: 
                    499: /**
                    500:  * See header
                    501:  */
                    502: tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake,
                    503:                                                        tls_alert_t *alert, tls_application_t *application,
                    504:                                                        tls_purpose_t purpose)
                    505: {
                    506:        private_tls_fragmentation_t *this;
                    507: 
                    508:        INIT(this,
                    509:                .public = {
                    510:                        .process = _process,
                    511:                        .build = _build,
                    512:                        .application_finished = _application_finished,
                    513:                        .destroy = _destroy,
                    514:                },
                    515:                .handshake = handshake,
                    516:                .alert = alert,
                    517:                .state = ALERT_NONE,
                    518:                .application = application,
                    519:                .purpose = purpose,
                    520:        );
                    521: 
                    522:        return &this->public;
                    523: }

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