diff options
-rw-r--r-- | src/net/tls.c | 101 |
1 files changed, 62 insertions, 39 deletions
diff --git a/src/net/tls.c b/src/net/tls.c index da16889fd..66ab1e9ce 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -1394,21 +1394,18 @@ struct tls_key_exchange_algorithm tls_pubkey_exchange_algorithm = { }; /** - * Transmit Client Key Exchange record using DHE key exchange + * Verify Diffie-Hellman parameter signature * * @v tls TLS connection + * @v param_len Diffie-Hellman parameter length * @ret rc Return status code */ -static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { +static int tls_verify_dh_params ( struct tls_connection *tls, + size_t param_len ) { struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending; struct pubkey_algorithm *pubkey; struct digest_algorithm *digest; int use_sig_hash = tls_version ( tls, TLS_VERSION_TLS_1_2 ); - uint8_t private[ sizeof ( tls->client_random.random ) ]; - const struct { - uint16_t len; - uint8_t data[0]; - } __attribute__ (( packed )) *dh_val[3]; const struct { struct tls_signature_hash_id sig_hash[use_sig_hash]; uint16_t signature_len; @@ -1416,29 +1413,14 @@ static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { } __attribute__ (( packed )) *sig; const void *data; size_t remaining; - size_t frag_len; - unsigned int i; int rc; - /* Parse ServerKeyExchange */ - data = tls->server_key; - remaining = tls->server_key_len; - for ( i = 0 ; i < ( sizeof ( dh_val ) / sizeof ( dh_val[0] ) ) ; i++ ){ - dh_val[i] = data; - if ( ( sizeof ( *dh_val[i] ) > remaining ) || - ( ntohs ( dh_val[i]->len ) > ( remaining - - sizeof ( *dh_val[i] ) ) )){ - DBGC ( tls, "TLS %p received underlength " - "ServerKeyExchange\n", tls ); - DBGC_HDA ( tls, 0, tls->server_key, - tls->server_key_len ); - rc = -EINVAL_KEY_EXCHANGE; - goto err_header; - } - frag_len = ( sizeof ( *dh_val[i] ) + ntohs ( dh_val[i]->len )); - data += frag_len; - remaining -= frag_len; - } + /* Signature follows parameters */ + assert ( param_len <= tls->server_key_len ); + data = ( tls->server_key + param_len ); + remaining = ( tls->server_key_len - param_len ); + + /* Parse signature from ServerKeyExchange */ sig = data; if ( ( sizeof ( *sig ) > remaining ) || ( ntohs ( sig->signature_len ) > ( remaining - @@ -1446,8 +1428,7 @@ static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { DBGC ( tls, "TLS %p received underlength ServerKeyExchange\n", tls ); DBGC_HDA ( tls, 0, tls->server_key, tls->server_key_len ); - rc = -EINVAL_KEY_EXCHANGE; - goto err_header; + return -EINVAL_KEY_EXCHANGE; } /* Identify signature and hash algorithm */ @@ -1457,15 +1438,13 @@ static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { if ( ( ! pubkey ) || ( ! digest ) ) { DBGC ( tls, "TLS %p ServerKeyExchange unsupported " "signature and hash algorithm\n", tls ); - rc = -ENOTSUP_SIG_HASH; - goto err_sig_hash; + return -ENOTSUP_SIG_HASH; } if ( pubkey != cipherspec->suite->pubkey ) { DBGC ( tls, "TLS %p ServerKeyExchange incorrect " "signature algorithm %s (expected %s)\n", tls, pubkey->name, cipherspec->suite->pubkey->name ); - rc = -EPERM_KEY_EXCHANGE; - goto err_sig_hash; + return -EPERM_KEY_EXCHANGE; } } else { pubkey = cipherspec->suite->pubkey; @@ -1485,8 +1464,7 @@ static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { sizeof ( tls->client_random ) ); digest_update ( digest, ctx, tls->server_random, sizeof ( tls->server_random ) ); - digest_update ( digest, ctx, tls->server_key, - ( tls->server_key_len - remaining ) ); + digest_update ( digest, ctx, tls->server_key, param_len ); digest_final ( digest, ctx, hash ); /* Verify signature */ @@ -1497,11 +1475,57 @@ static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { "verification\n", tls ); DBGC_HDA ( tls, 0, tls->server_key, tls->server_key_len ); - rc = -EPERM_KEY_EXCHANGE; - goto err_verify; + return -EPERM_KEY_EXCHANGE; } } + return 0; +} + +/** + * Transmit Client Key Exchange record using DHE key exchange + * + * @v tls TLS connection + * @ret rc Return status code + */ +static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { + uint8_t private[ sizeof ( tls->client_random.random ) ]; + const struct { + uint16_t len; + uint8_t data[0]; + } __attribute__ (( packed )) *dh_val[3]; + const void *data; + size_t remaining; + size_t frag_len; + size_t param_len; + unsigned int i; + int rc; + + /* Parse ServerKeyExchange */ + data = tls->server_key; + remaining = tls->server_key_len; + for ( i = 0 ; i < ( sizeof ( dh_val ) / sizeof ( dh_val[0] ) ) ; i++ ){ + dh_val[i] = data; + if ( ( sizeof ( *dh_val[i] ) > remaining ) || + ( ntohs ( dh_val[i]->len ) > ( remaining - + sizeof ( *dh_val[i] ) ) )){ + DBGC ( tls, "TLS %p received underlength " + "ServerKeyExchange\n", tls ); + DBGC_HDA ( tls, 0, tls->server_key, + tls->server_key_len ); + rc = -EINVAL_KEY_EXCHANGE; + goto err_header; + } + frag_len = ( sizeof ( *dh_val[i] ) + ntohs ( dh_val[i]->len )); + data += frag_len; + remaining -= frag_len; + } + param_len = ( tls->server_key_len - remaining ); + + /* Verify parameter signature */ + if ( ( rc = tls_verify_dh_params ( tls, param_len ) ) != 0 ) + goto err_verify; + /* Generate Diffie-Hellman private key */ if ( ( rc = tls_generate_random ( tls, private, sizeof ( private ) ) ) != 0 ) { @@ -1573,7 +1597,6 @@ static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { err_alloc: err_random: err_verify: - err_sig_hash: err_header: return rc; } |