Annotation of qemu/roms/ipxe/src/net/tls.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (C) 2007 Michael Brown <[email protected]>.
        !             3:  *
        !             4:  * This program is free software; you can redistribute it and/or
        !             5:  * modify it under the terms of the GNU General Public License as
        !             6:  * published by the Free Software Foundation; either version 2 of the
        !             7:  * License, or any later version.
        !             8:  *
        !             9:  * This program is distributed in the hope that it will be useful, but
        !            10:  * WITHOUT ANY WARRANTY; without even the implied warranty of
        !            11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            12:  * General Public License for more details.
        !            13:  *
        !            14:  * You should have received a copy of the GNU General Public License
        !            15:  * along with this program; if not, write to the Free Software
        !            16:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
        !            17:  */
        !            18: 
        !            19: FILE_LICENCE ( GPL2_OR_LATER );
        !            20: 
        !            21: /**
        !            22:  * @file
        !            23:  *
        !            24:  * Transport Layer Security Protocol
        !            25:  */
        !            26: 
        !            27: #include <stdint.h>
        !            28: #include <stdlib.h>
        !            29: #include <stdarg.h>
        !            30: #include <string.h>
        !            31: #include <errno.h>
        !            32: #include <byteswap.h>
        !            33: #include <ipxe/hmac.h>
        !            34: #include <ipxe/md5.h>
        !            35: #include <ipxe/sha1.h>
        !            36: #include <ipxe/aes.h>
        !            37: #include <ipxe/rsa.h>
        !            38: #include <ipxe/iobuf.h>
        !            39: #include <ipxe/xfer.h>
        !            40: #include <ipxe/open.h>
        !            41: #include <ipxe/asn1.h>
        !            42: #include <ipxe/x509.h>
        !            43: #include <ipxe/tls.h>
        !            44: 
        !            45: static int tls_send_plaintext ( struct tls_session *tls, unsigned int type,
        !            46:                                const void *data, size_t len );
        !            47: static void tls_clear_cipher ( struct tls_session *tls,
        !            48:                               struct tls_cipherspec *cipherspec );
        !            49: 
        !            50: /******************************************************************************
        !            51:  *
        !            52:  * Utility functions
        !            53:  *
        !            54:  ******************************************************************************
        !            55:  */
        !            56: 
        !            57: /**
        !            58:  * Extract 24-bit field value
        !            59:  *
        !            60:  * @v field24          24-bit field
        !            61:  * @ret value          Field value
        !            62:  *
        !            63:  * TLS uses 24-bit integers in several places, which are awkward to
        !            64:  * parse in C.
        !            65:  */
        !            66: static unsigned long tls_uint24 ( uint8_t field24[3] ) {
        !            67:        return ( ( field24[0] << 16 ) + ( field24[1] << 8 ) + field24[2] );
        !            68: }
        !            69: 
        !            70: /******************************************************************************
        !            71:  *
        !            72:  * Cleanup functions
        !            73:  *
        !            74:  ******************************************************************************
        !            75:  */
        !            76: 
        !            77: /**
        !            78:  * Free TLS session
        !            79:  *
        !            80:  * @v refcnt           Reference counter
        !            81:  */
        !            82: static void free_tls ( struct refcnt *refcnt ) {
        !            83:        struct tls_session *tls =
        !            84:                container_of ( refcnt, struct tls_session, refcnt );
        !            85: 
        !            86:        /* Free dynamically-allocated resources */
        !            87:        tls_clear_cipher ( tls, &tls->tx_cipherspec );
        !            88:        tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
        !            89:        tls_clear_cipher ( tls, &tls->rx_cipherspec );
        !            90:        tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
        !            91:        x509_free_rsa_public_key ( &tls->rsa );
        !            92:        free ( tls->rx_data );
        !            93: 
        !            94:        /* Free TLS structure itself */
        !            95:        free ( tls );   
        !            96: }
        !            97: 
        !            98: /**
        !            99:  * Finish with TLS session
        !           100:  *
        !           101:  * @v tls              TLS session
        !           102:  * @v rc               Status code
        !           103:  */
        !           104: static void tls_close ( struct tls_session *tls, int rc ) {
        !           105: 
        !           106:        /* Remove process */
        !           107:        process_del ( &tls->process );
        !           108:        
        !           109:        /* Close ciphertext and plaintext streams */
        !           110:        intf_shutdown ( &tls->cipherstream, rc );
        !           111:        intf_shutdown ( &tls->plainstream, rc );
        !           112: }
        !           113: 
        !           114: /******************************************************************************
        !           115:  *
        !           116:  * Random number generation
        !           117:  *
        !           118:  ******************************************************************************
        !           119:  */
        !           120: 
        !           121: /**
        !           122:  * Generate random data
        !           123:  *
        !           124:  * @v data             Buffer to fill
        !           125:  * @v len              Length of buffer
        !           126:  */
        !           127: static void tls_generate_random ( void *data, size_t len ) {
        !           128:        /* FIXME: Some real random data source would be nice... */
        !           129:        memset ( data, 0x01, len );
        !           130: }
        !           131: 
        !           132: /**
        !           133:  * Update HMAC with a list of ( data, len ) pairs
        !           134:  *
        !           135:  * @v digest           Hash function to use
        !           136:  * @v digest_ctx       Digest context
        !           137:  * @v args             ( data, len ) pairs of data, terminated by NULL
        !           138:  */
        !           139: static void tls_hmac_update_va ( struct digest_algorithm *digest,
        !           140:                                 void *digest_ctx, va_list args ) {
        !           141:        void *data;
        !           142:        size_t len;
        !           143: 
        !           144:        while ( ( data = va_arg ( args, void * ) ) ) {
        !           145:                len = va_arg ( args, size_t );
        !           146:                hmac_update ( digest, digest_ctx, data, len );
        !           147:        }
        !           148: }
        !           149: 
        !           150: /**
        !           151:  * Generate secure pseudo-random data using a single hash function
        !           152:  *
        !           153:  * @v tls              TLS session
        !           154:  * @v digest           Hash function to use
        !           155:  * @v secret           Secret
        !           156:  * @v secret_len       Length of secret
        !           157:  * @v out              Output buffer
        !           158:  * @v out_len          Length of output buffer
        !           159:  * @v seeds            ( data, len ) pairs of seed data, terminated by NULL
        !           160:  */
        !           161: static void tls_p_hash_va ( struct tls_session *tls,
        !           162:                            struct digest_algorithm *digest,
        !           163:                            void *secret, size_t secret_len,
        !           164:                            void *out, size_t out_len,
        !           165:                            va_list seeds ) {
        !           166:        uint8_t secret_copy[secret_len];
        !           167:        uint8_t digest_ctx[digest->ctxsize];
        !           168:        uint8_t digest_ctx_partial[digest->ctxsize];
        !           169:        uint8_t a[digest->digestsize];
        !           170:        uint8_t out_tmp[digest->digestsize];
        !           171:        size_t frag_len = digest->digestsize;
        !           172:        va_list tmp;
        !           173: 
        !           174:        /* Copy the secret, in case HMAC modifies it */
        !           175:        memcpy ( secret_copy, secret, secret_len );
        !           176:        secret = secret_copy;
        !           177:        DBGC2 ( tls, "TLS %p %s secret:\n", tls, digest->name );
        !           178:        DBGC2_HD ( tls, secret, secret_len );
        !           179: 
        !           180:        /* Calculate A(1) */
        !           181:        hmac_init ( digest, digest_ctx, secret, &secret_len );
        !           182:        va_copy ( tmp, seeds );
        !           183:        tls_hmac_update_va ( digest, digest_ctx, tmp );
        !           184:        va_end ( tmp );
        !           185:        hmac_final ( digest, digest_ctx, secret, &secret_len, a );
        !           186:        DBGC2 ( tls, "TLS %p %s A(1):\n", tls, digest->name );
        !           187:        DBGC2_HD ( tls, &a, sizeof ( a ) );
        !           188: 
        !           189:        /* Generate as much data as required */
        !           190:        while ( out_len ) {
        !           191:                /* Calculate output portion */
        !           192:                hmac_init ( digest, digest_ctx, secret, &secret_len );
        !           193:                hmac_update ( digest, digest_ctx, a, sizeof ( a ) );
        !           194:                memcpy ( digest_ctx_partial, digest_ctx, digest->ctxsize );
        !           195:                va_copy ( tmp, seeds );
        !           196:                tls_hmac_update_va ( digest, digest_ctx, tmp );
        !           197:                va_end ( tmp );
        !           198:                hmac_final ( digest, digest_ctx,
        !           199:                             secret, &secret_len, out_tmp );
        !           200: 
        !           201:                /* Copy output */
        !           202:                if ( frag_len > out_len )
        !           203:                        frag_len = out_len;
        !           204:                memcpy ( out, out_tmp, frag_len );
        !           205:                DBGC2 ( tls, "TLS %p %s output:\n", tls, digest->name );
        !           206:                DBGC2_HD ( tls, out, frag_len );
        !           207: 
        !           208:                /* Calculate A(i) */
        !           209:                hmac_final ( digest, digest_ctx_partial,
        !           210:                             secret, &secret_len, a );
        !           211:                DBGC2 ( tls, "TLS %p %s A(n):\n", tls, digest->name );
        !           212:                DBGC2_HD ( tls, &a, sizeof ( a ) );
        !           213: 
        !           214:                out += frag_len;
        !           215:                out_len -= frag_len;
        !           216:        }
        !           217: }
        !           218: 
        !           219: /**
        !           220:  * Generate secure pseudo-random data
        !           221:  *
        !           222:  * @v tls              TLS session
        !           223:  * @v secret           Secret
        !           224:  * @v secret_len       Length of secret
        !           225:  * @v out              Output buffer
        !           226:  * @v out_len          Length of output buffer
        !           227:  * @v ...              ( data, len ) pairs of seed data, terminated by NULL
        !           228:  */
        !           229: static void tls_prf ( struct tls_session *tls, void *secret, size_t secret_len,
        !           230:                      void *out, size_t out_len, ... ) {
        !           231:        va_list seeds;
        !           232:        va_list tmp;
        !           233:        size_t subsecret_len;
        !           234:        void *md5_secret;
        !           235:        void *sha1_secret;
        !           236:        uint8_t out_md5[out_len];
        !           237:        uint8_t out_sha1[out_len];
        !           238:        unsigned int i;
        !           239: 
        !           240:        va_start ( seeds, out_len );
        !           241: 
        !           242:        /* Split secret into two, with an overlap of up to one byte */
        !           243:        subsecret_len = ( ( secret_len + 1 ) / 2 );
        !           244:        md5_secret = secret;
        !           245:        sha1_secret = ( secret + secret_len - subsecret_len );
        !           246: 
        !           247:        /* Calculate MD5 portion */
        !           248:        va_copy ( tmp, seeds );
        !           249:        tls_p_hash_va ( tls, &md5_algorithm, md5_secret, subsecret_len,
        !           250:                        out_md5, out_len, seeds );
        !           251:        va_end ( tmp );
        !           252: 
        !           253:        /* Calculate SHA1 portion */
        !           254:        va_copy ( tmp, seeds );
        !           255:        tls_p_hash_va ( tls, &sha1_algorithm, sha1_secret, subsecret_len,
        !           256:                        out_sha1, out_len, seeds );
        !           257:        va_end ( tmp );
        !           258: 
        !           259:        /* XOR the two portions together into the final output buffer */
        !           260:        for ( i = 0 ; i < out_len ; i++ ) {
        !           261:                *( ( uint8_t * ) out + i ) = ( out_md5[i] ^ out_sha1[i] );
        !           262:        }
        !           263: 
        !           264:        va_end ( seeds );
        !           265: }
        !           266: 
        !           267: /**
        !           268:  * Generate secure pseudo-random data
        !           269:  *
        !           270:  * @v secret           Secret
        !           271:  * @v secret_len       Length of secret
        !           272:  * @v out              Output buffer
        !           273:  * @v out_len          Length of output buffer
        !           274:  * @v label            String literal label
        !           275:  * @v ...              ( data, len ) pairs of seed data
        !           276:  */
        !           277: #define tls_prf_label( tls, secret, secret_len, out, out_len, label, ... ) \
        !           278:        tls_prf ( (tls), (secret), (secret_len), (out), (out_len),         \
        !           279:                  label, ( sizeof ( label ) - 1 ), __VA_ARGS__, NULL )
        !           280: 
        !           281: /******************************************************************************
        !           282:  *
        !           283:  * Secret management
        !           284:  *
        !           285:  ******************************************************************************
        !           286:  */
        !           287: 
        !           288: /**
        !           289:  * Generate master secret
        !           290:  *
        !           291:  * @v tls              TLS session
        !           292:  *
        !           293:  * The pre-master secret and the client and server random values must
        !           294:  * already be known.
        !           295:  */
        !           296: static void tls_generate_master_secret ( struct tls_session *tls ) {
        !           297:        DBGC ( tls, "TLS %p pre-master-secret:\n", tls );
        !           298:        DBGC_HD ( tls, &tls->pre_master_secret,
        !           299:                  sizeof ( tls->pre_master_secret ) );
        !           300:        DBGC ( tls, "TLS %p client random bytes:\n", tls );
        !           301:        DBGC_HD ( tls, &tls->client_random, sizeof ( tls->client_random ) );
        !           302:        DBGC ( tls, "TLS %p server random bytes:\n", tls );
        !           303:        DBGC_HD ( tls, &tls->server_random, sizeof ( tls->server_random ) );
        !           304: 
        !           305:        tls_prf_label ( tls, &tls->pre_master_secret,
        !           306:                        sizeof ( tls->pre_master_secret ),
        !           307:                        &tls->master_secret, sizeof ( tls->master_secret ),
        !           308:                        "master secret",
        !           309:                        &tls->client_random, sizeof ( tls->client_random ),
        !           310:                        &tls->server_random, sizeof ( tls->server_random ) );
        !           311: 
        !           312:        DBGC ( tls, "TLS %p generated master secret:\n", tls );
        !           313:        DBGC_HD ( tls, &tls->master_secret, sizeof ( tls->master_secret ) );
        !           314: }
        !           315: 
        !           316: /**
        !           317:  * Generate key material
        !           318:  *
        !           319:  * @v tls              TLS session
        !           320:  *
        !           321:  * The master secret must already be known.
        !           322:  */
        !           323: static int tls_generate_keys ( struct tls_session *tls ) {
        !           324:        struct tls_cipherspec *tx_cipherspec = &tls->tx_cipherspec_pending;
        !           325:        struct tls_cipherspec *rx_cipherspec = &tls->rx_cipherspec_pending;
        !           326:        size_t hash_size = tx_cipherspec->digest->digestsize;
        !           327:        size_t key_size = tx_cipherspec->key_len;
        !           328:        size_t iv_size = tx_cipherspec->cipher->blocksize;
        !           329:        size_t total = ( 2 * ( hash_size + key_size + iv_size ) );
        !           330:        uint8_t key_block[total];
        !           331:        uint8_t *key;
        !           332:        int rc;
        !           333: 
        !           334:        /* Generate key block */
        !           335:        tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ),
        !           336:                        key_block, sizeof ( key_block ), "key expansion",
        !           337:                        &tls->server_random, sizeof ( tls->server_random ),
        !           338:                        &tls->client_random, sizeof ( tls->client_random ) );
        !           339: 
        !           340:        /* Split key block into portions */
        !           341:        key = key_block;
        !           342: 
        !           343:        /* TX MAC secret */
        !           344:        memcpy ( tx_cipherspec->mac_secret, key, hash_size );
        !           345:        DBGC ( tls, "TLS %p TX MAC secret:\n", tls );
        !           346:        DBGC_HD ( tls, key, hash_size );
        !           347:        key += hash_size;
        !           348: 
        !           349:        /* RX MAC secret */
        !           350:        memcpy ( rx_cipherspec->mac_secret, key, hash_size );
        !           351:        DBGC ( tls, "TLS %p RX MAC secret:\n", tls );
        !           352:        DBGC_HD ( tls, key, hash_size );
        !           353:        key += hash_size;
        !           354: 
        !           355:        /* TX key */
        !           356:        if ( ( rc = cipher_setkey ( tx_cipherspec->cipher,
        !           357:                                    tx_cipherspec->cipher_ctx,
        !           358:                                    key, key_size ) ) != 0 ) {
        !           359:                DBGC ( tls, "TLS %p could not set TX key: %s\n",
        !           360:                       tls, strerror ( rc ) );
        !           361:                return rc;
        !           362:        }
        !           363:        DBGC ( tls, "TLS %p TX key:\n", tls );
        !           364:        DBGC_HD ( tls, key, key_size );
        !           365:        key += key_size;
        !           366: 
        !           367:        /* RX key */
        !           368:        if ( ( rc = cipher_setkey ( rx_cipherspec->cipher,
        !           369:                                    rx_cipherspec->cipher_ctx,
        !           370:                                    key, key_size ) ) != 0 ) {
        !           371:                DBGC ( tls, "TLS %p could not set TX key: %s\n",
        !           372:                       tls, strerror ( rc ) );
        !           373:                return rc;
        !           374:        }
        !           375:        DBGC ( tls, "TLS %p RX key:\n", tls );
        !           376:        DBGC_HD ( tls, key, key_size );
        !           377:        key += key_size;
        !           378: 
        !           379:        /* TX initialisation vector */
        !           380:        cipher_setiv ( tx_cipherspec->cipher, tx_cipherspec->cipher_ctx, key );
        !           381:        DBGC ( tls, "TLS %p TX IV:\n", tls );
        !           382:        DBGC_HD ( tls, key, iv_size );
        !           383:        key += iv_size;
        !           384: 
        !           385:        /* RX initialisation vector */
        !           386:        cipher_setiv ( rx_cipherspec->cipher, rx_cipherspec->cipher_ctx, key );
        !           387:        DBGC ( tls, "TLS %p RX IV:\n", tls );
        !           388:        DBGC_HD ( tls, key, iv_size );
        !           389:        key += iv_size;
        !           390: 
        !           391:        assert ( ( key_block + total ) == key );
        !           392: 
        !           393:        return 0;
        !           394: }
        !           395: 
        !           396: /******************************************************************************
        !           397:  *
        !           398:  * Cipher suite management
        !           399:  *
        !           400:  ******************************************************************************
        !           401:  */
        !           402: 
        !           403: /**
        !           404:  * Clear cipher suite
        !           405:  *
        !           406:  * @v cipherspec       TLS cipher specification
        !           407:  */
        !           408: static void tls_clear_cipher ( struct tls_session *tls __unused,
        !           409:                               struct tls_cipherspec *cipherspec ) {
        !           410:        free ( cipherspec->dynamic );
        !           411:        memset ( cipherspec, 0, sizeof ( cipherspec ) );
        !           412:        cipherspec->pubkey = &pubkey_null;
        !           413:        cipherspec->cipher = &cipher_null;
        !           414:        cipherspec->digest = &digest_null;
        !           415: }
        !           416: 
        !           417: /**
        !           418:  * Set cipher suite
        !           419:  *
        !           420:  * @v tls              TLS session
        !           421:  * @v cipherspec       TLS cipher specification
        !           422:  * @v pubkey           Public-key encryption elgorithm
        !           423:  * @v cipher           Bulk encryption cipher algorithm
        !           424:  * @v digest           MAC digest algorithm
        !           425:  * @v key_len          Key length
        !           426:  * @ret rc             Return status code
        !           427:  */
        !           428: static int tls_set_cipher ( struct tls_session *tls,
        !           429:                            struct tls_cipherspec *cipherspec,
        !           430:                            struct pubkey_algorithm *pubkey,
        !           431:                            struct cipher_algorithm *cipher,
        !           432:                            struct digest_algorithm *digest,
        !           433:                            size_t key_len ) {
        !           434:        size_t total;
        !           435:        void *dynamic;
        !           436: 
        !           437:        /* Clear out old cipher contents, if any */
        !           438:        tls_clear_cipher ( tls, cipherspec );
        !           439:        
        !           440:        /* Allocate dynamic storage */
        !           441:        total = ( pubkey->ctxsize + 2 * cipher->ctxsize + digest->digestsize );
        !           442:        dynamic = malloc ( total );
        !           443:        if ( ! dynamic ) {
        !           444:                DBGC ( tls, "TLS %p could not allocate %zd bytes for crypto "
        !           445:                       "context\n", tls, total );
        !           446:                return -ENOMEM;
        !           447:        }
        !           448:        memset ( dynamic, 0, total );
        !           449: 
        !           450:        /* Assign storage */
        !           451:        cipherspec->dynamic = dynamic;
        !           452:        cipherspec->pubkey_ctx = dynamic;       dynamic += pubkey->ctxsize;
        !           453:        cipherspec->cipher_ctx = dynamic;       dynamic += cipher->ctxsize;
        !           454:        cipherspec->cipher_next_ctx = dynamic;  dynamic += cipher->ctxsize;
        !           455:        cipherspec->mac_secret = dynamic;       dynamic += digest->digestsize;
        !           456:        assert ( ( cipherspec->dynamic + total ) == dynamic );
        !           457: 
        !           458:        /* Store parameters */
        !           459:        cipherspec->pubkey = pubkey;
        !           460:        cipherspec->cipher = cipher;
        !           461:        cipherspec->digest = digest;
        !           462:        cipherspec->key_len = key_len;
        !           463: 
        !           464:        return 0;
        !           465: }
        !           466: 
        !           467: /**
        !           468:  * Select next cipher suite
        !           469:  *
        !           470:  * @v tls              TLS session
        !           471:  * @v cipher_suite     Cipher suite specification
        !           472:  * @ret rc             Return status code
        !           473:  */
        !           474: static int tls_select_cipher ( struct tls_session *tls,
        !           475:                               unsigned int cipher_suite ) {
        !           476:        struct pubkey_algorithm *pubkey = &pubkey_null;
        !           477:        struct cipher_algorithm *cipher = &cipher_null;
        !           478:        struct digest_algorithm *digest = &digest_null;
        !           479:        unsigned int key_len = 0;
        !           480:        int rc;
        !           481: 
        !           482:        switch ( cipher_suite ) {
        !           483:        case htons ( TLS_RSA_WITH_AES_128_CBC_SHA ):
        !           484:                key_len = ( 128 / 8 );
        !           485:                cipher = &aes_cbc_algorithm;
        !           486:                digest = &sha1_algorithm;
        !           487:                break;
        !           488:        case htons ( TLS_RSA_WITH_AES_256_CBC_SHA ):
        !           489:                key_len = ( 256 / 8 );
        !           490:                cipher = &aes_cbc_algorithm;
        !           491:                digest = &sha1_algorithm;
        !           492:                break;
        !           493:        default:
        !           494:                DBGC ( tls, "TLS %p does not support cipher %04x\n",
        !           495:                       tls, ntohs ( cipher_suite ) );
        !           496:                return -ENOTSUP;
        !           497:        }
        !           498: 
        !           499:        /* Set ciphers */
        !           500:        if ( ( rc = tls_set_cipher ( tls, &tls->tx_cipherspec_pending, pubkey,
        !           501:                                     cipher, digest, key_len ) ) != 0 )
        !           502:                return rc;
        !           503:        if ( ( rc = tls_set_cipher ( tls, &tls->rx_cipherspec_pending, pubkey,
        !           504:                                     cipher, digest, key_len ) ) != 0 )
        !           505:                return rc;
        !           506: 
        !           507:        DBGC ( tls, "TLS %p selected %s-%s-%d-%s\n", tls,
        !           508:               pubkey->name, cipher->name, ( key_len * 8 ), digest->name );
        !           509: 
        !           510:        return 0;
        !           511: }
        !           512: 
        !           513: /**
        !           514:  * Activate next cipher suite
        !           515:  *
        !           516:  * @v tls              TLS session
        !           517:  * @v pending          Pending cipher specification
        !           518:  * @v active           Active cipher specification to replace
        !           519:  * @ret rc             Return status code
        !           520:  */
        !           521: static int tls_change_cipher ( struct tls_session *tls,
        !           522:                               struct tls_cipherspec *pending,
        !           523:                               struct tls_cipherspec *active ) {
        !           524: 
        !           525:        /* Sanity check */
        !           526:        if ( /* FIXME (when pubkey is not hard-coded to RSA):
        !           527:              * ( pending->pubkey == &pubkey_null ) || */
        !           528:             ( pending->cipher == &cipher_null ) ||
        !           529:             ( pending->digest == &digest_null ) ) {
        !           530:                DBGC ( tls, "TLS %p refusing to use null cipher\n", tls );
        !           531:                return -ENOTSUP;
        !           532:        }
        !           533: 
        !           534:        tls_clear_cipher ( tls, active );
        !           535:        memswap ( active, pending, sizeof ( *active ) );
        !           536:        return 0;
        !           537: }
        !           538: 
        !           539: /******************************************************************************
        !           540:  *
        !           541:  * Handshake verification
        !           542:  *
        !           543:  ******************************************************************************
        !           544:  */
        !           545: 
        !           546: /**
        !           547:  * Add handshake record to verification hash
        !           548:  *
        !           549:  * @v tls              TLS session
        !           550:  * @v data             Handshake record
        !           551:  * @v len              Length of handshake record
        !           552:  */
        !           553: static void tls_add_handshake ( struct tls_session *tls,
        !           554:                                const void *data, size_t len ) {
        !           555: 
        !           556:        digest_update ( &md5_algorithm, tls->handshake_md5_ctx, data, len );
        !           557:        digest_update ( &sha1_algorithm, tls->handshake_sha1_ctx, data, len );
        !           558: }
        !           559: 
        !           560: /**
        !           561:  * Calculate handshake verification hash
        !           562:  *
        !           563:  * @v tls              TLS session
        !           564:  * @v out              Output buffer
        !           565:  *
        !           566:  * Calculates the MD5+SHA1 digest over all handshake messages seen so
        !           567:  * far.
        !           568:  */
        !           569: static void tls_verify_handshake ( struct tls_session *tls, void *out ) {
        !           570:        struct digest_algorithm *md5 = &md5_algorithm;
        !           571:        struct digest_algorithm *sha1 = &sha1_algorithm;
        !           572:        uint8_t md5_ctx[md5->ctxsize];
        !           573:        uint8_t sha1_ctx[sha1->ctxsize];
        !           574:        void *md5_digest = out;
        !           575:        void *sha1_digest = ( out + md5->digestsize );
        !           576: 
        !           577:        memcpy ( md5_ctx, tls->handshake_md5_ctx, sizeof ( md5_ctx ) );
        !           578:        memcpy ( sha1_ctx, tls->handshake_sha1_ctx, sizeof ( sha1_ctx ) );
        !           579:        digest_final ( md5, md5_ctx, md5_digest );
        !           580:        digest_final ( sha1, sha1_ctx, sha1_digest );
        !           581: }
        !           582: 
        !           583: /******************************************************************************
        !           584:  *
        !           585:  * Record handling
        !           586:  *
        !           587:  ******************************************************************************
        !           588:  */
        !           589: 
        !           590: /**
        !           591:  * Transmit Handshake record
        !           592:  *
        !           593:  * @v tls              TLS session
        !           594:  * @v data             Plaintext record
        !           595:  * @v len              Length of plaintext record
        !           596:  * @ret rc             Return status code
        !           597:  */
        !           598: static int tls_send_handshake ( struct tls_session *tls,
        !           599:                                void *data, size_t len ) {
        !           600: 
        !           601:        /* Add to handshake digest */
        !           602:        tls_add_handshake ( tls, data, len );
        !           603: 
        !           604:        /* Send record */
        !           605:        return tls_send_plaintext ( tls, TLS_TYPE_HANDSHAKE, data, len );
        !           606: }
        !           607: 
        !           608: /**
        !           609:  * Transmit Client Hello record
        !           610:  *
        !           611:  * @v tls              TLS session
        !           612:  * @ret rc             Return status code
        !           613:  */
        !           614: static int tls_send_client_hello ( struct tls_session *tls ) {
        !           615:        struct {
        !           616:                uint32_t type_length;
        !           617:                uint16_t version;
        !           618:                uint8_t random[32];
        !           619:                uint8_t session_id_len;
        !           620:                uint16_t cipher_suite_len;
        !           621:                uint16_t cipher_suites[2];
        !           622:                uint8_t compression_methods_len;
        !           623:                uint8_t compression_methods[1];
        !           624:        } __attribute__ (( packed )) hello;
        !           625: 
        !           626:        memset ( &hello, 0, sizeof ( hello ) );
        !           627:        hello.type_length = ( cpu_to_le32 ( TLS_CLIENT_HELLO ) |
        !           628:                              htonl ( sizeof ( hello ) -
        !           629:                                      sizeof ( hello.type_length ) ) );
        !           630:        hello.version = htons ( TLS_VERSION_TLS_1_0 );
        !           631:        memcpy ( &hello.random, &tls->client_random, sizeof ( hello.random ) );
        !           632:        hello.cipher_suite_len = htons ( sizeof ( hello.cipher_suites ) );
        !           633:        hello.cipher_suites[0] = htons ( TLS_RSA_WITH_AES_128_CBC_SHA );
        !           634:        hello.cipher_suites[1] = htons ( TLS_RSA_WITH_AES_256_CBC_SHA );
        !           635:        hello.compression_methods_len = sizeof ( hello.compression_methods );
        !           636: 
        !           637:        return tls_send_handshake ( tls, &hello, sizeof ( hello ) );
        !           638: }
        !           639: 
        !           640: /**
        !           641:  * Transmit Client Key Exchange record
        !           642:  *
        !           643:  * @v tls              TLS session
        !           644:  * @ret rc             Return status code
        !           645:  */
        !           646: static int tls_send_client_key_exchange ( struct tls_session *tls ) {
        !           647:        /* FIXME: Hack alert */
        !           648:        RSA_CTX *rsa_ctx;
        !           649:        RSA_pub_key_new ( &rsa_ctx, tls->rsa.modulus, tls->rsa.modulus_len,
        !           650:                          tls->rsa.exponent, tls->rsa.exponent_len );
        !           651:        struct {
        !           652:                uint32_t type_length;
        !           653:                uint16_t encrypted_pre_master_secret_len;
        !           654:                uint8_t encrypted_pre_master_secret[rsa_ctx->num_octets];
        !           655:        } __attribute__ (( packed )) key_xchg;
        !           656: 
        !           657:        memset ( &key_xchg, 0, sizeof ( key_xchg ) );
        !           658:        key_xchg.type_length = ( cpu_to_le32 ( TLS_CLIENT_KEY_EXCHANGE ) |
        !           659:                                 htonl ( sizeof ( key_xchg ) -
        !           660:                                         sizeof ( key_xchg.type_length ) ) );
        !           661:        key_xchg.encrypted_pre_master_secret_len
        !           662:                = htons ( sizeof ( key_xchg.encrypted_pre_master_secret ) );
        !           663: 
        !           664:        /* FIXME: Hack alert */
        !           665:        DBGC ( tls, "RSA encrypting plaintext, modulus, exponent:\n" );
        !           666:        DBGC_HD ( tls, &tls->pre_master_secret,
        !           667:                  sizeof ( tls->pre_master_secret ) );
        !           668:        DBGC_HD ( tls, tls->rsa.modulus, tls->rsa.modulus_len );
        !           669:        DBGC_HD ( tls, tls->rsa.exponent, tls->rsa.exponent_len );
        !           670:        RSA_encrypt ( rsa_ctx, ( const uint8_t * ) &tls->pre_master_secret,
        !           671:                      sizeof ( tls->pre_master_secret ),
        !           672:                      key_xchg.encrypted_pre_master_secret, 0 );
        !           673:        DBGC ( tls, "RSA encrypt done.  Ciphertext:\n" );
        !           674:        DBGC_HD ( tls, &key_xchg.encrypted_pre_master_secret,
        !           675:                  sizeof ( key_xchg.encrypted_pre_master_secret ) );
        !           676:        RSA_free ( rsa_ctx );
        !           677: 
        !           678: 
        !           679:        return tls_send_handshake ( tls, &key_xchg, sizeof ( key_xchg ) );
        !           680: }
        !           681: 
        !           682: /**
        !           683:  * Transmit Change Cipher record
        !           684:  *
        !           685:  * @v tls              TLS session
        !           686:  * @ret rc             Return status code
        !           687:  */
        !           688: static int tls_send_change_cipher ( struct tls_session *tls ) {
        !           689:        static const uint8_t change_cipher[1] = { 1 };
        !           690:        return tls_send_plaintext ( tls, TLS_TYPE_CHANGE_CIPHER,
        !           691:                                    change_cipher, sizeof ( change_cipher ) );
        !           692: }
        !           693: 
        !           694: /**
        !           695:  * Transmit Finished record
        !           696:  *
        !           697:  * @v tls              TLS session
        !           698:  * @ret rc             Return status code
        !           699:  */
        !           700: static int tls_send_finished ( struct tls_session *tls ) {
        !           701:        struct {
        !           702:                uint32_t type_length;
        !           703:                uint8_t verify_data[12];
        !           704:        } __attribute__ (( packed )) finished;
        !           705:        uint8_t digest[MD5_DIGEST_SIZE + SHA1_DIGEST_SIZE];
        !           706: 
        !           707:        memset ( &finished, 0, sizeof ( finished ) );
        !           708:        finished.type_length = ( cpu_to_le32 ( TLS_FINISHED ) |
        !           709:                                 htonl ( sizeof ( finished ) -
        !           710:                                         sizeof ( finished.type_length ) ) );
        !           711:        tls_verify_handshake ( tls, digest );
        !           712:        tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ),
        !           713:                        finished.verify_data, sizeof ( finished.verify_data ),
        !           714:                        "client finished", digest, sizeof ( digest ) );
        !           715: 
        !           716:        return tls_send_handshake ( tls, &finished, sizeof ( finished ) );
        !           717: }
        !           718: 
        !           719: /**
        !           720:  * Receive new Change Cipher record
        !           721:  *
        !           722:  * @v tls              TLS session
        !           723:  * @v data             Plaintext record
        !           724:  * @v len              Length of plaintext record
        !           725:  * @ret rc             Return status code
        !           726:  */
        !           727: static int tls_new_change_cipher ( struct tls_session *tls,
        !           728:                                   void *data, size_t len ) {
        !           729:        int rc;
        !           730: 
        !           731:        if ( ( len != 1 ) || ( *( ( uint8_t * ) data ) != 1 ) ) {
        !           732:                DBGC ( tls, "TLS %p received invalid Change Cipher\n", tls );
        !           733:                DBGC_HD ( tls, data, len );
        !           734:                return -EINVAL;
        !           735:        }
        !           736: 
        !           737:        if ( ( rc = tls_change_cipher ( tls, &tls->rx_cipherspec_pending,
        !           738:                                        &tls->rx_cipherspec ) ) != 0 ) {
        !           739:                DBGC ( tls, "TLS %p could not activate RX cipher: %s\n",
        !           740:                       tls, strerror ( rc ) );
        !           741:                return rc;
        !           742:        }
        !           743:        tls->rx_seq = ~( ( uint64_t ) 0 );
        !           744: 
        !           745:        return 0;
        !           746: }
        !           747: 
        !           748: /**
        !           749:  * Receive new Alert record
        !           750:  *
        !           751:  * @v tls              TLS session
        !           752:  * @v data             Plaintext record
        !           753:  * @v len              Length of plaintext record
        !           754:  * @ret rc             Return status code
        !           755:  */
        !           756: static int tls_new_alert ( struct tls_session *tls, void *data, size_t len ) {
        !           757:        struct {
        !           758:                uint8_t level;
        !           759:                uint8_t description;
        !           760:                char next[0];
        !           761:        } __attribute__ (( packed )) *alert = data;
        !           762:        void *end = alert->next;
        !           763: 
        !           764:        /* Sanity check */
        !           765:        if ( end != ( data + len ) ) {
        !           766:                DBGC ( tls, "TLS %p received overlength Alert\n", tls );
        !           767:                DBGC_HD ( tls, data, len );
        !           768:                return -EINVAL;
        !           769:        }
        !           770: 
        !           771:        switch ( alert->level ) {
        !           772:        case TLS_ALERT_WARNING:
        !           773:                DBGC ( tls, "TLS %p received warning alert %d\n",
        !           774:                       tls, alert->description );
        !           775:                return 0;
        !           776:        case TLS_ALERT_FATAL:
        !           777:                DBGC ( tls, "TLS %p received fatal alert %d\n",
        !           778:                       tls, alert->description );
        !           779:                return -EPERM;
        !           780:        default:
        !           781:                DBGC ( tls, "TLS %p received unknown alert level %d"
        !           782:                       "(alert %d)\n", tls, alert->level, alert->description );
        !           783:                return -EIO;
        !           784:        }
        !           785: }
        !           786: 
        !           787: /**
        !           788:  * Receive new Server Hello handshake record
        !           789:  *
        !           790:  * @v tls              TLS session
        !           791:  * @v data             Plaintext handshake record
        !           792:  * @v len              Length of plaintext handshake record
        !           793:  * @ret rc             Return status code
        !           794:  */
        !           795: static int tls_new_server_hello ( struct tls_session *tls,
        !           796:                                  void *data, size_t len ) {
        !           797:        struct {
        !           798:                uint16_t version;
        !           799:                uint8_t random[32];
        !           800:                uint8_t session_id_len;
        !           801:                char next[0];
        !           802:        } __attribute__ (( packed )) *hello_a = data;
        !           803:        struct {
        !           804:                uint8_t session_id[hello_a->session_id_len];
        !           805:                uint16_t cipher_suite;
        !           806:                uint8_t compression_method;
        !           807:                char next[0];
        !           808:        } __attribute__ (( packed )) *hello_b = ( void * ) &hello_a->next;
        !           809:        void *end = hello_b->next;
        !           810:        int rc;
        !           811: 
        !           812:        /* Sanity check */
        !           813:        if ( end != ( data + len ) ) {
        !           814:                DBGC ( tls, "TLS %p received overlength Server Hello\n", tls );
        !           815:                DBGC_HD ( tls, data, len );
        !           816:                return -EINVAL;
        !           817:        }
        !           818: 
        !           819:        /* Check protocol version */
        !           820:        if ( ntohs ( hello_a->version ) < TLS_VERSION_TLS_1_0 ) {
        !           821:                DBGC ( tls, "TLS %p does not support protocol version %d.%d\n",
        !           822:                       tls, ( ntohs ( hello_a->version ) >> 8 ),
        !           823:                       ( ntohs ( hello_a->version ) & 0xff ) );
        !           824:                return -ENOTSUP;
        !           825:        }
        !           826: 
        !           827:        /* Copy out server random bytes */
        !           828:        memcpy ( &tls->server_random, &hello_a->random,
        !           829:                 sizeof ( tls->server_random ) );
        !           830: 
        !           831:        /* Select cipher suite */
        !           832:        if ( ( rc = tls_select_cipher ( tls, hello_b->cipher_suite ) ) != 0 )
        !           833:                return rc;
        !           834: 
        !           835:        /* Generate secrets */
        !           836:        tls_generate_master_secret ( tls );
        !           837:        if ( ( rc = tls_generate_keys ( tls ) ) != 0 )
        !           838:                return rc;
        !           839: 
        !           840:        return 0;
        !           841: }
        !           842: 
        !           843: /**
        !           844:  * Receive new Certificate handshake record
        !           845:  *
        !           846:  * @v tls              TLS session
        !           847:  * @v data             Plaintext handshake record
        !           848:  * @v len              Length of plaintext handshake record
        !           849:  * @ret rc             Return status code
        !           850:  */
        !           851: static int tls_new_certificate ( struct tls_session *tls,
        !           852:                                 void *data, size_t len ) {
        !           853:        struct {
        !           854:                uint8_t length[3];
        !           855:                uint8_t certificates[0];
        !           856:        } __attribute__ (( packed )) *certificate = data;
        !           857:        struct {
        !           858:                uint8_t length[3];
        !           859:                uint8_t certificate[0];
        !           860:        } __attribute__ (( packed )) *element =
        !           861:                  ( ( void * ) certificate->certificates );
        !           862:        size_t elements_len = tls_uint24 ( certificate->length );
        !           863:        void *end = ( certificate->certificates + elements_len );
        !           864:        struct asn1_cursor cursor;
        !           865:        int rc;
        !           866: 
        !           867:        /* Sanity check */
        !           868:        if ( end != ( data + len ) ) {
        !           869:                DBGC ( tls, "TLS %p received overlength Server Certificate\n",
        !           870:                       tls );
        !           871:                DBGC_HD ( tls, data, len );
        !           872:                return -EINVAL;
        !           873:        }
        !           874: 
        !           875:        /* Traverse certificate chain */
        !           876:        do {
        !           877:                cursor.data = element->certificate;
        !           878:                cursor.len = tls_uint24 ( element->length );
        !           879:                if ( ( cursor.data + cursor.len ) > end ) {
        !           880:                        DBGC ( tls, "TLS %p received corrupt Server "
        !           881:                               "Certificate\n", tls );
        !           882:                        DBGC_HD ( tls, data, len );
        !           883:                        return -EINVAL;
        !           884:                }
        !           885: 
        !           886:                // HACK
        !           887:                if ( ( rc = x509_rsa_public_key ( &cursor,
        !           888:                                                  &tls->rsa ) ) != 0 ) {
        !           889:                        DBGC ( tls, "TLS %p cannot determine RSA public key: "
        !           890:                               "%s\n", tls, strerror ( rc ) );
        !           891:                        return rc;
        !           892:                }
        !           893:                return 0;
        !           894: 
        !           895:                element = ( cursor.data + cursor.len );
        !           896:        } while ( element != end );
        !           897: 
        !           898:        return -EINVAL;
        !           899: }
        !           900: 
        !           901: /**
        !           902:  * Receive new Server Hello Done handshake record
        !           903:  *
        !           904:  * @v tls              TLS session
        !           905:  * @v data             Plaintext handshake record
        !           906:  * @v len              Length of plaintext handshake record
        !           907:  * @ret rc             Return status code
        !           908:  */
        !           909: static int tls_new_server_hello_done ( struct tls_session *tls,
        !           910:                                       void *data, size_t len ) {
        !           911:        struct {
        !           912:                char next[0];
        !           913:        } __attribute__ (( packed )) *hello_done = data;
        !           914:        void *end = hello_done->next;
        !           915: 
        !           916:        /* Sanity check */
        !           917:        if ( end != ( data + len ) ) {
        !           918:                DBGC ( tls, "TLS %p received overlength Server Hello Done\n",
        !           919:                       tls );
        !           920:                DBGC_HD ( tls, data, len );
        !           921:                return -EINVAL;
        !           922:        }
        !           923: 
        !           924:        /* Check that we are ready to send the Client Key Exchange */
        !           925:        if ( tls->tx_state != TLS_TX_NONE ) {
        !           926:                DBGC ( tls, "TLS %p received Server Hello Done while in "
        !           927:                       "TX state %d\n", tls, tls->tx_state );
        !           928:                return -EIO;
        !           929:        }
        !           930: 
        !           931:        /* Start sending the Client Key Exchange */
        !           932:        tls->tx_state = TLS_TX_CLIENT_KEY_EXCHANGE;
        !           933: 
        !           934:        return 0;
        !           935: }
        !           936: 
        !           937: /**
        !           938:  * Receive new Finished handshake record
        !           939:  *
        !           940:  * @v tls              TLS session
        !           941:  * @v data             Plaintext handshake record
        !           942:  * @v len              Length of plaintext handshake record
        !           943:  * @ret rc             Return status code
        !           944:  */
        !           945: static int tls_new_finished ( struct tls_session *tls,
        !           946:                              void *data, size_t len ) {
        !           947: 
        !           948:        /* FIXME: Handle this properly */
        !           949:        tls->tx_state = TLS_TX_DATA;
        !           950:        ( void ) data;
        !           951:        ( void ) len;
        !           952:        return 0;
        !           953: }
        !           954: 
        !           955: /**
        !           956:  * Receive new Handshake record
        !           957:  *
        !           958:  * @v tls              TLS session
        !           959:  * @v data             Plaintext record
        !           960:  * @v len              Length of plaintext record
        !           961:  * @ret rc             Return status code
        !           962:  */
        !           963: static int tls_new_handshake ( struct tls_session *tls,
        !           964:                               void *data, size_t len ) {
        !           965:        void *end = ( data + len );
        !           966:        int rc;
        !           967: 
        !           968:        while ( data != end ) {
        !           969:                struct {
        !           970:                        uint8_t type;
        !           971:                        uint8_t length[3];
        !           972:                        uint8_t payload[0];
        !           973:                } __attribute__ (( packed )) *handshake = data;
        !           974:                void *payload = &handshake->payload;
        !           975:                size_t payload_len = tls_uint24 ( handshake->length );
        !           976:                void *next = ( payload + payload_len );
        !           977: 
        !           978:                /* Sanity check */
        !           979:                if ( next > end ) {
        !           980:                        DBGC ( tls, "TLS %p received overlength Handshake\n",
        !           981:                               tls );
        !           982:                        DBGC_HD ( tls, data, len );
        !           983:                        return -EINVAL;
        !           984:                }
        !           985: 
        !           986:                switch ( handshake->type ) {
        !           987:                case TLS_SERVER_HELLO:
        !           988:                        rc = tls_new_server_hello ( tls, payload, payload_len );
        !           989:                        break;
        !           990:                case TLS_CERTIFICATE:
        !           991:                        rc = tls_new_certificate ( tls, payload, payload_len );
        !           992:                        break;
        !           993:                case TLS_SERVER_HELLO_DONE:
        !           994:                        rc = tls_new_server_hello_done ( tls, payload,
        !           995:                                                         payload_len );
        !           996:                        break;
        !           997:                case TLS_FINISHED:
        !           998:                        rc = tls_new_finished ( tls, payload, payload_len );
        !           999:                        break;
        !          1000:                default:
        !          1001:                        DBGC ( tls, "TLS %p ignoring handshake type %d\n",
        !          1002:                               tls, handshake->type );
        !          1003:                        rc = 0;
        !          1004:                        break;
        !          1005:                }
        !          1006: 
        !          1007:                /* Add to handshake digest (except for Hello Requests,
        !          1008:                 * which are explicitly excluded).
        !          1009:                 */
        !          1010:                if ( handshake->type != TLS_HELLO_REQUEST )
        !          1011:                        tls_add_handshake ( tls, data,
        !          1012:                                            sizeof ( *handshake ) +
        !          1013:                                            payload_len );
        !          1014: 
        !          1015:                /* Abort on failure */
        !          1016:                if ( rc != 0 )
        !          1017:                        return rc;
        !          1018: 
        !          1019:                /* Move to next handshake record */
        !          1020:                data = next;
        !          1021:        }
        !          1022: 
        !          1023:        return 0;
        !          1024: }
        !          1025: 
        !          1026: /**
        !          1027:  * Receive new record
        !          1028:  *
        !          1029:  * @v tls              TLS session
        !          1030:  * @v type             Record type
        !          1031:  * @v data             Plaintext record
        !          1032:  * @v len              Length of plaintext record
        !          1033:  * @ret rc             Return status code
        !          1034:  */
        !          1035: static int tls_new_record ( struct tls_session *tls,
        !          1036:                            unsigned int type, void *data, size_t len ) {
        !          1037: 
        !          1038:        switch ( type ) {
        !          1039:        case TLS_TYPE_CHANGE_CIPHER:
        !          1040:                return tls_new_change_cipher ( tls, data, len );
        !          1041:        case TLS_TYPE_ALERT:
        !          1042:                return tls_new_alert ( tls, data, len );
        !          1043:        case TLS_TYPE_HANDSHAKE:
        !          1044:                return tls_new_handshake ( tls, data, len );
        !          1045:        case TLS_TYPE_DATA:
        !          1046:                return xfer_deliver_raw ( &tls->plainstream, data, len );
        !          1047:        default:
        !          1048:                /* RFC4346 says that we should just ignore unknown
        !          1049:                 * record types.
        !          1050:                 */
        !          1051:                DBGC ( tls, "TLS %p ignoring record type %d\n", tls, type );
        !          1052:                return 0;
        !          1053:        }
        !          1054: }
        !          1055: 
        !          1056: /******************************************************************************
        !          1057:  *
        !          1058:  * Record encryption/decryption
        !          1059:  *
        !          1060:  ******************************************************************************
        !          1061:  */
        !          1062: 
        !          1063: /**
        !          1064:  * Calculate HMAC
        !          1065:  *
        !          1066:  * @v tls              TLS session
        !          1067:  * @v cipherspec       Cipher specification
        !          1068:  * @v seq              Sequence number
        !          1069:  * @v tlshdr           TLS header
        !          1070:  * @v data             Data
        !          1071:  * @v len              Length of data
        !          1072:  * @v mac              HMAC to fill in
        !          1073:  */
        !          1074: static void tls_hmac ( struct tls_session *tls __unused,
        !          1075:                       struct tls_cipherspec *cipherspec,
        !          1076:                       uint64_t seq, struct tls_header *tlshdr,
        !          1077:                       const void *data, size_t len, void *hmac ) {
        !          1078:        struct digest_algorithm *digest = cipherspec->digest;
        !          1079:        uint8_t digest_ctx[digest->ctxsize];
        !          1080: 
        !          1081:        hmac_init ( digest, digest_ctx, cipherspec->mac_secret,
        !          1082:                    &digest->digestsize );
        !          1083:        seq = cpu_to_be64 ( seq );
        !          1084:        hmac_update ( digest, digest_ctx, &seq, sizeof ( seq ) );
        !          1085:        hmac_update ( digest, digest_ctx, tlshdr, sizeof ( *tlshdr ) );
        !          1086:        hmac_update ( digest, digest_ctx, data, len );
        !          1087:        hmac_final ( digest, digest_ctx, cipherspec->mac_secret,
        !          1088:                     &digest->digestsize, hmac );
        !          1089: }
        !          1090: 
        !          1091: /**
        !          1092:  * Allocate and assemble stream-ciphered record from data and MAC portions
        !          1093:  *
        !          1094:  * @v tls              TLS session
        !          1095:  * @ret data           Data
        !          1096:  * @ret len            Length of data
        !          1097:  * @ret digest         MAC digest
        !          1098:  * @ret plaintext_len  Length of plaintext record
        !          1099:  * @ret plaintext      Allocated plaintext record
        !          1100:  */
        !          1101: static void * __malloc tls_assemble_stream ( struct tls_session *tls,
        !          1102:                                    const void *data, size_t len,
        !          1103:                                    void *digest, size_t *plaintext_len ) {
        !          1104:        size_t mac_len = tls->tx_cipherspec.digest->digestsize;
        !          1105:        void *plaintext;
        !          1106:        void *content;
        !          1107:        void *mac;
        !          1108: 
        !          1109:        /* Calculate stream-ciphered struct length */
        !          1110:        *plaintext_len = ( len + mac_len );
        !          1111: 
        !          1112:        /* Allocate stream-ciphered struct */
        !          1113:        plaintext = malloc ( *plaintext_len );
        !          1114:        if ( ! plaintext )
        !          1115:                return NULL;
        !          1116:        content = plaintext;
        !          1117:        mac = ( content + len );
        !          1118: 
        !          1119:        /* Fill in stream-ciphered struct */
        !          1120:        memcpy ( content, data, len );
        !          1121:        memcpy ( mac, digest, mac_len );
        !          1122: 
        !          1123:        return plaintext;
        !          1124: }
        !          1125: 
        !          1126: /**
        !          1127:  * Allocate and assemble block-ciphered record from data and MAC portions
        !          1128:  *
        !          1129:  * @v tls              TLS session
        !          1130:  * @ret data           Data
        !          1131:  * @ret len            Length of data
        !          1132:  * @ret digest         MAC digest
        !          1133:  * @ret plaintext_len  Length of plaintext record
        !          1134:  * @ret plaintext      Allocated plaintext record
        !          1135:  */
        !          1136: static void * tls_assemble_block ( struct tls_session *tls,
        !          1137:                                   const void *data, size_t len,
        !          1138:                                   void *digest, size_t *plaintext_len ) {
        !          1139:        size_t blocksize = tls->tx_cipherspec.cipher->blocksize;
        !          1140:        size_t iv_len = blocksize;
        !          1141:        size_t mac_len = tls->tx_cipherspec.digest->digestsize;
        !          1142:        size_t padding_len;
        !          1143:        void *plaintext;
        !          1144:        void *iv;
        !          1145:        void *content;
        !          1146:        void *mac;
        !          1147:        void *padding;
        !          1148: 
        !          1149:        /* FIXME: TLSv1.1 has an explicit IV */
        !          1150:        iv_len = 0;
        !          1151: 
        !          1152:        /* Calculate block-ciphered struct length */
        !          1153:        padding_len = ( ( blocksize - 1 ) & -( iv_len + len + mac_len + 1 ) );
        !          1154:        *plaintext_len = ( iv_len + len + mac_len + padding_len + 1 );
        !          1155: 
        !          1156:        /* Allocate block-ciphered struct */
        !          1157:        plaintext = malloc ( *plaintext_len );
        !          1158:        if ( ! plaintext )
        !          1159:                return NULL;
        !          1160:        iv = plaintext;
        !          1161:        content = ( iv + iv_len );
        !          1162:        mac = ( content + len );
        !          1163:        padding = ( mac + mac_len );
        !          1164: 
        !          1165:        /* Fill in block-ciphered struct */
        !          1166:        memset ( iv, 0, iv_len );
        !          1167:        memcpy ( content, data, len );
        !          1168:        memcpy ( mac, digest, mac_len );
        !          1169:        memset ( padding, padding_len, ( padding_len + 1 ) );
        !          1170: 
        !          1171:        return plaintext;
        !          1172: }
        !          1173: 
        !          1174: /**
        !          1175:  * Send plaintext record
        !          1176:  *
        !          1177:  * @v tls              TLS session
        !          1178:  * @v type             Record type
        !          1179:  * @v data             Plaintext record
        !          1180:  * @v len              Length of plaintext record
        !          1181:  * @ret rc             Return status code
        !          1182:  */
        !          1183: static int tls_send_plaintext ( struct tls_session *tls, unsigned int type,
        !          1184:                                const void *data, size_t len ) {
        !          1185:        struct tls_header plaintext_tlshdr;
        !          1186:        struct tls_header *tlshdr;
        !          1187:        struct tls_cipherspec *cipherspec = &tls->tx_cipherspec;
        !          1188:        void *plaintext = NULL;
        !          1189:        size_t plaintext_len;
        !          1190:        struct io_buffer *ciphertext = NULL;
        !          1191:        size_t ciphertext_len;
        !          1192:        size_t mac_len = cipherspec->digest->digestsize;
        !          1193:        uint8_t mac[mac_len];
        !          1194:        int rc;
        !          1195: 
        !          1196:        /* Construct header */
        !          1197:        plaintext_tlshdr.type = type;
        !          1198:        plaintext_tlshdr.version = htons ( TLS_VERSION_TLS_1_0 );
        !          1199:        plaintext_tlshdr.length = htons ( len );
        !          1200: 
        !          1201:        /* Calculate MAC */
        !          1202:        tls_hmac ( tls, cipherspec, tls->tx_seq, &plaintext_tlshdr,
        !          1203:                   data, len, mac );
        !          1204: 
        !          1205:        /* Allocate and assemble plaintext struct */
        !          1206:        if ( is_stream_cipher ( cipherspec->cipher ) ) {
        !          1207:                plaintext = tls_assemble_stream ( tls, data, len, mac,
        !          1208:                                                  &plaintext_len );
        !          1209:        } else {
        !          1210:                plaintext = tls_assemble_block ( tls, data, len, mac,
        !          1211:                                                 &plaintext_len );
        !          1212:        }
        !          1213:        if ( ! plaintext ) {
        !          1214:                DBGC ( tls, "TLS %p could not allocate %zd bytes for "
        !          1215:                       "plaintext\n", tls, plaintext_len );
        !          1216:                rc = -ENOMEM;
        !          1217:                goto done;
        !          1218:        }
        !          1219: 
        !          1220:        DBGC2 ( tls, "Sending plaintext data:\n" );
        !          1221:        DBGC2_HD ( tls, plaintext, plaintext_len );
        !          1222: 
        !          1223:        /* Allocate ciphertext */
        !          1224:        ciphertext_len = ( sizeof ( *tlshdr ) + plaintext_len );
        !          1225:        ciphertext = xfer_alloc_iob ( &tls->cipherstream, ciphertext_len );
        !          1226:        if ( ! ciphertext ) {
        !          1227:                DBGC ( tls, "TLS %p could not allocate %zd bytes for "
        !          1228:                       "ciphertext\n", tls, ciphertext_len );
        !          1229:                rc = -ENOMEM;
        !          1230:                goto done;
        !          1231:        }
        !          1232: 
        !          1233:        /* Assemble ciphertext */
        !          1234:        tlshdr = iob_put ( ciphertext, sizeof ( *tlshdr ) );
        !          1235:        tlshdr->type = type;
        !          1236:        tlshdr->version = htons ( TLS_VERSION_TLS_1_0 );
        !          1237:        tlshdr->length = htons ( plaintext_len );
        !          1238:        memcpy ( cipherspec->cipher_next_ctx, cipherspec->cipher_ctx,
        !          1239:                 cipherspec->cipher->ctxsize );
        !          1240:        cipher_encrypt ( cipherspec->cipher, cipherspec->cipher_next_ctx,
        !          1241:                         plaintext, iob_put ( ciphertext, plaintext_len ),
        !          1242:                         plaintext_len );
        !          1243: 
        !          1244:        /* Free plaintext as soon as possible to conserve memory */
        !          1245:        free ( plaintext );
        !          1246:        plaintext = NULL;
        !          1247: 
        !          1248:        /* Send ciphertext */
        !          1249:        if ( ( rc = xfer_deliver_iob ( &tls->cipherstream,
        !          1250:                                       iob_disown ( ciphertext ) ) ) != 0 ) {
        !          1251:                DBGC ( tls, "TLS %p could not deliver ciphertext: %s\n",
        !          1252:                       tls, strerror ( rc ) );
        !          1253:                goto done;
        !          1254:        }
        !          1255: 
        !          1256:        /* Update TX state machine to next record */
        !          1257:        tls->tx_seq += 1;
        !          1258:        memcpy ( tls->tx_cipherspec.cipher_ctx,
        !          1259:                 tls->tx_cipherspec.cipher_next_ctx,
        !          1260:                 tls->tx_cipherspec.cipher->ctxsize );
        !          1261: 
        !          1262:  done:
        !          1263:        free ( plaintext );
        !          1264:        free_iob ( ciphertext );
        !          1265:        return rc;
        !          1266: }
        !          1267: 
        !          1268: /**
        !          1269:  * Split stream-ciphered record into data and MAC portions
        !          1270:  *
        !          1271:  * @v tls              TLS session
        !          1272:  * @v plaintext                Plaintext record
        !          1273:  * @v plaintext_len    Length of record
        !          1274:  * @ret data           Data
        !          1275:  * @ret len            Length of data
        !          1276:  * @ret digest         MAC digest
        !          1277:  * @ret rc             Return status code
        !          1278:  */
        !          1279: static int tls_split_stream ( struct tls_session *tls,
        !          1280:                              void *plaintext, size_t plaintext_len,
        !          1281:                              void **data, size_t *len, void **digest ) {
        !          1282:        void *content;
        !          1283:        size_t content_len;
        !          1284:        void *mac;
        !          1285:        size_t mac_len;
        !          1286: 
        !          1287:        /* Decompose stream-ciphered data */
        !          1288:        mac_len = tls->rx_cipherspec.digest->digestsize;
        !          1289:        if ( plaintext_len < mac_len ) {
        !          1290:                DBGC ( tls, "TLS %p received underlength record\n", tls );
        !          1291:                DBGC_HD ( tls, plaintext, plaintext_len );
        !          1292:                return -EINVAL;
        !          1293:        }
        !          1294:        content_len = ( plaintext_len - mac_len );
        !          1295:        content = plaintext;
        !          1296:        mac = ( content + content_len );
        !          1297: 
        !          1298:        /* Fill in return values */
        !          1299:        *data = content;
        !          1300:        *len = content_len;
        !          1301:        *digest = mac;
        !          1302: 
        !          1303:        return 0;
        !          1304: }
        !          1305: 
        !          1306: /**
        !          1307:  * Split block-ciphered record into data and MAC portions
        !          1308:  *
        !          1309:  * @v tls              TLS session
        !          1310:  * @v plaintext                Plaintext record
        !          1311:  * @v plaintext_len    Length of record
        !          1312:  * @ret data           Data
        !          1313:  * @ret len            Length of data
        !          1314:  * @ret digest         MAC digest
        !          1315:  * @ret rc             Return status code
        !          1316:  */
        !          1317: static int tls_split_block ( struct tls_session *tls,
        !          1318:                             void *plaintext, size_t plaintext_len,
        !          1319:                             void **data, size_t *len,
        !          1320:                             void **digest ) {
        !          1321:        void *iv;
        !          1322:        size_t iv_len;
        !          1323:        void *content;
        !          1324:        size_t content_len;
        !          1325:        void *mac;
        !          1326:        size_t mac_len;
        !          1327:        void *padding;
        !          1328:        size_t padding_len;
        !          1329:        unsigned int i;
        !          1330: 
        !          1331:        /* Decompose block-ciphered data */
        !          1332:        if ( plaintext_len < 1 ) {
        !          1333:                DBGC ( tls, "TLS %p received underlength record\n", tls );
        !          1334:                DBGC_HD ( tls, plaintext, plaintext_len );
        !          1335:                return -EINVAL;
        !          1336:        }
        !          1337:        iv_len = tls->rx_cipherspec.cipher->blocksize;
        !          1338: 
        !          1339:        /* FIXME: TLSv1.1 uses an explicit IV */
        !          1340:        iv_len = 0;
        !          1341: 
        !          1342:        mac_len = tls->rx_cipherspec.digest->digestsize;
        !          1343:        padding_len = *( ( uint8_t * ) ( plaintext + plaintext_len - 1 ) );
        !          1344:        if ( plaintext_len < ( iv_len + mac_len + padding_len + 1 ) ) {
        !          1345:                DBGC ( tls, "TLS %p received underlength record\n", tls );
        !          1346:                DBGC_HD ( tls, plaintext, plaintext_len );
        !          1347:                return -EINVAL;
        !          1348:        }
        !          1349:        content_len = ( plaintext_len - iv_len - mac_len - padding_len - 1 );
        !          1350:        iv = plaintext;
        !          1351:        content = ( iv + iv_len );
        !          1352:        mac = ( content + content_len );
        !          1353:        padding = ( mac + mac_len );
        !          1354: 
        !          1355:        /* Verify padding bytes */
        !          1356:        for ( i = 0 ; i < padding_len ; i++ ) {
        !          1357:                if ( *( ( uint8_t * ) ( padding + i ) ) != padding_len ) {
        !          1358:                        DBGC ( tls, "TLS %p received bad padding\n", tls );
        !          1359:                        DBGC_HD ( tls, plaintext, plaintext_len );
        !          1360:                        return -EINVAL;
        !          1361:                }
        !          1362:        }
        !          1363: 
        !          1364:        /* Fill in return values */
        !          1365:        *data = content;
        !          1366:        *len = content_len;
        !          1367:        *digest = mac;
        !          1368: 
        !          1369:        return 0;
        !          1370: }
        !          1371: 
        !          1372: /**
        !          1373:  * Receive new ciphertext record
        !          1374:  *
        !          1375:  * @v tls              TLS session
        !          1376:  * @v tlshdr           Record header
        !          1377:  * @v ciphertext       Ciphertext record
        !          1378:  * @ret rc             Return status code
        !          1379:  */
        !          1380: static int tls_new_ciphertext ( struct tls_session *tls,
        !          1381:                                struct tls_header *tlshdr, void *ciphertext ) {
        !          1382:        struct tls_header plaintext_tlshdr;
        !          1383:        struct tls_cipherspec *cipherspec = &tls->rx_cipherspec;
        !          1384:        size_t record_len = ntohs ( tlshdr->length );
        !          1385:        void *plaintext = NULL;
        !          1386:        void *data;
        !          1387:        size_t len;
        !          1388:        void *mac;
        !          1389:        size_t mac_len = cipherspec->digest->digestsize;
        !          1390:        uint8_t verify_mac[mac_len];
        !          1391:        int rc;
        !          1392: 
        !          1393:        /* Allocate buffer for plaintext */
        !          1394:        plaintext = malloc ( record_len );
        !          1395:        if ( ! plaintext ) {
        !          1396:                DBGC ( tls, "TLS %p could not allocate %zd bytes for "
        !          1397:                       "decryption buffer\n", tls, record_len );
        !          1398:                rc = -ENOMEM;
        !          1399:                goto done;
        !          1400:        }
        !          1401: 
        !          1402:        /* Decrypt the record */
        !          1403:        cipher_decrypt ( cipherspec->cipher, cipherspec->cipher_ctx,
        !          1404:                         ciphertext, plaintext, record_len );
        !          1405: 
        !          1406:        /* Split record into content and MAC */
        !          1407:        if ( is_stream_cipher ( cipherspec->cipher ) ) {
        !          1408:                if ( ( rc = tls_split_stream ( tls, plaintext, record_len,
        !          1409:                                               &data, &len, &mac ) ) != 0 )
        !          1410:                        goto done;
        !          1411:        } else {
        !          1412:                if ( ( rc = tls_split_block ( tls, plaintext, record_len,
        !          1413:                                              &data, &len, &mac ) ) != 0 )
        !          1414:                        goto done;
        !          1415:        }
        !          1416: 
        !          1417:        /* Verify MAC */
        !          1418:        plaintext_tlshdr.type = tlshdr->type;
        !          1419:        plaintext_tlshdr.version = tlshdr->version;
        !          1420:        plaintext_tlshdr.length = htons ( len );
        !          1421:        tls_hmac ( tls, cipherspec, tls->rx_seq, &plaintext_tlshdr,
        !          1422:                   data, len, verify_mac);
        !          1423:        if ( memcmp ( mac, verify_mac, mac_len ) != 0 ) {
        !          1424:                DBGC ( tls, "TLS %p failed MAC verification\n", tls );
        !          1425:                DBGC_HD ( tls, plaintext, record_len );
        !          1426:                goto done;
        !          1427:        }
        !          1428: 
        !          1429:        DBGC2 ( tls, "Received plaintext data:\n" );
        !          1430:        DBGC2_HD ( tls, data, len );
        !          1431: 
        !          1432:        /* Process plaintext record */
        !          1433:        if ( ( rc = tls_new_record ( tls, tlshdr->type, data, len ) ) != 0 )
        !          1434:                goto done;
        !          1435: 
        !          1436:        rc = 0;
        !          1437:  done:
        !          1438:        free ( plaintext );
        !          1439:        return rc;
        !          1440: }
        !          1441: 
        !          1442: /******************************************************************************
        !          1443:  *
        !          1444:  * Plaintext stream operations
        !          1445:  *
        !          1446:  ******************************************************************************
        !          1447:  */
        !          1448: 
        !          1449: /**
        !          1450:  * Check flow control window
        !          1451:  *
        !          1452:  * @v tls              TLS session
        !          1453:  * @ret len            Length of window
        !          1454:  */
        !          1455: static size_t tls_plainstream_window ( struct tls_session *tls ) {
        !          1456: 
        !          1457:        /* Block window unless we are ready to accept data */
        !          1458:        if ( tls->tx_state != TLS_TX_DATA )
        !          1459:                return 0;
        !          1460: 
        !          1461:        return xfer_window ( &tls->cipherstream );
        !          1462: }
        !          1463: 
        !          1464: /**
        !          1465:  * Deliver datagram as raw data
        !          1466:  *
        !          1467:  * @v tls              TLS session
        !          1468:  * @v iobuf            I/O buffer
        !          1469:  * @v meta             Data transfer metadata
        !          1470:  * @ret rc             Return status code
        !          1471:  */
        !          1472: static int tls_plainstream_deliver ( struct tls_session *tls,
        !          1473:                                     struct io_buffer *iobuf,
        !          1474:                                     struct xfer_metadata *meta __unused ) {
        !          1475:        int rc;
        !          1476:        
        !          1477:        /* Refuse unless we are ready to accept data */
        !          1478:        if ( tls->tx_state != TLS_TX_DATA ) {
        !          1479:                rc = -ENOTCONN;
        !          1480:                goto done;
        !          1481:        }
        !          1482: 
        !          1483:        if ( ( rc = tls_send_plaintext ( tls, TLS_TYPE_DATA, iobuf->data,
        !          1484:                                         iob_len ( iobuf ) ) ) != 0 )
        !          1485:                goto done;
        !          1486: 
        !          1487:  done:
        !          1488:        free_iob ( iobuf );
        !          1489:        return rc;
        !          1490: }
        !          1491: 
        !          1492: /** TLS plaintext stream interface operations */
        !          1493: static struct interface_operation tls_plainstream_ops[] = {
        !          1494:        INTF_OP ( xfer_deliver, struct tls_session *, tls_plainstream_deliver ),
        !          1495:        INTF_OP ( xfer_window, struct tls_session *, tls_plainstream_window ),
        !          1496:        INTF_OP ( intf_close, struct tls_session *, tls_close ),
        !          1497: };
        !          1498: 
        !          1499: /** TLS plaintext stream interface descriptor */
        !          1500: static struct interface_descriptor tls_plainstream_desc =
        !          1501:        INTF_DESC_PASSTHRU ( struct tls_session, plainstream,
        !          1502:                             tls_plainstream_ops, cipherstream );
        !          1503: 
        !          1504: /******************************************************************************
        !          1505:  *
        !          1506:  * Ciphertext stream operations
        !          1507:  *
        !          1508:  ******************************************************************************
        !          1509:  */
        !          1510: 
        !          1511: /**
        !          1512:  * Handle received TLS header
        !          1513:  *
        !          1514:  * @v tls              TLS session
        !          1515:  * @ret rc             Returned status code
        !          1516:  */
        !          1517: static int tls_newdata_process_header ( struct tls_session *tls ) {
        !          1518:        size_t data_len = ntohs ( tls->rx_header.length );
        !          1519: 
        !          1520:        /* Allocate data buffer now that we know the length */
        !          1521:        assert ( tls->rx_data == NULL );
        !          1522:        tls->rx_data = malloc ( data_len );
        !          1523:        if ( ! tls->rx_data ) {
        !          1524:                DBGC ( tls, "TLS %p could not allocate %zd bytes "
        !          1525:                       "for receive buffer\n", tls, data_len );
        !          1526:                return -ENOMEM;
        !          1527:        }
        !          1528: 
        !          1529:        /* Move to data state */
        !          1530:        tls->rx_state = TLS_RX_DATA;
        !          1531: 
        !          1532:        return 0;
        !          1533: }
        !          1534: 
        !          1535: /**
        !          1536:  * Handle received TLS data payload
        !          1537:  *
        !          1538:  * @v tls              TLS session
        !          1539:  * @ret rc             Returned status code
        !          1540:  */
        !          1541: static int tls_newdata_process_data ( struct tls_session *tls ) {
        !          1542:        int rc;
        !          1543: 
        !          1544:        /* Process record */
        !          1545:        if ( ( rc = tls_new_ciphertext ( tls, &tls->rx_header,
        !          1546:                                         tls->rx_data ) ) != 0 )
        !          1547:                return rc;
        !          1548: 
        !          1549:        /* Increment RX sequence number */
        !          1550:        tls->rx_seq += 1;
        !          1551: 
        !          1552:        /* Free data buffer */
        !          1553:        free ( tls->rx_data );
        !          1554:        tls->rx_data = NULL;
        !          1555: 
        !          1556:        /* Return to header state */
        !          1557:        tls->rx_state = TLS_RX_HEADER;
        !          1558: 
        !          1559:        return 0;
        !          1560: }
        !          1561: 
        !          1562: /**
        !          1563:  * Receive new ciphertext
        !          1564:  *
        !          1565:  * @v tls              TLS session
        !          1566:  * @v iobuf            I/O buffer
        !          1567:  * @v meta             Data transfer metadat
        !          1568:  * @ret rc             Return status code
        !          1569:  */
        !          1570: static int tls_cipherstream_deliver ( struct tls_session *tls,
        !          1571:                                      struct io_buffer *iobuf,
        !          1572:                                      struct xfer_metadata *xfer __unused ) {
        !          1573:        size_t frag_len;
        !          1574:        void *buf;
        !          1575:        size_t buf_len;
        !          1576:        int ( * process ) ( struct tls_session *tls );
        !          1577:        int rc;
        !          1578: 
        !          1579:        while ( iob_len ( iobuf ) ) {
        !          1580:                /* Select buffer according to current state */
        !          1581:                switch ( tls->rx_state ) {
        !          1582:                case TLS_RX_HEADER:
        !          1583:                        buf = &tls->rx_header;
        !          1584:                        buf_len = sizeof ( tls->rx_header );
        !          1585:                        process = tls_newdata_process_header;
        !          1586:                        break;
        !          1587:                case TLS_RX_DATA:
        !          1588:                        buf = tls->rx_data;
        !          1589:                        buf_len = ntohs ( tls->rx_header.length );
        !          1590:                        process = tls_newdata_process_data;
        !          1591:                        break;
        !          1592:                default:
        !          1593:                        assert ( 0 );
        !          1594:                        rc = -EINVAL;
        !          1595:                        goto done;
        !          1596:                }
        !          1597: 
        !          1598:                /* Copy data portion to buffer */
        !          1599:                frag_len = ( buf_len - tls->rx_rcvd );
        !          1600:                if ( frag_len > iob_len  ( iobuf ) )
        !          1601:                        frag_len = iob_len ( iobuf );
        !          1602:                memcpy ( ( buf + tls->rx_rcvd ), iobuf->data, frag_len );
        !          1603:                tls->rx_rcvd += frag_len;
        !          1604:                iob_pull ( iobuf, frag_len );
        !          1605: 
        !          1606:                /* Process data if buffer is now full */
        !          1607:                if ( tls->rx_rcvd == buf_len ) {
        !          1608:                        if ( ( rc = process ( tls ) ) != 0 ) {
        !          1609:                                tls_close ( tls, rc );
        !          1610:                                goto done;
        !          1611:                        }
        !          1612:                        tls->rx_rcvd = 0;
        !          1613:                }
        !          1614:        }
        !          1615:        rc = 0;
        !          1616: 
        !          1617:  done:
        !          1618:        free_iob ( iobuf );
        !          1619:        return rc;
        !          1620: }
        !          1621: 
        !          1622: /** TLS ciphertext stream interface operations */
        !          1623: static struct interface_operation tls_cipherstream_ops[] = {
        !          1624:        INTF_OP ( xfer_deliver, struct tls_session *,
        !          1625:                  tls_cipherstream_deliver ),
        !          1626:        INTF_OP ( intf_close, struct tls_session *, tls_close ),
        !          1627: };
        !          1628: 
        !          1629: /** TLS ciphertext stream interface descriptor */
        !          1630: static struct interface_descriptor tls_cipherstream_desc =
        !          1631:        INTF_DESC_PASSTHRU ( struct tls_session, cipherstream,
        !          1632:                             tls_cipherstream_ops, plainstream );
        !          1633: 
        !          1634: /******************************************************************************
        !          1635:  *
        !          1636:  * Controlling process
        !          1637:  *
        !          1638:  ******************************************************************************
        !          1639:  */
        !          1640: 
        !          1641: /**
        !          1642:  * TLS TX state machine
        !          1643:  *
        !          1644:  * @v process          TLS process
        !          1645:  */
        !          1646: static void tls_step ( struct process *process ) {
        !          1647:        struct tls_session *tls =
        !          1648:                container_of ( process, struct tls_session, process );
        !          1649:        int rc;
        !          1650: 
        !          1651:        /* Wait for cipherstream to become ready */
        !          1652:        if ( ! xfer_window ( &tls->cipherstream ) )
        !          1653:                return;
        !          1654: 
        !          1655:        switch ( tls->tx_state ) {
        !          1656:        case TLS_TX_NONE:
        !          1657:                /* Nothing to do */
        !          1658:                break;
        !          1659:        case TLS_TX_CLIENT_HELLO:
        !          1660:                /* Send Client Hello */
        !          1661:                if ( ( rc = tls_send_client_hello ( tls ) ) != 0 ) {
        !          1662:                        DBGC ( tls, "TLS %p could not send Client Hello: %s\n",
        !          1663:                               tls, strerror ( rc ) );
        !          1664:                        goto err;
        !          1665:                }
        !          1666:                tls->tx_state = TLS_TX_NONE;
        !          1667:                break;
        !          1668:        case TLS_TX_CLIENT_KEY_EXCHANGE:
        !          1669:                /* Send Client Key Exchange */
        !          1670:                if ( ( rc = tls_send_client_key_exchange ( tls ) ) != 0 ) {
        !          1671:                        DBGC ( tls, "TLS %p could send Client Key Exchange: "
        !          1672:                               "%s\n", tls, strerror ( rc ) );
        !          1673:                        goto err;
        !          1674:                }
        !          1675:                tls->tx_state = TLS_TX_CHANGE_CIPHER;
        !          1676:                break;
        !          1677:        case TLS_TX_CHANGE_CIPHER:
        !          1678:                /* Send Change Cipher, and then change the cipher in use */
        !          1679:                if ( ( rc = tls_send_change_cipher ( tls ) ) != 0 ) {
        !          1680:                        DBGC ( tls, "TLS %p could not send Change Cipher: "
        !          1681:                               "%s\n", tls, strerror ( rc ) );
        !          1682:                        goto err;
        !          1683:                }
        !          1684:                if ( ( rc = tls_change_cipher ( tls,
        !          1685:                                                &tls->tx_cipherspec_pending,
        !          1686:                                                &tls->tx_cipherspec )) != 0 ){
        !          1687:                        DBGC ( tls, "TLS %p could not activate TX cipher: "
        !          1688:                               "%s\n", tls, strerror ( rc ) );
        !          1689:                        goto err;
        !          1690:                }
        !          1691:                tls->tx_seq = 0;
        !          1692:                tls->tx_state = TLS_TX_FINISHED;
        !          1693:                break;
        !          1694:        case TLS_TX_FINISHED:
        !          1695:                /* Send Finished */
        !          1696:                if ( ( rc = tls_send_finished ( tls ) ) != 0 ) {
        !          1697:                        DBGC ( tls, "TLS %p could not send Finished: %s\n",
        !          1698:                               tls, strerror ( rc ) );
        !          1699:                        goto err;
        !          1700:                }
        !          1701:                tls->tx_state = TLS_TX_NONE;
        !          1702:                break;
        !          1703:        case TLS_TX_DATA:
        !          1704:                /* Nothing to do */
        !          1705:                break;
        !          1706:        default:
        !          1707:                assert ( 0 );
        !          1708:        }
        !          1709: 
        !          1710:        return;
        !          1711: 
        !          1712:  err:
        !          1713:        tls_close ( tls, rc );
        !          1714: }
        !          1715: 
        !          1716: /******************************************************************************
        !          1717:  *
        !          1718:  * Instantiator
        !          1719:  *
        !          1720:  ******************************************************************************
        !          1721:  */
        !          1722: 
        !          1723: int add_tls ( struct interface *xfer, struct interface **next ) {
        !          1724:        struct tls_session *tls;
        !          1725: 
        !          1726:        /* Allocate and initialise TLS structure */
        !          1727:        tls = malloc ( sizeof ( *tls ) );
        !          1728:        if ( ! tls )
        !          1729:                return -ENOMEM;
        !          1730:        memset ( tls, 0, sizeof ( *tls ) );
        !          1731:        ref_init ( &tls->refcnt, free_tls );
        !          1732:        intf_init ( &tls->plainstream, &tls_plainstream_desc, &tls->refcnt );
        !          1733:        intf_init ( &tls->cipherstream, &tls_cipherstream_desc, &tls->refcnt );
        !          1734:        tls_clear_cipher ( tls, &tls->tx_cipherspec );
        !          1735:        tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
        !          1736:        tls_clear_cipher ( tls, &tls->rx_cipherspec );
        !          1737:        tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
        !          1738:        tls->client_random.gmt_unix_time = 0;
        !          1739:        tls_generate_random ( &tls->client_random.random,
        !          1740:                              ( sizeof ( tls->client_random.random ) ) );
        !          1741:        tls->pre_master_secret.version = htons ( TLS_VERSION_TLS_1_0 );
        !          1742:        tls_generate_random ( &tls->pre_master_secret.random,
        !          1743:                              ( sizeof ( tls->pre_master_secret.random ) ) );
        !          1744:        digest_init ( &md5_algorithm, tls->handshake_md5_ctx );
        !          1745:        digest_init ( &sha1_algorithm, tls->handshake_sha1_ctx );
        !          1746:        tls->tx_state = TLS_TX_CLIENT_HELLO;
        !          1747:        process_init ( &tls->process, tls_step, &tls->refcnt );
        !          1748: 
        !          1749:        /* Attach to parent interface, mortalise self, and return */
        !          1750:        intf_plug_plug ( &tls->plainstream, xfer );
        !          1751:        *next = &tls->cipherstream;
        !          1752:        ref_put ( &tls->refcnt );
        !          1753:        return 0;
        !          1754: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.