Annotation of embedaddon/strongswan/src/libtls/tls.c, revision 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>