mirror of https://github.com/ipxe/ipxe.git
[tls] Allow transmitted records to be scheduled independently
Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/6/head
parent
b7f8d1bbfd
commit
56a7981d58
|
@ -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;
|
||||||
|
|
112
src/net/tls.c
112
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 );
|
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 );
|
||||||
|
|
Loading…
Reference in New Issue