aboutsummaryrefslogtreecommitdiffstats
path: root/src/net
diff options
context:
space:
mode:
Diffstat (limited to 'src/net')
-rw-r--r--src/net/tls.c177
1 files changed, 114 insertions, 63 deletions
diff --git a/src/net/tls.c b/src/net/tls.c
index af310a58f..899629626 100644
--- a/src/net/tls.c
+++ b/src/net/tls.c
@@ -383,6 +383,7 @@ static void free_tls ( struct refcnt *refcnt ) {
tls_clear_cipher ( tls, &tls->rx_cipherspec );
tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
free ( tls->server_key );
+ free ( tls->handshake_ctx );
list_for_each_entry_safe ( iobuf, tmp, &tls->rx_data, list ) {
list_del ( &iobuf->list );
free_iob ( iobuf );
@@ -564,8 +565,8 @@ static void tls_prf ( struct tls_connection *tls, const void *secret,
va_start ( seeds, out_len );
if ( tls_version ( tls, TLS_VERSION_TLS_1_2 ) ) {
- /* Use P_SHA256 for TLSv1.2 and later */
- tls_p_hash_va ( tls, &sha256_algorithm, secret, secret_len,
+ /* Use handshake digest PRF for TLSv1.2 and later */
+ tls_p_hash_va ( tls, tls->handshake_digest, secret, secret_len,
out, out_len, seeds );
} else {
/* Use combination of P_MD5 and P_SHA-1 for TLSv1.1
@@ -730,6 +731,83 @@ static int tls_generate_keys ( struct tls_connection *tls ) {
/******************************************************************************
*
+ * Handshake verification
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Clear handshake digest algorithm
+ *
+ * @v tls TLS connection
+ */
+static void tls_clear_handshake ( struct tls_connection *tls ) {
+
+ /* Select null digest algorithm */
+ tls->handshake_digest = &digest_null;
+
+ /* Free any existing context */
+ free ( tls->handshake_ctx );
+ tls->handshake_ctx = NULL;
+}
+
+/**
+ * Select handshake digest algorithm
+ *
+ * @v tls TLS connection
+ * @v digest Handshake digest algorithm
+ * @ret rc Return status code
+ */
+static int tls_select_handshake ( struct tls_connection *tls,
+ struct digest_algorithm *digest ) {
+
+ /* Clear existing handshake digest */
+ tls_clear_handshake ( tls );
+
+ /* Allocate and initialise context */
+ tls->handshake_ctx = malloc ( digest->ctxsize );
+ if ( ! tls->handshake_ctx )
+ return -ENOMEM;
+ tls->handshake_digest = digest;
+ digest_init ( digest, tls->handshake_ctx );
+
+ return 0;
+}
+
+/**
+ * Add handshake record to verification hash
+ *
+ * @v tls TLS connection
+ * @v data Handshake record
+ * @v len Length of handshake record
+ * @ret rc Return status code
+ */
+static int tls_add_handshake ( struct tls_connection *tls,
+ const void *data, size_t len ) {
+ struct digest_algorithm *digest = tls->handshake_digest;
+
+ digest_update ( digest, tls->handshake_ctx, data, len );
+ return 0;
+}
+
+/**
+ * Calculate handshake verification hash
+ *
+ * @v tls TLS connection
+ * @v out Output buffer
+ *
+ * Calculates the digest over all handshake messages seen so far.
+ */
+static void tls_verify_handshake ( struct tls_connection *tls, void *out ) {
+ struct digest_algorithm *digest = tls->handshake_digest;
+ uint8_t ctx[ digest->ctxsize ];
+
+ memcpy ( ctx, tls->handshake_ctx, sizeof ( ctx ) );
+ digest_final ( digest, ctx, out );
+}
+
+/******************************************************************************
+ *
* Cipher suite management
*
******************************************************************************
@@ -835,6 +913,7 @@ static int tls_set_cipher ( struct tls_connection *tls,
static int tls_select_cipher ( struct tls_connection *tls,
unsigned int cipher_suite ) {
struct tls_cipher_suite *suite;
+ struct digest_algorithm *digest;
int rc;
/* Identify cipher suite */
@@ -845,6 +924,12 @@ static int tls_select_cipher ( struct tls_connection *tls,
return -ENOTSUP_CIPHER;
}
+ /* Set handshake digest algorithm */
+ digest = ( tls_version ( tls, TLS_VERSION_TLS_1_2 ) ?
+ suite->handshake : &md5_sha1_algorithm );
+ if ( ( rc = tls_select_handshake ( tls, digest ) ) != 0 )
+ return rc;
+
/* Set ciphers */
if ( ( rc = tls_set_cipher ( tls, &tls->tx_cipherspec_pending,
suite ) ) != 0 )
@@ -958,46 +1043,6 @@ tls_signature_hash_digest ( struct tls_signature_hash_id code ) {
/******************************************************************************
*
- * Handshake verification
- *
- ******************************************************************************
- */
-
-/**
- * Add handshake record to verification hash
- *
- * @v tls TLS connection
- * @v data Handshake record
- * @v len Length of handshake record
- */
-static void tls_add_handshake ( struct tls_connection *tls,
- const void *data, size_t len ) {
-
- digest_update ( &md5_sha1_algorithm, tls->handshake_md5_sha1_ctx,
- data, len );
- digest_update ( &sha256_algorithm, tls->handshake_sha256_ctx,
- data, len );
-}
-
-/**
- * Calculate handshake verification hash
- *
- * @v tls TLS connection
- * @v out Output buffer
- *
- * Calculates the MD5+SHA1 or SHA256 digest over all handshake
- * messages seen so far.
- */
-static void tls_verify_handshake ( struct tls_connection *tls, void *out ) {
- struct digest_algorithm *digest = tls->handshake_digest;
- uint8_t ctx[ digest->ctxsize ];
-
- memcpy ( ctx, tls->handshake_ctx, sizeof ( ctx ) );
- digest_final ( digest, ctx, out );
-}
-
-/******************************************************************************
- *
* Record handling
*
******************************************************************************
@@ -1037,12 +1082,6 @@ static void tls_restart ( struct tls_connection *tls ) {
assert ( ! is_pending ( &tls->server_negotiation ) );
assert ( ! is_pending ( &tls->validation ) );
- /* (Re)initialise handshake context */
- digest_init ( &md5_sha1_algorithm, tls->handshake_md5_sha1_ctx );
- digest_init ( &sha256_algorithm, tls->handshake_sha256_ctx );
- tls->handshake_digest = &sha256_algorithm;
- tls->handshake_ctx = tls->handshake_sha256_ctx;
-
/* (Re)start negotiation */
tls->tx_pending = TLS_TX_CLIENT_HELLO;
tls_tx_resume ( tls );
@@ -1059,7 +1098,7 @@ static void tls_restart ( struct tls_connection *tls ) {
* @ret rc Return status code
*/
static int tls_send_handshake ( struct tls_connection *tls,
- void *data, size_t len ) {
+ const void *data, size_t len ) {
/* Add to handshake digest */
tls_add_handshake ( tls, data, len );
@@ -1069,12 +1108,16 @@ static int tls_send_handshake ( struct tls_connection *tls,
}
/**
- * Transmit Client Hello record
+ * Digest or transmit Client Hello record
*
* @v tls TLS connection
+ * @v action Action to take on Client Hello record
* @ret rc Return status code
*/
-static int tls_send_client_hello ( struct tls_connection *tls ) {
+static int tls_client_hello ( struct tls_connection *tls,
+ int ( * action ) ( struct tls_connection *tls,
+ const void *data,
+ size_t len ) ) {
struct tls_session *session = tls->session;
size_t name_len = strlen ( session->name );
struct {
@@ -1182,7 +1225,18 @@ static int tls_send_client_hello ( struct tls_connection *tls ) {
memcpy ( hello.extensions.session_ticket.data, session->ticket,
sizeof ( hello.extensions.session_ticket.data ) );
- return tls_send_handshake ( tls, &hello, sizeof ( hello ) );
+ return action ( tls, &hello, sizeof ( hello ) );
+}
+
+/**
+ * Transmit Client Hello record
+ *
+ * @v tls TLS connection
+ * @ret rc Return status code
+ */
+static int tls_send_client_hello ( struct tls_connection *tls ) {
+
+ return tls_client_hello ( tls, tls_send_handshake );
}
/**
@@ -1892,22 +1946,18 @@ static int tls_new_server_hello ( struct tls_connection *tls,
DBGC ( tls, "TLS %p using protocol version %d.%d\n",
tls, ( version >> 8 ), ( version & 0xff ) );
- /* Use MD5+SHA1 digest algorithm for handshake verification
- * for versions earlier than TLSv1.2.
- */
- if ( ! tls_version ( tls, TLS_VERSION_TLS_1_2 ) ) {
- tls->handshake_digest = &md5_sha1_algorithm;
- tls->handshake_ctx = tls->handshake_md5_sha1_ctx;
- }
+ /* Select cipher suite */
+ if ( ( rc = tls_select_cipher ( tls, hello_b->cipher_suite ) ) != 0 )
+ return rc;
+
+ /* Add preceding Client Hello to handshake digest */
+ if ( ( rc = tls_client_hello ( tls, tls_add_handshake ) ) != 0 )
+ return rc;
/* Copy out server random bytes */
memcpy ( &tls->server_random, &hello_a->random,
sizeof ( tls->server_random ) );
- /* Select cipher suite */
- if ( ( rc = tls_select_cipher ( tls, hello_b->cipher_suite ) ) != 0 )
- return rc;
-
/* Check session ID */
if ( hello_a->session_id_len &&
( hello_a->session_id_len == tls->session_id_len ) &&
@@ -3504,6 +3554,7 @@ int add_tls ( struct interface *xfer, const char *name,
tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
tls_clear_cipher ( tls, &tls->rx_cipherspec );
tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
+ tls_clear_handshake ( tls );
tls->client_random.gmt_unix_time = time ( NULL );
iob_populate ( &tls->rx_header_iobuf, &tls->rx_header, 0,
sizeof ( tls->rx_header ) );