Annotation of embedaddon/strongswan/src/libtls/tls.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.h"
                     17: 
                     18: #include <utils/debug.h>
                     19: 
                     20: #include "tls_protection.h"
                     21: #include "tls_compression.h"
                     22: #include "tls_fragmentation.h"
                     23: #include "tls_crypto.h"
                     24: #include "tls_server.h"
                     25: #include "tls_peer.h"
                     26: 
                     27: ENUM_BEGIN(tls_version_names, SSL_2_0, SSL_2_0,
                     28:        "SSLv2");
                     29: ENUM_NEXT(tls_version_names, SSL_3_0, TLS_1_2, SSL_2_0,
                     30:        "SSLv3",
                     31:        "TLS 1.0",
                     32:        "TLS 1.1",
                     33:        "TLS 1.2");
                     34: ENUM_END(tls_version_names, TLS_1_2);
                     35: 
                     36: ENUM(tls_content_type_names, TLS_CHANGE_CIPHER_SPEC, TLS_APPLICATION_DATA,
                     37:        "ChangeCipherSpec",
                     38:        "Alert",
                     39:        "Handshake",
                     40:        "ApplicationData",
                     41: );
                     42: 
                     43: ENUM_BEGIN(tls_handshake_type_names, TLS_HELLO_REQUEST, TLS_SERVER_HELLO,
                     44:        "HelloRequest",
                     45:        "ClientHello",
                     46:        "ServerHello");
                     47: ENUM_NEXT(tls_handshake_type_names,
                     48:                TLS_CERTIFICATE, TLS_CLIENT_KEY_EXCHANGE, TLS_SERVER_HELLO,
                     49:        "Certificate",
                     50:        "ServerKeyExchange",
                     51:        "CertificateRequest",
                     52:        "ServerHelloDone",
                     53:        "CertificateVerify",
                     54:        "ClientKeyExchange");
                     55: ENUM_NEXT(tls_handshake_type_names,
                     56:                TLS_FINISHED, TLS_FINISHED, TLS_CLIENT_KEY_EXCHANGE,
                     57:        "Finished");
                     58: ENUM_END(tls_handshake_type_names, TLS_FINISHED);
                     59: 
                     60: ENUM_BEGIN(tls_extension_names, TLS_EXT_SERVER_NAME, TLS_EXT_STATUS_REQUEST,
                     61:        "server name",
                     62:        "max fragment length",
                     63:        "client certificate url",
                     64:        "trusted ca keys",
                     65:        "truncated hmac",
                     66:        "status request");
                     67: ENUM_NEXT(tls_extension_names,
                     68:                TLS_EXT_ELLIPTIC_CURVES, TLS_EXT_EC_POINT_FORMATS,
                     69:                TLS_EXT_STATUS_REQUEST,
                     70:        "elliptic curves",
                     71:        "ec point formats");
                     72: ENUM_NEXT(tls_extension_names,
                     73:                TLS_EXT_SIGNATURE_ALGORITHMS, TLS_EXT_SIGNATURE_ALGORITHMS,
                     74:                TLS_EXT_EC_POINT_FORMATS,
                     75:        "signature algorithms");
                     76: ENUM_NEXT(tls_extension_names,
                     77:                TLS_EXT_RENEGOTIATION_INFO, TLS_EXT_RENEGOTIATION_INFO,
                     78:                TLS_EXT_SIGNATURE_ALGORITHMS,
                     79:        "renegotiation info");
                     80: ENUM_END(tls_extension_names, TLS_EXT_RENEGOTIATION_INFO);
                     81: 
                     82: /**
                     83:  * TLS record
                     84:  */
                     85: typedef struct __attribute__((packed)) {
                     86:        uint8_t type;
                     87:        uint16_t version;
                     88:        uint16_t length;
                     89:        char data[];
                     90: } tls_record_t;
                     91: 
                     92: typedef struct private_tls_t private_tls_t;
                     93: 
                     94: /**
                     95:  * Private data of an tls_protection_t object.
                     96:  */
                     97: struct private_tls_t {
                     98: 
                     99:        /**
                    100:         * Public tls_t interface.
                    101:         */
                    102:        tls_t public;
                    103: 
                    104:        /**
                    105:         * Role this TLS stack acts as.
                    106:         */
                    107:        bool is_server;
                    108: 
                    109:        /**
                    110:         * Negotiated TLS version
                    111:         */
                    112:        tls_version_t version;
                    113: 
                    114:        /**
                    115:         * TLS stack purpose, as given to constructor
                    116:         */
                    117:        tls_purpose_t purpose;
                    118: 
                    119:        /**
                    120:         * TLS record protection layer
                    121:         */
                    122:        tls_protection_t *protection;
                    123: 
                    124:        /**
                    125:         * TLS record compression layer
                    126:         */
                    127:        tls_compression_t *compression;
                    128: 
                    129:        /**
                    130:         * TLS record fragmentation layer
                    131:         */
                    132:        tls_fragmentation_t *fragmentation;
                    133: 
                    134:        /**
                    135:         * TLS alert handler
                    136:         */
                    137:        tls_alert_t *alert;
                    138: 
                    139:        /**
                    140:         * TLS crypto helper context
                    141:         */
                    142:        tls_crypto_t *crypto;
                    143: 
                    144:        /**
                    145:         * TLS handshake protocol handler
                    146:         */
                    147:        tls_handshake_t *handshake;
                    148: 
                    149:        /**
                    150:         * TLS application data handler
                    151:         */
                    152:        tls_application_t *application;
                    153: 
                    154:        /**
                    155:         * Allocated input buffer
                    156:         */
                    157:        chunk_t input;
                    158: 
                    159:        /**
                    160:         * Number of bytes read in input buffer
                    161:         */
                    162:        size_t inpos;
                    163: 
                    164:        /**
                    165:         * Allocated output buffer
                    166:         */
                    167:        chunk_t output;
                    168: 
                    169:        /**
                    170:         * Number of bytes processed from output buffer
                    171:         */
                    172:        size_t outpos;
                    173: 
                    174:        /**
                    175:         * Position in partially received record header
                    176:         */
                    177:        size_t headpos;
                    178: 
                    179:        /**
                    180:         * Partial TLS record header received
                    181:         */
                    182:        tls_record_t head;
                    183: };
                    184: 
                    185: /**
                    186:  * Described in header.
                    187:  */
                    188: void libtls_init(void)
                    189: {
                    190:        /* empty */
                    191: }
                    192: 
                    193: METHOD(tls_t, process, status_t,
                    194:        private_tls_t *this, void *buf, size_t buflen)
                    195: {
                    196:        tls_record_t *record;
                    197:        status_t status;
                    198:        u_int len;
                    199: 
                    200:        if (this->headpos)
                    201:        {       /* have a partial TLS record header, try to complete it */
                    202:                len = min(buflen, sizeof(this->head) - this->headpos);
                    203:                memcpy(((char*)&this->head) + this->headpos, buf, len);
                    204:                this->headpos += len;
                    205:                buflen -= len;
                    206:                buf += len;
                    207:                if (this->headpos == sizeof(this->head))
                    208:                {       /* header complete, allocate space with new header */
                    209:                        len = untoh16(&this->head.length);
                    210:                        this->input = chunk_alloc(len + sizeof(tls_record_t));
                    211:                        memcpy(this->input.ptr, &this->head, sizeof(this->head));
                    212:                        this->inpos = sizeof(this->head);
                    213:                        this->headpos = 0;
                    214:                }
                    215:        }
                    216: 
                    217:        while (buflen)
                    218:        {
                    219:                if (this->input.len == 0)
                    220:                {
                    221:                        while (buflen >= sizeof(tls_record_t))
                    222:                        {
                    223:                                /* try to process records inline */
                    224:                                record = buf;
                    225:                                len = untoh16(&record->length);
                    226: 
                    227:                                if (len + sizeof(tls_record_t) > buflen)
                    228:                                {       /* not a full record, read to buffer */
                    229:                                        this->input = chunk_alloc(len + sizeof(tls_record_t));
                    230:                                        this->inpos = 0;
                    231:                                        break;
                    232:                                }
                    233:                                DBG2(DBG_TLS, "processing TLS %N record (%d bytes)",
                    234:                                         tls_content_type_names, record->type, len);
                    235:                                status = this->protection->process(this->protection,
                    236:                                                                record->type, chunk_create(record->data, len));
                    237:                                if (status != NEED_MORE)
                    238:                                {
                    239:                                        return status;
                    240:                                }
                    241:                                buf += len + sizeof(tls_record_t);
                    242:                                buflen -= len + sizeof(tls_record_t);
                    243:                                if (buflen == 0)
                    244:                                {
                    245:                                        return NEED_MORE;
                    246:                                }
                    247:                        }
                    248:                        if (buflen < sizeof(tls_record_t))
                    249:                        {
                    250:                                DBG2(DBG_TLS, "received incomplete TLS record header");
                    251:                                memcpy(&this->head, buf, buflen);
                    252:                                this->headpos = buflen;
                    253:                                break;
                    254:                        }
                    255:                }
                    256:                len = min(buflen, this->input.len - this->inpos);
                    257:                memcpy(this->input.ptr + this->inpos, buf, len);
                    258:                buf += len;
                    259:                buflen -= len;
                    260:                this->inpos += len;
                    261:                DBG2(DBG_TLS, "buffering %d bytes, %d bytes of %d byte TLS record received",
                    262:                         len, this->inpos, this->input.len);
                    263:                if (this->input.len == this->inpos)
                    264:                {
                    265:                        record = (tls_record_t*)this->input.ptr;
                    266:                        len = untoh16(&record->length);
                    267: 
                    268:                        DBG2(DBG_TLS, "processing buffered TLS %N record (%d bytes)",
                    269:                                 tls_content_type_names, record->type, len);
                    270:                        status = this->protection->process(this->protection,
                    271:                                                                record->type, chunk_create(record->data, len));
                    272:                        chunk_free(&this->input);
                    273:                        this->inpos = 0;
                    274:                        if (status != NEED_MORE)
                    275:                        {
                    276:                                return status;
                    277:                        }
                    278:                }
                    279:        }
                    280:        return NEED_MORE;
                    281: }
                    282: 
                    283: METHOD(tls_t, build, status_t,
                    284:        private_tls_t *this, void *buf, size_t *buflen, size_t *msglen)
                    285: {
                    286:        tls_content_type_t type;
                    287:        tls_record_t record;
                    288:        status_t status;
                    289:        chunk_t data;
                    290:        size_t len;
                    291: 
                    292:        len = *buflen;
                    293:        if (this->output.len == 0)
                    294:        {
                    295:                /* query upper layers for new records, as many as we can get */
                    296:                while (TRUE)
                    297:                {
                    298:                        status = this->protection->build(this->protection, &type, &data);
                    299:                        switch (status)
                    300:                        {
                    301:                                case NEED_MORE:
                    302:                                        record.type = type;
                    303:                                        htoun16(&record.version, this->version);
                    304:                                        htoun16(&record.length, data.len);
                    305:                                        this->output = chunk_cat("mcm", this->output,
                    306:                                                                                         chunk_from_thing(record), data);
                    307:                                        DBG2(DBG_TLS, "sending TLS %N record (%d bytes)",
                    308:                                                 tls_content_type_names, type, data.len);
                    309:                                        continue;
                    310:                                case INVALID_STATE:
                    311:                                        if (this->output.len == 0)
                    312:                                        {
                    313:                                                return INVALID_STATE;
                    314:                                        }
                    315:                                        break;
                    316:                                default:
                    317:                                        return status;
                    318:                        }
                    319:                        break;
                    320:                }
                    321:                if (msglen)
                    322:                {
                    323:                        *msglen = this->output.len;
                    324:                }
                    325:        }
                    326:        else
                    327:        {
                    328:                if (msglen)
                    329:                {
                    330:                        *msglen = 0;
                    331:                }
                    332:        }
                    333:        len = min(len, this->output.len - this->outpos);
                    334:        memcpy(buf, this->output.ptr + this->outpos, len);
                    335:        this->outpos += len;
                    336:        *buflen = len;
                    337:        if (this->outpos == this->output.len)
                    338:        {
                    339:                chunk_free(&this->output);
                    340:                this->outpos = 0;
                    341:                return ALREADY_DONE;
                    342:        }
                    343:        return NEED_MORE;
                    344: }
                    345: 
                    346: METHOD(tls_t, is_server, bool,
                    347:        private_tls_t *this)
                    348: {
                    349:        return this->is_server;
                    350: }
                    351: 
                    352: METHOD(tls_t, get_server_id, identification_t*,
                    353:        private_tls_t *this)
                    354: {
                    355:        return this->handshake->get_server_id(this->handshake);
                    356: }
                    357: 
                    358: METHOD(tls_t, get_peer_id, identification_t*,
                    359:        private_tls_t *this)
                    360: {
                    361:        return this->handshake->get_peer_id(this->handshake);
                    362: }
                    363: 
                    364: METHOD(tls_t, get_version, tls_version_t,
                    365:        private_tls_t *this)
                    366: {
                    367:        return this->version;
                    368: }
                    369: 
                    370: METHOD(tls_t, set_version, bool,
                    371:        private_tls_t *this, tls_version_t version)
                    372: {
                    373:        if (version > this->version)
                    374:        {
                    375:                return FALSE;
                    376:        }
                    377:        switch (version)
                    378:        {
                    379:                case TLS_1_0:
                    380:                case TLS_1_1:
                    381:                case TLS_1_2:
                    382:                        this->version = version;
                    383:                        this->protection->set_version(this->protection, version);
                    384:                        return TRUE;
                    385:                case SSL_2_0:
                    386:                case SSL_3_0:
                    387:                default:
                    388:                        return FALSE;
                    389:        }
                    390: }
                    391: 
                    392: METHOD(tls_t, get_purpose, tls_purpose_t,
                    393:        private_tls_t *this)
                    394: {
                    395:        return this->purpose;
                    396: }
                    397: 
                    398: METHOD(tls_t, is_complete, bool,
                    399:        private_tls_t *this)
                    400: {
                    401:        if (this->handshake->finished(this->handshake))
                    402:        {
                    403:                if (!this->application)
                    404:                {
                    405:                        return TRUE;
                    406:                }
                    407:                return this->fragmentation->application_finished(this->fragmentation);
                    408:        }
                    409:        return FALSE;
                    410: }
                    411: 
                    412: METHOD(tls_t, get_eap_msk, chunk_t,
                    413:        private_tls_t *this)
                    414: {
                    415:        return this->crypto->get_eap_msk(this->crypto);
                    416: }
                    417: 
                    418: METHOD(tls_t, get_auth, auth_cfg_t*,
                    419:        private_tls_t *this)
                    420: {
                    421:        return this->handshake->get_auth(this->handshake);
                    422: }
                    423: 
                    424: METHOD(tls_t, destroy, void,
                    425:        private_tls_t *this)
                    426: {
                    427:        this->protection->destroy(this->protection);
                    428:        this->compression->destroy(this->compression);
                    429:        this->fragmentation->destroy(this->fragmentation);
                    430:        this->crypto->destroy(this->crypto);
                    431:        this->handshake->destroy(this->handshake);
                    432:        DESTROY_IF(this->application);
                    433:        this->alert->destroy(this->alert);
                    434: 
                    435:        free(this->input.ptr);
                    436:        free(this->output.ptr);
                    437: 
                    438:        free(this);
                    439: }
                    440: 
                    441: /**
                    442:  * See header
                    443:  */
                    444: tls_t *tls_create(bool is_server, identification_t *server,
                    445:                                  identification_t *peer, tls_purpose_t purpose,
                    446:                                  tls_application_t *application, tls_cache_t *cache)
                    447: {
                    448:        private_tls_t *this;
                    449: 
                    450:        switch (purpose)
                    451:        {
                    452:                case TLS_PURPOSE_EAP_TLS:
                    453:                case TLS_PURPOSE_EAP_TTLS:
                    454:                case TLS_PURPOSE_EAP_PEAP:
                    455:                case TLS_PURPOSE_GENERIC:
                    456:                case TLS_PURPOSE_GENERIC_NULLOK:
                    457:                        break;
                    458:                default:
                    459:                        return NULL;
                    460:        }
                    461: 
                    462:        INIT(this,
                    463:                .public = {
                    464:                        .process = _process,
                    465:                        .build = _build,
                    466:                        .is_server = _is_server,
                    467:                        .get_server_id = _get_server_id,
                    468:                        .get_peer_id = _get_peer_id,
                    469:                        .get_version = _get_version,
                    470:                        .set_version = _set_version,
                    471:                        .get_purpose = _get_purpose,
                    472:                        .is_complete = _is_complete,
                    473:                        .get_eap_msk = _get_eap_msk,
                    474:                        .get_auth = _get_auth,
                    475:                        .destroy = _destroy,
                    476:                },
                    477:                .is_server = is_server,
                    478:                .version = TLS_1_2,
                    479:                .application = application,
                    480:                .purpose = purpose,
                    481:        );
                    482:        lib->settings->add_fallback(lib->settings, "%s.tls", "libtls", lib->ns);
                    483: 
                    484:        this->crypto = tls_crypto_create(&this->public, cache);
                    485:        this->alert = tls_alert_create();
                    486:        if (is_server)
                    487:        {
                    488:                this->handshake = &tls_server_create(&this->public, this->crypto,
                    489:                                                                                this->alert, server, peer)->handshake;
                    490:        }
                    491:        else
                    492:        {
                    493:                this->handshake = &tls_peer_create(&this->public, this->crypto,
                    494:                                                                                this->alert, peer, server)->handshake;
                    495:        }
                    496:        this->fragmentation = tls_fragmentation_create(this->handshake, this->alert,
                    497:                                                                                                   this->application, purpose);
                    498:        this->compression = tls_compression_create(this->fragmentation, this->alert);
                    499:        this->protection = tls_protection_create(this->compression, this->alert);
                    500:        this->crypto->set_protection(this->crypto, this->protection);
                    501: 
                    502:        return &this->public;
                    503: }

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