mirror of https://github.com/ipxe/ipxe.git
[tls] Handle fragmented handshake records
Originally-implemented-by: Christopher Schenk <christopher@cschenk.net> Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/930/head
parent
aa368ba529
commit
1d1cf74a5e
|
@ -398,6 +398,8 @@ struct tls_connection {
|
||||||
struct io_buffer rx_header_iobuf;
|
struct io_buffer rx_header_iobuf;
|
||||||
/** List of received data buffers */
|
/** List of received data buffers */
|
||||||
struct list_head rx_data;
|
struct list_head rx_data;
|
||||||
|
/** Received handshake fragment */
|
||||||
|
struct io_buffer *rx_handshake;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** RX I/O buffer size
|
/** RX I/O buffer size
|
||||||
|
|
|
@ -388,6 +388,7 @@ static void free_tls ( struct refcnt *refcnt ) {
|
||||||
list_del ( &iobuf->list );
|
list_del ( &iobuf->list );
|
||||||
free_iob ( iobuf );
|
free_iob ( iobuf );
|
||||||
}
|
}
|
||||||
|
free_iob ( tls->rx_handshake );
|
||||||
x509_chain_put ( tls->certs );
|
x509_chain_put ( tls->certs );
|
||||||
x509_chain_put ( tls->chain );
|
x509_chain_put ( tls->chain );
|
||||||
x509_root_put ( tls->root );
|
x509_root_put ( tls->root );
|
||||||
|
@ -2426,17 +2427,13 @@ static int tls_new_handshake ( struct tls_connection *tls,
|
||||||
|
|
||||||
/* Parse header */
|
/* Parse header */
|
||||||
if ( sizeof ( *handshake ) > remaining ) {
|
if ( sizeof ( *handshake ) > remaining ) {
|
||||||
DBGC ( tls, "TLS %p received underlength Handshake\n",
|
/* Leave remaining fragment unconsumed */
|
||||||
tls );
|
break;
|
||||||
DBGC_HD ( tls, handshake, remaining );
|
|
||||||
return -EINVAL_HANDSHAKE;
|
|
||||||
}
|
}
|
||||||
payload_len = tls_uint24 ( &handshake->length );
|
payload_len = tls_uint24 ( &handshake->length );
|
||||||
if ( payload_len > ( remaining - sizeof ( *handshake ) ) ) {
|
if ( payload_len > ( remaining - sizeof ( *handshake ) ) ) {
|
||||||
DBGC ( tls, "TLS %p received overlength Handshake\n",
|
/* Leave remaining fragment unconsumed */
|
||||||
tls );
|
break;
|
||||||
DBGC_HD ( tls, handshake, remaining );
|
|
||||||
return -EINVAL_HANDSHAKE;
|
|
||||||
}
|
}
|
||||||
payload = &handshake->payload;
|
payload = &handshake->payload;
|
||||||
record_len = ( sizeof ( *handshake ) + payload_len );
|
record_len = ( sizeof ( *handshake ) + payload_len );
|
||||||
|
@ -2554,14 +2551,16 @@ static int tls_new_record ( struct tls_connection *tls, unsigned int type,
|
||||||
struct list_head *rx_data ) {
|
struct list_head *rx_data ) {
|
||||||
int ( * handler ) ( struct tls_connection *tls,
|
int ( * handler ) ( struct tls_connection *tls,
|
||||||
struct io_buffer *iobuf );
|
struct io_buffer *iobuf );
|
||||||
struct io_buffer *iobuf;
|
struct io_buffer *tmp = NULL;
|
||||||
|
struct io_buffer **iobuf;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Deliver data records as-is to the plainstream interface */
|
/* Deliver data records as-is to the plainstream interface */
|
||||||
if ( type == TLS_TYPE_DATA )
|
if ( type == TLS_TYPE_DATA )
|
||||||
return tls_new_data ( tls, rx_data );
|
return tls_new_data ( tls, rx_data );
|
||||||
|
|
||||||
/* Determine handler */
|
/* Determine handler and fragment buffer */
|
||||||
|
iobuf = &tmp;
|
||||||
switch ( type ) {
|
switch ( type ) {
|
||||||
case TLS_TYPE_CHANGE_CIPHER:
|
case TLS_TYPE_CHANGE_CIPHER:
|
||||||
handler = tls_new_change_cipher;
|
handler = tls_new_change_cipher;
|
||||||
|
@ -2571,6 +2570,7 @@ static int tls_new_record ( struct tls_connection *tls, unsigned int type,
|
||||||
break;
|
break;
|
||||||
case TLS_TYPE_HANDSHAKE:
|
case TLS_TYPE_HANDSHAKE:
|
||||||
handler = tls_new_handshake;
|
handler = tls_new_handshake;
|
||||||
|
iobuf = &tls->rx_handshake;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DBGC ( tls, "TLS %p unknown record type %d\n", tls, type );
|
DBGC ( tls, "TLS %p unknown record type %d\n", tls, type );
|
||||||
|
@ -2579,8 +2579,10 @@ static int tls_new_record ( struct tls_connection *tls, unsigned int type,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Merge into a single I/O buffer */
|
/* Merge into a single I/O buffer */
|
||||||
iobuf = iob_concatenate ( rx_data );
|
if ( *iobuf )
|
||||||
if ( ! iobuf ) {
|
list_add ( &(*iobuf)->list, rx_data );
|
||||||
|
*iobuf = iob_concatenate ( rx_data );
|
||||||
|
if ( ! *iobuf ) {
|
||||||
DBGC ( tls, "TLS %p could not concatenate non-data record "
|
DBGC ( tls, "TLS %p could not concatenate non-data record "
|
||||||
"type %d\n", tls, type );
|
"type %d\n", tls, type );
|
||||||
rc = -ENOMEM_RX_CONCAT;
|
rc = -ENOMEM_RX_CONCAT;
|
||||||
|
@ -2588,19 +2590,23 @@ static int tls_new_record ( struct tls_connection *tls, unsigned int type,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle record */
|
/* Handle record */
|
||||||
if ( ( rc = handler ( tls, iobuf ) ) != 0 )
|
if ( ( rc = handler ( tls, *iobuf ) ) != 0 )
|
||||||
goto err_handle;
|
goto err_handle;
|
||||||
|
|
||||||
/* Sanity check */
|
/* Discard I/O buffer if empty */
|
||||||
assert ( iob_len ( iobuf ) == 0 );
|
if ( ! iob_len ( *iobuf ) ) {
|
||||||
|
free_iob ( *iobuf );
|
||||||
|
*iobuf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Free I/O buffer */
|
/* Sanity check */
|
||||||
free_iob ( iobuf );
|
assert ( tmp == NULL );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_handle:
|
err_handle:
|
||||||
free_iob ( iobuf );
|
free_iob ( *iobuf );
|
||||||
|
*iobuf = NULL;
|
||||||
err_concatenate:
|
err_concatenate:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue