Annotation of embedaddon/strongswan/src/libtls/tls_peer.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_peer.h"
        !            17: 
        !            18: #include <utils/debug.h>
        !            19: #include <credentials/certificates/x509.h>
        !            20: 
        !            21: #include <time.h>
        !            22: 
        !            23: typedef struct private_tls_peer_t private_tls_peer_t;
        !            24: 
        !            25: typedef enum {
        !            26:        STATE_INIT,
        !            27:        STATE_HELLO_SENT,
        !            28:        STATE_HELLO_RECEIVED,
        !            29:        STATE_HELLO_DONE,
        !            30:        STATE_CERT_SENT,
        !            31:        STATE_CERT_RECEIVED,
        !            32:        STATE_KEY_EXCHANGE_RECEIVED,
        !            33:        STATE_CERTREQ_RECEIVED,
        !            34:        STATE_KEY_EXCHANGE_SENT,
        !            35:        STATE_VERIFY_SENT,
        !            36:        STATE_CIPHERSPEC_CHANGED_OUT,
        !            37:        STATE_FINISHED_SENT,
        !            38:        STATE_CIPHERSPEC_CHANGED_IN,
        !            39:        STATE_FINISHED_RECEIVED,
        !            40: } peer_state_t;
        !            41: 
        !            42: /**
        !            43:  * Private data of an tls_peer_t object.
        !            44:  */
        !            45: struct private_tls_peer_t {
        !            46: 
        !            47:        /**
        !            48:         * Public tls_peer_t interface.
        !            49:         */
        !            50:        tls_peer_t public;
        !            51: 
        !            52:        /**
        !            53:         * TLS stack
        !            54:         */
        !            55:        tls_t *tls;
        !            56: 
        !            57:        /**
        !            58:         * TLS crypto context
        !            59:         */
        !            60:        tls_crypto_t *crypto;
        !            61: 
        !            62:        /**
        !            63:         * TLS alert handler
        !            64:         */
        !            65:        tls_alert_t *alert;
        !            66: 
        !            67:        /**
        !            68:         * Peer identity, NULL for no client authentication
        !            69:         */
        !            70:        identification_t *peer;
        !            71: 
        !            72:        /**
        !            73:         * Server identity
        !            74:         */
        !            75:        identification_t *server;
        !            76: 
        !            77:        /**
        !            78:         * State we are in
        !            79:         */
        !            80:        peer_state_t state;
        !            81: 
        !            82:        /**
        !            83:         * TLS version we offered in hello
        !            84:         */
        !            85:        tls_version_t hello_version;
        !            86: 
        !            87:        /**
        !            88:         * Hello random data selected by client
        !            89:         */
        !            90:        char client_random[32];
        !            91: 
        !            92:        /**
        !            93:         * Hello random data selected by server
        !            94:         */
        !            95:        char server_random[32];
        !            96: 
        !            97:        /**
        !            98:         * Auth helper for peer authentication
        !            99:         */
        !           100:        auth_cfg_t *peer_auth;
        !           101: 
        !           102:        /**
        !           103:         * Auth helper for server authentication
        !           104:         */
        !           105:        auth_cfg_t *server_auth;
        !           106: 
        !           107:        /**
        !           108:         * Peer private key
        !           109:         */
        !           110:        private_key_t *private;
        !           111: 
        !           112:        /**
        !           113:         * DHE exchange
        !           114:         */
        !           115:        diffie_hellman_t *dh;
        !           116: 
        !           117:        /**
        !           118:         * Resuming a session?
        !           119:         */
        !           120:        bool resume;
        !           121: 
        !           122:        /**
        !           123:         * TLS session identifier
        !           124:         */
        !           125:        chunk_t session;
        !           126: 
        !           127:        /**
        !           128:         * List of server-supported hashsig algorithms
        !           129:         */
        !           130:        chunk_t hashsig;
        !           131: 
        !           132:        /**
        !           133:         * List of server-supported client certificate types
        !           134:         */
        !           135:        chunk_t cert_types;
        !           136: };
        !           137: 
        !           138: /**
        !           139:  * Process a server hello message
        !           140:  */
        !           141: static status_t process_server_hello(private_tls_peer_t *this,
        !           142:                                                                         bio_reader_t *reader)
        !           143: {
        !           144:        uint8_t compression;
        !           145:        uint16_t version, cipher;
        !           146:        chunk_t random, session, ext = chunk_empty;
        !           147:        tls_cipher_suite_t suite = 0;
        !           148: 
        !           149:        this->crypto->append_handshake(this->crypto,
        !           150:                                                                   TLS_SERVER_HELLO, reader->peek(reader));
        !           151: 
        !           152:        if (!reader->read_uint16(reader, &version) ||
        !           153:                !reader->read_data(reader, sizeof(this->server_random), &random) ||
        !           154:                !reader->read_data8(reader, &session) ||
        !           155:                !reader->read_uint16(reader, &cipher) ||
        !           156:                !reader->read_uint8(reader, &compression) ||
        !           157:                (reader->remaining(reader) && !reader->read_data16(reader, &ext)))
        !           158:        {
        !           159:                DBG1(DBG_TLS, "received invalid ServerHello");
        !           160:                this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
        !           161:                return NEED_MORE;
        !           162:        }
        !           163: 
        !           164:        memcpy(this->server_random, random.ptr, sizeof(this->server_random));
        !           165: 
        !           166:        if (!this->tls->set_version(this->tls, version))
        !           167:        {
        !           168:                DBG1(DBG_TLS, "negotiated version %N not supported",
        !           169:                         tls_version_names, version);
        !           170:                this->alert->add(this->alert, TLS_FATAL, TLS_PROTOCOL_VERSION);
        !           171:                return NEED_MORE;
        !           172:        }
        !           173: 
        !           174:        if (chunk_equals(this->session, session))
        !           175:        {
        !           176:                suite = this->crypto->resume_session(this->crypto, session, this->server,
        !           177:                                                                                chunk_from_thing(this->client_random),
        !           178:                                                                                chunk_from_thing(this->server_random));
        !           179:                if (suite)
        !           180:                {
        !           181:                        DBG1(DBG_TLS, "resumed %N using suite %N",
        !           182:                                 tls_version_names, version, tls_cipher_suite_names, suite);
        !           183:                        this->resume = TRUE;
        !           184:                }
        !           185:        }
        !           186:        if (!suite)
        !           187:        {
        !           188:                suite = cipher;
        !           189:                if (!this->crypto->select_cipher_suite(this->crypto, &suite, 1, KEY_ANY))
        !           190:                {
        !           191:                        DBG1(DBG_TLS, "received TLS cipher suite %N unacceptable",
        !           192:                                 tls_cipher_suite_names, suite);
        !           193:                        this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
        !           194:                        return NEED_MORE;
        !           195:                }
        !           196:                DBG1(DBG_TLS, "negotiated %N using suite %N",
        !           197:                         tls_version_names, version, tls_cipher_suite_names, suite);
        !           198:                free(this->session.ptr);
        !           199:                this->session = chunk_clone(session);
        !           200:        }
        !           201:        this->state = STATE_HELLO_RECEIVED;
        !           202:        return NEED_MORE;
        !           203: }
        !           204: 
        !           205: /**
        !           206:  * Check if a server certificate is acceptable for the given server identity
        !           207:  */
        !           208: static bool check_certificate(private_tls_peer_t *this, certificate_t *cert)
        !           209: {
        !           210:        identification_t *id;
        !           211: 
        !           212:        if (cert->has_subject(cert, this->server))
        !           213:        {
        !           214:                return TRUE;
        !           215:        }
        !           216:        id = cert->get_subject(cert);
        !           217:        if (id->matches(id, this->server))
        !           218:        {
        !           219:                return TRUE;
        !           220:        }
        !           221:        if (cert->get_type(cert) == CERT_X509)
        !           222:        {
        !           223:                x509_t *x509 = (x509_t*)cert;
        !           224:                enumerator_t *enumerator;
        !           225: 
        !           226:                enumerator = x509->create_subjectAltName_enumerator(x509);
        !           227:                while (enumerator->enumerate(enumerator, &id))
        !           228:                {
        !           229:                        if (id->matches(id, this->server))
        !           230:                        {
        !           231:                                enumerator->destroy(enumerator);
        !           232:                                return TRUE;
        !           233:                        }
        !           234:                }
        !           235:                enumerator->destroy(enumerator);
        !           236:        }
        !           237:        DBG1(DBG_TLS, "server certificate does not match to '%Y'", this->server);
        !           238:        return FALSE;
        !           239: }
        !           240: 
        !           241: /**
        !           242:  * Process a Certificate message
        !           243:  */
        !           244: static status_t process_certificate(private_tls_peer_t *this,
        !           245:                                                                        bio_reader_t *reader)
        !           246: {
        !           247:        certificate_t *cert;
        !           248:        bio_reader_t *certs;
        !           249:        chunk_t data;
        !           250:        bool first = TRUE;
        !           251: 
        !           252:        this->crypto->append_handshake(this->crypto,
        !           253:                                                                   TLS_CERTIFICATE, reader->peek(reader));
        !           254: 
        !           255:        if (!reader->read_data24(reader, &data))
        !           256:        {
        !           257:                DBG1(DBG_TLS, "certificate message header invalid");
        !           258:                this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
        !           259:                return NEED_MORE;
        !           260:        }
        !           261:        certs = bio_reader_create(data);
        !           262:        while (certs->remaining(certs))
        !           263:        {
        !           264:                if (!certs->read_data24(certs, &data))
        !           265:                {
        !           266:                        DBG1(DBG_TLS, "certificate message invalid");
        !           267:                        this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
        !           268:                        certs->destroy(certs);
        !           269:                        return NEED_MORE;
        !           270:                }
        !           271:                cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
        !           272:                                                                  BUILD_BLOB_ASN1_DER, data, BUILD_END);
        !           273:                if (cert)
        !           274:                {
        !           275:                        if (first)
        !           276:                        {
        !           277:                                if (!check_certificate(this, cert))
        !           278:                                {
        !           279:                                        cert->destroy(cert);
        !           280:                                        certs->destroy(certs);
        !           281:                                        this->alert->add(this->alert, TLS_FATAL, TLS_ACCESS_DENIED);
        !           282:                                        return NEED_MORE;
        !           283:                                }
        !           284:                                this->server_auth->add(this->server_auth,
        !           285:                                                                           AUTH_HELPER_SUBJECT_CERT, cert);
        !           286:                                DBG1(DBG_TLS, "received TLS server certificate '%Y'",
        !           287:                                         cert->get_subject(cert));
        !           288:                                first = FALSE;
        !           289:                        }
        !           290:                        else
        !           291:                        {
        !           292:                                DBG1(DBG_TLS, "received TLS intermediate certificate '%Y'",
        !           293:                                         cert->get_subject(cert));
        !           294:                                this->server_auth->add(this->server_auth,
        !           295:                                                                           AUTH_HELPER_IM_CERT, cert);
        !           296:                        }
        !           297:                }
        !           298:                else
        !           299:                {
        !           300:                        DBG1(DBG_TLS, "parsing TLS certificate failed, skipped");
        !           301:                        this->alert->add(this->alert, TLS_WARNING, TLS_BAD_CERTIFICATE);
        !           302:                }
        !           303:        }
        !           304:        certs->destroy(certs);
        !           305:        this->state = STATE_CERT_RECEIVED;
        !           306:        return NEED_MORE;
        !           307: }
        !           308: 
        !           309: /**
        !           310:  * Find a trusted public key to encrypt/verify key exchange data
        !           311:  */
        !           312: static public_key_t *find_public_key(private_tls_peer_t *this)
        !           313: {
        !           314:        public_key_t *public = NULL, *current;
        !           315:        certificate_t *cert, *found;
        !           316:        enumerator_t *enumerator;
        !           317:        auth_cfg_t *auth;
        !           318: 
        !           319:        cert = this->server_auth->get(this->server_auth, AUTH_HELPER_SUBJECT_CERT);
        !           320:        if (cert)
        !           321:        {
        !           322:                enumerator = lib->credmgr->create_public_enumerator(lib->credmgr,
        !           323:                                                                                        KEY_ANY, cert->get_subject(cert),
        !           324:                                                                                        this->server_auth, TRUE);
        !           325:                while (enumerator->enumerate(enumerator, &current, &auth))
        !           326:                {
        !           327:                        found = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
        !           328:                        if (found && cert->equals(cert, found))
        !           329:                        {
        !           330:                                public = current->get_ref(current);
        !           331:                                this->server_auth->merge(this->server_auth, auth, FALSE);
        !           332:                                break;
        !           333:                        }
        !           334:                }
        !           335:                enumerator->destroy(enumerator);
        !           336:        }
        !           337:        return public;
        !           338: }
        !           339: 
        !           340: /**
        !           341:  * Process a Key Exchange message using MODP Diffie Hellman
        !           342:  */
        !           343: static status_t process_modp_key_exchange(private_tls_peer_t *this,
        !           344:                                                                                  bio_reader_t *reader)
        !           345: {
        !           346:        chunk_t prime, generator, pub, chunk;
        !           347:        public_key_t *public;
        !           348: 
        !           349:        chunk = reader->peek(reader);
        !           350:        if (!reader->read_data16(reader, &prime) ||
        !           351:                !reader->read_data16(reader, &generator) ||
        !           352:                !reader->read_data16(reader, &pub))
        !           353:        {
        !           354:                DBG1(DBG_TLS, "received invalid Server Key Exchange");
        !           355:                this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
        !           356:                return NEED_MORE;
        !           357:        }
        !           358:        /* reject (export) DH groups using primes smaller than 1024 bit */
        !           359:        if (prime.len < 1024 / 8)
        !           360:        {
        !           361:                DBG1(DBG_TLS, "short DH prime received (%zu bytes)", prime.len);
        !           362:                this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
        !           363:                return NEED_MORE;
        !           364:        }
        !           365:        public = find_public_key(this);
        !           366:        if (!public)
        !           367:        {
        !           368:                DBG1(DBG_TLS, "no TLS public key found for server '%Y'", this->server);
        !           369:                this->alert->add(this->alert, TLS_FATAL, TLS_CERTIFICATE_UNKNOWN);
        !           370:                return NEED_MORE;
        !           371:        }
        !           372: 
        !           373:        chunk.len = 2 + prime.len + 2 + generator.len + 2 + pub.len;
        !           374:        chunk = chunk_cat("ccc", chunk_from_thing(this->client_random),
        !           375:                                          chunk_from_thing(this->server_random), chunk);
        !           376:        if (!this->crypto->verify(this->crypto, public, reader, chunk))
        !           377:        {
        !           378:                public->destroy(public);
        !           379:                free(chunk.ptr);
        !           380:                DBG1(DBG_TLS, "verifying DH parameters failed");
        !           381:                this->alert->add(this->alert, TLS_FATAL, TLS_BAD_CERTIFICATE);
        !           382:                return NEED_MORE;
        !           383:        }
        !           384:        public->destroy(public);
        !           385:        free(chunk.ptr);
        !           386: 
        !           387:        this->dh = lib->crypto->create_dh(lib->crypto, MODP_CUSTOM,
        !           388:                                                                          generator, prime);
        !           389:        if (!this->dh)
        !           390:        {
        !           391:                DBG1(DBG_TLS, "custom DH parameters not supported");
        !           392:                this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
        !           393:                return NEED_MORE;
        !           394:        }
        !           395:        if (!this->dh->set_other_public_value(this->dh, pub))
        !           396:        {
        !           397:                DBG1(DBG_TLS, "applying DH public value failed");
        !           398:                this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
        !           399:                return NEED_MORE;
        !           400:        }
        !           401: 
        !           402:        this->state = STATE_KEY_EXCHANGE_RECEIVED;
        !           403:        return NEED_MORE;
        !           404: }
        !           405: 
        !           406: /**
        !           407:  * Get the EC group for a TLS named curve
        !           408:  */
        !           409: static diffie_hellman_group_t curve_to_ec_group(private_tls_peer_t *this,
        !           410:                                                                                                tls_named_curve_t curve)
        !           411: {
        !           412:        diffie_hellman_group_t group;
        !           413:        tls_named_curve_t current;
        !           414:        enumerator_t *enumerator;
        !           415: 
        !           416:        enumerator = this->crypto->create_ec_enumerator(this->crypto);
        !           417:        while (enumerator->enumerate(enumerator, &group, &current))
        !           418:        {
        !           419:                if (current == curve)
        !           420:                {
        !           421:                        enumerator->destroy(enumerator);
        !           422:                        return group;
        !           423:                }
        !           424:        }
        !           425:        enumerator->destroy(enumerator);
        !           426:        return 0;
        !           427: }
        !           428: 
        !           429: /**
        !           430:  * Process a Key Exchange message using EC Diffie Hellman
        !           431:  */
        !           432: static status_t process_ec_key_exchange(private_tls_peer_t *this,
        !           433:                                                                                bio_reader_t *reader)
        !           434: {
        !           435:        diffie_hellman_group_t group;
        !           436:        public_key_t *public;
        !           437:        uint8_t type;
        !           438:        uint16_t curve;
        !           439:        chunk_t pub, chunk;
        !           440: 
        !           441:        chunk = reader->peek(reader);
        !           442:        if (!reader->read_uint8(reader, &type))
        !           443:        {
        !           444:                DBG1(DBG_TLS, "received invalid Server Key Exchange");
        !           445:                this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
        !           446:                return NEED_MORE;
        !           447:        }
        !           448:        if (type != TLS_ECC_NAMED_CURVE)
        !           449:        {
        !           450:                DBG1(DBG_TLS, "ECDH curve type %N not supported",
        !           451:                         tls_ecc_curve_type_names, type);
        !           452:                this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
        !           453:                return NEED_MORE;
        !           454:        }
        !           455:        if (!reader->read_uint16(reader, &curve) ||
        !           456:                !reader->read_data8(reader, &pub) || pub.len == 0)
        !           457:        {
        !           458:                DBG1(DBG_TLS, "received invalid Server Key Exchange");
        !           459:                this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
        !           460:                return NEED_MORE;
        !           461:        }
        !           462: 
        !           463:        group = curve_to_ec_group(this, curve);
        !           464:        if (!group)
        !           465:        {
        !           466:                DBG1(DBG_TLS, "ECDH curve %N not supported",
        !           467:                         tls_named_curve_names, curve);
        !           468:                this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
        !           469:                return NEED_MORE;
        !           470:        }
        !           471: 
        !           472:        public = find_public_key(this);
        !           473:        if (!public)
        !           474:        {
        !           475:                DBG1(DBG_TLS, "no TLS public key found for server '%Y'", this->server);
        !           476:                this->alert->add(this->alert, TLS_FATAL, TLS_CERTIFICATE_UNKNOWN);
        !           477:                return NEED_MORE;
        !           478:        }
        !           479: 
        !           480:        chunk.len = 4 + pub.len;
        !           481:        chunk = chunk_cat("ccc", chunk_from_thing(this->client_random),
        !           482:                                          chunk_from_thing(this->server_random), chunk);
        !           483:        if (!this->crypto->verify(this->crypto, public, reader, chunk))
        !           484:        {
        !           485:                public->destroy(public);
        !           486:                free(chunk.ptr);
        !           487:                DBG1(DBG_TLS, "verifying DH parameters failed");
        !           488:                this->alert->add(this->alert, TLS_FATAL, TLS_BAD_CERTIFICATE);
        !           489:                return NEED_MORE;
        !           490:        }
        !           491:        public->destroy(public);
        !           492:        free(chunk.ptr);
        !           493: 
        !           494:        this->dh = lib->crypto->create_dh(lib->crypto, group);
        !           495:        if (!this->dh)
        !           496:        {
        !           497:                DBG1(DBG_TLS, "DH group %N not supported",
        !           498:                         diffie_hellman_group_names, group);
        !           499:                this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
        !           500:                return NEED_MORE;
        !           501:        }
        !           502: 
        !           503:        if (pub.ptr[0] != TLS_ANSI_UNCOMPRESSED)
        !           504:        {
        !           505:                DBG1(DBG_TLS, "DH point format '%N' not supported",
        !           506:                         tls_ansi_point_format_names, pub.ptr[0]);
        !           507:                this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
        !           508:                return NEED_MORE;
        !           509:        }
        !           510:        if (!this->dh->set_other_public_value(this->dh, chunk_skip(pub, 1)))
        !           511:        {
        !           512:                DBG1(DBG_TLS, "applying DH public value failed");
        !           513:                this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
        !           514:                return NEED_MORE;
        !           515:        }
        !           516: 
        !           517:        this->state = STATE_KEY_EXCHANGE_RECEIVED;
        !           518:        return NEED_MORE;
        !           519: }
        !           520: 
        !           521: /**
        !           522:  * Process a Server Key Exchange
        !           523:  */
        !           524: static status_t process_key_exchange(private_tls_peer_t *this,
        !           525:                                                                         bio_reader_t *reader)
        !           526: {
        !           527:        diffie_hellman_group_t group;
        !           528: 
        !           529:        this->crypto->append_handshake(this->crypto,
        !           530:                                                                TLS_SERVER_KEY_EXCHANGE, reader->peek(reader));
        !           531: 
        !           532:        group = this->crypto->get_dh_group(this->crypto);
        !           533:        if (group == MODP_NONE)
        !           534:        {
        !           535:                DBG1(DBG_TLS, "received Server Key Exchange, but not required "
        !           536:                         "for current suite");
        !           537:                this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
        !           538:                return NEED_MORE;
        !           539:        }
        !           540:        if (diffie_hellman_group_is_ec(group))
        !           541:        {
        !           542:                return process_ec_key_exchange(this, reader);
        !           543:        }
        !           544:        return process_modp_key_exchange(this, reader);
        !           545: }
        !           546: 
        !           547: /**
        !           548:  * Process a Certificate Request message
        !           549:  */
        !           550: static status_t process_certreq(private_tls_peer_t *this, bio_reader_t *reader)
        !           551: {
        !           552:        chunk_t types, hashsig, data;
        !           553:        bio_reader_t *authorities;
        !           554:        identification_t *id;
        !           555:        certificate_t *cert;
        !           556: 
        !           557:        if (!this->peer)
        !           558:        {
        !           559:                DBG1(DBG_TLS, "server requested a certificate, but client "
        !           560:                         "authentication disabled");
        !           561:        }
        !           562:        this->crypto->append_handshake(this->crypto,
        !           563:                                                                TLS_CERTIFICATE_REQUEST, reader->peek(reader));
        !           564: 
        !           565:        if (!reader->read_data8(reader, &types))
        !           566:        {
        !           567:                DBG1(DBG_TLS, "certreq message header invalid");
        !           568:                this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
        !           569:                return NEED_MORE;
        !           570:        }
        !           571:        this->cert_types = chunk_clone(types);
        !           572:        if (this->tls->get_version(this->tls) >= TLS_1_2)
        !           573:        {
        !           574:                if (!reader->read_data16(reader, &hashsig))
        !           575:                {
        !           576:                        DBG1(DBG_TLS, "certreq message invalid");
        !           577:                        this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
        !           578:                        return NEED_MORE;
        !           579:                }
        !           580:                this->hashsig = chunk_clone(hashsig);
        !           581:        }
        !           582:        if (!reader->read_data16(reader, &data))
        !           583:        {
        !           584:                DBG1(DBG_TLS, "certreq message invalid");
        !           585:                this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
        !           586:                return NEED_MORE;
        !           587:        }
        !           588:        authorities = bio_reader_create(data);
        !           589:        while (authorities->remaining(authorities))
        !           590:        {
        !           591:                if (!authorities->read_data16(authorities, &data))
        !           592:                {
        !           593:                        DBG1(DBG_TLS, "certreq message invalid");
        !           594:                        this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
        !           595:                        authorities->destroy(authorities);
        !           596:                        return NEED_MORE;
        !           597:                }
        !           598:                if (this->peer)
        !           599:                {
        !           600:                        id = identification_create_from_encoding(ID_DER_ASN1_DN, data);
        !           601:                        cert = lib->credmgr->get_cert(lib->credmgr,
        !           602:                                                                                  CERT_X509, KEY_ANY, id, TRUE);
        !           603:                        if (cert)
        !           604:                        {
        !           605:                                DBG1(DBG_TLS, "received TLS cert request for '%Y", id);
        !           606:                                this->peer_auth->add(this->peer_auth, AUTH_RULE_CA_CERT, cert);
        !           607:                        }
        !           608:                        else
        !           609:                        {
        !           610:                                DBG1(DBG_TLS, "received TLS cert request for unknown CA '%Y'", id);
        !           611:                        }
        !           612:                        id->destroy(id);
        !           613:                }
        !           614:        }
        !           615:        authorities->destroy(authorities);
        !           616:        this->state = STATE_CERTREQ_RECEIVED;
        !           617:        return NEED_MORE;
        !           618: }
        !           619: 
        !           620: /**
        !           621:  * Process Hello Done message
        !           622:  */
        !           623: static status_t process_hello_done(private_tls_peer_t *this,
        !           624:                                                                   bio_reader_t *reader)
        !           625: {
        !           626:        this->crypto->append_handshake(this->crypto,
        !           627:                                                                   TLS_SERVER_HELLO_DONE, reader->peek(reader));
        !           628:        this->state = STATE_HELLO_DONE;
        !           629:        return NEED_MORE;
        !           630: }
        !           631: 
        !           632: /**
        !           633:  * Process finished message
        !           634:  */
        !           635: static status_t process_finished(private_tls_peer_t *this, bio_reader_t *reader)
        !           636: {
        !           637:        chunk_t received;
        !           638:        char buf[12];
        !           639: 
        !           640:        if (!reader->read_data(reader, sizeof(buf), &received))
        !           641:        {
        !           642:                DBG1(DBG_TLS, "received server finished too short");
        !           643:                this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
        !           644:                return NEED_MORE;
        !           645:        }
        !           646:        if (!this->crypto->calculate_finished(this->crypto, "server finished", buf))
        !           647:        {
        !           648:                DBG1(DBG_TLS, "calculating server finished failed");
        !           649:                this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
        !           650:                return NEED_MORE;
        !           651:        }
        !           652:        if (!chunk_equals_const(received, chunk_from_thing(buf)))
        !           653:        {
        !           654:                DBG1(DBG_TLS, "received server finished invalid");
        !           655:                this->alert->add(this->alert, TLS_FATAL, TLS_DECRYPT_ERROR);
        !           656:                return NEED_MORE;
        !           657:        }
        !           658:        this->state = STATE_FINISHED_RECEIVED;
        !           659:        this->crypto->append_handshake(this->crypto, TLS_FINISHED, received);
        !           660: 
        !           661:        return NEED_MORE;
        !           662: }
        !           663: 
        !           664: METHOD(tls_handshake_t, process, status_t,
        !           665:        private_tls_peer_t *this, tls_handshake_type_t type, bio_reader_t *reader)
        !           666: {
        !           667:        tls_handshake_type_t expected;
        !           668: 
        !           669:        switch (this->state)
        !           670:        {
        !           671:                case STATE_HELLO_SENT:
        !           672:                        if (type == TLS_SERVER_HELLO)
        !           673:                        {
        !           674:                                return process_server_hello(this, reader);
        !           675:                        }
        !           676:                        expected = TLS_SERVER_HELLO;
        !           677:                        break;
        !           678:                case STATE_HELLO_RECEIVED:
        !           679:                        if (type == TLS_CERTIFICATE)
        !           680:                        {
        !           681:                                return process_certificate(this, reader);
        !           682:                        }
        !           683:                        expected = TLS_CERTIFICATE;
        !           684:                        break;
        !           685:                case STATE_CERT_RECEIVED:
        !           686:                        if (type == TLS_SERVER_KEY_EXCHANGE)
        !           687:                        {
        !           688:                                return process_key_exchange(this, reader);
        !           689:                        }
        !           690:                        /* fall through since TLS_SERVER_KEY_EXCHANGE is optional */
        !           691:                case STATE_KEY_EXCHANGE_RECEIVED:
        !           692:                        if (type == TLS_CERTIFICATE_REQUEST)
        !           693:                        {
        !           694:                                return process_certreq(this, reader);
        !           695:                        }
        !           696:                        /* no cert request, server does not want to authenticate us */
        !           697:                        DESTROY_IF(this->peer);
        !           698:                        this->peer = NULL;
        !           699:                        /* fall through since TLS_CERTIFICATE_REQUEST is optional */
        !           700:                case STATE_CERTREQ_RECEIVED:
        !           701:                        if (type == TLS_SERVER_HELLO_DONE)
        !           702:                        {
        !           703:                                return process_hello_done(this, reader);
        !           704:                        }
        !           705:                        expected = TLS_SERVER_HELLO_DONE;
        !           706:                        break;
        !           707:                case STATE_CIPHERSPEC_CHANGED_IN:
        !           708:                        if (type == TLS_FINISHED)
        !           709:                        {
        !           710:                                return process_finished(this, reader);
        !           711:                        }
        !           712:                        expected = TLS_FINISHED;
        !           713:                        break;
        !           714:                default:
        !           715:                        DBG1(DBG_TLS, "TLS %N not expected in current state",
        !           716:                                 tls_handshake_type_names, type);
        !           717:                        this->alert->add(this->alert, TLS_FATAL, TLS_UNEXPECTED_MESSAGE);
        !           718:                        return NEED_MORE;
        !           719:        }
        !           720:        DBG1(DBG_TLS, "TLS %N expected, but received %N",
        !           721:                 tls_handshake_type_names, expected, tls_handshake_type_names, type);
        !           722:        this->alert->add(this->alert, TLS_FATAL, TLS_UNEXPECTED_MESSAGE);
        !           723:        return NEED_MORE;
        !           724: }
        !           725: 
        !           726: /**
        !           727:  * Send a client hello
        !           728:  */
        !           729: static status_t send_client_hello(private_tls_peer_t *this,
        !           730:                                                        tls_handshake_type_t *type, bio_writer_t *writer)
        !           731: {
        !           732:        tls_cipher_suite_t *suites;
        !           733:        bio_writer_t *extensions, *curves = NULL;
        !           734:        tls_version_t version;
        !           735:        tls_named_curve_t curve;
        !           736:        enumerator_t *enumerator;
        !           737:        int count, i;
        !           738:        rng_t *rng;
        !           739: 
        !           740:        htoun32(&this->client_random, time(NULL));
        !           741:        rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
        !           742:        if (!rng ||
        !           743:                !rng->get_bytes(rng, sizeof(this->client_random) - 4,
        !           744:                                                this->client_random + 4))
        !           745:        {
        !           746:                DBG1(DBG_TLS, "failed to generate client random");
        !           747:                this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
        !           748:                DESTROY_IF(rng);
        !           749:                return NEED_MORE;
        !           750:        }
        !           751:        rng->destroy(rng);
        !           752: 
        !           753:        /* TLS version */
        !           754:        version = this->tls->get_version(this->tls);
        !           755:        this->hello_version = version;
        !           756:        writer->write_uint16(writer, version);
        !           757:        writer->write_data(writer, chunk_from_thing(this->client_random));
        !           758: 
        !           759:        /* session identifier */
        !           760:        this->session = this->crypto->get_session(this->crypto, this->server);
        !           761:        writer->write_data8(writer, this->session);
        !           762: 
        !           763:        /* add TLS cipher suites */
        !           764:        count = this->crypto->get_cipher_suites(this->crypto, &suites);
        !           765:        writer->write_uint16(writer, count * 2);
        !           766:        for (i = 0; i < count; i++)
        !           767:        {
        !           768:                writer->write_uint16(writer, suites[i]);
        !           769:        }
        !           770: 
        !           771:        /* NULL compression only */
        !           772:        writer->write_uint8(writer, 1);
        !           773:        writer->write_uint8(writer, 0);
        !           774: 
        !           775:        extensions = bio_writer_create(32);
        !           776: 
        !           777:        extensions->write_uint16(extensions, TLS_EXT_SIGNATURE_ALGORITHMS);
        !           778:        this->crypto->get_signature_algorithms(this->crypto, extensions);
        !           779: 
        !           780:        /* add supported Elliptic Curves, if any */
        !           781:        enumerator = this->crypto->create_ec_enumerator(this->crypto);
        !           782:        while (enumerator->enumerate(enumerator, NULL, &curve))
        !           783:        {
        !           784:                if (!curves)
        !           785:                {
        !           786:                        extensions->write_uint16(extensions, TLS_EXT_ELLIPTIC_CURVES);
        !           787:                        curves = bio_writer_create(16);
        !           788:                }
        !           789:                curves->write_uint16(curves, curve);
        !           790:        }
        !           791:        enumerator->destroy(enumerator);
        !           792:        if (curves)
        !           793:        {
        !           794:                curves->wrap16(curves);
        !           795:                extensions->write_data16(extensions, curves->get_buf(curves));
        !           796:                curves->destroy(curves);
        !           797: 
        !           798:                /* if we support curves, add point format extension */
        !           799:                extensions->write_uint16(extensions, TLS_EXT_EC_POINT_FORMATS);
        !           800:                extensions->write_uint16(extensions, 2);
        !           801:                extensions->write_uint8(extensions, 1);
        !           802:                extensions->write_uint8(extensions, TLS_EC_POINT_UNCOMPRESSED);
        !           803:        }
        !           804:        if (this->server->get_type(this->server) == ID_FQDN)
        !           805:        {
        !           806:                bio_writer_t *names;
        !           807: 
        !           808:                DBG2(DBG_TLS, "sending Server Name Indication for '%Y'", this->server);
        !           809: 
        !           810:                names = bio_writer_create(8);
        !           811:                names->write_uint8(names, TLS_NAME_TYPE_HOST_NAME);
        !           812:                names->write_data16(names, this->server->get_encoding(this->server));
        !           813:                names->wrap16(names);
        !           814:                extensions->write_uint16(extensions, TLS_EXT_SERVER_NAME);
        !           815:                extensions->write_data16(extensions, names->get_buf(names));
        !           816:                names->destroy(names);
        !           817:        }
        !           818: 
        !           819:        writer->write_data16(writer, extensions->get_buf(extensions));
        !           820:        extensions->destroy(extensions);
        !           821: 
        !           822:        *type = TLS_CLIENT_HELLO;
        !           823:        this->state = STATE_HELLO_SENT;
        !           824:        this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
        !           825:        return NEED_MORE;
        !           826: }
        !           827: 
        !           828: /**
        !           829:  * Find a private key suitable to sign Certificate Verify
        !           830:  */
        !           831: static private_key_t *find_private_key(private_tls_peer_t *this)
        !           832: {
        !           833:        private_key_t *key = NULL;
        !           834:        bio_reader_t *reader;
        !           835:        key_type_t type;
        !           836:        uint8_t cert;
        !           837: 
        !           838:        if (!this->peer)
        !           839:        {
        !           840:                return NULL;
        !           841:        }
        !           842:        reader = bio_reader_create(this->cert_types);
        !           843:        while (reader->remaining(reader) && reader->read_uint8(reader, &cert))
        !           844:        {
        !           845:                switch (cert)
        !           846:                {
        !           847:                        case TLS_RSA_SIGN:
        !           848:                                type = KEY_RSA;
        !           849:                                break;
        !           850:                        case TLS_ECDSA_SIGN:
        !           851:                                type = KEY_ECDSA;
        !           852:                                break;
        !           853:                        default:
        !           854:                                continue;
        !           855:                }
        !           856:                key = lib->credmgr->get_private(lib->credmgr, type,
        !           857:                                                                                this->peer, this->peer_auth);
        !           858:                if (key)
        !           859:                {
        !           860:                        break;
        !           861:                }
        !           862:        }
        !           863:        reader->destroy(reader);
        !           864:        return key;
        !           865: }
        !           866: 
        !           867: /**
        !           868:  * Send Certificate
        !           869:  */
        !           870: static status_t send_certificate(private_tls_peer_t *this,
        !           871:                                                        tls_handshake_type_t *type, bio_writer_t *writer)
        !           872: {
        !           873:        enumerator_t *enumerator;
        !           874:        certificate_t *cert;
        !           875:        auth_rule_t rule;
        !           876:        bio_writer_t *certs;
        !           877:        chunk_t data;
        !           878: 
        !           879:        this->private = find_private_key(this);
        !           880:        if (!this->private)
        !           881:        {
        !           882:                DBG1(DBG_TLS, "no TLS peer certificate found for '%Y', "
        !           883:                         "skipping client authentication", this->peer);
        !           884:                this->peer->destroy(this->peer);
        !           885:                this->peer = NULL;
        !           886:        }
        !           887: 
        !           888:        /* generate certificate payload */
        !           889:        certs = bio_writer_create(256);
        !           890:        if (this->peer)
        !           891:        {
        !           892:                cert = this->peer_auth->get(this->peer_auth, AUTH_RULE_SUBJECT_CERT);
        !           893:                if (cert)
        !           894:                {
        !           895:                        if (cert->get_encoding(cert, CERT_ASN1_DER, &data))
        !           896:                        {
        !           897:                                DBG1(DBG_TLS, "sending TLS peer certificate '%Y'",
        !           898:                                         cert->get_subject(cert));
        !           899:                                certs->write_data24(certs, data);
        !           900:                                free(data.ptr);
        !           901:                        }
        !           902:                }
        !           903:                enumerator = this->peer_auth->create_enumerator(this->peer_auth);
        !           904:                while (enumerator->enumerate(enumerator, &rule, &cert))
        !           905:                {
        !           906:                        if (rule == AUTH_RULE_IM_CERT)
        !           907:                        {
        !           908:                                if (cert->get_encoding(cert, CERT_ASN1_DER, &data))
        !           909:                                {
        !           910:                                        DBG1(DBG_TLS, "sending TLS intermediate certificate '%Y'",
        !           911:                                                 cert->get_subject(cert));
        !           912:                                        certs->write_data24(certs, data);
        !           913:                                        free(data.ptr);
        !           914:                                }
        !           915:                        }
        !           916:                }
        !           917:                enumerator->destroy(enumerator);
        !           918:        }
        !           919: 
        !           920:        writer->write_data24(writer, certs->get_buf(certs));
        !           921:        certs->destroy(certs);
        !           922: 
        !           923:        *type = TLS_CERTIFICATE;
        !           924:        this->state = STATE_CERT_SENT;
        !           925:        this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
        !           926:        return NEED_MORE;
        !           927: }
        !           928: 
        !           929: /**
        !           930:  * Send client key exchange, using premaster encryption
        !           931:  */
        !           932: static status_t send_key_exchange_encrypt(private_tls_peer_t *this,
        !           933:                                                        tls_handshake_type_t *type, bio_writer_t *writer)
        !           934: {
        !           935:        public_key_t *public;
        !           936:        rng_t *rng;
        !           937:        char premaster[48];
        !           938:        chunk_t encrypted;
        !           939: 
        !           940:        rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
        !           941:        if (!rng || !rng->get_bytes(rng, sizeof(premaster) - 2, premaster + 2))
        !           942:        {
        !           943:                DBG1(DBG_TLS, "failed to generate TLS premaster secret");
        !           944:                this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
        !           945:                DESTROY_IF(rng);
        !           946:                return NEED_MORE;
        !           947:        }
        !           948:        rng->destroy(rng);
        !           949:        htoun16(premaster, this->hello_version);
        !           950: 
        !           951:        if (!this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster),
        !           952:                                                                          this->session, this->server,
        !           953:                                                                          chunk_from_thing(this->client_random),
        !           954:                                                                          chunk_from_thing(this->server_random)))
        !           955:        {
        !           956:                this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
        !           957:                return NEED_MORE;
        !           958:        }
        !           959: 
        !           960:        public = find_public_key(this);
        !           961:        if (!public)
        !           962:        {
        !           963:                DBG1(DBG_TLS, "no TLS public key found for server '%Y'", this->server);
        !           964:                this->alert->add(this->alert, TLS_FATAL, TLS_CERTIFICATE_UNKNOWN);
        !           965:                return NEED_MORE;
        !           966:        }
        !           967:        if (!public->encrypt(public, ENCRYPT_RSA_PKCS1,
        !           968:                                                 chunk_from_thing(premaster), &encrypted))
        !           969:        {
        !           970:                public->destroy(public);
        !           971:                DBG1(DBG_TLS, "encrypting TLS premaster secret failed");
        !           972:                this->alert->add(this->alert, TLS_FATAL, TLS_BAD_CERTIFICATE);
        !           973:                return NEED_MORE;
        !           974:        }
        !           975:        public->destroy(public);
        !           976: 
        !           977:        writer->write_data16(writer, encrypted);
        !           978:        free(encrypted.ptr);
        !           979: 
        !           980:        *type = TLS_CLIENT_KEY_EXCHANGE;
        !           981:        this->state = STATE_KEY_EXCHANGE_SENT;
        !           982:        this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
        !           983:        return NEED_MORE;
        !           984: }
        !           985: 
        !           986: /**
        !           987:  * Send client key exchange, using DHE exchange
        !           988:  */
        !           989: static status_t send_key_exchange_dhe(private_tls_peer_t *this,
        !           990:                                                        tls_handshake_type_t *type, bio_writer_t *writer)
        !           991: {
        !           992:        chunk_t premaster, pub;
        !           993: 
        !           994:        if (!this->dh->get_shared_secret(this->dh, &premaster))
        !           995:        {
        !           996:                DBG1(DBG_TLS, "calculating premaster from DH failed");
        !           997:                this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
        !           998:                return NEED_MORE;
        !           999:        }
        !          1000:        if (!this->crypto->derive_secrets(this->crypto, premaster,
        !          1001:                                                                          this->session, this->server,
        !          1002:                                                                          chunk_from_thing(this->client_random),
        !          1003:                                                                          chunk_from_thing(this->server_random)))
        !          1004:        {
        !          1005:                this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
        !          1006:                chunk_clear(&premaster);
        !          1007:                return NEED_MORE;
        !          1008:        }
        !          1009:        chunk_clear(&premaster);
        !          1010: 
        !          1011:        if (!this->dh->get_my_public_value(this->dh, &pub))
        !          1012:        {
        !          1013:                this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
        !          1014:                return NEED_MORE;
        !          1015:        }
        !          1016:        if (this->dh->get_dh_group(this->dh) == MODP_CUSTOM)
        !          1017:        {
        !          1018:                writer->write_data16(writer, pub);
        !          1019:        }
        !          1020:        else
        !          1021:        {       /* ECP uses 8bit length header only, but a point format */
        !          1022:                writer->write_uint8(writer, pub.len + 1);
        !          1023:                writer->write_uint8(writer, TLS_ANSI_UNCOMPRESSED);
        !          1024:                writer->write_data(writer, pub);
        !          1025:        }
        !          1026:        free(pub.ptr);
        !          1027: 
        !          1028:        *type = TLS_CLIENT_KEY_EXCHANGE;
        !          1029:        this->state = STATE_KEY_EXCHANGE_SENT;
        !          1030:        this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
        !          1031:        return NEED_MORE;
        !          1032: }
        !          1033: 
        !          1034: /**
        !          1035:  * Send client key exchange, depending on suite
        !          1036:  */
        !          1037: static status_t send_key_exchange(private_tls_peer_t *this,
        !          1038:                                                        tls_handshake_type_t *type, bio_writer_t *writer)
        !          1039: {
        !          1040:        if (this->dh)
        !          1041:        {
        !          1042:                return send_key_exchange_dhe(this, type, writer);
        !          1043:        }
        !          1044:        return send_key_exchange_encrypt(this, type, writer);
        !          1045: }
        !          1046: 
        !          1047: /**
        !          1048:  * Send certificate verify
        !          1049:  */
        !          1050: static status_t send_certificate_verify(private_tls_peer_t *this,
        !          1051:                                                        tls_handshake_type_t *type, bio_writer_t *writer)
        !          1052: {
        !          1053:        if (!this->private ||
        !          1054:                !this->crypto->sign_handshake(this->crypto, this->private,
        !          1055:                                                                          writer, this->hashsig))
        !          1056:        {
        !          1057:                DBG1(DBG_TLS, "creating TLS Certificate Verify signature failed");
        !          1058:                this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
        !          1059:                return NEED_MORE;
        !          1060:        }
        !          1061: 
        !          1062:        *type = TLS_CERTIFICATE_VERIFY;
        !          1063:        this->state = STATE_VERIFY_SENT;
        !          1064:        this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
        !          1065:        return NEED_MORE;
        !          1066: }
        !          1067: 
        !          1068: /**
        !          1069:  * Send Finished
        !          1070:  */
        !          1071: static status_t send_finished(private_tls_peer_t *this,
        !          1072:                                                          tls_handshake_type_t *type, bio_writer_t *writer)
        !          1073: {
        !          1074:        char buf[12];
        !          1075: 
        !          1076:        if (!this->crypto->calculate_finished(this->crypto, "client finished", buf))
        !          1077:        {
        !          1078:                DBG1(DBG_TLS, "calculating client finished data failed");
        !          1079:                this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
        !          1080:                return NEED_MORE;
        !          1081:        }
        !          1082: 
        !          1083:        writer->write_data(writer, chunk_from_thing(buf));
        !          1084: 
        !          1085:        *type = TLS_FINISHED;
        !          1086:        this->state = STATE_FINISHED_SENT;
        !          1087:        this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
        !          1088:        return NEED_MORE;
        !          1089: }
        !          1090: 
        !          1091: METHOD(tls_handshake_t, build, status_t,
        !          1092:        private_tls_peer_t *this, tls_handshake_type_t *type, bio_writer_t *writer)
        !          1093: {
        !          1094:        switch (this->state)
        !          1095:        {
        !          1096:                case STATE_INIT:
        !          1097:                        return send_client_hello(this, type, writer);
        !          1098:                case STATE_HELLO_DONE:
        !          1099:                        if (this->peer)
        !          1100:                        {
        !          1101:                                return send_certificate(this, type, writer);
        !          1102:                        }
        !          1103:                        /* otherwise fall through to next state */
        !          1104:                case STATE_CERT_SENT:
        !          1105:                        return send_key_exchange(this, type, writer);
        !          1106:                case STATE_KEY_EXCHANGE_SENT:
        !          1107:                        if (this->peer)
        !          1108:                        {
        !          1109:                                return send_certificate_verify(this, type, writer);
        !          1110:                        }
        !          1111:                        else
        !          1112:                        {
        !          1113:                                return INVALID_STATE;
        !          1114:                        }
        !          1115:                case STATE_CIPHERSPEC_CHANGED_OUT:
        !          1116:                        return send_finished(this, type, writer);
        !          1117:                default:
        !          1118:                        return INVALID_STATE;
        !          1119:        }
        !          1120: }
        !          1121: 
        !          1122: METHOD(tls_handshake_t, cipherspec_changed, bool,
        !          1123:        private_tls_peer_t *this, bool inbound)
        !          1124: {
        !          1125:        if (inbound)
        !          1126:        {
        !          1127:                if (this->resume)
        !          1128:                {
        !          1129:                        return this->state == STATE_HELLO_RECEIVED;
        !          1130:                }
        !          1131:                return this->state == STATE_FINISHED_SENT;
        !          1132:        }
        !          1133:        else
        !          1134:        {
        !          1135:                if (this->resume)
        !          1136:                {
        !          1137:                        return this->state == STATE_FINISHED_RECEIVED;
        !          1138:                }
        !          1139:                if (this->peer)
        !          1140:                {
        !          1141:                        return this->state == STATE_VERIFY_SENT;
        !          1142:                }
        !          1143:                return this->state == STATE_KEY_EXCHANGE_SENT;
        !          1144:        }
        !          1145: }
        !          1146: 
        !          1147: METHOD(tls_handshake_t, change_cipherspec, void,
        !          1148:        private_tls_peer_t *this, bool inbound)
        !          1149: {
        !          1150:        this->crypto->change_cipher(this->crypto, inbound);
        !          1151:        if (inbound)
        !          1152:        {
        !          1153:                this->state = STATE_CIPHERSPEC_CHANGED_IN;
        !          1154:        }
        !          1155:        else
        !          1156:        {
        !          1157:                this->state = STATE_CIPHERSPEC_CHANGED_OUT;
        !          1158:        }
        !          1159: }
        !          1160: 
        !          1161: METHOD(tls_handshake_t, finished, bool,
        !          1162:        private_tls_peer_t *this)
        !          1163: {
        !          1164:        if (this->resume)
        !          1165:        {
        !          1166:                return this->state == STATE_FINISHED_SENT;
        !          1167:        }
        !          1168:        return this->state == STATE_FINISHED_RECEIVED;
        !          1169: }
        !          1170: 
        !          1171: METHOD(tls_handshake_t, get_peer_id, identification_t*,
        !          1172:        private_tls_peer_t *this)
        !          1173: {
        !          1174:        return this->peer;
        !          1175: }
        !          1176: 
        !          1177: METHOD(tls_handshake_t, get_server_id, identification_t*,
        !          1178:        private_tls_peer_t *this)
        !          1179: {
        !          1180:        return this->server;
        !          1181: }
        !          1182: 
        !          1183: METHOD(tls_handshake_t, get_auth, auth_cfg_t*,
        !          1184:        private_tls_peer_t *this)
        !          1185: {
        !          1186:        return this->server_auth;
        !          1187: }
        !          1188: 
        !          1189: METHOD(tls_handshake_t, destroy, void,
        !          1190:        private_tls_peer_t *this)
        !          1191: {
        !          1192:        DESTROY_IF(this->private);
        !          1193:        DESTROY_IF(this->dh);
        !          1194:        DESTROY_IF(this->peer);
        !          1195:        this->server->destroy(this->server);
        !          1196:        this->peer_auth->destroy(this->peer_auth);
        !          1197:        this->server_auth->destroy(this->server_auth);
        !          1198:        free(this->hashsig.ptr);
        !          1199:        free(this->cert_types.ptr);
        !          1200:        free(this->session.ptr);
        !          1201:        free(this);
        !          1202: }
        !          1203: 
        !          1204: /**
        !          1205:  * See header
        !          1206:  */
        !          1207: tls_peer_t *tls_peer_create(tls_t *tls, tls_crypto_t *crypto, tls_alert_t *alert,
        !          1208:                                                        identification_t *peer, identification_t *server)
        !          1209: {
        !          1210:        private_tls_peer_t *this;
        !          1211: 
        !          1212:        INIT(this,
        !          1213:                .public = {
        !          1214:                        .handshake = {
        !          1215:                                .process = _process,
        !          1216:                                .build = _build,
        !          1217:                                .cipherspec_changed = _cipherspec_changed,
        !          1218:                                .change_cipherspec = _change_cipherspec,
        !          1219:                                .finished = _finished,
        !          1220:                                .get_peer_id = _get_peer_id,
        !          1221:                                .get_server_id = _get_server_id,
        !          1222:                                .get_auth = _get_auth,
        !          1223:                                .destroy = _destroy,
        !          1224:                        },
        !          1225:                },
        !          1226:                .state = STATE_INIT,
        !          1227:                .tls = tls,
        !          1228:                .crypto = crypto,
        !          1229:                .alert = alert,
        !          1230:                .peer = peer ? peer->clone(peer) : NULL,
        !          1231:                .server = server->clone(server),
        !          1232:                .peer_auth = auth_cfg_create(),
        !          1233:                .server_auth = auth_cfg_create(),
        !          1234:        );
        !          1235: 
        !          1236:        return &this->public;
        !          1237: }

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