summaryrefslogtreecommitdiff
path: root/programs/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'programs/ssl')
-rw-r--r--programs/ssl/CMakeLists.txt61
-rw-r--r--programs/ssl/dtls_client.c342
-rw-r--r--programs/ssl/dtls_server.c408
-rw-r--r--programs/ssl/mini_client.c274
-rw-r--r--programs/ssl/ssl_client1.c288
-rw-r--r--programs/ssl/ssl_client2.c3230
-rw-r--r--programs/ssl/ssl_context_info.c1012
-rw-r--r--programs/ssl/ssl_fork_server.c381
-rw-r--r--programs/ssl/ssl_mail_client.c804
-rw-r--r--programs/ssl/ssl_pthread_server.c489
-rw-r--r--programs/ssl/ssl_server.c362
-rw-r--r--programs/ssl/ssl_server2.c4357
-rw-r--r--programs/ssl/ssl_test_common_source.c375
-rw-r--r--programs/ssl/ssl_test_lib.c648
-rw-r--r--programs/ssl/ssl_test_lib.h331
15 files changed, 13362 insertions, 0 deletions
diff --git a/programs/ssl/CMakeLists.txt b/programs/ssl/CMakeLists.txt
new file mode 100644
index 00000000000..ec2c86fb4ad
--- /dev/null
+++ b/programs/ssl/CMakeLists.txt
@@ -0,0 +1,61 @@
+find_package(Threads)
+
+set(libs
+ ${mbedtls_target}
+)
+
+set(executables
+ dtls_client
+ dtls_server
+ mini_client
+ ssl_client1
+ ssl_client2
+ ssl_context_info
+ ssl_fork_server
+ ssl_mail_client
+ ssl_server
+ ssl_server2
+)
+
+if(GEN_FILES)
+ # Inform CMake that the following file will be generated as part of the build
+ # process, so it doesn't complain that it doesn't exist yet. Starting from
+ # CMake 3.20, this will no longer be necessary as CMake will automatically
+ # propagate this information across the tree, for now it's only visible
+ # inside the same directory, so we need to propagate manually.
+ set_source_files_properties(
+ ${CMAKE_CURRENT_BINARY_DIR}/../test/query_config.c
+ PROPERTIES GENERATED TRUE)
+endif()
+
+foreach(exe IN LISTS executables)
+ set(extra_sources "")
+ if(exe STREQUAL "ssl_client2" OR exe STREQUAL "ssl_server2")
+ list(APPEND extra_sources
+ ssl_test_lib.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../test/query_config.h
+ ${CMAKE_CURRENT_BINARY_DIR}/../test/query_config.c)
+ endif()
+ add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>
+ ${extra_sources})
+ target_link_libraries(${exe} ${libs} ${CMAKE_THREAD_LIBS_INIT})
+ target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/include)
+ if(exe STREQUAL "ssl_client2" OR exe STREQUAL "ssl_server2")
+ if(GEN_FILES)
+ add_dependencies(${exe} generate_query_config_c)
+ endif()
+ target_include_directories(${exe}
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../test)
+ endif()
+endforeach()
+
+if(THREADS_FOUND)
+ add_executable(ssl_pthread_server ssl_pthread_server.c $<TARGET_OBJECTS:mbedtls_test>)
+ target_include_directories(ssl_pthread_server PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/include)
+ target_link_libraries(ssl_pthread_server ${libs} ${CMAKE_THREAD_LIBS_INIT})
+ list(APPEND executables ssl_pthread_server)
+endif(THREADS_FOUND)
+
+install(TARGETS ${executables}
+ DESTINATION "bin"
+ PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
diff --git a/programs/ssl/dtls_client.c b/programs/ssl/dtls_client.c
new file mode 100644
index 00000000000..ddb3c34b915
--- /dev/null
+++ b/programs/ssl/dtls_client.c
@@ -0,0 +1,342 @@
+/*
+ * Simple DTLS client demonstration program
+ *
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "mbedtls/build_info.h"
+
+#include "mbedtls/platform.h"
+
+#if !defined(MBEDTLS_SSL_CLI_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) || \
+ !defined(MBEDTLS_NET_C) || !defined(MBEDTLS_TIMING_C) || \
+ !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_CTR_DRBG_C) || \
+ !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_RSA_C) || \
+ !defined(MBEDTLS_PEM_PARSE_C)
+int main(void)
+{
+ mbedtls_printf("MBEDTLS_SSL_CLI_C and/or MBEDTLS_SSL_PROTO_DTLS and/or "
+ "MBEDTLS_NET_C and/or MBEDTLS_TIMING_C and/or "
+ "MBEDTLS_ENTROPY_C and/or MBEDTLS_CTR_DRBG_C and/or "
+ "MBEDTLS_X509_CRT_PARSE_C and/or MBEDTLS_RSA_C and/or "
+ "MBEDTLS_PEM_PARSE_C not defined.\n");
+ mbedtls_exit(0);
+}
+#else
+
+#include <string.h>
+
+#include "mbedtls/net_sockets.h"
+#include "mbedtls/debug.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/error.h"
+#include "mbedtls/timing.h"
+#include "test/certs.h"
+
+/* Uncomment out the following line to default to IPv4 and disable IPv6 */
+//#define FORCE_IPV4
+
+#define SERVER_PORT "4433"
+#define SERVER_NAME "localhost"
+
+#ifdef FORCE_IPV4
+#define SERVER_ADDR "127.0.0.1" /* Forces IPv4 */
+#else
+#define SERVER_ADDR "::1"
+#endif
+
+#define MESSAGE "Echo this"
+
+#define READ_TIMEOUT_MS 1000
+#define MAX_RETRY 5
+
+#define DEBUG_LEVEL 0
+
+
+static void my_debug(void *ctx, int level,
+ const char *file, int line,
+ const char *str)
+{
+ ((void) level);
+
+ mbedtls_fprintf((FILE *) ctx, "%s:%04d: %s", file, line, str);
+ fflush((FILE *) ctx);
+}
+
+int main(int argc, char *argv[])
+{
+ int ret, len;
+ mbedtls_net_context server_fd;
+ uint32_t flags;
+ unsigned char buf[1024];
+ const char *pers = "dtls_client";
+ int retry_left = MAX_RETRY;
+
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_ssl_context ssl;
+ mbedtls_ssl_config conf;
+ mbedtls_x509_crt cacert;
+ mbedtls_timing_delay_context timer;
+
+ ((void) argc);
+ ((void) argv);
+
+#if defined(MBEDTLS_DEBUG_C)
+ mbedtls_debug_set_threshold(DEBUG_LEVEL);
+#endif
+
+ /*
+ * 0. Initialize the RNG and the session data
+ */
+ mbedtls_net_init(&server_fd);
+ mbedtls_ssl_init(&ssl);
+ mbedtls_ssl_config_init(&conf);
+ mbedtls_x509_crt_init(&cacert);
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+ mbedtls_entropy_init(&entropy);
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ psa_status_t status = psa_crypto_init();
+ if (status != PSA_SUCCESS) {
+ mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
+ (int) status);
+ ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
+ goto exit;
+ }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ mbedtls_printf("\n . Seeding the random number generator...");
+ fflush(stdout);
+
+ if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
+ (const unsigned char *) pers,
+ strlen(pers))) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 0. Load certificates
+ */
+ mbedtls_printf(" . Loading the CA root certificate ...");
+ fflush(stdout);
+
+ ret = mbedtls_x509_crt_parse(&cacert, (const unsigned char *) mbedtls_test_cas_pem,
+ mbedtls_test_cas_pem_len);
+ if (ret < 0) {
+ mbedtls_printf(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok (%d skipped)\n", ret);
+
+ /*
+ * 1. Start the connection
+ */
+ mbedtls_printf(" . Connecting to udp/%s/%s...", SERVER_NAME, SERVER_PORT);
+ fflush(stdout);
+
+ if ((ret = mbedtls_net_connect(&server_fd, SERVER_ADDR,
+ SERVER_PORT, MBEDTLS_NET_PROTO_UDP)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_net_connect returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 2. Setup stuff
+ */
+ mbedtls_printf(" . Setting up the DTLS structure...");
+ fflush(stdout);
+
+ if ((ret = mbedtls_ssl_config_defaults(&conf,
+ MBEDTLS_SSL_IS_CLIENT,
+ MBEDTLS_SSL_TRANSPORT_DATAGRAM,
+ MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret);
+ goto exit;
+ }
+
+ /* OPTIONAL is usually a bad choice for security, but makes interop easier
+ * in this simplified example, in which the ca chain is hardcoded.
+ * Production code should set a proper ca chain and use REQUIRED. */
+ mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
+ mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
+ mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
+ mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
+ mbedtls_ssl_conf_read_timeout(&conf, READ_TIMEOUT_MS);
+
+ if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_setup returned %d\n\n", ret);
+ goto exit;
+ }
+
+ if ((ret = mbedtls_ssl_set_hostname(&ssl, SERVER_NAME)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_ssl_set_bio(&ssl, &server_fd,
+ mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout);
+
+ mbedtls_ssl_set_timer_cb(&ssl, &timer, mbedtls_timing_set_delay,
+ mbedtls_timing_get_delay);
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 4. Handshake
+ */
+ mbedtls_printf(" . Performing the DTLS handshake...");
+ fflush(stdout);
+
+ do {
+ ret = mbedtls_ssl_handshake(&ssl);
+ } while (ret == MBEDTLS_ERR_SSL_WANT_READ ||
+ ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 5. Verify the server certificate
+ */
+ mbedtls_printf(" . Verifying peer X.509 certificate...");
+
+ /* In real life, we would have used MBEDTLS_SSL_VERIFY_REQUIRED so that the
+ * handshake would not succeed if the peer's cert is bad. Even if we used
+ * MBEDTLS_SSL_VERIFY_OPTIONAL, we would bail out here if ret != 0 */
+ if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) {
+#if !defined(MBEDTLS_X509_REMOVE_INFO)
+ char vrfy_buf[512];
+#endif
+
+ mbedtls_printf(" failed\n");
+
+#if !defined(MBEDTLS_X509_REMOVE_INFO)
+ mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags);
+
+ mbedtls_printf("%s\n", vrfy_buf);
+#endif
+ } else {
+ mbedtls_printf(" ok\n");
+ }
+
+ /*
+ * 6. Write the echo request
+ */
+send_request:
+ mbedtls_printf(" > Write to server:");
+ fflush(stdout);
+
+ len = sizeof(MESSAGE) - 1;
+
+ do {
+ ret = mbedtls_ssl_write(&ssl, (unsigned char *) MESSAGE, len);
+ } while (ret == MBEDTLS_ERR_SSL_WANT_READ ||
+ ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+
+ if (ret < 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_write returned %d\n\n", ret);
+ goto exit;
+ }
+
+ len = ret;
+ mbedtls_printf(" %d bytes written\n\n%s\n\n", len, MESSAGE);
+
+ /*
+ * 7. Read the echo response
+ */
+ mbedtls_printf(" < Read from server:");
+ fflush(stdout);
+
+ len = sizeof(buf) - 1;
+ memset(buf, 0, sizeof(buf));
+
+ do {
+ ret = mbedtls_ssl_read(&ssl, buf, len);
+ } while (ret == MBEDTLS_ERR_SSL_WANT_READ ||
+ ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+
+ if (ret <= 0) {
+ switch (ret) {
+ case MBEDTLS_ERR_SSL_TIMEOUT:
+ mbedtls_printf(" timeout\n\n");
+ if (retry_left-- > 0) {
+ goto send_request;
+ }
+ goto exit;
+
+ case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+ mbedtls_printf(" connection was closed gracefully\n");
+ goto close_notify;
+
+ default:
+ mbedtls_printf(" mbedtls_ssl_read returned -0x%x\n\n", (unsigned int) -ret);
+ goto exit;
+ }
+ }
+
+ len = ret;
+ mbedtls_printf(" %d bytes read\n\n%s\n\n", len, buf);
+
+ /*
+ * 8. Done, cleanly close the connection
+ */
+close_notify:
+ mbedtls_printf(" . Closing the connection...");
+
+ /* No error checking, the connection might be closed already */
+ do {
+ ret = mbedtls_ssl_close_notify(&ssl);
+ } while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+ ret = 0;
+
+ mbedtls_printf(" done\n");
+
+ /*
+ * 9. Final clean-ups and exit
+ */
+exit:
+
+#ifdef MBEDTLS_ERROR_C
+ if (ret != 0) {
+ char error_buf[100];
+ mbedtls_strerror(ret, error_buf, 100);
+ mbedtls_printf("Last error was: %d - %s\n\n", ret, error_buf);
+ }
+#endif
+
+ mbedtls_net_free(&server_fd);
+ mbedtls_x509_crt_free(&cacert);
+ mbedtls_ssl_free(&ssl);
+ mbedtls_ssl_config_free(&conf);
+ mbedtls_ctr_drbg_free(&ctr_drbg);
+ mbedtls_entropy_free(&entropy);
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ mbedtls_psa_crypto_free();
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ /* Shell can not handle large exit numbers -> 1 for errors */
+ if (ret < 0) {
+ ret = 1;
+ }
+
+ mbedtls_exit(ret);
+}
+#endif /* MBEDTLS_SSL_CLI_C && MBEDTLS_SSL_PROTO_DTLS && MBEDTLS_NET_C &&
+ MBEDTLS_TIMING_C && MBEDTLS_ENTROPY_C && MBEDTLS_CTR_DRBG_C &&
+ MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_RSA_C && MBEDTLS_PEM_PARSE_C */
diff --git a/programs/ssl/dtls_server.c b/programs/ssl/dtls_server.c
new file mode 100644
index 00000000000..732625e7fbc
--- /dev/null
+++ b/programs/ssl/dtls_server.c
@@ -0,0 +1,408 @@
+/*
+ * Simple DTLS server demonstration program
+ *
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "mbedtls/build_info.h"
+
+#include "mbedtls/platform.h"
+
+/* Uncomment out the following line to default to IPv4 and disable IPv6 */
+//#define FORCE_IPV4
+
+#ifdef FORCE_IPV4
+#define BIND_IP "0.0.0.0" /* Forces IPv4 */
+#else
+#define BIND_IP "::"
+#endif
+
+#if !defined(MBEDTLS_SSL_SRV_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) || \
+ !defined(MBEDTLS_SSL_COOKIE_C) || !defined(MBEDTLS_NET_C) || \
+ !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_CTR_DRBG_C) || \
+ !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_RSA_C) || \
+ !defined(MBEDTLS_PEM_PARSE_C) || !defined(MBEDTLS_TIMING_C)
+
+int main(void)
+{
+ printf("MBEDTLS_SSL_SRV_C and/or MBEDTLS_SSL_PROTO_DTLS and/or "
+ "MBEDTLS_SSL_COOKIE_C and/or MBEDTLS_NET_C and/or "
+ "MBEDTLS_ENTROPY_C and/or MBEDTLS_CTR_DRBG_C and/or "
+ "MBEDTLS_X509_CRT_PARSE_C and/or MBEDTLS_RSA_C and/or "
+ "MBEDTLS_PEM_PARSE_C and/or MBEDTLS_TIMING_C not defined.\n");
+ mbedtls_exit(0);
+}
+#else
+
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/x509.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/ssl_cookie.h"
+#include "mbedtls/net_sockets.h"
+#include "mbedtls/error.h"
+#include "mbedtls/debug.h"
+#include "mbedtls/timing.h"
+
+#include "test/certs.h"
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+#include "mbedtls/ssl_cache.h"
+#endif
+
+#define READ_TIMEOUT_MS 10000 /* 10 seconds */
+#define DEBUG_LEVEL 0
+
+
+static void my_debug(void *ctx, int level,
+ const char *file, int line,
+ const char *str)
+{
+ ((void) level);
+
+ mbedtls_fprintf((FILE *) ctx, "%s:%04d: %s", file, line, str);
+ fflush((FILE *) ctx);
+}
+
+int main(void)
+{
+ int ret, len;
+ mbedtls_net_context listen_fd, client_fd;
+ unsigned char buf[1024];
+ const char *pers = "dtls_server";
+ unsigned char client_ip[16] = { 0 };
+ size_t cliip_len;
+ mbedtls_ssl_cookie_ctx cookie_ctx;
+
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_ssl_context ssl;
+ mbedtls_ssl_config conf;
+ mbedtls_x509_crt srvcert;
+ mbedtls_pk_context pkey;
+ mbedtls_timing_delay_context timer;
+#if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_cache_context cache;
+#endif
+
+ mbedtls_net_init(&listen_fd);
+ mbedtls_net_init(&client_fd);
+ mbedtls_ssl_init(&ssl);
+ mbedtls_ssl_config_init(&conf);
+ mbedtls_ssl_cookie_init(&cookie_ctx);
+#if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_cache_init(&cache);
+#endif
+ mbedtls_x509_crt_init(&srvcert);
+ mbedtls_pk_init(&pkey);
+ mbedtls_entropy_init(&entropy);
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ psa_status_t status = psa_crypto_init();
+ if (status != PSA_SUCCESS) {
+ mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
+ (int) status);
+ ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
+ goto exit;
+ }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+#if defined(MBEDTLS_DEBUG_C)
+ mbedtls_debug_set_threshold(DEBUG_LEVEL);
+#endif
+
+ /*
+ * 1. Seed the RNG
+ */
+ printf(" . Seeding the random number generator...");
+ fflush(stdout);
+
+ if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
+ (const unsigned char *) pers,
+ strlen(pers))) != 0) {
+ printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret);
+ goto exit;
+ }
+
+ printf(" ok\n");
+
+ /*
+ * 2. Load the certificates and private RSA key
+ */
+ printf("\n . Loading the server cert. and key...");
+ fflush(stdout);
+
+ /*
+ * This demonstration program uses embedded test certificates.
+ * Instead, you may want to use mbedtls_x509_crt_parse_file() to read the
+ * server and CA certificates, as well as mbedtls_pk_parse_keyfile().
+ */
+ ret = mbedtls_x509_crt_parse(&srvcert, (const unsigned char *) mbedtls_test_srv_crt,
+ mbedtls_test_srv_crt_len);
+ if (ret != 0) {
+ printf(" failed\n ! mbedtls_x509_crt_parse returned %d\n\n", ret);
+ goto exit;
+ }
+
+ ret = mbedtls_x509_crt_parse(&srvcert, (const unsigned char *) mbedtls_test_cas_pem,
+ mbedtls_test_cas_pem_len);
+ if (ret != 0) {
+ printf(" failed\n ! mbedtls_x509_crt_parse returned %d\n\n", ret);
+ goto exit;
+ }
+
+ ret = mbedtls_pk_parse_key(&pkey,
+ (const unsigned char *) mbedtls_test_srv_key,
+ mbedtls_test_srv_key_len,
+ NULL,
+ 0,
+ mbedtls_ctr_drbg_random,
+ &ctr_drbg);
+ if (ret != 0) {
+ printf(" failed\n ! mbedtls_pk_parse_key returned %d\n\n", ret);
+ goto exit;
+ }
+
+ printf(" ok\n");
+
+ /*
+ * 3. Setup the "listening" UDP socket
+ */
+ printf(" . Bind on udp/*/4433 ...");
+ fflush(stdout);
+
+ if ((ret = mbedtls_net_bind(&listen_fd, BIND_IP, "4433", MBEDTLS_NET_PROTO_UDP)) != 0) {
+ printf(" failed\n ! mbedtls_net_bind returned %d\n\n", ret);
+ goto exit;
+ }
+
+ printf(" ok\n");
+
+ /*
+ * 4. Setup stuff
+ */
+ printf(" . Setting up the DTLS data...");
+ fflush(stdout);
+
+ if ((ret = mbedtls_ssl_config_defaults(&conf,
+ MBEDTLS_SSL_IS_SERVER,
+ MBEDTLS_SSL_TRANSPORT_DATAGRAM,
+ MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
+ mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
+ mbedtls_ssl_conf_read_timeout(&conf, READ_TIMEOUT_MS);
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_conf_session_cache(&conf, &cache,
+ mbedtls_ssl_cache_get,
+ mbedtls_ssl_cache_set);
+#endif
+
+ mbedtls_ssl_conf_ca_chain(&conf, srvcert.next, NULL);
+ if ((ret = mbedtls_ssl_conf_own_cert(&conf, &srvcert, &pkey)) != 0) {
+ printf(" failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret);
+ goto exit;
+ }
+
+ if ((ret = mbedtls_ssl_cookie_setup(&cookie_ctx,
+ mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) {
+ printf(" failed\n ! mbedtls_ssl_cookie_setup returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_ssl_conf_dtls_cookies(&conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check,
+ &cookie_ctx);
+
+ if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
+ printf(" failed\n ! mbedtls_ssl_setup returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_ssl_set_timer_cb(&ssl, &timer, mbedtls_timing_set_delay,
+ mbedtls_timing_get_delay);
+
+ printf(" ok\n");
+
+reset:
+#ifdef MBEDTLS_ERROR_C
+ if (ret != 0) {
+ char error_buf[100];
+ mbedtls_strerror(ret, error_buf, 100);
+ printf("Last error was: %d - %s\n\n", ret, error_buf);
+ }
+#endif
+
+ mbedtls_net_free(&client_fd);
+
+ mbedtls_ssl_session_reset(&ssl);
+
+ /*
+ * 5. Wait until a client connects
+ */
+ printf(" . Waiting for a remote connection ...");
+ fflush(stdout);
+
+ if ((ret = mbedtls_net_accept(&listen_fd, &client_fd,
+ client_ip, sizeof(client_ip), &cliip_len)) != 0) {
+ printf(" failed\n ! mbedtls_net_accept returned %d\n\n", ret);
+ goto exit;
+ }
+
+ /* For HelloVerifyRequest cookies */
+ if ((ret = mbedtls_ssl_set_client_transport_id(&ssl,
+ client_ip, cliip_len)) != 0) {
+ printf(" failed\n ! "
+ "mbedtls_ssl_set_client_transport_id() returned -0x%x\n\n", (unsigned int) -ret);
+ goto exit;
+ }
+
+ mbedtls_ssl_set_bio(&ssl, &client_fd,
+ mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout);
+
+ printf(" ok\n");
+
+ /*
+ * 6. Handshake
+ */
+ printf(" . Performing the DTLS handshake...");
+ fflush(stdout);
+
+ do {
+ ret = mbedtls_ssl_handshake(&ssl);
+ } while (ret == MBEDTLS_ERR_SSL_WANT_READ ||
+ ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+
+ if (ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED) {
+ printf(" hello verification requested\n");
+ ret = 0;
+ goto reset;
+ } else if (ret != 0) {
+ printf(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", (unsigned int) -ret);
+ goto reset;
+ }
+
+ printf(" ok\n");
+
+ /*
+ * 7. Read the echo Request
+ */
+ printf(" < Read from client:");
+ fflush(stdout);
+
+ len = sizeof(buf) - 1;
+ memset(buf, 0, sizeof(buf));
+
+ do {
+ ret = mbedtls_ssl_read(&ssl, buf, len);
+ } while (ret == MBEDTLS_ERR_SSL_WANT_READ ||
+ ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+
+ if (ret <= 0) {
+ switch (ret) {
+ case MBEDTLS_ERR_SSL_TIMEOUT:
+ printf(" timeout\n\n");
+ goto reset;
+
+ case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+ printf(" connection was closed gracefully\n");
+ goto close_notify;
+
+ default:
+ printf(" mbedtls_ssl_read returned -0x%x\n\n", (unsigned int) -ret);
+ goto reset;
+ }
+ }
+
+ len = ret;
+ printf(" %d bytes read\n\n%s\n\n", len, buf);
+
+ /*
+ * 8. Write the 200 Response
+ */
+ printf(" > Write to client:");
+ fflush(stdout);
+
+ do {
+ ret = mbedtls_ssl_write(&ssl, buf, len);
+ } while (ret == MBEDTLS_ERR_SSL_WANT_READ ||
+ ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+
+ if (ret < 0) {
+ printf(" failed\n ! mbedtls_ssl_write returned %d\n\n", ret);
+ goto exit;
+ }
+
+ len = ret;
+ printf(" %d bytes written\n\n%s\n\n", len, buf);
+
+ /*
+ * 9. Done, cleanly close the connection
+ */
+close_notify:
+ printf(" . Closing the connection...");
+
+ /* No error checking, the connection might be closed already */
+ do {
+ ret = mbedtls_ssl_close_notify(&ssl);
+ } while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+ ret = 0;
+
+ printf(" done\n");
+
+ goto reset;
+
+ /*
+ * Final clean-ups and exit
+ */
+exit:
+
+#ifdef MBEDTLS_ERROR_C
+ if (ret != 0) {
+ char error_buf[100];
+ mbedtls_strerror(ret, error_buf, 100);
+ printf("Last error was: %d - %s\n\n", ret, error_buf);
+ }
+#endif
+
+ mbedtls_net_free(&client_fd);
+ mbedtls_net_free(&listen_fd);
+
+ mbedtls_x509_crt_free(&srvcert);
+ mbedtls_pk_free(&pkey);
+ mbedtls_ssl_free(&ssl);
+ mbedtls_ssl_config_free(&conf);
+ mbedtls_ssl_cookie_free(&cookie_ctx);
+#if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_cache_free(&cache);
+#endif
+ mbedtls_ctr_drbg_free(&ctr_drbg);
+ mbedtls_entropy_free(&entropy);
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ mbedtls_psa_crypto_free();
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ /* Shell can not handle large exit numbers -> 1 for errors */
+ if (ret < 0) {
+ ret = 1;
+ }
+
+ mbedtls_exit(ret);
+}
+#endif /* MBEDTLS_SSL_SRV_C && MBEDTLS_SSL_PROTO_DTLS &&
+ MBEDTLS_SSL_COOKIE_C && MBEDTLS_NET_C && MBEDTLS_ENTROPY_C &&
+ MBEDTLS_CTR_DRBG_C && MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_RSA_C
+ && MBEDTLS_PEM_PARSE_C && MBEDTLS_TIMING_C */
diff --git a/programs/ssl/mini_client.c b/programs/ssl/mini_client.c
new file mode 100644
index 00000000000..6bef2085c54
--- /dev/null
+++ b/programs/ssl/mini_client.c
@@ -0,0 +1,274 @@
+/*
+ * Minimal SSL client, used for memory measurements.
+ * (meant to be used with config-suite-b.h or config-ccm-psk-tls1_2.h)
+ *
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "mbedtls/build_info.h"
+
+#include "mbedtls/platform.h"
+
+/*
+ * We're creating and connecting the socket "manually" rather than using the
+ * NET module, in order to avoid the overhead of getaddrinfo() which tends to
+ * dominate memory usage in small configurations. For the sake of simplicity,
+ * only a Unix version is implemented.
+ *
+ * Warning: we are breaking some of the abstractions from the NET layer here.
+ * This is not a good example for general use. This programs has the specific
+ * goal of minimizing use of the libc functions on full-blown OSes.
+ */
+#if defined(unix) || defined(__unix__) || defined(__unix) || defined(__APPLE__)
+#define UNIX
+#endif
+
+#if !defined(MBEDTLS_CTR_DRBG_C) || !defined(MBEDTLS_ENTROPY_C) || \
+ !defined(MBEDTLS_NET_C) || !defined(MBEDTLS_SSL_CLI_C) || \
+ !defined(UNIX)
+
+int main(void)
+{
+ mbedtls_printf("MBEDTLS_CTR_DRBG_C and/or MBEDTLS_ENTROPY_C and/or "
+ "MBEDTLS_NET_C and/or MBEDTLS_SSL_CLI_C and/or UNIX "
+ "not defined.\n");
+ mbedtls_exit(0);
+}
+#else
+
+#include <string.h>
+
+#include "mbedtls/net_sockets.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/*
+ * Hardcoded values for server host and port
+ */
+#define PORT_BE 0x1151 /* 4433 */
+#define PORT_LE 0x5111
+#define ADDR_BE 0x7f000001 /* 127.0.0.1 */
+#define ADDR_LE 0x0100007f
+#define HOSTNAME "localhost" /* for cert verification if enabled */
+
+#define GET_REQUEST "GET / HTTP/1.0\r\n\r\n"
+
+const char *pers = "mini_client";
+
+#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED)
+const unsigned char psk[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
+};
+const char psk_id[] = "Client_identity";
+#endif
+
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+/* This is tests/data_files/test-ca2.crt, a CA using EC secp384r1 */
+const unsigned char ca_cert[] = {
+ 0x30, 0x82, 0x02, 0x52, 0x30, 0x82, 0x01, 0xd7, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x09, 0x00, 0xc1, 0x43, 0xe2, 0x7e, 0x62, 0x43, 0xcc, 0xe8,
+ 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
+ 0x30, 0x3e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x4e, 0x4c, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a,
+ 0x13, 0x08, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, 0x53, 0x4c, 0x31, 0x1c,
+ 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x13, 0x50, 0x6f, 0x6c,
+ 0x61, 0x72, 0x73, 0x73, 0x6c, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45,
+ 0x43, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x39,
+ 0x32, 0x34, 0x31, 0x35, 0x34, 0x39, 0x34, 0x38, 0x5a, 0x17, 0x0d, 0x32,
+ 0x33, 0x30, 0x39, 0x32, 0x32, 0x31, 0x35, 0x34, 0x39, 0x34, 0x38, 0x5a,
+ 0x30, 0x3e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x4e, 0x4c, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a,
+ 0x13, 0x08, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, 0x53, 0x4c, 0x31, 0x1c,
+ 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x13, 0x50, 0x6f, 0x6c,
+ 0x61, 0x72, 0x73, 0x73, 0x6c, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45,
+ 0x43, 0x20, 0x43, 0x41, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86,
+ 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22,
+ 0x03, 0x62, 0x00, 0x04, 0xc3, 0xda, 0x2b, 0x34, 0x41, 0x37, 0x58, 0x2f,
+ 0x87, 0x56, 0xfe, 0xfc, 0x89, 0xba, 0x29, 0x43, 0x4b, 0x4e, 0xe0, 0x6e,
+ 0xc3, 0x0e, 0x57, 0x53, 0x33, 0x39, 0x58, 0xd4, 0x52, 0xb4, 0x91, 0x95,
+ 0x39, 0x0b, 0x23, 0xdf, 0x5f, 0x17, 0x24, 0x62, 0x48, 0xfc, 0x1a, 0x95,
+ 0x29, 0xce, 0x2c, 0x2d, 0x87, 0xc2, 0x88, 0x52, 0x80, 0xaf, 0xd6, 0x6a,
+ 0xab, 0x21, 0xdd, 0xb8, 0xd3, 0x1c, 0x6e, 0x58, 0xb8, 0xca, 0xe8, 0xb2,
+ 0x69, 0x8e, 0xf3, 0x41, 0xad, 0x29, 0xc3, 0xb4, 0x5f, 0x75, 0xa7, 0x47,
+ 0x6f, 0xd5, 0x19, 0x29, 0x55, 0x69, 0x9a, 0x53, 0x3b, 0x20, 0xb4, 0x66,
+ 0x16, 0x60, 0x33, 0x1e, 0xa3, 0x81, 0xa0, 0x30, 0x81, 0x9d, 0x30, 0x1d,
+ 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x9d, 0x6d, 0x20,
+ 0x24, 0x49, 0x01, 0x3f, 0x2b, 0xcb, 0x78, 0xb5, 0x19, 0xbc, 0x7e, 0x24,
+ 0xc9, 0xdb, 0xfb, 0x36, 0x7c, 0x30, 0x6e, 0x06, 0x03, 0x55, 0x1d, 0x23,
+ 0x04, 0x67, 0x30, 0x65, 0x80, 0x14, 0x9d, 0x6d, 0x20, 0x24, 0x49, 0x01,
+ 0x3f, 0x2b, 0xcb, 0x78, 0xb5, 0x19, 0xbc, 0x7e, 0x24, 0xc9, 0xdb, 0xfb,
+ 0x36, 0x7c, 0xa1, 0x42, 0xa4, 0x40, 0x30, 0x3e, 0x31, 0x0b, 0x30, 0x09,
+ 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x11, 0x30,
+ 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x08, 0x50, 0x6f, 0x6c, 0x61,
+ 0x72, 0x53, 0x53, 0x4c, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04,
+ 0x03, 0x13, 0x13, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x73, 0x73, 0x6c, 0x20,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x43, 0x20, 0x43, 0x41, 0x82, 0x09,
+ 0x00, 0xc1, 0x43, 0xe2, 0x7e, 0x62, 0x43, 0xcc, 0xe8, 0x30, 0x0c, 0x06,
+ 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+ 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03,
+ 0x69, 0x00, 0x30, 0x66, 0x02, 0x31, 0x00, 0xc3, 0xb4, 0x62, 0x73, 0x56,
+ 0x28, 0x95, 0x00, 0x7d, 0x78, 0x12, 0x26, 0xd2, 0x71, 0x7b, 0x19, 0xf8,
+ 0x8a, 0x98, 0x3e, 0x92, 0xfe, 0x33, 0x9e, 0xe4, 0x79, 0xd2, 0xfe, 0x7a,
+ 0xb7, 0x87, 0x74, 0x3c, 0x2b, 0xb8, 0xd7, 0x69, 0x94, 0x0b, 0xa3, 0x67,
+ 0x77, 0xb8, 0xb3, 0xbe, 0xd1, 0x36, 0x32, 0x02, 0x31, 0x00, 0xfd, 0x67,
+ 0x9c, 0x94, 0x23, 0x67, 0xc0, 0x56, 0xba, 0x4b, 0x33, 0x15, 0x00, 0xc6,
+ 0xe3, 0xcc, 0x31, 0x08, 0x2c, 0x9c, 0x8b, 0xda, 0xa9, 0x75, 0x23, 0x2f,
+ 0xb8, 0x28, 0xe7, 0xf2, 0x9c, 0x14, 0x3a, 0x40, 0x01, 0x5c, 0xaf, 0x0c,
+ 0xb2, 0xcf, 0x74, 0x7f, 0x30, 0x9f, 0x08, 0x43, 0xad, 0x20,
+};
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
+enum exit_codes {
+ exit_ok = 0,
+ ctr_drbg_seed_failed,
+ ssl_config_defaults_failed,
+ ssl_setup_failed,
+ hostname_failed,
+ socket_failed,
+ connect_failed,
+ x509_crt_parse_failed,
+ ssl_handshake_failed,
+ ssl_write_failed,
+};
+
+
+int main(void)
+{
+ int ret = exit_ok;
+ mbedtls_net_context server_fd;
+ struct sockaddr_in addr;
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+ mbedtls_x509_crt ca;
+#endif
+
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_ssl_context ssl;
+ mbedtls_ssl_config conf;
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+
+ /*
+ * 0. Initialize and setup stuff
+ */
+ mbedtls_net_init(&server_fd);
+ mbedtls_ssl_init(&ssl);
+ mbedtls_ssl_config_init(&conf);
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+ mbedtls_x509_crt_init(&ca);
+#endif
+ mbedtls_entropy_init(&entropy);
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ psa_status_t status = psa_crypto_init();
+ if (status != PSA_SUCCESS) {
+ ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
+ goto exit;
+ }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ if (mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
+ (const unsigned char *) pers, strlen(pers)) != 0) {
+ ret = ctr_drbg_seed_failed;
+ goto exit;
+ }
+
+ if (mbedtls_ssl_config_defaults(&conf,
+ MBEDTLS_SSL_IS_CLIENT,
+ MBEDTLS_SSL_TRANSPORT_STREAM,
+ MBEDTLS_SSL_PRESET_DEFAULT) != 0) {
+ ret = ssl_config_defaults_failed;
+ goto exit;
+ }
+
+ mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
+
+#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED)
+ mbedtls_ssl_conf_psk(&conf, psk, sizeof(psk),
+ (const unsigned char *) psk_id, sizeof(psk_id) - 1);
+#endif
+
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+ if (mbedtls_x509_crt_parse_der(&ca, ca_cert, sizeof(ca_cert)) != 0) {
+ ret = x509_crt_parse_failed;
+ goto exit;
+ }
+
+ mbedtls_ssl_conf_ca_chain(&conf, &ca, NULL);
+ mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
+#endif
+
+ if (mbedtls_ssl_setup(&ssl, &conf) != 0) {
+ ret = ssl_setup_failed;
+ goto exit;
+ }
+
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+ if (mbedtls_ssl_set_hostname(&ssl, HOSTNAME) != 0) {
+ ret = hostname_failed;
+ goto exit;
+ }
+#endif
+
+ /*
+ * 1. Start the connection
+ */
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+
+ ret = 1; /* for endianness detection */
+ addr.sin_port = *((char *) &ret) == ret ? PORT_LE : PORT_BE;
+ addr.sin_addr.s_addr = *((char *) &ret) == ret ? ADDR_LE : ADDR_BE;
+ ret = 0;
+
+ if ((server_fd.fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ ret = socket_failed;
+ goto exit;
+ }
+
+ if (connect(server_fd.fd,
+ (const struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ ret = connect_failed;
+ goto exit;
+ }
+
+ mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
+
+ if (mbedtls_ssl_handshake(&ssl) != 0) {
+ ret = ssl_handshake_failed;
+ goto exit;
+ }
+
+ /*
+ * 2. Write the GET request and close the connection
+ */
+ if (mbedtls_ssl_write(&ssl, (const unsigned char *) GET_REQUEST,
+ sizeof(GET_REQUEST) - 1) <= 0) {
+ ret = ssl_write_failed;
+ goto exit;
+ }
+
+ mbedtls_ssl_close_notify(&ssl);
+
+exit:
+ mbedtls_net_free(&server_fd);
+ mbedtls_ssl_free(&ssl);
+ mbedtls_ssl_config_free(&conf);
+ mbedtls_ctr_drbg_free(&ctr_drbg);
+ mbedtls_entropy_free(&entropy);
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+ mbedtls_x509_crt_free(&ca);
+#endif
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ mbedtls_psa_crypto_free();
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ mbedtls_exit(ret);
+}
+#endif
diff --git a/programs/ssl/ssl_client1.c b/programs/ssl/ssl_client1.c
new file mode 100644
index 00000000000..ee734b1ed10
--- /dev/null
+++ b/programs/ssl/ssl_client1.c
@@ -0,0 +1,288 @@
+/*
+ * SSL client demonstration program
+ *
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "mbedtls/build_info.h"
+
+#include "mbedtls/platform.h"
+
+#if !defined(MBEDTLS_BIGNUM_C) || !defined(MBEDTLS_ENTROPY_C) || \
+ !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_CLI_C) || \
+ !defined(MBEDTLS_NET_C) || !defined(MBEDTLS_RSA_C) || \
+ !defined(MBEDTLS_PEM_PARSE_C) || !defined(MBEDTLS_CTR_DRBG_C) || \
+ !defined(MBEDTLS_X509_CRT_PARSE_C)
+int main(void)
+{
+ mbedtls_printf("MBEDTLS_BIGNUM_C and/or MBEDTLS_ENTROPY_C and/or "
+ "MBEDTLS_SSL_TLS_C and/or MBEDTLS_SSL_CLI_C and/or "
+ "MBEDTLS_NET_C and/or MBEDTLS_RSA_C and/or "
+ "MBEDTLS_CTR_DRBG_C and/or MBEDTLS_X509_CRT_PARSE_C "
+ "not defined.\n");
+ mbedtls_exit(0);
+}
+#else
+
+#include "mbedtls/net_sockets.h"
+#include "mbedtls/debug.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/error.h"
+#include "test/certs.h"
+
+#include <string.h>
+
+#define SERVER_PORT "4433"
+#define SERVER_NAME "localhost"
+#define GET_REQUEST "GET / HTTP/1.0\r\n\r\n"
+
+#define DEBUG_LEVEL 1
+
+
+static void my_debug(void *ctx, int level,
+ const char *file, int line,
+ const char *str)
+{
+ ((void) level);
+
+ mbedtls_fprintf((FILE *) ctx, "%s:%04d: %s", file, line, str);
+ fflush((FILE *) ctx);
+}
+
+int main(void)
+{
+ int ret = 1, len;
+ int exit_code = MBEDTLS_EXIT_FAILURE;
+ mbedtls_net_context server_fd;
+ uint32_t flags;
+ unsigned char buf[1024];
+ const char *pers = "ssl_client1";
+
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_ssl_context ssl;
+ mbedtls_ssl_config conf;
+ mbedtls_x509_crt cacert;
+
+#if defined(MBEDTLS_DEBUG_C)
+ mbedtls_debug_set_threshold(DEBUG_LEVEL);
+#endif
+
+ /*
+ * 0. Initialize the RNG and the session data
+ */
+ mbedtls_net_init(&server_fd);
+ mbedtls_ssl_init(&ssl);
+ mbedtls_ssl_config_init(&conf);
+ mbedtls_x509_crt_init(&cacert);
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+ mbedtls_entropy_init(&entropy);
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ psa_status_t status = psa_crypto_init();
+ if (status != PSA_SUCCESS) {
+ mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
+ (int) status);
+ goto exit;
+ }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ mbedtls_printf("\n . Seeding the random number generator...");
+ fflush(stdout);
+
+
+ if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
+ (const unsigned char *) pers,
+ strlen(pers))) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 0. Initialize certificates
+ */
+ mbedtls_printf(" . Loading the CA root certificate ...");
+ fflush(stdout);
+
+ ret = mbedtls_x509_crt_parse(&cacert, (const unsigned char *) mbedtls_test_cas_pem,
+ mbedtls_test_cas_pem_len);
+ if (ret < 0) {
+ mbedtls_printf(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok (%d skipped)\n", ret);
+
+ /*
+ * 1. Start the connection
+ */
+ mbedtls_printf(" . Connecting to tcp/%s/%s...", SERVER_NAME, SERVER_PORT);
+ fflush(stdout);
+
+ if ((ret = mbedtls_net_connect(&server_fd, SERVER_NAME,
+ SERVER_PORT, MBEDTLS_NET_PROTO_TCP)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_net_connect returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 2. Setup stuff
+ */
+ mbedtls_printf(" . Setting up the SSL/TLS structure...");
+ fflush(stdout);
+
+ if ((ret = mbedtls_ssl_config_defaults(&conf,
+ MBEDTLS_SSL_IS_CLIENT,
+ MBEDTLS_SSL_TRANSPORT_STREAM,
+ MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /* OPTIONAL is not optimal for security,
+ * but makes interop easier in this simplified example */
+ mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
+ mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
+ mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
+ mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
+
+ if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_setup returned %d\n\n", ret);
+ goto exit;
+ }
+
+ if ((ret = mbedtls_ssl_set_hostname(&ssl, SERVER_NAME)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
+
+ /*
+ * 4. Handshake
+ */
+ mbedtls_printf(" . Performing the SSL/TLS handshake...");
+ fflush(stdout);
+
+ while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 5. Verify the server certificate
+ */
+ mbedtls_printf(" . Verifying peer X.509 certificate...");
+
+ /* In real life, we probably want to bail out when ret != 0 */
+ if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) {
+#if !defined(MBEDTLS_X509_REMOVE_INFO)
+ char vrfy_buf[512];
+#endif
+
+ mbedtls_printf(" failed\n");
+
+#if !defined(MBEDTLS_X509_REMOVE_INFO)
+ mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags);
+
+ mbedtls_printf("%s\n", vrfy_buf);
+#endif
+ } else {
+ mbedtls_printf(" ok\n");
+ }
+
+ /*
+ * 3. Write the GET request
+ */
+ mbedtls_printf(" > Write to server:");
+ fflush(stdout);
+
+ len = sprintf((char *) buf, GET_REQUEST);
+
+ while ((ret = mbedtls_ssl_write(&ssl, buf, len)) <= 0) {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_write returned %d\n\n", ret);
+ goto exit;
+ }
+ }
+
+ len = ret;
+ mbedtls_printf(" %d bytes written\n\n%s", len, (char *) buf);
+
+ /*
+ * 7. Read the HTTP response
+ */
+ mbedtls_printf(" < Read from server:");
+ fflush(stdout);
+
+ do {
+ len = sizeof(buf) - 1;
+ memset(buf, 0, sizeof(buf));
+ ret = mbedtls_ssl_read(&ssl, buf, len);
+
+ if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+ continue;
+ }
+
+ if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
+ break;
+ }
+
+ if (ret < 0) {
+ mbedtls_printf("failed\n ! mbedtls_ssl_read returned %d\n\n", ret);
+ break;
+ }
+
+ if (ret == 0) {
+ mbedtls_printf("\n\nEOF\n\n");
+ break;
+ }
+
+ len = ret;
+ mbedtls_printf(" %d bytes read\n\n%s", len, (char *) buf);
+ } while (1);
+
+ mbedtls_ssl_close_notify(&ssl);
+
+ exit_code = MBEDTLS_EXIT_SUCCESS;
+
+exit:
+
+#ifdef MBEDTLS_ERROR_C
+ if (exit_code != MBEDTLS_EXIT_SUCCESS) {
+ char error_buf[100];
+ mbedtls_strerror(ret, error_buf, 100);
+ mbedtls_printf("Last error was: %d - %s\n\n", ret, error_buf);
+ }
+#endif
+
+ mbedtls_net_free(&server_fd);
+ mbedtls_x509_crt_free(&cacert);
+ mbedtls_ssl_free(&ssl);
+ mbedtls_ssl_config_free(&conf);
+ mbedtls_ctr_drbg_free(&ctr_drbg);
+ mbedtls_entropy_free(&entropy);
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ mbedtls_psa_crypto_free();
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ mbedtls_exit(exit_code);
+}
+#endif /* MBEDTLS_BIGNUM_C && MBEDTLS_ENTROPY_C && MBEDTLS_SSL_TLS_C &&
+ MBEDTLS_SSL_CLI_C && MBEDTLS_NET_C && MBEDTLS_RSA_C &&
+ MBEDTLS_PEM_PARSE_C && MBEDTLS_CTR_DRBG_C && MBEDTLS_X509_CRT_PARSE_C */
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
new file mode 100644
index 00000000000..43133d901c7
--- /dev/null
+++ b/programs/ssl/ssl_client2.c
@@ -0,0 +1,3230 @@
+/*
+ * SSL client with certificate authentication
+ *
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#define MBEDTLS_ALLOW_PRIVATE_ACCESS
+
+#include "ssl_test_lib.h"
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)
+#include "test/psa_crypto_helpers.h"
+#endif /* MBEDTLS_USE_PSA_CRYPTO || MBEDTLS_SSL_PROTO_TLS1_3 */
+
+#if defined(MBEDTLS_SSL_TEST_IMPOSSIBLE)
+int main(void)
+{
+ mbedtls_printf(MBEDTLS_SSL_TEST_IMPOSSIBLE);
+ mbedtls_exit(0);
+}
+#elif !defined(MBEDTLS_SSL_CLI_C)
+int main(void)
+{
+ mbedtls_printf("MBEDTLS_SSL_CLI_C not defined.\n");
+ mbedtls_exit(0);
+}
+#else /* !MBEDTLS_SSL_TEST_IMPOSSIBLE && MBEDTLS_SSL_CLI_C */
+
+/* Size of memory to be allocated for the heap, when using the library's memory
+ * management and MBEDTLS_MEMORY_BUFFER_ALLOC_C is enabled. */
+#define MEMORY_HEAP_SIZE 120000
+
+#define MAX_REQUEST_SIZE 20000
+#define MAX_REQUEST_SIZE_STR "20000"
+
+#define DFL_SERVER_NAME "localhost"
+#define DFL_SERVER_ADDR NULL
+#define DFL_SERVER_PORT "4433"
+#define DFL_REQUEST_PAGE "/"
+#define DFL_REQUEST_SIZE -1
+#define DFL_DEBUG_LEVEL 0
+#define DFL_CONTEXT_CRT_CB 0
+#define DFL_NBIO 0
+#define DFL_EVENT 0
+#define DFL_READ_TIMEOUT 0
+#define DFL_MAX_RESEND 0
+#define DFL_CA_FILE ""
+#define DFL_CA_PATH ""
+#define DFL_CRT_FILE ""
+#define DFL_KEY_FILE ""
+#define DFL_KEY_OPAQUE 0
+#define DFL_KEY_PWD ""
+#define DFL_PSK ""
+#define DFL_EARLY_DATA -1
+#define DFL_PSK_OPAQUE 0
+#define DFL_PSK_IDENTITY "Client_identity"
+#define DFL_ECJPAKE_PW NULL
+#define DFL_ECJPAKE_PW_OPAQUE 0
+#define DFL_EC_MAX_OPS -1
+#define DFL_FORCE_CIPHER 0
+#define DFL_TLS1_3_KEX_MODES MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_ALL
+#define DFL_RENEGOTIATION MBEDTLS_SSL_RENEGOTIATION_DISABLED
+#define DFL_ALLOW_LEGACY -2
+#define DFL_RENEGOTIATE 0
+#define DFL_EXCHANGES 1
+#define DFL_MIN_VERSION -1
+#define DFL_MAX_VERSION -1
+#define DFL_SHA1 -1
+#define DFL_AUTH_MODE -1
+#define DFL_MFL_CODE MBEDTLS_SSL_MAX_FRAG_LEN_NONE
+#define DFL_TRUNC_HMAC -1
+#define DFL_RECSPLIT -1
+#define DFL_DHMLEN -1
+#define DFL_RECONNECT 0
+#define DFL_RECO_SERVER_NAME NULL
+#define DFL_RECO_DELAY 0
+#define DFL_RECO_MODE 1
+#define DFL_CID_ENABLED 0
+#define DFL_CID_VALUE ""
+#define DFL_CID_ENABLED_RENEGO -1
+#define DFL_CID_VALUE_RENEGO NULL
+#define DFL_RECONNECT_HARD 0
+#define DFL_TICKETS MBEDTLS_SSL_SESSION_TICKETS_ENABLED
+#define DFL_ALPN_STRING NULL
+#define DFL_GROUPS NULL
+#define DFL_SIG_ALGS NULL
+#define DFL_TRANSPORT MBEDTLS_SSL_TRANSPORT_STREAM
+#define DFL_HS_TO_MIN 0
+#define DFL_HS_TO_MAX 0
+#define DFL_DTLS_MTU -1
+#define DFL_DGRAM_PACKING 1
+#define DFL_FALLBACK -1
+#define DFL_EXTENDED_MS -1
+#define DFL_ETM -1
+#define DFL_SERIALIZE 0
+#define DFL_CONTEXT_FILE ""
+#define DFL_EXTENDED_MS_ENFORCE -1
+#define DFL_CA_CALLBACK 0
+#define DFL_EAP_TLS 0
+#define DFL_REPRODUCIBLE 0
+#define DFL_NSS_KEYLOG 0
+#define DFL_NSS_KEYLOG_FILE NULL
+#define DFL_SKIP_CLOSE_NOTIFY 0
+#define DFL_QUERY_CONFIG_MODE 0
+#define DFL_USE_SRTP 0
+#define DFL_SRTP_FORCE_PROFILE 0
+#define DFL_SRTP_MKI ""
+#define DFL_KEY_OPAQUE_ALG "none"
+
+#define GET_REQUEST "GET %s HTTP/1.0\r\nExtra-header: "
+#define GET_REQUEST_END "\r\n\r\n"
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+#define USAGE_CONTEXT_CRT_CB \
+ " context_crt_cb=%%d This determines whether the CRT verification callback is bound\n" \
+ " to the SSL configuration of the SSL context.\n" \
+ " Possible values:\n" \
+ " - 0 (default): Use CRT callback bound to configuration\n" \
+ " - 1: Use CRT callback bound to SSL context\n"
+#else
+#define USAGE_CONTEXT_CRT_CB ""
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+#if defined(MBEDTLS_FS_IO)
+#define USAGE_IO \
+ " ca_file=%%s The single file containing the top-level CA(s) you fully trust\n" \
+ " default: \"\" (pre-loaded)\n" \
+ " use \"none\" to skip loading any top-level CAs.\n" \
+ " ca_path=%%s The path containing the top-level CA(s) you fully trust\n" \
+ " default: \"\" (pre-loaded) (overrides ca_file)\n" \
+ " use \"none\" to skip loading any top-level CAs.\n" \
+ " crt_file=%%s Your own cert and chain (in bottom to top order, top may be omitted)\n" \
+ " default: \"\" (pre-loaded)\n" \
+ " key_file=%%s default: \"\" (pre-loaded)\n" \
+ " key_pwd=%%s Password for key specified by key_file argument\n" \
+ " default: none\n"
+#else
+#define USAGE_IO \
+ " No file operations available (MBEDTLS_FS_IO not defined)\n"
+#endif /* MBEDTLS_FS_IO */
+#else /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+#define USAGE_IO ""
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+#if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+#define USAGE_KEY_OPAQUE \
+ " key_opaque=%%d Handle your private key as if it were opaque\n" \
+ " default: 0 (disabled)\n"
+#else
+#define USAGE_KEY_OPAQUE ""
+#endif
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+#define USAGE_CID \
+ " cid=%%d Disable (0) or enable (1) the use of the DTLS Connection ID extension.\n" \
+ " default: 0 (disabled)\n" \
+ " cid_renego=%%d Disable (0) or enable (1) the use of the DTLS Connection ID extension during renegotiation.\n" \
+ " default: same as 'cid' parameter\n" \
+ " cid_val=%%s The CID to use for incoming messages (in hex, without 0x).\n" \
+ " default: \"\"\n" \
+ " cid_val_renego=%%s The CID to use for incoming messages (in hex, without 0x) after renegotiation.\n" \
+ " default: same as 'cid_val' parameter\n"
+#else /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+#define USAGE_CID ""
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED)
+#define USAGE_PSK_RAW \
+ " psk=%%s default: \"\" (disabled)\n" \
+ " The PSK values are in hex, without 0x.\n" \
+ " psk_identity=%%s default: \"Client_identity\"\n"
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#define USAGE_PSK_SLOT \
+ " psk_opaque=%%d default: 0 (don't use opaque static PSK)\n" \
+ " Enable this to store the PSK configured through command line\n" \
+ " parameter `psk` in a PSA-based key slot.\n" \
+ " Note: Currently only supported in conjunction with\n" \
+ " the use of min_version to force TLS 1.2 and force_ciphersuite \n" \
+ " to force a particular PSK-only ciphersuite.\n" \
+ " Note: This is to test integration of PSA-based opaque PSKs with\n" \
+ " Mbed TLS only. Production systems are likely to configure Mbed TLS\n" \
+ " with prepopulated key slots instead of importing raw key material.\n"
+#else
+#define USAGE_PSK_SLOT ""
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+#define USAGE_PSK USAGE_PSK_RAW USAGE_PSK_SLOT
+#else
+#define USAGE_PSK ""
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED */
+
+#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
+#define USAGE_CA_CALLBACK \
+ " ca_callback=%%d default: 0 (disabled)\n" \
+ " Enable this to use the trusted certificate callback function\n"
+#else
+#define USAGE_CA_CALLBACK ""
+#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+#define USAGE_TICKETS \
+ " tickets=%%d default: 1 (enabled)\n"
+#else
+#define USAGE_TICKETS ""
+#endif /* MBEDTLS_SSL_SESSION_TICKETS */
+
+#define USAGE_EAP_TLS \
+ " eap_tls=%%d default: 0 (disabled)\n"
+#define USAGE_NSS_KEYLOG \
+ " nss_keylog=%%d default: 0 (disabled)\n" \
+ " This cannot be used with eap_tls=1\n"
+#define USAGE_NSS_KEYLOG_FILE \
+ " nss_keylog_file=%%s\n"
+#if defined(MBEDTLS_SSL_DTLS_SRTP)
+#define USAGE_SRTP \
+ " use_srtp=%%d default: 0 (disabled)\n" \
+ " This cannot be used with eap_tls=1 or " \
+ " nss_keylog=1\n" \
+ " srtp_force_profile=%%d default: 0 (all enabled)\n" \
+ " available profiles:\n" \
+ " 1 - SRTP_AES128_CM_HMAC_SHA1_80\n" \
+ " 2 - SRTP_AES128_CM_HMAC_SHA1_32\n" \
+ " 3 - SRTP_NULL_HMAC_SHA1_80\n" \
+ " 4 - SRTP_NULL_HMAC_SHA1_32\n" \
+ " mki=%%s default: \"\" (in hex, without 0x)\n"
+#else /* MBEDTLS_SSL_DTLS_SRTP */
+#define USAGE_SRTP ""
+#endif
+
+#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+#define USAGE_MAX_FRAG_LEN \
+ " max_frag_len=%%d default: 16384 (tls default)\n" \
+ " options: 512, 1024, 2048, 4096\n"
+#else
+#define USAGE_MAX_FRAG_LEN ""
+#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
+
+#if defined(MBEDTLS_DHM_C)
+#define USAGE_DHMLEN \
+ " dhmlen=%%d default: (library default: 1024 bits)\n"
+#else
+#define USAGE_DHMLEN
+#endif
+
+#if defined(MBEDTLS_SSL_ALPN)
+#define USAGE_ALPN \
+ " alpn=%%s default: \"\" (disabled)\n" \
+ " example: spdy/1,http/1.1\n"
+#else
+#define USAGE_ALPN ""
+#endif /* MBEDTLS_SSL_ALPN */
+
+#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) || \
+ (defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_EPHEMERAL_ENABLED) && \
+ defined(PSA_WANT_ALG_FFDH))
+#define USAGE_GROUPS \
+ " groups=a,b,c,d default: \"default\" (library default)\n" \
+ " example: \"secp521r1,brainpoolP512r1\"\n" \
+ " - use \"none\" for empty list\n" \
+ " - see mbedtls_ecp_curve_list()\n" \
+ " for acceptable EC group names\n" \
+ " - the following ffdh groups are supported:\n" \
+ " ffdhe2048, ffdhe3072, ffdhe4096, ffdhe6144,\n" \
+ " ffdhe8192\n"
+#else
+#define USAGE_GROUPS ""
+#endif
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+#define USAGE_SIG_ALGS \
+ " sig_algs=a,b,c,d default: \"default\" (library default)\n" \
+ " example: \"ecdsa_secp256r1_sha256,ecdsa_secp384r1_sha384\"\n"
+#else
+#define USAGE_SIG_ALGS ""
+#endif
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+#define USAGE_DTLS \
+ " dtls=%%d default: 0 (TLS)\n" \
+ " hs_timeout=%%d-%%d default: (library default: 1000-60000)\n" \
+ " range of DTLS handshake timeouts in millisecs\n" \
+ " mtu=%%d default: (library default: unlimited)\n" \
+ " dgram_packing=%%d default: 1 (allowed)\n" \
+ " allow or forbid packing of multiple\n" \
+ " records within a single datgram.\n"
+#else
+#define USAGE_DTLS ""
+#endif
+
+#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
+#define USAGE_EMS \
+ " extended_ms=0/1 default: (library default: on)\n"
+#else
+#define USAGE_EMS ""
+#endif
+
+#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+#define USAGE_ETM \
+ " etm=0/1 default: (library default: on)\n"
+#else
+#define USAGE_ETM ""
+#endif
+
+#define USAGE_REPRODUCIBLE \
+ " reproducible=0/1 default: 0 (disabled)\n"
+
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+#define USAGE_RENEGO \
+ " renegotiation=%%d default: 0 (disabled)\n" \
+ " renegotiate=%%d default: 0 (disabled)\n"
+#else
+#define USAGE_RENEGO ""
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#define USAGE_ECJPAKE \
+ " ecjpake_pw=%%s default: none (disabled)\n" \
+ " ecjpake_pw_opaque=%%d default: 0 (disabled)\n"
+#else /* MBEDTLS_USE_PSA_CRYPTO */
+#define USAGE_ECJPAKE \
+ " ecjpake_pw=%%s default: none (disabled)\n"
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+#else /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
+#define USAGE_ECJPAKE ""
+#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+#define USAGE_ECRESTART \
+ " ec_max_ops=%%s default: library default (restart disabled)\n"
+#else
+#define USAGE_ECRESTART ""
+#endif
+
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+#define USAGE_SERIALIZATION \
+ " serialize=%%d default: 0 (do not serialize/deserialize)\n" \
+ " options: 1 (serialize)\n" \
+ " 2 (serialize with re-initialization)\n" \
+ " context_file=%%s The file path to write a serialized connection\n" \
+ " in the form of base64 code (serialize option\n" \
+ " must be set)\n" \
+ " default: \"\" (do nothing)\n" \
+ " option: a file path\n"
+#else
+#define USAGE_SERIALIZATION ""
+#endif
+
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+#define USAGE_EARLY_DATA \
+ " early_data=%%d default: library default\n" \
+ " options: 0 (disabled), 1 (enabled)\n"
+#else
+#define USAGE_EARLY_DATA ""
+#endif /* MBEDTLS_SSL_EARLY_DATA && MBEDTLS_SSL_PROTO_TLS1_3 */
+
+#define USAGE_KEY_OPAQUE_ALGS \
+ " key_opaque_algs=%%s Allowed opaque key algorithms.\n" \
+ " comma-separated pair of values among the following:\n" \
+ " rsa-sign-pkcs1, rsa-sign-pss, rsa-sign-pss-sha256,\n" \
+ " rsa-sign-pss-sha384, rsa-sign-pss-sha512, rsa-decrypt,\n" \
+ " ecdsa-sign, ecdh, none (only acceptable for\n" \
+ " the second value).\n" \
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+#define USAGE_TLS1_3_KEY_EXCHANGE_MODES \
+ " tls13_kex_modes=%%s default: all\n" \
+ " options: psk, psk_ephemeral, psk_all, ephemeral,\n" \
+ " ephemeral_all, all, psk_or_ephemeral\n"
+#else
+#define USAGE_TLS1_3_KEY_EXCHANGE_MODES ""
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+
+/* USAGE is arbitrarily split to stay under the portable string literal
+ * length limit: 4095 bytes in C99. */
+#define USAGE1 \
+ "\n usage: ssl_client2 param=<>...\n" \
+ "\n acceptable parameters:\n" \
+ " server_name=%%s default: localhost\n" \
+ " server_addr=%%s default: given by name\n" \
+ " server_port=%%d default: 4433\n" \
+ " request_page=%%s default: \".\"\n" \
+ " request_size=%%d default: about 34 (basic request)\n" \
+ " (minimum: 0, max: " MAX_REQUEST_SIZE_STR ")\n" \
+ " If 0, in the first exchange only an empty\n" \
+ " application data message is sent followed by\n" \
+ " a second non-empty message before attempting\n" \
+ " to read a response from the server\n" \
+ " debug_level=%%d default: 0 (disabled)\n" \
+ " build_version=%%d default: none (disabled)\n" \
+ " option: 1 (print build version only and stop)\n" \
+ " nbio=%%d default: 0 (blocking I/O)\n" \
+ " options: 1 (non-blocking), 2 (added delays)\n" \
+ " event=%%d default: 0 (loop)\n" \
+ " options: 1 (level-triggered, implies nbio=1),\n" \
+ " read_timeout=%%d default: 0 ms (no timeout)\n" \
+ " max_resend=%%d default: 0 (no resend on timeout)\n" \
+ " skip_close_notify=%%d default: 0 (send close_notify)\n" \
+ "\n" \
+ USAGE_DTLS \
+ USAGE_CID \
+ USAGE_SRTP \
+ "\n"
+#define USAGE2 \
+ " auth_mode=%%s default: (library default: none)\n" \
+ " options: none, optional, required\n" \
+ USAGE_IO \
+ USAGE_KEY_OPAQUE \
+ USAGE_CA_CALLBACK \
+ "\n" \
+ USAGE_PSK \
+ USAGE_ECJPAKE \
+ USAGE_ECRESTART \
+ "\n"
+#define USAGE3 \
+ " allow_legacy=%%d default: (library default: no)\n" \
+ USAGE_RENEGO \
+ " exchanges=%%d default: 1\n" \
+ " reconnect=%%d number of reconnections using session resumption\n" \
+ " default: 0 (disabled)\n" \
+ " reco_server_name=%%s default: NULL\n" \
+ " reco_delay=%%d default: 0 milliseconds\n" \
+ " reco_mode=%%d 0: copy session, 1: serialize session\n" \
+ " default: 1\n" \
+ " reconnect_hard=%%d default: 0 (disabled)\n" \
+ USAGE_TICKETS \
+ USAGE_EAP_TLS \
+ USAGE_MAX_FRAG_LEN \
+ USAGE_CONTEXT_CRT_CB \
+ USAGE_ALPN \
+ USAGE_EMS \
+ USAGE_ETM \
+ USAGE_REPRODUCIBLE \
+ USAGE_GROUPS \
+ USAGE_SIG_ALGS \
+ USAGE_EARLY_DATA \
+ USAGE_DHMLEN \
+ USAGE_KEY_OPAQUE_ALGS \
+ "\n"
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+#define TLS1_3_VERSION_OPTIONS ", tls13"
+#else /* MBEDTLS_SSL_PROTO_TLS1_3 */
+#define TLS1_3_VERSION_OPTIONS ""
+#endif /* !MBEDTLS_SSL_PROTO_TLS1_3 */
+
+#define USAGE4 \
+ " allow_sha1=%%d default: 0\n" \
+ " min_version=%%s default: (library default: tls12)\n" \
+ " max_version=%%s default: (library default: tls12)\n" \
+ " force_version=%%s default: \"\" (none)\n" \
+ " options: tls12, dtls12" TLS1_3_VERSION_OPTIONS \
+ "\n\n" \
+ " force_ciphersuite=<name> default: all enabled\n" \
+ USAGE_TLS1_3_KEY_EXCHANGE_MODES \
+ " query_config=<name> return 0 if the specified\n" \
+ " configuration macro is defined and 1\n" \
+ " otherwise. The expansion of the macro\n" \
+ " is printed if it is defined\n" \
+ USAGE_SERIALIZATION \
+ "\n"
+
+/*
+ * global options
+ */
+struct options {
+ const char *server_name; /* hostname of the server (client only) */
+ const char *server_addr; /* address of the server (client only) */
+ const char *server_port; /* port on which the ssl service runs */
+ int debug_level; /* level of debugging */
+ int nbio; /* should I/O be blocking? */
+ int event; /* loop or event-driven IO? level or edge triggered? */
+ uint32_t read_timeout; /* timeout on mbedtls_ssl_read() in milliseconds */
+ int max_resend; /* DTLS times to resend on read timeout */
+ const char *request_page; /* page on server to request */
+ int request_size; /* pad request with header to requested size */
+ const char *ca_file; /* the file with the CA certificate(s) */
+ const char *ca_path; /* the path with the CA certificate(s) reside */
+ const char *crt_file; /* the file with the client certificate */
+ const char *key_file; /* the file with the client key */
+ int key_opaque; /* handle private key as if it were opaque */
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ int psk_opaque;
+#endif
+#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
+ int ca_callback; /* Use callback for trusted certificate list */
+#endif
+ const char *key_pwd; /* the password for the client key */
+ const char *psk; /* the pre-shared key */
+ const char *psk_identity; /* the pre-shared key identity */
+ const char *ecjpake_pw; /* the EC J-PAKE password */
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ int ecjpake_pw_opaque; /* set to 1 to use the opaque method for setting the password */
+#endif
+ int ec_max_ops; /* EC consecutive operations limit */
+ int force_ciphersuite[2]; /* protocol/ciphersuite to use, or all */
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ int tls13_kex_modes; /* supported TLS 1.3 key exchange modes */
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+ int renegotiation; /* enable / disable renegotiation */
+ int allow_legacy; /* allow legacy renegotiation */
+ int renegotiate; /* attempt renegotiation? */
+ int renego_delay; /* delay before enforcing renegotiation */
+ int exchanges; /* number of data exchanges */
+ int min_version; /* minimum protocol version accepted */
+ int max_version; /* maximum protocol version accepted */
+ int allow_sha1; /* flag for SHA-1 support */
+ int auth_mode; /* verify mode for connection */
+ unsigned char mfl_code; /* code for maximum fragment length */
+ int trunc_hmac; /* negotiate truncated hmac or not */
+ int recsplit; /* enable record splitting? */
+ int dhmlen; /* minimum DHM params len in bits */
+ int reconnect; /* attempt to resume session */
+ const char *reco_server_name; /* hostname of the server (re-connect) */
+ int reco_delay; /* delay in seconds before resuming session */
+ int reco_mode; /* how to keep the session around */
+ int reconnect_hard; /* unexpectedly reconnect from the same port */
+ int tickets; /* enable / disable session tickets */
+ const char *groups; /* list of supported groups */
+ const char *sig_algs; /* supported TLS 1.3 signature algorithms */
+ const char *alpn_string; /* ALPN supported protocols */
+ int transport; /* TLS or DTLS? */
+ uint32_t hs_to_min; /* Initial value of DTLS handshake timer */
+ uint32_t hs_to_max; /* Max value of DTLS handshake timer */
+ int dtls_mtu; /* UDP Maximum transport unit for DTLS */
+ int fallback; /* is this a fallback connection? */
+ int dgram_packing; /* allow/forbid datagram packing */
+ int extended_ms; /* negotiate extended master secret? */
+ int etm; /* negotiate encrypt then mac? */
+ int context_crt_cb; /* use context-specific CRT verify callback */
+ int eap_tls; /* derive EAP-TLS keying material? */
+ int nss_keylog; /* export NSS key log material */
+ const char *nss_keylog_file; /* NSS key log file */
+ int cid_enabled; /* whether to use the CID extension or not */
+ int cid_enabled_renego; /* whether to use the CID extension or not
+ * during renegotiation */
+ const char *cid_val; /* the CID to use for incoming messages */
+ int serialize; /* serialize/deserialize connection */
+ const char *context_file; /* the file to write a serialized connection
+ * in the form of base64 code (serialize
+ * option must be set) */
+ const char *cid_val_renego; /* the CID to use for incoming messages
+ * after renegotiation */
+ int reproducible; /* make communication reproducible */
+ int skip_close_notify; /* skip sending the close_notify alert */
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+ int early_data; /* early data enablement flag */
+#endif
+ int query_config_mode; /* whether to read config */
+ int use_srtp; /* Support SRTP */
+ int force_srtp_profile; /* SRTP protection profile to use or all */
+ const char *mki; /* The dtls mki value to use */
+ const char *key_opaque_alg1; /* Allowed opaque key alg 1 */
+ const char *key_opaque_alg2; /* Allowed Opaque key alg 2 */
+} opt;
+
+#include "ssl_test_common_source.c"
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+static unsigned char peer_crt_info[1024];
+
+/*
+ * Enabled if debug_level > 1 in code below
+ */
+static int my_verify(void *data, mbedtls_x509_crt *crt,
+ int depth, uint32_t *flags)
+{
+ char buf[1024];
+ ((void) data);
+
+ mbedtls_printf("\nVerify requested for (Depth %d):\n", depth);
+
+#if !defined(MBEDTLS_X509_REMOVE_INFO)
+ mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "", crt);
+ if (depth == 0) {
+ memcpy(peer_crt_info, buf, sizeof(buf));
+ }
+
+ if (opt.debug_level == 0) {
+ return 0;
+ }
+
+ mbedtls_printf("%s", buf);
+#else
+ ((void) crt);
+ ((void) depth);
+#endif
+
+ if ((*flags) == 0) {
+ mbedtls_printf(" This certificate has no flags\n");
+ } else {
+ x509_crt_verify_info(buf, sizeof(buf), " ! ", *flags);
+ mbedtls_printf("%s\n", buf);
+ }
+
+ return 0;
+}
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+int report_cid_usage(mbedtls_ssl_context *ssl,
+ const char *additional_description)
+{
+ int ret;
+ unsigned char peer_cid[MBEDTLS_SSL_CID_OUT_LEN_MAX];
+ size_t peer_cid_len;
+ int cid_negotiated;
+
+ if (opt.transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
+ return 0;
+ }
+
+ /* Check if the use of a CID has been negotiated,
+ * but don't ask for the CID value and length.
+ *
+ * Note: Here and below, we're demonstrating the various ways
+ * in which mbedtls_ssl_get_peer_cid() can be called,
+ * depending on whether or not the length/value of the
+ * peer's CID is needed.
+ *
+ * An actual application, however, should use
+ * just one call to mbedtls_ssl_get_peer_cid(). */
+ ret = mbedtls_ssl_get_peer_cid(ssl, &cid_negotiated,
+ NULL, NULL);
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_get_peer_cid returned -0x%x\n\n",
+ (unsigned int) -ret);
+ return ret;
+ }
+
+ if (cid_negotiated == MBEDTLS_SSL_CID_DISABLED) {
+ if (opt.cid_enabled == MBEDTLS_SSL_CID_ENABLED) {
+ mbedtls_printf("(%s) Use of Connection ID was rejected by the server.\n",
+ additional_description);
+ }
+ } else {
+ size_t idx = 0;
+ mbedtls_printf("(%s) Use of Connection ID has been negotiated.\n",
+ additional_description);
+
+ /* Ask for just the length of the peer's CID. */
+ ret = mbedtls_ssl_get_peer_cid(ssl, &cid_negotiated,
+ NULL, &peer_cid_len);
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_get_peer_cid returned -0x%x\n\n",
+ (unsigned int) -ret);
+ return ret;
+ }
+
+ /* Ask for just length + value of the peer's CID. */
+ ret = mbedtls_ssl_get_peer_cid(ssl, &cid_negotiated,
+ peer_cid, &peer_cid_len);
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_get_peer_cid returned -0x%x\n\n",
+ (unsigned int) -ret);
+ return ret;
+ }
+ mbedtls_printf("(%s) Peer CID (length %u Bytes): ",
+ additional_description,
+ (unsigned) peer_cid_len);
+ while (idx < peer_cid_len) {
+ mbedtls_printf("%02x ", peer_cid[idx]);
+ idx++;
+ }
+ mbedtls_printf("\n");
+ }
+
+ return 0;
+}
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+
+static int ssl_save_session_serialize(mbedtls_ssl_context *ssl,
+ unsigned char **session_data,
+ size_t *session_data_len)
+{
+ int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+ mbedtls_ssl_session exported_session;
+
+ /* free any previously saved data */
+ if (*session_data != NULL) {
+ mbedtls_platform_zeroize(*session_data, *session_data_len);
+ mbedtls_free(*session_data);
+ *session_data = NULL;
+ *session_data_len = 0;
+ }
+
+ mbedtls_ssl_session_init(&exported_session);
+ ret = mbedtls_ssl_get_session(ssl, &exported_session);
+ if (ret != 0) {
+ mbedtls_printf(
+ "failed\n ! mbedtls_ssl_get_session() returned -%#02x\n",
+ (unsigned) -ret);
+ goto exit;
+ }
+
+ /* get size of the buffer needed */
+ (void) mbedtls_ssl_session_save(&exported_session, NULL, 0, session_data_len);
+ *session_data = mbedtls_calloc(1, *session_data_len);
+ if (*session_data == NULL) {
+ mbedtls_printf(" failed\n ! alloc %u bytes for session data\n",
+ (unsigned) *session_data_len);
+ ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
+ goto exit;
+ }
+
+ /* actually save session data */
+ if ((ret = mbedtls_ssl_session_save(&exported_session,
+ *session_data, *session_data_len,
+ session_data_len)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_session_saved returned -0x%04x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+exit:
+ mbedtls_ssl_session_free(&exported_session);
+ return ret;
+}
+
+/*
+ * Build HTTP request
+ */
+static int build_http_request(unsigned char *buf, size_t buf_size, size_t *request_len)
+{
+ int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+ size_t len, tail_len, request_size;
+
+ ret = mbedtls_snprintf((char *) buf, buf_size, GET_REQUEST, opt.request_page);
+ if (ret < 0) {
+ return ret;
+ }
+
+ len = (size_t) ret;
+ tail_len = strlen(GET_REQUEST_END);
+ if (opt.request_size != DFL_REQUEST_SIZE) {
+ request_size = (size_t) opt.request_size;
+ } else {
+ request_size = len + tail_len;
+ }
+
+ if (request_size > buf_size) {
+ return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL;
+ }
+
+ /* Add padding to GET request to reach opt.request_size in length */
+ if (opt.request_size != DFL_REQUEST_SIZE &&
+ len + tail_len < request_size) {
+ memset(buf + len, 'A', request_size - len - tail_len);
+ len = request_size - tail_len;
+ }
+
+ strncpy((char *) buf + len, GET_REQUEST_END, buf_size - len);
+ len += tail_len;
+
+ /* Truncate if request size is smaller than the "natural" size */
+ if (opt.request_size != DFL_REQUEST_SIZE &&
+ len > request_size) {
+ len = request_size;
+
+ /* Still end with \r\n unless that's really not possible */
+ if (len >= 2) {
+ buf[len - 2] = '\r';
+ }
+ if (len >= 1) {
+ buf[len - 1] = '\n';
+ }
+ }
+
+ *request_len = len;
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret = 0, i;
+ size_t len, written, frags, retry_left;
+ int query_config_ret = 0;
+ mbedtls_net_context server_fd;
+ io_ctx_t io_ctx;
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ uint16_t sig_alg_list[SIG_ALG_LIST_SIZE];
+#endif
+
+ unsigned char buf[MAX_REQUEST_SIZE + 1];
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED)
+ unsigned char psk[MBEDTLS_PSK_MAX_LEN];
+ size_t psk_len = 0;
+#endif
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+ unsigned char cid[MBEDTLS_SSL_CID_IN_LEN_MAX];
+ unsigned char cid_renego[MBEDTLS_SSL_CID_IN_LEN_MAX];
+ size_t cid_len = 0;
+ size_t cid_renego_len = 0;
+#endif
+
+#if defined(MBEDTLS_SSL_ALPN)
+ const char *alpn_list[ALPN_LIST_SIZE];
+#endif
+
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+ unsigned char alloc_buf[MEMORY_HEAP_SIZE];
+#endif
+ uint16_t group_list[GROUP_LIST_SIZE];
+#if defined(MBEDTLS_SSL_DTLS_SRTP)
+ unsigned char mki[MBEDTLS_TLS_SRTP_MAX_MKI_LENGTH];
+ size_t mki_len = 0;
+#endif
+
+ const char *pers = "ssl_client2";
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED)
+ mbedtls_svc_key_id_t slot = MBEDTLS_SVC_KEY_ID_INIT;
+ psa_algorithm_t alg = 0;
+ psa_key_attributes_t key_attributes;
+#endif
+ psa_status_t status;
+#elif defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ psa_status_t status;
+#endif
+
+ rng_context_t rng;
+ mbedtls_ssl_context ssl;
+ mbedtls_ssl_config conf;
+ mbedtls_ssl_session saved_session;
+ unsigned char *session_data = NULL;
+ size_t session_data_len = 0;
+#if defined(MBEDTLS_TIMING_C)
+ mbedtls_timing_delay_context timer;
+#endif
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ uint32_t flags;
+ mbedtls_x509_crt cacert;
+ mbedtls_x509_crt clicert;
+ mbedtls_pk_context pkey;
+ mbedtls_x509_crt_profile crt_profile_for_test = mbedtls_x509_crt_profile_default;
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ mbedtls_svc_key_id_t key_slot = MBEDTLS_SVC_KEY_ID_INIT; /* invalid key slot */
+#endif
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+ char *p, *q;
+ const int *list;
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+ unsigned char *context_buf = NULL;
+ size_t context_buf_len;
+#endif
+ unsigned char eap_tls_keymaterial[16];
+ unsigned char eap_tls_iv[8];
+ const char *eap_tls_label = "client EAP encryption";
+ eap_tls_keys eap_tls_keying;
+#if defined(MBEDTLS_SSL_DTLS_SRTP)
+ /*! master keys and master salt for SRTP generated during handshake */
+ unsigned char dtls_srtp_key_material[MBEDTLS_TLS_SRTP_MAX_KEY_MATERIAL_LENGTH];
+ const char *dtls_srtp_label = "EXTRACTOR-dtls_srtp";
+ dtls_srtp_keys dtls_srtp_keying;
+ const mbedtls_ssl_srtp_profile default_profiles[] = {
+ MBEDTLS_TLS_SRTP_AES128_CM_HMAC_SHA1_80,
+ MBEDTLS_TLS_SRTP_AES128_CM_HMAC_SHA1_32,
+ MBEDTLS_TLS_SRTP_NULL_HMAC_SHA1_80,
+ MBEDTLS_TLS_SRTP_NULL_HMAC_SHA1_32,
+ MBEDTLS_TLS_SRTP_UNSET
+ };
+#endif /* MBEDTLS_SSL_DTLS_SRTP */
+#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) && \
+ defined(MBEDTLS_USE_PSA_CRYPTO)
+ mbedtls_svc_key_id_t ecjpake_pw_slot = MBEDTLS_SVC_KEY_ID_INIT; /* ecjpake password key slot */
+#endif /* MBEDTLS_USE_PSA_CRYPTO && MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
+
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+ mbedtls_memory_buffer_alloc_init(alloc_buf, sizeof(alloc_buf));
+#endif
+
+#if defined(MBEDTLS_TEST_HOOKS)
+ test_hooks_init();
+#endif /* MBEDTLS_TEST_HOOKS */
+
+ /*
+ * Make sure memory references are valid.
+ */
+ mbedtls_net_init(&server_fd);
+ mbedtls_ssl_init(&ssl);
+ mbedtls_ssl_config_init(&conf);
+ mbedtls_ssl_session_init(&saved_session);
+ rng_init(&rng);
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ mbedtls_x509_crt_init(&cacert);
+ mbedtls_x509_crt_init(&clicert);
+ mbedtls_pk_init(&pkey);
+#endif
+#if defined(MBEDTLS_SSL_ALPN)
+ memset((void *) alpn_list, 0, sizeof(alpn_list));
+#endif
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ status = psa_crypto_init();
+ if (status != PSA_SUCCESS) {
+ mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
+ (int) status);
+ ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
+ goto exit;
+ }
+#endif /* MBEDTLS_USE_PSA_CRYPTO || MBEDTLS_SSL_PROTO_TLS1_3 */
+#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+ mbedtls_test_enable_insecure_external_rng();
+#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+
+ opt.server_name = DFL_SERVER_NAME;
+ opt.server_addr = DFL_SERVER_ADDR;
+ opt.server_port = DFL_SERVER_PORT;
+ opt.debug_level = DFL_DEBUG_LEVEL;
+ opt.cid_enabled = DFL_CID_ENABLED;
+ opt.cid_val = DFL_CID_VALUE;
+ opt.cid_enabled_renego = DFL_CID_ENABLED_RENEGO;
+ opt.cid_val_renego = DFL_CID_VALUE_RENEGO;
+ opt.nbio = DFL_NBIO;
+ opt.event = DFL_EVENT;
+ opt.context_crt_cb = DFL_CONTEXT_CRT_CB;
+ opt.read_timeout = DFL_READ_TIMEOUT;
+ opt.max_resend = DFL_MAX_RESEND;
+ opt.request_page = DFL_REQUEST_PAGE;
+ opt.request_size = DFL_REQUEST_SIZE;
+ opt.ca_file = DFL_CA_FILE;
+ opt.ca_path = DFL_CA_PATH;
+ opt.crt_file = DFL_CRT_FILE;
+ opt.key_file = DFL_KEY_FILE;
+ opt.key_opaque = DFL_KEY_OPAQUE;
+ opt.key_pwd = DFL_KEY_PWD;
+ opt.psk = DFL_PSK;
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ opt.psk_opaque = DFL_PSK_OPAQUE;
+#endif
+#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
+ opt.ca_callback = DFL_CA_CALLBACK;
+#endif
+ opt.psk_identity = DFL_PSK_IDENTITY;
+ opt.ecjpake_pw = DFL_ECJPAKE_PW;
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ opt.ecjpake_pw_opaque = DFL_ECJPAKE_PW_OPAQUE;
+#endif
+ opt.ec_max_ops = DFL_EC_MAX_OPS;
+ opt.force_ciphersuite[0] = DFL_FORCE_CIPHER;
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ opt.tls13_kex_modes = DFL_TLS1_3_KEX_MODES;
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+ opt.renegotiation = DFL_RENEGOTIATION;
+ opt.allow_legacy = DFL_ALLOW_LEGACY;
+ opt.renegotiate = DFL_RENEGOTIATE;
+ opt.exchanges = DFL_EXCHANGES;
+ opt.min_version = DFL_MIN_VERSION;
+ opt.max_version = DFL_MAX_VERSION;
+ opt.allow_sha1 = DFL_SHA1;
+ opt.auth_mode = DFL_AUTH_MODE;
+ opt.mfl_code = DFL_MFL_CODE;
+ opt.trunc_hmac = DFL_TRUNC_HMAC;
+ opt.recsplit = DFL_RECSPLIT;
+ opt.dhmlen = DFL_DHMLEN;
+ opt.reconnect = DFL_RECONNECT;
+ opt.reco_server_name = DFL_RECO_SERVER_NAME;
+ opt.reco_delay = DFL_RECO_DELAY;
+ opt.reco_mode = DFL_RECO_MODE;
+ opt.reconnect_hard = DFL_RECONNECT_HARD;
+ opt.tickets = DFL_TICKETS;
+ opt.alpn_string = DFL_ALPN_STRING;
+ opt.groups = DFL_GROUPS;
+ opt.sig_algs = DFL_SIG_ALGS;
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+ opt.early_data = DFL_EARLY_DATA;
+#endif
+ opt.transport = DFL_TRANSPORT;
+ opt.hs_to_min = DFL_HS_TO_MIN;
+ opt.hs_to_max = DFL_HS_TO_MAX;
+ opt.dtls_mtu = DFL_DTLS_MTU;
+ opt.fallback = DFL_FALLBACK;
+ opt.extended_ms = DFL_EXTENDED_MS;
+ opt.etm = DFL_ETM;
+ opt.dgram_packing = DFL_DGRAM_PACKING;
+ opt.serialize = DFL_SERIALIZE;
+ opt.context_file = DFL_CONTEXT_FILE;
+ opt.eap_tls = DFL_EAP_TLS;
+ opt.reproducible = DFL_REPRODUCIBLE;
+ opt.nss_keylog = DFL_NSS_KEYLOG;
+ opt.nss_keylog_file = DFL_NSS_KEYLOG_FILE;
+ opt.skip_close_notify = DFL_SKIP_CLOSE_NOTIFY;
+ opt.query_config_mode = DFL_QUERY_CONFIG_MODE;
+ opt.use_srtp = DFL_USE_SRTP;
+ opt.force_srtp_profile = DFL_SRTP_FORCE_PROFILE;
+ opt.mki = DFL_SRTP_MKI;
+ opt.key_opaque_alg1 = DFL_KEY_OPAQUE_ALG;
+ opt.key_opaque_alg2 = DFL_KEY_OPAQUE_ALG;
+
+ p = q = NULL;
+ if (argc < 1) {
+usage:
+ if (p != NULL && q != NULL) {
+ printf("unrecognized value for '%s': '%s'\n", p, q);
+ } else if (p != NULL && q == NULL) {
+ printf("unrecognized param: '%s'\n", p);
+ }
+
+ mbedtls_printf("usage: ssl_client2 [param=value] [...]\n");
+ mbedtls_printf(" ssl_client2 help[_theme]\n");
+ mbedtls_printf("'help' lists acceptable 'param' and 'value'\n");
+ mbedtls_printf("'help_ciphersuites' lists available ciphersuites\n");
+ mbedtls_printf("\n");
+
+ if (ret == 0) {
+ ret = 1;
+ }
+ goto exit;
+ }
+
+ for (i = 1; i < argc; i++) {
+ p = argv[i];
+
+ if (strcmp(p, "help") == 0) {
+ mbedtls_printf(USAGE1);
+ mbedtls_printf(USAGE2);
+ mbedtls_printf(USAGE3);
+ mbedtls_printf(USAGE4);
+
+ ret = 0;
+ goto exit;
+ }
+ if (strcmp(p, "help_ciphersuites") == 0) {
+ mbedtls_printf(" acceptable ciphersuite names:\n");
+ for (list = mbedtls_ssl_list_ciphersuites();
+ *list != 0;
+ list++) {
+ mbedtls_printf(" %s\n", mbedtls_ssl_get_ciphersuite_name(*list));
+ }
+
+ ret = 0;
+ goto exit;
+ }
+
+ if ((q = strchr(p, '=')) == NULL) {
+ mbedtls_printf("param requires a value: '%s'\n", p);
+ p = NULL; // avoid "unrecnognized param" message
+ goto usage;
+ }
+ *q++ = '\0';
+
+ if (strcmp(p, "server_name") == 0) {
+ opt.server_name = q;
+ } else if (strcmp(p, "server_addr") == 0) {
+ opt.server_addr = q;
+ } else if (strcmp(p, "server_port") == 0) {
+ opt.server_port = q;
+ } else if (strcmp(p, "dtls") == 0) {
+ int t = atoi(q);
+ if (t == 0) {
+ opt.transport = MBEDTLS_SSL_TRANSPORT_STREAM;
+ } else if (t == 1) {
+ opt.transport = MBEDTLS_SSL_TRANSPORT_DATAGRAM;
+ } else {
+ goto usage;
+ }
+ } else if (strcmp(p, "debug_level") == 0) {
+ opt.debug_level = atoi(q);
+ if (opt.debug_level < 0 || opt.debug_level > 65535) {
+ goto usage;
+ }
+ } else if (strcmp(p, "build_version") == 0) {
+ if (strcmp(q, "1") == 0) {
+ mbedtls_printf("build version: %s (build %d)\n",
+ MBEDTLS_VERSION_STRING_FULL,
+ MBEDTLS_VERSION_NUMBER);
+ goto exit;
+ }
+ } else if (strcmp(p, "context_crt_cb") == 0) {
+ opt.context_crt_cb = atoi(q);
+ if (opt.context_crt_cb != 0 && opt.context_crt_cb != 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "nbio") == 0) {
+ opt.nbio = atoi(q);
+ if (opt.nbio < 0 || opt.nbio > 2) {
+ goto usage;
+ }
+ } else if (strcmp(p, "event") == 0) {
+ opt.event = atoi(q);
+ if (opt.event < 0 || opt.event > 2) {
+ goto usage;
+ }
+ } else if (strcmp(p, "read_timeout") == 0) {
+ opt.read_timeout = atoi(q);
+ } else if (strcmp(p, "max_resend") == 0) {
+ opt.max_resend = atoi(q);
+ if (opt.max_resend < 0) {
+ goto usage;
+ }
+ } else if (strcmp(p, "request_page") == 0) {
+ opt.request_page = q;
+ } else if (strcmp(p, "request_size") == 0) {
+ opt.request_size = atoi(q);
+ if (opt.request_size < 0 ||
+ opt.request_size > MAX_REQUEST_SIZE) {
+ goto usage;
+ }
+ } else if (strcmp(p, "ca_file") == 0) {
+ opt.ca_file = q;
+ } else if (strcmp(p, "ca_path") == 0) {
+ opt.ca_path = q;
+ } else if (strcmp(p, "crt_file") == 0) {
+ opt.crt_file = q;
+ } else if (strcmp(p, "key_file") == 0) {
+ opt.key_file = q;
+ } else if (strcmp(p, "key_pwd") == 0) {
+ opt.key_pwd = q;
+ }
+#if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ else if (strcmp(p, "key_opaque") == 0) {
+ opt.key_opaque = atoi(q);
+ }
+#endif
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+ else if (strcmp(p, "cid") == 0) {
+ opt.cid_enabled = atoi(q);
+ if (opt.cid_enabled != 0 && opt.cid_enabled != 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "cid_renego") == 0) {
+ opt.cid_enabled_renego = atoi(q);
+ if (opt.cid_enabled_renego != 0 && opt.cid_enabled_renego != 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "cid_val") == 0) {
+ opt.cid_val = q;
+ } else if (strcmp(p, "cid_val_renego") == 0) {
+ opt.cid_val_renego = q;
+ }
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+ else if (strcmp(p, "psk") == 0) {
+ opt.psk = q;
+ }
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ else if (strcmp(p, "psk_opaque") == 0) {
+ opt.psk_opaque = atoi(q);
+ }
+#endif
+#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
+ else if (strcmp(p, "ca_callback") == 0) {
+ opt.ca_callback = atoi(q);
+ }
+#endif
+ else if (strcmp(p, "psk_identity") == 0) {
+ opt.psk_identity = q;
+ } else if (strcmp(p, "ecjpake_pw") == 0) {
+ opt.ecjpake_pw = q;
+ }
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ else if (strcmp(p, "ecjpake_pw_opaque") == 0) {
+ opt.ecjpake_pw_opaque = atoi(q);
+ }
+#endif
+ else if (strcmp(p, "ec_max_ops") == 0) {
+ opt.ec_max_ops = atoi(q);
+ } else if (strcmp(p, "force_ciphersuite") == 0) {
+ opt.force_ciphersuite[0] = mbedtls_ssl_get_ciphersuite_id(q);
+
+ if (opt.force_ciphersuite[0] == 0) {
+ ret = 2;
+ goto usage;
+ }
+ opt.force_ciphersuite[1] = 0;
+ } else if (strcmp(p, "renegotiation") == 0) {
+ opt.renegotiation = (atoi(q)) ?
+ MBEDTLS_SSL_RENEGOTIATION_ENABLED :
+ MBEDTLS_SSL_RENEGOTIATION_DISABLED;
+ } else if (strcmp(p, "allow_legacy") == 0) {
+ switch (atoi(q)) {
+ case -1:
+ opt.allow_legacy = MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE;
+ break;
+ case 0:
+ opt.allow_legacy = MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION;
+ break;
+ case 1:
+ opt.allow_legacy = MBEDTLS_SSL_LEGACY_ALLOW_RENEGOTIATION;
+ break;
+ default: goto usage;
+ }
+ } else if (strcmp(p, "renegotiate") == 0) {
+ opt.renegotiate = atoi(q);
+ if (opt.renegotiate < 0 || opt.renegotiate > 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "exchanges") == 0) {
+ opt.exchanges = atoi(q);
+ if (opt.exchanges < 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "reconnect") == 0) {
+ opt.reconnect = atoi(q);
+ if (opt.reconnect < 0 || opt.reconnect > 2) {
+ goto usage;
+ }
+ } else if (strcmp(p, "reco_server_name") == 0) {
+ opt.reco_server_name = q;
+ } else if (strcmp(p, "reco_delay") == 0) {
+ opt.reco_delay = atoi(q);
+ if (opt.reco_delay < 0) {
+ goto usage;
+ }
+ } else if (strcmp(p, "reco_mode") == 0) {
+ opt.reco_mode = atoi(q);
+ if (opt.reco_mode < 0) {
+ goto usage;
+ }
+ } else if (strcmp(p, "reconnect_hard") == 0) {
+ opt.reconnect_hard = atoi(q);
+ if (opt.reconnect_hard < 0 || opt.reconnect_hard > 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "tickets") == 0) {
+ opt.tickets = atoi(q);
+ if (opt.tickets < 0) {
+ goto usage;
+ }
+ } else if (strcmp(p, "alpn") == 0) {
+ opt.alpn_string = q;
+ } else if (strcmp(p, "extended_ms") == 0) {
+ switch (atoi(q)) {
+ case 0:
+ opt.extended_ms = MBEDTLS_SSL_EXTENDED_MS_DISABLED;
+ break;
+ case 1:
+ opt.extended_ms = MBEDTLS_SSL_EXTENDED_MS_ENABLED;
+ break;
+ default: goto usage;
+ }
+ } else if (strcmp(p, "groups") == 0) {
+ opt.groups = q;
+ }
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ else if (strcmp(p, "sig_algs") == 0) {
+ opt.sig_algs = q;
+ }
+#endif
+ else if (strcmp(p, "etm") == 0) {
+ switch (atoi(q)) {
+ case 0: opt.etm = MBEDTLS_SSL_ETM_DISABLED; break;
+ case 1: opt.etm = MBEDTLS_SSL_ETM_ENABLED; break;
+ default: goto usage;
+ }
+ }
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+ else if (strcmp(p, "early_data") == 0) {
+ switch (atoi(q)) {
+ case 0:
+ opt.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED;
+ break;
+ case 1:
+ opt.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED;
+ break;
+ default: goto usage;
+ }
+ }
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
+ else if (strcmp(p, "tls13_kex_modes") == 0) {
+ if (strcmp(q, "psk") == 0) {
+ opt.tls13_kex_modes = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK;
+ } else if (strcmp(q, "psk_ephemeral") == 0) {
+ opt.tls13_kex_modes = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL;
+ } else if (strcmp(q, "ephemeral") == 0) {
+ opt.tls13_kex_modes = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL;
+ } else if (strcmp(q, "ephemeral_all") == 0) {
+ opt.tls13_kex_modes = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ALL;
+ } else if (strcmp(q, "psk_all") == 0) {
+ opt.tls13_kex_modes = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ALL;
+ } else if (strcmp(q, "all") == 0) {
+ opt.tls13_kex_modes = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_ALL;
+ } else if (strcmp(q, "psk_or_ephemeral") == 0) {
+ opt.tls13_kex_modes = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK |
+ MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL;
+ } else {
+ goto usage;
+ }
+ }
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+ else if (strcmp(p, "min_version") == 0) {
+ if (strcmp(q, "tls12") == 0 ||
+ strcmp(q, "dtls12") == 0) {
+ opt.min_version = MBEDTLS_SSL_VERSION_TLS1_2;
+ }
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ else if (strcmp(q, "tls13") == 0) {
+ opt.min_version = MBEDTLS_SSL_VERSION_TLS1_3;
+ }
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+ else {
+ goto usage;
+ }
+ } else if (strcmp(p, "max_version") == 0) {
+ if (strcmp(q, "tls12") == 0 ||
+ strcmp(q, "dtls12") == 0) {
+ opt.max_version = MBEDTLS_SSL_VERSION_TLS1_2;
+ }
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ else if (strcmp(q, "tls13") == 0) {
+ opt.max_version = MBEDTLS_SSL_VERSION_TLS1_3;
+ }
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+ else {
+ goto usage;
+ }
+ } else if (strcmp(p, "allow_sha1") == 0) {
+ switch (atoi(q)) {
+ case 0: opt.allow_sha1 = 0; break;
+ case 1: opt.allow_sha1 = 1; break;
+ default: goto usage;
+ }
+ } else if (strcmp(p, "force_version") == 0) {
+ if (strcmp(q, "tls12") == 0) {
+ opt.min_version = MBEDTLS_SSL_VERSION_TLS1_2;
+ opt.max_version = MBEDTLS_SSL_VERSION_TLS1_2;
+ } else if (strcmp(q, "dtls12") == 0) {
+ opt.min_version = MBEDTLS_SSL_VERSION_TLS1_2;
+ opt.max_version = MBEDTLS_SSL_VERSION_TLS1_2;
+ opt.transport = MBEDTLS_SSL_TRANSPORT_DATAGRAM;
+ }
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ else if (strcmp(q, "tls13") == 0) {
+ opt.min_version = MBEDTLS_SSL_VERSION_TLS1_3;
+ opt.max_version = MBEDTLS_SSL_VERSION_TLS1_3;
+ }
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+ else {
+ goto usage;
+ }
+ } else if (strcmp(p, "auth_mode") == 0) {
+ if (strcmp(q, "none") == 0) {
+ opt.auth_mode = MBEDTLS_SSL_VERIFY_NONE;
+ } else if (strcmp(q, "optional") == 0) {
+ opt.auth_mode = MBEDTLS_SSL_VERIFY_OPTIONAL;
+ } else if (strcmp(q, "required") == 0) {
+ opt.auth_mode = MBEDTLS_SSL_VERIFY_REQUIRED;
+ } else {
+ goto usage;
+ }
+ } else if (strcmp(p, "max_frag_len") == 0) {
+ if (strcmp(q, "512") == 0) {
+ opt.mfl_code = MBEDTLS_SSL_MAX_FRAG_LEN_512;
+ } else if (strcmp(q, "1024") == 0) {
+ opt.mfl_code = MBEDTLS_SSL_MAX_FRAG_LEN_1024;
+ } else if (strcmp(q, "2048") == 0) {
+ opt.mfl_code = MBEDTLS_SSL_MAX_FRAG_LEN_2048;
+ } else if (strcmp(q, "4096") == 0) {
+ opt.mfl_code = MBEDTLS_SSL_MAX_FRAG_LEN_4096;
+ } else {
+ goto usage;
+ }
+ } else if (strcmp(p, "trunc_hmac") == 0) {
+ switch (atoi(q)) {
+ case 0: opt.trunc_hmac = MBEDTLS_SSL_TRUNC_HMAC_DISABLED; break;
+ case 1: opt.trunc_hmac = MBEDTLS_SSL_TRUNC_HMAC_ENABLED; break;
+ default: goto usage;
+ }
+ } else if (strcmp(p, "hs_timeout") == 0) {
+ if ((p = strchr(q, '-')) == NULL) {
+ goto usage;
+ }
+ *p++ = '\0';
+ opt.hs_to_min = atoi(q);
+ opt.hs_to_max = atoi(p);
+ if (opt.hs_to_min == 0 || opt.hs_to_max < opt.hs_to_min) {
+ goto usage;
+ }
+ } else if (strcmp(p, "mtu") == 0) {
+ opt.dtls_mtu = atoi(q);
+ if (opt.dtls_mtu < 0) {
+ goto usage;
+ }
+ } else if (strcmp(p, "dgram_packing") == 0) {
+ opt.dgram_packing = atoi(q);
+ if (opt.dgram_packing != 0 &&
+ opt.dgram_packing != 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "recsplit") == 0) {
+ opt.recsplit = atoi(q);
+ if (opt.recsplit < 0 || opt.recsplit > 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "dhmlen") == 0) {
+ opt.dhmlen = atoi(q);
+ if (opt.dhmlen < 0) {
+ goto usage;
+ }
+ } else if (strcmp(p, "query_config") == 0) {
+ opt.query_config_mode = 1;
+ query_config_ret = query_config(q);
+ goto exit;
+ } else if (strcmp(p, "serialize") == 0) {
+ opt.serialize = atoi(q);
+ if (opt.serialize < 0 || opt.serialize > 2) {
+ goto usage;
+ }
+ } else if (strcmp(p, "context_file") == 0) {
+ opt.context_file = q;
+ } else if (strcmp(p, "eap_tls") == 0) {
+ opt.eap_tls = atoi(q);
+ if (opt.eap_tls < 0 || opt.eap_tls > 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "reproducible") == 0) {
+ opt.reproducible = 1;
+ } else if (strcmp(p, "nss_keylog") == 0) {
+ opt.nss_keylog = atoi(q);
+ if (opt.nss_keylog < 0 || opt.nss_keylog > 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "nss_keylog_file") == 0) {
+ opt.nss_keylog_file = q;
+ } else if (strcmp(p, "skip_close_notify") == 0) {
+ opt.skip_close_notify = atoi(q);
+ if (opt.skip_close_notify < 0 || opt.skip_close_notify > 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "use_srtp") == 0) {
+ opt.use_srtp = atoi(q);
+ } else if (strcmp(p, "srtp_force_profile") == 0) {
+ opt.force_srtp_profile = atoi(q);
+ } else if (strcmp(p, "mki") == 0) {
+ opt.mki = q;
+ } else if (strcmp(p, "key_opaque_algs") == 0) {
+ if (key_opaque_alg_parse(q, &opt.key_opaque_alg1,
+ &opt.key_opaque_alg2) != 0) {
+ goto usage;
+ }
+ } else {
+ /* This signals that the problem is with p not q */
+ q = NULL;
+ goto usage;
+ }
+ }
+ /* This signals that any further errors are not with a single option */
+ p = q = NULL;
+
+ if (opt.nss_keylog != 0 && opt.eap_tls != 0) {
+ mbedtls_printf("Error: eap_tls and nss_keylog options cannot be used together.\n");
+ goto usage;
+ }
+
+ /* Event-driven IO is incompatible with the above custom
+ * receive and send functions, as the polling builds on
+ * refers to the underlying net_context. */
+ if (opt.event == 1 && opt.nbio != 1) {
+ mbedtls_printf("Warning: event-driven IO mandates nbio=1 - overwrite\n");
+ opt.nbio = 1;
+ }
+
+#if defined(MBEDTLS_DEBUG_C)
+ mbedtls_debug_set_threshold(opt.debug_level);
+#endif
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED)
+ /*
+ * Unhexify the pre-shared key if any is given
+ */
+ if (strlen(opt.psk)) {
+ if (mbedtls_test_unhexify(psk, sizeof(psk),
+ opt.psk, &psk_len) != 0) {
+ mbedtls_printf("pre-shared key not valid\n");
+ goto exit;
+ }
+ }
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED */
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ if (opt.psk_opaque != 0) {
+ if (opt.psk == NULL) {
+ mbedtls_printf("psk_opaque set but no psk to be imported specified.\n");
+ ret = 2;
+ goto usage;
+ }
+
+ if (opt.force_ciphersuite[0] <= 0) {
+ mbedtls_printf(
+ "opaque PSKs are only supported in conjunction with forcing TLS 1.2 and a PSK-only ciphersuite through the 'force_ciphersuite' option.\n");
+ ret = 2;
+ goto usage;
+ }
+ }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ if (opt.force_ciphersuite[0] > 0) {
+ const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
+ ciphersuite_info =
+ mbedtls_ssl_ciphersuite_from_id(opt.force_ciphersuite[0]);
+
+ if (opt.max_version != -1 &&
+ ciphersuite_info->min_tls_version > opt.max_version) {
+ mbedtls_printf("forced ciphersuite not allowed with this protocol version\n");
+ ret = 2;
+ goto usage;
+ }
+ if (opt.min_version != -1 &&
+ ciphersuite_info->max_tls_version < opt.min_version) {
+ mbedtls_printf("forced ciphersuite not allowed with this protocol version\n");
+ ret = 2;
+ goto usage;
+ }
+
+ /* If the server selects a version that's not supported by
+ * this suite, then there will be no common ciphersuite... */
+ if (opt.max_version == -1 ||
+ opt.max_version > ciphersuite_info->max_tls_version) {
+ opt.max_version = ciphersuite_info->max_tls_version;
+ }
+ if (opt.min_version < ciphersuite_info->min_tls_version) {
+ opt.min_version = ciphersuite_info->min_tls_version;
+ /* DTLS starts with TLS 1.2 */
+ if (opt.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+ opt.min_version < MBEDTLS_SSL_VERSION_TLS1_2) {
+ opt.min_version = MBEDTLS_SSL_VERSION_TLS1_2;
+ }
+ }
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED)
+ if (opt.psk_opaque != 0) {
+ /* Determine KDF algorithm the opaque PSK will be used in. */
+#if defined(MBEDTLS_MD_CAN_SHA384)
+ if (ciphersuite_info->mac == MBEDTLS_MD_SHA384) {
+ alg = PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_384);
+ } else
+#endif /* MBEDTLS_MD_CAN_SHA384 */
+ alg = PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256);
+ }
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED */
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+ }
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+ if (mbedtls_test_unhexify(cid, sizeof(cid),
+ opt.cid_val, &cid_len) != 0) {
+ mbedtls_printf("CID not valid\n");
+ goto exit;
+ }
+
+ /* Keep CID settings for renegotiation unless
+ * specified otherwise. */
+ if (opt.cid_enabled_renego == DFL_CID_ENABLED_RENEGO) {
+ opt.cid_enabled_renego = opt.cid_enabled;
+ }
+ if (opt.cid_val_renego == DFL_CID_VALUE_RENEGO) {
+ opt.cid_val_renego = opt.cid_val;
+ }
+
+ if (mbedtls_test_unhexify(cid_renego, sizeof(cid_renego),
+ opt.cid_val_renego, &cid_renego_len) != 0) {
+ mbedtls_printf("CID not valid\n");
+ goto exit;
+ }
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+
+ if (opt.groups != NULL) {
+ if (parse_groups(opt.groups, group_list, GROUP_LIST_SIZE) != 0) {
+ goto exit;
+ }
+ }
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ if (opt.sig_algs != NULL) {
+ p = (char *) opt.sig_algs;
+ i = 0;
+
+ /* Leave room for a final MBEDTLS_TLS1_3_SIG_NONE in signature algorithm list (sig_alg_list). */
+ while (i < SIG_ALG_LIST_SIZE - 1 && *p != '\0') {
+ q = p;
+
+ /* Terminate the current string */
+ while (*p != ',' && *p != '\0') {
+ p++;
+ }
+ if (*p == ',') {
+ *p++ = '\0';
+ }
+
+ if (strcmp(q, "rsa_pkcs1_sha256") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_RSA_PKCS1_SHA256;
+ } else if (strcmp(q, "rsa_pkcs1_sha384") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_RSA_PKCS1_SHA384;
+ } else if (strcmp(q, "rsa_pkcs1_sha512") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_RSA_PKCS1_SHA512;
+ } else if (strcmp(q, "ecdsa_secp256r1_sha256") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_ECDSA_SECP256R1_SHA256;
+ } else if (strcmp(q, "ecdsa_secp384r1_sha384") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_ECDSA_SECP384R1_SHA384;
+ } else if (strcmp(q, "ecdsa_secp521r1_sha512") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_ECDSA_SECP521R1_SHA512;
+ } else if (strcmp(q, "rsa_pss_rsae_sha256") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_RSA_PSS_RSAE_SHA256;
+ } else if (strcmp(q, "rsa_pss_rsae_sha384") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_RSA_PSS_RSAE_SHA384;
+ } else if (strcmp(q, "rsa_pss_rsae_sha512") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_RSA_PSS_RSAE_SHA512;
+ } else if (strcmp(q, "ed25519") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_ED25519;
+ } else if (strcmp(q, "ed448") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_ED448;
+ } else if (strcmp(q, "rsa_pss_pss_sha256") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_RSA_PSS_PSS_SHA256;
+ } else if (strcmp(q, "rsa_pss_pss_sha384") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_RSA_PSS_PSS_SHA384;
+ } else if (strcmp(q, "rsa_pss_pss_sha512") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_RSA_PSS_PSS_SHA512;
+ } else if (strcmp(q, "rsa_pkcs1_sha1") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_RSA_PKCS1_SHA1;
+ } else if (strcmp(q, "ecdsa_sha1") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_ECDSA_SHA1;
+ } else {
+ ret = -1;
+ mbedtls_printf("unknown signature algorithm \"%s\"\n", q);
+ mbedtls_print_supported_sig_algs();
+ goto exit;
+ }
+ }
+
+ if (i == (SIG_ALG_LIST_SIZE - 1) && *p != '\0') {
+ mbedtls_printf("signature algorithm list too long, maximum %d",
+ SIG_ALG_LIST_SIZE - 1);
+ goto exit;
+ }
+
+ sig_alg_list[i] = MBEDTLS_TLS1_3_SIG_NONE;
+ }
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+
+#if defined(MBEDTLS_SSL_ALPN)
+ if (opt.alpn_string != NULL) {
+ p = (char *) opt.alpn_string;
+ i = 0;
+
+ /* Leave room for a final NULL in alpn_list */
+ while (i < ALPN_LIST_SIZE - 1 && *p != '\0') {
+ alpn_list[i++] = p;
+
+ /* Terminate the current string and move on to next one */
+ while (*p != ',' && *p != '\0') {
+ p++;
+ }
+ if (*p == ',') {
+ *p++ = '\0';
+ }
+ }
+ }
+#endif /* MBEDTLS_SSL_ALPN */
+
+ mbedtls_printf("build version: %s (build %d)\n",
+ MBEDTLS_VERSION_STRING_FULL, MBEDTLS_VERSION_NUMBER);
+
+ /*
+ * 0. Initialize the RNG and the session data
+ */
+ mbedtls_printf("\n . Seeding the random number generator...");
+ fflush(stdout);
+
+ ret = rng_seed(&rng, opt.reproducible, pers);
+ if (ret != 0) {
+ goto exit;
+ }
+ mbedtls_printf(" ok\n");
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ /*
+ * 1.1. Load the trusted CA
+ */
+ mbedtls_printf(" . Loading the CA root certificate ...");
+ fflush(stdout);
+
+ if (strcmp(opt.ca_path, "none") == 0 ||
+ strcmp(opt.ca_file, "none") == 0) {
+ ret = 0;
+ } else
+#if defined(MBEDTLS_FS_IO)
+ if (strlen(opt.ca_path)) {
+ ret = mbedtls_x509_crt_parse_path(&cacert, opt.ca_path);
+ } else if (strlen(opt.ca_file)) {
+ ret = mbedtls_x509_crt_parse_file(&cacert, opt.ca_file);
+ } else
+#endif
+ {
+#if defined(MBEDTLS_PEM_PARSE_C)
+ for (i = 0; mbedtls_test_cas[i] != NULL; i++) {
+ ret = mbedtls_x509_crt_parse(&cacert,
+ (const unsigned char *) mbedtls_test_cas[i],
+ mbedtls_test_cas_len[i]);
+ if (ret != 0) {
+ break;
+ }
+ }
+#endif /* MBEDTLS_PEM_PARSE_C */
+ if (ret == 0) {
+ for (i = 0; mbedtls_test_cas_der[i] != NULL; i++) {
+ ret = mbedtls_x509_crt_parse_der(&cacert,
+ (const unsigned char *) mbedtls_test_cas_der[i],
+ mbedtls_test_cas_der_len[i]);
+ if (ret != 0) {
+ break;
+ }
+ }
+ }
+ }
+ if (ret < 0) {
+ mbedtls_printf(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok (%d skipped)\n", ret);
+
+ /*
+ * 1.2. Load own certificate and private key
+ *
+ * (can be skipped if client authentication is not required)
+ */
+ mbedtls_printf(" . Loading the client cert. and key...");
+ fflush(stdout);
+
+ if (strcmp(opt.crt_file, "none") == 0) {
+ ret = 0;
+ } else
+#if defined(MBEDTLS_FS_IO)
+ if (strlen(opt.crt_file)) {
+ ret = mbedtls_x509_crt_parse_file(&clicert, opt.crt_file);
+ } else
+#endif
+ { ret = mbedtls_x509_crt_parse(&clicert,
+ (const unsigned char *) mbedtls_test_cli_crt,
+ mbedtls_test_cli_crt_len); }
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ if (strcmp(opt.key_file, "none") == 0) {
+ ret = 0;
+ } else
+#if defined(MBEDTLS_FS_IO)
+ if (strlen(opt.key_file)) {
+ ret = mbedtls_pk_parse_keyfile(&pkey, opt.key_file, opt.key_pwd, rng_get, &rng);
+ } else
+#endif
+ { ret = mbedtls_pk_parse_key(&pkey,
+ (const unsigned char *) mbedtls_test_cli_key,
+ mbedtls_test_cli_key_len, NULL, 0, rng_get, &rng); }
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_pk_parse_key returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ if (opt.key_opaque != 0) {
+ psa_algorithm_t psa_alg, psa_alg2 = PSA_ALG_NONE;
+ psa_key_usage_t usage = 0;
+
+ if (key_opaque_set_alg_usage(opt.key_opaque_alg1,
+ opt.key_opaque_alg2,
+ &psa_alg, &psa_alg2,
+ &usage,
+ mbedtls_pk_get_type(&pkey)) == 0) {
+ ret = pk_wrap_as_opaque(&pkey, psa_alg, psa_alg2, usage, &key_slot);
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! "
+ "mbedtls_pk_get_psa_attributes returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ }
+ }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ mbedtls_printf(" ok (key type: %s)\n",
+ strlen(opt.key_file) || strlen(opt.key_opaque_alg1) ?
+ mbedtls_pk_get_name(&pkey) : "none");
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+
+ /*
+ * 2. Setup stuff
+ */
+ mbedtls_printf(" . Setting up the SSL/TLS structure...");
+ fflush(stdout);
+
+ if ((ret = mbedtls_ssl_config_defaults(&conf,
+ MBEDTLS_SSL_IS_CLIENT,
+ opt.transport,
+ MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_config_defaults returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ /* The default algorithms profile disables SHA-1, but our tests still
+ rely on it heavily. */
+ if (opt.allow_sha1 > 0) {
+ crt_profile_for_test.allowed_mds |= MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1);
+ mbedtls_ssl_conf_cert_profile(&conf, &crt_profile_for_test);
+ mbedtls_ssl_conf_sig_algs(&conf, ssl_sig_algs_for_test);
+ }
+ if (opt.context_crt_cb == 0) {
+ mbedtls_ssl_conf_verify(&conf, my_verify, NULL);
+ }
+
+ memset(peer_crt_info, 0, sizeof(peer_crt_info));
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+ if (opt.cid_enabled == 1 || opt.cid_enabled_renego == 1) {
+ if (opt.cid_enabled == 1 &&
+ opt.cid_enabled_renego == 1 &&
+ cid_len != cid_renego_len) {
+ mbedtls_printf("CID length must not change during renegotiation\n");
+ goto usage;
+ }
+
+ if (opt.cid_enabled == 1) {
+ ret = mbedtls_ssl_conf_cid(&conf, cid_len,
+ MBEDTLS_SSL_UNEXPECTED_CID_IGNORE);
+ } else {
+ ret = mbedtls_ssl_conf_cid(&conf, cid_renego_len,
+ MBEDTLS_SSL_UNEXPECTED_CID_IGNORE);
+ }
+
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_conf_cid_len returned -%#04x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ }
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+
+ if (opt.auth_mode != DFL_AUTH_MODE) {
+ mbedtls_ssl_conf_authmode(&conf, opt.auth_mode);
+ }
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if (opt.hs_to_min != DFL_HS_TO_MIN || opt.hs_to_max != DFL_HS_TO_MAX) {
+ mbedtls_ssl_conf_handshake_timeout(&conf, opt.hs_to_min,
+ opt.hs_to_max);
+ }
+
+ if (opt.dgram_packing != DFL_DGRAM_PACKING) {
+ mbedtls_ssl_set_datagram_packing(&ssl, opt.dgram_packing);
+ }
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
+#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+ if ((ret = mbedtls_ssl_conf_max_frag_len(&conf, opt.mfl_code)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_conf_max_frag_len returned %d\n\n",
+ ret);
+ goto exit;
+ }
+#endif
+
+#if defined(MBEDTLS_SSL_DTLS_SRTP)
+ const mbedtls_ssl_srtp_profile forced_profile[] =
+ { opt.force_srtp_profile, MBEDTLS_TLS_SRTP_UNSET };
+ if (opt.use_srtp == 1) {
+ if (opt.force_srtp_profile != 0) {
+ ret = mbedtls_ssl_conf_dtls_srtp_protection_profiles(&conf, forced_profile);
+ } else {
+ ret = mbedtls_ssl_conf_dtls_srtp_protection_profiles(&conf, default_profiles);
+ }
+
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! "
+ "mbedtls_ssl_conf_dtls_srtp_protection_profiles returned %d\n\n",
+ ret);
+ goto exit;
+ }
+
+ } else if (opt.force_srtp_profile != 0) {
+ mbedtls_printf(" failed\n ! must enable use_srtp to force srtp profile\n\n");
+ goto exit;
+ }
+#endif /* MBEDTLS_SSL_DTLS_SRTP */
+
+#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
+ if (opt.extended_ms != DFL_EXTENDED_MS) {
+ mbedtls_ssl_conf_extended_master_secret(&conf, opt.extended_ms);
+ }
+#endif
+
+#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+ if (opt.etm != DFL_ETM) {
+ mbedtls_ssl_conf_encrypt_then_mac(&conf, opt.etm);
+ }
+#endif
+
+#if defined(MBEDTLS_DHM_C)
+ if (opt.dhmlen != DFL_DHMLEN) {
+ mbedtls_ssl_conf_dhm_min_bitlen(&conf, opt.dhmlen);
+ }
+#endif
+
+#if defined(MBEDTLS_SSL_ALPN)
+ if (opt.alpn_string != NULL) {
+ if ((ret = mbedtls_ssl_conf_alpn_protocols(&conf, alpn_list)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_conf_alpn_protocols returned %d\n\n",
+ ret);
+ goto exit;
+ }
+ }
+#endif
+
+ if (opt.reproducible) {
+#if defined(MBEDTLS_HAVE_TIME)
+#if defined(MBEDTLS_PLATFORM_TIME_ALT)
+ mbedtls_platform_set_time(dummy_constant_time);
+#else
+ fprintf(stderr, "Warning: reproducible option used without constant time\n");
+#endif
+#endif /* MBEDTLS_HAVE_TIME */
+ }
+ mbedtls_ssl_conf_rng(&conf, rng_get, &rng);
+ mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
+
+ mbedtls_ssl_conf_read_timeout(&conf, opt.read_timeout);
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+ mbedtls_ssl_conf_session_tickets(&conf, opt.tickets);
+#endif
+
+ if (opt.force_ciphersuite[0] != DFL_FORCE_CIPHER) {
+ mbedtls_ssl_conf_ciphersuites(&conf, opt.force_ciphersuite);
+ }
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ mbedtls_ssl_conf_tls13_key_exchange_modes(&conf, opt.tls13_kex_modes);
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+
+ if (opt.allow_legacy != DFL_ALLOW_LEGACY) {
+ mbedtls_ssl_conf_legacy_renegotiation(&conf, opt.allow_legacy);
+ }
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+ mbedtls_ssl_conf_renegotiation(&conf, opt.renegotiation);
+#endif
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ if (strcmp(opt.ca_path, "none") != 0 &&
+ strcmp(opt.ca_file, "none") != 0) {
+#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
+ if (opt.ca_callback != 0) {
+ mbedtls_ssl_conf_ca_cb(&conf, ca_callback, &cacert);
+ } else
+#endif
+ mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
+ }
+ if (strcmp(opt.crt_file, "none") != 0 &&
+ strcmp(opt.key_file, "none") != 0) {
+ if ((ret = mbedtls_ssl_conf_own_cert(&conf, &clicert, &pkey)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n",
+ ret);
+ goto exit;
+ }
+ }
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+
+#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) || \
+ (defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_EPHEMERAL_ENABLED) && \
+ defined(PSA_WANT_ALG_FFDH))
+ if (opt.groups != NULL &&
+ strcmp(opt.groups, "default") != 0) {
+ mbedtls_ssl_conf_groups(&conf, group_list);
+ }
+#endif
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ if (opt.sig_algs != NULL) {
+ mbedtls_ssl_conf_sig_algs(&conf, sig_alg_list);
+ }
+#endif
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED)
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ if (opt.psk_opaque != 0) {
+ key_attributes = psa_key_attributes_init();
+ psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_DERIVE);
+ psa_set_key_algorithm(&key_attributes, alg);
+ psa_set_key_type(&key_attributes, PSA_KEY_TYPE_DERIVE);
+
+ status = psa_import_key(&key_attributes, psk, psk_len, &slot);
+ if (status != PSA_SUCCESS) {
+ ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
+ goto exit;
+ }
+
+ if ((ret = mbedtls_ssl_conf_psk_opaque(&conf, slot,
+ (const unsigned char *) opt.psk_identity,
+ strlen(opt.psk_identity))) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_conf_psk_opaque returned %d\n\n",
+ ret);
+ goto exit;
+ }
+ } else
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+ if (psk_len > 0) {
+ ret = mbedtls_ssl_conf_psk(&conf, psk, psk_len,
+ (const unsigned char *) opt.psk_identity,
+ strlen(opt.psk_identity));
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_conf_psk returned %d\n\n", ret);
+ goto exit;
+ }
+ }
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED */
+
+ if (opt.min_version != DFL_MIN_VERSION) {
+ mbedtls_ssl_conf_min_tls_version(&conf, opt.min_version);
+ }
+
+ if (opt.max_version != DFL_MAX_VERSION) {
+ mbedtls_ssl_conf_max_tls_version(&conf, opt.max_version);
+ }
+
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+ if (opt.early_data != DFL_EARLY_DATA) {
+ mbedtls_ssl_conf_early_data(&conf, opt.early_data);
+ }
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
+ if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_setup returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ if (opt.eap_tls != 0) {
+ mbedtls_ssl_set_export_keys_cb(&ssl, eap_tls_key_derivation,
+ &eap_tls_keying);
+ } else if (opt.nss_keylog != 0) {
+ mbedtls_ssl_set_export_keys_cb(&ssl,
+ nss_keylog_export,
+ NULL);
+ }
+#if defined(MBEDTLS_SSL_DTLS_SRTP)
+ else if (opt.use_srtp != 0) {
+ mbedtls_ssl_set_export_keys_cb(&ssl, dtls_srtp_key_derivation,
+ &dtls_srtp_keying);
+ }
+#endif /* MBEDTLS_SSL_DTLS_SRTP */
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ if ((ret = mbedtls_ssl_set_hostname(&ssl, opt.server_name)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n",
+ ret);
+ goto exit;
+ }
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+ if (opt.ecjpake_pw != DFL_ECJPAKE_PW) {
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ if (opt.ecjpake_pw_opaque != DFL_ECJPAKE_PW_OPAQUE) {
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+ psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
+ psa_set_key_algorithm(&attributes, PSA_ALG_JPAKE);
+ psa_set_key_type(&attributes, PSA_KEY_TYPE_PASSWORD);
+
+ status = psa_import_key(&attributes,
+ (const unsigned char *) opt.ecjpake_pw,
+ strlen(opt.ecjpake_pw),
+ &ecjpake_pw_slot);
+ if (status != PSA_SUCCESS) {
+ mbedtls_printf(" failed\n ! psa_import_key returned %d\n\n",
+ status);
+ goto exit;
+ }
+ if ((ret = mbedtls_ssl_set_hs_ecjpake_password_opaque(&ssl,
+ ecjpake_pw_slot)) != 0) {
+ mbedtls_printf(
+ " failed\n ! mbedtls_ssl_set_hs_ecjpake_password_opaque returned %d\n\n",
+ ret);
+ goto exit;
+ }
+ mbedtls_printf("using opaque password\n");
+ } else
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+ {
+ if ((ret = mbedtls_ssl_set_hs_ecjpake_password(&ssl,
+ (const unsigned char *) opt.ecjpake_pw,
+ strlen(opt.ecjpake_pw))) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_set_hs_ecjpake_password returned %d\n\n",
+ ret);
+ goto exit;
+ }
+ }
+ }
+#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ if (opt.context_crt_cb == 1) {
+ mbedtls_ssl_set_verify(&ssl, my_verify, NULL);
+ }
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+
+ io_ctx.ssl = &ssl;
+ io_ctx.net = &server_fd;
+ mbedtls_ssl_set_bio(&ssl, &io_ctx, send_cb, recv_cb,
+ opt.nbio == 0 ? recv_timeout_cb : NULL);
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+ if (opt.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
+ if ((ret = mbedtls_ssl_set_cid(&ssl, opt.cid_enabled,
+ cid, cid_len)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_set_cid returned %d\n\n",
+ ret);
+ goto exit;
+ }
+ }
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if (opt.dtls_mtu != DFL_DTLS_MTU) {
+ mbedtls_ssl_set_mtu(&ssl, opt.dtls_mtu);
+ }
+#endif
+
+#if defined(MBEDTLS_TIMING_C)
+ mbedtls_ssl_set_timer_cb(&ssl, &timer, mbedtls_timing_set_delay,
+ mbedtls_timing_get_delay);
+#endif
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+ if (opt.ec_max_ops != DFL_EC_MAX_OPS) {
+ mbedtls_ecp_set_max_ops(opt.ec_max_ops);
+ }
+#endif
+
+#if defined(MBEDTLS_SSL_DTLS_SRTP)
+ if (opt.use_srtp != 0 && strlen(opt.mki) != 0) {
+ if (mbedtls_test_unhexify(mki, sizeof(mki),
+ opt.mki, &mki_len) != 0) {
+ mbedtls_printf("mki value not valid hex\n");
+ goto exit;
+ }
+
+ mbedtls_ssl_conf_srtp_mki_value_supported(&conf, MBEDTLS_SSL_DTLS_SRTP_MKI_SUPPORTED);
+ if ((ret = mbedtls_ssl_dtls_srtp_set_mki_value(&ssl, mki,
+ (uint16_t) strlen(opt.mki) / 2)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_dtls_srtp_set_mki_value returned %d\n\n", ret);
+ goto exit;
+ }
+ }
+#endif
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 3. Start the connection
+ */
+ if (opt.server_addr == NULL) {
+ opt.server_addr = opt.server_name;
+ }
+
+ mbedtls_printf(" . Connecting to %s/%s/%s...",
+ opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM ? "tcp" : "udp",
+ opt.server_addr, opt.server_port);
+ fflush(stdout);
+
+ if ((ret = mbedtls_net_connect(&server_fd,
+ opt.server_addr, opt.server_port,
+ opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM ?
+ MBEDTLS_NET_PROTO_TCP : MBEDTLS_NET_PROTO_UDP)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_net_connect returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ if (opt.nbio > 0) {
+ ret = mbedtls_net_set_nonblock(&server_fd);
+ } else {
+ ret = mbedtls_net_set_block(&server_fd);
+ }
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! net_set_(non)block() returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 4. Handshake
+ */
+ mbedtls_printf(" . Performing the SSL/TLS handshake...");
+ fflush(stdout);
+
+ while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
+ ret != MBEDTLS_ERR_SSL_WANT_WRITE &&
+ ret != MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n",
+ (unsigned int) -ret);
+ if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
+ mbedtls_printf(
+ " Unable to verify the server's certificate. "
+ "Either it is invalid,\n"
+ " or you didn't set ca_file or ca_path "
+ "to an appropriate value.\n"
+ " Alternatively, you may want to use "
+ "auth_mode=optional for testing purposes if "
+ "not using TLS 1.3.\n"
+ " For TLS 1.3 server, try `ca_path=/etc/ssl/certs/`"
+ "or other folder that has root certificates\n");
+ }
+ mbedtls_printf("\n");
+ goto exit;
+ }
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+ if (ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) {
+ continue;
+ }
+#endif
+
+ /* For event-driven IO, wait for socket to become available */
+ if (opt.event == 1 /* level triggered IO */) {
+#if defined(MBEDTLS_TIMING_C)
+ ret = idle(&server_fd, &timer, ret);
+#else
+ ret = idle(&server_fd, ret);
+#endif
+ if (ret != 0) {
+ goto exit;
+ }
+ }
+ }
+
+ {
+ int suite_id = mbedtls_ssl_get_ciphersuite_id_from_ssl(&ssl);
+ const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
+ ciphersuite_info = mbedtls_ssl_ciphersuite_from_id(suite_id);
+
+ mbedtls_printf(" ok\n [ Protocol is %s ]\n"
+ " [ Ciphersuite is %s ]\n"
+ " [ Key size is %u ]\n",
+ mbedtls_ssl_get_version(&ssl),
+ mbedtls_ssl_ciphersuite_get_name(ciphersuite_info),
+ (unsigned int)
+ mbedtls_ssl_ciphersuite_get_cipher_key_bitlen(ciphersuite_info));
+ }
+
+ if ((ret = mbedtls_ssl_get_record_expansion(&ssl)) >= 0) {
+ mbedtls_printf(" [ Record expansion is %d ]\n", ret);
+ } else {
+ mbedtls_printf(" [ Record expansion is unknown ]\n");
+ }
+
+#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+ mbedtls_printf(" [ Maximum incoming record payload length is %u ]\n",
+ (unsigned int) mbedtls_ssl_get_max_in_record_payload(&ssl));
+ mbedtls_printf(" [ Maximum outgoing record payload length is %u ]\n",
+ (unsigned int) mbedtls_ssl_get_max_out_record_payload(&ssl));
+#endif
+
+#if defined(MBEDTLS_SSL_ALPN)
+ if (opt.alpn_string != NULL) {
+ const char *alp = mbedtls_ssl_get_alpn_protocol(&ssl);
+ mbedtls_printf(" [ Application Layer Protocol is %s ]\n",
+ alp ? alp : "(none)");
+ }
+#endif
+
+ if (opt.eap_tls != 0) {
+ size_t j = 0;
+
+ if ((ret = mbedtls_ssl_tls_prf(eap_tls_keying.tls_prf_type,
+ eap_tls_keying.master_secret,
+ sizeof(eap_tls_keying.master_secret),
+ eap_tls_label,
+ eap_tls_keying.randbytes,
+ sizeof(eap_tls_keying.randbytes),
+ eap_tls_keymaterial,
+ sizeof(eap_tls_keymaterial)))
+ != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_tls_prf returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" EAP-TLS key material is:");
+ for (j = 0; j < sizeof(eap_tls_keymaterial); j++) {
+ if (j % 8 == 0) {
+ mbedtls_printf("\n ");
+ }
+ mbedtls_printf("%02x ", eap_tls_keymaterial[j]);
+ }
+ mbedtls_printf("\n");
+
+ if ((ret = mbedtls_ssl_tls_prf(eap_tls_keying.tls_prf_type, NULL, 0,
+ eap_tls_label,
+ eap_tls_keying.randbytes,
+ sizeof(eap_tls_keying.randbytes),
+ eap_tls_iv,
+ sizeof(eap_tls_iv))) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_tls_prf returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" EAP-TLS IV is:");
+ for (j = 0; j < sizeof(eap_tls_iv); j++) {
+ if (j % 8 == 0) {
+ mbedtls_printf("\n ");
+ }
+ mbedtls_printf("%02x ", eap_tls_iv[j]);
+ }
+ mbedtls_printf("\n");
+ }
+
+#if defined(MBEDTLS_SSL_DTLS_SRTP)
+ else if (opt.use_srtp != 0) {
+ size_t j = 0;
+ mbedtls_dtls_srtp_info dtls_srtp_negotiation_result;
+ mbedtls_ssl_get_dtls_srtp_negotiation_result(&ssl, &dtls_srtp_negotiation_result);
+
+ if (dtls_srtp_negotiation_result.chosen_dtls_srtp_profile
+ == MBEDTLS_TLS_SRTP_UNSET) {
+ mbedtls_printf(" Unable to negotiate "
+ "the use of DTLS-SRTP\n");
+ } else {
+ if ((ret = mbedtls_ssl_tls_prf(dtls_srtp_keying.tls_prf_type,
+ dtls_srtp_keying.master_secret,
+ sizeof(dtls_srtp_keying.master_secret),
+ dtls_srtp_label,
+ dtls_srtp_keying.randbytes,
+ sizeof(dtls_srtp_keying.randbytes),
+ dtls_srtp_key_material,
+ sizeof(dtls_srtp_key_material)))
+ != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_tls_prf returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" DTLS-SRTP key material is:");
+ for (j = 0; j < sizeof(dtls_srtp_key_material); j++) {
+ if (j % 8 == 0) {
+ mbedtls_printf("\n ");
+ }
+ mbedtls_printf("%02x ", dtls_srtp_key_material[j]);
+ }
+ mbedtls_printf("\n");
+
+ /* produce a less readable output used to perform automatic checks
+ * - compare client and server output
+ * - interop test with openssl which client produces this kind of output
+ */
+ mbedtls_printf(" Keying material: ");
+ for (j = 0; j < sizeof(dtls_srtp_key_material); j++) {
+ mbedtls_printf("%02X", dtls_srtp_key_material[j]);
+ }
+ mbedtls_printf("\n");
+
+ if (dtls_srtp_negotiation_result.mki_len > 0) {
+ mbedtls_printf(" DTLS-SRTP mki value: ");
+ for (j = 0; j < dtls_srtp_negotiation_result.mki_len; j++) {
+ mbedtls_printf("%02X", dtls_srtp_negotiation_result.mki_value[j]);
+ }
+ } else {
+ mbedtls_printf(" DTLS-SRTP no mki value negotiated");
+ }
+ mbedtls_printf("\n");
+ }
+ }
+#endif /* MBEDTLS_SSL_DTLS_SRTP */
+ if (opt.reconnect != 0 && ssl.tls_version != MBEDTLS_SSL_VERSION_TLS1_3) {
+ mbedtls_printf(" . Saving session for reuse...");
+ fflush(stdout);
+
+ if (opt.reco_mode == 1) {
+ if ((ret = ssl_save_session_serialize(&ssl,
+ &session_data, &session_data_len)) != 0) {
+ mbedtls_printf(" failed\n ! ssl_save_session_serialize returned -0x%04x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ } else {
+ if ((ret = mbedtls_ssl_get_session(&ssl, &saved_session)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_get_session returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ }
+
+ mbedtls_printf(" ok\n");
+
+ if (opt.reco_mode == 1) {
+ mbedtls_printf(" [ Saved %u bytes of session data]\n",
+ (unsigned) session_data_len);
+ }
+ }
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ /*
+ * 5. Verify the server certificate
+ */
+ mbedtls_printf(" . Verifying peer X.509 certificate...");
+
+ if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) {
+ char vrfy_buf[512];
+ mbedtls_printf(" failed\n");
+
+ x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf),
+ " ! ", flags);
+
+ mbedtls_printf("%s\n", vrfy_buf);
+ } else {
+ mbedtls_printf(" ok\n");
+ }
+
+#if !defined(MBEDTLS_X509_REMOVE_INFO)
+ mbedtls_printf(" . Peer certificate information ...\n");
+ mbedtls_printf("%s\n", peer_crt_info);
+#endif /* !MBEDTLS_X509_REMOVE_INFO */
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+ ret = report_cid_usage(&ssl, "initial handshake");
+ if (ret != 0) {
+ goto exit;
+ }
+
+ if (opt.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
+ if ((ret = mbedtls_ssl_set_cid(&ssl, opt.cid_enabled_renego,
+ cid_renego,
+ cid_renego_len)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_set_cid returned %d\n\n",
+ ret);
+ goto exit;
+ }
+ }
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+ if (opt.renegotiate) {
+ /*
+ * Perform renegotiation (this must be done when the server is waiting
+ * for input from our side).
+ */
+ mbedtls_printf(" . Performing renegotiation...");
+ fflush(stdout);
+ while ((ret = mbedtls_ssl_renegotiate(&ssl)) != 0) {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
+ ret != MBEDTLS_ERR_SSL_WANT_WRITE &&
+ ret != MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_renegotiate returned %d\n\n",
+ ret);
+ goto exit;
+ }
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+ if (ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) {
+ continue;
+ }
+#endif
+
+ /* For event-driven IO, wait for socket to become available */
+ if (opt.event == 1 /* level triggered IO */) {
+#if defined(MBEDTLS_TIMING_C)
+ idle(&server_fd, &timer, ret);
+#else
+ idle(&server_fd, ret);
+#endif
+ }
+
+ }
+ mbedtls_printf(" ok\n");
+ }
+#endif /* MBEDTLS_SSL_RENEGOTIATION */
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+ ret = report_cid_usage(&ssl, "after renegotiation");
+ if (ret != 0) {
+ goto exit;
+ }
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+
+ /*
+ * 6. Write the GET request
+ */
+ retry_left = opt.max_resend;
+send_request:
+ mbedtls_printf(" > Write to server:");
+ fflush(stdout);
+
+ ret = build_http_request(buf, sizeof(buf) - 1, &len);
+ if (ret != 0) {
+ goto exit;
+ }
+
+ if (opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM) {
+ written = 0;
+ frags = 0;
+
+ do {
+ while ((ret = mbedtls_ssl_write(&ssl, buf + written,
+ len - written)) < 0) {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
+ ret != MBEDTLS_ERR_SSL_WANT_WRITE &&
+ ret != MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_write returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ /* For event-driven IO, wait for socket to become available */
+ if (opt.event == 1 /* level triggered IO */) {
+#if defined(MBEDTLS_TIMING_C)
+ idle(&server_fd, &timer, ret);
+#else
+ idle(&server_fd, ret);
+#endif
+ }
+ }
+
+ frags++;
+ written += ret;
+ } while (written < len);
+ } else { /* Not stream, so datagram */
+ while (1) {
+ ret = mbedtls_ssl_write(&ssl, buf, len);
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+ if (ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) {
+ continue;
+ }
+#endif
+
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
+ ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ break;
+ }
+
+ /* For event-driven IO, wait for socket to become available */
+ if (opt.event == 1 /* level triggered IO */) {
+#if defined(MBEDTLS_TIMING_C)
+ idle(&server_fd, &timer, ret);
+#else
+ idle(&server_fd, ret);
+#endif
+ }
+ }
+
+ if (ret < 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_write returned %d\n\n",
+ ret);
+ goto exit;
+ }
+
+ frags = 1;
+ written = ret;
+
+ if (written < len) {
+ mbedtls_printf(" warning\n ! request didn't fit into single datagram and "
+ "was truncated to size %u", (unsigned) written);
+ }
+ }
+
+ buf[written] = '\0';
+ mbedtls_printf(
+ " %" MBEDTLS_PRINTF_SIZET " bytes written in %" MBEDTLS_PRINTF_SIZET " fragments\n\n%s\n",
+ written,
+ frags,
+ (char *) buf);
+
+ /* Send a non-empty request if request_size == 0 */
+ if (len == 0) {
+ opt.request_size = DFL_REQUEST_SIZE;
+ goto send_request;
+ }
+
+ /*
+ * 7. Read the HTTP response
+ */
+
+ /*
+ * TLS and DTLS need different reading styles (stream vs datagram)
+ */
+ if (opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM) {
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS)
+ int ticket_id = 0;
+#endif
+ do {
+ len = sizeof(buf) - 1;
+ memset(buf, 0, sizeof(buf));
+ ret = mbedtls_ssl_read(&ssl, buf, len);
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+ if (ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) {
+ continue;
+ }
+#endif
+
+ if (ret == MBEDTLS_ERR_SSL_WANT_READ ||
+ ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+ /* For event-driven IO, wait for socket to become available */
+ if (opt.event == 1 /* level triggered IO */) {
+#if defined(MBEDTLS_TIMING_C)
+ idle(&server_fd, &timer, ret);
+#else
+ idle(&server_fd, ret);
+#endif
+ }
+ continue;
+ }
+
+ if (ret <= 0) {
+ switch (ret) {
+ case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+ mbedtls_printf(" connection was closed gracefully\n");
+ ret = 0;
+ goto close_notify;
+
+ case 0:
+ case MBEDTLS_ERR_NET_CONN_RESET:
+ mbedtls_printf(" connection was reset by peer\n");
+ ret = 0;
+ goto reconnect;
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+ case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET:
+ /* We were waiting for application data but got
+ * a NewSessionTicket instead. */
+ mbedtls_printf(" got new session ticket ( %d ).\n",
+ ticket_id++);
+ if (opt.reconnect != 0) {
+ mbedtls_printf(" . Saving session for reuse...");
+ fflush(stdout);
+
+ if (opt.reco_mode == 1) {
+ if ((ret = ssl_save_session_serialize(&ssl,
+ &session_data,
+ &session_data_len)) != 0) {
+ mbedtls_printf(
+ " failed\n ! ssl_save_session_serialize returned -0x%04x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ } else {
+ if ((ret = mbedtls_ssl_get_session(&ssl, &saved_session)) != 0) {
+ mbedtls_printf(
+ " failed\n ! mbedtls_ssl_get_session returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ }
+
+ mbedtls_printf(" ok\n");
+
+ if (opt.reco_mode == 1) {
+ mbedtls_printf(" [ Saved %u bytes of session data]\n",
+ (unsigned) session_data_len);
+ }
+ }
+ continue;
+#endif /* MBEDTLS_SSL_SESSION_TICKETS */
+
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+
+ default:
+ mbedtls_printf(" mbedtls_ssl_read returned -0x%x\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ }
+
+ len = ret;
+ buf[len] = '\0';
+ mbedtls_printf(" < Read from server: %" MBEDTLS_PRINTF_SIZET " bytes read\n\n%s",
+ len,
+ (char *) buf);
+ fflush(stdout);
+ /* End of message should be detected according to the syntax of the
+ * application protocol (eg HTTP), just use a dummy test here. */
+ if (ret > 0 && buf[len-1] == '\n') {
+ ret = 0;
+ break;
+ }
+ } while (1);
+ } else { /* Not stream, so datagram */
+ len = sizeof(buf) - 1;
+ memset(buf, 0, sizeof(buf));
+
+ while (1) {
+ ret = mbedtls_ssl_read(&ssl, buf, len);
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+ if (ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) {
+ continue;
+ }
+#endif
+
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
+ ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ break;
+ }
+
+ /* For event-driven IO, wait for socket to become available */
+ if (opt.event == 1 /* level triggered IO */) {
+#if defined(MBEDTLS_TIMING_C)
+ idle(&server_fd, &timer, ret);
+#else
+ idle(&server_fd, ret);
+#endif
+ }
+ }
+
+ if (ret <= 0) {
+ switch (ret) {
+ case MBEDTLS_ERR_SSL_TIMEOUT:
+ mbedtls_printf(" timeout\n");
+ if (retry_left-- > 0) {
+ goto send_request;
+ }
+ goto exit;
+
+ case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+ mbedtls_printf(" connection was closed gracefully\n");
+ ret = 0;
+ goto close_notify;
+
+ default:
+ mbedtls_printf(" mbedtls_ssl_read returned -0x%x\n", (unsigned int) -ret);
+ goto exit;
+ }
+ }
+
+ len = ret;
+ buf[len] = '\0';
+ mbedtls_printf(" < Read from server: %" MBEDTLS_PRINTF_SIZET " bytes read\n\n%s",
+ len,
+ (char *) buf);
+ ret = 0;
+ }
+
+ /*
+ * 7b. Simulate hard reset and reconnect from same port?
+ */
+ if (opt.reconnect_hard != 0) {
+ opt.reconnect_hard = 0;
+
+ mbedtls_printf(" . Restarting connection from same port...");
+ fflush(stdout);
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ memset(peer_crt_info, 0, sizeof(peer_crt_info));
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+
+ if ((ret = mbedtls_ssl_session_reset(&ssl)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_session_reset returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
+ ret != MBEDTLS_ERR_SSL_WANT_WRITE &&
+ ret != MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ /* For event-driven IO, wait for socket to become available */
+ if (opt.event == 1 /* level triggered IO */) {
+#if defined(MBEDTLS_TIMING_C)
+ idle(&server_fd, &timer, ret);
+#else
+ idle(&server_fd, ret);
+#endif
+ }
+ }
+
+ mbedtls_printf(" ok\n");
+
+ goto send_request;
+ }
+
+ /*
+ * 7c. Simulate serialize/deserialize and go back to data exchange
+ */
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+ if (opt.serialize != 0) {
+ size_t buf_len;
+
+ mbedtls_printf(" . Serializing live connection...");
+
+ ret = mbedtls_ssl_context_save(&ssl, NULL, 0, &buf_len);
+ if (ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_context_save returned "
+ "-0x%x\n\n", (unsigned int) -ret);
+
+ goto exit;
+ }
+
+ if ((context_buf = mbedtls_calloc(1, buf_len)) == NULL) {
+ mbedtls_printf(" failed\n ! Couldn't allocate buffer for "
+ "serialized context");
+
+ goto exit;
+ }
+ context_buf_len = buf_len;
+
+ if ((ret = mbedtls_ssl_context_save(&ssl, context_buf,
+ buf_len, &buf_len)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_context_save returned "
+ "-0x%x\n\n", (unsigned int) -ret);
+
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /* Save serialized context to the 'opt.context_file' as a base64 code */
+ if (0 < strlen(opt.context_file)) {
+ FILE *b64_file;
+ uint8_t *b64_buf;
+ size_t b64_len;
+
+ mbedtls_printf(" . Save serialized context to a file... ");
+
+ mbedtls_base64_encode(NULL, 0, &b64_len, context_buf, buf_len);
+
+ if ((b64_buf = mbedtls_calloc(1, b64_len)) == NULL) {
+ mbedtls_printf("failed\n ! Couldn't allocate buffer for "
+ "the base64 code\n");
+ goto exit;
+ }
+
+ if ((ret = mbedtls_base64_encode(b64_buf, b64_len, &b64_len,
+ context_buf, buf_len)) != 0) {
+ mbedtls_printf("failed\n ! mbedtls_base64_encode returned "
+ "-0x%x\n", (unsigned int) -ret);
+ mbedtls_free(b64_buf);
+ goto exit;
+ }
+
+ if ((b64_file = fopen(opt.context_file, "w")) == NULL) {
+ mbedtls_printf("failed\n ! Cannot open '%s' for writing.\n",
+ opt.context_file);
+ mbedtls_free(b64_buf);
+ goto exit;
+ }
+
+ if (b64_len != fwrite(b64_buf, 1, b64_len, b64_file)) {
+ mbedtls_printf("failed\n ! fwrite(%ld bytes) failed\n",
+ (long) b64_len);
+ mbedtls_free(b64_buf);
+ fclose(b64_file);
+ goto exit;
+ }
+
+ mbedtls_free(b64_buf);
+ fclose(b64_file);
+
+ mbedtls_printf("ok\n");
+ }
+
+ if (opt.serialize == 1) {
+ /* nothing to do here, done by context_save() already */
+ mbedtls_printf(" . Context has been reset... ok\n");
+ }
+
+ if (opt.serialize == 2) {
+ mbedtls_printf(" . Freeing and reinitializing context...");
+
+ mbedtls_ssl_free(&ssl);
+
+ mbedtls_ssl_init(&ssl);
+
+ if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_setup returned "
+ "-0x%x\n\n", (unsigned int) -ret);
+ goto exit;
+ }
+
+ if (opt.nbio == 2) {
+ mbedtls_ssl_set_bio(&ssl, &server_fd, delayed_send,
+ delayed_recv, NULL);
+ } else {
+ mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send,
+ mbedtls_net_recv,
+ opt.nbio == 0 ? mbedtls_net_recv_timeout : NULL);
+ }
+
+#if defined(MBEDTLS_TIMING_C)
+ mbedtls_ssl_set_timer_cb(&ssl, &timer,
+ mbedtls_timing_set_delay,
+ mbedtls_timing_get_delay);
+#endif /* MBEDTLS_TIMING_C */
+
+ mbedtls_printf(" ok\n");
+ }
+
+ mbedtls_printf(" . Deserializing connection...");
+
+ if ((ret = mbedtls_ssl_context_load(&ssl, context_buf,
+ buf_len)) != 0) {
+ mbedtls_printf("failed\n ! mbedtls_ssl_context_load returned "
+ "-0x%x\n\n", (unsigned int) -ret);
+
+ goto exit;
+ }
+
+ mbedtls_free(context_buf);
+ context_buf = NULL;
+ context_buf_len = 0;
+
+ mbedtls_printf(" ok\n");
+ }
+#endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
+
+ /*
+ * 7d. Continue doing data exchanges?
+ */
+ if (--opt.exchanges > 0) {
+ goto send_request;
+ }
+
+ /*
+ * 8. Done, cleanly close the connection
+ */
+close_notify:
+ mbedtls_printf(" . Closing the connection...");
+ fflush(stdout);
+
+ /*
+ * Most of the time sending a close_notify before closing is the right
+ * thing to do. However, when the server already knows how many messages
+ * are expected and closes the connection by itself, this alert becomes
+ * redundant. Sometimes with DTLS this redundancy becomes a problem by
+ * leading to a race condition where the server might close the connection
+ * before seeing the alert, and since UDP is connection-less when the
+ * alert arrives it will be seen as a new connection, which will fail as
+ * the alert is clearly not a valid ClientHello. This may cause spurious
+ * failures in tests that use DTLS and resumption with ssl_server2 in
+ * ssl-opt.sh, avoided by enabling skip_close_notify client-side.
+ */
+ if (opt.skip_close_notify == 0) {
+ /* No error checking, the connection might be closed already */
+ do {
+ ret = mbedtls_ssl_close_notify(&ssl);
+ } while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+ ret = 0;
+ }
+
+ mbedtls_printf(" done\n");
+
+ /*
+ * 9. Reconnect?
+ */
+reconnect:
+ if (opt.reconnect != 0) {
+ --opt.reconnect;
+
+ mbedtls_net_free(&server_fd);
+
+#if defined(MBEDTLS_TIMING_C)
+ if (opt.reco_delay > 0) {
+ mbedtls_net_usleep(1000 * opt.reco_delay);
+ }
+#endif
+
+ mbedtls_printf(" . Reconnecting with saved session...");
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ memset(peer_crt_info, 0, sizeof(peer_crt_info));
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+
+ if ((ret = mbedtls_ssl_session_reset(&ssl)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_session_reset returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ if (opt.reco_mode == 1) {
+ if ((ret = mbedtls_ssl_session_load(&saved_session,
+ session_data,
+ session_data_len)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_session_load returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ }
+
+ if ((ret = mbedtls_ssl_set_session(&ssl, &saved_session)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_set_session returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+ if (opt.reco_server_name != NULL &&
+ (ret = mbedtls_ssl_set_hostname(&ssl,
+ opt.reco_server_name)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n",
+ ret);
+ goto exit;
+ }
+#endif
+
+ if ((ret = mbedtls_net_connect(&server_fd,
+ opt.server_addr, opt.server_port,
+ opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM ?
+ MBEDTLS_NET_PROTO_TCP : MBEDTLS_NET_PROTO_UDP)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_net_connect returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ if (opt.nbio > 0) {
+ ret = mbedtls_net_set_nonblock(&server_fd);
+ } else {
+ ret = mbedtls_net_set_block(&server_fd);
+ }
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! net_set_(non)block() returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ ret = build_http_request(buf, sizeof(buf) - 1, &len);
+ if (ret != 0) {
+ goto exit;
+ }
+
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+ if (ssl.conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_ENABLED) {
+ frags = 0;
+ written = 0;
+ do {
+ while ((ret = mbedtls_ssl_write_early_data(&ssl, buf + written,
+ len - written)) < 0) {
+ if (ret == MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA) {
+ goto end_of_early_data;
+ }
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
+ ret != MBEDTLS_ERR_SSL_WANT_WRITE &&
+ ret != MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_write returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ /* For event-driven IO, wait for socket to become available */
+ if (opt.event == 1 /* level triggered IO */) {
+#if defined(MBEDTLS_TIMING_C)
+ idle(&server_fd, &timer, ret);
+#else
+ idle(&server_fd, ret);
+#endif
+ }
+ }
+
+ frags++;
+ written += ret;
+ } while (written < len);
+
+end_of_early_data:
+
+ buf[written] = '\0';
+ mbedtls_printf(
+ " %" MBEDTLS_PRINTF_SIZET " bytes of early data written in %" MBEDTLS_PRINTF_SIZET " fragments\n\n%s\n",
+ written,
+ frags,
+ (char *) buf);
+ }
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
+ while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
+ ret != MBEDTLS_ERR_SSL_WANT_WRITE &&
+ ret != MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ }
+
+ mbedtls_printf(" ok\n");
+
+ goto send_request;
+ }
+
+ /*
+ * Cleanup and exit
+ */
+exit:
+#ifdef MBEDTLS_ERROR_C
+ if (ret != 0) {
+ char error_buf[100];
+ mbedtls_strerror(ret, error_buf, 100);
+ mbedtls_printf("Last error was: -0x%X - %s\n\n", (unsigned int) -ret, error_buf);
+ }
+#endif
+
+ mbedtls_net_free(&server_fd);
+
+ mbedtls_ssl_free(&ssl);
+ mbedtls_ssl_config_free(&conf);
+ mbedtls_ssl_session_free(&saved_session);
+
+ if (session_data != NULL) {
+ mbedtls_platform_zeroize(session_data, session_data_len);
+ }
+ mbedtls_free(session_data);
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+ if (context_buf != NULL) {
+ mbedtls_platform_zeroize(context_buf, context_buf_len);
+ }
+ mbedtls_free(context_buf);
+#endif
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ mbedtls_x509_crt_free(&clicert);
+ mbedtls_x509_crt_free(&cacert);
+ mbedtls_pk_free(&pkey);
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ psa_destroy_key(key_slot);
+#endif
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED) && \
+ defined(MBEDTLS_USE_PSA_CRYPTO)
+ if (opt.psk_opaque != 0) {
+ /* This is ok even if the slot hasn't been
+ * initialized (we might have jumed here
+ * immediately because of bad cmd line params,
+ * for example). */
+ status = psa_destroy_key(slot);
+ if ((status != PSA_SUCCESS) &&
+ (opt.query_config_mode == DFL_QUERY_CONFIG_MODE)) {
+ mbedtls_printf("Failed to destroy key slot %u - error was %d",
+ (unsigned) MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot),
+ (int) status);
+ if (ret == 0) {
+ ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
+ }
+ }
+ }
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED &&
+ MBEDTLS_USE_PSA_CRYPTO */
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) && \
+ defined(MBEDTLS_USE_PSA_CRYPTO)
+ /*
+ * In case opaque keys it's the user responsibility to keep the key valid
+ * for the duration of the handshake and destroy it at the end
+ */
+ if ((opt.ecjpake_pw_opaque != DFL_ECJPAKE_PW_OPAQUE)) {
+ psa_key_attributes_t check_attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+ /* Verify that the key is still valid before destroying it */
+ if (psa_get_key_attributes(ecjpake_pw_slot, &check_attributes) !=
+ PSA_SUCCESS) {
+ if (ret == 0) {
+ ret = 1;
+ }
+ mbedtls_printf("The EC J-PAKE password key has unexpectedly been already destroyed\n");
+ } else {
+ psa_destroy_key(ecjpake_pw_slot);
+ }
+ }
+#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED && MBEDTLS_USE_PSA_CRYPTO */
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ const char *message = mbedtls_test_helper_is_psa_leaking();
+ if (message) {
+ if (ret == 0) {
+ ret = 1;
+ }
+ mbedtls_printf("PSA memory leak detected: %s\n", message);
+ }
+#endif /* MBEDTLS_USE_PSA_CRYPTO || MBEDTLS_SSL_PROTO_TLS1_3 */
+
+ /* For builds with MBEDTLS_TEST_USE_PSA_CRYPTO_RNG psa crypto
+ * resources are freed by rng_free(). */
+#if (defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)) && \
+ !defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+ mbedtls_psa_crypto_free();
+#endif
+
+ rng_free(&rng);
+
+#if defined(MBEDTLS_TEST_HOOKS)
+ if (test_hooks_failure_detected()) {
+ if (ret == 0) {
+ ret = 1;
+ }
+ mbedtls_printf("Test hooks detected errors.\n");
+ }
+ test_hooks_free();
+#endif /* MBEDTLS_TEST_HOOKS */
+
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+#if defined(MBEDTLS_MEMORY_DEBUG)
+ mbedtls_memory_buffer_alloc_status();
+#endif
+ mbedtls_memory_buffer_alloc_free();
+#endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */
+
+ // Shell can not handle large exit numbers -> 1 for errors
+ if (ret < 0) {
+ ret = 1;
+ }
+
+ if (opt.query_config_mode == DFL_QUERY_CONFIG_MODE) {
+ mbedtls_exit(ret);
+ } else {
+ mbedtls_exit(query_config_ret);
+ }
+}
+#endif /* !MBEDTLS_SSL_TEST_IMPOSSIBLE && MBEDTLS_SSL_CLI_C */
diff --git a/programs/ssl/ssl_context_info.c b/programs/ssl/ssl_context_info.c
new file mode 100644
index 00000000000..ee2cdb7b963
--- /dev/null
+++ b/programs/ssl/ssl_context_info.c
@@ -0,0 +1,1012 @@
+/*
+ * Mbed TLS SSL context deserializer from base64 code
+ *
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "mbedtls/build_info.h"
+#include "mbedtls/debug.h"
+#include "mbedtls/platform.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_ERROR_C) || \
+ !defined(MBEDTLS_SSL_TLS_C)
+int main(void)
+{
+ printf("MBEDTLS_X509_CRT_PARSE_C and/or MBEDTLS_ERROR_C and/or "
+ "MBEDTLS_SSL_TLS_C not defined.\n");
+ return 0;
+}
+#else
+
+#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#if defined(MBEDTLS_HAVE_TIME)
+#include <time.h>
+#endif
+#include "mbedtls/ssl.h"
+#include "mbedtls/error.h"
+#include "mbedtls/base64.h"
+#include "mbedtls/md.h"
+#include "mbedtls/x509_crt.h"
+#include "mbedtls/ssl_ciphersuites.h"
+
+/*
+ * This program version
+ */
+#define PROG_NAME "ssl_context_info"
+#define VER_MAJOR 0
+#define VER_MINOR 1
+
+/*
+ * Flags copied from the Mbed TLS library.
+ */
+#define SESSION_CONFIG_TIME_BIT (1 << 0)
+#define SESSION_CONFIG_CRT_BIT (1 << 1)
+#define SESSION_CONFIG_CLIENT_TICKET_BIT (1 << 2)
+#define SESSION_CONFIG_MFL_BIT (1 << 3)
+#define SESSION_CONFIG_TRUNC_HMAC_BIT (1 << 4)
+#define SESSION_CONFIG_ETM_BIT (1 << 5)
+#define SESSION_CONFIG_TICKET_BIT (1 << 6)
+
+#define CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT (1 << 0)
+#define CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT (1 << 1)
+#define CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT (1 << 2)
+#define CONTEXT_CONFIG_ALPN_BIT (1 << 3)
+
+#define TRANSFORM_RANDBYTE_LEN 64
+
+/*
+ * Minimum and maximum number of bytes for specific data: context, sessions,
+ * certificates, tickets and buffers in the program. The context and session
+ * size values have been calculated based on the 'print_deserialized_ssl_context()'
+ * and 'print_deserialized_ssl_session()' content.
+ */
+#define MIN_CONTEXT_LEN 84
+#define MIN_SESSION_LEN 88
+
+#define MAX_CONTEXT_LEN 875 /* without session data */
+#define MAX_SESSION_LEN 109 /* without certificate and ticket data */
+#define MAX_CERTIFICATE_LEN ((1 << 24) - 1)
+#define MAX_TICKET_LEN ((1 << 24) - 1)
+
+#define MIN_SERIALIZED_DATA (MIN_CONTEXT_LEN + MIN_SESSION_LEN)
+#define MAX_SERIALIZED_DATA (MAX_CONTEXT_LEN + MAX_SESSION_LEN + \
+ MAX_CERTIFICATE_LEN + MAX_TICKET_LEN)
+
+#define MIN_BASE64_LEN (MIN_SERIALIZED_DATA * 4 / 3)
+#define MAX_BASE64_LEN (MAX_SERIALIZED_DATA * 4 / 3 + 3)
+
+/*
+ * A macro that prevents from reading out of the ssl buffer range.
+ */
+#define CHECK_SSL_END(LEN) \
+ do \
+ { \
+ if (end - ssl < (int) (LEN)) \
+ { \
+ printf_err("%s", buf_ln_err); \
+ return; \
+ } \
+ } while (0)
+
+/*
+ * Global values
+ */
+FILE *b64_file = NULL; /* file with base64 codes to deserialize */
+char conf_keep_peer_certificate = 1; /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE from mbedTLS configuration */
+char conf_dtls_proto = 1; /* MBEDTLS_SSL_PROTO_DTLS from mbedTLS configuration */
+char debug = 0; /* flag for debug messages */
+const char alloc_err[] = "Cannot allocate memory\n";
+const char buf_ln_err[] = "Buffer does not have enough data to complete the parsing\n";
+
+/*
+ * Basic printing functions
+ */
+void print_version(void)
+{
+ printf("%s v%d.%d\n", PROG_NAME, VER_MAJOR, VER_MINOR);
+}
+
+void print_usage(void)
+{
+ print_version();
+ printf("\nThis program is used to deserialize an Mbed TLS SSL session from the base64 code provided\n"
+ "in the text file. The program can deserialize many codes from one file, but they must be\n"
+ "separated, e.g. by a newline.\n\n");
+ printf(
+ "Usage:\n"
+ "\t-f path - Path to the file with base64 code\n"
+ "\t-v - Show version\n"
+ "\t-h - Show this usage\n"
+ "\t-d - Print more information\n"
+ "\t--keep-peer-cert=0 - Use this option if you know that the Mbed TLS library\n"
+ "\t has been compiled with the MBEDTLS_SSL_KEEP_PEER_CERTIFICATE\n"
+ "\t flag. You can also use it if there are some problems with reading\n"
+ "\t the information about certificate\n"
+ "\t--dtls-protocol=0 - Use this option if you know that the Mbed TLS library\n"
+ "\t has been compiled without the MBEDTLS_SSL_PROTO_DTLS flag\n"
+ "\n"
+ );
+}
+
+void printf_dbg(const char *str, ...)
+{
+ if (debug) {
+ va_list args;
+ va_start(args, str);
+ printf("debug: ");
+ vprintf(str, args);
+ fflush(stdout);
+ va_end(args);
+ }
+}
+
+MBEDTLS_PRINTF_ATTRIBUTE(1, 2)
+void printf_err(const char *str, ...)
+{
+ va_list args;
+ va_start(args, str);
+ fflush(stdout);
+ fprintf(stderr, "ERROR: ");
+ vfprintf(stderr, str, args);
+ fflush(stderr);
+ va_end(args);
+}
+
+/*
+ * Exit from the program in case of error
+ */
+void error_exit(void)
+{
+ if (NULL != b64_file) {
+ fclose(b64_file);
+ }
+ exit(-1);
+}
+
+/*
+ * This function takes the input arguments of this program
+ */
+void parse_arguments(int argc, char *argv[])
+{
+ int i = 1;
+
+ if (argc < 2) {
+ print_usage();
+ error_exit();
+ }
+
+ while (i < argc) {
+ if (strcmp(argv[i], "-d") == 0) {
+ debug = 1;
+ } else if (strcmp(argv[i], "-h") == 0) {
+ print_usage();
+ } else if (strcmp(argv[i], "-v") == 0) {
+ print_version();
+ } else if (strcmp(argv[i], "-f") == 0) {
+ if (++i >= argc) {
+ printf_err("File path is empty\n");
+ error_exit();
+ }
+
+ if (NULL != b64_file) {
+ printf_err("Cannot specify more than one file with -f\n");
+ error_exit();
+ }
+
+ if ((b64_file = fopen(argv[i], "r")) == NULL) {
+ printf_err("Cannot find file \"%s\"\n", argv[i]);
+ error_exit();
+ }
+ } else if (strcmp(argv[i], "--keep-peer-cert=0") == 0) {
+ conf_keep_peer_certificate = 0;
+ } else if (strcmp(argv[i], "--dtls-protocol=0") == 0) {
+ conf_dtls_proto = 0;
+ } else {
+ print_usage();
+ error_exit();
+ }
+
+ i++;
+ }
+}
+
+/*
+ * This function prints base64 code to the stdout
+ */
+void print_b64(const uint8_t *b, size_t len)
+{
+ size_t i = 0;
+ const uint8_t *end = b + len;
+ printf("\t");
+ while (b < end) {
+ if (++i > 75) {
+ printf("\n\t");
+ i = 0;
+ }
+ printf("%c", *b++);
+ }
+ printf("\n");
+ fflush(stdout);
+}
+
+/*
+ * This function prints hex code from the buffer to the stdout.
+ *
+ * /p b buffer with data to print
+ * /p len number of bytes to print
+ * /p in_line number of bytes in one line
+ * /p prefix prefix for the new lines
+ */
+void print_hex(const uint8_t *b, size_t len,
+ const size_t in_line, const char *prefix)
+{
+ size_t i = 0;
+ const uint8_t *end = b + len;
+
+ if (prefix == NULL) {
+ prefix = "";
+ }
+
+ while (b < end) {
+ if (++i > in_line) {
+ printf("\n%s", prefix);
+ i = 1;
+ }
+ printf("%02X ", (uint8_t) *b++);
+ }
+ printf("\n");
+ fflush(stdout);
+}
+
+/*
+ * Print the value of time_t in format e.g. 2020-01-23 13:05:59
+ */
+void print_time(const uint64_t *time)
+{
+#if defined(MBEDTLS_HAVE_TIME)
+ char buf[20];
+ struct tm *t = gmtime((time_t *) time);
+ static const char format[] = "%Y-%m-%d %H:%M:%S";
+ if (NULL != t) {
+ strftime(buf, sizeof(buf), format, t);
+ printf("%s\n", buf);
+ } else {
+ printf("unknown\n");
+ }
+#else
+ (void) time;
+ printf("not supported\n");
+#endif
+}
+
+/*
+ * Print the input string if the bit is set in the value
+ */
+void print_if_bit(const char *str, int bit, int val)
+{
+ if (bit & val) {
+ printf("\t%s\n", str);
+ }
+}
+
+/*
+ * Return pointer to hardcoded "enabled" or "disabled" depending on the input value
+ */
+const char *get_enabled_str(int is_en)
+{
+ return (is_en) ? "enabled" : "disabled";
+}
+
+/*
+ * Return pointer to hardcoded MFL string value depending on the MFL code at the input
+ */
+const char *get_mfl_str(int mfl_code)
+{
+ switch (mfl_code) {
+ case MBEDTLS_SSL_MAX_FRAG_LEN_NONE:
+ return "none";
+ case MBEDTLS_SSL_MAX_FRAG_LEN_512:
+ return "512";
+ case MBEDTLS_SSL_MAX_FRAG_LEN_1024:
+ return "1024";
+ case MBEDTLS_SSL_MAX_FRAG_LEN_2048:
+ return "2048";
+ case MBEDTLS_SSL_MAX_FRAG_LEN_4096:
+ return "4096";
+ default:
+ return "error";
+ }
+}
+
+/*
+ * Read next base64 code from the 'b64_file'. The 'b64_file' must be opened
+ * previously. After each call to this function, the internal file position
+ * indicator of the global b64_file is advanced.
+ *
+ * Note - This function checks the size of the input buffer and if necessary,
+ * increases it to the maximum MAX_BASE64_LEN
+ *
+ * /p b64 pointer to the pointer of the buffer for input data
+ * /p max_len pointer to the current buffer capacity. It can be changed if
+ * the buffer needs to be increased
+ *
+ * \retval number of bytes written in to the b64 buffer or 0 in case no more
+ * data was found
+ */
+size_t read_next_b64_code(uint8_t **b64, size_t *max_len)
+{
+ int valid_balance = 0; /* balance between valid and invalid characters */
+ size_t len = 0;
+ char pad = 0;
+ int c = 0;
+
+ while (EOF != c) {
+ char c_valid = 0;
+
+ c = fgetc(b64_file);
+
+ if (pad > 0) {
+ if (c == '=' && pad == 1) {
+ c_valid = 1;
+ pad = 2;
+ }
+ } else if ((c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') ||
+ c == '+' || c == '/') {
+ c_valid = 1;
+ } else if (c == '=') {
+ c_valid = 1;
+ pad = 1;
+ } else if (c == '-') {
+ c = '+';
+ c_valid = 1;
+ } else if (c == '_') {
+ c = '/';
+ c_valid = 1;
+ }
+
+ if (c_valid) {
+ /* A string of characters that could be a base64 code. */
+ valid_balance++;
+
+ if (len < *max_len) {
+ (*b64)[len++] = c;
+ } else if (*max_len < MAX_BASE64_LEN) {
+ /* Current buffer is too small, but can be resized. */
+ void *ptr;
+ size_t new_size = (MAX_BASE64_LEN - 4096 > *max_len) ?
+ *max_len + 4096 : MAX_BASE64_LEN;
+
+ ptr = realloc(*b64, new_size);
+ if (NULL == ptr) {
+ printf_err(alloc_err);
+ return 0;
+ }
+ *b64 = ptr;
+ *max_len = new_size;
+ (*b64)[len++] = c;
+ } else {
+ /* Too much data so it will be treated as invalid */
+ len++;
+ }
+ } else if (len > 0) {
+ /* End of a string that could be a base64 code, but need to check
+ * that the length of the characters is correct. */
+
+ valid_balance--;
+
+ if (len < MIN_CONTEXT_LEN) {
+ printf_dbg("The code found is too small to be a SSL context.\n");
+ len = pad = 0;
+ } else if (len > *max_len) {
+ printf_err("The code found is too large by %" MBEDTLS_PRINTF_SIZET " bytes.\n",
+ len - *max_len);
+ len = pad = 0;
+ } else if (len % 4 != 0) {
+ printf_err("The length of the base64 code found should be a multiple of 4.\n");
+ len = pad = 0;
+ } else {
+ /* Base64 code with valid character length. */
+ return len;
+ }
+ } else {
+ valid_balance--;
+ }
+
+ /* Detection of potentially wrong file format like: binary, zip, ISO, etc. */
+ if (valid_balance < -100) {
+ printf_err("Too many bad symbols detected. File check aborted.\n");
+ return 0;
+ }
+ }
+
+ printf_dbg("End of file\n");
+ return 0;
+}
+
+#if !defined(MBEDTLS_X509_REMOVE_INFO)
+/*
+ * This function deserializes and prints to the stdout all obtained information
+ * about the certificates from provided data.
+ *
+ * /p ssl pointer to serialized certificate
+ * /p len number of bytes in the buffer
+ */
+void print_deserialized_ssl_cert(const uint8_t *ssl, uint32_t len)
+{
+ enum { STRLEN = 4096 };
+ mbedtls_x509_crt crt;
+ int ret;
+ char str[STRLEN];
+
+ printf("\nCertificate:\n");
+
+ mbedtls_x509_crt_init(&crt);
+ ret = mbedtls_x509_crt_parse_der(&crt, ssl, len);
+ if (0 != ret) {
+ mbedtls_strerror(ret, str, STRLEN);
+ printf_err("Invalid format of X.509 - %s\n", str);
+ printf("Cannot deserialize:\n\t");
+ print_hex(ssl, len, 25, "\t");
+ } else {
+ mbedtls_x509_crt *current = &crt;
+
+ while (current != NULL) {
+ ret = mbedtls_x509_crt_info(str, STRLEN, "\t", current);
+ if (0 > ret) {
+ mbedtls_strerror(ret, str, STRLEN);
+ printf_err("Cannot write to the output - %s\n", str);
+ } else {
+ printf("%s", str);
+ }
+
+ current = current->next;
+
+ if (current) {
+ printf("\n");
+ }
+
+ }
+ }
+
+ mbedtls_x509_crt_free(&crt);
+}
+#endif /* !MBEDTLS_X509_REMOVE_INFO */
+
+/*
+ * This function deserializes and prints to the stdout all obtained information
+ * about the session from provided data. This function was built based on
+ * mbedtls_ssl_session_load(). mbedtls_ssl_session_load() could not be used
+ * due to dependencies on the mbedTLS configuration.
+ *
+ * The data structure in the buffer:
+ * uint64 start_time;
+ * uint8 ciphersuite[2]; // defined by the standard
+ * uint8 compression; // 0 or 1
+ * uint8 session_id_len; // at most 32
+ * opaque session_id[32];
+ * opaque master[48]; // fixed length in the standard
+ * uint32 verify_result;
+ * opaque peer_cert<0..2^24-1>; // length 0 means no peer cert
+ * opaque ticket<0..2^24-1>; // length 0 means no ticket
+ * uint32 ticket_lifetime;
+ * uint8 mfl_code; // up to 255 according to standard
+ * uint8 trunc_hmac; // 0 or 1
+ * uint8 encrypt_then_mac; // 0 or 1
+ *
+ * /p ssl pointer to serialized session
+ * /p len number of bytes in the buffer
+ * /p session_cfg_flag session configuration flags
+ */
+void print_deserialized_ssl_session(const uint8_t *ssl, uint32_t len,
+ int session_cfg_flag)
+{
+ const struct mbedtls_ssl_ciphersuite_t *ciphersuite_info;
+ int ciphersuite_id;
+ uint32_t cert_len, ticket_len;
+ uint32_t verify_result, ticket_lifetime;
+ const uint8_t *end = ssl + len;
+
+ printf("\nSession info:\n");
+
+ if (session_cfg_flag & SESSION_CONFIG_TIME_BIT) {
+ uint64_t start;
+ CHECK_SSL_END(8);
+ start = ((uint64_t) ssl[0] << 56) |
+ ((uint64_t) ssl[1] << 48) |
+ ((uint64_t) ssl[2] << 40) |
+ ((uint64_t) ssl[3] << 32) |
+ ((uint64_t) ssl[4] << 24) |
+ ((uint64_t) ssl[5] << 16) |
+ ((uint64_t) ssl[6] << 8) |
+ ((uint64_t) ssl[7]);
+ ssl += 8;
+ printf("\tstart time : ");
+ print_time(&start);
+ }
+
+ CHECK_SSL_END(2);
+ ciphersuite_id = ((int) ssl[0] << 8) | (int) ssl[1];
+ printf_dbg("Ciphersuite ID: %d\n", ciphersuite_id);
+ ssl += 2;
+
+ ciphersuite_info = mbedtls_ssl_ciphersuite_from_id(ciphersuite_id);
+ if (ciphersuite_info == NULL) {
+ printf_err("Cannot find ciphersuite info\n");
+ } else {
+#if defined(MBEDTLS_MD_C)
+ const mbedtls_md_info_t *md_info;
+#endif
+
+ printf("\tciphersuite : %s\n", mbedtls_ssl_ciphersuite_get_name(ciphersuite_info));
+ printf("\tcipher flags : 0x%02X\n", ciphersuite_info->MBEDTLS_PRIVATE(flags));
+
+#if defined(MBEDTLS_CIPHER_C)
+ const mbedtls_cipher_info_t *cipher_info;
+ cipher_info = mbedtls_cipher_info_from_type(ciphersuite_info->MBEDTLS_PRIVATE(cipher));
+ if (cipher_info == NULL) {
+ printf_err("Cannot find cipher info\n");
+ } else {
+ printf("\tcipher : %s\n", mbedtls_cipher_info_get_name(cipher_info));
+ }
+#else /* MBEDTLS_CIPHER_C */
+ printf("\tcipher type : %d\n", ciphersuite_info->MBEDTLS_PRIVATE(cipher));
+#endif /* MBEDTLS_CIPHER_C */
+
+#if defined(MBEDTLS_MD_C)
+ md_info = mbedtls_md_info_from_type(ciphersuite_info->MBEDTLS_PRIVATE(mac));
+ if (md_info == NULL) {
+ printf_err("Cannot find Message-Digest info\n");
+ } else {
+ printf("\tMessage-Digest : %s\n", mbedtls_md_get_name(md_info));
+ }
+#endif /* MBEDTLS_MD_C */
+ }
+
+ CHECK_SSL_END(1);
+ printf("\tcompression : %s\n", get_enabled_str(*ssl++));
+
+ /* Note - Here we can get session ID length from serialized data, but we
+ * use hardcoded 32-bytes length. This approach was taken from
+ * 'mbedtls_ssl_session_load()'. */
+ CHECK_SSL_END(1 + 32);
+ printf_dbg("Session id length: %u\n", (uint32_t) *ssl++);
+ printf("\tsession ID : ");
+ print_hex(ssl, 32, 16, "\t ");
+ ssl += 32;
+
+ printf("\tmaster secret : ");
+ CHECK_SSL_END(48);
+ print_hex(ssl, 48, 16, "\t ");
+ ssl += 48;
+
+ CHECK_SSL_END(4);
+ verify_result = ((uint32_t) ssl[0] << 24) |
+ ((uint32_t) ssl[1] << 16) |
+ ((uint32_t) ssl[2] << 8) |
+ ((uint32_t) ssl[3]);
+ ssl += 4;
+ printf("\tverify result : 0x%08X\n", verify_result);
+
+ if (SESSION_CONFIG_CRT_BIT & session_cfg_flag) {
+ if (conf_keep_peer_certificate) {
+ CHECK_SSL_END(3);
+ cert_len = ((uint32_t) ssl[0] << 16) |
+ ((uint32_t) ssl[1] << 8) |
+ ((uint32_t) ssl[2]);
+ ssl += 3;
+ printf_dbg("Certificate length: %u\n", cert_len);
+
+ if (cert_len > 0) {
+ CHECK_SSL_END(cert_len);
+#if !defined(MBEDTLS_X509_REMOVE_INFO)
+ print_deserialized_ssl_cert(ssl, cert_len);
+#endif
+ ssl += cert_len;
+ }
+ } else {
+ printf("\tPeer digest : ");
+
+ CHECK_SSL_END(1);
+ switch ((mbedtls_md_type_t) *ssl++) {
+ case MBEDTLS_MD_NONE:
+ printf("none\n");
+ break;
+ case MBEDTLS_MD_MD5:
+ printf("MD5\n");
+ break;
+ case MBEDTLS_MD_SHA1:
+ printf("SHA1\n");
+ break;
+ case MBEDTLS_MD_SHA224:
+ printf("SHA224\n");
+ break;
+ case MBEDTLS_MD_SHA256:
+ printf("SHA256\n");
+ break;
+ case MBEDTLS_MD_SHA384:
+ printf("SHA384\n");
+ break;
+ case MBEDTLS_MD_SHA512:
+ printf("SHA512\n");
+ break;
+ case MBEDTLS_MD_RIPEMD160:
+ printf("RIPEMD160\n");
+ break;
+ default:
+ printf("undefined or erroneous\n");
+ break;
+ }
+
+ CHECK_SSL_END(1);
+ cert_len = (uint32_t) *ssl++;
+ printf_dbg("Message-Digest length: %u\n", cert_len);
+
+ if (cert_len > 0) {
+ printf("\tPeer digest cert : ");
+ CHECK_SSL_END(cert_len);
+ print_hex(ssl, cert_len, 16, "\t ");
+ ssl += cert_len;
+ }
+ }
+ }
+
+ if (SESSION_CONFIG_CLIENT_TICKET_BIT & session_cfg_flag) {
+ printf("\nTicket:\n");
+
+ CHECK_SSL_END(3);
+ ticket_len = ((uint32_t) ssl[0] << 16) |
+ ((uint32_t) ssl[1] << 8) |
+ ((uint32_t) ssl[2]);
+ ssl += 3;
+ printf_dbg("Ticket length: %u\n", ticket_len);
+
+ if (ticket_len > 0) {
+ printf("\t");
+ CHECK_SSL_END(ticket_len);
+ print_hex(ssl, ticket_len, 22, "\t");
+ ssl += ticket_len;
+ printf("\n");
+ }
+
+ CHECK_SSL_END(4);
+ ticket_lifetime = ((uint32_t) ssl[0] << 24) |
+ ((uint32_t) ssl[1] << 16) |
+ ((uint32_t) ssl[2] << 8) |
+ ((uint32_t) ssl[3]);
+ ssl += 4;
+ printf("\tlifetime : %u sec.\n", ticket_lifetime);
+ }
+
+ if (ssl < end) {
+ printf("\nSession others:\n");
+ }
+
+ if (SESSION_CONFIG_MFL_BIT & session_cfg_flag) {
+ CHECK_SSL_END(1);
+ printf("\tMFL : %s\n", get_mfl_str(*ssl++));
+ }
+
+ if (SESSION_CONFIG_TRUNC_HMAC_BIT & session_cfg_flag) {
+ CHECK_SSL_END(1);
+ printf("\tnegotiate truncated HMAC : %s\n", get_enabled_str(*ssl++));
+ }
+
+ if (SESSION_CONFIG_ETM_BIT & session_cfg_flag) {
+ CHECK_SSL_END(1);
+ printf("\tEncrypt-then-MAC : %s\n", get_enabled_str(*ssl++));
+ }
+
+ if (0 != (end - ssl)) {
+ printf_err("%i bytes left to analyze from session\n", (int32_t) (end - ssl));
+ }
+}
+
+/*
+ * This function deserializes and prints to the stdout all obtained information
+ * about the context from provided data. This function was built based on
+ * mbedtls_ssl_context_load(). mbedtls_ssl_context_load() could not be used
+ * due to dependencies on the mbedTLS configuration and the configuration of
+ * the context when serialization was created.
+ *
+ * The data structure in the buffer:
+ * // header
+ * uint8 version[3];
+ * uint8 configuration[5];
+ * // session sub-structure
+ * uint32_t session_len;
+ * opaque session<1..2^32-1>; // see mbedtls_ssl_session_save()
+ * // transform sub-structure
+ * uint8 random[64]; // ServerHello.random+ClientHello.random
+ * uint8 in_cid_len;
+ * uint8 in_cid<0..2^8-1> // Connection ID: expected incoming value
+ * uint8 out_cid_len;
+ * uint8 out_cid<0..2^8-1> // Connection ID: outgoing value to use
+ * // fields from ssl_context
+ * uint32 badmac_seen; // DTLS: number of records with failing MAC
+ * uint64 in_window_top; // DTLS: last validated record seq_num
+ * uint64 in_window; // DTLS: bitmask for replay protection
+ * uint8 disable_datagram_packing; // DTLS: only one record per datagram
+ * uint64 cur_out_ctr; // Record layer: outgoing sequence number
+ * uint16 mtu; // DTLS: path mtu (max outgoing fragment size)
+ * uint8 alpn_chosen_len;
+ * uint8 alpn_chosen<0..2^8-1> // ALPN: negotiated application protocol
+ *
+ * /p ssl pointer to serialized session
+ * /p len number of bytes in the buffer
+ */
+void print_deserialized_ssl_context(const uint8_t *ssl, size_t len)
+{
+ const uint8_t *end = ssl + len;
+ uint32_t session_len;
+ int session_cfg_flag;
+ int context_cfg_flag;
+
+ printf("\nMbed TLS version:\n");
+
+ CHECK_SSL_END(3 + 2 + 3);
+
+ printf("\tmajor %u\n", (uint32_t) *ssl++);
+ printf("\tminor %u\n", (uint32_t) *ssl++);
+ printf("\tpath %u\n", (uint32_t) *ssl++);
+
+ printf("\nEnabled session and context configuration:\n");
+
+ session_cfg_flag = ((int) ssl[0] << 8) | ((int) ssl[1]);
+ ssl += 2;
+
+ context_cfg_flag = ((int) ssl[0] << 16) |
+ ((int) ssl[1] << 8) |
+ ((int) ssl[2]);
+ ssl += 3;
+
+ printf_dbg("Session config flags 0x%04X\n", session_cfg_flag);
+ printf_dbg("Context config flags 0x%06X\n", context_cfg_flag);
+
+ print_if_bit("MBEDTLS_HAVE_TIME", SESSION_CONFIG_TIME_BIT, session_cfg_flag);
+ print_if_bit("MBEDTLS_X509_CRT_PARSE_C", SESSION_CONFIG_CRT_BIT, session_cfg_flag);
+ print_if_bit("MBEDTLS_SSL_MAX_FRAGMENT_LENGTH", SESSION_CONFIG_MFL_BIT, session_cfg_flag);
+ print_if_bit("MBEDTLS_SSL_ENCRYPT_THEN_MAC", SESSION_CONFIG_ETM_BIT, session_cfg_flag);
+ print_if_bit("MBEDTLS_SSL_SESSION_TICKETS", SESSION_CONFIG_TICKET_BIT, session_cfg_flag);
+ print_if_bit("MBEDTLS_SSL_SESSION_TICKETS and client",
+ SESSION_CONFIG_CLIENT_TICKET_BIT,
+ session_cfg_flag);
+
+ print_if_bit("MBEDTLS_SSL_DTLS_CONNECTION_ID",
+ CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT,
+ context_cfg_flag);
+ print_if_bit("MBEDTLS_SSL_DTLS_ANTI_REPLAY",
+ CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT,
+ context_cfg_flag);
+ print_if_bit("MBEDTLS_SSL_ALPN", CONTEXT_CONFIG_ALPN_BIT, context_cfg_flag);
+
+ CHECK_SSL_END(4);
+ session_len = ((uint32_t) ssl[0] << 24) |
+ ((uint32_t) ssl[1] << 16) |
+ ((uint32_t) ssl[2] << 8) |
+ ((uint32_t) ssl[3]);
+ ssl += 4;
+ printf_dbg("Session length %u\n", session_len);
+
+ CHECK_SSL_END(session_len);
+ print_deserialized_ssl_session(ssl, session_len, session_cfg_flag);
+ ssl += session_len;
+
+ printf("\nRandom bytes:\n\t");
+
+ CHECK_SSL_END(TRANSFORM_RANDBYTE_LEN);
+ print_hex(ssl, TRANSFORM_RANDBYTE_LEN, 22, "\t");
+ ssl += TRANSFORM_RANDBYTE_LEN;
+
+ printf("\nContext others:\n");
+
+ if (CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT & context_cfg_flag) {
+ uint8_t cid_len;
+
+ CHECK_SSL_END(1);
+ cid_len = *ssl++;
+ printf_dbg("In CID length %u\n", (uint32_t) cid_len);
+
+ printf("\tin CID : ");
+ if (cid_len > 0) {
+ CHECK_SSL_END(cid_len);
+ print_hex(ssl, cid_len, 20, "\t");
+ ssl += cid_len;
+ } else {
+ printf("none\n");
+ }
+
+ CHECK_SSL_END(1);
+ cid_len = *ssl++;
+ printf_dbg("Out CID length %u\n", (uint32_t) cid_len);
+
+ printf("\tout CID : ");
+ if (cid_len > 0) {
+ CHECK_SSL_END(cid_len);
+ print_hex(ssl, cid_len, 20, "\t");
+ ssl += cid_len;
+ } else {
+ printf("none\n");
+ }
+ }
+
+ if (CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT & context_cfg_flag) {
+ uint32_t badmac_seen;
+
+ CHECK_SSL_END(4);
+ badmac_seen = ((uint32_t) ssl[0] << 24) |
+ ((uint32_t) ssl[1] << 16) |
+ ((uint32_t) ssl[2] << 8) |
+ ((uint32_t) ssl[3]);
+ ssl += 4;
+ printf("\tbad MAC seen number : %u\n", badmac_seen);
+
+ /* value 'in_window_top' from mbedtls_ssl_context */
+ printf("\tlast validated record sequence no. : ");
+ CHECK_SSL_END(8);
+ print_hex(ssl, 8, 20, "");
+ ssl += 8;
+
+ /* value 'in_window' from mbedtls_ssl_context */
+ printf("\tbitmask for replay detection : ");
+ CHECK_SSL_END(8);
+ print_hex(ssl, 8, 20, "");
+ ssl += 8;
+ }
+
+ if (conf_dtls_proto) {
+ CHECK_SSL_END(1);
+ printf("\tDTLS datagram packing : %s\n",
+ get_enabled_str(!(*ssl++)));
+ }
+
+ /* value 'cur_out_ctr' from mbedtls_ssl_context */
+ printf("\toutgoing record sequence no. : ");
+ CHECK_SSL_END(8);
+ print_hex(ssl, 8, 20, "");
+ ssl += 8;
+
+ if (conf_dtls_proto) {
+ uint16_t mtu;
+ CHECK_SSL_END(2);
+ mtu = (ssl[0] << 8) | ssl[1];
+ ssl += 2;
+ printf("\tMTU : %u\n", mtu);
+ }
+
+
+ if (CONTEXT_CONFIG_ALPN_BIT & context_cfg_flag) {
+ uint8_t alpn_len;
+
+ CHECK_SSL_END(1);
+ alpn_len = *ssl++;
+ printf_dbg("ALPN length %u\n", (uint32_t) alpn_len);
+
+ printf("\tALPN negotiation : ");
+ CHECK_SSL_END(alpn_len);
+ if (alpn_len > 0) {
+ if (strlen((const char *) ssl) == alpn_len) {
+ printf("%s\n", ssl);
+ } else {
+ printf("\n");
+ printf_err("\tALPN negotiation is incorrect\n");
+ }
+ ssl += alpn_len;
+ } else {
+ printf("not selected\n");
+ }
+ }
+
+ if (0 != (end - ssl)) {
+ printf_err("%i bytes left to analyze from context\n", (int32_t) (end - ssl));
+ }
+ printf("\n");
+}
+
+int main(int argc, char *argv[])
+{
+ enum { SSL_INIT_LEN = 4096 };
+
+ uint32_t b64_counter = 0;
+ uint8_t *b64_buf = NULL;
+ uint8_t *ssl_buf = NULL;
+ size_t b64_max_len = SSL_INIT_LEN;
+ size_t ssl_max_len = SSL_INIT_LEN;
+ size_t ssl_len = 0;
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ psa_status_t status = psa_crypto_init();
+ if (status != PSA_SUCCESS) {
+ mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
+ (int) status);
+ return MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
+ }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ /* The 'b64_file' is opened when parsing arguments to check that the
+ * file name is correct */
+ parse_arguments(argc, argv);
+
+ if (NULL != b64_file) {
+ b64_buf = malloc(SSL_INIT_LEN);
+ ssl_buf = malloc(SSL_INIT_LEN);
+
+ if (NULL == b64_buf || NULL == ssl_buf) {
+ printf_err(alloc_err);
+ fclose(b64_file);
+ b64_file = NULL;
+ }
+ }
+
+ while (NULL != b64_file) {
+ size_t b64_len = read_next_b64_code(&b64_buf, &b64_max_len);
+ if (b64_len > 0) {
+ int ret;
+ size_t ssl_required_len = b64_len * 3 / 4 + 1;
+
+ /* Allocate more memory if necessary. */
+ if (ssl_required_len > ssl_max_len) {
+ void *ptr = realloc(ssl_buf, ssl_required_len);
+ if (NULL == ptr) {
+ printf_err(alloc_err);
+ fclose(b64_file);
+ b64_file = NULL;
+ break;
+ }
+ ssl_buf = ptr;
+ ssl_max_len = ssl_required_len;
+ }
+
+ printf("\nDeserializing number %u:\n", ++b64_counter);
+
+ printf("\nBase64 code:\n");
+ print_b64(b64_buf, b64_len);
+
+ ret = mbedtls_base64_decode(ssl_buf, ssl_max_len, &ssl_len, b64_buf, b64_len);
+ if (ret != 0) {
+ mbedtls_strerror(ret, (char *) b64_buf, b64_max_len);
+ printf_err("base64 code cannot be decoded - %s\n", b64_buf);
+ continue;
+ }
+
+ if (debug) {
+ printf("\nDecoded data in hex:\n\t");
+ print_hex(ssl_buf, ssl_len, 25, "\t");
+ }
+
+ print_deserialized_ssl_context(ssl_buf, ssl_len);
+
+ } else {
+ fclose(b64_file);
+ b64_file = NULL;
+ }
+ }
+
+ free(b64_buf);
+ free(ssl_buf);
+
+ if (b64_counter > 0) {
+ printf_dbg("Finished. Found %u base64 codes\n", b64_counter);
+ } else {
+ printf("Finished. No valid base64 code found\n");
+ }
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ mbedtls_psa_crypto_free();
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ return 0;
+}
+
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
diff --git a/programs/ssl/ssl_fork_server.c b/programs/ssl/ssl_fork_server.c
new file mode 100644
index 00000000000..f4822b7e688
--- /dev/null
+++ b/programs/ssl/ssl_fork_server.c
@@ -0,0 +1,381 @@
+/*
+ * SSL server demonstration program using fork() for handling multiple clients
+ *
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "mbedtls/build_info.h"
+
+#include "mbedtls/platform.h"
+
+#if !defined(MBEDTLS_BIGNUM_C) || !defined(MBEDTLS_ENTROPY_C) || \
+ !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_SRV_C) || \
+ !defined(MBEDTLS_NET_C) || !defined(MBEDTLS_RSA_C) || \
+ !defined(MBEDTLS_CTR_DRBG_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \
+ !defined(MBEDTLS_TIMING_C) || !defined(MBEDTLS_FS_IO) || \
+ !defined(MBEDTLS_PEM_PARSE_C)
+int main(int argc, char *argv[])
+{
+ ((void) argc);
+ ((void) argv);
+
+ mbedtls_printf("MBEDTLS_BIGNUM_C and/or MBEDTLS_ENTROPY_C "
+ "and/or MBEDTLS_SSL_TLS_C and/or MBEDTLS_SSL_SRV_C and/or "
+ "MBEDTLS_NET_C and/or MBEDTLS_RSA_C and/or "
+ "MBEDTLS_CTR_DRBG_C and/or MBEDTLS_X509_CRT_PARSE_C and/or "
+ "MBEDTLS_TIMING_C and/or MBEDTLS_PEM_PARSE_C not defined.\n");
+ mbedtls_exit(0);
+}
+#elif defined(_WIN32)
+int main(void)
+{
+ mbedtls_printf("_WIN32 defined. This application requires fork() and signals "
+ "to work correctly.\n");
+ mbedtls_exit(0);
+}
+#else
+
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "test/certs.h"
+#include "mbedtls/x509.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/net_sockets.h"
+#include "mbedtls/timing.h"
+
+#include <string.h>
+#include <signal.h>
+
+#if !defined(_MSC_VER) || defined(EFIX64) || defined(EFI32)
+#include <unistd.h>
+#endif
+
+#define HTTP_RESPONSE \
+ "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" \
+ "<h2>Mbed TLS Test Server</h2>\r\n" \
+ "<p>Successful connection using: %s</p>\r\n"
+
+#define DEBUG_LEVEL 0
+
+
+static void my_debug(void *ctx, int level,
+ const char *file, int line,
+ const char *str)
+{
+ ((void) level);
+
+ mbedtls_fprintf((FILE *) ctx, "%s:%04d: %s", file, line, str);
+ fflush((FILE *) ctx);
+}
+
+int main(void)
+{
+ int ret = 1, len, cnt = 0, pid;
+ int exit_code = MBEDTLS_EXIT_FAILURE;
+ mbedtls_net_context listen_fd, client_fd;
+ unsigned char buf[1024];
+ const char *pers = "ssl_fork_server";
+
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_ssl_context ssl;
+ mbedtls_ssl_config conf;
+ mbedtls_x509_crt srvcert;
+ mbedtls_pk_context pkey;
+
+ mbedtls_net_init(&listen_fd);
+ mbedtls_net_init(&client_fd);
+ mbedtls_ssl_init(&ssl);
+ mbedtls_ssl_config_init(&conf);
+ mbedtls_entropy_init(&entropy);
+ mbedtls_pk_init(&pkey);
+ mbedtls_x509_crt_init(&srvcert);
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ psa_status_t status = psa_crypto_init();
+ if (status != PSA_SUCCESS) {
+ mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
+ (int) status);
+ goto exit;
+ }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ signal(SIGCHLD, SIG_IGN);
+
+ /*
+ * 0. Initial seeding of the RNG
+ */
+ mbedtls_printf("\n . Initial seeding of the random generator...");
+ fflush(stdout);
+
+ if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
+ (const unsigned char *) pers,
+ strlen(pers))) != 0) {
+ mbedtls_printf(" failed! mbedtls_ctr_drbg_seed returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 1. Load the certificates and private RSA key
+ */
+ mbedtls_printf(" . Loading the server cert. and key...");
+ fflush(stdout);
+
+ /*
+ * This demonstration program uses embedded test certificates.
+ * Instead, you may want to use mbedtls_x509_crt_parse_file() to read the
+ * server and CA certificates, as well as mbedtls_pk_parse_keyfile().
+ */
+ ret = mbedtls_x509_crt_parse(&srvcert, (const unsigned char *) mbedtls_test_srv_crt,
+ mbedtls_test_srv_crt_len);
+ if (ret != 0) {
+ mbedtls_printf(" failed! mbedtls_x509_crt_parse returned %d\n\n", ret);
+ goto exit;
+ }
+
+ ret = mbedtls_x509_crt_parse(&srvcert, (const unsigned char *) mbedtls_test_cas_pem,
+ mbedtls_test_cas_pem_len);
+ if (ret != 0) {
+ mbedtls_printf(" failed! mbedtls_x509_crt_parse returned %d\n\n", ret);
+ goto exit;
+ }
+
+ ret = mbedtls_pk_parse_key(&pkey, (const unsigned char *) mbedtls_test_srv_key,
+ mbedtls_test_srv_key_len, NULL, 0,
+ mbedtls_ctr_drbg_random, &ctr_drbg);
+ if (ret != 0) {
+ mbedtls_printf(" failed! mbedtls_pk_parse_key returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 1b. Prepare SSL configuration
+ */
+ mbedtls_printf(" . Configuring SSL...");
+ fflush(stdout);
+
+ if ((ret = mbedtls_ssl_config_defaults(&conf,
+ MBEDTLS_SSL_IS_SERVER,
+ MBEDTLS_SSL_TRANSPORT_STREAM,
+ MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
+ mbedtls_printf(" failed! mbedtls_ssl_config_defaults returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
+ mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
+
+ mbedtls_ssl_conf_ca_chain(&conf, srvcert.next, NULL);
+ if ((ret = mbedtls_ssl_conf_own_cert(&conf, &srvcert, &pkey)) != 0) {
+ mbedtls_printf(" failed! mbedtls_ssl_conf_own_cert returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 2. Setup the listening TCP socket
+ */
+ mbedtls_printf(" . Bind on https://localhost:4433/ ...");
+ fflush(stdout);
+
+ if ((ret = mbedtls_net_bind(&listen_fd, NULL, "4433", MBEDTLS_NET_PROTO_TCP)) != 0) {
+ mbedtls_printf(" failed! mbedtls_net_bind returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ while (1) {
+ /*
+ * 3. Wait until a client connects
+ */
+ mbedtls_net_init(&client_fd);
+ mbedtls_ssl_init(&ssl);
+
+ mbedtls_printf(" . Waiting for a remote connection ...\n");
+ fflush(stdout);
+
+ if ((ret = mbedtls_net_accept(&listen_fd, &client_fd,
+ NULL, 0, NULL)) != 0) {
+ mbedtls_printf(" failed! mbedtls_net_accept returned %d\n\n", ret);
+ goto exit;
+ }
+
+ /*
+ * 3.5. Forking server thread
+ */
+
+ mbedtls_printf(" . Forking to handle connection ...");
+ fflush(stdout);
+
+ pid = fork();
+
+ if (pid < 0) {
+ mbedtls_printf(" failed! fork returned %d\n\n", pid);
+ goto exit;
+ }
+
+ if (pid != 0) {
+ mbedtls_printf(" ok\n");
+ mbedtls_net_close(&client_fd);
+
+ if ((ret = mbedtls_ctr_drbg_reseed(&ctr_drbg,
+ (const unsigned char *) "parent",
+ 6)) != 0) {
+ mbedtls_printf(" failed! mbedtls_ctr_drbg_reseed returned %d\n\n", ret);
+ goto exit;
+ }
+
+ continue;
+ }
+
+ mbedtls_net_close(&listen_fd);
+
+ pid = getpid();
+
+ /*
+ * 4. Setup stuff
+ */
+ mbedtls_printf("pid %d: Setting up the SSL data.\n", pid);
+ fflush(stdout);
+
+ if ((ret = mbedtls_ctr_drbg_reseed(&ctr_drbg,
+ (const unsigned char *) "child",
+ 5)) != 0) {
+ mbedtls_printf(
+ "pid %d: SSL setup failed! mbedtls_ctr_drbg_reseed returned %d\n\n",
+ pid, ret);
+ goto exit;
+ }
+
+ if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
+ mbedtls_printf(
+ "pid %d: SSL setup failed! mbedtls_ssl_setup returned %d\n\n",
+ pid, ret);
+ goto exit;
+ }
+
+ mbedtls_ssl_set_bio(&ssl, &client_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
+
+ mbedtls_printf("pid %d: SSL setup ok\n", pid);
+
+ /*
+ * 5. Handshake
+ */
+ mbedtls_printf("pid %d: Performing the SSL/TLS handshake.\n", pid);
+ fflush(stdout);
+
+ while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ mbedtls_printf(
+ "pid %d: SSL handshake failed! mbedtls_ssl_handshake returned %d\n\n",
+ pid, ret);
+ goto exit;
+ }
+ }
+
+ mbedtls_printf("pid %d: SSL handshake ok\n", pid);
+
+ /*
+ * 6. Read the HTTP Request
+ */
+ mbedtls_printf("pid %d: Start reading from client.\n", pid);
+ fflush(stdout);
+
+ do {
+ len = sizeof(buf) - 1;
+ memset(buf, 0, sizeof(buf));
+ ret = mbedtls_ssl_read(&ssl, buf, len);
+
+ if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+ continue;
+ }
+
+ if (ret <= 0) {
+ switch (ret) {
+ case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+ mbedtls_printf("pid %d: connection was closed gracefully\n", pid);
+ break;
+
+ case MBEDTLS_ERR_NET_CONN_RESET:
+ mbedtls_printf("pid %d: connection was reset by peer\n", pid);
+ break;
+
+ default:
+ mbedtls_printf("pid %d: mbedtls_ssl_read returned %d\n", pid, ret);
+ break;
+ }
+
+ break;
+ }
+
+ len = ret;
+ mbedtls_printf("pid %d: %d bytes read\n\n%s", pid, len, (char *) buf);
+
+ if (ret > 0) {
+ break;
+ }
+ } while (1);
+
+ /*
+ * 7. Write the 200 Response
+ */
+ mbedtls_printf("pid %d: Start writing to client.\n", pid);
+ fflush(stdout);
+
+ len = sprintf((char *) buf, HTTP_RESPONSE,
+ mbedtls_ssl_get_ciphersuite(&ssl));
+
+ while (cnt++ < 100) {
+ while ((ret = mbedtls_ssl_write(&ssl, buf, len)) <= 0) {
+ if (ret == MBEDTLS_ERR_NET_CONN_RESET) {
+ mbedtls_printf(
+ "pid %d: Write failed! peer closed the connection\n\n", pid);
+ goto exit;
+ }
+
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ mbedtls_printf(
+ "pid %d: Write failed! mbedtls_ssl_write returned %d\n\n",
+ pid, ret);
+ goto exit;
+ }
+ }
+ len = ret;
+ mbedtls_printf("pid %d: %d bytes written\n\n%s\n", pid, len, (char *) buf);
+
+ mbedtls_net_usleep(1000000);
+ }
+
+ mbedtls_ssl_close_notify(&ssl);
+ goto exit;
+ }
+
+ exit_code = MBEDTLS_EXIT_SUCCESS;
+
+exit:
+ mbedtls_net_free(&client_fd);
+ mbedtls_net_free(&listen_fd);
+ mbedtls_x509_crt_free(&srvcert);
+ mbedtls_pk_free(&pkey);
+ mbedtls_ssl_free(&ssl);
+ mbedtls_ssl_config_free(&conf);
+ mbedtls_ctr_drbg_free(&ctr_drbg);
+ mbedtls_entropy_free(&entropy);
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ mbedtls_psa_crypto_free();
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ mbedtls_exit(exit_code);
+}
+#endif /* MBEDTLS_BIGNUM_C && MBEDTLS_ENTROPY_C &&
+ MBEDTLS_SSL_TLS_C && MBEDTLS_SSL_SRV_C && MBEDTLS_NET_C &&
+ MBEDTLS_RSA_C && MBEDTLS_CTR_DRBG_C && MBEDTLS_PEM_PARSE_C &&
+ ! _WIN32 */
diff --git a/programs/ssl/ssl_mail_client.c b/programs/ssl/ssl_mail_client.c
new file mode 100644
index 00000000000..febb881c804
--- /dev/null
+++ b/programs/ssl/ssl_mail_client.c
@@ -0,0 +1,804 @@
+/*
+ * SSL client for SMTP servers
+ *
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+/* Enable definition of gethostname() even when compiling with -std=c99. Must
+ * be set before mbedtls_config.h, which pulls in glibc's features.h indirectly.
+ * Harmless on other platforms. */
+
+#define _POSIX_C_SOURCE 200112L
+#define _XOPEN_SOURCE 600
+
+#include "mbedtls/build_info.h"
+
+#include "mbedtls/platform.h"
+
+#if !defined(MBEDTLS_BIGNUM_C) || !defined(MBEDTLS_ENTROPY_C) || \
+ !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_CLI_C) || \
+ !defined(MBEDTLS_NET_C) || !defined(MBEDTLS_RSA_C) || \
+ !defined(MBEDTLS_CTR_DRBG_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \
+ !defined(MBEDTLS_FS_IO)
+int main(void)
+{
+ mbedtls_printf("MBEDTLS_BIGNUM_C and/or MBEDTLS_ENTROPY_C and/or "
+ "MBEDTLS_SSL_TLS_C and/or MBEDTLS_SSL_CLI_C and/or "
+ "MBEDTLS_NET_C and/or MBEDTLS_RSA_C and/or "
+ "MBEDTLS_CTR_DRBG_C and/or MBEDTLS_X509_CRT_PARSE_C "
+ "not defined.\n");
+ mbedtls_exit(0);
+}
+#else
+
+#include "mbedtls/base64.h"
+#include "mbedtls/error.h"
+#include "mbedtls/net_sockets.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "test/certs.h"
+#include "mbedtls/x509.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#if !defined(_MSC_VER) || defined(EFIX64) || defined(EFI32)
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#if defined(_WIN32) || defined(_WIN32_WCE)
+#include <winsock2.h>
+#include <windows.h>
+
+#if defined(_MSC_VER)
+#if defined(_WIN32_WCE)
+#pragma comment( lib, "ws2.lib" )
+#else
+#pragma comment( lib, "ws2_32.lib" )
+#endif
+#endif /* _MSC_VER */
+#endif
+
+#define DFL_SERVER_NAME "localhost"
+#define DFL_SERVER_PORT "465"
+#define DFL_USER_NAME "user"
+#define DFL_USER_PWD "password"
+#define DFL_MAIL_FROM ""
+#define DFL_MAIL_TO ""
+#define DFL_DEBUG_LEVEL 0
+#define DFL_CA_FILE ""
+#define DFL_CRT_FILE ""
+#define DFL_KEY_FILE ""
+#define DFL_FORCE_CIPHER 0
+#define DFL_MODE 0
+#define DFL_AUTHENTICATION 0
+
+#define MODE_SSL_TLS 0
+#define MODE_STARTTLS 0
+
+#if defined(MBEDTLS_BASE64_C)
+#define USAGE_AUTH \
+ " authentication=%%d default: 0 (disabled)\n" \
+ " user_name=%%s default: \"" DFL_USER_NAME "\"\n" \
+ " user_pwd=%%s default: \"" \
+ DFL_USER_PWD "\"\n"
+#else
+#define USAGE_AUTH \
+ " authentication options disabled. (Require MBEDTLS_BASE64_C)\n"
+#endif /* MBEDTLS_BASE64_C */
+
+#if defined(MBEDTLS_FS_IO)
+#define USAGE_IO \
+ " ca_file=%%s default: \"\" (pre-loaded)\n" \
+ " crt_file=%%s default: \"\" (pre-loaded)\n" \
+ " key_file=%%s default: \"\" (pre-loaded)\n"
+#else
+#define USAGE_IO \
+ " No file operations available (MBEDTLS_FS_IO not defined)\n"
+#endif /* MBEDTLS_FS_IO */
+
+#define USAGE \
+ "\n usage: ssl_mail_client param=<>...\n" \
+ "\n acceptable parameters:\n" \
+ " server_name=%%s default: " DFL_SERVER_NAME "\n" \
+ " server_port=%%d default: " \
+ DFL_SERVER_PORT "\n" \
+ " debug_level=%%d default: 0 (disabled)\n" \
+ " mode=%%d default: 0 (SSL/TLS) (1 for STARTTLS)\n" \
+ USAGE_AUTH \
+ " mail_from=%%s default: \"\"\n" \
+ " mail_to=%%s default: \"\"\n" \
+ USAGE_IO \
+ " force_ciphersuite=<name> default: all enabled\n" \
+ " acceptable ciphersuite names:\n"
+
+
+/*
+ * global options
+ */
+struct options {
+ const char *server_name; /* hostname of the server (client only) */
+ const char *server_port; /* port on which the ssl service runs */
+ int debug_level; /* level of debugging */
+ int authentication; /* if authentication is required */
+ int mode; /* SSL/TLS (0) or STARTTLS (1) */
+ const char *user_name; /* username to use for authentication */
+ const char *user_pwd; /* password to use for authentication */
+ const char *mail_from; /* E-Mail address to use as sender */
+ const char *mail_to; /* E-Mail address to use as recipient */
+ const char *ca_file; /* the file with the CA certificate(s) */
+ const char *crt_file; /* the file with the client certificate */
+ const char *key_file; /* the file with the client key */
+ int force_ciphersuite[2]; /* protocol/ciphersuite to use, or all */
+} opt;
+
+static void my_debug(void *ctx, int level,
+ const char *file, int line,
+ const char *str)
+{
+ ((void) level);
+
+ mbedtls_fprintf((FILE *) ctx, "%s:%04d: %s", file, line, str);
+ fflush((FILE *) ctx);
+}
+
+static int do_handshake(mbedtls_ssl_context *ssl)
+{
+ int ret;
+ uint32_t flags;
+ unsigned char buf[1024];
+ memset(buf, 0, 1024);
+
+ /*
+ * 4. Handshake
+ */
+ mbedtls_printf(" . Performing the SSL/TLS handshake...");
+ fflush(stdout);
+
+ while ((ret = mbedtls_ssl_handshake(ssl)) != 0) {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+#if defined(MBEDTLS_ERROR_C)
+ mbedtls_strerror(ret, (char *) buf, 1024);
+#endif
+ mbedtls_printf(" failed\n ! mbedtls_ssl_handshake returned %d: %s\n\n", ret, buf);
+ return -1;
+ }
+ }
+
+ mbedtls_printf(" ok\n [ Ciphersuite is %s ]\n",
+ mbedtls_ssl_get_ciphersuite(ssl));
+
+ /*
+ * 5. Verify the server certificate
+ */
+ mbedtls_printf(" . Verifying peer X.509 certificate...");
+
+ /* In real life, we probably want to bail out when ret != 0 */
+ if ((flags = mbedtls_ssl_get_verify_result(ssl)) != 0) {
+#if !defined(MBEDTLS_X509_REMOVE_INFO)
+ char vrfy_buf[512];
+#endif
+
+ mbedtls_printf(" failed\n");
+
+#if !defined(MBEDTLS_X509_REMOVE_INFO)
+ mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags);
+
+ mbedtls_printf("%s\n", vrfy_buf);
+#endif
+ } else {
+ mbedtls_printf(" ok\n");
+ }
+
+#if !defined(MBEDTLS_X509_REMOVE_INFO)
+ mbedtls_printf(" . Peer certificate information ...\n");
+ mbedtls_x509_crt_info((char *) buf, sizeof(buf) - 1, " ",
+ mbedtls_ssl_get_peer_cert(ssl));
+ mbedtls_printf("%s\n", buf);
+#endif
+
+ return 0;
+}
+
+static int write_ssl_data(mbedtls_ssl_context *ssl, unsigned char *buf, size_t len)
+{
+ int ret;
+
+ mbedtls_printf("\n%s", buf);
+ while (len && (ret = mbedtls_ssl_write(ssl, buf, len)) <= 0) {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_write returned %d\n\n", ret);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int write_ssl_and_get_response(mbedtls_ssl_context *ssl, unsigned char *buf, size_t len)
+{
+ int ret;
+ unsigned char data[128];
+ char code[4];
+ size_t i, idx = 0;
+
+ mbedtls_printf("\n%s", buf);
+ while (len && (ret = mbedtls_ssl_write(ssl, buf, len)) <= 0) {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_write returned %d\n\n", ret);
+ return -1;
+ }
+ }
+
+ do {
+ len = sizeof(data) - 1;
+ memset(data, 0, sizeof(data));
+ ret = mbedtls_ssl_read(ssl, data, len);
+
+ if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+ continue;
+ }
+
+ if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
+ return -1;
+ }
+
+ if (ret <= 0) {
+ mbedtls_printf("failed\n ! mbedtls_ssl_read returned %d\n\n", ret);
+ return -1;
+ }
+
+ mbedtls_printf("\n%s", data);
+ len = ret;
+ for (i = 0; i < len; i++) {
+ if (data[i] != '\n') {
+ if (idx < 4) {
+ code[idx++] = data[i];
+ }
+ continue;
+ }
+
+ if (idx == 4 && code[0] >= '0' && code[0] <= '9' && code[3] == ' ') {
+ code[3] = '\0';
+ return atoi(code);
+ }
+
+ idx = 0;
+ }
+ } while (1);
+}
+
+static int write_and_get_response(mbedtls_net_context *sock_fd, unsigned char *buf, size_t len)
+{
+ int ret;
+ unsigned char data[128];
+ char code[4];
+ size_t i, idx = 0;
+
+ mbedtls_printf("\n%s", buf);
+ if (len && (ret = mbedtls_net_send(sock_fd, buf, len)) <= 0) {
+ mbedtls_printf(" failed\n ! mbedtls_net_send returned %d\n\n", ret);
+ return -1;
+ }
+
+ do {
+ len = sizeof(data) - 1;
+ memset(data, 0, sizeof(data));
+ ret = mbedtls_net_recv(sock_fd, data, len);
+
+ if (ret <= 0) {
+ mbedtls_printf("failed\n ! mbedtls_net_recv returned %d\n\n", ret);
+ return -1;
+ }
+
+ data[len] = '\0';
+ mbedtls_printf("\n%s", data);
+ len = ret;
+ for (i = 0; i < len; i++) {
+ if (data[i] != '\n') {
+ if (idx < 4) {
+ code[idx++] = data[i];
+ }
+ continue;
+ }
+
+ if (idx == 4 && code[0] >= '0' && code[0] <= '9' && code[3] == ' ') {
+ code[3] = '\0';
+ return atoi(code);
+ }
+
+ idx = 0;
+ }
+ } while (1);
+}
+
+int main(int argc, char *argv[])
+{
+ int ret = 1, len;
+ int exit_code = MBEDTLS_EXIT_FAILURE;
+ mbedtls_net_context server_fd;
+#if defined(MBEDTLS_BASE64_C)
+ unsigned char base[1024];
+ /* buf is used as the destination buffer for printing base with the format:
+ * "%s\r\n". Hence, the size of buf should be at least the size of base
+ * plus 2 bytes for the \r and \n characters.
+ */
+ unsigned char buf[sizeof(base) + 2];
+#else
+ unsigned char buf[1024];
+#endif
+ char hostname[32];
+ const char *pers = "ssl_mail_client";
+
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_ssl_context ssl;
+ mbedtls_ssl_config conf;
+ mbedtls_x509_crt cacert;
+ mbedtls_x509_crt clicert;
+ mbedtls_pk_context pkey;
+ int i;
+ size_t n;
+ char *p, *q;
+ const int *list;
+
+ /*
+ * Make sure memory references are valid in case we exit early.
+ */
+ mbedtls_net_init(&server_fd);
+ mbedtls_ssl_init(&ssl);
+ mbedtls_ssl_config_init(&conf);
+ memset(&buf, 0, sizeof(buf));
+ mbedtls_x509_crt_init(&cacert);
+ mbedtls_x509_crt_init(&clicert);
+ mbedtls_pk_init(&pkey);
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+ mbedtls_entropy_init(&entropy);
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ psa_status_t status = psa_crypto_init();
+ if (status != PSA_SUCCESS) {
+ mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
+ (int) status);
+ goto exit;
+ }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ if (argc < 2) {
+usage:
+ mbedtls_printf(USAGE);
+
+ list = mbedtls_ssl_list_ciphersuites();
+ while (*list) {
+ mbedtls_printf(" %s\n", mbedtls_ssl_get_ciphersuite_name(*list));
+ list++;
+ }
+ mbedtls_printf("\n");
+ goto exit;
+ }
+
+ opt.server_name = DFL_SERVER_NAME;
+ opt.server_port = DFL_SERVER_PORT;
+ opt.debug_level = DFL_DEBUG_LEVEL;
+ opt.authentication = DFL_AUTHENTICATION;
+ opt.mode = DFL_MODE;
+ opt.user_name = DFL_USER_NAME;
+ opt.user_pwd = DFL_USER_PWD;
+ opt.mail_from = DFL_MAIL_FROM;
+ opt.mail_to = DFL_MAIL_TO;
+ opt.ca_file = DFL_CA_FILE;
+ opt.crt_file = DFL_CRT_FILE;
+ opt.key_file = DFL_KEY_FILE;
+ opt.force_ciphersuite[0] = DFL_FORCE_CIPHER;
+
+ for (i = 1; i < argc; i++) {
+ p = argv[i];
+ if ((q = strchr(p, '=')) == NULL) {
+ goto usage;
+ }
+ *q++ = '\0';
+
+ if (strcmp(p, "server_name") == 0) {
+ opt.server_name = q;
+ } else if (strcmp(p, "server_port") == 0) {
+ opt.server_port = q;
+ } else if (strcmp(p, "debug_level") == 0) {
+ opt.debug_level = atoi(q);
+ if (opt.debug_level < 0 || opt.debug_level > 65535) {
+ goto usage;
+ }
+ } else if (strcmp(p, "authentication") == 0) {
+ opt.authentication = atoi(q);
+ if (opt.authentication < 0 || opt.authentication > 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "mode") == 0) {
+ opt.mode = atoi(q);
+ if (opt.mode < 0 || opt.mode > 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "user_name") == 0) {
+ opt.user_name = q;
+ } else if (strcmp(p, "user_pwd") == 0) {
+ opt.user_pwd = q;
+ } else if (strcmp(p, "mail_from") == 0) {
+ opt.mail_from = q;
+ } else if (strcmp(p, "mail_to") == 0) {
+ opt.mail_to = q;
+ } else if (strcmp(p, "ca_file") == 0) {
+ opt.ca_file = q;
+ } else if (strcmp(p, "crt_file") == 0) {
+ opt.crt_file = q;
+ } else if (strcmp(p, "key_file") == 0) {
+ opt.key_file = q;
+ } else if (strcmp(p, "force_ciphersuite") == 0) {
+ opt.force_ciphersuite[0] = -1;
+
+ opt.force_ciphersuite[0] = mbedtls_ssl_get_ciphersuite_id(q);
+
+ if (opt.force_ciphersuite[0] <= 0) {
+ goto usage;
+ }
+
+ opt.force_ciphersuite[1] = 0;
+ } else {
+ goto usage;
+ }
+ }
+
+ /*
+ * 0. Initialize the RNG and the session data
+ */
+ mbedtls_printf("\n . Seeding the random number generator...");
+ fflush(stdout);
+
+ if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
+ (const unsigned char *) pers,
+ strlen(pers))) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 1.1. Load the trusted CA
+ */
+ mbedtls_printf(" . Loading the CA root certificate ...");
+ fflush(stdout);
+
+#if defined(MBEDTLS_FS_IO)
+ if (strlen(opt.ca_file)) {
+ ret = mbedtls_x509_crt_parse_file(&cacert, opt.ca_file);
+ } else
+#endif
+#if defined(MBEDTLS_PEM_PARSE_C)
+ ret = mbedtls_x509_crt_parse(&cacert, (const unsigned char *) mbedtls_test_cas_pem,
+ mbedtls_test_cas_pem_len);
+#else
+ {
+ mbedtls_printf("MBEDTLS_PEM_PARSE_C not defined.");
+ goto exit;
+ }
+#endif
+ if (ret < 0) {
+ mbedtls_printf(" failed\n ! mbedtls_x509_crt_parse returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok (%d skipped)\n", ret);
+
+ /*
+ * 1.2. Load own certificate and private key
+ *
+ * (can be skipped if client authentication is not required)
+ */
+ mbedtls_printf(" . Loading the client cert. and key...");
+ fflush(stdout);
+
+#if defined(MBEDTLS_FS_IO)
+ if (strlen(opt.crt_file)) {
+ ret = mbedtls_x509_crt_parse_file(&clicert, opt.crt_file);
+ } else
+#endif
+ ret = mbedtls_x509_crt_parse(&clicert, (const unsigned char *) mbedtls_test_cli_crt,
+ mbedtls_test_cli_crt_len);
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_x509_crt_parse returned %d\n\n", ret);
+ goto exit;
+ }
+
+#if defined(MBEDTLS_FS_IO)
+ if (strlen(opt.key_file)) {
+ ret = mbedtls_pk_parse_keyfile(&pkey, opt.key_file, "",
+ mbedtls_ctr_drbg_random, &ctr_drbg);
+ } else
+#endif
+#if defined(MBEDTLS_PEM_PARSE_C)
+ {
+ ret = mbedtls_pk_parse_key(&pkey,
+ (const unsigned char *) mbedtls_test_cli_key,
+ mbedtls_test_cli_key_len,
+ NULL,
+ 0,
+ mbedtls_ctr_drbg_random,
+ &ctr_drbg);
+ }
+#else
+ {
+ mbedtls_printf("MBEDTLS_PEM_PARSE_C not defined.");
+ goto exit;
+ }
+#endif
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_pk_parse_key returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 2. Start the connection
+ */
+ mbedtls_printf(" . Connecting to tcp/%s/%s...", opt.server_name,
+ opt.server_port);
+ fflush(stdout);
+
+ if ((ret = mbedtls_net_connect(&server_fd, opt.server_name,
+ opt.server_port, MBEDTLS_NET_PROTO_TCP)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_net_connect returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 3. Setup stuff
+ */
+ mbedtls_printf(" . Setting up the SSL/TLS structure...");
+ fflush(stdout);
+
+ if ((ret = mbedtls_ssl_config_defaults(&conf,
+ MBEDTLS_SSL_IS_CLIENT,
+ MBEDTLS_SSL_TRANSPORT_STREAM,
+ MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret);
+ goto exit;
+ }
+
+ /* OPTIONAL is not optimal for security,
+ * but makes interop easier in this simplified example */
+ mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
+
+ mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
+ mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
+
+ if (opt.force_ciphersuite[0] != DFL_FORCE_CIPHER) {
+ mbedtls_ssl_conf_ciphersuites(&conf, opt.force_ciphersuite);
+ }
+
+ mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
+ if ((ret = mbedtls_ssl_conf_own_cert(&conf, &clicert, &pkey)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret);
+ goto exit;
+ }
+
+ if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_setup returned %d\n\n", ret);
+ goto exit;
+ }
+
+ if ((ret = mbedtls_ssl_set_hostname(&ssl, opt.server_name)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
+
+ mbedtls_printf(" ok\n");
+
+ if (opt.mode == MODE_SSL_TLS) {
+ if (do_handshake(&ssl) != 0) {
+ goto exit;
+ }
+
+ mbedtls_printf(" > Get header from server:");
+ fflush(stdout);
+
+ ret = write_ssl_and_get_response(&ssl, buf, 0);
+ if (ret < 200 || ret > 299) {
+ mbedtls_printf(" failed\n ! server responded with %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ mbedtls_printf(" > Write EHLO to server:");
+ fflush(stdout);
+
+ gethostname(hostname, 32);
+ len = sprintf((char *) buf, "EHLO %s\r\n", hostname);
+ ret = write_ssl_and_get_response(&ssl, buf, len);
+ if (ret < 200 || ret > 299) {
+ mbedtls_printf(" failed\n ! server responded with %d\n\n", ret);
+ goto exit;
+ }
+ } else {
+ mbedtls_printf(" > Get header from server:");
+ fflush(stdout);
+
+ ret = write_and_get_response(&server_fd, buf, 0);
+ if (ret < 200 || ret > 299) {
+ mbedtls_printf(" failed\n ! server responded with %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ mbedtls_printf(" > Write EHLO to server:");
+ fflush(stdout);
+
+ gethostname(hostname, 32);
+ len = sprintf((char *) buf, "EHLO %s\r\n", hostname);
+ ret = write_and_get_response(&server_fd, buf, len);
+ if (ret < 200 || ret > 299) {
+ mbedtls_printf(" failed\n ! server responded with %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ mbedtls_printf(" > Write STARTTLS to server:");
+ fflush(stdout);
+
+ gethostname(hostname, 32);
+ len = sprintf((char *) buf, "STARTTLS\r\n");
+ ret = write_and_get_response(&server_fd, buf, len);
+ if (ret < 200 || ret > 299) {
+ mbedtls_printf(" failed\n ! server responded with %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ if (do_handshake(&ssl) != 0) {
+ goto exit;
+ }
+ }
+
+#if defined(MBEDTLS_BASE64_C)
+ if (opt.authentication) {
+ mbedtls_printf(" > Write AUTH LOGIN to server:");
+ fflush(stdout);
+
+ len = sprintf((char *) buf, "AUTH LOGIN\r\n");
+ ret = write_ssl_and_get_response(&ssl, buf, len);
+ if (ret < 200 || ret > 399) {
+ mbedtls_printf(" failed\n ! server responded with %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ mbedtls_printf(" > Write username to server: %s", opt.user_name);
+ fflush(stdout);
+
+ ret = mbedtls_base64_encode(base, sizeof(base), &n, (const unsigned char *) opt.user_name,
+ strlen(opt.user_name));
+
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_base64_encode returned %d\n\n", ret);
+ goto exit;
+ }
+ len = sprintf((char *) buf, "%s\r\n", base);
+ ret = write_ssl_and_get_response(&ssl, buf, len);
+ if (ret < 300 || ret > 399) {
+ mbedtls_printf(" failed\n ! server responded with %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ mbedtls_printf(" > Write password to server: %s", opt.user_pwd);
+ fflush(stdout);
+
+ ret = mbedtls_base64_encode(base, sizeof(base), &n, (const unsigned char *) opt.user_pwd,
+ strlen(opt.user_pwd));
+
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_base64_encode returned %d\n\n", ret);
+ goto exit;
+ }
+ len = sprintf((char *) buf, "%s\r\n", base);
+ ret = write_ssl_and_get_response(&ssl, buf, len);
+ if (ret < 200 || ret > 399) {
+ mbedtls_printf(" failed\n ! server responded with %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+ }
+#endif
+
+ mbedtls_printf(" > Write MAIL FROM to server:");
+ fflush(stdout);
+
+ len = sprintf((char *) buf, "MAIL FROM:<%s>\r\n", opt.mail_from);
+ ret = write_ssl_and_get_response(&ssl, buf, len);
+ if (ret < 200 || ret > 299) {
+ mbedtls_printf(" failed\n ! server responded with %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ mbedtls_printf(" > Write RCPT TO to server:");
+ fflush(stdout);
+
+ len = sprintf((char *) buf, "RCPT TO:<%s>\r\n", opt.mail_to);
+ ret = write_ssl_and_get_response(&ssl, buf, len);
+ if (ret < 200 || ret > 299) {
+ mbedtls_printf(" failed\n ! server responded with %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ mbedtls_printf(" > Write DATA to server:");
+ fflush(stdout);
+
+ len = sprintf((char *) buf, "DATA\r\n");
+ ret = write_ssl_and_get_response(&ssl, buf, len);
+ if (ret < 300 || ret > 399) {
+ mbedtls_printf(" failed\n ! server responded with %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ mbedtls_printf(" > Write content to server:");
+ fflush(stdout);
+
+ len = sprintf((char *) buf, "From: %s\r\nSubject: Mbed TLS Test mail\r\n\r\n"
+ "This is a simple test mail from the "
+ "Mbed TLS mail client example.\r\n"
+ "\r\n"
+ "Enjoy!", opt.mail_from);
+ ret = write_ssl_data(&ssl, buf, len);
+
+ len = sprintf((char *) buf, "\r\n.\r\n");
+ ret = write_ssl_and_get_response(&ssl, buf, len);
+ if (ret < 200 || ret > 299) {
+ mbedtls_printf(" failed\n ! server responded with %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ mbedtls_ssl_close_notify(&ssl);
+
+ exit_code = MBEDTLS_EXIT_SUCCESS;
+
+exit:
+
+ mbedtls_net_free(&server_fd);
+ mbedtls_x509_crt_free(&clicert);
+ mbedtls_x509_crt_free(&cacert);
+ mbedtls_pk_free(&pkey);
+ mbedtls_ssl_free(&ssl);
+ mbedtls_ssl_config_free(&conf);
+ mbedtls_ctr_drbg_free(&ctr_drbg);
+ mbedtls_entropy_free(&entropy);
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ mbedtls_psa_crypto_free();
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ mbedtls_exit(exit_code);
+}
+#endif /* MBEDTLS_BIGNUM_C && MBEDTLS_ENTROPY_C && MBEDTLS_SSL_TLS_C &&
+ MBEDTLS_SSL_CLI_C && MBEDTLS_NET_C && MBEDTLS_RSA_C **
+ MBEDTLS_CTR_DRBG_C */
diff --git a/programs/ssl/ssl_pthread_server.c b/programs/ssl/ssl_pthread_server.c
new file mode 100644
index 00000000000..fcb8f2f4d5b
--- /dev/null
+++ b/programs/ssl/ssl_pthread_server.c
@@ -0,0 +1,489 @@
+/*
+ * SSL server demonstration program using pthread for handling multiple
+ * clients.
+ *
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "mbedtls/build_info.h"
+
+#include "mbedtls/platform.h"
+
+#if !defined(MBEDTLS_BIGNUM_C) || !defined(MBEDTLS_ENTROPY_C) || \
+ !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_SRV_C) || \
+ !defined(MBEDTLS_NET_C) || !defined(MBEDTLS_RSA_C) || \
+ !defined(MBEDTLS_CTR_DRBG_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \
+ !defined(MBEDTLS_FS_IO) || !defined(MBEDTLS_THREADING_C) || \
+ !defined(MBEDTLS_THREADING_PTHREAD) || !defined(MBEDTLS_PEM_PARSE_C)
+int main(void)
+{
+ mbedtls_printf("MBEDTLS_BIGNUM_C and/or MBEDTLS_ENTROPY_C "
+ "and/or MBEDTLS_SSL_TLS_C and/or MBEDTLS_SSL_SRV_C and/or "
+ "MBEDTLS_NET_C and/or MBEDTLS_RSA_C and/or "
+ "MBEDTLS_CTR_DRBG_C and/or MBEDTLS_X509_CRT_PARSE_C and/or "
+ "MBEDTLS_THREADING_C and/or MBEDTLS_THREADING_PTHREAD "
+ "and/or MBEDTLS_PEM_PARSE_C not defined.\n");
+ mbedtls_exit(0);
+}
+#else
+
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/x509.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/net_sockets.h"
+#include "mbedtls/error.h"
+#include "test/certs.h"
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+#include "mbedtls/ssl_cache.h"
+#endif
+
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+#include "mbedtls/memory_buffer_alloc.h"
+#endif
+
+
+#define HTTP_RESPONSE \
+ "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" \
+ "<h2>Mbed TLS Test Server</h2>\r\n" \
+ "<p>Successful connection using: %s</p>\r\n"
+
+#define DEBUG_LEVEL 0
+
+#define MAX_NUM_THREADS 5
+
+mbedtls_threading_mutex_t debug_mutex;
+
+static void my_mutexed_debug(void *ctx, int level,
+ const char *file, int line,
+ const char *str)
+{
+ long int thread_id = (long int) pthread_self();
+
+ mbedtls_mutex_lock(&debug_mutex);
+
+ ((void) level);
+ mbedtls_fprintf((FILE *) ctx, "%s:%04d: [ #%ld ] %s",
+ file, line, thread_id, str);
+ fflush((FILE *) ctx);
+
+ mbedtls_mutex_unlock(&debug_mutex);
+}
+
+typedef struct {
+ mbedtls_net_context client_fd;
+ int thread_complete;
+ const mbedtls_ssl_config *config;
+} thread_info_t;
+
+typedef struct {
+ int active;
+ thread_info_t data;
+ pthread_t thread;
+} pthread_info_t;
+
+static thread_info_t base_info;
+static pthread_info_t threads[MAX_NUM_THREADS];
+
+static void *handle_ssl_connection(void *data)
+{
+ int ret, len;
+ thread_info_t *thread_info = (thread_info_t *) data;
+ mbedtls_net_context *client_fd = &thread_info->client_fd;
+ long int thread_id = (long int) pthread_self();
+ unsigned char buf[1024];
+ mbedtls_ssl_context ssl;
+
+ /* Make sure memory references are valid */
+ mbedtls_ssl_init(&ssl);
+
+ mbedtls_printf(" [ #%ld ] Setting up SSL/TLS data\n", thread_id);
+
+ /*
+ * 4. Get the SSL context ready
+ */
+ if ((ret = mbedtls_ssl_setup(&ssl, thread_info->config)) != 0) {
+ mbedtls_printf(" [ #%ld ] failed: mbedtls_ssl_setup returned -0x%04x\n",
+ thread_id, (unsigned int) -ret);
+ goto thread_exit;
+ }
+
+ mbedtls_ssl_set_bio(&ssl, client_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
+
+ /*
+ * 5. Handshake
+ */
+ mbedtls_printf(" [ #%ld ] Performing the SSL/TLS handshake\n", thread_id);
+
+ while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ mbedtls_printf(" [ #%ld ] failed: mbedtls_ssl_handshake returned -0x%04x\n",
+ thread_id, (unsigned int) -ret);
+ goto thread_exit;
+ }
+ }
+
+ mbedtls_printf(" [ #%ld ] ok\n", thread_id);
+
+ /*
+ * 6. Read the HTTP Request
+ */
+ mbedtls_printf(" [ #%ld ] < Read from client\n", thread_id);
+
+ do {
+ len = sizeof(buf) - 1;
+ memset(buf, 0, sizeof(buf));
+ ret = mbedtls_ssl_read(&ssl, buf, len);
+
+ if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+ continue;
+ }
+
+ if (ret <= 0) {
+ switch (ret) {
+ case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+ mbedtls_printf(" [ #%ld ] connection was closed gracefully\n",
+ thread_id);
+ goto thread_exit;
+
+ case MBEDTLS_ERR_NET_CONN_RESET:
+ mbedtls_printf(" [ #%ld ] connection was reset by peer\n",
+ thread_id);
+ goto thread_exit;
+
+ default:
+ mbedtls_printf(" [ #%ld ] mbedtls_ssl_read returned -0x%04x\n",
+ thread_id, (unsigned int) -ret);
+ goto thread_exit;
+ }
+ }
+
+ len = ret;
+ mbedtls_printf(" [ #%ld ] %d bytes read\n=====\n%s\n=====\n",
+ thread_id, len, (char *) buf);
+
+ if (ret > 0) {
+ break;
+ }
+ } while (1);
+
+ /*
+ * 7. Write the 200 Response
+ */
+ mbedtls_printf(" [ #%ld ] > Write to client:\n", thread_id);
+
+ len = sprintf((char *) buf, HTTP_RESPONSE,
+ mbedtls_ssl_get_ciphersuite(&ssl));
+
+ while ((ret = mbedtls_ssl_write(&ssl, buf, len)) <= 0) {
+ if (ret == MBEDTLS_ERR_NET_CONN_RESET) {
+ mbedtls_printf(" [ #%ld ] failed: peer closed the connection\n",
+ thread_id);
+ goto thread_exit;
+ }
+
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ mbedtls_printf(" [ #%ld ] failed: mbedtls_ssl_write returned -0x%04x\n",
+ thread_id, (unsigned int) ret);
+ goto thread_exit;
+ }
+ }
+
+ len = ret;
+ mbedtls_printf(" [ #%ld ] %d bytes written\n=====\n%s\n=====\n",
+ thread_id, len, (char *) buf);
+
+ mbedtls_printf(" [ #%ld ] . Closing the connection...", thread_id);
+
+ while ((ret = mbedtls_ssl_close_notify(&ssl)) < 0) {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
+ ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ mbedtls_printf(" [ #%ld ] failed: mbedtls_ssl_close_notify returned -0x%04x\n",
+ thread_id, (unsigned int) ret);
+ goto thread_exit;
+ }
+ }
+
+ mbedtls_printf(" ok\n");
+
+ ret = 0;
+
+thread_exit:
+
+#ifdef MBEDTLS_ERROR_C
+ if (ret != 0) {
+ char error_buf[100];
+ mbedtls_strerror(ret, error_buf, 100);
+ mbedtls_printf(" [ #%ld ] Last error was: -0x%04x - %s\n\n",
+ thread_id, (unsigned int) -ret, error_buf);
+ }
+#endif
+
+ mbedtls_net_free(client_fd);
+ mbedtls_ssl_free(&ssl);
+
+ thread_info->thread_complete = 1;
+
+ return NULL;
+}
+
+static int thread_create(mbedtls_net_context *client_fd)
+{
+ int ret, i;
+
+ /*
+ * Find in-active or finished thread slot
+ */
+ for (i = 0; i < MAX_NUM_THREADS; i++) {
+ if (threads[i].active == 0) {
+ break;
+ }
+
+ if (threads[i].data.thread_complete == 1) {
+ mbedtls_printf(" [ main ] Cleaning up thread %d\n", i);
+ pthread_join(threads[i].thread, NULL);
+ memset(&threads[i], 0, sizeof(pthread_info_t));
+ break;
+ }
+ }
+
+ if (i == MAX_NUM_THREADS) {
+ return -1;
+ }
+
+ /*
+ * Fill thread-info for thread
+ */
+ memcpy(&threads[i].data, &base_info, sizeof(base_info));
+ threads[i].active = 1;
+ memcpy(&threads[i].data.client_fd, client_fd, sizeof(mbedtls_net_context));
+
+ if ((ret = pthread_create(&threads[i].thread, NULL, handle_ssl_connection,
+ &threads[i].data)) != 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+int main(void)
+{
+ int ret;
+ mbedtls_net_context listen_fd, client_fd;
+ const char pers[] = "ssl_pthread_server";
+
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_ssl_config conf;
+ mbedtls_x509_crt srvcert;
+ mbedtls_x509_crt cachain;
+ mbedtls_pk_context pkey;
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+ unsigned char alloc_buf[100000];
+#endif
+#if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_cache_context cache;
+#endif
+
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+ mbedtls_memory_buffer_alloc_init(alloc_buf, sizeof(alloc_buf));
+#endif
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_cache_init(&cache);
+#endif
+
+ mbedtls_x509_crt_init(&srvcert);
+ mbedtls_x509_crt_init(&cachain);
+
+ mbedtls_ssl_config_init(&conf);
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+ memset(threads, 0, sizeof(threads));
+ mbedtls_net_init(&listen_fd);
+ mbedtls_net_init(&client_fd);
+
+ mbedtls_mutex_init(&debug_mutex);
+
+ base_info.config = &conf;
+
+ /*
+ * We use only a single entropy source that is used in all the threads.
+ */
+ mbedtls_entropy_init(&entropy);
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ psa_status_t status = psa_crypto_init();
+ if (status != PSA_SUCCESS) {
+ mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
+ (int) status);
+ ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
+ goto exit;
+ }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ /*
+ * 1a. Seed the random number generator
+ */
+ mbedtls_printf(" . Seeding the random number generator...");
+
+ if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
+ (const unsigned char *) pers,
+ strlen(pers))) != 0) {
+ mbedtls_printf(" failed: mbedtls_ctr_drbg_seed returned -0x%04x\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 1b. Load the certificates and private RSA key
+ */
+ mbedtls_printf("\n . Loading the server cert. and key...");
+ fflush(stdout);
+
+ /*
+ * This demonstration program uses embedded test certificates.
+ * Instead, you may want to use mbedtls_x509_crt_parse_file() to read the
+ * server and CA certificates, as well as mbedtls_pk_parse_keyfile().
+ */
+ ret = mbedtls_x509_crt_parse(&srvcert, (const unsigned char *) mbedtls_test_srv_crt,
+ mbedtls_test_srv_crt_len);
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_x509_crt_parse returned %d\n\n", ret);
+ goto exit;
+ }
+
+ ret = mbedtls_x509_crt_parse(&cachain, (const unsigned char *) mbedtls_test_cas_pem,
+ mbedtls_test_cas_pem_len);
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_x509_crt_parse returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_pk_init(&pkey);
+ ret = mbedtls_pk_parse_key(&pkey, (const unsigned char *) mbedtls_test_srv_key,
+ mbedtls_test_srv_key_len, NULL, 0,
+ mbedtls_ctr_drbg_random, &ctr_drbg);
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_pk_parse_key returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 1c. Prepare SSL configuration
+ */
+ mbedtls_printf(" . Setting up the SSL data....");
+
+ if ((ret = mbedtls_ssl_config_defaults(&conf,
+ MBEDTLS_SSL_IS_SERVER,
+ MBEDTLS_SSL_TRANSPORT_STREAM,
+ MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
+ mbedtls_printf(" failed: mbedtls_ssl_config_defaults returned -0x%04x\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
+ mbedtls_ssl_conf_dbg(&conf, my_mutexed_debug, stdout);
+
+ /* mbedtls_ssl_cache_get() and mbedtls_ssl_cache_set() are thread-safe if
+ * MBEDTLS_THREADING_C is set.
+ */
+#if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_conf_session_cache(&conf, &cache,
+ mbedtls_ssl_cache_get,
+ mbedtls_ssl_cache_set);
+#endif
+
+ mbedtls_ssl_conf_ca_chain(&conf, &cachain, NULL);
+ if ((ret = mbedtls_ssl_conf_own_cert(&conf, &srvcert, &pkey)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 2. Setup the listening TCP socket
+ */
+ mbedtls_printf(" . Bind on https://localhost:4433/ ...");
+ fflush(stdout);
+
+ if ((ret = mbedtls_net_bind(&listen_fd, NULL, "4433", MBEDTLS_NET_PROTO_TCP)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_net_bind returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+reset:
+#ifdef MBEDTLS_ERROR_C
+ if (ret != 0) {
+ char error_buf[100];
+ mbedtls_strerror(ret, error_buf, 100);
+ mbedtls_printf(" [ main ] Last error was: -0x%04x - %s\n", (unsigned int) -ret,
+ error_buf);
+ }
+#endif
+
+ /*
+ * 3. Wait until a client connects
+ */
+ mbedtls_printf(" [ main ] Waiting for a remote connection\n");
+
+ if ((ret = mbedtls_net_accept(&listen_fd, &client_fd,
+ NULL, 0, NULL)) != 0) {
+ mbedtls_printf(" [ main ] failed: mbedtls_net_accept returned -0x%04x\n",
+ (unsigned int) ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" [ main ] ok\n");
+ mbedtls_printf(" [ main ] Creating a new thread\n");
+
+ if ((ret = thread_create(&client_fd)) != 0) {
+ mbedtls_printf(" [ main ] failed: thread_create returned %d\n", ret);
+ mbedtls_net_free(&client_fd);
+ goto reset;
+ }
+
+ ret = 0;
+ goto reset;
+
+exit:
+ mbedtls_x509_crt_free(&srvcert);
+ mbedtls_pk_free(&pkey);
+#if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_cache_free(&cache);
+#endif
+ mbedtls_ctr_drbg_free(&ctr_drbg);
+ mbedtls_entropy_free(&entropy);
+ mbedtls_ssl_config_free(&conf);
+ mbedtls_net_free(&listen_fd);
+ mbedtls_mutex_free(&debug_mutex);
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+ mbedtls_memory_buffer_alloc_free();
+#endif
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ mbedtls_psa_crypto_free();
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ mbedtls_exit(ret);
+}
+
+#endif /* MBEDTLS_BIGNUM_C && MBEDTLS_ENTROPY_C &&
+ MBEDTLS_SSL_TLS_C && MBEDTLS_SSL_SRV_C && MBEDTLS_NET_C &&
+ MBEDTLS_RSA_C && MBEDTLS_CTR_DRBG_C && MBEDTLS_THREADING_C &&
+ MBEDTLS_THREADING_PTHREAD && MBEDTLS_PEM_PARSE_C */
diff --git a/programs/ssl/ssl_server.c b/programs/ssl/ssl_server.c
new file mode 100644
index 00000000000..6becf8d9131
--- /dev/null
+++ b/programs/ssl/ssl_server.c
@@ -0,0 +1,362 @@
+/*
+ * SSL server demonstration program
+ *
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "mbedtls/build_info.h"
+
+#include "mbedtls/platform.h"
+
+#if !defined(MBEDTLS_BIGNUM_C) || !defined(MBEDTLS_PEM_PARSE_C) || \
+ !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_SSL_TLS_C) || \
+ !defined(MBEDTLS_SSL_SRV_C) || !defined(MBEDTLS_NET_C) || \
+ !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_CTR_DRBG_C) || \
+ !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_FS_IO)
+int main(void)
+{
+ mbedtls_printf("MBEDTLS_BIGNUM_C and/or MBEDTLS_ENTROPY_C "
+ "and/or MBEDTLS_SSL_TLS_C and/or MBEDTLS_SSL_SRV_C and/or "
+ "MBEDTLS_NET_C and/or MBEDTLS_RSA_C and/or "
+ "MBEDTLS_CTR_DRBG_C and/or MBEDTLS_X509_CRT_PARSE_C "
+ "and/or MBEDTLS_PEM_PARSE_C not defined.\n");
+ mbedtls_exit(0);
+}
+#else
+
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/x509.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/net_sockets.h"
+#include "mbedtls/error.h"
+#include "mbedtls/debug.h"
+#include "test/certs.h"
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+#include "mbedtls/ssl_cache.h"
+#endif
+
+#define HTTP_RESPONSE \
+ "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" \
+ "<h2>Mbed TLS Test Server</h2>\r\n" \
+ "<p>Successful connection using: %s</p>\r\n"
+
+#define DEBUG_LEVEL 0
+
+
+static void my_debug(void *ctx, int level,
+ const char *file, int line,
+ const char *str)
+{
+ ((void) level);
+
+ mbedtls_fprintf((FILE *) ctx, "%s:%04d: %s", file, line, str);
+ fflush((FILE *) ctx);
+}
+
+int main(void)
+{
+ int ret, len;
+ mbedtls_net_context listen_fd, client_fd;
+ unsigned char buf[1024];
+ const char *pers = "ssl_server";
+
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_ssl_context ssl;
+ mbedtls_ssl_config conf;
+ mbedtls_x509_crt srvcert;
+ mbedtls_pk_context pkey;
+#if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_cache_context cache;
+#endif
+
+ mbedtls_net_init(&listen_fd);
+ mbedtls_net_init(&client_fd);
+ mbedtls_ssl_init(&ssl);
+ mbedtls_ssl_config_init(&conf);
+#if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_cache_init(&cache);
+#endif
+ mbedtls_x509_crt_init(&srvcert);
+ mbedtls_pk_init(&pkey);
+ mbedtls_entropy_init(&entropy);
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ psa_status_t status = psa_crypto_init();
+ if (status != PSA_SUCCESS) {
+ mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
+ (int) status);
+ ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
+ goto exit;
+ }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+#if defined(MBEDTLS_DEBUG_C)
+ mbedtls_debug_set_threshold(DEBUG_LEVEL);
+#endif
+
+ /*
+ * 1. Seed the RNG
+ */
+ mbedtls_printf(" . Seeding the random number generator...");
+ fflush(stdout);
+
+ if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
+ (const unsigned char *) pers,
+ strlen(pers))) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 2. Load the certificates and private RSA key
+ */
+ mbedtls_printf("\n . Loading the server cert. and key...");
+ fflush(stdout);
+
+ /*
+ * This demonstration program uses embedded test certificates.
+ * Instead, you may want to use mbedtls_x509_crt_parse_file() to read the
+ * server and CA certificates, as well as mbedtls_pk_parse_keyfile().
+ */
+ ret = mbedtls_x509_crt_parse(&srvcert, (const unsigned char *) mbedtls_test_srv_crt,
+ mbedtls_test_srv_crt_len);
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_x509_crt_parse returned %d\n\n", ret);
+ goto exit;
+ }
+
+ ret = mbedtls_x509_crt_parse(&srvcert, (const unsigned char *) mbedtls_test_cas_pem,
+ mbedtls_test_cas_pem_len);
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_x509_crt_parse returned %d\n\n", ret);
+ goto exit;
+ }
+
+ ret = mbedtls_pk_parse_key(&pkey, (const unsigned char *) mbedtls_test_srv_key,
+ mbedtls_test_srv_key_len, NULL, 0,
+ mbedtls_ctr_drbg_random, &ctr_drbg);
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_pk_parse_key returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 3. Setup the listening TCP socket
+ */
+ mbedtls_printf(" . Bind on https://localhost:4433/ ...");
+ fflush(stdout);
+
+ if ((ret = mbedtls_net_bind(&listen_fd, NULL, "4433", MBEDTLS_NET_PROTO_TCP)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_net_bind returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 4. Setup stuff
+ */
+ mbedtls_printf(" . Setting up the SSL data....");
+ fflush(stdout);
+
+ if ((ret = mbedtls_ssl_config_defaults(&conf,
+ MBEDTLS_SSL_IS_SERVER,
+ MBEDTLS_SSL_TRANSPORT_STREAM,
+ MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
+ mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_conf_session_cache(&conf, &cache,
+ mbedtls_ssl_cache_get,
+ mbedtls_ssl_cache_set);
+#endif
+
+ mbedtls_ssl_conf_ca_chain(&conf, srvcert.next, NULL);
+ if ((ret = mbedtls_ssl_conf_own_cert(&conf, &srvcert, &pkey)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret);
+ goto exit;
+ }
+
+ if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_setup returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+reset:
+#ifdef MBEDTLS_ERROR_C
+ if (ret != 0) {
+ char error_buf[100];
+ mbedtls_strerror(ret, error_buf, 100);
+ mbedtls_printf("Last error was: %d - %s\n\n", ret, error_buf);
+ }
+#endif
+
+ mbedtls_net_free(&client_fd);
+
+ mbedtls_ssl_session_reset(&ssl);
+
+ /*
+ * 3. Wait until a client connects
+ */
+ mbedtls_printf(" . Waiting for a remote connection ...");
+ fflush(stdout);
+
+ if ((ret = mbedtls_net_accept(&listen_fd, &client_fd,
+ NULL, 0, NULL)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_net_accept returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_ssl_set_bio(&ssl, &client_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 5. Handshake
+ */
+ mbedtls_printf(" . Performing the SSL/TLS handshake...");
+ fflush(stdout);
+
+ while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_handshake returned %d\n\n", ret);
+ goto reset;
+ }
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 6. Read the HTTP Request
+ */
+ mbedtls_printf(" < Read from client:");
+ fflush(stdout);
+
+ do {
+ len = sizeof(buf) - 1;
+ memset(buf, 0, sizeof(buf));
+ ret = mbedtls_ssl_read(&ssl, buf, len);
+
+ if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+ continue;
+ }
+
+ if (ret <= 0) {
+ switch (ret) {
+ case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+ mbedtls_printf(" connection was closed gracefully\n");
+ break;
+
+ case MBEDTLS_ERR_NET_CONN_RESET:
+ mbedtls_printf(" connection was reset by peer\n");
+ break;
+
+ default:
+ mbedtls_printf(" mbedtls_ssl_read returned -0x%x\n", (unsigned int) -ret);
+ break;
+ }
+
+ break;
+ }
+
+ len = ret;
+ mbedtls_printf(" %d bytes read\n\n%s", len, (char *) buf);
+
+ if (ret > 0) {
+ break;
+ }
+ } while (1);
+
+ /*
+ * 7. Write the 200 Response
+ */
+ mbedtls_printf(" > Write to client:");
+ fflush(stdout);
+
+ len = sprintf((char *) buf, HTTP_RESPONSE,
+ mbedtls_ssl_get_ciphersuite(&ssl));
+
+ while ((ret = mbedtls_ssl_write(&ssl, buf, len)) <= 0) {
+ if (ret == MBEDTLS_ERR_NET_CONN_RESET) {
+ mbedtls_printf(" failed\n ! peer closed the connection\n\n");
+ goto reset;
+ }
+
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_write returned %d\n\n", ret);
+ goto exit;
+ }
+ }
+
+ len = ret;
+ mbedtls_printf(" %d bytes written\n\n%s\n", len, (char *) buf);
+
+ mbedtls_printf(" . Closing the connection...");
+
+ while ((ret = mbedtls_ssl_close_notify(&ssl)) < 0) {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
+ ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_close_notify returned %d\n\n", ret);
+ goto reset;
+ }
+ }
+
+ mbedtls_printf(" ok\n");
+
+ ret = 0;
+ goto reset;
+
+exit:
+
+#ifdef MBEDTLS_ERROR_C
+ if (ret != 0) {
+ char error_buf[100];
+ mbedtls_strerror(ret, error_buf, 100);
+ mbedtls_printf("Last error was: %d - %s\n\n", ret, error_buf);
+ }
+#endif
+
+ mbedtls_net_free(&client_fd);
+ mbedtls_net_free(&listen_fd);
+ mbedtls_x509_crt_free(&srvcert);
+ mbedtls_pk_free(&pkey);
+ mbedtls_ssl_free(&ssl);
+ mbedtls_ssl_config_free(&conf);
+#if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_cache_free(&cache);
+#endif
+ mbedtls_ctr_drbg_free(&ctr_drbg);
+ mbedtls_entropy_free(&entropy);
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ mbedtls_psa_crypto_free();
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ mbedtls_exit(ret);
+}
+#endif /* MBEDTLS_BIGNUM_C && MBEDTLS_ENTROPY_C &&
+ MBEDTLS_SSL_TLS_C && MBEDTLS_SSL_SRV_C && MBEDTLS_NET_C &&
+ MBEDTLS_RSA_C && MBEDTLS_CTR_DRBG_C && MBEDTLS_X509_CRT_PARSE_C
+ && MBEDTLS_FS_IO && MBEDTLS_PEM_PARSE_C */
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
new file mode 100644
index 00000000000..a5d2ed10206
--- /dev/null
+++ b/programs/ssl/ssl_server2.c
@@ -0,0 +1,4357 @@
+/*
+ * SSL client with options
+ *
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#define MBEDTLS_ALLOW_PRIVATE_ACCESS
+
+#include "ssl_test_lib.h"
+
+#if defined(MBEDTLS_SSL_TEST_IMPOSSIBLE)
+int main(void)
+{
+ mbedtls_printf(MBEDTLS_SSL_TEST_IMPOSSIBLE);
+ mbedtls_exit(0);
+}
+#elif !defined(MBEDTLS_SSL_SRV_C)
+int main(void)
+{
+ mbedtls_printf("MBEDTLS_SSL_SRV_C not defined.\n");
+ mbedtls_exit(0);
+}
+#else /* !MBEDTLS_SSL_TEST_IMPOSSIBLE && MBEDTLS_SSL_SRV_C */
+
+#include <stdint.h>
+
+#if !defined(_MSC_VER)
+#include <inttypes.h>
+#endif
+
+#if !defined(_WIN32)
+#include <signal.h>
+#endif
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+#include "mbedtls/ssl_cache.h"
+#endif
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
+#include "mbedtls/ssl_ticket.h"
+#endif
+
+#if defined(MBEDTLS_SSL_COOKIE_C)
+#include "mbedtls/ssl_cookie.h"
+#endif
+
+#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) && defined(MBEDTLS_FS_IO)
+#define SNI_OPTION
+#endif
+
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)
+#include "test/psa_crypto_helpers.h"
+#endif
+
+#include "mbedtls/pk.h"
+#include "mbedtls/dhm.h"
+
+/* Size of memory to be allocated for the heap, when using the library's memory
+ * management and MBEDTLS_MEMORY_BUFFER_ALLOC_C is enabled. */
+#define MEMORY_HEAP_SIZE 180000
+
+#define DFL_SERVER_ADDR NULL
+#define DFL_SERVER_PORT "4433"
+#define DFL_RESPONSE_SIZE -1
+#define DFL_DEBUG_LEVEL 0
+#define DFL_NBIO 0
+#define DFL_EVENT 0
+#define DFL_READ_TIMEOUT 0
+#define DFL_CA_FILE ""
+#define DFL_CA_PATH ""
+#define DFL_CRT_FILE ""
+#define DFL_KEY_FILE ""
+#define DFL_KEY_OPAQUE 0
+#define DFL_KEY_PWD ""
+#define DFL_CRT_FILE2 ""
+#define DFL_KEY_FILE2 ""
+#define DFL_KEY_PWD2 ""
+#define DFL_ASYNC_OPERATIONS "-"
+#define DFL_ASYNC_PRIVATE_DELAY1 (-1)
+#define DFL_ASYNC_PRIVATE_DELAY2 (-1)
+#define DFL_ASYNC_PRIVATE_ERROR (0)
+#define DFL_PSK ""
+#define DFL_PSK_OPAQUE 0
+#define DFL_PSK_LIST_OPAQUE 0
+#define DFL_PSK_IDENTITY "Client_identity"
+#define DFL_ECJPAKE_PW NULL
+#define DFL_ECJPAKE_PW_OPAQUE 0
+#define DFL_PSK_LIST NULL
+#define DFL_FORCE_CIPHER 0
+#define DFL_TLS1_3_KEX_MODES MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_ALL
+#define DFL_RENEGOTIATION MBEDTLS_SSL_RENEGOTIATION_DISABLED
+#define DFL_ALLOW_LEGACY -2
+#define DFL_RENEGOTIATE 0
+#define DFL_RENEGO_DELAY -2
+#define DFL_RENEGO_PERIOD ((uint64_t) -1)
+#define DFL_EXCHANGES 1
+#define DFL_MIN_VERSION -1
+#define DFL_MAX_VERSION -1
+#define DFL_SHA1 -1
+#define DFL_CID_ENABLED 0
+#define DFL_CID_VALUE ""
+#define DFL_CID_ENABLED_RENEGO -1
+#define DFL_CID_VALUE_RENEGO NULL
+#define DFL_AUTH_MODE -1
+#define DFL_CERT_REQ_CA_LIST MBEDTLS_SSL_CERT_REQ_CA_LIST_ENABLED
+#define DFL_CERT_REQ_DN_HINT 0
+#define DFL_MFL_CODE MBEDTLS_SSL_MAX_FRAG_LEN_NONE
+#define DFL_TRUNC_HMAC -1
+#define DFL_TICKETS MBEDTLS_SSL_SESSION_TICKETS_ENABLED
+#define DFL_DUMMY_TICKET 0
+#define DFL_TICKET_ROTATE 0
+#define DFL_TICKET_TIMEOUT 86400
+#define DFL_TICKET_AEAD MBEDTLS_CIPHER_AES_256_GCM
+#define DFL_CACHE_MAX -1
+#define DFL_CACHE_TIMEOUT -1
+#define DFL_CACHE_REMOVE 0
+#define DFL_SNI NULL
+#define DFL_ALPN_STRING NULL
+#define DFL_GROUPS NULL
+#define DFL_EARLY_DATA -1
+#define DFL_MAX_EARLY_DATA_SIZE ((uint32_t) -1)
+#define DFL_SIG_ALGS NULL
+#define DFL_DHM_FILE NULL
+#define DFL_TRANSPORT MBEDTLS_SSL_TRANSPORT_STREAM
+#define DFL_COOKIES 1
+#define DFL_ANTI_REPLAY -1
+#define DFL_HS_TO_MIN 0
+#define DFL_HS_TO_MAX 0
+#define DFL_DTLS_MTU -1
+#define DFL_BADMAC_LIMIT -1
+#define DFL_DGRAM_PACKING 1
+#define DFL_EXTENDED_MS -1
+#define DFL_ETM -1
+#define DFL_SERIALIZE 0
+#define DFL_CONTEXT_FILE ""
+#define DFL_EXTENDED_MS_ENFORCE -1
+#define DFL_CA_CALLBACK 0
+#define DFL_EAP_TLS 0
+#define DFL_REPRODUCIBLE 0
+#define DFL_NSS_KEYLOG 0
+#define DFL_NSS_KEYLOG_FILE NULL
+#define DFL_QUERY_CONFIG_MODE 0
+#define DFL_USE_SRTP 0
+#define DFL_SRTP_FORCE_PROFILE 0
+#define DFL_SRTP_SUPPORT_MKI 0
+#define DFL_KEY_OPAQUE_ALG "none"
+
+#define LONG_RESPONSE "<p>01-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \
+ "02-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \
+ "03-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \
+ "04-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \
+ "05-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \
+ "06-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \
+ "07-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah</p>\r\n"
+
+/* Uncomment LONG_RESPONSE at the end of HTTP_RESPONSE to test sending longer
+ * packets (for fragmentation purposes) */
+#define HTTP_RESPONSE \
+ "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" \
+ "<h2>Mbed TLS Test Server</h2>\r\n" \
+ "<p>Successful connection using: %s</p>\r\n" // LONG_RESPONSE
+
+/*
+ * Size of the basic I/O buffer. Able to hold our default response.
+ */
+#define DFL_IO_BUF_LEN 200
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+#if defined(MBEDTLS_FS_IO)
+#define USAGE_IO \
+ " ca_file=%%s The single file containing the top-level CA(s) you fully trust\n" \
+ " default: \"\" (pre-loaded)\n" \
+ " use \"none\" to skip loading any top-level CAs.\n" \
+ " ca_path=%%s The path containing the top-level CA(s) you fully trust\n" \
+ " default: \"\" (pre-loaded) (overrides ca_file)\n" \
+ " use \"none\" to skip loading any top-level CAs.\n" \
+ " crt_file=%%s Your own cert and chain (in bottom to top order, top may be omitted)\n" \
+ " default: see note after key_file2\n" \
+ " key_file=%%s default: see note after key_file2\n" \
+ " key_pwd=%%s Password for key specified by key_file argument\n" \
+ " default: none\n" \
+ " crt_file2=%%s Your second cert and chain (in bottom to top order, top may be omitted)\n" \
+ " default: see note after key_file2\n" \
+ " key_file2=%%s default: see note below\n" \
+ " note: if neither crt_file/key_file nor crt_file2/key_file2 are used,\n" \
+ " preloaded certificate(s) and key(s) are used if available\n" \
+ " key_pwd2=%%s Password for key specified by key_file2 argument\n" \
+ " default: none\n" \
+ " dhm_file=%%s File containing Diffie-Hellman parameters\n" \
+ " default: preloaded parameters\n"
+#else
+#define USAGE_IO \
+ "\n" \
+ " No file operations available (MBEDTLS_FS_IO not defined)\n" \
+ "\n"
+#endif /* MBEDTLS_FS_IO */
+#else
+#define USAGE_IO ""
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+#if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+#define USAGE_KEY_OPAQUE \
+ " key_opaque=%%d Handle your private keys as if they were opaque\n" \
+ " default: 0 (disabled)\n"
+#else
+#define USAGE_KEY_OPAQUE ""
+#endif
+
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+#define USAGE_SSL_ASYNC \
+ " async_operations=%%c... d=decrypt, s=sign (default: -=off)\n" \
+ " async_private_delay1=%%d Asynchronous delay for key_file or preloaded key\n" \
+ " async_private_delay2=%%d Asynchronous delay for key_file2 and sni\n" \
+ " default: -1 (not asynchronous)\n" \
+ " async_private_error=%%d Async callback error injection (default=0=none,\n" \
+ " 1=start, 2=cancel, 3=resume, negative=first time only)"
+#else
+#define USAGE_SSL_ASYNC ""
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+#define USAGE_CID \
+ " cid=%%d Disable (0) or enable (1) the use of the DTLS Connection ID extension.\n" \
+ " default: 0 (disabled)\n" \
+ " cid_renego=%%d Disable (0) or enable (1) the use of the DTLS Connection ID extension during renegotiation.\n" \
+ " default: same as 'cid' parameter\n" \
+ " cid_val=%%s The CID to use for incoming messages (in hex, without 0x).\n" \
+ " default: \"\"\n" \
+ " cid_val_renego=%%s The CID to use for incoming messages (in hex, without 0x) after renegotiation.\n" \
+ " default: same as 'cid_val' parameter\n"
+#else /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+#define USAGE_CID ""
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED)
+#define USAGE_PSK_RAW \
+ " psk=%%s default: \"\" (disabled)\n" \
+ " The PSK values are in hex, without 0x.\n" \
+ " psk_list=%%s default: \"\"\n" \
+ " A list of (PSK identity, PSK value) pairs.\n" \
+ " The PSK values are in hex, without 0x.\n" \
+ " id1,psk1[,id2,psk2[,...]]\n" \
+ " psk_identity=%%s default: \"Client_identity\"\n"
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#define USAGE_PSK_SLOT \
+ " psk_opaque=%%d default: 0 (don't use opaque static PSK)\n" \
+ " Enable this to store the PSK configured through command line\n" \
+ " parameter `psk` in a PSA-based key slot.\n" \
+ " Note: Currently only supported in conjunction with\n" \
+ " the use of min_version to force TLS 1.2 and force_ciphersuite \n" \
+ " to force a particular PSK-only ciphersuite.\n" \
+ " Note: This is to test integration of PSA-based opaque PSKs with\n" \
+ " Mbed TLS only. Production systems are likely to configure Mbed TLS\n" \
+ " with prepopulated key slots instead of importing raw key material.\n" \
+ " psk_list_opaque=%%d default: 0 (don't use opaque dynamic PSKs)\n" \
+ " Enable this to store the list of dynamically chosen PSKs configured\n" \
+ " through the command line parameter `psk_list` in PSA-based key slots.\n" \
+ " Note: Currently only supported in conjunction with\n" \
+ " the use of min_version to force TLS 1.2 and force_ciphersuite \n" \
+ " to force a particular PSK-only ciphersuite.\n" \
+ " Note: This is to test integration of PSA-based opaque PSKs with\n" \
+ " Mbed TLS only. Production systems are likely to configure Mbed TLS\n" \
+ " with prepopulated key slots instead of importing raw key material.\n"
+#else
+#define USAGE_PSK_SLOT ""
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+#define USAGE_PSK USAGE_PSK_RAW USAGE_PSK_SLOT
+#else
+#define USAGE_PSK ""
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED */
+
+#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
+#define USAGE_CA_CALLBACK \
+ " ca_callback=%%d default: 0 (disabled)\n" \
+ " Enable this to use the trusted certificate callback function\n"
+#else
+#define USAGE_CA_CALLBACK ""
+#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
+#define USAGE_TICKETS \
+ " tickets=%%d default: 1 (enabled)\n" \
+ " ticket_rotate=%%d default: 0 (disabled)\n" \
+ " ticket_timeout=%%d default: 86400 (one day)\n" \
+ " ticket_aead=%%s default: \"AES-256-GCM\"\n"
+#else /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_TICKET_C */
+#define USAGE_TICKETS ""
+#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_TICKET_C */
+
+#define USAGE_EAP_TLS \
+ " eap_tls=%%d default: 0 (disabled)\n"
+#define USAGE_NSS_KEYLOG \
+ " nss_keylog=%%d default: 0 (disabled)\n" \
+ " This cannot be used with eap_tls=1\n"
+#define USAGE_NSS_KEYLOG_FILE \
+ " nss_keylog_file=%%s\n"
+#if defined(MBEDTLS_SSL_DTLS_SRTP)
+#define USAGE_SRTP \
+ " use_srtp=%%d default: 0 (disabled)\n" \
+ " srtp_force_profile=%%d default: 0 (all enabled)\n" \
+ " available profiles:\n" \
+ " 1 - SRTP_AES128_CM_HMAC_SHA1_80\n" \
+ " 2 - SRTP_AES128_CM_HMAC_SHA1_32\n" \
+ " 3 - SRTP_NULL_HMAC_SHA1_80\n" \
+ " 4 - SRTP_NULL_HMAC_SHA1_32\n" \
+ " support_mki=%%d default: 0 (not supported)\n"
+#else /* MBEDTLS_SSL_DTLS_SRTP */
+#define USAGE_SRTP ""
+#endif
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+#define USAGE_CACHE \
+ " cache_max=%%d default: cache default (50)\n" \
+ " cache_remove=%%d default: 0 (don't remove)\n"
+#if defined(MBEDTLS_HAVE_TIME)
+#define USAGE_CACHE_TIME \
+ " cache_timeout=%%d default: cache default (1d)\n"
+#else
+#define USAGE_CACHE_TIME ""
+#endif
+#else
+#define USAGE_CACHE ""
+#define USAGE_CACHE_TIME ""
+#endif /* MBEDTLS_SSL_CACHE_C */
+
+#if defined(SNI_OPTION)
+#if defined(MBEDTLS_X509_CRL_PARSE_C)
+#define SNI_CRL ",crl"
+#else
+#define SNI_CRL ""
+#endif
+
+#define USAGE_SNI \
+ " sni=%%s name1,cert1,key1,ca1"SNI_CRL ",auth1[,...]\n" \
+ " default: disabled\n"
+#else
+#define USAGE_SNI ""
+#endif /* SNI_OPTION */
+
+#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+#define USAGE_MAX_FRAG_LEN \
+ " max_frag_len=%%d default: 16384 (tls default)\n" \
+ " options: 512, 1024, 2048, 4096\n"
+#else
+#define USAGE_MAX_FRAG_LEN ""
+#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
+
+#if defined(MBEDTLS_SSL_ALPN)
+#define USAGE_ALPN \
+ " alpn=%%s default: \"\" (disabled)\n" \
+ " example: spdy/1,http/1.1\n"
+#else
+#define USAGE_ALPN ""
+#endif /* MBEDTLS_SSL_ALPN */
+
+#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY)
+#define USAGE_COOKIES \
+ " cookies=0/1/-1 default: 1 (enabled)\n" \
+ " 0: disabled, -1: library default (broken)\n"
+#else
+#define USAGE_COOKIES ""
+#endif
+
+#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
+#define USAGE_ANTI_REPLAY \
+ " anti_replay=0/1 default: (library default: enabled)\n"
+#else
+#define USAGE_ANTI_REPLAY ""
+#endif
+
+#define USAGE_BADMAC_LIMIT \
+ " badmac_limit=%%d default: (library default: disabled)\n"
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+#define USAGE_DTLS \
+ " dtls=%%d default: 0 (TLS)\n" \
+ " hs_timeout=%%d-%%d default: (library default: 1000-60000)\n" \
+ " range of DTLS handshake timeouts in millisecs\n" \
+ " mtu=%%d default: (library default: unlimited)\n" \
+ " dgram_packing=%%d default: 1 (allowed)\n" \
+ " allow or forbid packing of multiple\n" \
+ " records within a single datgram.\n"
+#else
+#define USAGE_DTLS ""
+#endif
+
+#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
+#define USAGE_EMS \
+ " extended_ms=0/1 default: (library default: on)\n"
+#else
+#define USAGE_EMS ""
+#endif
+
+#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+#define USAGE_ETM \
+ " etm=0/1 default: (library default: on)\n"
+#else
+#define USAGE_ETM ""
+#endif
+
+#define USAGE_REPRODUCIBLE \
+ " reproducible=0/1 default: 0 (disabled)\n"
+
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+#define USAGE_RENEGO \
+ " renegotiation=%%d default: 0 (disabled)\n" \
+ " renegotiate=%%d default: 0 (disabled)\n" \
+ " renego_delay=%%d default: -2 (library default)\n" \
+ " renego_period=%%d default: (2^64 - 1 for TLS, 2^48 - 1 for DTLS)\n"
+#else
+#define USAGE_RENEGO ""
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#define USAGE_ECJPAKE \
+ " ecjpake_pw=%%s default: none (disabled)\n" \
+ " ecjpake_pw_opaque=%%d default: 0 (disabled)\n"
+#else /* MBEDTLS_USE_PSA_CRYPTO */
+#define USAGE_ECJPAKE \
+ " ecjpake_pw=%%s default: none (disabled)\n"
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+#else /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
+#define USAGE_ECJPAKE ""
+#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
+
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+#define USAGE_EARLY_DATA \
+ " early_data=%%d default: library default\n" \
+ " options: 0 (disabled), 1 (enabled)\n" \
+ " max_early_data_size=%%d default: library default\n" \
+ " options: max amount of early data\n"
+#else
+#define USAGE_EARLY_DATA ""
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
+#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) || \
+ (defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_EPHEMERAL_ENABLED) && \
+ defined(PSA_WANT_ALG_FFDH))
+#define USAGE_GROUPS \
+ " groups=a,b,c,d default: \"default\" (library default)\n" \
+ " example: \"secp521r1,brainpoolP512r1\"\n" \
+ " - use \"none\" for empty list\n" \
+ " - see mbedtls_ecp_curve_list()\n" \
+ " for acceptable EC group names\n" \
+ " - the following ffdh groups are supported:\n" \
+ " ffdhe2048, ffdhe3072, ffdhe4096, ffdhe6144,\n" \
+ " ffdhe8192\n"
+#else
+#define USAGE_GROUPS ""
+#endif
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+#define USAGE_SIG_ALGS \
+ " sig_algs=a,b,c,d default: \"default\" (library default)\n" \
+ " example: \"ecdsa_secp256r1_sha256,ecdsa_secp384r1_sha384\"\n"
+#else
+#define USAGE_SIG_ALGS ""
+#endif
+
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+#define USAGE_SERIALIZATION \
+ " serialize=%%d default: 0 (do not serialize/deserialize)\n" \
+ " options: 1 (serialize)\n" \
+ " 2 (serialize with re-initialization)\n" \
+ " context_file=%%s The file path to write a serialized connection\n" \
+ " in the form of base64 code (serialize option\n" \
+ " must be set)\n" \
+ " default: \"\" (do nothing)\n" \
+ " option: a file path\n"
+#else
+#define USAGE_SERIALIZATION ""
+#endif
+
+#define USAGE_KEY_OPAQUE_ALGS \
+ " key_opaque_algs=%%s Allowed opaque key 1 algorithms.\n" \
+ " comma-separated pair of values among the following:\n" \
+ " rsa-sign-pkcs1, rsa-sign-pss, rsa-sign-pss-sha256,\n" \
+ " rsa-sign-pss-sha384, rsa-sign-pss-sha512, rsa-decrypt,\n" \
+ " ecdsa-sign, ecdh, none (only acceptable for\n" \
+ " the second value).\n" \
+ " key_opaque_algs2=%%s Allowed opaque key 2 algorithms.\n" \
+ " comma-separated pair of values among the following:\n" \
+ " rsa-sign-pkcs1, rsa-sign-pss, rsa-sign-pss-sha256,\n" \
+ " rsa-sign-pss-sha384, rsa-sign-pss-sha512, rsa-decrypt,\n" \
+ " ecdsa-sign, ecdh, none (only acceptable for\n" \
+ " the second value).\n"
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+#define USAGE_TLS1_3_KEY_EXCHANGE_MODES \
+ " tls13_kex_modes=%%s default: all\n" \
+ " options: psk, psk_ephemeral, psk_all, ephemeral,\n" \
+ " ephemeral_all, all, psk_or_ephemeral\n"
+#else
+#define USAGE_TLS1_3_KEY_EXCHANGE_MODES ""
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+
+
+/* USAGE is arbitrarily split to stay under the portable string literal
+ * length limit: 4095 bytes in C99. */
+#define USAGE1 \
+ "\n usage: ssl_server2 param=<>...\n" \
+ "\n acceptable parameters:\n" \
+ " server_addr=%%s default: (all interfaces)\n" \
+ " server_port=%%d default: 4433\n" \
+ " debug_level=%%d default: 0 (disabled)\n" \
+ " build_version=%%d default: none (disabled)\n" \
+ " option: 1 (print build version only and stop)\n" \
+ " buffer_size=%%d default: 200 \n" \
+ " (minimum: 1)\n" \
+ " response_size=%%d default: about 152 (basic response)\n" \
+ " (minimum: 0, max: 16384)\n" \
+ " increases buffer_size if bigger\n" \
+ " nbio=%%d default: 0 (blocking I/O)\n" \
+ " options: 1 (non-blocking), 2 (added delays)\n" \
+ " event=%%d default: 0 (loop)\n" \
+ " options: 1 (level-triggered, implies nbio=1),\n" \
+ " read_timeout=%%d default: 0 ms (no timeout)\n" \
+ "\n" \
+ USAGE_DTLS \
+ USAGE_SRTP \
+ USAGE_COOKIES \
+ USAGE_ANTI_REPLAY \
+ USAGE_BADMAC_LIMIT \
+ "\n"
+#define USAGE2 \
+ " auth_mode=%%s default: (library default: none)\n" \
+ " options: none, optional, required\n" \
+ " cert_req_ca_list=%%d default: 1 (send ca list)\n" \
+ " options: 1 (send ca list), 0 (don't send)\n" \
+ " 2 (send conf dn hint), 3 (send hs dn hint)\n" \
+ USAGE_IO \
+ USAGE_KEY_OPAQUE \
+ "\n" \
+ USAGE_PSK \
+ USAGE_CA_CALLBACK \
+ USAGE_ECJPAKE \
+ "\n"
+#define USAGE3 \
+ " allow_legacy=%%d default: (library default: no)\n" \
+ USAGE_RENEGO \
+ " exchanges=%%d default: 1\n" \
+ "\n" \
+ USAGE_TICKETS \
+ USAGE_EAP_TLS \
+ USAGE_REPRODUCIBLE \
+ USAGE_NSS_KEYLOG \
+ USAGE_NSS_KEYLOG_FILE \
+ USAGE_CACHE \
+ USAGE_CACHE_TIME \
+ USAGE_MAX_FRAG_LEN \
+ USAGE_ALPN \
+ USAGE_EMS \
+ USAGE_ETM \
+ USAGE_GROUPS \
+ USAGE_SIG_ALGS \
+ USAGE_KEY_OPAQUE_ALGS \
+ USAGE_EARLY_DATA \
+ "\n"
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+#define TLS1_3_VERSION_OPTIONS ", tls13"
+#else /* MBEDTLS_SSL_PROTO_TLS1_3 */
+#define TLS1_3_VERSION_OPTIONS ""
+#endif /* !MBEDTLS_SSL_PROTO_TLS1_3 */
+
+#define USAGE4 \
+ USAGE_SSL_ASYNC \
+ USAGE_SNI \
+ " allow_sha1=%%d default: 0\n" \
+ " min_version=%%s default: (library default: tls12)\n" \
+ " max_version=%%s default: (library default: tls12)\n" \
+ " force_version=%%s default: \"\" (none)\n" \
+ " options: tls12, dtls12" TLS1_3_VERSION_OPTIONS \
+ "\n\n" \
+ " force_ciphersuite=<name> default: all enabled\n" \
+ USAGE_TLS1_3_KEY_EXCHANGE_MODES \
+ " query_config=<name> return 0 if the specified\n" \
+ " configuration macro is defined and 1\n" \
+ " otherwise. The expansion of the macro\n" \
+ " is printed if it is defined\n" \
+ USAGE_SERIALIZATION \
+ "\n"
+
+#define PUT_UINT64_BE(out_be, in_le, i) \
+ { \
+ (out_be)[(i) + 0] = (unsigned char) (((in_le) >> 56) & 0xFF); \
+ (out_be)[(i) + 1] = (unsigned char) (((in_le) >> 48) & 0xFF); \
+ (out_be)[(i) + 2] = (unsigned char) (((in_le) >> 40) & 0xFF); \
+ (out_be)[(i) + 3] = (unsigned char) (((in_le) >> 32) & 0xFF); \
+ (out_be)[(i) + 4] = (unsigned char) (((in_le) >> 24) & 0xFF); \
+ (out_be)[(i) + 5] = (unsigned char) (((in_le) >> 16) & 0xFF); \
+ (out_be)[(i) + 6] = (unsigned char) (((in_le) >> 8) & 0xFF); \
+ (out_be)[(i) + 7] = (unsigned char) (((in_le) >> 0) & 0xFF); \
+ }
+
+/* This is global so it can be easily accessed by callback functions */
+rng_context_t rng;
+
+/*
+ * global options
+ */
+struct options {
+ const char *server_addr; /* address on which the ssl service runs */
+ const char *server_port; /* port on which the ssl service runs */
+ int debug_level; /* level of debugging */
+ int nbio; /* should I/O be blocking? */
+ int event; /* loop or event-driven IO? level or edge triggered? */
+ uint32_t read_timeout; /* timeout on mbedtls_ssl_read() in milliseconds */
+ int response_size; /* pad response with header to requested size */
+ uint16_t buffer_size; /* IO buffer size */
+ const char *ca_file; /* the file with the CA certificate(s) */
+ const char *ca_path; /* the path with the CA certificate(s) reside */
+ const char *crt_file; /* the file with the server certificate */
+ const char *key_file; /* the file with the server key */
+ int key_opaque; /* handle private key as if it were opaque */
+ const char *key_pwd; /* the password for the server key */
+ const char *crt_file2; /* the file with the 2nd server certificate */
+ const char *key_file2; /* the file with the 2nd server key */
+ const char *key_pwd2; /* the password for the 2nd server key */
+ const char *async_operations; /* supported SSL asynchronous operations */
+ int async_private_delay1; /* number of times f_async_resume needs to be called for key 1, or -1 for no async */
+ int async_private_delay2; /* number of times f_async_resume needs to be called for key 2, or -1 for no async */
+ int async_private_error; /* inject error in async private callback */
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ int psk_opaque;
+ int psk_list_opaque;
+#endif
+#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
+ int ca_callback; /* Use callback for trusted certificate list */
+#endif
+ const char *psk; /* the pre-shared key */
+ const char *psk_identity; /* the pre-shared key identity */
+ char *psk_list; /* list of PSK id/key pairs for callback */
+ const char *ecjpake_pw; /* the EC J-PAKE password */
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ int ecjpake_pw_opaque; /* set to 1 to use the opaque method for setting the password */
+#endif
+ int force_ciphersuite[2]; /* protocol/ciphersuite to use, or all */
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ int tls13_kex_modes; /* supported TLS 1.3 key exchange modes */
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+ int renegotiation; /* enable / disable renegotiation */
+ int allow_legacy; /* allow legacy renegotiation */
+ int renegotiate; /* attempt renegotiation? */
+ int renego_delay; /* delay before enforcing renegotiation */
+ uint64_t renego_period; /* period for automatic renegotiation */
+ int exchanges; /* number of data exchanges */
+ int min_version; /* minimum protocol version accepted */
+ int max_version; /* maximum protocol version accepted */
+ int allow_sha1; /* flag for SHA-1 support */
+ int auth_mode; /* verify mode for connection */
+ int cert_req_ca_list; /* should we send the CA list? */
+ int cert_req_dn_hint; /* mode to set DN hints for CA list to send */
+ unsigned char mfl_code; /* code for maximum fragment length */
+ int trunc_hmac; /* accept truncated hmac? */
+ int tickets; /* enable / disable session tickets */
+ int dummy_ticket; /* enable / disable dummy ticket generator */
+ int ticket_rotate; /* session ticket rotate (code coverage) */
+ int ticket_timeout; /* session ticket lifetime */
+ int ticket_aead; /* session ticket protection */
+ int cache_max; /* max number of session cache entries */
+#if defined(MBEDTLS_HAVE_TIME)
+ int cache_timeout; /* expiration delay of session cache entries*/
+#endif
+ int cache_remove; /* enable / disable cache entry removal */
+ char *sni; /* string describing sni information */
+ const char *groups; /* list of supported groups */
+ const char *sig_algs; /* supported TLS 1.3 signature algorithms */
+ const char *alpn_string; /* ALPN supported protocols */
+ const char *dhm_file; /* the file with the DH parameters */
+ int extended_ms; /* allow negotiation of extended MS? */
+ int etm; /* allow negotiation of encrypt-then-MAC? */
+ int transport; /* TLS or DTLS? */
+ int cookies; /* Use cookies for DTLS? -1 to break them */
+ int anti_replay; /* Use anti-replay for DTLS? -1 for default */
+ uint32_t hs_to_min; /* Initial value of DTLS handshake timer */
+ uint32_t hs_to_max; /* Max value of DTLS handshake timer */
+ int dtls_mtu; /* UDP Maximum transport unit for DTLS */
+ int dgram_packing; /* allow/forbid datagram packing */
+ int badmac_limit; /* Limit of records with bad MAC */
+ int eap_tls; /* derive EAP-TLS keying material? */
+ int nss_keylog; /* export NSS key log material */
+ const char *nss_keylog_file; /* NSS key log file */
+ int cid_enabled; /* whether to use the CID extension or not */
+ int cid_enabled_renego; /* whether to use the CID extension or not
+ * during renegotiation */
+ const char *cid_val; /* the CID to use for incoming messages */
+ int serialize; /* serialize/deserialize connection */
+ const char *context_file; /* the file to write a serialized connection
+ * in the form of base64 code (serialize
+ * option must be set) */
+ const char *cid_val_renego; /* the CID to use for incoming messages
+ * after renegotiation */
+ int reproducible; /* make communication reproducible */
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+ int early_data; /* early data enablement flag */
+ uint32_t max_early_data_size; /* max amount of early data */
+#endif
+ int query_config_mode; /* whether to read config */
+ int use_srtp; /* Support SRTP */
+ int force_srtp_profile; /* SRTP protection profile to use or all */
+ int support_mki; /* The dtls mki mki support */
+ const char *key1_opaque_alg1; /* Allowed opaque key 1 alg 1 */
+ const char *key1_opaque_alg2; /* Allowed opaque key 1 alg 2 */
+ const char *key2_opaque_alg1; /* Allowed opaque key 2 alg 1 */
+ const char *key2_opaque_alg2; /* Allowed opaque key 2 alg 2 */
+} opt;
+
+#include "ssl_test_common_source.c"
+
+/*
+ * Return authmode from string, or -1 on error
+ */
+static int get_auth_mode(const char *s)
+{
+ if (strcmp(s, "none") == 0) {
+ return MBEDTLS_SSL_VERIFY_NONE;
+ }
+ if (strcmp(s, "optional") == 0) {
+ return MBEDTLS_SSL_VERIFY_OPTIONAL;
+ }
+ if (strcmp(s, "required") == 0) {
+ return MBEDTLS_SSL_VERIFY_REQUIRED;
+ }
+
+ return -1;
+}
+
+/*
+ * Used by sni_parse and psk_parse to handle comma-separated lists
+ */
+#define GET_ITEM(dst) \
+ do \
+ { \
+ (dst) = p; \
+ while (*p != ',') \
+ if (++p > end) \
+ goto error; \
+ *p++ = '\0'; \
+ } while (0)
+
+#if defined(SNI_OPTION)
+typedef struct _sni_entry sni_entry;
+
+struct _sni_entry {
+ const char *name;
+ mbedtls_x509_crt *cert;
+ mbedtls_pk_context *key;
+ mbedtls_x509_crt *ca;
+ mbedtls_x509_crl *crl;
+ int authmode;
+ sni_entry *next;
+};
+
+void sni_free(sni_entry *head)
+{
+ sni_entry *cur = head, *next;
+
+ while (cur != NULL) {
+ mbedtls_x509_crt_free(cur->cert);
+ mbedtls_free(cur->cert);
+
+ mbedtls_pk_free(cur->key);
+ mbedtls_free(cur->key);
+
+ mbedtls_x509_crt_free(cur->ca);
+ mbedtls_free(cur->ca);
+#if defined(MBEDTLS_X509_CRL_PARSE_C)
+ mbedtls_x509_crl_free(cur->crl);
+ mbedtls_free(cur->crl);
+#endif
+ next = cur->next;
+ mbedtls_free(cur);
+ cur = next;
+ }
+}
+
+/*
+ * Parse a string of sextuples name1,crt1,key1,ca1,crl1,auth1[,...]
+ * into a usable sni_entry list. For ca1, crl1, auth1, the special value
+ * '-' means unset. If ca1 is unset, then crl1 is ignored too.
+ *
+ * Modifies the input string! This is not production quality!
+ */
+sni_entry *sni_parse(char *sni_string)
+{
+ sni_entry *cur = NULL, *new = NULL;
+ char *p = sni_string;
+ char *end = p;
+ char *crt_file, *key_file, *ca_file, *auth_str;
+#if defined(MBEDTLS_X509_CRL_PARSE_C)
+ char *crl_file;
+#endif
+
+ while (*end != '\0') {
+ ++end;
+ }
+ *end = ',';
+
+ while (p <= end) {
+ if ((new = mbedtls_calloc(1, sizeof(sni_entry))) == NULL) {
+ sni_free(cur);
+ return NULL;
+ }
+
+ GET_ITEM(new->name);
+ GET_ITEM(crt_file);
+ GET_ITEM(key_file);
+ GET_ITEM(ca_file);
+#if defined(MBEDTLS_X509_CRL_PARSE_C)
+ GET_ITEM(crl_file);
+#endif
+ GET_ITEM(auth_str);
+
+ if ((new->cert = mbedtls_calloc(1, sizeof(mbedtls_x509_crt))) == NULL ||
+ (new->key = mbedtls_calloc(1, sizeof(mbedtls_pk_context))) == NULL) {
+ goto error;
+ }
+
+ mbedtls_x509_crt_init(new->cert);
+ mbedtls_pk_init(new->key);
+
+ if (mbedtls_x509_crt_parse_file(new->cert, crt_file) != 0 ||
+ mbedtls_pk_parse_keyfile(new->key, key_file, "", rng_get, &rng) != 0) {
+ goto error;
+ }
+
+ if (strcmp(ca_file, "-") != 0) {
+ if ((new->ca = mbedtls_calloc(1, sizeof(mbedtls_x509_crt))) == NULL) {
+ goto error;
+ }
+
+ mbedtls_x509_crt_init(new->ca);
+
+ if (mbedtls_x509_crt_parse_file(new->ca, ca_file) != 0) {
+ goto error;
+ }
+ }
+
+#if defined(MBEDTLS_X509_CRL_PARSE_C)
+ if (strcmp(crl_file, "-") != 0) {
+ if ((new->crl = mbedtls_calloc(1, sizeof(mbedtls_x509_crl))) == NULL) {
+ goto error;
+ }
+
+ mbedtls_x509_crl_init(new->crl);
+
+ if (mbedtls_x509_crl_parse_file(new->crl, crl_file) != 0) {
+ goto error;
+ }
+ }
+#endif
+
+ if (strcmp(auth_str, "-") != 0) {
+ if ((new->authmode = get_auth_mode(auth_str)) < 0) {
+ goto error;
+ }
+ } else {
+ new->authmode = DFL_AUTH_MODE;
+ }
+
+ new->next = cur;
+ cur = new;
+ }
+
+ return cur;
+
+error:
+ sni_free(new);
+ sni_free(cur);
+ return NULL;
+}
+
+/*
+ * SNI callback.
+ */
+int sni_callback(void *p_info, mbedtls_ssl_context *ssl,
+ const unsigned char *name, size_t name_len)
+{
+ const sni_entry *cur = (const sni_entry *) p_info;
+
+ /* preserve behavior which checks for SNI match in sni_callback() for
+ * the benefits of tests using sni_callback(), even though the actual
+ * certificate assignment has moved to certificate selection callback
+ * in this application. This exercises sni_callback and cert_callback
+ * even though real applications might choose to do this differently.
+ * Application might choose to save name and name_len in user_data for
+ * later use in certificate selection callback.
+ */
+ while (cur != NULL) {
+ if (name_len == strlen(cur->name) &&
+ memcmp(name, cur->name, name_len) == 0) {
+ void *p;
+ *(const void **)&p = cur;
+ mbedtls_ssl_set_user_data_p(ssl, p);
+ return 0;
+ }
+
+ cur = cur->next;
+ }
+
+ return -1;
+}
+
+/*
+ * server certificate selection callback.
+ */
+int cert_callback(mbedtls_ssl_context *ssl)
+{
+ const sni_entry *cur = (sni_entry *) mbedtls_ssl_get_user_data_p(ssl);
+ if (cur != NULL) {
+ /*(exercise mbedtls_ssl_get_hs_sni(); not otherwise used here)*/
+ size_t name_len;
+ const unsigned char *name = mbedtls_ssl_get_hs_sni(ssl, &name_len);
+ if (strlen(cur->name) != name_len ||
+ memcmp(cur->name, name, name_len) != 0) {
+ return MBEDTLS_ERR_SSL_DECODE_ERROR;
+ }
+
+ if (cur->ca != NULL) {
+ mbedtls_ssl_set_hs_ca_chain(ssl, cur->ca, cur->crl);
+ }
+
+ if (cur->authmode != DFL_AUTH_MODE) {
+ mbedtls_ssl_set_hs_authmode(ssl, cur->authmode);
+ }
+
+ return mbedtls_ssl_set_hs_own_cert(ssl, cur->cert, cur->key);
+ }
+
+ return 0;
+}
+
+#endif /* SNI_OPTION */
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED)
+
+typedef struct _psk_entry psk_entry;
+
+struct _psk_entry {
+ const char *name;
+ size_t key_len;
+ unsigned char key[MBEDTLS_PSK_MAX_LEN];
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ mbedtls_svc_key_id_t slot;
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+ psk_entry *next;
+};
+
+/*
+ * Free a list of psk_entry's
+ */
+int psk_free(psk_entry *head)
+{
+ psk_entry *next;
+
+ while (head != NULL) {
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ psa_status_t status;
+ mbedtls_svc_key_id_t const slot = head->slot;
+
+ if (MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot) != 0) {
+ status = psa_destroy_key(slot);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ next = head->next;
+ mbedtls_free(head);
+ head = next;
+ }
+
+ return 0;
+}
+
+/*
+ * Parse a string of pairs name1,key1[,name2,key2[,...]]
+ * into a usable psk_entry list.
+ *
+ * Modifies the input string! This is not production quality!
+ */
+psk_entry *psk_parse(char *psk_string)
+{
+ psk_entry *cur = NULL, *new = NULL;
+ char *p = psk_string;
+ char *end = p;
+ char *key_hex;
+
+ while (*end != '\0') {
+ ++end;
+ }
+ *end = ',';
+
+ while (p <= end) {
+ if ((new = mbedtls_calloc(1, sizeof(psk_entry))) == NULL) {
+ goto error;
+ }
+
+ memset(new, 0, sizeof(psk_entry));
+
+ GET_ITEM(new->name);
+ GET_ITEM(key_hex);
+
+ if (mbedtls_test_unhexify(new->key, MBEDTLS_PSK_MAX_LEN,
+ key_hex, &new->key_len) != 0) {
+ goto error;
+ }
+
+ new->next = cur;
+ cur = new;
+ }
+
+ return cur;
+
+error:
+ psk_free(new);
+ psk_free(cur);
+ return 0;
+}
+
+/*
+ * PSK callback
+ */
+int psk_callback(void *p_info, mbedtls_ssl_context *ssl,
+ const unsigned char *name, size_t name_len)
+{
+ psk_entry *cur = (psk_entry *) p_info;
+
+ while (cur != NULL) {
+ if (name_len == strlen(cur->name) &&
+ memcmp(name, cur->name, name_len) == 0) {
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ if (MBEDTLS_SVC_KEY_ID_GET_KEY_ID(cur->slot) != 0) {
+ return mbedtls_ssl_set_hs_psk_opaque(ssl, cur->slot);
+ } else
+#endif
+ return mbedtls_ssl_set_hs_psk(ssl, cur->key, cur->key_len);
+ }
+
+ cur = cur->next;
+ }
+
+ return -1;
+}
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED */
+
+static mbedtls_net_context listen_fd, client_fd;
+
+/* Interruption handler to ensure clean exit (for valgrind testing) */
+#if !defined(_WIN32)
+static int received_sigterm = 0;
+void term_handler(int sig)
+{
+ ((void) sig);
+ received_sigterm = 1;
+ mbedtls_net_free(&listen_fd); /* causes mbedtls_net_accept() to abort */
+ mbedtls_net_free(&client_fd); /* causes net_read() to abort */
+}
+#endif
+
+/** Return true if \p ret is a status code indicating that there is an
+ * operation in progress on an SSL connection, and false if it indicates
+ * success or a fatal error.
+ *
+ * The possible operations in progress are:
+ *
+ * - A read, when the SSL input buffer does not contain a full message.
+ * - A write, when the SSL output buffer contains some data that has not
+ * been sent over the network yet.
+ * - An asynchronous callback that has not completed yet. */
+static int mbedtls_status_is_ssl_in_progress(int ret)
+{
+ return ret == MBEDTLS_ERR_SSL_WANT_READ ||
+ ret == MBEDTLS_ERR_SSL_WANT_WRITE ||
+ ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS;
+}
+
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+typedef struct {
+ mbedtls_x509_crt *cert; /*!< Certificate corresponding to the key */
+ mbedtls_pk_context *pk; /*!< Private key */
+ unsigned delay; /*!< Number of resume steps to go through */
+ unsigned pk_owned : 1; /*!< Whether to free the pk object on exit */
+} ssl_async_key_slot_t;
+
+typedef enum {
+ SSL_ASYNC_INJECT_ERROR_NONE = 0, /*!< Let the callbacks succeed */
+ SSL_ASYNC_INJECT_ERROR_START, /*!< Inject error during start */
+ SSL_ASYNC_INJECT_ERROR_CANCEL, /*!< Close the connection after async start */
+ SSL_ASYNC_INJECT_ERROR_RESUME, /*!< Inject error during resume */
+#define SSL_ASYNC_INJECT_ERROR_MAX SSL_ASYNC_INJECT_ERROR_RESUME
+} ssl_async_inject_error_t;
+
+typedef struct {
+ ssl_async_key_slot_t slots[4]; /* key, key2, sni1, sni2 */
+ size_t slots_used;
+ ssl_async_inject_error_t inject_error;
+ int (*f_rng)(void *, unsigned char *, size_t);
+ void *p_rng;
+} ssl_async_key_context_t;
+
+int ssl_async_set_key(ssl_async_key_context_t *ctx,
+ mbedtls_x509_crt *cert,
+ mbedtls_pk_context *pk,
+ int pk_take_ownership,
+ unsigned delay)
+{
+ if (ctx->slots_used >= sizeof(ctx->slots) / sizeof(*ctx->slots)) {
+ return -1;
+ }
+ ctx->slots[ctx->slots_used].cert = cert;
+ ctx->slots[ctx->slots_used].pk = pk;
+ ctx->slots[ctx->slots_used].delay = delay;
+ ctx->slots[ctx->slots_used].pk_owned = pk_take_ownership;
+ ++ctx->slots_used;
+ return 0;
+}
+
+#define SSL_ASYNC_INPUT_MAX_SIZE 512
+
+typedef enum {
+ ASYNC_OP_SIGN,
+ ASYNC_OP_DECRYPT,
+} ssl_async_operation_type_t;
+
+typedef struct {
+ unsigned slot;
+ ssl_async_operation_type_t operation_type;
+ mbedtls_md_type_t md_alg;
+ unsigned char input[SSL_ASYNC_INPUT_MAX_SIZE];
+ size_t input_len;
+ unsigned remaining_delay;
+} ssl_async_operation_context_t;
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+
+/* Note that ssl_async_operation_type_t and the array below need to be kept in sync!
+ * `ssl_async_operation_names[op]` is the name of op for each value `op`
+ * of type `ssl_async_operation_type_t`. */
+static const char *const ssl_async_operation_names[] =
+{
+ "sign",
+ "decrypt",
+};
+
+static int ssl_async_start(mbedtls_ssl_context *ssl,
+ mbedtls_x509_crt *cert,
+ ssl_async_operation_type_t op_type,
+ mbedtls_md_type_t md_alg,
+ const unsigned char *input,
+ size_t input_len)
+{
+ ssl_async_key_context_t *config_data =
+ mbedtls_ssl_conf_get_async_config_data(ssl->conf);
+ unsigned slot;
+ ssl_async_operation_context_t *ctx = NULL;
+ const char *op_name = ssl_async_operation_names[op_type];
+
+ {
+ char dn[100];
+ if (mbedtls_x509_dn_gets(dn, sizeof(dn), &cert->subject) > 0) {
+ mbedtls_printf("Async %s callback: looking for DN=%s\n",
+ op_name, dn);
+ }
+ }
+
+ /* Look for a private key that matches the public key in cert.
+ * Since this test code has the private key inside Mbed TLS,
+ * we call mbedtls_pk_check_pair to match a private key with the
+ * public key. */
+ for (slot = 0; slot < config_data->slots_used; slot++) {
+ if (mbedtls_pk_check_pair(&cert->pk,
+ config_data->slots[slot].pk,
+ rng_get, &rng) == 0) {
+ break;
+ }
+ }
+ if (slot == config_data->slots_used) {
+ mbedtls_printf("Async %s callback: no key matches this certificate.\n",
+ op_name);
+ return MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH;
+ }
+ mbedtls_printf("Async %s callback: using key slot %u, delay=%u.\n",
+ op_name, slot, config_data->slots[slot].delay);
+
+ if (config_data->inject_error == SSL_ASYNC_INJECT_ERROR_START) {
+ mbedtls_printf("Async %s callback: injected error\n", op_name);
+ return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
+ }
+
+ if (input_len > SSL_ASYNC_INPUT_MAX_SIZE) {
+ return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+ }
+
+ ctx = mbedtls_calloc(1, sizeof(*ctx));
+ if (ctx == NULL) {
+ return MBEDTLS_ERR_SSL_ALLOC_FAILED;
+ }
+ ctx->slot = slot;
+ ctx->operation_type = op_type;
+ ctx->md_alg = md_alg;
+ memcpy(ctx->input, input, input_len);
+ ctx->input_len = input_len;
+ ctx->remaining_delay = config_data->slots[slot].delay;
+ mbedtls_ssl_set_async_operation_data(ssl, ctx);
+
+ if (ctx->remaining_delay == 0) {
+ return 0;
+ } else {
+ return MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS;
+ }
+}
+
+static int ssl_async_sign(mbedtls_ssl_context *ssl,
+ mbedtls_x509_crt *cert,
+ mbedtls_md_type_t md_alg,
+ const unsigned char *hash,
+ size_t hash_len)
+{
+ return ssl_async_start(ssl, cert,
+ ASYNC_OP_SIGN, md_alg,
+ hash, hash_len);
+}
+
+static int ssl_async_decrypt(mbedtls_ssl_context *ssl,
+ mbedtls_x509_crt *cert,
+ const unsigned char *input,
+ size_t input_len)
+{
+ return ssl_async_start(ssl, cert,
+ ASYNC_OP_DECRYPT, MBEDTLS_MD_NONE,
+ input, input_len);
+}
+
+static int ssl_async_resume(mbedtls_ssl_context *ssl,
+ unsigned char *output,
+ size_t *output_len,
+ size_t output_size)
+{
+ ssl_async_operation_context_t *ctx = mbedtls_ssl_get_async_operation_data(ssl);
+ ssl_async_key_context_t *config_data =
+ mbedtls_ssl_conf_get_async_config_data(ssl->conf);
+ ssl_async_key_slot_t *key_slot = &config_data->slots[ctx->slot];
+ int ret;
+ const char *op_name;
+
+ if (ctx->remaining_delay > 0) {
+ --ctx->remaining_delay;
+ mbedtls_printf("Async resume (slot %u): call %u more times.\n",
+ ctx->slot, ctx->remaining_delay);
+ return MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS;
+ }
+
+ switch (ctx->operation_type) {
+ case ASYNC_OP_DECRYPT:
+ ret = mbedtls_pk_decrypt(key_slot->pk,
+ ctx->input, ctx->input_len,
+ output, output_len, output_size,
+ config_data->f_rng, config_data->p_rng);
+ break;
+ case ASYNC_OP_SIGN:
+ ret = mbedtls_pk_sign(key_slot->pk,
+ ctx->md_alg,
+ ctx->input, ctx->input_len,
+ output, output_size, output_len,
+ config_data->f_rng, config_data->p_rng);
+ break;
+ default:
+ mbedtls_printf(
+ "Async resume (slot %u): unknown operation type %ld. This shouldn't happen.\n",
+ ctx->slot,
+ (long) ctx->operation_type);
+ mbedtls_free(ctx);
+ return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
+ break;
+ }
+
+ op_name = ssl_async_operation_names[ctx->operation_type];
+
+ if (config_data->inject_error == SSL_ASYNC_INJECT_ERROR_RESUME) {
+ mbedtls_printf("Async resume callback: %s done but injected error\n",
+ op_name);
+ mbedtls_free(ctx);
+ return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
+ }
+
+ mbedtls_printf("Async resume (slot %u): %s done, status=%d.\n",
+ ctx->slot, op_name, ret);
+ mbedtls_free(ctx);
+ return ret;
+}
+
+static void ssl_async_cancel(mbedtls_ssl_context *ssl)
+{
+ ssl_async_operation_context_t *ctx = mbedtls_ssl_get_async_operation_data(ssl);
+ mbedtls_printf("Async cancel callback.\n");
+ mbedtls_free(ctx);
+}
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED)
+static psa_status_t psa_setup_psk_key_slot(mbedtls_svc_key_id_t *slot,
+ psa_algorithm_t alg,
+ unsigned char *psk,
+ size_t psk_len)
+{
+ psa_status_t status;
+ psa_key_attributes_t key_attributes;
+
+ key_attributes = psa_key_attributes_init();
+ psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_DERIVE);
+ psa_set_key_algorithm(&key_attributes, alg);
+ psa_set_key_type(&key_attributes, PSA_KEY_TYPE_DERIVE);
+
+ status = psa_import_key(&key_attributes, psk, psk_len, slot);
+ if (status != PSA_SUCCESS) {
+ fprintf(stderr, "IMPORT\n");
+ return status;
+ }
+
+ return PSA_SUCCESS;
+}
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED */
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+int report_cid_usage(mbedtls_ssl_context *ssl,
+ const char *additional_description)
+{
+ int ret;
+ unsigned char peer_cid[MBEDTLS_SSL_CID_OUT_LEN_MAX];
+ size_t peer_cid_len;
+ int cid_negotiated;
+
+ if (opt.transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
+ return 0;
+ }
+
+ /* Check if the use of a CID has been negotiated */
+ ret = mbedtls_ssl_get_peer_cid(ssl, &cid_negotiated,
+ peer_cid, &peer_cid_len);
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_get_peer_cid returned -0x%x\n\n",
+ (unsigned int) -ret);
+ return ret;
+ }
+
+ if (cid_negotiated == MBEDTLS_SSL_CID_DISABLED) {
+ if (opt.cid_enabled == MBEDTLS_SSL_CID_ENABLED) {
+ mbedtls_printf("(%s) Use of Connection ID was not offered by client.\n",
+ additional_description);
+ }
+ } else {
+ size_t idx = 0;
+ mbedtls_printf("(%s) Use of Connection ID has been negotiated.\n",
+ additional_description);
+ mbedtls_printf("(%s) Peer CID (length %u Bytes): ",
+ additional_description,
+ (unsigned) peer_cid_len);
+ while (idx < peer_cid_len) {
+ mbedtls_printf("%02x ", peer_cid[idx]);
+ idx++;
+ }
+ mbedtls_printf("\n");
+ }
+
+ return 0;
+}
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_HAVE_TIME)
+static inline void put_unaligned_uint32(void *p, uint32_t x)
+{
+ memcpy(p, &x, sizeof(x));
+}
+
+/* Functions for session ticket tests */
+int dummy_ticket_write(void *p_ticket, const mbedtls_ssl_session *session,
+ unsigned char *start, const unsigned char *end,
+ size_t *tlen, uint32_t *ticket_lifetime)
+{
+ int ret;
+ unsigned char *p = start;
+ size_t clear_len;
+ ((void) p_ticket);
+
+ if (end - p < 4) {
+ return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL;
+ }
+ put_unaligned_uint32(p, 7 * 24 * 3600);
+ *ticket_lifetime = 7 * 24 * 3600;
+ p += 4;
+
+ /* Dump session state */
+ if ((ret = mbedtls_ssl_session_save(session, p, end - p,
+ &clear_len)) != 0) {
+ return ret;
+ }
+
+ *tlen = 4 + clear_len;
+
+ return 0;
+}
+
+int dummy_ticket_parse(void *p_ticket, mbedtls_ssl_session *session,
+ unsigned char *buf, size_t len)
+{
+ int ret;
+ ((void) p_ticket);
+
+ if ((ret = mbedtls_ssl_session_load(session, buf + 4, len - 4)) != 0) {
+ return ret;
+ }
+
+ switch (opt.dummy_ticket % 11) {
+ case 1:
+ return MBEDTLS_ERR_SSL_INVALID_MAC;
+ case 2:
+ return MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
+ case 3:
+ /* Creation time in the future. */
+ session->ticket_creation_time = mbedtls_ms_time() + 1000;
+ break;
+ case 4:
+ /* Ticket has reached the end of lifetime. */
+ session->ticket_creation_time = mbedtls_ms_time() -
+ (7 * 24 * 3600 * 1000 + 1000);
+ break;
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ case 5:
+ /* Ticket is valid, but client age is below the lower bound of the tolerance window. */
+ session->ticket_age_add += MBEDTLS_SSL_TLS1_3_TICKET_AGE_TOLERANCE + 4 * 1000;
+ /* Make sure the execution time does not affect the result */
+ session->ticket_creation_time = mbedtls_ms_time();
+ break;
+
+ case 6:
+ /* Ticket is valid, but client age is beyond the upper bound of the tolerance window. */
+ session->ticket_age_add -= MBEDTLS_SSL_TLS1_3_TICKET_AGE_TOLERANCE + 4 * 1000;
+ /* Make sure the execution time does not affect the result */
+ session->ticket_creation_time = mbedtls_ms_time();
+ break;
+ case 7:
+ session->ticket_flags = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_NONE;
+ break;
+ case 8:
+ session->ticket_flags = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK;
+ break;
+ case 9:
+ session->ticket_flags = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL;
+ break;
+ case 10:
+ session->ticket_flags = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ALL;
+ break;
+#endif
+ default:
+ break;
+ }
+
+ return ret;
+}
+#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_HAVE_TIME */
+
+int parse_cipher(char *buf)
+{
+ if (strcmp(buf, "AES-128-CCM")) {
+ return MBEDTLS_CIPHER_AES_128_CCM;
+ } else if (strcmp(buf, "AES-128-GCM")) {
+ return MBEDTLS_CIPHER_AES_128_GCM;
+ } else if (strcmp(buf, "AES-192-CCM")) {
+ return MBEDTLS_CIPHER_AES_192_CCM;
+ } else if (strcmp(buf, "AES-192-GCM")) {
+ return MBEDTLS_CIPHER_AES_192_GCM;
+ } else if (strcmp(buf, "AES-256-CCM")) {
+ return MBEDTLS_CIPHER_AES_256_CCM;
+ } else if (strcmp(buf, "ARIA-128-CCM")) {
+ return MBEDTLS_CIPHER_ARIA_128_CCM;
+ } else if (strcmp(buf, "ARIA-128-GCM")) {
+ return MBEDTLS_CIPHER_ARIA_128_GCM;
+ } else if (strcmp(buf, "ARIA-192-CCM")) {
+ return MBEDTLS_CIPHER_ARIA_192_CCM;
+ } else if (strcmp(buf, "ARIA-192-GCM")) {
+ return MBEDTLS_CIPHER_ARIA_192_GCM;
+ } else if (strcmp(buf, "ARIA-256-CCM")) {
+ return MBEDTLS_CIPHER_ARIA_256_CCM;
+ } else if (strcmp(buf, "ARIA-256-GCM")) {
+ return MBEDTLS_CIPHER_ARIA_256_GCM;
+ } else if (strcmp(buf, "CAMELLIA-128-CCM")) {
+ return MBEDTLS_CIPHER_CAMELLIA_128_CCM;
+ } else if (strcmp(buf, "CAMELLIA-192-CCM")) {
+ return MBEDTLS_CIPHER_CAMELLIA_192_CCM;
+ } else if (strcmp(buf, "CAMELLIA-256-CCM")) {
+ return MBEDTLS_CIPHER_CAMELLIA_256_CCM;
+ } else if (strcmp(buf, "CHACHA20-POLY1305")) {
+ return MBEDTLS_CIPHER_CHACHA20_POLY1305;
+ }
+ return MBEDTLS_CIPHER_NONE;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret = 0, len, written, frags, exchanges_left;
+ int query_config_ret = 0;
+ io_ctx_t io_ctx;
+ unsigned char *buf = 0;
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED)
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ psa_algorithm_t alg = 0;
+ mbedtls_svc_key_id_t psk_slot = MBEDTLS_SVC_KEY_ID_INIT;
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+ unsigned char psk[MBEDTLS_PSK_MAX_LEN];
+ size_t psk_len = 0;
+ psk_entry *psk_info = NULL;
+#endif
+ const char *pers = "ssl_server2";
+ unsigned char client_ip[16] = { 0 };
+ size_t cliip_len;
+#if defined(MBEDTLS_SSL_COOKIE_C)
+ mbedtls_ssl_cookie_ctx cookie_ctx;
+#endif
+
+ mbedtls_ssl_context ssl;
+ mbedtls_ssl_config conf;
+#if defined(MBEDTLS_TIMING_C)
+ mbedtls_timing_delay_context timer;
+#endif
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+ unsigned char renego_period[8] = { 0 };
+#endif
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ uint32_t flags;
+ mbedtls_x509_crt cacert;
+ mbedtls_x509_crt srvcert;
+ mbedtls_pk_context pkey;
+ mbedtls_x509_crt srvcert2;
+ mbedtls_pk_context pkey2;
+ mbedtls_x509_crt_profile crt_profile_for_test = mbedtls_x509_crt_profile_default;
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ mbedtls_svc_key_id_t key_slot = MBEDTLS_SVC_KEY_ID_INIT; /* invalid key slot */
+ mbedtls_svc_key_id_t key_slot2 = MBEDTLS_SVC_KEY_ID_INIT; /* invalid key slot */
+#endif
+ int key_cert_init = 0, key_cert_init2 = 0;
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+ ssl_async_key_context_t ssl_async_keys;
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_FS_IO)
+ mbedtls_dhm_context dhm;
+#endif
+#if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_cache_context cache;
+#endif
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
+ mbedtls_ssl_ticket_context ticket_ctx;
+#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_TICKET_C */
+#if defined(SNI_OPTION)
+ sni_entry *sni_info = NULL;
+#endif
+ uint16_t group_list[GROUP_LIST_SIZE];
+#if defined(MBEDTLS_SSL_ALPN)
+ const char *alpn_list[ALPN_LIST_SIZE];
+#endif
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+ unsigned char alloc_buf[MEMORY_HEAP_SIZE];
+#endif
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+ unsigned char cid[MBEDTLS_SSL_CID_IN_LEN_MAX];
+ unsigned char cid_renego[MBEDTLS_SSL_CID_IN_LEN_MAX];
+ size_t cid_len = 0;
+ size_t cid_renego_len = 0;
+#endif
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+ unsigned char *context_buf = NULL;
+ size_t context_buf_len = 0;
+#endif
+#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) && \
+ defined(MBEDTLS_USE_PSA_CRYPTO)
+ mbedtls_svc_key_id_t ecjpake_pw_slot = MBEDTLS_SVC_KEY_ID_INIT; /* ecjpake password key slot */
+#endif /* MBEDTLS_USE_PSA_CRYPTO && MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ uint16_t sig_alg_list[SIG_ALG_LIST_SIZE];
+#endif
+
+ int i;
+ char *p, *q;
+ const int *list;
+#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ psa_status_t status;
+#endif
+ unsigned char eap_tls_keymaterial[16];
+ unsigned char eap_tls_iv[8];
+ const char *eap_tls_label = "client EAP encryption";
+ eap_tls_keys eap_tls_keying;
+#if defined(MBEDTLS_SSL_DTLS_SRTP)
+ /*! master keys and master salt for SRTP generated during handshake */
+ unsigned char dtls_srtp_key_material[MBEDTLS_TLS_SRTP_MAX_KEY_MATERIAL_LENGTH];
+ const char *dtls_srtp_label = "EXTRACTOR-dtls_srtp";
+ dtls_srtp_keys dtls_srtp_keying;
+ const mbedtls_ssl_srtp_profile default_profiles[] = {
+ MBEDTLS_TLS_SRTP_AES128_CM_HMAC_SHA1_80,
+ MBEDTLS_TLS_SRTP_AES128_CM_HMAC_SHA1_32,
+ MBEDTLS_TLS_SRTP_NULL_HMAC_SHA1_80,
+ MBEDTLS_TLS_SRTP_NULL_HMAC_SHA1_32,
+ MBEDTLS_TLS_SRTP_UNSET
+ };
+#endif /* MBEDTLS_SSL_DTLS_SRTP */
+
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+ mbedtls_memory_buffer_alloc_init(alloc_buf, sizeof(alloc_buf));
+#if defined(MBEDTLS_MEMORY_DEBUG)
+ size_t current_heap_memory, peak_heap_memory, heap_blocks;
+#endif /* MBEDTLS_MEMORY_DEBUG */
+#endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */
+
+#if defined(MBEDTLS_TEST_HOOKS)
+ test_hooks_init();
+#endif /* MBEDTLS_TEST_HOOKS */
+
+ /*
+ * Make sure memory references are valid in case we exit early.
+ */
+ mbedtls_net_init(&client_fd);
+ mbedtls_net_init(&listen_fd);
+ mbedtls_ssl_init(&ssl);
+ mbedtls_ssl_config_init(&conf);
+ rng_init(&rng);
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ mbedtls_x509_crt_init(&cacert);
+ mbedtls_x509_crt_init(&srvcert);
+ mbedtls_pk_init(&pkey);
+ mbedtls_x509_crt_init(&srvcert2);
+ mbedtls_pk_init(&pkey2);
+#endif
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+ memset(&ssl_async_keys, 0, sizeof(ssl_async_keys));
+#endif
+#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_FS_IO)
+ mbedtls_dhm_init(&dhm);
+#endif
+#if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_cache_init(&cache);
+#endif
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
+ mbedtls_ssl_ticket_init(&ticket_ctx);
+#endif
+#if defined(MBEDTLS_SSL_ALPN)
+ memset((void *) alpn_list, 0, sizeof(alpn_list));
+#endif
+#if defined(MBEDTLS_SSL_COOKIE_C)
+ mbedtls_ssl_cookie_init(&cookie_ctx);
+#endif
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ status = psa_crypto_init();
+ if (status != PSA_SUCCESS) {
+ mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
+ (int) status);
+ ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
+ goto exit;
+ }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+ mbedtls_test_enable_insecure_external_rng();
+#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+
+#if !defined(_WIN32)
+ /* Abort cleanly on SIGTERM and SIGINT */
+ signal(SIGTERM, term_handler);
+ signal(SIGINT, term_handler);
+#endif
+
+ opt.buffer_size = DFL_IO_BUF_LEN;
+ opt.server_addr = DFL_SERVER_ADDR;
+ opt.server_port = DFL_SERVER_PORT;
+ opt.debug_level = DFL_DEBUG_LEVEL;
+ opt.event = DFL_EVENT;
+ opt.response_size = DFL_RESPONSE_SIZE;
+ opt.nbio = DFL_NBIO;
+ opt.cid_enabled = DFL_CID_ENABLED;
+ opt.cid_enabled_renego = DFL_CID_ENABLED_RENEGO;
+ opt.cid_val = DFL_CID_VALUE;
+ opt.cid_val_renego = DFL_CID_VALUE_RENEGO;
+ opt.read_timeout = DFL_READ_TIMEOUT;
+ opt.ca_file = DFL_CA_FILE;
+ opt.ca_path = DFL_CA_PATH;
+ opt.crt_file = DFL_CRT_FILE;
+ opt.key_file = DFL_KEY_FILE;
+ opt.key_opaque = DFL_KEY_OPAQUE;
+ opt.key_pwd = DFL_KEY_PWD;
+ opt.crt_file2 = DFL_CRT_FILE2;
+ opt.key_file2 = DFL_KEY_FILE2;
+ opt.key_pwd2 = DFL_KEY_PWD2;
+ opt.async_operations = DFL_ASYNC_OPERATIONS;
+ opt.async_private_delay1 = DFL_ASYNC_PRIVATE_DELAY1;
+ opt.async_private_delay2 = DFL_ASYNC_PRIVATE_DELAY2;
+ opt.async_private_error = DFL_ASYNC_PRIVATE_ERROR;
+ opt.psk = DFL_PSK;
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ opt.psk_opaque = DFL_PSK_OPAQUE;
+ opt.psk_list_opaque = DFL_PSK_LIST_OPAQUE;
+#endif
+#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
+ opt.ca_callback = DFL_CA_CALLBACK;
+#endif
+ opt.psk_identity = DFL_PSK_IDENTITY;
+ opt.psk_list = DFL_PSK_LIST;
+ opt.ecjpake_pw = DFL_ECJPAKE_PW;
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ opt.ecjpake_pw_opaque = DFL_ECJPAKE_PW_OPAQUE;
+#endif
+ opt.force_ciphersuite[0] = DFL_FORCE_CIPHER;
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ opt.tls13_kex_modes = DFL_TLS1_3_KEX_MODES;
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+ opt.renegotiation = DFL_RENEGOTIATION;
+ opt.allow_legacy = DFL_ALLOW_LEGACY;
+ opt.renegotiate = DFL_RENEGOTIATE;
+ opt.renego_delay = DFL_RENEGO_DELAY;
+ opt.renego_period = DFL_RENEGO_PERIOD;
+ opt.exchanges = DFL_EXCHANGES;
+ opt.min_version = DFL_MIN_VERSION;
+ opt.max_version = DFL_MAX_VERSION;
+ opt.allow_sha1 = DFL_SHA1;
+ opt.auth_mode = DFL_AUTH_MODE;
+ opt.cert_req_ca_list = DFL_CERT_REQ_CA_LIST;
+ opt.cert_req_dn_hint = DFL_CERT_REQ_DN_HINT;
+ opt.mfl_code = DFL_MFL_CODE;
+ opt.trunc_hmac = DFL_TRUNC_HMAC;
+ opt.tickets = DFL_TICKETS;
+ opt.dummy_ticket = DFL_DUMMY_TICKET;
+ opt.ticket_rotate = DFL_TICKET_ROTATE;
+ opt.ticket_timeout = DFL_TICKET_TIMEOUT;
+ opt.ticket_aead = DFL_TICKET_AEAD;
+ opt.cache_max = DFL_CACHE_MAX;
+#if defined(MBEDTLS_HAVE_TIME)
+ opt.cache_timeout = DFL_CACHE_TIMEOUT;
+#endif
+ opt.cache_remove = DFL_CACHE_REMOVE;
+ opt.sni = DFL_SNI;
+ opt.alpn_string = DFL_ALPN_STRING;
+ opt.groups = DFL_GROUPS;
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+ opt.early_data = DFL_EARLY_DATA;
+ opt.max_early_data_size = DFL_MAX_EARLY_DATA_SIZE;
+#endif
+ opt.sig_algs = DFL_SIG_ALGS;
+ opt.dhm_file = DFL_DHM_FILE;
+ opt.transport = DFL_TRANSPORT;
+ opt.cookies = DFL_COOKIES;
+ opt.anti_replay = DFL_ANTI_REPLAY;
+ opt.hs_to_min = DFL_HS_TO_MIN;
+ opt.hs_to_max = DFL_HS_TO_MAX;
+ opt.dtls_mtu = DFL_DTLS_MTU;
+ opt.dgram_packing = DFL_DGRAM_PACKING;
+ opt.badmac_limit = DFL_BADMAC_LIMIT;
+ opt.extended_ms = DFL_EXTENDED_MS;
+ opt.etm = DFL_ETM;
+ opt.serialize = DFL_SERIALIZE;
+ opt.context_file = DFL_CONTEXT_FILE;
+ opt.eap_tls = DFL_EAP_TLS;
+ opt.reproducible = DFL_REPRODUCIBLE;
+ opt.nss_keylog = DFL_NSS_KEYLOG;
+ opt.nss_keylog_file = DFL_NSS_KEYLOG_FILE;
+ opt.query_config_mode = DFL_QUERY_CONFIG_MODE;
+ opt.use_srtp = DFL_USE_SRTP;
+ opt.force_srtp_profile = DFL_SRTP_FORCE_PROFILE;
+ opt.support_mki = DFL_SRTP_SUPPORT_MKI;
+ opt.key1_opaque_alg1 = DFL_KEY_OPAQUE_ALG;
+ opt.key1_opaque_alg2 = DFL_KEY_OPAQUE_ALG;
+ opt.key2_opaque_alg1 = DFL_KEY_OPAQUE_ALG;
+ opt.key2_opaque_alg2 = DFL_KEY_OPAQUE_ALG;
+
+ p = q = NULL;
+ if (argc < 1) {
+usage:
+ if (p != NULL && q != NULL) {
+ printf("unrecognized value for '%s': '%s'\n", p, q);
+ } else if (p != NULL && q == NULL) {
+ printf("unrecognized param: '%s'\n", p);
+ }
+
+ mbedtls_printf("usage: ssl_client2 [param=value] [...]\n");
+ mbedtls_printf(" ssl_client2 help[_theme]\n");
+ mbedtls_printf("'help' lists acceptable 'param' and 'value'\n");
+ mbedtls_printf("'help_ciphersuites' lists available ciphersuites\n");
+ mbedtls_printf("\n");
+
+ if (ret == 0) {
+ ret = 1;
+ }
+ goto exit;
+ }
+
+ for (i = 1; i < argc; i++) {
+ p = argv[i];
+
+ if (strcmp(p, "help") == 0) {
+ mbedtls_printf(USAGE1);
+ mbedtls_printf(USAGE2);
+ mbedtls_printf(USAGE3);
+ mbedtls_printf(USAGE4);
+
+ ret = 0;
+ goto exit;
+ }
+ if (strcmp(p, "help_ciphersuites") == 0) {
+ mbedtls_printf(" acceptable ciphersuite names:\n");
+ for (list = mbedtls_ssl_list_ciphersuites();
+ *list != 0;
+ list++) {
+ mbedtls_printf(" %s\n", mbedtls_ssl_get_ciphersuite_name(*list));
+ }
+
+ ret = 0;
+ goto exit;
+ }
+
+ if ((q = strchr(p, '=')) == NULL) {
+ mbedtls_printf("param requires a value: '%s'\n", p);
+ p = NULL; // avoid "unrecnognized param" message
+ goto usage;
+ }
+ *q++ = '\0';
+
+ if (strcmp(p, "server_port") == 0) {
+ opt.server_port = q;
+ } else if (strcmp(p, "server_addr") == 0) {
+ opt.server_addr = q;
+ } else if (strcmp(p, "dtls") == 0) {
+ int t = atoi(q);
+ if (t == 0) {
+ opt.transport = MBEDTLS_SSL_TRANSPORT_STREAM;
+ } else if (t == 1) {
+ opt.transport = MBEDTLS_SSL_TRANSPORT_DATAGRAM;
+ } else {
+ goto usage;
+ }
+ } else if (strcmp(p, "debug_level") == 0) {
+ opt.debug_level = atoi(q);
+ if (opt.debug_level < 0 || opt.debug_level > 65535) {
+ goto usage;
+ }
+ } else if (strcmp(p, "build_version") == 0) {
+ if (strcmp(q, "1") == 0) {
+ mbedtls_printf("build version: %s (build %d)\n",
+ MBEDTLS_VERSION_STRING_FULL,
+ MBEDTLS_VERSION_NUMBER);
+ goto exit;
+ }
+ } else if (strcmp(p, "nbio") == 0) {
+ opt.nbio = atoi(q);
+ if (opt.nbio < 0 || opt.nbio > 2) {
+ goto usage;
+ }
+ } else if (strcmp(p, "event") == 0) {
+ opt.event = atoi(q);
+ if (opt.event < 0 || opt.event > 2) {
+ goto usage;
+ }
+ } else if (strcmp(p, "read_timeout") == 0) {
+ opt.read_timeout = atoi(q);
+ } else if (strcmp(p, "buffer_size") == 0) {
+ opt.buffer_size = atoi(q);
+ if (opt.buffer_size < 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "response_size") == 0) {
+ opt.response_size = atoi(q);
+ if (opt.response_size < 0 || opt.response_size > MBEDTLS_SSL_OUT_CONTENT_LEN) {
+ goto usage;
+ }
+ if (opt.buffer_size < opt.response_size) {
+ opt.buffer_size = opt.response_size;
+ }
+ } else if (strcmp(p, "ca_file") == 0) {
+ opt.ca_file = q;
+ } else if (strcmp(p, "ca_path") == 0) {
+ opt.ca_path = q;
+ } else if (strcmp(p, "crt_file") == 0) {
+ opt.crt_file = q;
+ } else if (strcmp(p, "key_file") == 0) {
+ opt.key_file = q;
+ } else if (strcmp(p, "key_pwd") == 0) {
+ opt.key_pwd = q;
+ }
+#if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ else if (strcmp(p, "key_opaque") == 0) {
+ opt.key_opaque = atoi(q);
+ }
+#endif
+ else if (strcmp(p, "crt_file2") == 0) {
+ opt.crt_file2 = q;
+ } else if (strcmp(p, "key_file2") == 0) {
+ opt.key_file2 = q;
+ } else if (strcmp(p, "key_pwd2") == 0) {
+ opt.key_pwd2 = q;
+ } else if (strcmp(p, "dhm_file") == 0) {
+ opt.dhm_file = q;
+ }
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+ else if (strcmp(p, "async_operations") == 0) {
+ opt.async_operations = q;
+ } else if (strcmp(p, "async_private_delay1") == 0) {
+ opt.async_private_delay1 = atoi(q);
+ } else if (strcmp(p, "async_private_delay2") == 0) {
+ opt.async_private_delay2 = atoi(q);
+ } else if (strcmp(p, "async_private_error") == 0) {
+ int n = atoi(q);
+ if (n < -SSL_ASYNC_INJECT_ERROR_MAX ||
+ n > SSL_ASYNC_INJECT_ERROR_MAX) {
+ ret = 2;
+ goto usage;
+ }
+ opt.async_private_error = n;
+ }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+ else if (strcmp(p, "cid") == 0) {
+ opt.cid_enabled = atoi(q);
+ if (opt.cid_enabled != 0 && opt.cid_enabled != 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "cid_renego") == 0) {
+ opt.cid_enabled_renego = atoi(q);
+ if (opt.cid_enabled_renego != 0 && opt.cid_enabled_renego != 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "cid_val") == 0) {
+ opt.cid_val = q;
+ } else if (strcmp(p, "cid_val_renego") == 0) {
+ opt.cid_val_renego = q;
+ }
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+ else if (strcmp(p, "psk") == 0) {
+ opt.psk = q;
+ }
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ else if (strcmp(p, "psk_opaque") == 0) {
+ opt.psk_opaque = atoi(q);
+ } else if (strcmp(p, "psk_list_opaque") == 0) {
+ opt.psk_list_opaque = atoi(q);
+ }
+#endif
+#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
+ else if (strcmp(p, "ca_callback") == 0) {
+ opt.ca_callback = atoi(q);
+ }
+#endif
+ else if (strcmp(p, "psk_identity") == 0) {
+ opt.psk_identity = q;
+ } else if (strcmp(p, "psk_list") == 0) {
+ opt.psk_list = q;
+ } else if (strcmp(p, "ecjpake_pw") == 0) {
+ opt.ecjpake_pw = q;
+ }
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ else if (strcmp(p, "ecjpake_pw_opaque") == 0) {
+ opt.ecjpake_pw_opaque = atoi(q);
+ }
+#endif
+ else if (strcmp(p, "force_ciphersuite") == 0) {
+ opt.force_ciphersuite[0] = mbedtls_ssl_get_ciphersuite_id(q);
+
+ if (opt.force_ciphersuite[0] == 0) {
+ ret = 2;
+ goto usage;
+ }
+ opt.force_ciphersuite[1] = 0;
+ } else if (strcmp(p, "groups") == 0) {
+ opt.groups = q;
+ }
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ else if (strcmp(p, "sig_algs") == 0) {
+ opt.sig_algs = q;
+ }
+#endif
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+ else if (strcmp(p, "early_data") == 0) {
+ switch (atoi(q)) {
+ case 0:
+ opt.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED;
+ break;
+ case 1:
+ opt.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED;
+ break;
+ default: goto usage;
+ }
+ } else if (strcmp(p, "max_early_data_size") == 0) {
+ opt.max_early_data_size = (uint32_t) atoll(q);
+ }
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+ else if (strcmp(p, "renegotiation") == 0) {
+ opt.renegotiation = (atoi(q)) ?
+ MBEDTLS_SSL_RENEGOTIATION_ENABLED :
+ MBEDTLS_SSL_RENEGOTIATION_DISABLED;
+ } else if (strcmp(p, "allow_legacy") == 0) {
+ switch (atoi(q)) {
+ case -1:
+ opt.allow_legacy = MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE;
+ break;
+ case 0:
+ opt.allow_legacy = MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION;
+ break;
+ case 1:
+ opt.allow_legacy = MBEDTLS_SSL_LEGACY_ALLOW_RENEGOTIATION;
+ break;
+ default: goto usage;
+ }
+ } else if (strcmp(p, "renegotiate") == 0) {
+ opt.renegotiate = atoi(q);
+ if (opt.renegotiate < 0 || opt.renegotiate > 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "renego_delay") == 0) {
+ opt.renego_delay = atoi(q);
+ } else if (strcmp(p, "renego_period") == 0) {
+#if defined(_MSC_VER)
+ opt.renego_period = _strtoui64(q, NULL, 10);
+#else
+ if (sscanf(q, "%" SCNu64, &opt.renego_period) != 1) {
+ goto usage;
+ }
+#endif /* _MSC_VER */
+ if (opt.renego_period < 2) {
+ goto usage;
+ }
+ } else if (strcmp(p, "exchanges") == 0) {
+ opt.exchanges = atoi(q);
+ if (opt.exchanges < 0) {
+ goto usage;
+ }
+ }
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ else if (strcmp(p, "tls13_kex_modes") == 0) {
+ if (strcmp(q, "psk") == 0) {
+ opt.tls13_kex_modes = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK;
+ } else if (strcmp(q, "psk_ephemeral") == 0) {
+ opt.tls13_kex_modes = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL;
+ } else if (strcmp(q, "ephemeral") == 0) {
+ opt.tls13_kex_modes = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL;
+ } else if (strcmp(q, "ephemeral_all") == 0) {
+ opt.tls13_kex_modes = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ALL;
+ } else if (strcmp(q, "psk_all") == 0) {
+ opt.tls13_kex_modes = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ALL;
+ } else if (strcmp(q, "all") == 0) {
+ opt.tls13_kex_modes = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_ALL;
+ }
+ /* The purpose of `psk_or_ephemeral` is to improve test coverage. That
+ * is not recommended in practice.
+ * `psk_or_ephemeral` exists in theory, we need this mode to test if
+ * this setting work correctly. With this key exchange setting, server
+ * should always perform `ephemeral` handshake. `psk` or `psk_ephemeral`
+ * is not expected.
+ */
+ else if (strcmp(q, "psk_or_ephemeral") == 0) {
+ opt.tls13_kex_modes = MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK |
+ MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL;
+ } else {
+ goto usage;
+ }
+ }
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+
+ else if (strcmp(p, "min_version") == 0) {
+ if (strcmp(q, "tls12") == 0 ||
+ strcmp(q, "dtls12") == 0) {
+ opt.min_version = MBEDTLS_SSL_VERSION_TLS1_2;
+ }
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ else if (strcmp(q, "tls13") == 0) {
+ opt.min_version = MBEDTLS_SSL_VERSION_TLS1_3;
+ }
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+ else {
+ goto usage;
+ }
+ } else if (strcmp(p, "max_version") == 0) {
+ if (strcmp(q, "tls12") == 0 ||
+ strcmp(q, "dtls12") == 0) {
+ opt.max_version = MBEDTLS_SSL_VERSION_TLS1_2;
+ }
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ else if (strcmp(q, "tls13") == 0) {
+ opt.max_version = MBEDTLS_SSL_VERSION_TLS1_3;
+ }
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+ else {
+ goto usage;
+ }
+ } else if (strcmp(p, "allow_sha1") == 0) {
+ switch (atoi(q)) {
+ case 0: opt.allow_sha1 = 0; break;
+ case 1: opt.allow_sha1 = 1; break;
+ default: goto usage;
+ }
+ } else if (strcmp(p, "force_version") == 0) {
+ if (strcmp(q, "tls12") == 0) {
+ opt.min_version = MBEDTLS_SSL_VERSION_TLS1_2;
+ opt.max_version = MBEDTLS_SSL_VERSION_TLS1_2;
+ } else if (strcmp(q, "dtls12") == 0) {
+ opt.min_version = MBEDTLS_SSL_VERSION_TLS1_2;
+ opt.max_version = MBEDTLS_SSL_VERSION_TLS1_2;
+ opt.transport = MBEDTLS_SSL_TRANSPORT_DATAGRAM;
+ }
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ else if (strcmp(q, "tls13") == 0) {
+ opt.min_version = MBEDTLS_SSL_VERSION_TLS1_3;
+ opt.max_version = MBEDTLS_SSL_VERSION_TLS1_3;
+ }
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+ else {
+ goto usage;
+ }
+ } else if (strcmp(p, "auth_mode") == 0) {
+ if ((opt.auth_mode = get_auth_mode(q)) < 0) {
+ goto usage;
+ }
+ } else if (strcmp(p, "cert_req_ca_list") == 0) {
+ opt.cert_req_ca_list = atoi(q);
+ if (opt.cert_req_ca_list < 0 || opt.cert_req_ca_list > 3) {
+ goto usage;
+ }
+ if (opt.cert_req_ca_list > 1) {
+ opt.cert_req_dn_hint = opt.cert_req_ca_list;
+ opt.cert_req_ca_list = MBEDTLS_SSL_CERT_REQ_CA_LIST_ENABLED;
+ }
+ } else if (strcmp(p, "max_frag_len") == 0) {
+ if (strcmp(q, "512") == 0) {
+ opt.mfl_code = MBEDTLS_SSL_MAX_FRAG_LEN_512;
+ } else if (strcmp(q, "1024") == 0) {
+ opt.mfl_code = MBEDTLS_SSL_MAX_FRAG_LEN_1024;
+ } else if (strcmp(q, "2048") == 0) {
+ opt.mfl_code = MBEDTLS_SSL_MAX_FRAG_LEN_2048;
+ } else if (strcmp(q, "4096") == 0) {
+ opt.mfl_code = MBEDTLS_SSL_MAX_FRAG_LEN_4096;
+ } else {
+ goto usage;
+ }
+ } else if (strcmp(p, "alpn") == 0) {
+ opt.alpn_string = q;
+ } else if (strcmp(p, "trunc_hmac") == 0) {
+ switch (atoi(q)) {
+ case 0: opt.trunc_hmac = MBEDTLS_SSL_TRUNC_HMAC_DISABLED; break;
+ case 1: opt.trunc_hmac = MBEDTLS_SSL_TRUNC_HMAC_ENABLED; break;
+ default: goto usage;
+ }
+ } else if (strcmp(p, "extended_ms") == 0) {
+ switch (atoi(q)) {
+ case 0:
+ opt.extended_ms = MBEDTLS_SSL_EXTENDED_MS_DISABLED;
+ break;
+ case 1:
+ opt.extended_ms = MBEDTLS_SSL_EXTENDED_MS_ENABLED;
+ break;
+ default: goto usage;
+ }
+ } else if (strcmp(p, "etm") == 0) {
+ switch (atoi(q)) {
+ case 0: opt.etm = MBEDTLS_SSL_ETM_DISABLED; break;
+ case 1: opt.etm = MBEDTLS_SSL_ETM_ENABLED; break;
+ default: goto usage;
+ }
+ } else if (strcmp(p, "tickets") == 0) {
+ opt.tickets = atoi(q);
+ if (opt.tickets < 0) {
+ goto usage;
+ }
+ } else if (strcmp(p, "dummy_ticket") == 0) {
+ opt.dummy_ticket = atoi(q);
+ if (opt.dummy_ticket < 0) {
+ goto usage;
+ }
+ } else if (strcmp(p, "ticket_rotate") == 0) {
+ opt.ticket_rotate = atoi(q);
+ if (opt.ticket_rotate < 0 || opt.ticket_rotate > 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "ticket_timeout") == 0) {
+ opt.ticket_timeout = atoi(q);
+ if (opt.ticket_timeout < 0) {
+ goto usage;
+ }
+ } else if (strcmp(p, "ticket_aead") == 0) {
+ opt.ticket_aead = parse_cipher(q);
+
+ if (opt.ticket_aead == MBEDTLS_CIPHER_NONE) {
+ goto usage;
+ }
+ } else if (strcmp(p, "cache_max") == 0) {
+ opt.cache_max = atoi(q);
+ if (opt.cache_max < 0) {
+ goto usage;
+ }
+ }
+#if defined(MBEDTLS_HAVE_TIME)
+ else if (strcmp(p, "cache_timeout") == 0) {
+ opt.cache_timeout = atoi(q);
+ if (opt.cache_timeout < 0) {
+ goto usage;
+ }
+ }
+#endif
+ else if (strcmp(p, "cache_remove") == 0) {
+ opt.cache_remove = atoi(q);
+ if (opt.cache_remove < 0 || opt.cache_remove > 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "cookies") == 0) {
+ opt.cookies = atoi(q);
+ if (opt.cookies < -1 || opt.cookies > 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "anti_replay") == 0) {
+ opt.anti_replay = atoi(q);
+ if (opt.anti_replay < 0 || opt.anti_replay > 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "badmac_limit") == 0) {
+ opt.badmac_limit = atoi(q);
+ if (opt.badmac_limit < 0) {
+ goto usage;
+ }
+ } else if (strcmp(p, "hs_timeout") == 0) {
+ if ((p = strchr(q, '-')) == NULL) {
+ goto usage;
+ }
+ *p++ = '\0';
+ opt.hs_to_min = atoi(q);
+ opt.hs_to_max = atoi(p);
+ if (opt.hs_to_min == 0 || opt.hs_to_max < opt.hs_to_min) {
+ goto usage;
+ }
+ } else if (strcmp(p, "mtu") == 0) {
+ opt.dtls_mtu = atoi(q);
+ if (opt.dtls_mtu < 0) {
+ goto usage;
+ }
+ } else if (strcmp(p, "dgram_packing") == 0) {
+ opt.dgram_packing = atoi(q);
+ if (opt.dgram_packing != 0 &&
+ opt.dgram_packing != 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "sni") == 0) {
+ opt.sni = q;
+ } else if (strcmp(p, "query_config") == 0) {
+ opt.query_config_mode = 1;
+ query_config_ret = query_config(q);
+ goto exit;
+ } else if (strcmp(p, "serialize") == 0) {
+ opt.serialize = atoi(q);
+ if (opt.serialize < 0 || opt.serialize > 2) {
+ goto usage;
+ }
+ } else if (strcmp(p, "context_file") == 0) {
+ opt.context_file = q;
+ } else if (strcmp(p, "eap_tls") == 0) {
+ opt.eap_tls = atoi(q);
+ if (opt.eap_tls < 0 || opt.eap_tls > 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "reproducible") == 0) {
+ opt.reproducible = 1;
+ } else if (strcmp(p, "nss_keylog") == 0) {
+ opt.nss_keylog = atoi(q);
+ if (opt.nss_keylog < 0 || opt.nss_keylog > 1) {
+ goto usage;
+ }
+ } else if (strcmp(p, "nss_keylog_file") == 0) {
+ opt.nss_keylog_file = q;
+ } else if (strcmp(p, "use_srtp") == 0) {
+ opt.use_srtp = atoi(q);
+ } else if (strcmp(p, "srtp_force_profile") == 0) {
+ opt.force_srtp_profile = atoi(q);
+ } else if (strcmp(p, "support_mki") == 0) {
+ opt.support_mki = atoi(q);
+ } else if (strcmp(p, "key_opaque_algs") == 0) {
+ if (key_opaque_alg_parse(q, &opt.key1_opaque_alg1,
+ &opt.key1_opaque_alg2) != 0) {
+ goto usage;
+ }
+ } else if (strcmp(p, "key_opaque_algs2") == 0) {
+ if (key_opaque_alg_parse(q, &opt.key2_opaque_alg1,
+ &opt.key2_opaque_alg2) != 0) {
+ goto usage;
+ }
+ } else {
+ /* This signals that the problem is with p not q */
+ q = NULL;
+ goto usage;
+ }
+ }
+ /* This signals that any further erorrs are not with a single option */
+ p = q = NULL;
+
+ if (opt.nss_keylog != 0 && opt.eap_tls != 0) {
+ mbedtls_printf("Error: eap_tls and nss_keylog options cannot be used together.\n");
+ goto usage;
+ }
+
+ /* Event-driven IO is incompatible with the above custom
+ * receive and send functions, as the polling builds on
+ * refers to the underlying net_context. */
+ if (opt.event == 1 && opt.nbio != 1) {
+ mbedtls_printf("Warning: event-driven IO mandates nbio=1 - overwrite\n");
+ opt.nbio = 1;
+ }
+
+#if defined(MBEDTLS_DEBUG_C)
+ mbedtls_debug_set_threshold(opt.debug_level);
+#endif
+
+ /* buf will alternatively contain the input read from the client and the
+ * response that's about to be sent, plus a null byte in each case. */
+ size_t buf_content_size = opt.buffer_size;
+ /* The default response contains the ciphersuite name. Leave enough
+ * room for that plus some margin. */
+ if (buf_content_size < strlen(HTTP_RESPONSE) + 80) {
+ buf_content_size = strlen(HTTP_RESPONSE) + 80;
+ }
+ if (opt.response_size != DFL_RESPONSE_SIZE &&
+ buf_content_size < (size_t) opt.response_size) {
+ buf_content_size = opt.response_size;
+ }
+ buf = mbedtls_calloc(1, buf_content_size + 1);
+ if (buf == NULL) {
+ mbedtls_printf("Could not allocate %lu bytes\n",
+ (unsigned long) buf_content_size + 1);
+ ret = 3;
+ goto exit;
+ }
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ if (opt.psk_opaque != 0) {
+ if (strlen(opt.psk) == 0) {
+ mbedtls_printf("psk_opaque set but no psk to be imported specified.\n");
+ ret = 2;
+ goto usage;
+ }
+
+ if (opt.force_ciphersuite[0] <= 0) {
+ mbedtls_printf(
+ "opaque PSKs are only supported in conjunction with forcing TLS 1.2 and a PSK-only ciphersuite through the 'force_ciphersuite' option.\n");
+ ret = 2;
+ goto usage;
+ }
+ }
+
+ if (opt.psk_list_opaque != 0) {
+ if (opt.psk_list == NULL) {
+ mbedtls_printf("psk_slot set but no psk to be imported specified.\n");
+ ret = 2;
+ goto usage;
+ }
+
+ if (opt.force_ciphersuite[0] <= 0) {
+ mbedtls_printf(
+ "opaque PSKs are only supported in conjunction with forcing TLS 1.2 and a PSK-only ciphersuite through the 'force_ciphersuite' option.\n");
+ ret = 2;
+ goto usage;
+ }
+ }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ if (opt.force_ciphersuite[0] > 0) {
+ const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
+ ciphersuite_info =
+ mbedtls_ssl_ciphersuite_from_id(opt.force_ciphersuite[0]);
+
+ if (opt.max_version != -1 &&
+ ciphersuite_info->min_tls_version > opt.max_version) {
+ mbedtls_printf("forced ciphersuite not allowed with this protocol version\n");
+ ret = 2;
+ goto usage;
+ }
+ if (opt.min_version != -1 &&
+ ciphersuite_info->max_tls_version < opt.min_version) {
+ mbedtls_printf("forced ciphersuite not allowed with this protocol version\n");
+ ret = 2;
+ goto usage;
+ }
+
+ /* If we select a version that's not supported by
+ * this suite, then there will be no common ciphersuite... */
+ if (opt.max_version == -1 ||
+ opt.max_version > ciphersuite_info->max_tls_version) {
+ opt.max_version = ciphersuite_info->max_tls_version;
+ }
+ if (opt.min_version < ciphersuite_info->min_tls_version) {
+ opt.min_version = ciphersuite_info->min_tls_version;
+ }
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED)
+ if (opt.psk_opaque != 0 || opt.psk_list_opaque != 0) {
+ /* Determine KDF algorithm the opaque PSK will be used in. */
+#if defined(MBEDTLS_MD_CAN_SHA384)
+ if (ciphersuite_info->mac == MBEDTLS_MD_SHA384) {
+ alg = PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_384);
+ } else
+#endif /* MBEDTLS_MD_CAN_SHA384 */
+ alg = PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256);
+ }
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED */
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+ }
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+ if (mbedtls_test_unhexify(cid, sizeof(cid),
+ opt.cid_val, &cid_len) != 0) {
+ mbedtls_printf("CID not valid hex\n");
+ goto exit;
+ }
+
+ /* Keep CID settings for renegotiation unless
+ * specified otherwise. */
+ if (opt.cid_enabled_renego == DFL_CID_ENABLED_RENEGO) {
+ opt.cid_enabled_renego = opt.cid_enabled;
+ }
+ if (opt.cid_val_renego == DFL_CID_VALUE_RENEGO) {
+ opt.cid_val_renego = opt.cid_val;
+ }
+
+ if (mbedtls_test_unhexify(cid_renego, sizeof(cid_renego),
+ opt.cid_val_renego, &cid_renego_len) != 0) {
+ mbedtls_printf("CID not valid hex\n");
+ goto exit;
+ }
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED)
+ /*
+ * Unhexify the pre-shared key and parse the list if any given
+ */
+ if (mbedtls_test_unhexify(psk, sizeof(psk),
+ opt.psk, &psk_len) != 0) {
+ mbedtls_printf("pre-shared key not valid hex\n");
+ goto exit;
+ }
+
+ if (opt.psk_list != NULL) {
+ if ((psk_info = psk_parse(opt.psk_list)) == NULL) {
+ mbedtls_printf("psk_list invalid");
+ goto exit;
+ }
+ }
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED */
+
+ if (opt.groups != NULL) {
+ if (parse_groups(opt.groups, group_list, GROUP_LIST_SIZE) != 0) {
+ goto exit;
+ }
+ }
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ if (opt.sig_algs != NULL) {
+ p = (char *) opt.sig_algs;
+ i = 0;
+
+ /* Leave room for a final MBEDTLS_TLS1_3_SIG_NONE in signature algorithm list (sig_alg_list). */
+ while (i < SIG_ALG_LIST_SIZE - 1 && *p != '\0') {
+ q = p;
+
+ /* Terminate the current string */
+ while (*p != ',' && *p != '\0') {
+ p++;
+ }
+ if (*p == ',') {
+ *p++ = '\0';
+ }
+
+ if (strcmp(q, "rsa_pkcs1_sha256") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_RSA_PKCS1_SHA256;
+ } else if (strcmp(q, "rsa_pkcs1_sha384") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_RSA_PKCS1_SHA384;
+ } else if (strcmp(q, "rsa_pkcs1_sha512") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_RSA_PKCS1_SHA512;
+ } else if (strcmp(q, "ecdsa_secp256r1_sha256") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_ECDSA_SECP256R1_SHA256;
+ } else if (strcmp(q, "ecdsa_secp384r1_sha384") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_ECDSA_SECP384R1_SHA384;
+ } else if (strcmp(q, "ecdsa_secp521r1_sha512") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_ECDSA_SECP521R1_SHA512;
+ } else if (strcmp(q, "rsa_pss_rsae_sha256") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_RSA_PSS_RSAE_SHA256;
+ } else if (strcmp(q, "rsa_pss_rsae_sha384") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_RSA_PSS_RSAE_SHA384;
+ } else if (strcmp(q, "rsa_pss_rsae_sha512") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_RSA_PSS_RSAE_SHA512;
+ } else if (strcmp(q, "ed25519") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_ED25519;
+ } else if (strcmp(q, "ed448") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_ED448;
+ } else if (strcmp(q, "rsa_pss_pss_sha256") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_RSA_PSS_PSS_SHA256;
+ } else if (strcmp(q, "rsa_pss_pss_sha384") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_RSA_PSS_PSS_SHA384;
+ } else if (strcmp(q, "rsa_pss_pss_sha512") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_RSA_PSS_PSS_SHA512;
+ } else if (strcmp(q, "rsa_pkcs1_sha1") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_RSA_PKCS1_SHA1;
+ } else if (strcmp(q, "ecdsa_sha1") == 0) {
+ sig_alg_list[i++] = MBEDTLS_TLS1_3_SIG_ECDSA_SHA1;
+ } else {
+ ret = -1;
+ mbedtls_printf("unknown signature algorithm \"%s\"\n", q);
+ mbedtls_print_supported_sig_algs();
+ goto exit;
+ }
+ }
+
+ if (i == (SIG_ALG_LIST_SIZE - 1) && *p != '\0') {
+ mbedtls_printf("signature algorithm list too long, maximum %d",
+ SIG_ALG_LIST_SIZE - 1);
+ goto exit;
+ }
+
+ sig_alg_list[i] = MBEDTLS_TLS1_3_SIG_NONE;
+ }
+#endif
+
+#if defined(MBEDTLS_SSL_ALPN)
+ if (opt.alpn_string != NULL) {
+ p = (char *) opt.alpn_string;
+ i = 0;
+
+ /* Leave room for a final NULL in alpn_list */
+ while (i < ALPN_LIST_SIZE - 1 && *p != '\0') {
+ alpn_list[i++] = p;
+
+ /* Terminate the current string and move on to next one */
+ while (*p != ',' && *p != '\0') {
+ p++;
+ }
+ if (*p == ',') {
+ *p++ = '\0';
+ }
+ }
+ }
+#endif /* MBEDTLS_SSL_ALPN */
+
+ mbedtls_printf("build version: %s (build %d)\n",
+ MBEDTLS_VERSION_STRING_FULL, MBEDTLS_VERSION_NUMBER);
+
+ /*
+ * 0. Initialize the RNG and the session data
+ */
+ mbedtls_printf("\n . Seeding the random number generator...");
+ fflush(stdout);
+
+ ret = rng_seed(&rng, opt.reproducible, pers);
+ if (ret != 0) {
+ goto exit;
+ }
+ mbedtls_printf(" ok\n");
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ /*
+ * 1.1. Load the trusted CA
+ */
+ mbedtls_printf(" . Loading the CA root certificate ...");
+ fflush(stdout);
+
+ if (strcmp(opt.ca_path, "none") == 0 ||
+ strcmp(opt.ca_file, "none") == 0) {
+ ret = 0;
+ } else
+#if defined(MBEDTLS_FS_IO)
+ if (strlen(opt.ca_path)) {
+ ret = mbedtls_x509_crt_parse_path(&cacert, opt.ca_path);
+ } else if (strlen(opt.ca_file)) {
+ ret = mbedtls_x509_crt_parse_file(&cacert, opt.ca_file);
+ } else
+#endif
+ {
+#if defined(MBEDTLS_PEM_PARSE_C)
+ for (i = 0; mbedtls_test_cas[i] != NULL; i++) {
+ ret = mbedtls_x509_crt_parse(&cacert,
+ (const unsigned char *) mbedtls_test_cas[i],
+ mbedtls_test_cas_len[i]);
+ if (ret != 0) {
+ break;
+ }
+ }
+#endif /* MBEDTLS_PEM_PARSE_C */
+ if (ret == 0) {
+ for (i = 0; mbedtls_test_cas_der[i] != NULL; i++) {
+ ret = mbedtls_x509_crt_parse_der(&cacert,
+ (const unsigned char *) mbedtls_test_cas_der[i],
+ mbedtls_test_cas_der_len[i]);
+ if (ret != 0) {
+ break;
+ }
+ }
+ }
+ }
+ if (ret < 0) {
+ mbedtls_printf(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok (%d skipped)\n", ret);
+
+ /*
+ * 1.2. Load own certificate and private key
+ */
+ mbedtls_printf(" . Loading the server cert. and key...");
+ fflush(stdout);
+
+#if defined(MBEDTLS_FS_IO)
+ if (strlen(opt.crt_file) && strcmp(opt.crt_file, "none") != 0) {
+ key_cert_init++;
+ if ((ret = mbedtls_x509_crt_parse_file(&srvcert, opt.crt_file)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_x509_crt_parse_file returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ }
+ if (strlen(opt.key_file) && strcmp(opt.key_file, "none") != 0) {
+ key_cert_init++;
+ if ((ret = mbedtls_pk_parse_keyfile(&pkey, opt.key_file,
+ opt.key_pwd, rng_get, &rng)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_pk_parse_keyfile returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ }
+ if (key_cert_init == 1) {
+ mbedtls_printf(" failed\n ! crt_file without key_file or vice-versa\n\n");
+ goto exit;
+ }
+
+ if (strlen(opt.crt_file2) && strcmp(opt.crt_file2, "none") != 0) {
+ key_cert_init2++;
+ if ((ret = mbedtls_x509_crt_parse_file(&srvcert2, opt.crt_file2)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_x509_crt_parse_file(2) returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ }
+ if (strlen(opt.key_file2) && strcmp(opt.key_file2, "none") != 0) {
+ key_cert_init2++;
+ if ((ret = mbedtls_pk_parse_keyfile(&pkey2, opt.key_file2,
+ opt.key_pwd2, rng_get, &rng)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_pk_parse_keyfile(2) returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ }
+ if (key_cert_init2 == 1) {
+ mbedtls_printf(" failed\n ! crt_file2 without key_file2 or vice-versa\n\n");
+ goto exit;
+ }
+#endif
+ if (key_cert_init == 0 &&
+ strcmp(opt.crt_file, "none") != 0 &&
+ strcmp(opt.key_file, "none") != 0 &&
+ key_cert_init2 == 0 &&
+ strcmp(opt.crt_file2, "none") != 0 &&
+ strcmp(opt.key_file2, "none") != 0) {
+#if defined(MBEDTLS_RSA_C)
+ if ((ret = mbedtls_x509_crt_parse(&srvcert,
+ (const unsigned char *) mbedtls_test_srv_crt_rsa,
+ mbedtls_test_srv_crt_rsa_len)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ if ((ret = mbedtls_pk_parse_key(&pkey,
+ (const unsigned char *) mbedtls_test_srv_key_rsa,
+ mbedtls_test_srv_key_rsa_len, NULL, 0,
+ rng_get, &rng)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_pk_parse_key returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ key_cert_init = 2;
+#endif /* MBEDTLS_RSA_C */
+#if defined(MBEDTLS_PK_CAN_ECDSA_SOME)
+ if ((ret = mbedtls_x509_crt_parse(&srvcert2,
+ (const unsigned char *) mbedtls_test_srv_crt_ec,
+ mbedtls_test_srv_crt_ec_len)) != 0) {
+ mbedtls_printf(" failed\n ! x509_crt_parse2 returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ if ((ret = mbedtls_pk_parse_key(&pkey2,
+ (const unsigned char *) mbedtls_test_srv_key_ec,
+ mbedtls_test_srv_key_ec_len, NULL, 0,
+ rng_get, &rng)) != 0) {
+ mbedtls_printf(" failed\n ! pk_parse_key2 returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ key_cert_init2 = 2;
+#endif /* MBEDTLS_PK_CAN_ECDSA_SOME */
+ }
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ if (opt.key_opaque != 0) {
+ psa_algorithm_t psa_alg, psa_alg2 = PSA_ALG_NONE;
+ psa_key_usage_t psa_usage = 0;
+
+ if (key_opaque_set_alg_usage(opt.key1_opaque_alg1,
+ opt.key1_opaque_alg2,
+ &psa_alg, &psa_alg2,
+ &psa_usage,
+ mbedtls_pk_get_type(&pkey)) == 0) {
+ ret = pk_wrap_as_opaque(&pkey, psa_alg, psa_alg2, psa_usage, &key_slot);
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! "
+ "pk_wrap_as_opaque returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ }
+
+ psa_alg = PSA_ALG_NONE; psa_alg2 = PSA_ALG_NONE;
+ psa_usage = 0;
+
+ if (key_opaque_set_alg_usage(opt.key2_opaque_alg1,
+ opt.key2_opaque_alg2,
+ &psa_alg, &psa_alg2,
+ &psa_usage,
+ mbedtls_pk_get_type(&pkey2)) == 0) {
+ ret = pk_wrap_as_opaque(&pkey2, psa_alg, psa_alg2, psa_usage, &key_slot2);
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! "
+ "mbedtls_pk_get_psa_attributes returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ }
+ }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ mbedtls_printf(" ok (key types: %s, %s)\n",
+ key_cert_init ? mbedtls_pk_get_name(&pkey) : "none",
+ key_cert_init2 ? mbedtls_pk_get_name(&pkey2) : "none");
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+
+#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_FS_IO)
+ if (opt.dhm_file != NULL) {
+ mbedtls_printf(" . Loading DHM parameters...");
+ fflush(stdout);
+
+ if ((ret = mbedtls_dhm_parse_dhmfile(&dhm, opt.dhm_file)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_dhm_parse_dhmfile returned -0x%04X\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+ }
+#endif
+
+#if defined(SNI_OPTION)
+ if (opt.sni != NULL) {
+ mbedtls_printf(" . Setting up SNI information...");
+ fflush(stdout);
+
+ if ((sni_info = sni_parse(opt.sni)) == NULL) {
+ mbedtls_printf(" failed\n");
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+ }
+#endif /* SNI_OPTION */
+
+ /*
+ * 2. Setup stuff
+ */
+ mbedtls_printf(" . Setting up the SSL/TLS structure...");
+ fflush(stdout);
+
+ if ((ret = mbedtls_ssl_config_defaults(&conf,
+ MBEDTLS_SSL_IS_SERVER,
+ opt.transport,
+ MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_config_defaults returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ /* The default algorithms profile disables SHA-1, but our tests still
+ rely on it heavily. Hence we allow it here. A real-world server
+ should use the default profile unless there is a good reason not to. */
+ if (opt.allow_sha1 > 0) {
+ crt_profile_for_test.allowed_mds |= MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1);
+ mbedtls_ssl_conf_cert_profile(&conf, &crt_profile_for_test);
+ mbedtls_ssl_conf_sig_algs(&conf, ssl_sig_algs_for_test);
+ }
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+
+ if (opt.auth_mode != DFL_AUTH_MODE) {
+ mbedtls_ssl_conf_authmode(&conf, opt.auth_mode);
+ }
+
+ if (opt.cert_req_ca_list != DFL_CERT_REQ_CA_LIST) {
+ mbedtls_ssl_conf_cert_req_ca_list(&conf, opt.cert_req_ca_list);
+ }
+
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+ if (opt.early_data != DFL_EARLY_DATA) {
+ mbedtls_ssl_conf_early_data(&conf, opt.early_data);
+ }
+ if (opt.max_early_data_size != DFL_MAX_EARLY_DATA_SIZE) {
+ mbedtls_ssl_conf_max_early_data_size(
+ &conf, opt.max_early_data_size);
+ }
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
+#if defined(MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED)
+ /* exercise setting DN hints for server certificate request
+ * (Intended for use where the client cert expected has been signed by
+ * a specific CA which is an intermediate in a CA chain, not the root) */
+ if (opt.cert_req_dn_hint == 2 && key_cert_init2) {
+ mbedtls_ssl_conf_dn_hints(&conf, &srvcert2);
+ }
+#endif
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if (opt.hs_to_min != DFL_HS_TO_MIN || opt.hs_to_max != DFL_HS_TO_MAX) {
+ mbedtls_ssl_conf_handshake_timeout(&conf, opt.hs_to_min, opt.hs_to_max);
+ }
+
+ if (opt.dgram_packing != DFL_DGRAM_PACKING) {
+ mbedtls_ssl_set_datagram_packing(&ssl, opt.dgram_packing);
+ }
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
+#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+ if ((ret = mbedtls_ssl_conf_max_frag_len(&conf, opt.mfl_code)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_conf_max_frag_len returned %d\n\n", ret);
+ goto exit;
+ }
+#endif
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+ if (opt.cid_enabled == 1 || opt.cid_enabled_renego == 1) {
+ if (opt.cid_enabled == 1 &&
+ opt.cid_enabled_renego == 1 &&
+ cid_len != cid_renego_len) {
+ mbedtls_printf("CID length must not change during renegotiation\n");
+ goto usage;
+ }
+
+ if (opt.cid_enabled == 1) {
+ ret = mbedtls_ssl_conf_cid(&conf, cid_len,
+ MBEDTLS_SSL_UNEXPECTED_CID_IGNORE);
+ } else {
+ ret = mbedtls_ssl_conf_cid(&conf, cid_renego_len,
+ MBEDTLS_SSL_UNEXPECTED_CID_IGNORE);
+ }
+
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_conf_cid_len returned -%#04x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ }
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+
+#if defined(MBEDTLS_SSL_DTLS_SRTP)
+ const mbedtls_ssl_srtp_profile forced_profile[] =
+ { opt.force_srtp_profile, MBEDTLS_TLS_SRTP_UNSET };
+ if (opt.use_srtp == 1) {
+ if (opt.force_srtp_profile != 0) {
+ ret = mbedtls_ssl_conf_dtls_srtp_protection_profiles(&conf, forced_profile);
+ } else {
+ ret = mbedtls_ssl_conf_dtls_srtp_protection_profiles(&conf, default_profiles);
+ }
+
+ if (ret != 0) {
+ mbedtls_printf(
+ " failed\n ! mbedtls_ssl_conf_dtls_srtp_protection_profiles returned %d\n\n",
+ ret);
+ goto exit;
+ }
+
+ mbedtls_ssl_conf_srtp_mki_value_supported(&conf,
+ opt.support_mki ?
+ MBEDTLS_SSL_DTLS_SRTP_MKI_SUPPORTED :
+ MBEDTLS_SSL_DTLS_SRTP_MKI_UNSUPPORTED);
+
+ } else if (opt.force_srtp_profile != 0) {
+ mbedtls_printf(" failed\n ! must enable use_srtp to force srtp profile\n\n");
+ goto exit;
+ }
+#endif /* MBEDTLS_SSL_DTLS_SRTP */
+
+#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
+ if (opt.extended_ms != DFL_EXTENDED_MS) {
+ mbedtls_ssl_conf_extended_master_secret(&conf, opt.extended_ms);
+ }
+#endif
+
+#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+ if (opt.etm != DFL_ETM) {
+ mbedtls_ssl_conf_encrypt_then_mac(&conf, opt.etm);
+ }
+#endif
+
+#if defined(MBEDTLS_SSL_ALPN)
+ if (opt.alpn_string != NULL) {
+ if ((ret = mbedtls_ssl_conf_alpn_protocols(&conf, alpn_list)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_conf_alpn_protocols returned %d\n\n", ret);
+ goto exit;
+ }
+ }
+#endif
+
+ if (opt.reproducible) {
+#if defined(MBEDTLS_HAVE_TIME)
+#if defined(MBEDTLS_PLATFORM_TIME_ALT)
+ mbedtls_platform_set_time(dummy_constant_time);
+#else
+ fprintf(stderr, "Warning: reproducible option used without constant time\n");
+#endif
+#endif /* MBEDTLS_HAVE_TIME */
+ }
+ mbedtls_ssl_conf_rng(&conf, rng_get, &rng);
+ mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+ if (opt.cache_max != -1) {
+ mbedtls_ssl_cache_set_max_entries(&cache, opt.cache_max);
+ }
+
+#if defined(MBEDTLS_HAVE_TIME)
+ if (opt.cache_timeout != -1) {
+ mbedtls_ssl_cache_set_timeout(&cache, opt.cache_timeout);
+ }
+#endif
+
+ mbedtls_ssl_conf_session_cache(&conf, &cache,
+ mbedtls_ssl_cache_get,
+ mbedtls_ssl_cache_set);
+#endif
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
+ if (opt.tickets != MBEDTLS_SSL_SESSION_TICKETS_DISABLED) {
+#if defined(MBEDTLS_HAVE_TIME)
+ if (opt.dummy_ticket) {
+ mbedtls_ssl_conf_session_tickets_cb(&conf,
+ dummy_ticket_write,
+ dummy_ticket_parse,
+ NULL);
+ } else
+#endif /* MBEDTLS_HAVE_TIME */
+ {
+ if ((ret = mbedtls_ssl_ticket_setup(&ticket_ctx,
+ rng_get, &rng,
+ opt.ticket_aead,
+ opt.ticket_timeout)) != 0) {
+ mbedtls_printf(
+ " failed\n ! mbedtls_ssl_ticket_setup returned %d\n\n",
+ ret);
+ goto exit;
+ }
+
+ mbedtls_ssl_conf_session_tickets_cb(&conf,
+ mbedtls_ssl_ticket_write,
+ mbedtls_ssl_ticket_parse,
+ &ticket_ctx);
+ }
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ mbedtls_ssl_conf_new_session_tickets(&conf, opt.tickets);
+#endif
+ /* exercise manual ticket rotation (not required for typical use)
+ * (used for external synchronization of session ticket encryption keys)
+ */
+ if (opt.ticket_rotate) {
+ unsigned char kbuf[MBEDTLS_SSL_TICKET_MAX_KEY_BYTES];
+ unsigned char name[MBEDTLS_SSL_TICKET_KEY_NAME_BYTES];
+ if ((ret = rng_get(&rng, name, sizeof(name))) != 0 ||
+ (ret = rng_get(&rng, kbuf, sizeof(kbuf))) != 0 ||
+ (ret = mbedtls_ssl_ticket_rotate(&ticket_ctx,
+ name, sizeof(name), kbuf, sizeof(kbuf),
+ opt.ticket_timeout)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_ticket_rotate returned %d\n\n", ret);
+ goto exit;
+ }
+ }
+ }
+#endif
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if (opt.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
+#if defined(MBEDTLS_SSL_COOKIE_C)
+ if (opt.cookies > 0) {
+ if ((ret = mbedtls_ssl_cookie_setup(&cookie_ctx,
+ rng_get, &rng)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_cookie_setup returned %d\n\n", ret);
+ goto exit;
+ }
+
+ mbedtls_ssl_conf_dtls_cookies(&conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check,
+ &cookie_ctx);
+ } else
+#endif /* MBEDTLS_SSL_COOKIE_C */
+#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY)
+ if (opt.cookies == 0) {
+ mbedtls_ssl_conf_dtls_cookies(&conf, NULL, NULL, NULL);
+ } else
+#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */
+ {
+ ; /* Nothing to do */
+ }
+
+#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
+ if (opt.anti_replay != DFL_ANTI_REPLAY) {
+ mbedtls_ssl_conf_dtls_anti_replay(&conf, opt.anti_replay);
+ }
+#endif
+
+ if (opt.badmac_limit != DFL_BADMAC_LIMIT) {
+ mbedtls_ssl_conf_dtls_badmac_limit(&conf, opt.badmac_limit);
+ }
+ }
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
+ if (opt.force_ciphersuite[0] != DFL_FORCE_CIPHER) {
+ mbedtls_ssl_conf_ciphersuites(&conf, opt.force_ciphersuite);
+ }
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ mbedtls_ssl_conf_tls13_key_exchange_modes(&conf, opt.tls13_kex_modes);
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
+
+ if (opt.allow_legacy != DFL_ALLOW_LEGACY) {
+ mbedtls_ssl_conf_legacy_renegotiation(&conf, opt.allow_legacy);
+ }
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+ mbedtls_ssl_conf_renegotiation(&conf, opt.renegotiation);
+
+ if (opt.renego_delay != DFL_RENEGO_DELAY) {
+ mbedtls_ssl_conf_renegotiation_enforced(&conf, opt.renego_delay);
+ }
+
+ if (opt.renego_period != DFL_RENEGO_PERIOD) {
+ PUT_UINT64_BE(renego_period, opt.renego_period, 0);
+ mbedtls_ssl_conf_renegotiation_period(&conf, renego_period);
+ }
+#endif
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ if (strcmp(opt.ca_path, "none") != 0 &&
+ strcmp(opt.ca_file, "none") != 0) {
+#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
+ if (opt.ca_callback != 0) {
+ mbedtls_ssl_conf_ca_cb(&conf, ca_callback, &cacert);
+ } else
+#endif
+ mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
+ }
+ if (key_cert_init) {
+ mbedtls_pk_context *pk = &pkey;
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+ if (opt.async_private_delay1 >= 0) {
+ ret = ssl_async_set_key(&ssl_async_keys, &srvcert, pk, 0,
+ opt.async_private_delay1);
+ if (ret < 0) {
+ mbedtls_printf(" Test error: ssl_async_set_key failed (%d)\n",
+ ret);
+ goto exit;
+ }
+ pk = NULL;
+ }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+ if ((ret = mbedtls_ssl_conf_own_cert(&conf, &srvcert, pk)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret);
+ goto exit;
+ }
+ }
+ if (key_cert_init2) {
+ mbedtls_pk_context *pk = &pkey2;
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+ if (opt.async_private_delay2 >= 0) {
+ ret = ssl_async_set_key(&ssl_async_keys, &srvcert2, pk, 0,
+ opt.async_private_delay2);
+ if (ret < 0) {
+ mbedtls_printf(" Test error: ssl_async_set_key failed (%d)\n",
+ ret);
+ goto exit;
+ }
+ pk = NULL;
+ }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+ if ((ret = mbedtls_ssl_conf_own_cert(&conf, &srvcert2, pk)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret);
+ goto exit;
+ }
+ }
+
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+ if (opt.async_operations[0] != '-') {
+ mbedtls_ssl_async_sign_t *sign = NULL;
+ mbedtls_ssl_async_decrypt_t *decrypt = NULL;
+ const char *r;
+ for (r = opt.async_operations; *r; r++) {
+ switch (*r) {
+ case 'd':
+ decrypt = ssl_async_decrypt;
+ break;
+ case 's':
+ sign = ssl_async_sign;
+ break;
+ }
+ }
+ ssl_async_keys.inject_error = (opt.async_private_error < 0 ?
+ -opt.async_private_error :
+ opt.async_private_error);
+ ssl_async_keys.f_rng = rng_get;
+ ssl_async_keys.p_rng = &rng;
+ mbedtls_ssl_conf_async_private_cb(&conf,
+ sign,
+ decrypt,
+ ssl_async_resume,
+ ssl_async_cancel,
+ &ssl_async_keys);
+ }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+
+#if defined(SNI_OPTION)
+ if (opt.sni != NULL) {
+ mbedtls_ssl_conf_sni(&conf, sni_callback, sni_info);
+ mbedtls_ssl_conf_cert_cb(&conf, cert_callback);
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+ if (opt.async_private_delay2 >= 0) {
+ sni_entry *cur;
+ for (cur = sni_info; cur != NULL; cur = cur->next) {
+ ret = ssl_async_set_key(&ssl_async_keys,
+ cur->cert, cur->key, 1,
+ opt.async_private_delay2);
+ if (ret < 0) {
+ mbedtls_printf(" Test error: ssl_async_set_key failed (%d)\n",
+ ret);
+ goto exit;
+ }
+ cur->key = NULL;
+ }
+ }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+ }
+#endif
+
+#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) || \
+ (defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_EPHEMERAL_ENABLED) && \
+ defined(PSA_WANT_ALG_FFDH))
+ if (opt.groups != NULL &&
+ strcmp(opt.groups, "default") != 0) {
+ mbedtls_ssl_conf_groups(&conf, group_list);
+ }
+#endif
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ if (opt.sig_algs != NULL) {
+ mbedtls_ssl_conf_sig_algs(&conf, sig_alg_list);
+ }
+#endif
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED)
+
+ if (strlen(opt.psk) != 0 && strlen(opt.psk_identity) != 0) {
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ if (opt.psk_opaque != 0) {
+ /* The algorithm has already been determined earlier. */
+ status = psa_setup_psk_key_slot(&psk_slot, alg, psk, psk_len);
+ if (status != PSA_SUCCESS) {
+ fprintf(stderr, "SETUP FAIL\n");
+ ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
+ goto exit;
+ }
+ if ((ret = mbedtls_ssl_conf_psk_opaque(&conf, psk_slot,
+ (const unsigned char *) opt.psk_identity,
+ strlen(opt.psk_identity))) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_conf_psk_opaque returned %d\n\n",
+ ret);
+ goto exit;
+ }
+ } else
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+ if (psk_len > 0) {
+ ret = mbedtls_ssl_conf_psk(&conf, psk, psk_len,
+ (const unsigned char *) opt.psk_identity,
+ strlen(opt.psk_identity));
+ if (ret != 0) {
+ mbedtls_printf(" failed\n mbedtls_ssl_conf_psk returned -0x%04X\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ }
+ }
+
+ if (opt.psk_list != NULL) {
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ if (opt.psk_list_opaque != 0) {
+ psk_entry *cur_psk;
+ for (cur_psk = psk_info; cur_psk != NULL; cur_psk = cur_psk->next) {
+
+ status = psa_setup_psk_key_slot(&cur_psk->slot, alg,
+ cur_psk->key,
+ cur_psk->key_len);
+ if (status != PSA_SUCCESS) {
+ ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
+ goto exit;
+ }
+ }
+ }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+ mbedtls_ssl_conf_psk_cb(&conf, psk_callback, psk_info);
+ }
+#endif
+
+#if defined(MBEDTLS_DHM_C)
+ /*
+ * Use different group than default DHM group
+ */
+#if defined(MBEDTLS_FS_IO)
+ if (opt.dhm_file != NULL) {
+ ret = mbedtls_ssl_conf_dh_param_ctx(&conf, &dhm);
+ }
+#endif
+ if (ret != 0) {
+ mbedtls_printf(" failed\n mbedtls_ssl_conf_dh_param returned -0x%04X\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+#endif
+
+ if (opt.min_version != DFL_MIN_VERSION) {
+ mbedtls_ssl_conf_min_tls_version(&conf, opt.min_version);
+ }
+
+ if (opt.max_version != DFL_MIN_VERSION) {
+ mbedtls_ssl_conf_max_tls_version(&conf, opt.max_version);
+ }
+
+ if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_setup returned -0x%x\n\n", (unsigned int) -ret);
+ goto exit;
+ }
+
+ if (opt.eap_tls != 0) {
+ mbedtls_ssl_set_export_keys_cb(&ssl, eap_tls_key_derivation,
+ &eap_tls_keying);
+ } else if (opt.nss_keylog != 0) {
+ mbedtls_ssl_set_export_keys_cb(&ssl,
+ nss_keylog_export,
+ NULL);
+ }
+#if defined(MBEDTLS_SSL_DTLS_SRTP)
+ else if (opt.use_srtp != 0) {
+ mbedtls_ssl_set_export_keys_cb(&ssl, dtls_srtp_key_derivation,
+ &dtls_srtp_keying);
+ }
+#endif /* MBEDTLS_SSL_DTLS_SRTP */
+
+ io_ctx.ssl = &ssl;
+ io_ctx.net = &client_fd;
+ mbedtls_ssl_set_bio(&ssl, &io_ctx, send_cb, recv_cb,
+ opt.nbio == 0 ? recv_timeout_cb : NULL);
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+ if (opt.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
+ if ((ret = mbedtls_ssl_set_cid(&ssl, opt.cid_enabled,
+ cid, cid_len)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_set_cid returned %d\n\n",
+ ret);
+ goto exit;
+ }
+ }
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if (opt.dtls_mtu != DFL_DTLS_MTU) {
+ mbedtls_ssl_set_mtu(&ssl, opt.dtls_mtu);
+ }
+#endif
+
+#if defined(MBEDTLS_TIMING_C)
+ mbedtls_ssl_set_timer_cb(&ssl, &timer, mbedtls_timing_set_delay,
+ mbedtls_timing_get_delay);
+#endif
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 3. Setup the listening TCP socket
+ */
+ mbedtls_printf(" . Bind on %s://%s:%s/ ...",
+ opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM ? "tcp" : "udp",
+ opt.server_addr ? opt.server_addr : "*",
+ opt.server_port);
+ fflush(stdout);
+
+ if ((ret = mbedtls_net_bind(&listen_fd, opt.server_addr, opt.server_port,
+ opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM ?
+ MBEDTLS_NET_PROTO_TCP : MBEDTLS_NET_PROTO_UDP)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_net_bind returned -0x%x\n\n", (unsigned int) -ret);
+ goto exit;
+ }
+ mbedtls_printf(" ok\n");
+
+reset:
+#if !defined(_WIN32)
+ if (received_sigterm) {
+ mbedtls_printf(" interrupted by SIGTERM (not in net_accept())\n");
+ if (ret == MBEDTLS_ERR_NET_INVALID_CONTEXT) {
+ ret = 0;
+ }
+
+ goto exit;
+ }
+#endif
+
+ if (ret == MBEDTLS_ERR_SSL_CLIENT_RECONNECT) {
+ mbedtls_printf(" ! Client initiated reconnection from same port\n");
+ goto handshake;
+ }
+
+#ifdef MBEDTLS_ERROR_C
+ if (ret != 0) {
+ char error_buf[100];
+ mbedtls_strerror(ret, error_buf, 100);
+ mbedtls_printf("Last error was: %d - %s\n\n", ret, error_buf);
+ }
+#endif
+
+ mbedtls_net_free(&client_fd);
+
+ mbedtls_ssl_session_reset(&ssl);
+
+ /*
+ * 3. Wait until a client connects
+ */
+ mbedtls_printf(" . Waiting for a remote connection ...");
+ fflush(stdout);
+
+ if ((ret = mbedtls_net_accept(&listen_fd, &client_fd,
+ client_ip, sizeof(client_ip), &cliip_len)) != 0) {
+#if !defined(_WIN32)
+ if (received_sigterm) {
+ mbedtls_printf(" interrupted by SIGTERM (in net_accept())\n");
+ if (ret == MBEDTLS_ERR_NET_ACCEPT_FAILED) {
+ ret = 0;
+ }
+
+ goto exit;
+ }
+#endif
+
+ mbedtls_printf(" failed\n ! mbedtls_net_accept returned -0x%x\n\n", (unsigned int) -ret);
+ goto exit;
+ }
+
+ if (opt.nbio > 0) {
+ ret = mbedtls_net_set_nonblock(&client_fd);
+ } else {
+ ret = mbedtls_net_set_block(&client_fd);
+ }
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! net_set_(non)block() returned -0x%x\n\n", (unsigned int) -ret);
+ goto exit;
+ }
+
+ mbedtls_ssl_conf_read_timeout(&conf, opt.read_timeout);
+
+#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY)
+ if (opt.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
+ if ((ret = mbedtls_ssl_set_client_transport_id(&ssl,
+ client_ip, cliip_len)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_set_client_transport_id() returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+ }
+#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+ if (opt.ecjpake_pw != DFL_ECJPAKE_PW) {
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ if (opt.ecjpake_pw_opaque != DFL_ECJPAKE_PW_OPAQUE) {
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+ psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
+ psa_set_key_algorithm(&attributes, PSA_ALG_JPAKE);
+ psa_set_key_type(&attributes, PSA_KEY_TYPE_PASSWORD);
+
+ status = psa_import_key(&attributes,
+ (const unsigned char *) opt.ecjpake_pw,
+ strlen(opt.ecjpake_pw),
+ &ecjpake_pw_slot);
+ if (status != PSA_SUCCESS) {
+ mbedtls_printf(" failed\n ! psa_import_key returned %d\n\n",
+ status);
+ goto exit;
+ }
+ if ((ret = mbedtls_ssl_set_hs_ecjpake_password_opaque(&ssl,
+ ecjpake_pw_slot)) != 0) {
+ mbedtls_printf(
+ " failed\n ! mbedtls_ssl_set_hs_ecjpake_password_opaque returned %d\n\n",
+ ret);
+ goto exit;
+ }
+ mbedtls_printf("using opaque password\n");
+ } else
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+ {
+ if ((ret = mbedtls_ssl_set_hs_ecjpake_password(&ssl,
+ (const unsigned char *) opt.ecjpake_pw,
+ strlen(opt.ecjpake_pw))) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_set_hs_ecjpake_password returned %d\n\n",
+ ret);
+ goto exit;
+ }
+ }
+ }
+#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
+
+#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
+#if defined(MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED)
+ /* exercise setting DN hints for server certificate request
+ * (Intended for use where the client cert expected has been signed by
+ * a specific CA which is an intermediate in a CA chain, not the root)
+ * (Additionally, the CA choice would typically be influenced by SNI
+ * if being set per-handshake using mbedtls_ssl_set_hs_dn_hints()) */
+ if (opt.cert_req_dn_hint == 3 && key_cert_init2) {
+ mbedtls_ssl_set_hs_dn_hints(&ssl, &srvcert2);
+ }
+#endif
+#endif
+
+ mbedtls_printf(" ok\n");
+
+ /*
+ * 4. Handshake
+ */
+handshake:
+ mbedtls_printf(" . Performing the SSL/TLS handshake...");
+ fflush(stdout);
+
+ while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+ if (ret == MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA) {
+ memset(buf, 0, opt.buffer_size);
+ ret = mbedtls_ssl_read_early_data(&ssl, buf, opt.buffer_size);
+ if (ret > 0) {
+ buf[ret] = '\0';
+ mbedtls_printf(" %d early data bytes read\n\n%s\n",
+ ret, (char *) buf);
+ }
+ continue;
+ }
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+ if (ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS &&
+ ssl_async_keys.inject_error == SSL_ASYNC_INJECT_ERROR_CANCEL) {
+ mbedtls_printf(" cancelling on injected error\n");
+ break;
+ }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+
+ if (!mbedtls_status_is_ssl_in_progress(ret)) {
+ break;
+ }
+
+ /* For event-driven IO, wait for socket to become available */
+ if (opt.event == 1 /* level triggered IO */) {
+#if defined(MBEDTLS_TIMING_C)
+ ret = idle(&client_fd, &timer, ret);
+#else
+ ret = idle(&client_fd, ret);
+#endif
+ if (ret != 0) {
+ goto reset;
+ }
+ }
+ }
+
+ if (ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED) {
+ mbedtls_printf(" hello verification requested\n");
+ ret = 0;
+ goto reset;
+ } else if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n",
+ (unsigned int) -ret);
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
+ char vrfy_buf[512];
+ flags = mbedtls_ssl_get_verify_result(&ssl);
+
+ x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags);
+
+ mbedtls_printf("%s\n", vrfy_buf);
+ }
+#endif
+
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+ if (opt.async_private_error < 0) {
+ /* Injected error only the first time round, to test reset */
+ ssl_async_keys.inject_error = SSL_ASYNC_INJECT_ERROR_NONE;
+ }
+#endif
+ goto reset;
+ } else { /* ret == 0 */
+ int suite_id = mbedtls_ssl_get_ciphersuite_id_from_ssl(&ssl);
+ const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
+ ciphersuite_info = mbedtls_ssl_ciphersuite_from_id(suite_id);
+
+ mbedtls_printf(" ok\n [ Protocol is %s ]\n"
+ " [ Ciphersuite is %s ]\n"
+ " [ Key size is %u ]\n",
+ mbedtls_ssl_get_version(&ssl),
+ mbedtls_ssl_ciphersuite_get_name(ciphersuite_info),
+ (unsigned int)
+ mbedtls_ssl_ciphersuite_get_cipher_key_bitlen(ciphersuite_info));
+ }
+
+ if ((ret = mbedtls_ssl_get_record_expansion(&ssl)) >= 0) {
+ mbedtls_printf(" [ Record expansion is %d ]\n", ret);
+ } else {
+ mbedtls_printf(" [ Record expansion is unknown ]\n");
+ }
+
+#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) || defined(MBEDTLS_SSL_RECORD_SIZE_LIMIT)
+ mbedtls_printf(" [ Maximum incoming record payload length is %u ]\n",
+ (unsigned int) mbedtls_ssl_get_max_in_record_payload(&ssl));
+ mbedtls_printf(" [ Maximum outgoing record payload length is %u ]\n",
+ (unsigned int) mbedtls_ssl_get_max_out_record_payload(&ssl));
+#endif
+
+#if defined(MBEDTLS_SSL_ALPN)
+ if (opt.alpn_string != NULL) {
+ const char *alp = mbedtls_ssl_get_alpn_protocol(&ssl);
+ mbedtls_printf(" [ Application Layer Protocol is %s ]\n",
+ alp ? alp : "(none)");
+ }
+#endif
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ /*
+ * 5. Verify the client certificate
+ */
+ mbedtls_printf(" . Verifying peer X.509 certificate...");
+
+ if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) {
+ char vrfy_buf[512];
+
+ mbedtls_printf(" failed\n");
+
+ x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags);
+ mbedtls_printf("%s\n", vrfy_buf);
+ } else {
+ mbedtls_printf(" ok\n");
+ }
+
+#if !defined(MBEDTLS_X509_REMOVE_INFO)
+ if (mbedtls_ssl_get_peer_cert(&ssl) != NULL) {
+ char crt_buf[512];
+
+ mbedtls_printf(" . Peer certificate information ...\n");
+ mbedtls_x509_crt_info(crt_buf, sizeof(crt_buf), " ",
+ mbedtls_ssl_get_peer_cert(&ssl));
+ mbedtls_printf("%s\n", crt_buf);
+ }
+#endif /* MBEDTLS_X509_REMOVE_INFO */
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+
+ if (opt.eap_tls != 0) {
+ size_t j = 0;
+
+ if ((ret = mbedtls_ssl_tls_prf(eap_tls_keying.tls_prf_type,
+ eap_tls_keying.master_secret,
+ sizeof(eap_tls_keying.master_secret),
+ eap_tls_label,
+ eap_tls_keying.randbytes,
+ sizeof(eap_tls_keying.randbytes),
+ eap_tls_keymaterial,
+ sizeof(eap_tls_keymaterial)))
+ != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_tls_prf returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto reset;
+ }
+
+ mbedtls_printf(" EAP-TLS key material is:");
+ for (j = 0; j < sizeof(eap_tls_keymaterial); j++) {
+ if (j % 8 == 0) {
+ mbedtls_printf("\n ");
+ }
+ mbedtls_printf("%02x ", eap_tls_keymaterial[j]);
+ }
+ mbedtls_printf("\n");
+
+ if ((ret = mbedtls_ssl_tls_prf(eap_tls_keying.tls_prf_type, NULL, 0,
+ eap_tls_label,
+ eap_tls_keying.randbytes,
+ sizeof(eap_tls_keying.randbytes),
+ eap_tls_iv,
+ sizeof(eap_tls_iv))) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_tls_prf returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto reset;
+ }
+
+ mbedtls_printf(" EAP-TLS IV is:");
+ for (j = 0; j < sizeof(eap_tls_iv); j++) {
+ if (j % 8 == 0) {
+ mbedtls_printf("\n ");
+ }
+ mbedtls_printf("%02x ", eap_tls_iv[j]);
+ }
+ mbedtls_printf("\n");
+ }
+
+#if defined(MBEDTLS_SSL_DTLS_SRTP)
+ else if (opt.use_srtp != 0) {
+ size_t j = 0;
+ mbedtls_dtls_srtp_info dtls_srtp_negotiation_result;
+ mbedtls_ssl_get_dtls_srtp_negotiation_result(&ssl, &dtls_srtp_negotiation_result);
+
+ if (dtls_srtp_negotiation_result.chosen_dtls_srtp_profile
+ == MBEDTLS_TLS_SRTP_UNSET) {
+ mbedtls_printf(" Unable to negotiate "
+ "the use of DTLS-SRTP\n");
+ } else {
+ if ((ret = mbedtls_ssl_tls_prf(dtls_srtp_keying.tls_prf_type,
+ dtls_srtp_keying.master_secret,
+ sizeof(dtls_srtp_keying.master_secret),
+ dtls_srtp_label,
+ dtls_srtp_keying.randbytes,
+ sizeof(dtls_srtp_keying.randbytes),
+ dtls_srtp_key_material,
+ sizeof(dtls_srtp_key_material)))
+ != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_tls_prf returned -0x%x\n\n",
+ (unsigned int) -ret);
+ goto exit;
+ }
+
+ mbedtls_printf(" DTLS-SRTP key material is:");
+ for (j = 0; j < sizeof(dtls_srtp_key_material); j++) {
+ if (j % 8 == 0) {
+ mbedtls_printf("\n ");
+ }
+ mbedtls_printf("%02x ", dtls_srtp_key_material[j]);
+ }
+ mbedtls_printf("\n");
+
+ /* produce a less readable output used to perform automatic checks
+ * - compare client and server output
+ * - interop test with openssl which client produces this kind of output
+ */
+ mbedtls_printf(" Keying material: ");
+ for (j = 0; j < sizeof(dtls_srtp_key_material); j++) {
+ mbedtls_printf("%02X", dtls_srtp_key_material[j]);
+ }
+ mbedtls_printf("\n");
+
+ if (dtls_srtp_negotiation_result.mki_len > 0) {
+ mbedtls_printf(" DTLS-SRTP mki value: ");
+ for (j = 0; j < dtls_srtp_negotiation_result.mki_len; j++) {
+ mbedtls_printf("%02X", dtls_srtp_negotiation_result.mki_value[j]);
+ }
+ } else {
+ mbedtls_printf(" DTLS-SRTP no mki value negotiated");
+ }
+ mbedtls_printf("\n");
+
+ }
+ }
+#endif /* MBEDTLS_SSL_DTLS_SRTP */
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+ ret = report_cid_usage(&ssl, "initial handshake");
+ if (ret != 0) {
+ goto exit;
+ }
+
+ if (opt.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
+ if ((ret = mbedtls_ssl_set_cid(&ssl, opt.cid_enabled_renego,
+ cid_renego, cid_renego_len)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_set_cid returned %d\n\n",
+ ret);
+ goto exit;
+ }
+ }
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+
+#if defined(MBEDTLS_MEMORY_DEBUG)
+ mbedtls_memory_buffer_alloc_cur_get(&current_heap_memory, &heap_blocks);
+ mbedtls_memory_buffer_alloc_max_get(&peak_heap_memory, &heap_blocks);
+ mbedtls_printf("Heap memory usage after handshake: %lu bytes. Peak memory usage was %lu\n",
+ (unsigned long) current_heap_memory, (unsigned long) peak_heap_memory);
+#endif /* MBEDTLS_MEMORY_DEBUG */
+
+ if (opt.exchanges == 0) {
+ goto close_notify;
+ }
+
+ exchanges_left = opt.exchanges;
+data_exchange:
+ /*
+ * 6. Read the HTTP Request
+ */
+ mbedtls_printf(" < Read from client:");
+ fflush(stdout);
+
+ /*
+ * TLS and DTLS need different reading styles (stream vs datagram)
+ */
+ if (opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM) {
+ do {
+ int terminated = 0;
+ len = opt.buffer_size;
+ memset(buf, 0, opt.buffer_size);
+ ret = mbedtls_ssl_read(&ssl, buf, len);
+
+ if (mbedtls_status_is_ssl_in_progress(ret)) {
+ if (opt.event == 1 /* level triggered IO */) {
+#if defined(MBEDTLS_TIMING_C)
+ idle(&client_fd, &timer, ret);
+#else
+ idle(&client_fd, ret);
+#endif
+ }
+
+ continue;
+ }
+
+ if (ret <= 0) {
+ switch (ret) {
+ case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+ mbedtls_printf(" connection was closed gracefully\n");
+ goto close_notify;
+
+ case 0:
+ case MBEDTLS_ERR_NET_CONN_RESET:
+ mbedtls_printf(" connection was reset by peer\n");
+ ret = MBEDTLS_ERR_NET_CONN_RESET;
+ goto reset;
+
+ default:
+ mbedtls_printf(" mbedtls_ssl_read returned -0x%x\n", (unsigned int) -ret);
+ goto reset;
+ }
+ }
+
+ if (mbedtls_ssl_get_bytes_avail(&ssl) == 0) {
+ len = ret;
+ buf[len] = '\0';
+ mbedtls_printf(" %d bytes read\n\n%s\n", len, (char *) buf);
+
+ /* End of message should be detected according to the syntax of the
+ * application protocol (eg HTTP), just use a dummy test here. */
+ if (buf[len - 1] == '\n') {
+ terminated = 1;
+ }
+ } else {
+ int extra_len, ori_len;
+ unsigned char *larger_buf;
+
+ ori_len = ret;
+ extra_len = (int) mbedtls_ssl_get_bytes_avail(&ssl);
+
+ larger_buf = mbedtls_calloc(1, ori_len + extra_len + 1);
+ if (larger_buf == NULL) {
+ mbedtls_printf(" ! memory allocation failed\n");
+ ret = 1;
+ goto reset;
+ }
+
+ memset(larger_buf, 0, ori_len + extra_len);
+ memcpy(larger_buf, buf, ori_len);
+
+ /* This read should never fail and get the whole cached data */
+ ret = mbedtls_ssl_read(&ssl, larger_buf + ori_len, extra_len);
+ if (ret != extra_len ||
+ mbedtls_ssl_get_bytes_avail(&ssl) != 0) {
+ mbedtls_printf(" ! mbedtls_ssl_read failed on cached data\n");
+ ret = 1;
+ goto reset;
+ }
+
+ larger_buf[ori_len + extra_len] = '\0';
+ mbedtls_printf(" %d bytes read (%d + %d)\n\n%s\n",
+ ori_len + extra_len, ori_len, extra_len,
+ (char *) larger_buf);
+
+ /* End of message should be detected according to the syntax of the
+ * application protocol (eg HTTP), just use a dummy test here. */
+ if (larger_buf[ori_len + extra_len - 1] == '\n') {
+ terminated = 1;
+ }
+
+ mbedtls_free(larger_buf);
+ }
+
+ if (terminated) {
+ ret = 0;
+ break;
+ }
+ } while (1);
+ } else { /* Not stream, so datagram */
+ len = opt.buffer_size;
+ memset(buf, 0, opt.buffer_size);
+
+ do {
+ /* Without the call to `mbedtls_ssl_check_pending`, it might
+ * happen that the client sends application data in the same
+ * datagram as the Finished message concluding the handshake.
+ * In this case, the application data would be ready to be
+ * processed while the underlying transport wouldn't signal
+ * any further incoming data.
+ *
+ * See the test 'Event-driven I/O: session-id resume, UDP packing'
+ * in tests/ssl-opt.sh.
+ */
+
+ /* For event-driven IO, wait for socket to become available */
+ if (mbedtls_ssl_check_pending(&ssl) == 0 &&
+ opt.event == 1 /* level triggered IO */) {
+#if defined(MBEDTLS_TIMING_C)
+ idle(&client_fd, &timer, MBEDTLS_ERR_SSL_WANT_READ);
+#else
+ idle(&client_fd, MBEDTLS_ERR_SSL_WANT_READ);
+#endif
+ }
+
+ ret = mbedtls_ssl_read(&ssl, buf, len);
+
+ /* Note that even if `mbedtls_ssl_check_pending` returns true,
+ * it can happen that the subsequent call to `mbedtls_ssl_read`
+ * returns `MBEDTLS_ERR_SSL_WANT_READ`, because the pending messages
+ * might be discarded (e.g. because they are retransmissions). */
+ } while (mbedtls_status_is_ssl_in_progress(ret));
+
+ if (ret <= 0) {
+ switch (ret) {
+ case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+ mbedtls_printf(" connection was closed gracefully\n");
+ goto close_notify;
+
+ default:
+ mbedtls_printf(" mbedtls_ssl_read returned -0x%x\n", (unsigned int) -ret);
+ goto reset;
+ }
+ }
+
+ len = ret;
+ buf[len] = '\0';
+ mbedtls_printf(" %d bytes read\n\n%s", len, (char *) buf);
+ ret = 0;
+ }
+
+ /*
+ * 7a. Request renegotiation while client is waiting for input from us.
+ * (only on the first exchange, to be able to test retransmission)
+ */
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+ if (opt.renegotiate && exchanges_left == opt.exchanges) {
+ mbedtls_printf(" . Requestion renegotiation...");
+ fflush(stdout);
+
+ while ((ret = mbedtls_ssl_renegotiate(&ssl)) != 0) {
+ if (!mbedtls_status_is_ssl_in_progress(ret)) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_renegotiate returned %d\n\n", ret);
+ goto reset;
+ }
+
+ /* For event-driven IO, wait for socket to become available */
+ if (opt.event == 1 /* level triggered IO */) {
+#if defined(MBEDTLS_TIMING_C)
+ idle(&client_fd, &timer, ret);
+#else
+ idle(&client_fd, ret);
+#endif
+ }
+ }
+
+ mbedtls_printf(" ok\n");
+ }
+#endif /* MBEDTLS_SSL_RENEGOTIATION */
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+ ret = report_cid_usage(&ssl, "after renegotiation");
+ if (ret != 0) {
+ goto exit;
+ }
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+
+ /*
+ * 7. Write the 200 Response
+ */
+ mbedtls_printf(" > Write to client:");
+ fflush(stdout);
+
+ /* If the format of the response changes, make sure there is enough
+ * room in buf (buf_content_size calculation above). */
+ len = sprintf((char *) buf, HTTP_RESPONSE,
+ mbedtls_ssl_get_ciphersuite(&ssl));
+
+ /* Add padding to the response to reach opt.response_size in length */
+ if (opt.response_size != DFL_RESPONSE_SIZE &&
+ len < opt.response_size) {
+ memset(buf + len, 'B', opt.response_size - len);
+ len += opt.response_size - len;
+ }
+
+ /* Truncate if response size is smaller than the "natural" size */
+ if (opt.response_size != DFL_RESPONSE_SIZE &&
+ len > opt.response_size) {
+ len = opt.response_size;
+
+ /* Still end with \r\n unless that's really not possible */
+ if (len >= 2) {
+ buf[len - 2] = '\r';
+ }
+ if (len >= 1) {
+ buf[len - 1] = '\n';
+ }
+ }
+
+ if (opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM) {
+ for (written = 0, frags = 0; written < len; written += ret, frags++) {
+ while ((ret = mbedtls_ssl_write(&ssl, buf + written, len - written))
+ <= 0) {
+ if (ret == MBEDTLS_ERR_NET_CONN_RESET) {
+ mbedtls_printf(" failed\n ! peer closed the connection\n\n");
+ goto reset;
+ }
+
+ if (!mbedtls_status_is_ssl_in_progress(ret)) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_write returned %d\n\n", ret);
+ goto reset;
+ }
+
+ /* For event-driven IO, wait for socket to become available */
+ if (opt.event == 1 /* level triggered IO */) {
+#if defined(MBEDTLS_TIMING_C)
+ idle(&client_fd, &timer, ret);
+#else
+ idle(&client_fd, ret);
+#endif
+ }
+ }
+ }
+ } else { /* Not stream, so datagram */
+ while (1) {
+ ret = mbedtls_ssl_write(&ssl, buf, len);
+
+ if (!mbedtls_status_is_ssl_in_progress(ret)) {
+ break;
+ }
+
+ /* For event-driven IO, wait for socket to become available */
+ if (opt.event == 1 /* level triggered IO */) {
+#if defined(MBEDTLS_TIMING_C)
+ idle(&client_fd, &timer, ret);
+#else
+ idle(&client_fd, ret);
+#endif
+ }
+ }
+
+ if (ret < 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_write returned %d\n\n", ret);
+ goto reset;
+ }
+
+ frags = 1;
+ written = ret;
+ }
+
+ buf[written] = '\0';
+ mbedtls_printf(" %d bytes written in %d fragments\n\n%s\n", written, frags, (char *) buf);
+ ret = 0;
+
+ /*
+ * 7b. Simulate serialize/deserialize and go back to data exchange
+ */
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+ if (opt.serialize != 0) {
+ size_t buf_len;
+
+ mbedtls_printf(" . Serializing live connection...");
+
+ ret = mbedtls_ssl_context_save(&ssl, NULL, 0, &buf_len);
+ if (ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_context_save returned "
+ "-0x%x\n\n", (unsigned int) -ret);
+
+ goto exit;
+ }
+
+ if ((context_buf = mbedtls_calloc(1, buf_len)) == NULL) {
+ mbedtls_printf(" failed\n ! Couldn't allocate buffer for "
+ "serialized context");
+
+ goto exit;
+ }
+ context_buf_len = buf_len;
+
+ if ((ret = mbedtls_ssl_context_save(&ssl, context_buf,
+ buf_len, &buf_len)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_context_save returned "
+ "-0x%x\n\n", (unsigned int) -ret);
+
+ goto exit;
+ }
+
+ mbedtls_printf(" ok\n");
+
+ /* Save serialized context to the 'opt.context_file' as a base64 code */
+ if (0 < strlen(opt.context_file)) {
+ FILE *b64_file;
+ uint8_t *b64_buf;
+ size_t b64_len;
+
+ mbedtls_printf(" . Save serialized context to a file... ");
+
+ mbedtls_base64_encode(NULL, 0, &b64_len, context_buf, buf_len);
+
+ if ((b64_buf = mbedtls_calloc(1, b64_len)) == NULL) {
+ mbedtls_printf("failed\n ! Couldn't allocate buffer for "
+ "the base64 code\n");
+ goto exit;
+ }
+
+ if ((ret = mbedtls_base64_encode(b64_buf, b64_len, &b64_len,
+ context_buf, buf_len)) != 0) {
+ mbedtls_printf("failed\n ! mbedtls_base64_encode returned "
+ "-0x%x\n", (unsigned int) -ret);
+ mbedtls_free(b64_buf);
+ goto exit;
+ }
+
+ if ((b64_file = fopen(opt.context_file, "w")) == NULL) {
+ mbedtls_printf("failed\n ! Cannot open '%s' for writing.\n",
+ opt.context_file);
+ mbedtls_free(b64_buf);
+ goto exit;
+ }
+
+ if (b64_len != fwrite(b64_buf, 1, b64_len, b64_file)) {
+ mbedtls_printf("failed\n ! fwrite(%ld bytes) failed\n",
+ (long) b64_len);
+ mbedtls_free(b64_buf);
+ fclose(b64_file);
+ goto exit;
+ }
+
+ mbedtls_free(b64_buf);
+ fclose(b64_file);
+
+ mbedtls_printf("ok\n");
+ }
+
+ /*
+ * This simulates a workflow where you have a long-lived server
+ * instance, potentially with a pool of ssl_context objects, and you
+ * just want to re-use one while the connection is inactive: in that
+ * case you can just reset() it, and then it's ready to receive
+ * serialized data from another connection (or the same here).
+ */
+ if (opt.serialize == 1) {
+ /* nothing to do here, done by context_save() already */
+ mbedtls_printf(" . Context has been reset... ok\n");
+ }
+
+ /*
+ * This simulates a workflow where you have one server instance per
+ * connection, and want to release it entire when the connection is
+ * inactive, and spawn it again when needed again - this would happen
+ * between ssl_free() and ssl_init() below, together with any other
+ * teardown/startup code needed - for example, preparing the
+ * ssl_config again (see section 3 "setup stuff" in this file).
+ */
+ if (opt.serialize == 2) {
+ mbedtls_printf(" . Freeing and reinitializing context...");
+
+ mbedtls_ssl_free(&ssl);
+
+ mbedtls_ssl_init(&ssl);
+
+ if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ssl_setup returned "
+ "-0x%x\n\n", (unsigned int) -ret);
+ goto exit;
+ }
+
+ /*
+ * This illustrates the minimum amount of things you need to set
+ * up, however you could set up much more if desired, for example
+ * if you want to share your set up code between the case of
+ * establishing a new connection and this case.
+ */
+ if (opt.nbio == 2) {
+ mbedtls_ssl_set_bio(&ssl, &client_fd, delayed_send,
+ delayed_recv, NULL);
+ } else {
+ mbedtls_ssl_set_bio(&ssl, &client_fd, mbedtls_net_send,
+ mbedtls_net_recv,
+ opt.nbio == 0 ? mbedtls_net_recv_timeout : NULL);
+ }
+
+#if defined(MBEDTLS_TIMING_C)
+ mbedtls_ssl_set_timer_cb(&ssl, &timer,
+ mbedtls_timing_set_delay,
+ mbedtls_timing_get_delay);
+#endif /* MBEDTLS_TIMING_C */
+
+ mbedtls_printf(" ok\n");
+ }
+
+ mbedtls_printf(" . Deserializing connection...");
+
+ if ((ret = mbedtls_ssl_context_load(&ssl, context_buf,
+ buf_len)) != 0) {
+ mbedtls_printf("failed\n ! mbedtls_ssl_context_load returned "
+ "-0x%x\n\n", (unsigned int) -ret);
+
+ goto exit;
+ }
+
+ mbedtls_free(context_buf);
+ context_buf = NULL;
+ context_buf_len = 0;
+
+ mbedtls_printf(" ok\n");
+ }
+#endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
+
+ /*
+ * 7c. Continue doing data exchanges?
+ */
+ if (--exchanges_left > 0) {
+ goto data_exchange;
+ }
+
+ /*
+ * 8. Done, cleanly close the connection
+ */
+close_notify:
+ mbedtls_printf(" . Closing the connection...");
+
+ /* No error checking, the connection might be closed already */
+ do {
+ ret = mbedtls_ssl_close_notify(&ssl);
+ } while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);
+ ret = 0;
+
+ mbedtls_printf(" done\n");
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+ if (opt.cache_remove > 0) {
+ mbedtls_ssl_cache_remove(&cache, ssl.session->id, ssl.session->id_len);
+ }
+#endif
+
+ goto reset;
+
+ /*
+ * Cleanup and exit
+ */
+exit:
+#ifdef MBEDTLS_ERROR_C
+ if (ret != 0) {
+ char error_buf[100];
+ mbedtls_strerror(ret, error_buf, 100);
+ mbedtls_printf("Last error was: -0x%X - %s\n\n", (unsigned int) -ret, error_buf);
+ }
+#endif
+
+ if (opt.query_config_mode == DFL_QUERY_CONFIG_MODE) {
+ mbedtls_printf(" . Cleaning up...");
+ fflush(stdout);
+ }
+
+ mbedtls_net_free(&client_fd);
+ mbedtls_net_free(&listen_fd);
+
+ mbedtls_ssl_free(&ssl);
+ mbedtls_ssl_config_free(&conf);
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+ mbedtls_ssl_cache_free(&cache);
+#endif
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
+ mbedtls_ssl_ticket_free(&ticket_ctx);
+#endif
+#if defined(MBEDTLS_SSL_COOKIE_C)
+ mbedtls_ssl_cookie_free(&cookie_ctx);
+#endif
+
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+ if (context_buf != NULL) {
+ mbedtls_platform_zeroize(context_buf, context_buf_len);
+ }
+ mbedtls_free(context_buf);
+#endif
+
+#if defined(SNI_OPTION)
+ sni_free(sni_info);
+#endif
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED)
+ ret = psk_free(psk_info);
+ if ((ret != 0) && (opt.query_config_mode == DFL_QUERY_CONFIG_MODE)) {
+ mbedtls_printf("Failed to list of opaque PSKs - error was %d\n", ret);
+ }
+#endif
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+ mbedtls_x509_crt_free(&cacert);
+ mbedtls_x509_crt_free(&srvcert);
+ mbedtls_pk_free(&pkey);
+ mbedtls_x509_crt_free(&srvcert2);
+ mbedtls_pk_free(&pkey2);
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ psa_destroy_key(key_slot);
+ psa_destroy_key(key_slot2);
+#endif
+#endif
+
+#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_FS_IO)
+ mbedtls_dhm_free(&dhm);
+#endif
+
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+ for (i = 0; (size_t) i < ssl_async_keys.slots_used; i++) {
+ if (ssl_async_keys.slots[i].pk_owned) {
+ mbedtls_pk_free(ssl_async_keys.slots[i].pk);
+ mbedtls_free(ssl_async_keys.slots[i].pk);
+ ssl_async_keys.slots[i].pk = NULL;
+ }
+ }
+#endif
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED) && \
+ defined(MBEDTLS_USE_PSA_CRYPTO)
+ if (opt.psk_opaque != 0) {
+ /* This is ok even if the slot hasn't been
+ * initialized (we might have jumed here
+ * immediately because of bad cmd line params,
+ * for example). */
+ status = psa_destroy_key(psk_slot);
+ if ((status != PSA_SUCCESS) &&
+ (opt.query_config_mode == DFL_QUERY_CONFIG_MODE)) {
+ mbedtls_printf("Failed to destroy key slot %u - error was %d",
+ (unsigned) MBEDTLS_SVC_KEY_ID_GET_KEY_ID(psk_slot),
+ (int) status);
+ }
+ }
+#endif /* MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED &&
+ MBEDTLS_USE_PSA_CRYPTO */
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) && \
+ defined(MBEDTLS_USE_PSA_CRYPTO)
+ /*
+ * In case opaque keys it's the user responsibility to keep the key valid
+ * for the duration of the handshake and destroy it at the end
+ */
+ if ((opt.ecjpake_pw_opaque != DFL_ECJPAKE_PW_OPAQUE)) {
+ psa_key_attributes_t check_attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+ /* Verify that the key is still valid before destroying it */
+ if (psa_get_key_attributes(ecjpake_pw_slot, &check_attributes) !=
+ PSA_SUCCESS) {
+ if (ret == 0) {
+ ret = 1;
+ }
+ mbedtls_printf("The EC J-PAKE password key has unexpectedly been already destroyed\n");
+ } else {
+ psa_destroy_key(ecjpake_pw_slot);
+ }
+ }
+#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED && MBEDTLS_USE_PSA_CRYPTO */
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)
+ const char *message = mbedtls_test_helper_is_psa_leaking();
+ if (message) {
+ if (ret == 0) {
+ ret = 1;
+ }
+ mbedtls_printf("PSA memory leak detected: %s\n", message);
+ }
+#endif
+
+ /* For builds with MBEDTLS_TEST_USE_PSA_CRYPTO_RNG psa crypto
+ * resources are freed by rng_free(). */
+#if (defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)) \
+ && !defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+ mbedtls_psa_crypto_free();
+#endif
+
+ rng_free(&rng);
+
+ mbedtls_free(buf);
+
+#if defined(MBEDTLS_TEST_HOOKS)
+ /* Let test hooks detect errors such as resource leaks.
+ * Don't do it in query_config mode, because some test code prints
+ * information to stdout and this gets mixed with the regular output. */
+ if (opt.query_config_mode == DFL_QUERY_CONFIG_MODE) {
+ if (test_hooks_failure_detected()) {
+ if (ret == 0) {
+ ret = 1;
+ }
+ mbedtls_printf("Test hooks detected errors.\n");
+ }
+ }
+ test_hooks_free();
+#endif /* MBEDTLS_TEST_HOOKS */
+
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+#if defined(MBEDTLS_MEMORY_DEBUG)
+ mbedtls_memory_buffer_alloc_status();
+#endif
+ mbedtls_memory_buffer_alloc_free();
+#endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */
+
+ if (opt.query_config_mode == DFL_QUERY_CONFIG_MODE) {
+ mbedtls_printf(" done.\n");
+ }
+
+ // Shell can not handle large exit numbers -> 1 for errors
+ if (ret < 0) {
+ ret = 1;
+ }
+
+ if (opt.query_config_mode == DFL_QUERY_CONFIG_MODE) {
+ mbedtls_exit(ret);
+ } else {
+ mbedtls_exit(query_config_ret);
+ }
+}
+#endif /* !MBEDTLS_SSL_TEST_IMPOSSIBLE && MBEDTLS_SSL_SRV_C */
diff --git a/programs/ssl/ssl_test_common_source.c b/programs/ssl/ssl_test_common_source.c
new file mode 100644
index 00000000000..1ff2077d4a5
--- /dev/null
+++ b/programs/ssl/ssl_test_common_source.c
@@ -0,0 +1,375 @@
+/*
+ * Common source code for SSL test programs. This file is included by
+ * both ssl_client2.c and ssl_server2.c and is intended for source
+ * code that is textually identical in both programs, but that cannot be
+ * compiled separately because it refers to types or macros that are
+ * different in the two programs, or because it would have an incomplete
+ * type.
+ *
+ * This file is meant to be #include'd and cannot be compiled separately.
+ *
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+void eap_tls_key_derivation(void *p_expkey,
+ mbedtls_ssl_key_export_type secret_type,
+ const unsigned char *secret,
+ size_t secret_len,
+ const unsigned char client_random[32],
+ const unsigned char server_random[32],
+ mbedtls_tls_prf_types tls_prf_type)
+{
+ eap_tls_keys *keys = (eap_tls_keys *) p_expkey;
+
+ /* We're only interested in the TLS 1.2 master secret */
+ if (secret_type != MBEDTLS_SSL_KEY_EXPORT_TLS12_MASTER_SECRET) {
+ return;
+ }
+ if (secret_len != sizeof(keys->master_secret)) {
+ return;
+ }
+
+ memcpy(keys->master_secret, secret, sizeof(keys->master_secret));
+ memcpy(keys->randbytes, client_random, 32);
+ memcpy(keys->randbytes + 32, server_random, 32);
+ keys->tls_prf_type = tls_prf_type;
+}
+
+void nss_keylog_export(void *p_expkey,
+ mbedtls_ssl_key_export_type secret_type,
+ const unsigned char *secret,
+ size_t secret_len,
+ const unsigned char client_random[32],
+ const unsigned char server_random[32],
+ mbedtls_tls_prf_types tls_prf_type)
+{
+ char nss_keylog_line[200];
+ size_t const client_random_len = 32;
+ size_t len = 0;
+ size_t j;
+
+ /* We're only interested in the TLS 1.2 master secret */
+ if (secret_type != MBEDTLS_SSL_KEY_EXPORT_TLS12_MASTER_SECRET) {
+ return;
+ }
+
+ ((void) p_expkey);
+ ((void) server_random);
+ ((void) tls_prf_type);
+
+ len += sprintf(nss_keylog_line + len,
+ "%s", "CLIENT_RANDOM ");
+
+ for (j = 0; j < client_random_len; j++) {
+ len += sprintf(nss_keylog_line + len,
+ "%02x", client_random[j]);
+ }
+
+ len += sprintf(nss_keylog_line + len, " ");
+
+ for (j = 0; j < secret_len; j++) {
+ len += sprintf(nss_keylog_line + len,
+ "%02x", secret[j]);
+ }
+
+ len += sprintf(nss_keylog_line + len, "\n");
+ nss_keylog_line[len] = '\0';
+
+ mbedtls_printf("\n");
+ mbedtls_printf("---------------- NSS KEYLOG -----------------\n");
+ mbedtls_printf("%s", nss_keylog_line);
+ mbedtls_printf("---------------------------------------------\n");
+
+ if (opt.nss_keylog_file != NULL) {
+ FILE *f;
+
+ if ((f = fopen(opt.nss_keylog_file, "a")) == NULL) {
+ goto exit;
+ }
+
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be
+ * wiped. */
+ mbedtls_setbuf(f, NULL);
+
+ if (fwrite(nss_keylog_line, 1, len, f) != len) {
+ fclose(f);
+ goto exit;
+ }
+
+ fclose(f);
+ }
+
+exit:
+ mbedtls_platform_zeroize(nss_keylog_line,
+ sizeof(nss_keylog_line));
+}
+
+#if defined(MBEDTLS_SSL_DTLS_SRTP)
+void dtls_srtp_key_derivation(void *p_expkey,
+ mbedtls_ssl_key_export_type secret_type,
+ const unsigned char *secret,
+ size_t secret_len,
+ const unsigned char client_random[32],
+ const unsigned char server_random[32],
+ mbedtls_tls_prf_types tls_prf_type)
+{
+ dtls_srtp_keys *keys = (dtls_srtp_keys *) p_expkey;
+
+ /* We're only interested in the TLS 1.2 master secret */
+ if (secret_type != MBEDTLS_SSL_KEY_EXPORT_TLS12_MASTER_SECRET) {
+ return;
+ }
+ if (secret_len != sizeof(keys->master_secret)) {
+ return;
+ }
+
+ memcpy(keys->master_secret, secret, sizeof(keys->master_secret));
+ memcpy(keys->randbytes, client_random, 32);
+ memcpy(keys->randbytes + 32, server_random, 32);
+ keys->tls_prf_type = tls_prf_type;
+}
+#endif /* MBEDTLS_SSL_DTLS_SRTP */
+
+int ssl_check_record(mbedtls_ssl_context const *ssl,
+ unsigned char const *buf, size_t len)
+{
+ int my_ret = 0, ret_cr1, ret_cr2;
+ unsigned char *tmp_buf;
+
+ /* Record checking may modify the input buffer,
+ * so make a copy. */
+ tmp_buf = mbedtls_calloc(1, len);
+ if (tmp_buf == NULL) {
+ return MBEDTLS_ERR_SSL_ALLOC_FAILED;
+ }
+ memcpy(tmp_buf, buf, len);
+
+ ret_cr1 = mbedtls_ssl_check_record(ssl, tmp_buf, len);
+ if (ret_cr1 != MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE) {
+ /* Test-only: Make sure that mbedtls_ssl_check_record()
+ * doesn't alter state. */
+ memcpy(tmp_buf, buf, len); /* Restore buffer */
+ ret_cr2 = mbedtls_ssl_check_record(ssl, tmp_buf, len);
+ if (ret_cr2 != ret_cr1) {
+ mbedtls_printf("mbedtls_ssl_check_record() returned inconsistent results.\n");
+ my_ret = -1;
+ goto cleanup;
+ }
+
+ switch (ret_cr1) {
+ case 0:
+ break;
+
+ case MBEDTLS_ERR_SSL_INVALID_RECORD:
+ if (opt.debug_level > 1) {
+ mbedtls_printf("mbedtls_ssl_check_record() detected invalid record.\n");
+ }
+ break;
+
+ case MBEDTLS_ERR_SSL_INVALID_MAC:
+ if (opt.debug_level > 1) {
+ mbedtls_printf("mbedtls_ssl_check_record() detected unauthentic record.\n");
+ }
+ break;
+
+ case MBEDTLS_ERR_SSL_UNEXPECTED_RECORD:
+ if (opt.debug_level > 1) {
+ mbedtls_printf("mbedtls_ssl_check_record() detected unexpected record.\n");
+ }
+ break;
+
+ default:
+ mbedtls_printf("mbedtls_ssl_check_record() failed fatally with -%#04x.\n",
+ (unsigned int) -ret_cr1);
+ my_ret = -1;
+ goto cleanup;
+ }
+
+ /* Regardless of the outcome, forward the record to the stack. */
+ }
+
+cleanup:
+ mbedtls_free(tmp_buf);
+
+ return my_ret;
+}
+
+int recv_cb(void *ctx, unsigned char *buf, size_t len)
+{
+ io_ctx_t *io_ctx = (io_ctx_t *) ctx;
+ size_t recv_len;
+ int ret;
+
+ if (opt.nbio == 2) {
+ ret = delayed_recv(io_ctx->net, buf, len);
+ } else {
+ ret = mbedtls_net_recv(io_ctx->net, buf, len);
+ }
+ if (ret < 0) {
+ return ret;
+ }
+ recv_len = (size_t) ret;
+
+ if (opt.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
+ /* Here's the place to do any datagram/record checking
+ * in between receiving the packet from the underlying
+ * transport and passing it on to the TLS stack. */
+ if (ssl_check_record(io_ctx->ssl, buf, recv_len) != 0) {
+ return -1;
+ }
+ }
+
+ return (int) recv_len;
+}
+
+int recv_timeout_cb(void *ctx, unsigned char *buf, size_t len,
+ uint32_t timeout)
+{
+ io_ctx_t *io_ctx = (io_ctx_t *) ctx;
+ int ret;
+ size_t recv_len;
+
+ ret = mbedtls_net_recv_timeout(io_ctx->net, buf, len, timeout);
+ if (ret < 0) {
+ return ret;
+ }
+ recv_len = (size_t) ret;
+
+ if (opt.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
+ /* Here's the place to do any datagram/record checking
+ * in between receiving the packet from the underlying
+ * transport and passing it on to the TLS stack. */
+ if (ssl_check_record(io_ctx->ssl, buf, recv_len) != 0) {
+ return -1;
+ }
+ }
+
+ return (int) recv_len;
+}
+
+int send_cb(void *ctx, unsigned char const *buf, size_t len)
+{
+ io_ctx_t *io_ctx = (io_ctx_t *) ctx;
+
+ if (opt.nbio == 2) {
+ return delayed_send(io_ctx->net, buf, len);
+ }
+
+ return mbedtls_net_send(io_ctx->net, buf, len);
+}
+
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_PK_CAN_ECDSA_SOME) && defined(MBEDTLS_RSA_C)
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+/*
+ * When GnuTLS/Openssl server is configured in TLS 1.2 mode with a certificate
+ * declaring an RSA public key and Mbed TLS is configured in hybrid mode, if
+ * `rsa_pss_rsae_*` algorithms are before `rsa_pkcs1_*` ones in this list then
+ * the GnuTLS/Openssl server chooses an `rsa_pss_rsae_*` signature algorithm
+ * for its signature in the key exchange message. As Mbed TLS 1.2 does not
+ * support them, the handshake fails.
+ */
+#define MBEDTLS_SSL_SIG_ALG(hash) ((hash << 8) | MBEDTLS_SSL_SIG_ECDSA), \
+ ((hash << 8) | MBEDTLS_SSL_SIG_RSA), \
+ (0x800 | hash),
+#else
+#define MBEDTLS_SSL_SIG_ALG(hash) ((hash << 8) | MBEDTLS_SSL_SIG_ECDSA), \
+ ((hash << 8) | MBEDTLS_SSL_SIG_RSA),
+#endif
+#elif defined(MBEDTLS_PK_CAN_ECDSA_SOME)
+#define MBEDTLS_SSL_SIG_ALG(hash) ((hash << 8) | MBEDTLS_SSL_SIG_ECDSA),
+#elif defined(MBEDTLS_RSA_C)
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+/* See above */
+#define MBEDTLS_SSL_SIG_ALG(hash) ((hash << 8) | MBEDTLS_SSL_SIG_RSA), \
+ (0x800 | hash),
+#else
+#define MBEDTLS_SSL_SIG_ALG(hash) ((hash << 8) | MBEDTLS_SSL_SIG_RSA),
+#endif
+#else
+#define MBEDTLS_SSL_SIG_ALG(hash)
+#endif
+
+uint16_t ssl_sig_algs_for_test[] = {
+#if defined(MBEDTLS_MD_CAN_SHA512)
+ MBEDTLS_SSL_SIG_ALG(MBEDTLS_SSL_HASH_SHA512)
+#endif
+#if defined(MBEDTLS_MD_CAN_SHA384)
+ MBEDTLS_SSL_SIG_ALG(MBEDTLS_SSL_HASH_SHA384)
+#endif
+#if defined(MBEDTLS_MD_CAN_SHA256)
+ MBEDTLS_SSL_SIG_ALG(MBEDTLS_SSL_HASH_SHA256)
+#endif
+#if defined(MBEDTLS_MD_CAN_SHA224)
+ MBEDTLS_SSL_SIG_ALG(MBEDTLS_SSL_HASH_SHA224)
+#endif
+#if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_MD_CAN_SHA256)
+ MBEDTLS_TLS1_3_SIG_RSA_PSS_RSAE_SHA256,
+#endif /* MBEDTLS_RSA_C && MBEDTLS_MD_CAN_SHA256 */
+#if defined(MBEDTLS_MD_CAN_SHA1)
+ /* Allow SHA-1 as we use it extensively in tests. */
+ MBEDTLS_SSL_SIG_ALG(MBEDTLS_SSL_HASH_SHA1)
+#endif
+ MBEDTLS_TLS1_3_SIG_NONE
+};
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+/** Functionally equivalent to mbedtls_x509_crt_verify_info, see that function
+ * for more info.
+ */
+int x509_crt_verify_info(char *buf, size_t size, const char *prefix,
+ uint32_t flags)
+{
+#if !defined(MBEDTLS_X509_REMOVE_INFO)
+ return mbedtls_x509_crt_verify_info(buf, size, prefix, flags);
+
+#else /* !MBEDTLS_X509_REMOVE_INFO */
+ int ret;
+ char *p = buf;
+ size_t n = size;
+
+#define X509_CRT_ERROR_INFO(err, err_str, info) \
+ if ((flags & err) != 0) \
+ { \
+ ret = mbedtls_snprintf(p, n, "%s%s\n", prefix, info); \
+ MBEDTLS_X509_SAFE_SNPRINTF; \
+ flags ^= err; \
+ }
+
+ MBEDTLS_X509_CRT_ERROR_INFO_LIST
+#undef X509_CRT_ERROR_INFO
+
+ if (flags != 0) {
+ ret = mbedtls_snprintf(p, n, "%sUnknown reason "
+ "(this should not happen)\n", prefix);
+ MBEDTLS_X509_SAFE_SNPRINTF;
+ }
+
+ return (int) (size - n);
+#endif /* MBEDTLS_X509_REMOVE_INFO */
+}
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
+void mbedtls_print_supported_sig_algs(void)
+{
+ mbedtls_printf("supported signature algorithms:\n");
+ mbedtls_printf("\trsa_pkcs1_sha256 ");
+ mbedtls_printf("rsa_pkcs1_sha384 ");
+ mbedtls_printf("rsa_pkcs1_sha512\n");
+ mbedtls_printf("\tecdsa_secp256r1_sha256 ");
+ mbedtls_printf("ecdsa_secp384r1_sha384 ");
+ mbedtls_printf("ecdsa_secp521r1_sha512\n");
+ mbedtls_printf("\trsa_pss_rsae_sha256 ");
+ mbedtls_printf("rsa_pss_rsae_sha384 ");
+ mbedtls_printf("rsa_pss_rsae_sha512\n");
+ mbedtls_printf("\trsa_pss_pss_sha256 ");
+ mbedtls_printf("rsa_pss_pss_sha384 ");
+ mbedtls_printf("rsa_pss_pss_sha512\n");
+ mbedtls_printf("\ted25519 ");
+ mbedtls_printf("ed448 ");
+ mbedtls_printf("rsa_pkcs1_sha1 ");
+ mbedtls_printf("ecdsa_sha1\n");
+ mbedtls_printf("\n");
+}
diff --git a/programs/ssl/ssl_test_lib.c b/programs/ssl/ssl_test_lib.c
new file mode 100644
index 00000000000..17d36b7de67
--- /dev/null
+++ b/programs/ssl/ssl_test_lib.c
@@ -0,0 +1,648 @@
+/*
+ * Common code library for SSL test programs.
+ *
+ * In addition to the functions in this file, there is shared source code
+ * that cannot be compiled separately in "ssl_test_common_source.c".
+ *
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+
+#include "ssl_test_lib.h"
+
+#if defined(MBEDTLS_TEST_HOOKS)
+#include "test/threading_helpers.h"
+#endif
+
+#if !defined(MBEDTLS_SSL_TEST_IMPOSSIBLE)
+
+#define ARRAY_LENGTH(x) (sizeof(x)/sizeof(x[0]))
+
+void my_debug(void *ctx, int level,
+ const char *file, int line,
+ const char *str)
+{
+ const char *p, *basename;
+
+ /* Extract basename from file */
+ for (p = basename = file; *p != '\0'; p++) {
+ if (*p == '/' || *p == '\\') {
+ basename = p + 1;
+ }
+ }
+
+ mbedtls_fprintf((FILE *) ctx, "%s:%04d: |%d| %s",
+ basename, line, level, str);
+ fflush((FILE *) ctx);
+}
+
+#if defined(MBEDTLS_HAVE_TIME)
+mbedtls_time_t dummy_constant_time(mbedtls_time_t *time)
+{
+ (void) time;
+ return 0x5af2a056;
+}
+#endif
+
+#if !defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+static int dummy_entropy(void *data, unsigned char *output, size_t len)
+{
+ size_t i;
+ int ret;
+ (void) data;
+
+ ret = mbedtls_entropy_func(data, output, len);
+ for (i = 0; i < len; i++) {
+ //replace result with pseudo random
+ output[i] = (unsigned char) rand();
+ }
+ return ret;
+}
+#endif
+
+void rng_init(rng_context_t *rng)
+{
+#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+ (void) rng;
+ psa_crypto_init();
+#else /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
+
+#if defined(MBEDTLS_CTR_DRBG_C)
+ mbedtls_ctr_drbg_init(&rng->drbg);
+#elif defined(MBEDTLS_HMAC_DRBG_C)
+ mbedtls_hmac_drbg_init(&rng->drbg);
+#else
+#error "No DRBG available"
+#endif
+
+ mbedtls_entropy_init(&rng->entropy);
+#endif /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
+}
+
+int rng_seed(rng_context_t *rng, int reproducible, const char *pers)
+{
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+ if (reproducible) {
+ mbedtls_fprintf(stderr,
+ "MBEDTLS_USE_PSA_CRYPTO does not support reproducible mode.\n");
+ return -1;
+ }
+#endif
+#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+ /* The PSA crypto RNG does its own seeding. */
+ (void) rng;
+ (void) pers;
+ if (reproducible) {
+ mbedtls_fprintf(stderr,
+ "The PSA RNG does not support reproducible mode.\n");
+ return -1;
+ }
+ return 0;
+#else /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
+ int (*f_entropy)(void *, unsigned char *, size_t) =
+ (reproducible ? dummy_entropy : mbedtls_entropy_func);
+
+ if (reproducible) {
+ srand(1);
+ }
+
+#if defined(MBEDTLS_CTR_DRBG_C)
+ int ret = mbedtls_ctr_drbg_seed(&rng->drbg,
+ f_entropy, &rng->entropy,
+ (const unsigned char *) pers,
+ strlen(pers));
+#elif defined(MBEDTLS_HMAC_DRBG_C)
+#if defined(MBEDTLS_MD_CAN_SHA256)
+ const mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
+#elif defined(MBEDTLS_MD_CAN_SHA512)
+ const mbedtls_md_type_t md_type = MBEDTLS_MD_SHA512;
+#else
+#error "No message digest available for HMAC_DRBG"
+#endif
+ int ret = mbedtls_hmac_drbg_seed(&rng->drbg,
+ mbedtls_md_info_from_type(md_type),
+ f_entropy, &rng->entropy,
+ (const unsigned char *) pers,
+ strlen(pers));
+#else /* !defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_HMAC_DRBG_C) */
+#error "No DRBG available"
+#endif /* !defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_HMAC_DRBG_C) */
+
+ if (ret != 0) {
+ mbedtls_printf(" failed\n ! mbedtls_ctr_drbg_seed returned -0x%x\n",
+ (unsigned int) -ret);
+ return ret;
+ }
+#endif /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
+
+ return 0;
+}
+
+void rng_free(rng_context_t *rng)
+{
+#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+ (void) rng;
+ /* Deinitialize the PSA crypto subsystem. This deactivates all PSA APIs.
+ * This is ok because none of our applications try to do any crypto after
+ * deinitializing the RNG. */
+ mbedtls_psa_crypto_free();
+#else /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
+
+#if defined(MBEDTLS_CTR_DRBG_C)
+ mbedtls_ctr_drbg_free(&rng->drbg);
+#elif defined(MBEDTLS_HMAC_DRBG_C)
+ mbedtls_hmac_drbg_free(&rng->drbg);
+#else
+#error "No DRBG available"
+#endif
+
+ mbedtls_entropy_free(&rng->entropy);
+#endif /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
+}
+
+int rng_get(void *p_rng, unsigned char *output, size_t output_len)
+{
+#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+ (void) p_rng;
+ return mbedtls_psa_get_random(MBEDTLS_PSA_RANDOM_STATE,
+ output, output_len);
+#else /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
+ rng_context_t *rng = p_rng;
+
+#if defined(MBEDTLS_CTR_DRBG_C)
+ return mbedtls_ctr_drbg_random(&rng->drbg, output, output_len);
+#elif defined(MBEDTLS_HMAC_DRBG_C)
+ return mbedtls_hmac_drbg_random(&rng->drbg, output, output_len);
+#else
+#error "No DRBG available"
+#endif
+
+#endif /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
+}
+
+int key_opaque_alg_parse(const char *arg, const char **alg1, const char **alg2)
+{
+ char *separator;
+ if ((separator = strchr(arg, ',')) == NULL) {
+ return 1;
+ }
+ *separator = '\0';
+
+ *alg1 = arg;
+ *alg2 = separator + 1;
+
+ if (strcmp(*alg1, "rsa-sign-pkcs1") != 0 &&
+ strcmp(*alg1, "rsa-sign-pss") != 0 &&
+ strcmp(*alg1, "rsa-sign-pss-sha256") != 0 &&
+ strcmp(*alg1, "rsa-sign-pss-sha384") != 0 &&
+ strcmp(*alg1, "rsa-sign-pss-sha512") != 0 &&
+ strcmp(*alg1, "rsa-decrypt") != 0 &&
+ strcmp(*alg1, "ecdsa-sign") != 0 &&
+ strcmp(*alg1, "ecdh") != 0) {
+ return 1;
+ }
+
+ if (strcmp(*alg2, "rsa-sign-pkcs1") != 0 &&
+ strcmp(*alg2, "rsa-sign-pss") != 0 &&
+ strcmp(*alg1, "rsa-sign-pss-sha256") != 0 &&
+ strcmp(*alg1, "rsa-sign-pss-sha384") != 0 &&
+ strcmp(*alg1, "rsa-sign-pss-sha512") != 0 &&
+ strcmp(*alg2, "rsa-decrypt") != 0 &&
+ strcmp(*alg2, "ecdsa-sign") != 0 &&
+ strcmp(*alg2, "ecdh") != 0 &&
+ strcmp(*alg2, "none") != 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+int key_opaque_set_alg_usage(const char *alg1, const char *alg2,
+ psa_algorithm_t *psa_alg1,
+ psa_algorithm_t *psa_alg2,
+ psa_key_usage_t *usage,
+ mbedtls_pk_type_t key_type)
+{
+ if (strcmp(alg1, "none") != 0) {
+ const char *algs[] = { alg1, alg2 };
+ psa_algorithm_t *psa_algs[] = { psa_alg1, psa_alg2 };
+
+ for (int i = 0; i < 2; i++) {
+ if (strcmp(algs[i], "rsa-sign-pkcs1") == 0) {
+ *psa_algs[i] = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH);
+ *usage |= PSA_KEY_USAGE_SIGN_HASH;
+ } else if (strcmp(algs[i], "rsa-sign-pss") == 0) {
+ *psa_algs[i] = PSA_ALG_RSA_PSS(PSA_ALG_ANY_HASH);
+ *usage |= PSA_KEY_USAGE_SIGN_HASH;
+ } else if (strcmp(algs[i], "rsa-sign-pss-sha256") == 0) {
+ *psa_algs[i] = PSA_ALG_RSA_PSS(PSA_ALG_SHA_256);
+ *usage |= PSA_KEY_USAGE_SIGN_HASH;
+ } else if (strcmp(algs[i], "rsa-sign-pss-sha384") == 0) {
+ *psa_algs[i] = PSA_ALG_RSA_PSS(PSA_ALG_SHA_384);
+ *usage |= PSA_KEY_USAGE_SIGN_HASH;
+ } else if (strcmp(algs[i], "rsa-sign-pss-sha512") == 0) {
+ *psa_algs[i] = PSA_ALG_RSA_PSS(PSA_ALG_SHA_512);
+ *usage |= PSA_KEY_USAGE_SIGN_HASH;
+ } else if (strcmp(algs[i], "rsa-decrypt") == 0) {
+ *psa_algs[i] = PSA_ALG_RSA_PKCS1V15_CRYPT;
+ *usage |= PSA_KEY_USAGE_DECRYPT;
+ } else if (strcmp(algs[i], "ecdsa-sign") == 0) {
+ *psa_algs[i] = PSA_ALG_ECDSA(PSA_ALG_ANY_HASH);
+ *usage |= PSA_KEY_USAGE_SIGN_HASH;
+ } else if (strcmp(algs[i], "ecdh") == 0) {
+ *psa_algs[i] = PSA_ALG_ECDH;
+ *usage |= PSA_KEY_USAGE_DERIVE;
+ } else if (strcmp(algs[i], "none") == 0) {
+ *psa_algs[i] = PSA_ALG_NONE;
+ }
+ }
+ } else {
+ if (key_type == MBEDTLS_PK_ECKEY) {
+ *psa_alg1 = PSA_ALG_ECDSA(PSA_ALG_ANY_HASH);
+ *psa_alg2 = PSA_ALG_ECDH;
+ *usage = PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_DERIVE;
+ } else if (key_type == MBEDTLS_PK_RSA) {
+ *psa_alg1 = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH);
+ *psa_alg2 = PSA_ALG_RSA_PSS(PSA_ALG_ANY_HASH);
+ *usage = PSA_KEY_USAGE_SIGN_HASH;
+ } else {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+#if defined(MBEDTLS_PK_C)
+int pk_wrap_as_opaque(mbedtls_pk_context *pk, psa_algorithm_t psa_alg, psa_algorithm_t psa_alg2,
+ psa_key_usage_t psa_usage, mbedtls_svc_key_id_t *key_id)
+{
+ int ret;
+ psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
+
+ ret = mbedtls_pk_get_psa_attributes(pk, PSA_KEY_USAGE_SIGN_HASH, &key_attr);
+ if (ret != 0) {
+ return ret;
+ }
+ psa_set_key_usage_flags(&key_attr, psa_usage);
+ psa_set_key_algorithm(&key_attr, psa_alg);
+ if (psa_alg2 != PSA_ALG_NONE) {
+ psa_set_key_enrollment_algorithm(&key_attr, psa_alg2);
+ }
+ ret = mbedtls_pk_import_into_psa(pk, &key_attr, key_id);
+ if (ret != 0) {
+ return ret;
+ }
+ mbedtls_pk_free(pk);
+ mbedtls_pk_init(pk);
+ ret = mbedtls_pk_setup_opaque(pk, *key_id);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return 0;
+}
+#endif /* MBEDTLS_PK_C */
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
+int ca_callback(void *data, mbedtls_x509_crt const *child,
+ mbedtls_x509_crt **candidates)
+{
+ int ret = 0;
+ mbedtls_x509_crt *ca = (mbedtls_x509_crt *) data;
+ mbedtls_x509_crt *first;
+
+ /* This is a test-only implementation of the CA callback
+ * which always returns the entire list of trusted certificates.
+ * Production implementations managing a large number of CAs
+ * should use an efficient presentation and lookup for the
+ * set of trusted certificates (such as a hashtable) and only
+ * return those trusted certificates which satisfy basic
+ * parental checks, such as the matching of child `Issuer`
+ * and parent `Subject` field or matching key identifiers. */
+ ((void) child);
+
+ first = mbedtls_calloc(1, sizeof(mbedtls_x509_crt));
+ if (first == NULL) {
+ ret = -1;
+ goto exit;
+ }
+ mbedtls_x509_crt_init(first);
+
+ if (mbedtls_x509_crt_parse_der(first, ca->raw.p, ca->raw.len) != 0) {
+ ret = -1;
+ goto exit;
+ }
+
+ while (ca->next != NULL) {
+ ca = ca->next;
+ if (mbedtls_x509_crt_parse_der(first, ca->raw.p, ca->raw.len) != 0) {
+ ret = -1;
+ goto exit;
+ }
+ }
+
+exit:
+
+ if (ret != 0) {
+ mbedtls_x509_crt_free(first);
+ mbedtls_free(first);
+ first = NULL;
+ }
+
+ *candidates = first;
+ return ret;
+}
+#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */
+
+int delayed_recv(void *ctx, unsigned char *buf, size_t len)
+{
+ static int first_try = 1;
+ int ret;
+
+ if (first_try) {
+ first_try = 0;
+ return MBEDTLS_ERR_SSL_WANT_READ;
+ }
+
+ ret = mbedtls_net_recv(ctx, buf, len);
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ) {
+ first_try = 1; /* Next call will be a new operation */
+ }
+ return ret;
+}
+
+int delayed_send(void *ctx, const unsigned char *buf, size_t len)
+{
+ static int first_try = 1;
+ int ret;
+
+ if (first_try) {
+ first_try = 0;
+ return MBEDTLS_ERR_SSL_WANT_WRITE;
+ }
+
+ ret = mbedtls_net_send(ctx, buf, len);
+ if (ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ first_try = 1; /* Next call will be a new operation */
+ }
+ return ret;
+}
+
+#if !defined(MBEDTLS_TIMING_C)
+int idle(mbedtls_net_context *fd,
+ int idle_reason)
+#else
+int idle(mbedtls_net_context *fd,
+ mbedtls_timing_delay_context *timer,
+ int idle_reason)
+#endif
+{
+ int ret;
+ int poll_type = 0;
+
+ if (idle_reason == MBEDTLS_ERR_SSL_WANT_WRITE) {
+ poll_type = MBEDTLS_NET_POLL_WRITE;
+ } else if (idle_reason == MBEDTLS_ERR_SSL_WANT_READ) {
+ poll_type = MBEDTLS_NET_POLL_READ;
+ }
+#if !defined(MBEDTLS_TIMING_C)
+ else {
+ return 0;
+ }
+#endif
+
+ while (1) {
+ /* Check if timer has expired */
+#if defined(MBEDTLS_TIMING_C)
+ if (timer != NULL &&
+ mbedtls_timing_get_delay(timer) == 2) {
+ break;
+ }
+#endif /* MBEDTLS_TIMING_C */
+
+ /* Check if underlying transport became available */
+ if (poll_type != 0) {
+ ret = mbedtls_net_poll(fd, poll_type, 0);
+ if (ret < 0) {
+ return ret;
+ }
+ if (ret == poll_type) {
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+#if defined(MBEDTLS_TEST_HOOKS)
+
+void test_hooks_init(void)
+{
+ mbedtls_test_info_reset();
+
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+ mbedtls_test_mutex_usage_init();
+#endif
+}
+
+int test_hooks_failure_detected(void)
+{
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+ /* Errors are reported via mbedtls_test_info. */
+ mbedtls_test_mutex_usage_check();
+#endif
+
+ if (mbedtls_test_get_result() != MBEDTLS_TEST_RESULT_SUCCESS) {
+ return 1;
+ }
+ return 0;
+}
+
+void test_hooks_free(void)
+{
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+ mbedtls_test_mutex_usage_end();
+#endif
+}
+
+#endif /* MBEDTLS_TEST_HOOKS */
+
+static const struct {
+ uint16_t tls_id;
+ const char *name;
+ uint8_t is_supported;
+} tls_id_group_name_table[] =
+{
+#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) || defined(PSA_WANT_ECC_SECP_R1_521)
+ { MBEDTLS_SSL_IANA_TLS_GROUP_SECP521R1, "secp521r1", 1 },
+#else
+ { MBEDTLS_SSL_IANA_TLS_GROUP_SECP521R1, "secp521r1", 0 },
+#endif
+#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) || defined(PSA_WANT_ECC_BRAINPOOL_P_R1_512)
+ { MBEDTLS_SSL_IANA_TLS_GROUP_BP512R1, "brainpoolP512r1", 1 },
+#else
+ { MBEDTLS_SSL_IANA_TLS_GROUP_BP512R1, "brainpoolP512r1", 0 },
+#endif
+#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) || defined(PSA_WANT_ECC_SECP_R1_384)
+ { MBEDTLS_SSL_IANA_TLS_GROUP_SECP384R1, "secp384r1", 1 },
+#else
+ { MBEDTLS_SSL_IANA_TLS_GROUP_SECP384R1, "secp384r1", 0 },
+#endif
+#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) || defined(PSA_WANT_ECC_BRAINPOOL_P_R1_384)
+ { MBEDTLS_SSL_IANA_TLS_GROUP_BP384R1, "brainpoolP384r1", 1 },
+#else
+ { MBEDTLS_SSL_IANA_TLS_GROUP_BP384R1, "brainpoolP384r1", 0 },
+#endif
+#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || defined(PSA_WANT_ECC_SECP_R1_256)
+ { MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1, "secp256r1", 1 },
+#else
+ { MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1, "secp256r1", 0 },
+#endif
+#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) || defined(PSA_WANT_ECC_SECP_K1_256)
+ { MBEDTLS_SSL_IANA_TLS_GROUP_SECP256K1, "secp256k1", 1 },
+#else
+ { MBEDTLS_SSL_IANA_TLS_GROUP_SECP256K1, "secp256k1", 0 },
+#endif
+#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) || defined(PSA_WANT_ECC_BRAINPOOL_P_R1_256)
+ { MBEDTLS_SSL_IANA_TLS_GROUP_BP256R1, "brainpoolP256r1", 1 },
+#else
+ { MBEDTLS_SSL_IANA_TLS_GROUP_BP256R1, "brainpoolP256r1", 0 },
+#endif
+#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) || defined(PSA_WANT_ECC_SECP_R1_224)
+ { MBEDTLS_SSL_IANA_TLS_GROUP_SECP224R1, "secp224r1", 1 },
+#else
+ { MBEDTLS_SSL_IANA_TLS_GROUP_SECP224R1, "secp224r1", 0 },
+#endif
+#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) || defined(PSA_WANT_ECC_SECP_K1_224)
+ { MBEDTLS_SSL_IANA_TLS_GROUP_SECP224K1, "secp224k1", 1 },
+#else
+ { MBEDTLS_SSL_IANA_TLS_GROUP_SECP224K1, "secp224k1", 0 },
+#endif
+#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) || defined(PSA_WANT_ECC_SECP_R1_192)
+ { MBEDTLS_SSL_IANA_TLS_GROUP_SECP192R1, "secp192r1", 1 },
+#else
+ { MBEDTLS_SSL_IANA_TLS_GROUP_SECP192R1, "secp192r1", 0 },
+#endif
+#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) || defined(PSA_WANT_ECC_SECP_K1_192)
+ { MBEDTLS_SSL_IANA_TLS_GROUP_SECP192K1, "secp192k1", 1 },
+#else
+ { MBEDTLS_SSL_IANA_TLS_GROUP_SECP192K1, "secp192k1", 0 },
+#endif
+#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) || defined(PSA_WANT_ECC_MONTGOMERY_255)
+ { MBEDTLS_SSL_IANA_TLS_GROUP_X25519, "x25519", 1 },
+#else
+ { MBEDTLS_SSL_IANA_TLS_GROUP_X25519, "x25519", 0 },
+#endif
+#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) || defined(PSA_WANT_ECC_MONTGOMERY_448)
+ { MBEDTLS_SSL_IANA_TLS_GROUP_X448, "x448", 1 },
+#else
+ { MBEDTLS_SSL_IANA_TLS_GROUP_X448, "x448", 0 },
+#endif
+#if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_EPHEMERAL_ENABLED) && \
+ defined(PSA_WANT_ALG_FFDH)
+#if defined(PSA_WANT_DH_RFC7919_2048)
+ { MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE2048, "ffdhe2048", 1 },
+#else /* PSA_WANT_DH_RFC7919_2048 */
+ { MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE2048, "ffdhe2048", 0 },
+#endif /* PSA_WANT_DH_RFC7919_2048 */
+#if defined(PSA_WANT_DH_RFC7919_3072)
+ { MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE3072, "ffdhe3072", 1 },
+#else /* PSA_WANT_DH_RFC7919_3072 */
+ { MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE3072, "ffdhe3072", 0 },
+#endif /* PSA_WANT_DH_RFC7919_3072 */
+#if defined(PSA_WANT_DH_RFC7919_4096)
+ { MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE4096, "ffdhe4096", 1 },
+#else /* PSA_WANT_DH_RFC7919_4096 */
+ { MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE4096, "ffdhe4096", 0 },
+#endif /* PSA_WANT_DH_RFC7919_4096 */
+#if defined(PSA_WANT_DH_RFC7919_6144)
+ { MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE6144, "ffdhe6144", 1 },
+#else /* PSA_WANT_DH_RFC7919_6144 */
+ { MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE6144, "ffdhe6144", 0 },
+#endif /* PSA_WANT_DH_RFC7919_6144 */
+#if defined(PSA_WANT_DH_RFC7919_8192)
+ { MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE8192, "ffdhe8192", 1 },
+#else /* PSA_WANT_DH_RFC7919_8192 */
+ { MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE8192, "ffdhe8192", 0 },
+#endif /* PSA_WANT_DH_RFC7919_8192 */
+#endif /* MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_EPHEMERAL_ENABLED && PSA_WANT_ALG_FFDH */
+ { 0, NULL, 0 },
+};
+
+static uint16_t mbedtls_ssl_get_curve_tls_id_from_name(const char *name)
+{
+ if (name == NULL) {
+ return 0;
+ }
+
+ for (int i = 0; tls_id_group_name_table[i].tls_id != 0; i++) {
+ if (strcmp(tls_id_group_name_table[i].name, name) == 0) {
+ return tls_id_group_name_table[i].tls_id;
+ }
+ }
+
+ return 0;
+}
+
+static void mbedtls_ssl_print_supported_groups_list(void)
+{
+ for (int i = 0; tls_id_group_name_table[i].tls_id != 0; i++) {
+ if (tls_id_group_name_table[i].is_supported == 1) {
+ mbedtls_printf("%s ", tls_id_group_name_table[i].name);
+ }
+ }
+}
+
+int parse_groups(const char *groups, uint16_t *group_list, size_t group_list_len)
+{
+ char *p = (char *) groups;
+ char *q = NULL;
+ size_t i = 0;
+
+ if (strcmp(p, "none") == 0) {
+ group_list[0] = 0;
+ } else if (strcmp(p, "default") != 0) {
+ /* Leave room for a final NULL in group list */
+ while (i < group_list_len - 1 && *p != '\0') {
+ uint16_t curve_tls_id;
+ q = p;
+
+ /* Terminate the current string */
+ while (*p != ',' && *p != '\0') {
+ p++;
+ }
+ if (*p == ',') {
+ *p++ = '\0';
+ }
+
+ if ((curve_tls_id = mbedtls_ssl_get_curve_tls_id_from_name(q)) != 0) {
+ group_list[i++] = curve_tls_id;
+ } else {
+ mbedtls_printf("unknown group %s\n", q);
+ mbedtls_printf("supported groups: ");
+ mbedtls_ssl_print_supported_groups_list();
+ mbedtls_printf("\n");
+ return -1;
+ }
+ }
+
+ mbedtls_printf("Number of groups: %u\n", (unsigned int) i);
+
+ if (i == group_list_len - 1 && *p != '\0') {
+ mbedtls_printf("groups list too long, maximum %u",
+ (unsigned int) (group_list_len - 1));
+ return -1;
+ }
+
+ group_list[i] = 0;
+ }
+
+ return 0;
+}
+
+#endif /* !defined(MBEDTLS_SSL_TEST_IMPOSSIBLE) */
diff --git a/programs/ssl/ssl_test_lib.h b/programs/ssl/ssl_test_lib.h
new file mode 100644
index 00000000000..1da2dfb4888
--- /dev/null
+++ b/programs/ssl/ssl_test_lib.h
@@ -0,0 +1,331 @@
+/*
+ * Common code for SSL test programs
+ *
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef MBEDTLS_PROGRAMS_SSL_SSL_TEST_LIB_H
+#define MBEDTLS_PROGRAMS_SSL_SSL_TEST_LIB_H
+
+#include "mbedtls/build_info.h"
+
+#include "mbedtls/platform.h"
+#include "mbedtls/md.h"
+
+#undef HAVE_RNG
+#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) && \
+ (defined(MBEDTLS_USE_PSA_CRYPTO) || \
+ defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG))
+#define HAVE_RNG
+#elif defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_CTR_DRBG_C)
+#define HAVE_RNG
+#elif defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_HMAC_DRBG_C) && \
+ (defined(MBEDTLS_MD_CAN_SHA256) || defined(MBEDTLS_MD_CAN_SHA512))
+#define HAVE_RNG
+#endif
+
+#if !defined(MBEDTLS_NET_C) || \
+ !defined(MBEDTLS_SSL_TLS_C)
+#define MBEDTLS_SSL_TEST_IMPOSSIBLE \
+ "MBEDTLS_NET_C and/or " \
+ "MBEDTLS_SSL_TLS_C not defined."
+#elif !defined(HAVE_RNG)
+#define MBEDTLS_SSL_TEST_IMPOSSIBLE \
+ "No random generator is available.\n"
+#else
+#undef MBEDTLS_SSL_TEST_IMPOSSIBLE
+
+#undef HAVE_RNG
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mbedtls/net_sockets.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/ssl_ciphersuites.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/hmac_drbg.h"
+#include "mbedtls/x509.h"
+#include "mbedtls/error.h"
+#include "mbedtls/debug.h"
+#include "mbedtls/timing.h"
+#include "mbedtls/base64.h"
+#include "test/certs.h"
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+#include "psa/crypto.h"
+#include "mbedtls/psa_util.h"
+#endif
+
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+#include "mbedtls/memory_buffer_alloc.h"
+#endif
+
+#include <test/helpers.h>
+
+#include "../test/query_config.h"
+
+#define ALPN_LIST_SIZE 10
+#define GROUP_LIST_SIZE 25
+#define SIG_ALG_LIST_SIZE 5
+
+typedef struct eap_tls_keys {
+ unsigned char master_secret[48];
+ unsigned char randbytes[64];
+ mbedtls_tls_prf_types tls_prf_type;
+} eap_tls_keys;
+
+#if defined(MBEDTLS_SSL_DTLS_SRTP)
+
+/* Supported SRTP mode needs a maximum of :
+ * - 16 bytes for key (AES-128)
+ * - 14 bytes SALT
+ * One for sender, one for receiver context
+ */
+#define MBEDTLS_TLS_SRTP_MAX_KEY_MATERIAL_LENGTH 60
+
+typedef struct dtls_srtp_keys {
+ unsigned char master_secret[48];
+ unsigned char randbytes[64];
+ mbedtls_tls_prf_types tls_prf_type;
+} dtls_srtp_keys;
+
+#endif /* MBEDTLS_SSL_DTLS_SRTP */
+
+typedef struct {
+ mbedtls_ssl_context *ssl;
+ mbedtls_net_context *net;
+} io_ctx_t;
+
+void my_debug(void *ctx, int level,
+ const char *file, int line,
+ const char *str);
+
+#if defined(MBEDTLS_HAVE_TIME)
+mbedtls_time_t dummy_constant_time(mbedtls_time_t *time);
+#endif
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO) && !defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+/* If MBEDTLS_TEST_USE_PSA_CRYPTO_RNG is defined, the SSL test programs will use
+ * mbedtls_psa_get_random() rather than entropy+DRBG as a random generator.
+ *
+ * The constraints are:
+ * - Without the entropy module, the PSA RNG is the only option.
+ * - Without at least one of the DRBG modules, the PSA RNG is the only option.
+ * - The PSA RNG does not support explicit seeding, so it is incompatible with
+ * the reproducible mode used by test programs.
+ * - For good overall test coverage, there should be at least one configuration
+ * where the test programs use the PSA RNG while the PSA RNG is itself based
+ * on entropy+DRBG, and at least one configuration where the test programs
+ * do not use the PSA RNG even though it's there.
+ *
+ * A simple choice that meets the constraints is to use the PSA RNG whenever
+ * MBEDTLS_USE_PSA_CRYPTO is enabled. There's no real technical reason the
+ * choice to use the PSA RNG in the test programs and the choice to use
+ * PSA crypto when TLS code needs crypto have to be tied together, but it
+ * happens to be a good match. It's also a good match from an application
+ * perspective: either PSA is preferred for TLS (both for crypto and for
+ * random generation) or it isn't.
+ */
+#define MBEDTLS_TEST_USE_PSA_CRYPTO_RNG
+#endif
+
+/** A context for random number generation (RNG).
+ */
+typedef struct {
+#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+ unsigned char dummy;
+#else /* MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
+ mbedtls_entropy_context entropy;
+#if defined(MBEDTLS_CTR_DRBG_C)
+ mbedtls_ctr_drbg_context drbg;
+#elif defined(MBEDTLS_HMAC_DRBG_C)
+ mbedtls_hmac_drbg_context drbg;
+#else
+#error "No DRBG available"
+#endif
+#endif /* MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
+} rng_context_t;
+
+/** Initialize the RNG.
+ *
+ * This function only initializes the memory used by the RNG context.
+ * Before using the RNG, it must be seeded with rng_seed().
+ */
+void rng_init(rng_context_t *rng);
+
+/* Seed the random number generator.
+ *
+ * \param rng The RNG context to use. It must have been initialized
+ * with rng_init().
+ * \param reproducible If zero, seed the RNG from entropy.
+ * If nonzero, use a fixed seed, so that the program
+ * will produce the same sequence of random numbers
+ * each time it is invoked.
+ * \param pers A null-terminated string. Different values for this
+ * string cause the RNG to emit different output for
+ * the same seed.
+ *
+ * return 0 on success, a negative value on error.
+ */
+int rng_seed(rng_context_t *rng, int reproducible, const char *pers);
+
+/** Deinitialize the RNG. Free any embedded resource.
+ *
+ * \param rng The RNG context to deinitialize. It must have been
+ * initialized with rng_init().
+ */
+void rng_free(rng_context_t *rng);
+
+/** Generate random data.
+ *
+ * This function is suitable for use as the \c f_rng argument to Mbed TLS
+ * library functions.
+ *
+ * \param p_rng The random generator context. This must be a pointer to
+ * a #rng_context_t structure.
+ * \param output The buffer to fill.
+ * \param output_len The length of the buffer in bytes.
+ *
+ * \return \c 0 on success.
+ * \return An Mbed TLS error code on error.
+ */
+int rng_get(void *p_rng, unsigned char *output, size_t output_len);
+
+/** Parse command-line option: key_opaque_algs
+ *
+ *
+ * \param arg String value of key_opaque_algs
+ * Coma-separated pair of values among the following:
+ * - "rsa-sign-pkcs1"
+ * - "rsa-sign-pss"
+ * - "rsa-decrypt"
+ * - "ecdsa-sign"
+ * - "ecdh"
+ * - "none" (only acceptable for the second value).
+ * \param alg1 Address of pointer to alg #1
+ * \param alg2 Address of pointer to alg #2
+ *
+ * \return \c 0 on success.
+ * \return \c 1 on parse failure.
+ */
+int key_opaque_alg_parse(const char *arg, const char **alg1, const char **alg2);
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+/** Parse given opaque key algorithms to obtain psa algs and usage
+ * that will be passed to mbedtls_pk_wrap_as_opaque().
+ *
+ *
+ * \param alg1 input string opaque key algorithm #1
+ * \param alg2 input string opaque key algorithm #2
+ * \param psa_alg1 output PSA algorithm #1
+ * \param psa_alg2 output PSA algorithm #2
+ * \param usage output key usage
+ * \param key_type key type used to set default psa algorithm/usage
+ * when alg1 in "none"
+ *
+ * \return \c 0 on success.
+ * \return \c 1 on parse failure.
+ */
+int key_opaque_set_alg_usage(const char *alg1, const char *alg2,
+ psa_algorithm_t *psa_alg1,
+ psa_algorithm_t *psa_alg2,
+ psa_key_usage_t *usage,
+ mbedtls_pk_type_t key_type);
+
+#if defined(MBEDTLS_PK_C)
+/** Turn a non-opaque PK context into an opaque one with folowing steps:
+ * - extract the key data and attributes from the PK context.
+ * - import the key material into PSA.
+ * - free the provided PK context and re-initilize it as an opaque PK context
+ * wrapping the PSA key imported in the above step.
+ *
+ * \param[in/out] pk On input the non-opaque PK context which contains the
+ * key to be wrapped. On output the re-initialized PK
+ * context which represents the opaque version of the one
+ * provided as input.
+ * \param[in] psa_alg The primary algorithm that will be associated to the
+ * PSA key.
+ * \param[in] psa_alg2 The enrollment algorithm that will be associated to the
+ * PSA key.
+ * \param[in] psa_usage The PSA key usage policy.
+ * \param[out] key_id The PSA key identifier of the imported key.
+ *
+ * \return \c 0 on sucess.
+ * \return \c -1 on failure.
+ */
+int pk_wrap_as_opaque(mbedtls_pk_context *pk, psa_algorithm_t psa_alg, psa_algorithm_t psa_alg2,
+ psa_key_usage_t psa_usage, mbedtls_svc_key_id_t *key_id);
+#endif /* MBEDTLS_PK_C */
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+/* The test implementation of the PSA external RNG is insecure. When
+ * MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG is enabled, before using any PSA crypto
+ * function that makes use of an RNG, you must call
+ * mbedtls_test_enable_insecure_external_rng(). */
+#include <test/fake_external_rng_for_test.h>
+#endif
+
+#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
+int ca_callback(void *data, mbedtls_x509_crt const *child,
+ mbedtls_x509_crt **candidates);
+#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */
+
+/*
+ * Test recv/send functions that make sure each try returns
+ * WANT_READ/WANT_WRITE at least once before succeeding
+ */
+int delayed_recv(void *ctx, unsigned char *buf, size_t len);
+int delayed_send(void *ctx, const unsigned char *buf, size_t len);
+
+/*
+ * Wait for an event from the underlying transport or the timer
+ * (Used in event-driven IO mode).
+ */
+int idle(mbedtls_net_context *fd,
+#if defined(MBEDTLS_TIMING_C)
+ mbedtls_timing_delay_context *timer,
+#endif
+ int idle_reason);
+
+#if defined(MBEDTLS_TEST_HOOKS)
+/** Initialize whatever test hooks are enabled by the compile-time
+ * configuration and make sense for the TLS test programs. */
+void test_hooks_init(void);
+
+/** Check if any test hooks detected a problem.
+ *
+ * If a problem was detected, it's ok for the calling program to keep going,
+ * but it should ultimately exit with an error status.
+ *
+ * \note When implementing a test hook that detects errors on its own
+ * (as opposed to e.g. leaving the error for a memory sanitizer to
+ * report), make sure to print a message to standard error either at
+ * the time the problem is detected or during the execution of this
+ * function. This function does not indicate what problem was detected,
+ * so printing a message is the only way to provide feedback in the
+ * logs of the calling program.
+ *
+ * \return Nonzero if a problem was detected.
+ * \c 0 if no problem was detected.
+ */
+int test_hooks_failure_detected(void);
+
+/** Free any resources allocated for the sake of test hooks.
+ *
+ * Call this at the end of the program so that resource leak analyzers
+ * don't complain.
+ */
+void test_hooks_free(void);
+
+#endif /* !MBEDTLS_TEST_HOOKS */
+
+/* Helper functions for FFDH groups. */
+int parse_groups(const char *groups, uint16_t *group_list, size_t group_list_len);
+
+#endif /* MBEDTLS_SSL_TEST_IMPOSSIBLE conditions: else */
+#endif /* MBEDTLS_PROGRAMS_SSL_SSL_TEST_LIB_H */