diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e2f3fdc..56767534 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -825,11 +825,6 @@ if(ENABLE_TLS AND NOT WIN32) tool_tls13_psk_only_sm4_gcm tool_tls13_early_data_sm4_gcm PROPERTIES FIXTURES_REQUIRED gmssl_cert_files) - set_tests_properties( - tool_tls13_hrr_sm4_gcm - tool_tls13_psk_only_sm4_gcm - tool_tls13_early_data_sm4_gcm - PROPERTIES DISABLED TRUE) if(OPENSSL_EXECUTABLE AND GMSSL_OPENSSL_INTEROP_ENABLED) add_test(NAME tool_tls12_openssl_server COMMAND ${CMAKE_COMMAND} -DOPENSSL_EXECUTABLE=${OPENSSL_EXECUTABLE} -DTEST_CASE=tls12_openssl_server -P "${CMAKE_SOURCE_DIR}/cmake/openssl_interop_commands.cmake") add_test(NAME tool_tls12_openssl_server_renegotiation_info COMMAND ${CMAKE_COMMAND} -DOPENSSL_EXECUTABLE=${OPENSSL_EXECUTABLE} -DTEST_CASE=tls12_openssl_server_renegotiation_info -P "${CMAKE_SOURCE_DIR}/cmake/openssl_interop_commands.cmake") @@ -855,10 +850,6 @@ if(ENABLE_TLS AND NOT WIN32) tool_tls13_psk_only_openssl_server tool_tls13_psk_only_openssl_client PROPERTIES FIXTURES_REQUIRED gmssl_cert_files) - set_tests_properties( - tool_tls13_psk_only_openssl_server - tool_tls13_psk_only_openssl_client - PROPERTIES DISABLED TRUE) elseif(NOT OPENSSL_EXECUTABLE) message(STATUS "openssl executable not found; skipping OpenSSL TLS interop tests") endif() @@ -874,7 +865,7 @@ endif() # set(CPACK_PACKAGE_NAME "GmSSL") set(CPACK_PACKAGE_VENDOR "GmSSL develop team") -set(CPACK_PACKAGE_VERSION "3.2.0-dev.1133") +set(CPACK_PACKAGE_VERSION "3.2.0-dev.1134") set(CPACK_PACKAGE_DESCRIPTION_FILE ${PROJECT_SOURCE_DIR}/README.md) set(CPACK_NSIS_MODIFY_PATH ON) include(CPack) diff --git a/cmake/tls_command_test.cmake b/cmake/tls_command_test.cmake index 6b40cea1..644b24e1 100644 --- a/cmake/tls_command_test.cmake +++ b/cmake/tls_command_test.cmake @@ -5,6 +5,11 @@ function(gmssl_require_file file) endfunction() function(gmssl_run_command_interop_test) + if(POLICY CMP0053) + cmake_policy(PUSH) + cmake_policy(SET CMP0053 NEW) + endif() + set(one_value_args TEST_NAME PORT SERVER_COMMAND CLIENT_COMMAND EXPECT_CLIENT_LOG EXPECT_SERVER_LOG) cmake_parse_arguments(TEST "" "${one_value_args}" "" ${ARGN}) @@ -81,9 +86,18 @@ function(gmssl_run_command_interop_test) message(FATAL_ERROR "server log does not contain expected text: ${TEST_EXPECT_SERVER_LOG}") endif() endif() + + if(POLICY CMP0053) + cmake_policy(POP) + endif() endfunction() function(gmssl_run_tls_command_test) + if(POLICY CMP0053) + cmake_policy(PUSH) + cmake_policy(SET CMP0053 NEW) + endif() + set(one_value_args TEST_NAME PORT EXPECT_CLIENT_LOG EXPECT_SERVER_LOG) set(multi_value_args SERVER_ARGS CLIENT_ARGS) cmake_parse_arguments(TEST "" "${one_value_args}" "${multi_value_args}" ${ARGN}) @@ -180,4 +194,8 @@ function(gmssl_run_tls_command_test) message(FATAL_ERROR "server log does not contain expected text: ${TEST_EXPECT_SERVER_LOG}") endif() endif() + + if(POLICY CMP0053) + cmake_policy(POP) + endif() endfunction() diff --git a/include/gmssl/version.h b/include/gmssl/version.h index d349921c..91218a25 100644 --- a/include/gmssl/version.h +++ b/include/gmssl/version.h @@ -18,7 +18,7 @@ extern "C" { #define GMSSL_VERSION_NUM 30200 -#define GMSSL_VERSION_STR "GmSSL 3.2.0-dev.1133" +#define GMSSL_VERSION_STR "GmSSL 3.2.0-dev.1134" int gmssl_version_num(void); const char *gmssl_version_str(void); diff --git a/src/tls13.c b/src/tls13.c index 9a7ad617..f82a084d 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -7634,11 +7634,15 @@ int tls13_recv_client_hello_again(TLS_CONNECT *conn) // Extensions const uint8_t *key_share = NULL; - size_t key_share_len; + size_t key_share_len = 0; const uint8_t *pre_shared_key = NULL; - size_t pre_shared_key_len; + size_t pre_shared_key_len = 0; const uint8_t *cookie = NULL; - size_t cookie_len; + size_t cookie_len = 0; + const uint8_t *client_hello1_exts; + size_t client_hello1_exts_len; + const uint8_t *client_hello2_exts; + size_t client_hello2_exts_len; const uint8_t *key_exchange; size_t key_exchange_len; @@ -7702,14 +7706,20 @@ int tls13_recv_client_hello_again(TLS_CONNECT *conn) // update client_server memcpy(conn->client_random, random, 32); + client_hello1_exts = _exts; + client_hello1_exts_len = _extslen; + client_hello2_exts = exts; + client_hello2_exts_len = extslen; while (extslen) { int ext_type; const uint8_t *ext_data; size_t ext_datalen; - int _ext_type; - const uint8_t *_ext_data; - size_t _ext_datalen; + const uint8_t *matching_ext_data = NULL; + size_t matching_ext_datalen = 0; + int matching_ext_found = 0; + const uint8_t *search_exts = client_hello1_exts; + size_t search_exts_len = client_hello1_exts_len; if (tls_ext_from_bytes(&ext_type, &ext_data, &ext_datalen, &exts, &extslen) != 1) { error_print(); @@ -7717,6 +7727,29 @@ int tls13_recv_client_hello_again(TLS_CONNECT *conn) return -1; } + { + const uint8_t *dup_exts = exts; + size_t dup_exts_len = extslen; + + while (dup_exts_len) { + int dup_ext_type; + const uint8_t *dup_ext_data; + size_t dup_ext_datalen; + + if (tls_ext_from_bytes(&dup_ext_type, &dup_ext_data, &dup_ext_datalen, + &dup_exts, &dup_exts_len) != 1) { + error_print(); + tls13_send_alert(conn, TLS_alert_decode_error); + return -1; + } + if (dup_ext_type == ext_type) { + error_print(); + tls13_send_alert(conn, TLS_alert_illegal_parameter); + return -1; + } + } + } + // ClientHello2 extensions // * key_share - must exist, only one key_exchange based on conn->key_exchange_group // * pre_shared_key - might be subset of ClientHello1.pre_shared_key @@ -7747,20 +7780,30 @@ int tls13_recv_client_hello_again(TLS_CONNECT *conn) continue; } - // get ext in ClientHello1 (omit early_data) - if (tls_ext_from_bytes(&_ext_type, &_ext_data, &_ext_datalen, &_exts, &_extslen) != 1) { - error_print(); - tls13_send_alert(conn, TLS_alert_decode_error); - return -1; - } - if (_ext_type == TLS_extension_early_data) { - if (tls_ext_from_bytes(&_ext_type, &_ext_data, &_ext_datalen, &_exts, &_extslen) != 1) { + // Find the corresponding ClientHello1 extension by type. The order + // can change after HRR; early_data is intentionally omitted. + while (search_exts_len) { + int _ext_type; + const uint8_t *_ext_data; + size_t _ext_datalen; + + if (tls_ext_from_bytes(&_ext_type, &_ext_data, &_ext_datalen, &search_exts, &search_exts_len) != 1) { error_print(); tls13_send_alert(conn, TLS_alert_decode_error); return -1; } + + if (_ext_type == TLS_extension_early_data) { + continue; + } + if (ext_type == _ext_type) { + matching_ext_data = _ext_data; + matching_ext_datalen = _ext_datalen; + matching_ext_found = 1; + break; + } } - if (ext_type != _ext_type) { + if (!matching_ext_found) { error_print(); tls13_send_alert(conn, TLS_alert_illegal_parameter); return -1; @@ -7774,6 +7817,11 @@ int tls13_recv_client_hello_again(TLS_CONNECT *conn) tls13_send_alert(conn, TLS_alert_decode_error); return -1; } + if (key_share) { + error_print(); + tls13_send_alert(conn, TLS_alert_illegal_parameter); + return -1; + } key_share = ext_data; key_share_len = ext_datalen; break; @@ -7785,13 +7833,20 @@ int tls13_recv_client_hello_again(TLS_CONNECT *conn) const uint8_t *binders; size_t binders_len; const uint8_t *_psk_identities; + const uint8_t *_psk_identities_start; size_t _psk_identities_len; + size_t _psk_identities_start_len; if (!ext_data) { error_print(); tls13_send_alert(conn, TLS_alert_decode_error); return -1; } + if (pre_shared_key) { + error_print(); + tls13_send_alert(conn, TLS_alert_illegal_parameter); + return -1; + } if (tls13_client_pre_shared_key_from_bytes(&psk_identities, &psk_identities_len, &binders, &binders_len, ext_data, ext_datalen) != 1) { error_print(); @@ -7799,10 +7854,12 @@ int tls13_recv_client_hello_again(TLS_CONNECT *conn) return -1; } if (tls13_client_pre_shared_key_from_bytes(&_psk_identities, &_psk_identities_len, - &binders, &binders_len, _ext_data, _ext_datalen) != 1) { + &binders, &binders_len, matching_ext_data, matching_ext_datalen) != 1) { error_print(); return -1; } + _psk_identities_start = _psk_identities; + _psk_identities_start_len = _psk_identities_len; while (psk_identities_len) { const uint8_t *id; size_t idlen; @@ -7810,6 +7867,8 @@ int tls13_recv_client_hello_again(TLS_CONNECT *conn) const uint8_t *_id; size_t _idlen; int match = 0; + _psk_identities = _psk_identities_start; + _psk_identities_len = _psk_identities_start_len; if (tls13_psk_identity_from_bytes(&id, &idlen, &age, &psk_identities, &psk_identities_len) != 1) { error_print(); @@ -7838,8 +7897,8 @@ int tls13_recv_client_hello_again(TLS_CONNECT *conn) break; default: - if (ext_datalen != _ext_datalen - || memcmp(ext_data, _ext_data, _ext_datalen) != 0) { + if (ext_datalen != matching_ext_datalen + || (ext_datalen && memcmp(ext_data, matching_ext_data, matching_ext_datalen) != 0)) { error_print(); tls13_send_alert(conn, TLS_alert_illegal_parameter); return -1; @@ -7847,6 +7906,53 @@ int tls13_recv_client_hello_again(TLS_CONNECT *conn) } } + // ClientHello2 must not drop any ClientHello1 extension except early_data. + while (client_hello1_exts_len) { + int _ext_type; + const uint8_t *_ext_data; + size_t _ext_datalen; + const uint8_t *search_exts = client_hello2_exts; + size_t search_exts_len = client_hello2_exts_len; + int found = 0; + + if (tls_ext_from_bytes(&_ext_type, &_ext_data, &_ext_datalen, + &client_hello1_exts, &client_hello1_exts_len) != 1) { + error_print(); + tls13_send_alert(conn, TLS_alert_decode_error); + return -1; + } + if (_ext_type == TLS_extension_early_data) { + continue; + } + if (_ext_type == TLS_extension_key_share && key_share) { + continue; + } + if (_ext_type == TLS_extension_pre_shared_key && pre_shared_key) { + continue; + } + while (!found && search_exts_len) { + int ext_type; + const uint8_t *ext_data; + size_t ext_datalen; + + if (tls_ext_from_bytes(&ext_type, &ext_data, &ext_datalen, &search_exts, &search_exts_len) != 1) { + error_print(); + tls13_send_alert(conn, TLS_alert_decode_error); + return -1; + } + if (ext_type == _ext_type + && ext_datalen == _ext_datalen + && (!ext_datalen || memcmp(ext_data, _ext_data, _ext_datalen) == 0)) { + found = 1; + } + } + if (!found) { + error_print(); + tls13_send_alert(conn, TLS_alert_illegal_parameter); + return -1; + } + } + // client must echo ClientHello1.cookie if (conn->cookie && !cookie) { error_print();