david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[tls] Allow transmitted records to be scheduled independently

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown 2012-03-03 22:15:25 +00:00
parent b7f8d1bbfd
commit 56a7981d58
2 changed files with 39 additions and 93 deletions

View File

@ -84,14 +84,12 @@ enum tls_rx_state {
TLS_RX_DATA, TLS_RX_DATA,
}; };
/** TLS TX state machine state */ /** TLS TX pending flags */
enum tls_tx_state { enum tls_tx_pending {
TLS_TX_NONE = 0, TLS_TX_CLIENT_HELLO = 0x0001,
TLS_TX_CLIENT_HELLO, TLS_TX_CLIENT_KEY_EXCHANGE = 0x0002,
TLS_TX_CLIENT_KEY_EXCHANGE, TLS_TX_CHANGE_CIPHER = 0x0004,
TLS_TX_CHANGE_CIPHER, TLS_TX_FINISHED = 0x0008,
TLS_TX_FINISHED,
TLS_TX_DATA
}; };
/** A TLS cipher specification */ /** A TLS cipher specification */
@ -172,10 +170,12 @@ struct tls_session {
/** TX sequence number */ /** TX sequence number */
uint64_t tx_seq; uint64_t tx_seq;
/** TX state */ /** TX pending transmissions */
enum tls_tx_state tx_state; unsigned int tx_pending;
/** TX process */ /** TX process */
struct process process; struct process process;
/** TX ready for plaintext data */
int tx_ready;
/** RX sequence number */ /** RX sequence number */
uint64_t rx_seq; uint64_t rx_seq;

View File

@ -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 ); 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 * Transmit Handshake record
* *
@ -1025,15 +978,11 @@ static int tls_new_server_hello_done ( struct tls_session *tls,
return -EINVAL; return -EINVAL;
} }
/* Check that we are ready to send the Client Key Exchange */ /* Schedule Client Key Exchange, Change Cipher, and Finished */
if ( tls->tx_state != TLS_TX_NONE ) { tls->tx_pending |= ( TLS_TX_CLIENT_KEY_EXCHANGE |
DBGC ( tls, "TLS %p received Server Hello Done while in " TLS_TX_CHANGE_CIPHER |
"TX state %d\n", tls, tls->tx_state ); TLS_TX_FINISHED );
return -EIO; tls_tx_resume ( tls );
}
/* Start sending the Client Key Exchange */
tls_tx_start ( tls, TLS_TX_CLIENT_KEY_EXCHANGE );
return 0; return 0;
} }
@ -1050,10 +999,15 @@ static int tls_new_finished ( struct tls_session *tls,
void *data, size_t len ) { void *data, size_t len ) {
/* FIXME: Handle this properly */ /* FIXME: Handle this properly */
tls_tx_data ( tls );
( void ) data; ( void ) data;
( void ) len; ( 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; 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 ) { static size_t tls_plainstream_window ( struct tls_session *tls ) {
/* Block window unless we are ready to accept data */ /* Block window unless we are ready to accept data */
if ( tls->tx_state != TLS_TX_DATA ) if ( ! tls->tx_ready )
return 0; return 0;
return xfer_window ( &tls->cipherstream ); return xfer_window ( &tls->cipherstream );
@ -1581,7 +1535,7 @@ static int tls_plainstream_deliver ( struct tls_session *tls,
int rc; int rc;
/* Refuse unless we are ready to accept data */ /* Refuse unless we are ready to accept data */
if ( tls->tx_state != TLS_TX_DATA ) { if ( ! tls->tx_ready ) {
rc = -ENOTCONN; rc = -ENOTCONN;
goto done; goto done;
} }
@ -1757,29 +1711,24 @@ static void tls_tx_step ( struct tls_session *tls ) {
if ( ! xfer_window ( &tls->cipherstream ) ) if ( ! xfer_window ( &tls->cipherstream ) )
return; return;
switch ( tls->tx_state ) { /* Send first pending transmission */
case TLS_TX_NONE: if ( tls->tx_pending & TLS_TX_CLIENT_HELLO ) {
/* Nothing to do */
break;
case TLS_TX_CLIENT_HELLO:
/* Send Client Hello */ /* Send Client Hello */
if ( ( rc = tls_send_client_hello ( tls ) ) != 0 ) { if ( ( rc = tls_send_client_hello ( tls ) ) != 0 ) {
DBGC ( tls, "TLS %p could not send Client Hello: %s\n", DBGC ( tls, "TLS %p could not send Client Hello: %s\n",
tls, strerror ( rc ) ); tls, strerror ( rc ) );
goto err; goto err;
} }
tls_tx_none ( tls ); tls->tx_pending &= ~TLS_TX_CLIENT_HELLO;
break; } else if ( tls->tx_pending & TLS_TX_CLIENT_KEY_EXCHANGE ) {
case TLS_TX_CLIENT_KEY_EXCHANGE:
/* Send Client Key Exchange */ /* Send Client Key Exchange */
if ( ( rc = tls_send_client_key_exchange ( tls ) ) != 0 ) { if ( ( rc = tls_send_client_key_exchange ( tls ) ) != 0 ) {
DBGC ( tls, "TLS %p could send Client Key Exchange: " DBGC ( tls, "TLS %p could send Client Key Exchange: "
"%s\n", tls, strerror ( rc ) ); "%s\n", tls, strerror ( rc ) );
goto err; goto err;
} }
tls_tx_start ( tls, TLS_TX_CHANGE_CIPHER ); tls->tx_pending &= ~TLS_TX_CLIENT_KEY_EXCHANGE;
break; } else if ( tls->tx_pending & TLS_TX_CHANGE_CIPHER ) {
case TLS_TX_CHANGE_CIPHER:
/* Send Change Cipher, and then change the cipher in use */ /* Send Change Cipher, and then change the cipher in use */
if ( ( rc = tls_send_change_cipher ( tls ) ) != 0 ) { if ( ( rc = tls_send_change_cipher ( tls ) ) != 0 ) {
DBGC ( tls, "TLS %p could not send Change Cipher: " DBGC ( tls, "TLS %p could not send Change Cipher: "
@ -1794,24 +1743,21 @@ static void tls_tx_step ( struct tls_session *tls ) {
goto err; goto err;
} }
tls->tx_seq = 0; tls->tx_seq = 0;
tls_tx_start ( tls, TLS_TX_FINISHED ); tls->tx_pending &= ~TLS_TX_CHANGE_CIPHER;
break; } else if ( tls->tx_pending & TLS_TX_FINISHED ) {
case TLS_TX_FINISHED:
/* Send Finished */ /* Send Finished */
if ( ( rc = tls_send_finished ( tls ) ) != 0 ) { if ( ( rc = tls_send_finished ( tls ) ) != 0 ) {
DBGC ( tls, "TLS %p could not send Finished: %s\n", DBGC ( tls, "TLS %p could not send Finished: %s\n",
tls, strerror ( rc ) ); tls, strerror ( rc ) );
goto err; goto err;
} }
tls_tx_none ( tls ); tls->tx_pending &= ~TLS_TX_FINISHED;
break;
case TLS_TX_DATA:
/* Nothing to do */
break;
default:
assert ( 0 );
} }
/* Reschedule process if pending transmissions remain */
if ( tls->tx_pending )
tls_tx_resume ( tls );
return; return;
err: err:
@ -1862,8 +1808,8 @@ int add_tls ( struct interface *xfer, const char *name,
} }
digest_init ( &md5_algorithm, tls->handshake_md5_ctx ); digest_init ( &md5_algorithm, tls->handshake_md5_ctx );
digest_init ( &sha1_algorithm, tls->handshake_sha1_ctx ); digest_init ( &sha1_algorithm, tls->handshake_sha1_ctx );
process_init_stopped ( &tls->process, &tls_process_desc, &tls->refcnt ); tls->tx_pending = TLS_TX_CLIENT_HELLO;
tls_tx_start ( tls, TLS_TX_CLIENT_HELLO ); process_init ( &tls->process, &tls_process_desc, &tls->refcnt );
/* Attach to parent interface, mortalise self, and return */ /* Attach to parent interface, mortalise self, and return */
intf_plug_plug ( &tls->plainstream, xfer ); intf_plug_plug ( &tls->plainstream, xfer );