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

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);
                    295:                        break;
                    296:                case TLS_APPLICATION_DATA:
                    297:                        status = process_application(this, reader);
                    298:                        break;
                    299:                default:
                    300:                        DBG1(DBG_TLS, "received unknown TLS content type %d, ignored", type);
                    301:                        status = NEED_MORE;
                    302:                        break;
                    303:        }
                    304:        reader->destroy(reader);
                    305:        return status;
                    306: }
                    307: 
                    308: /**
                    309:  * Check if alerts are pending
                    310:  */
                    311: static bool check_alerts(private_tls_fragmentation_t *this, chunk_t *data)
                    312: {
                    313:        tls_alert_level_t level;
                    314:        tls_alert_desc_t desc;
                    315:        bio_writer_t *writer;
                    316: 
                    317:        if (this->alert->get(this->alert, &level, &desc))
                    318:        {
                    319:                writer = bio_writer_create(2);
                    320: 
                    321:                writer->write_uint8(writer, level);
                    322:                writer->write_uint8(writer, desc);
                    323: 
                    324:                *data = chunk_clone(writer->get_buf(writer));
                    325:                writer->destroy(writer);
                    326:                return TRUE;
                    327:        }
                    328:        return FALSE;
                    329: }
                    330: 
                    331: /**
                    332:  * Build handshake message
                    333:  */
                    334: static status_t build_handshake(private_tls_fragmentation_t *this)
                    335: {
                    336:        bio_writer_t *hs, *msg;
                    337:        tls_handshake_type_t type;
                    338:        status_t status;
                    339: 
                    340:        msg = bio_writer_create(64);
                    341:        while (TRUE)
                    342:        {
                    343:                hs = bio_writer_create(64);
                    344:                status = this->handshake->build(this->handshake, &type, hs);
                    345:                switch (status)
                    346:                {
                    347:                        case NEED_MORE:
                    348:                                if (this->alert->fatal(this->alert))
                    349:                                {
                    350:                                        break;
                    351:                                }
                    352:                                msg->write_uint8(msg, type);
                    353:                                msg->write_data24(msg, hs->get_buf(hs));
                    354:                                DBG2(DBG_TLS, "sending TLS %N handshake (%u bytes)",
                    355:                                         tls_handshake_type_names, type, hs->get_buf(hs).len);
                    356:                                if (!this->handshake->cipherspec_changed(this->handshake, FALSE))
                    357:                                {
                    358:                                        hs->destroy(hs);
                    359:                                        continue;
                    360:                                }
                    361:                                /* FALL */
                    362:                        case INVALID_STATE:
                    363:                                this->output_type = TLS_HANDSHAKE;
                    364:                                this->output = chunk_clone(msg->get_buf(msg));
                    365:                                break;
                    366:                        default:
                    367:                                break;
                    368:                }
                    369:                hs->destroy(hs);
                    370:                break;
                    371:        }
                    372:        msg->destroy(msg);
                    373:        return status;
                    374: }
                    375: 
                    376: /**
                    377:  * Build TLS application data
                    378:  */
                    379: static status_t build_application(private_tls_fragmentation_t *this)
                    380: {
                    381:        bio_writer_t *msg;
                    382:        status_t status;
                    383: 
                    384:        msg = bio_writer_create(64);
                    385:        while (TRUE)
                    386:        {
                    387:                status = this->application->build(this->application, msg);
                    388:                switch (status)
                    389:                {
                    390:                        case NEED_MORE:
                    391:                                continue;
                    392:                        case INVALID_STATE:
                    393:                                this->output_type = TLS_APPLICATION_DATA;
                    394:                                this->output = chunk_clone(msg->get_buf(msg));
                    395:                                break;
                    396:                        case SUCCESS:
                    397:                                this->application_finished = TRUE;
                    398:                                if (!send_close_notify(this))
                    399:                                {
                    400:                                        break;
                    401:                                }
                    402:                                /* FALL */
                    403:                        case FAILED:
                    404:                        default:
                    405:                                this->alert->add(this->alert, TLS_FATAL, TLS_CLOSE_NOTIFY);
                    406:                                break;
                    407:                }
                    408:                break;
                    409:        }
                    410:        msg->destroy(msg);
                    411:        return status;
                    412: }
                    413: 
                    414: METHOD(tls_fragmentation_t, build, status_t,
                    415:        private_tls_fragmentation_t *this, tls_content_type_t *type, chunk_t *data)
                    416: {
                    417:        status_t status = INVALID_STATE;
                    418: 
                    419:        switch (this->state)
                    420:        {
                    421:                case ALERT_SENDING:
                    422:                        this->state = ALERT_SENT;
                    423:                        return INVALID_STATE;
                    424:                case ALERT_SENT:
                    425:                        if (this->application_finished)
                    426:                        {
                    427:                                return SUCCESS;
                    428:                        }
                    429:                        return FAILED;
                    430:                case ALERT_NONE:
                    431:                        break;
                    432:        }
                    433:        if (check_alerts(this, data))
                    434:        {
                    435:                this->state = ALERT_SENDING;
                    436:                *type = TLS_ALERT;
                    437:                return NEED_MORE;
                    438:        }
                    439:        if (!this->output.len)
                    440:        {
                    441:                if (this->handshake->cipherspec_changed(this->handshake, FALSE))
                    442:                {
                    443:                        this->handshake->change_cipherspec(this->handshake, FALSE);
                    444:                        *type = TLS_CHANGE_CIPHER_SPEC;
                    445:                        *data = chunk_clone(chunk_from_chars(0x01));
                    446:                        return NEED_MORE;
                    447:                }
                    448:                if (!this->handshake->finished(this->handshake))
                    449:                {
                    450:                        status = build_handshake(this);
                    451:                }
                    452:                else if (this->application)
                    453:                {
                    454:                        status = build_application(this);
                    455:                }
                    456:                if (check_alerts(this, data))
                    457:                {
                    458:                        this->state = ALERT_SENDING;
                    459:                        *type = TLS_ALERT;
                    460:                        return NEED_MORE;
                    461:                }
                    462:        }
                    463:        if (this->output.len)
                    464:        {
                    465:                *type = this->output_type;
                    466:                if (this->output.len <= TLS_MAX_FRAGMENT_LEN)
                    467:                {
                    468:                        *data = this->output;
                    469:                        this->output = chunk_empty;
                    470:                        return NEED_MORE;
                    471:                }
                    472:                *data = chunk_create(this->output.ptr, TLS_MAX_FRAGMENT_LEN);
                    473:                this->output = chunk_clone(chunk_skip(this->output, TLS_MAX_FRAGMENT_LEN));
                    474:                return NEED_MORE;
                    475:        }
                    476:        return status;
                    477: }
                    478: 
                    479: METHOD(tls_fragmentation_t, application_finished, bool,
                    480:        private_tls_fragmentation_t *this)
                    481: {
                    482:        return this->application_finished;
                    483: }
                    484: 
                    485: METHOD(tls_fragmentation_t, destroy, void,
                    486:        private_tls_fragmentation_t *this)
                    487: {
                    488:        free(this->input.ptr);
                    489:        free(this->output.ptr);
                    490:        free(this);
                    491: }
                    492: 
                    493: /**
                    494:  * See header
                    495:  */
                    496: tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake,
                    497:                                                        tls_alert_t *alert, tls_application_t *application,
                    498:                                                        tls_purpose_t purpose)
                    499: {
                    500:        private_tls_fragmentation_t *this;
                    501: 
                    502:        INIT(this,
                    503:                .public = {
                    504:                        .process = _process,
                    505:                        .build = _build,
                    506:                        .application_finished = _application_finished,
                    507:                        .destroy = _destroy,
                    508:                },
                    509:                .handshake = handshake,
                    510:                .alert = alert,
                    511:                .state = ALERT_NONE,
                    512:                .application = application,
                    513:                .purpose = purpose,
                    514:        );
                    515: 
                    516:        return &this->public;
                    517: }

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