From 56a7981d5889c91fb333c6b98daf7b9a9d1ec0ee Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 3 Mar 2012 22:15:25 +0000 Subject: [PATCH] [tls] Allow transmitted records to be scheduled independently Signed-off-by: Michael Brown --- src/include/ipxe/tls.h | 20 ++++---- src/net/tls.c | 112 +++++++++++------------------------------ 2 files changed, 39 insertions(+), 93 deletions(-) diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index 90833781..2aa2b06d 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -84,14 +84,12 @@ enum tls_rx_state { TLS_RX_DATA, }; -/** TLS TX state machine state */ -enum tls_tx_state { - TLS_TX_NONE = 0, - TLS_TX_CLIENT_HELLO, - TLS_TX_CLIENT_KEY_EXCHANGE, - TLS_TX_CHANGE_CIPHER, - TLS_TX_FINISHED, - TLS_TX_DATA +/** TLS TX pending flags */ +enum tls_tx_pending { + TLS_TX_CLIENT_HELLO = 0x0001, + TLS_TX_CLIENT_KEY_EXCHANGE = 0x0002, + TLS_TX_CHANGE_CIPHER = 0x0004, + TLS_TX_FINISHED = 0x0008, }; /** A TLS cipher specification */ @@ -172,10 +170,12 @@ struct tls_session { /** TX sequence number */ uint64_t tx_seq; - /** TX state */ - enum tls_tx_state tx_state; + /** TX pending transmissions */ + unsigned int tx_pending; /** TX process */ struct process process; + /** TX ready for plaintext data */ + int tx_ready; /** RX sequence number */ uint64_t rx_seq; diff --git a/src/net/tls.c b/src/net/tls.c index 919025e7..edf8d9fb 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -596,7 +596,7 @@ static void tls_verify_handshake ( struct tls_session *tls, void *out ) { /****************************************************************************** * - * TX state machine transitions + * Record handling * ****************************************************************************** */ @@ -610,53 +610,6 @@ static void tls_tx_resume ( struct tls_session *tls ) { process_add ( &tls->process ); } -/** - * Enter TX state machine active state - * - * @v tls TLS session - * @v state TX state - */ -static void tls_tx_start ( struct tls_session *tls, enum tls_tx_state state ) { - - /* Enter specified state */ - tls->tx_state = state; - - /* Resume state machine */ - tls_tx_resume ( tls ); -} - -/** - * Enter TX state machine idle state - * - * @v tls TLS session - */ -static void tls_tx_none ( struct tls_session *tls ) { - - /* Enter idle state */ - tls->tx_state = TLS_TX_NONE; -} - -/** - * Enter TX state machine data state - * - * @v tls TLS session - */ -static void tls_tx_data ( struct tls_session *tls ) { - - /* Enter data state */ - tls->tx_state = TLS_TX_DATA; - - /* Send notification of a window change */ - xfer_window_changed ( &tls->plainstream ); -} - -/****************************************************************************** - * - * Record handling - * - ****************************************************************************** - */ - /** * Transmit Handshake record * @@ -1025,15 +978,11 @@ static int tls_new_server_hello_done ( struct tls_session *tls, return -EINVAL; } - /* Check that we are ready to send the Client Key Exchange */ - if ( tls->tx_state != TLS_TX_NONE ) { - DBGC ( tls, "TLS %p received Server Hello Done while in " - "TX state %d\n", tls, tls->tx_state ); - return -EIO; - } - - /* Start sending the Client Key Exchange */ - tls_tx_start ( tls, TLS_TX_CLIENT_KEY_EXCHANGE ); + /* Schedule Client Key Exchange, Change Cipher, and Finished */ + tls->tx_pending |= ( TLS_TX_CLIENT_KEY_EXCHANGE | + TLS_TX_CHANGE_CIPHER | + TLS_TX_FINISHED ); + tls_tx_resume ( tls ); return 0; } @@ -1050,10 +999,15 @@ static int tls_new_finished ( struct tls_session *tls, void *data, size_t len ) { /* FIXME: Handle this properly */ - tls_tx_data ( tls ); ( void ) data; ( void ) len; + /* Mark session as ready to transmit plaintext data */ + tls->tx_ready = 1; + + /* Send notification of a window change */ + xfer_window_changed ( &tls->plainstream ); + return 0; } @@ -1561,7 +1515,7 @@ static int tls_new_ciphertext ( struct tls_session *tls, static size_t tls_plainstream_window ( struct tls_session *tls ) { /* Block window unless we are ready to accept data */ - if ( tls->tx_state != TLS_TX_DATA ) + if ( ! tls->tx_ready ) return 0; return xfer_window ( &tls->cipherstream ); @@ -1581,7 +1535,7 @@ static int tls_plainstream_deliver ( struct tls_session *tls, int rc; /* Refuse unless we are ready to accept data */ - if ( tls->tx_state != TLS_TX_DATA ) { + if ( ! tls->tx_ready ) { rc = -ENOTCONN; goto done; } @@ -1757,29 +1711,24 @@ static void tls_tx_step ( struct tls_session *tls ) { if ( ! xfer_window ( &tls->cipherstream ) ) return; - switch ( tls->tx_state ) { - case TLS_TX_NONE: - /* Nothing to do */ - break; - case TLS_TX_CLIENT_HELLO: + /* Send first pending transmission */ + if ( tls->tx_pending & TLS_TX_CLIENT_HELLO ) { /* Send Client Hello */ if ( ( rc = tls_send_client_hello ( tls ) ) != 0 ) { DBGC ( tls, "TLS %p could not send Client Hello: %s\n", tls, strerror ( rc ) ); goto err; } - tls_tx_none ( tls ); - break; - case TLS_TX_CLIENT_KEY_EXCHANGE: + tls->tx_pending &= ~TLS_TX_CLIENT_HELLO; + } else if ( tls->tx_pending & TLS_TX_CLIENT_KEY_EXCHANGE ) { /* Send Client Key Exchange */ if ( ( rc = tls_send_client_key_exchange ( tls ) ) != 0 ) { DBGC ( tls, "TLS %p could send Client Key Exchange: " "%s\n", tls, strerror ( rc ) ); goto err; } - tls_tx_start ( tls, TLS_TX_CHANGE_CIPHER ); - break; - case TLS_TX_CHANGE_CIPHER: + tls->tx_pending &= ~TLS_TX_CLIENT_KEY_EXCHANGE; + } else if ( tls->tx_pending & TLS_TX_CHANGE_CIPHER ) { /* Send Change Cipher, and then change the cipher in use */ if ( ( rc = tls_send_change_cipher ( tls ) ) != 0 ) { DBGC ( tls, "TLS %p could not send Change Cipher: " @@ -1794,24 +1743,21 @@ static void tls_tx_step ( struct tls_session *tls ) { goto err; } tls->tx_seq = 0; - tls_tx_start ( tls, TLS_TX_FINISHED ); - break; - case TLS_TX_FINISHED: + tls->tx_pending &= ~TLS_TX_CHANGE_CIPHER; + } else if ( tls->tx_pending & TLS_TX_FINISHED ) { /* Send Finished */ if ( ( rc = tls_send_finished ( tls ) ) != 0 ) { DBGC ( tls, "TLS %p could not send Finished: %s\n", tls, strerror ( rc ) ); goto err; } - tls_tx_none ( tls ); - break; - case TLS_TX_DATA: - /* Nothing to do */ - break; - default: - assert ( 0 ); + tls->tx_pending &= ~TLS_TX_FINISHED; } + /* Reschedule process if pending transmissions remain */ + if ( tls->tx_pending ) + tls_tx_resume ( tls ); + return; err: @@ -1862,8 +1808,8 @@ int add_tls ( struct interface *xfer, const char *name, } digest_init ( &md5_algorithm, tls->handshake_md5_ctx ); digest_init ( &sha1_algorithm, tls->handshake_sha1_ctx ); - process_init_stopped ( &tls->process, &tls_process_desc, &tls->refcnt ); - tls_tx_start ( tls, TLS_TX_CLIENT_HELLO ); + tls->tx_pending = TLS_TX_CLIENT_HELLO; + process_init ( &tls->process, &tls_process_desc, &tls->refcnt ); /* Attach to parent interface, mortalise self, and return */ intf_plug_plug ( &tls->plainstream, xfer );