mirror of
https://github.com/espressif/esp-idf.git
synced 2025-11-06 22:58:55 +00:00
feat(esp_tls): supports setting tls version and ciphersuite in server config
Closes https://github.com/espressif/esp-idf/issues/17660
This commit is contained in:
@@ -364,6 +364,12 @@ typedef struct esp_tls_cfg_server {
|
|||||||
Important note: the pointer must be valid for connection */
|
Important note: the pointer must be valid for connection */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
esp_tls_proto_ver_t tls_version; /*!< TLS protocol version for this server, e.g., TLS 1.2, TLS 1.3
|
||||||
|
(default - no preference). Enables TLS version control per server instance. */
|
||||||
|
|
||||||
|
const int *ciphersuites_list; /*!< Pointer to a zero-terminated array of IANA identifiers of TLS ciphersuites.
|
||||||
|
Please check the list validity by esp_tls_get_ciphersuites_list() API.
|
||||||
|
This allows per-server cipher suite configuration. */
|
||||||
} esp_tls_cfg_server_t;
|
} esp_tls_cfg_server_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -868,6 +868,29 @@ static esp_err_t set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Configure per-service TLS version
|
||||||
|
const esp_tls_proto_ver_t tls_ver = cfg->tls_version;
|
||||||
|
if (tls_ver == ESP_TLS_VER_TLS_1_3) {
|
||||||
|
#if CONFIG_MBEDTLS_SSL_PROTO_TLS1_3
|
||||||
|
ESP_LOGI(TAG, "Setting server TLS version to 0x%4x", MBEDTLS_SSL_VERSION_TLS1_3);
|
||||||
|
mbedtls_ssl_conf_min_tls_version(&tls->conf, MBEDTLS_SSL_VERSION_TLS1_3);
|
||||||
|
mbedtls_ssl_conf_max_tls_version(&tls->conf, MBEDTLS_SSL_VERSION_TLS1_3);
|
||||||
|
#else
|
||||||
|
ESP_LOGE(TAG, "TLS 1.3 is not enabled in config");
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
#endif
|
||||||
|
} else if (tls_ver == ESP_TLS_VER_TLS_1_2) {
|
||||||
|
ESP_LOGD(TAG, "Setting server TLS version to 0x%4x", MBEDTLS_SSL_VERSION_TLS1_2);
|
||||||
|
mbedtls_ssl_conf_min_tls_version(&tls->conf, MBEDTLS_SSL_VERSION_TLS1_2);
|
||||||
|
mbedtls_ssl_conf_max_tls_version(&tls->conf, MBEDTLS_SSL_VERSION_TLS1_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfg->ciphersuites_list != NULL && cfg->ciphersuites_list[0] != 0) {
|
||||||
|
ESP_LOGD(TAG, "Set the server ciphersuites list (user-provided)");
|
||||||
|
mbedtls_ssl_conf_ciphersuites(&tls->conf, cfg->ciphersuites_list);
|
||||||
|
} else {
|
||||||
|
ESP_LOGD(TAG, "No custom cipher suites provided - using default");
|
||||||
|
}
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -141,6 +141,15 @@ struct httpd_ssl_config {
|
|||||||
|
|
||||||
/** TLS handshake timeout in milliseconds, default timeout is 10 seconds if not set */
|
/** TLS handshake timeout in milliseconds, default timeout is 10 seconds if not set */
|
||||||
uint32_t tls_handshake_timeout_ms;
|
uint32_t tls_handshake_timeout_ms;
|
||||||
|
|
||||||
|
/** TLS protocol version for this server, e.g., TLS 1.2, TLS 1.3
|
||||||
|
* (default - no preference). Enables per-server TLS version control. */
|
||||||
|
esp_tls_proto_ver_t tls_version;
|
||||||
|
|
||||||
|
/** Pointer to a zero-terminated array of IANA identifiers of TLS ciphersuites.
|
||||||
|
* Please check the list validity by esp_tls_get_ciphersuites_list() API.
|
||||||
|
* This allows per-server cipher suite configuration. */
|
||||||
|
const int *ciphersuites_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct httpd_ssl_config httpd_ssl_config_t;
|
typedef struct httpd_ssl_config httpd_ssl_config_t;
|
||||||
@@ -203,7 +212,9 @@ typedef struct httpd_ssl_config httpd_ssl_config_t;
|
|||||||
.ssl_userdata = NULL, \
|
.ssl_userdata = NULL, \
|
||||||
.cert_select_cb = NULL, \
|
.cert_select_cb = NULL, \
|
||||||
.alpn_protos = NULL, \
|
.alpn_protos = NULL, \
|
||||||
.tls_handshake_timeout_ms = 0 \
|
.tls_handshake_timeout_ms = 0, \
|
||||||
|
.tls_version = ESP_TLS_VER_ANY, \
|
||||||
|
.ciphersuites_list = NULL, \
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -279,6 +279,9 @@ static esp_err_t create_secure_context(const struct httpd_ssl_config *config, ht
|
|||||||
cfg->alpn_protos = config->alpn_protos;
|
cfg->alpn_protos = config->alpn_protos;
|
||||||
cfg->tls_handshake_timeout_ms = config->tls_handshake_timeout_ms;
|
cfg->tls_handshake_timeout_ms = config->tls_handshake_timeout_ms;
|
||||||
|
|
||||||
|
cfg->tls_version = config->tls_version;
|
||||||
|
cfg->ciphersuites_list = config->ciphersuites_list;
|
||||||
|
|
||||||
#if defined(CONFIG_ESP_HTTPS_SERVER_CERT_SELECT_HOOK)
|
#if defined(CONFIG_ESP_HTTPS_SERVER_CERT_SELECT_HOOK)
|
||||||
cfg->cert_select_cb = config->cert_select_cb;
|
cfg->cert_select_cb = config->cert_select_cb;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -7,4 +7,31 @@ menu "Example Configuration"
|
|||||||
Enable user callback for esp_https_server which can be used to get SSL context (connection information)
|
Enable user callback for esp_https_server which can be used to get SSL context (connection information)
|
||||||
E.g. Certificate of the connected client
|
E.g. Certificate of the connected client
|
||||||
|
|
||||||
|
choice EXAMPLE_ENABLE_HTTPS_SERVER_TLS_VERSION
|
||||||
|
prompt "Choose TLS version"
|
||||||
|
default EXAMPLE_ENABLE_HTTPS_SERVER_TLS_1_2_ONLY
|
||||||
|
config EXAMPLE_ENABLE_HTTPS_SERVER_TLS_1_2_ONLY
|
||||||
|
bool "TLS 1.2"
|
||||||
|
select MBEDTLS_SSL_PROTO_TLS1_2
|
||||||
|
help
|
||||||
|
Enable HTTPS server TLS 1.2
|
||||||
|
config EXAMPLE_ENABLE_HTTPS_SERVER_TLS_1_3_ONLY
|
||||||
|
bool "TLS 1.3"
|
||||||
|
select MBEDTLS_SSL_PROTO_TLS1_3
|
||||||
|
help
|
||||||
|
Enable HTTPS server TLS 1.3
|
||||||
|
config EXAMPLE_ENABLE_HTTPS_SERVER_TLS_ANY
|
||||||
|
bool "TLS 1.3 and 1.2"
|
||||||
|
select MBEDTLS_SSL_PROTO_TLS1_3
|
||||||
|
select MBEDTLS_SSL_PROTO_TLS1_2
|
||||||
|
help
|
||||||
|
Enable HTTPS server TLS 1.3 and 1.2
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config EXAMPLE_ENABLE_HTTPS_SERVER_CUSTOM_CIPHERSUITES
|
||||||
|
bool "Enable HTTPS server custom ciphersuites"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Enable HTTPS server custom ciphersuites
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|||||||
@@ -21,6 +21,10 @@
|
|||||||
#include "esp_tls.h"
|
#include "esp_tls.h"
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
|
#if CONFIG_EXAMPLE_ENABLE_HTTPS_SERVER_CUSTOM_CIPHERSUITES
|
||||||
|
#include "mbedtls/ssl_ciphersuites.h"
|
||||||
|
#endif // CONFIG_EXAMPLE_ENABLE_HTTPS_SERVER_CUSTOM_CIPHERSUITES
|
||||||
|
|
||||||
/* A simple example that demonstrates how to create GET and POST
|
/* A simple example that demonstrates how to create GET and POST
|
||||||
* handlers and start an HTTPS server.
|
* handlers and start an HTTPS server.
|
||||||
*/
|
*/
|
||||||
@@ -159,6 +163,27 @@ static httpd_handle_t start_webserver(void)
|
|||||||
conf.prvtkey_pem = prvtkey_pem_start;
|
conf.prvtkey_pem = prvtkey_pem_start;
|
||||||
conf.prvtkey_len = prvtkey_pem_end - prvtkey_pem_start;
|
conf.prvtkey_len = prvtkey_pem_end - prvtkey_pem_start;
|
||||||
|
|
||||||
|
#if CONFIG_EXAMPLE_ENABLE_HTTPS_SERVER_CUSTOM_CIPHERSUITES
|
||||||
|
static const int ciphersuites_to_use[] = {
|
||||||
|
MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
|
||||||
|
MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
|
||||||
|
MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
|
||||||
|
MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
conf.ciphersuites_list = ciphersuites_to_use;
|
||||||
|
#else
|
||||||
|
conf.ciphersuites_list = NULL;
|
||||||
|
#endif // CONFIG_EXAMPLE_ENABLE_HTTPS_SERVER_CUSTOM_CIPHERSUITES
|
||||||
|
|
||||||
|
#if CONFIG_EXAMPLE_ENABLE_HTTPS_SERVER_TLS_1_3_ONLY
|
||||||
|
conf.tls_version = ESP_TLS_VER_TLS_1_3;
|
||||||
|
#elif CONFIG_EXAMPLE_ENABLE_HTTPS_SERVER_TLS_1_2_ONLY
|
||||||
|
conf.tls_version = ESP_TLS_VER_TLS_1_2;
|
||||||
|
#else
|
||||||
|
conf.tls_version = ESP_TLS_VER_ANY;
|
||||||
|
#endif // CONFIG_EXAMPLE_ENABLE_HTTPS_SERVER_TLS_1_3_ONLY
|
||||||
|
|
||||||
#if CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK
|
#if CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK
|
||||||
conf.user_cb = https_server_user_callback;
|
conf.user_cb = https_server_user_callback;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ def test_examples_protocol_https_server_simple(dut: Dut) -> None:
|
|||||||
# check and log bin size
|
# check and log bin size
|
||||||
binary_file = os.path.join(dut.app.binary_path, 'https_server.bin')
|
binary_file = os.path.join(dut.app.binary_path, 'https_server.bin')
|
||||||
bin_size = os.path.getsize(binary_file)
|
bin_size = os.path.getsize(binary_file)
|
||||||
logging.info('https_server_simple_bin_size : {}KB'.format(bin_size // 1024))
|
logging.info(f'https_server_simple_bin_size : {bin_size // 1024}KB')
|
||||||
# start test
|
# start test
|
||||||
logging.info('Waiting to connect with AP')
|
logging.info('Waiting to connect with AP')
|
||||||
if dut.app.sdkconfig.get('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN') is True:
|
if dut.app.sdkconfig.get('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN') is True:
|
||||||
@@ -125,8 +125,8 @@ def test_examples_protocol_https_server_simple(dut: Dut) -> None:
|
|||||||
|
|
||||||
# Expected logs
|
# Expected logs
|
||||||
|
|
||||||
logging.info('Got IP : {}'.format(got_ip))
|
logging.info(f'Got IP : {got_ip}')
|
||||||
logging.info('Got Port : {}'.format(got_port))
|
logging.info(f'Got Port : {got_port}')
|
||||||
|
|
||||||
logging.info('Performing GET request over an SSL connection with the server')
|
logging.info('Performing GET request over an SSL connection with the server')
|
||||||
|
|
||||||
@@ -156,7 +156,7 @@ def test_examples_protocol_https_server_simple(dut: Dut) -> None:
|
|||||||
|
|
||||||
if dut.app.sdkconfig.get('CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK') is True:
|
if dut.app.sdkconfig.get('CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK') is True:
|
||||||
current_cipher = dut.expect(r'Current Ciphersuite(.*)', timeout=5)[0]
|
current_cipher = dut.expect(r'Current Ciphersuite(.*)', timeout=5)[0]
|
||||||
logging.info('Current Ciphersuite {}'.format(current_cipher))
|
logging.info(f'Current Ciphersuite {current_cipher}')
|
||||||
|
|
||||||
logging.info('Checking user callback: Obtaining client certificate...')
|
logging.info('Checking user callback: Obtaining client certificate...')
|
||||||
|
|
||||||
@@ -166,9 +166,9 @@ def test_examples_protocol_https_server_simple(dut: Dut) -> None:
|
|||||||
1
|
1
|
||||||
].decode()
|
].decode()
|
||||||
|
|
||||||
logging.info('Serial No. {}'.format(serial_number))
|
logging.info(f'Serial No. {serial_number}')
|
||||||
logging.info('Issuer Name {}'.format(issuer_name))
|
logging.info(f'Issuer Name {issuer_name}')
|
||||||
logging.info('Expires on {}'.format(expiry))
|
logging.info(f'Expires on {expiry}')
|
||||||
|
|
||||||
# Close the connection
|
# Close the connection
|
||||||
conn.close()
|
conn.close()
|
||||||
@@ -203,8 +203,8 @@ def test_examples_protocol_https_server_simple_dynamic_buffers(dut: Dut) -> None
|
|||||||
|
|
||||||
# Expected logs
|
# Expected logs
|
||||||
|
|
||||||
logging.info('Got IP : {}'.format(got_ip))
|
logging.info(f'Got IP : {got_ip}')
|
||||||
logging.info('Got Port : {}'.format(got_port))
|
logging.info(f'Got Port : {got_port}')
|
||||||
|
|
||||||
logging.info('Performing GET request over an SSL connection with the server')
|
logging.info('Performing GET request over an SSL connection with the server')
|
||||||
|
|
||||||
@@ -233,7 +233,7 @@ def test_examples_protocol_https_server_simple_dynamic_buffers(dut: Dut) -> None
|
|||||||
|
|
||||||
if dut.app.sdkconfig.get('CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK') is True:
|
if dut.app.sdkconfig.get('CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK') is True:
|
||||||
current_cipher = dut.expect(r'Current Ciphersuite(.*)', timeout=5)[0]
|
current_cipher = dut.expect(r'Current Ciphersuite(.*)', timeout=5)[0]
|
||||||
logging.info('Current Ciphersuite {}'.format(current_cipher))
|
logging.info(f'Current Ciphersuite {current_cipher}')
|
||||||
|
|
||||||
logging.info('Checking user callback: Obtaining client certificate...')
|
logging.info('Checking user callback: Obtaining client certificate...')
|
||||||
|
|
||||||
@@ -243,9 +243,9 @@ def test_examples_protocol_https_server_simple_dynamic_buffers(dut: Dut) -> None
|
|||||||
1
|
1
|
||||||
].decode()
|
].decode()
|
||||||
|
|
||||||
logging.info('Serial No. : {}'.format(serial_number))
|
logging.info(f'Serial No. : {serial_number}')
|
||||||
logging.info('Issuer Name : {}'.format(issuer_name))
|
logging.info(f'Issuer Name : {issuer_name}')
|
||||||
logging.info('Expires on : {}'.format(expiry))
|
logging.info(f'Expires on : {expiry}')
|
||||||
|
|
||||||
# Close the connection
|
# Close the connection
|
||||||
conn.close()
|
conn.close()
|
||||||
@@ -277,8 +277,8 @@ def test_examples_protocol_https_server_tls1_3(dut: Dut) -> None:
|
|||||||
|
|
||||||
# Expected logs
|
# Expected logs
|
||||||
|
|
||||||
logging.info('Got IP : {}'.format(got_ip))
|
logging.info(f'Got IP : {got_ip}')
|
||||||
logging.info('Got Port : {}'.format(got_port))
|
logging.info(f'Got Port : {got_port}')
|
||||||
logging.info('Performing GET request over an SSL connection with the server using TLSv1.3')
|
logging.info('Performing GET request over an SSL connection with the server using TLSv1.3')
|
||||||
|
|
||||||
CLIENT_CERT_FILE = 'client_cert.pem'
|
CLIENT_CERT_FILE = 'client_cert.pem'
|
||||||
@@ -288,14 +288,25 @@ def test_examples_protocol_https_server_tls1_3(dut: Dut) -> None:
|
|||||||
cert.write(client_cert_pem)
|
cert.write(client_cert_pem)
|
||||||
key.write(client_key_pem)
|
key.write(client_key_pem)
|
||||||
|
|
||||||
|
# First try with TLSv1.2 and that should fail
|
||||||
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
||||||
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_3
|
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
|
||||||
ssl_context.maximum_version = ssl.TLSVersion.TLSv1_3
|
ssl_context.maximum_version = ssl.TLSVersion.TLSv1_2
|
||||||
ssl_context.verify_mode = ssl.CERT_REQUIRED
|
ssl_context.verify_mode = ssl.CERT_REQUIRED
|
||||||
ssl_context.check_hostname = False
|
ssl_context.check_hostname = False
|
||||||
ssl_context.load_verify_locations(cadata=server_cert_pem)
|
ssl_context.load_verify_locations(cadata=server_cert_pem)
|
||||||
|
|
||||||
ssl_context.load_cert_chain(certfile=CLIENT_CERT_FILE, keyfile=CLIENT_KEY_FILE)
|
ssl_context.load_cert_chain(certfile=CLIENT_CERT_FILE, keyfile=CLIENT_KEY_FILE)
|
||||||
|
conn = http.client.HTTPSConnection(got_ip, got_port, context=ssl_context)
|
||||||
|
try:
|
||||||
|
conn.request('GET', '/')
|
||||||
|
except ssl.SSLError as e:
|
||||||
|
logging.info(f'SSL handshake failed with TLSv1.2: {e}')
|
||||||
|
else:
|
||||||
|
logging.info('SSL handshake succeeded with TLSv1.2')
|
||||||
|
raise RuntimeError('This should have failed')
|
||||||
|
|
||||||
|
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_3
|
||||||
|
ssl_context.maximum_version = ssl.TLSVersion.TLSv1_3
|
||||||
|
|
||||||
os.remove(CLIENT_CERT_FILE)
|
os.remove(CLIENT_CERT_FILE)
|
||||||
os.remove(CLIENT_KEY_FILE)
|
os.remove(CLIENT_KEY_FILE)
|
||||||
@@ -312,7 +323,7 @@ def test_examples_protocol_https_server_tls1_3(dut: Dut) -> None:
|
|||||||
|
|
||||||
if dut.app.sdkconfig.get('CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK') is True:
|
if dut.app.sdkconfig.get('CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK') is True:
|
||||||
current_cipher = dut.expect(r'Current Ciphersuite(.*)', timeout=5)[0]
|
current_cipher = dut.expect(r'Current Ciphersuite(.*)', timeout=5)[0]
|
||||||
logging.info('Current Ciphersuite {}'.format(current_cipher))
|
logging.info(f'Current Ciphersuite {current_cipher}')
|
||||||
|
|
||||||
logging.info('Checking user callback: Obtaining client certificate...')
|
logging.info('Checking user callback: Obtaining client certificate...')
|
||||||
|
|
||||||
@@ -323,9 +334,120 @@ def test_examples_protocol_https_server_tls1_3(dut: Dut) -> None:
|
|||||||
timeout=5,
|
timeout=5,
|
||||||
)[1].decode()
|
)[1].decode()
|
||||||
|
|
||||||
logging.info('Serial No. : {}'.format(serial_number))
|
logging.info(f'Serial No. : {serial_number}')
|
||||||
logging.info('Issuer Name : {}'.format(issuer_name))
|
logging.info(f'Issuer Name : {issuer_name}')
|
||||||
logging.info('Expires on : {}'.format(expiry))
|
logging.info(f'Expires on : {expiry}')
|
||||||
|
|
||||||
|
# Close the connection
|
||||||
|
conn.close()
|
||||||
|
logging.info('Correct response obtained')
|
||||||
|
logging.info('SSL connection test successful\nClosing the connection')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.wifi_router
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'config',
|
||||||
|
[
|
||||||
|
'tls1_2_only',
|
||||||
|
],
|
||||||
|
indirect=True,
|
||||||
|
)
|
||||||
|
@idf_parametrize('target', ['esp32', 'esp32c3', 'esp32s3'], indirect=['target'])
|
||||||
|
def test_examples_protocol_https_server_tls1_2_only(dut: Dut) -> None:
|
||||||
|
logging.info('Waiting to connect with AP')
|
||||||
|
if dut.app.sdkconfig.get('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN') is True:
|
||||||
|
dut.expect('Please input ssid password:')
|
||||||
|
env_name = 'wifi_router'
|
||||||
|
ap_ssid = get_env_config_variable(env_name, 'ap_ssid')
|
||||||
|
ap_password = get_env_config_variable(env_name, 'ap_password')
|
||||||
|
dut.write(f'{ap_ssid} {ap_password}')
|
||||||
|
# Parse IP address and port of the server
|
||||||
|
dut.expect(r'Starting server')
|
||||||
|
got_port = int(dut.expect(r'Server listening on port (\d+)', timeout=30)[1].decode())
|
||||||
|
got_ip = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=30)[1].decode()
|
||||||
|
|
||||||
|
# Expected logs
|
||||||
|
logging.info(f'Got IP : {got_ip}')
|
||||||
|
logging.info(f'Got Port : {got_port}')
|
||||||
|
logging.info('Performing GET request over an SSL connection with the server using TLSv1.2')
|
||||||
|
|
||||||
|
CLIENT_CERT_FILE = 'client_cert.pem'
|
||||||
|
CLIENT_KEY_FILE = 'client_key.pem'
|
||||||
|
|
||||||
|
with open(CLIENT_CERT_FILE, 'w', encoding='utf-8') as cert, open(CLIENT_KEY_FILE, 'w', encoding='utf-8') as key:
|
||||||
|
cert.write(client_cert_pem)
|
||||||
|
key.write(client_key_pem)
|
||||||
|
|
||||||
|
# First try with TLSv1.3 and that should fail
|
||||||
|
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
||||||
|
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_3
|
||||||
|
ssl_context.maximum_version = ssl.TLSVersion.TLSv1_3
|
||||||
|
ssl_context.verify_mode = ssl.CERT_REQUIRED
|
||||||
|
ssl_context.check_hostname = False
|
||||||
|
ssl_context.load_verify_locations(cadata=server_cert_pem)
|
||||||
|
ssl_context.load_cert_chain(certfile=CLIENT_CERT_FILE, keyfile=CLIENT_KEY_FILE)
|
||||||
|
conn = http.client.HTTPSConnection(got_ip, got_port, context=ssl_context)
|
||||||
|
try:
|
||||||
|
conn.request('GET', '/')
|
||||||
|
except ssl.SSLError as e:
|
||||||
|
logging.info(f'SSL handshake failed with TLSv1.3: {e}')
|
||||||
|
else:
|
||||||
|
logging.info('SSL handshake succeeded with TLSv1.3')
|
||||||
|
raise RuntimeError('This should have failed')
|
||||||
|
|
||||||
|
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
|
||||||
|
ssl_context.maximum_version = ssl.TLSVersion.TLSv1_2
|
||||||
|
|
||||||
|
# Also now with TLS1.2, try with a non matching ciphersuite and that should fail
|
||||||
|
# Server only accepts: DHE-RSA-AES128-SHA256, DHE-RSA-AES256-SHA256,
|
||||||
|
# ECDHE-RSA-AES256-SHA384, ECDHE-RSA-AES128-SHA256
|
||||||
|
# Try AES128-GCM-SHA256 which is NOT in the list
|
||||||
|
ssl_context.set_ciphers('AES128-GCM-SHA256')
|
||||||
|
|
||||||
|
conn = http.client.HTTPSConnection(got_ip, got_port, context=ssl_context)
|
||||||
|
try:
|
||||||
|
logging.info('Trying SSL handshake with non-matching ciphersuite (should fail)')
|
||||||
|
conn.request('GET', '/')
|
||||||
|
except ssl.SSLError as e:
|
||||||
|
logging.info(f'SSL handshake failed with non-matching ciphersuite (expected): {e}')
|
||||||
|
else:
|
||||||
|
logging.info('SSL handshake succeeded with non-matching ciphersuite')
|
||||||
|
raise RuntimeError('This should have failed - custom ciphersuites not enforced')
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
# Now try with the matching ciphersuite
|
||||||
|
ssl_context.set_ciphers('DHE-RSA-AES128-SHA256')
|
||||||
|
|
||||||
|
os.remove(CLIENT_CERT_FILE)
|
||||||
|
os.remove(CLIENT_KEY_FILE)
|
||||||
|
|
||||||
|
conn = http.client.HTTPSConnection(got_ip, got_port, context=ssl_context)
|
||||||
|
logging.info('Performing SSL handshake with the server')
|
||||||
|
conn.request('GET', '/')
|
||||||
|
resp = conn.getresponse()
|
||||||
|
dut.expect('performing session handshake')
|
||||||
|
got_resp = resp.read().decode('utf-8')
|
||||||
|
if got_resp != success_response:
|
||||||
|
logging.info('Response obtained does not match with correct response')
|
||||||
|
raise RuntimeError('Failed to test SSL connection')
|
||||||
|
|
||||||
|
if dut.app.sdkconfig.get('CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK') is True:
|
||||||
|
current_cipher = dut.expect(r'Current Ciphersuite(.*)', timeout=5)[0]
|
||||||
|
logging.info(f'Current Ciphersuite {current_cipher}')
|
||||||
|
|
||||||
|
logging.info('Checking user callback: Obtaining client certificate...')
|
||||||
|
|
||||||
|
serial_number = dut.expect(r'serial number\s*:([^\n]*)', timeout=5)[0]
|
||||||
|
issuer_name = dut.expect(r'issuer name\s*:([^\n]*)', timeout=5)[0]
|
||||||
|
expiry = dut.expect(
|
||||||
|
r'expires on\s*:((.*)\d{4}\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])*)',
|
||||||
|
timeout=5,
|
||||||
|
)[1].decode()
|
||||||
|
|
||||||
|
logging.info(f'Serial No. : {serial_number}')
|
||||||
|
logging.info(f'Issuer Name : {issuer_name}')
|
||||||
|
logging.info(f'Expires on : {expiry}')
|
||||||
|
|
||||||
# Close the connection
|
# Close the connection
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
CONFIG_ESP_HTTPS_SERVER_ENABLE=y
|
||||||
|
CONFIG_ESP_HTTPS_SERVER_CERT_SELECT_HOOK=y
|
||||||
|
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
|
||||||
|
CONFIG_EXAMPLE_ENABLE_HTTPS_SERVER_TLS_1_2_ONLY=y
|
||||||
|
CONFIG_EXAMPLE_ENABLE_HTTPS_SERVER_CUSTOM_CIPHERSUITES=y
|
||||||
@@ -6,3 +6,4 @@ CONFIG_MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE=y
|
|||||||
CONFIG_MBEDTLS_SSL_TLS1_3_KEXM_PSK=y
|
CONFIG_MBEDTLS_SSL_TLS1_3_KEXM_PSK=y
|
||||||
CONFIG_MBEDTLS_SSL_TLS1_3_KEXM_EPHEMERAL=y
|
CONFIG_MBEDTLS_SSL_TLS1_3_KEXM_EPHEMERAL=y
|
||||||
CONFIG_MBEDTLS_SSL_TLS1_3_KEXM_PSK_EPHEMERAL=y
|
CONFIG_MBEDTLS_SSL_TLS1_3_KEXM_PSK_EPHEMERAL=y
|
||||||
|
CONFIG_EXAMPLE_ENABLE_HTTPS_SERVER_TLS_1_3_ONLY=y
|
||||||
|
|||||||
Reference in New Issue
Block a user