diff options
author | Michael Brown <mcb30@ipxe.org> | 2022-11-09 14:04:43 +0000 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2022-11-09 14:49:42 +0000 |
commit | 7256a6eb24720adfd30c0307a415e51e9a402059 (patch) | |
tree | b6ef488a22970b854c3312724b3c690e0c0bff9e /src | |
parent | 51ecc054906eb0b1738c9d5541c7c4dfc15ec5fe (diff) | |
download | ipxe-7256a6eb24720adfd30c0307a415e51e9a402059.zip ipxe-7256a6eb24720adfd30c0307a415e51e9a402059.tar.gz ipxe-7256a6eb24720adfd30c0307a415e51e9a402059.tar.bz2 |
[tls] Allow handshake digest algorithm to be specified by cipher suite
All existing cipher suites use SHA-256 as the TLSv1.2 and above
handshake digest algorithm (even when using SHA-1 as the MAC digest
algorithm). Some GCM cipher suites use SHA-384 as the handshake
digest algorithm.
Allow the cipher suite to specify the handshake (and PRF) digest
algorithm to be used for TLSv1.2 and above.
This requires some restructuring to allow for the fact that the
ClientHello message must be included within the handshake digest, even
though the relevant digest algorithm is not yet known at the point
that the ClientHello is sent. Fortunately, the ClientHello may be
reproduced verbatim at the point of receiving the ServerHello, so we
rely on reconstructing (rather than storing) this message.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/crypto/mishmash/rsa_aes_cbc_sha1.c | 5 | ||||
-rw-r--r-- | src/crypto/mishmash/rsa_aes_cbc_sha256.c | 4 | ||||
-rw-r--r-- | src/include/ipxe/tls.h | 7 | ||||
-rw-r--r-- | src/net/tls.c | 177 |
4 files changed, 125 insertions, 68 deletions
diff --git a/src/crypto/mishmash/rsa_aes_cbc_sha1.c b/src/crypto/mishmash/rsa_aes_cbc_sha1.c index 4f399a0..c2ecf12 100644 --- a/src/crypto/mishmash/rsa_aes_cbc_sha1.c +++ b/src/crypto/mishmash/rsa_aes_cbc_sha1.c @@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/rsa.h> #include <ipxe/aes.h> #include <ipxe/sha1.h> +#include <ipxe/sha256.h> #include <ipxe/tls.h> /** TLS_DHE_RSA_WITH_AES_128_CBC_SHA cipher suite */ @@ -41,6 +42,7 @@ tls_dhe_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 03 ) = { .pubkey = &rsa_algorithm, .cipher = &aes_cbc_algorithm, .digest = &sha1_algorithm, + .handshake = &sha256_algorithm, }; /** TLS_DHE_RSA_WITH_AES_256_CBC_SHA cipher suite */ @@ -55,6 +57,7 @@ tls_dhe_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 04 ) = { .pubkey = &rsa_algorithm, .cipher = &aes_cbc_algorithm, .digest = &sha1_algorithm, + .handshake = &sha256_algorithm, }; /** TLS_RSA_WITH_AES_128_CBC_SHA cipher suite */ @@ -69,6 +72,7 @@ tls_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 13 ) = { .pubkey = &rsa_algorithm, .cipher = &aes_cbc_algorithm, .digest = &sha1_algorithm, + .handshake = &sha256_algorithm, }; /** TLS_RSA_WITH_AES_256_CBC_SHA cipher suite */ @@ -83,4 +87,5 @@ tls_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 14 ) = { .pubkey = &rsa_algorithm, .cipher = &aes_cbc_algorithm, .digest = &sha1_algorithm, + .handshake = &sha256_algorithm, }; diff --git a/src/crypto/mishmash/rsa_aes_cbc_sha256.c b/src/crypto/mishmash/rsa_aes_cbc_sha256.c index 4b02a77..7f114b1 100644 --- a/src/crypto/mishmash/rsa_aes_cbc_sha256.c +++ b/src/crypto/mishmash/rsa_aes_cbc_sha256.c @@ -41,6 +41,7 @@ tls_dhe_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 01 ) = { .pubkey = &rsa_algorithm, .cipher = &aes_cbc_algorithm, .digest = &sha256_algorithm, + .handshake = &sha256_algorithm, }; /** TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 cipher suite */ @@ -55,6 +56,7 @@ tls_dhe_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite ( 02 ) = { .pubkey = &rsa_algorithm, .cipher = &aes_cbc_algorithm, .digest = &sha256_algorithm, + .handshake = &sha256_algorithm, }; /** TLS_RSA_WITH_AES_128_CBC_SHA256 cipher suite */ @@ -69,6 +71,7 @@ tls_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 11 ) = { .pubkey = &rsa_algorithm, .cipher = &aes_cbc_algorithm, .digest = &sha256_algorithm, + .handshake = &sha256_algorithm, }; /** TLS_RSA_WITH_AES_256_CBC_SHA256 cipher suite */ @@ -83,4 +86,5 @@ tls_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite ( 12 ) = { .pubkey = &rsa_algorithm, .cipher = &aes_cbc_algorithm, .digest = &sha256_algorithm, + .handshake = &sha256_algorithm, }; diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index 8796fe9..3558141 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -16,7 +16,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/crypto.h> #include <ipxe/md5.h> #include <ipxe/sha1.h> -#include <ipxe/sha256.h> #include <ipxe/x509.h> #include <ipxe/privkey.h> #include <ipxe/pending.h> @@ -177,6 +176,8 @@ struct tls_cipher_suite { struct cipher_algorithm *cipher; /** MAC digest algorithm */ struct digest_algorithm *digest; + /** Handshake digest algorithm (for TLSv1.2 and above) */ + struct digest_algorithm *handshake; /** Numeric code (in network-endian order) */ uint16_t code; /** Key length */ @@ -346,10 +347,6 @@ struct tls_connection { void *server_key; /** Server Key Exchange record length */ size_t server_key_len; - /** MD5+SHA1 context for handshake verification */ - uint8_t handshake_md5_sha1_ctx[MD5_SHA1_CTX_SIZE]; - /** SHA256 context for handshake verification */ - uint8_t handshake_sha256_ctx[SHA256_CTX_SIZE]; /** Digest algorithm used for handshake verification */ struct digest_algorithm *handshake_digest; /** Digest algorithm context used for handshake verification */ diff --git a/src/net/tls.c b/src/net/tls.c index af310a5..8996296 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 ) ); |