1/* 2 * SSL server demonstration program using pthread for handling multiple 3 * clients. 4 * 5 * Copyright The Mbed TLS Contributors 6 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 7 */ 8 9#include "mbedtls/build_info.h" 10 11#include "mbedtls/platform.h" 12 13#if !defined(MBEDTLS_BIGNUM_C) || !defined(MBEDTLS_ENTROPY_C) || \ 14 !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_SRV_C) || \ 15 !defined(MBEDTLS_NET_C) || !defined(MBEDTLS_RSA_C) || \ 16 !defined(MBEDTLS_CTR_DRBG_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \ 17 !defined(MBEDTLS_FS_IO) || !defined(MBEDTLS_THREADING_C) || \ 18 !defined(MBEDTLS_THREADING_PTHREAD) || !defined(MBEDTLS_PEM_PARSE_C) 19int main(void) 20{ 21 mbedtls_printf("MBEDTLS_BIGNUM_C and/or MBEDTLS_ENTROPY_C " 22 "and/or MBEDTLS_SSL_TLS_C and/or MBEDTLS_SSL_SRV_C and/or " 23 "MBEDTLS_NET_C and/or MBEDTLS_RSA_C and/or " 24 "MBEDTLS_CTR_DRBG_C and/or MBEDTLS_X509_CRT_PARSE_C and/or " 25 "MBEDTLS_THREADING_C and/or MBEDTLS_THREADING_PTHREAD " 26 "and/or MBEDTLS_PEM_PARSE_C not defined.\n"); 27 mbedtls_exit(0); 28} 29#else 30 31#include <stdlib.h> 32#include <string.h> 33 34#if defined(_WIN32) 35#include <windows.h> 36#endif 37 38#include "mbedtls/entropy.h" 39#include "mbedtls/ctr_drbg.h" 40#include "mbedtls/x509.h" 41#include "mbedtls/ssl.h" 42#include "mbedtls/net_sockets.h" 43#include "mbedtls/error.h" 44#include "test/certs.h" 45 46#if defined(MBEDTLS_SSL_CACHE_C) 47#include "mbedtls/ssl_cache.h" 48#endif 49 50#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) 51#include "mbedtls/memory_buffer_alloc.h" 52#endif 53 54 55#define HTTP_RESPONSE \ 56 "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" \ 57 "<h2>Mbed TLS Test Server</h2>\r\n" \ 58 "<p>Successful connection using: %s</p>\r\n" 59 60#define DEBUG_LEVEL 0 61 62#define MAX_NUM_THREADS 5 63 64mbedtls_threading_mutex_t debug_mutex; 65 66static void my_mutexed_debug(void *ctx, int level, 67 const char *file, int line, 68 const char *str) 69{ 70 long int thread_id = (long int) pthread_self(); 71 72 mbedtls_mutex_lock(&debug_mutex); 73 74 ((void) level); 75 mbedtls_fprintf((FILE *) ctx, "%s:%04d: [ #%ld ] %s", 76 file, line, thread_id, str); 77 fflush((FILE *) ctx); 78 79 mbedtls_mutex_unlock(&debug_mutex); 80} 81 82typedef struct { 83 mbedtls_net_context client_fd; 84 int thread_complete; 85 const mbedtls_ssl_config *config; 86} thread_info_t; 87 88typedef struct { 89 int active; 90 thread_info_t data; 91 pthread_t thread; 92} pthread_info_t; 93 94static thread_info_t base_info; 95static pthread_info_t threads[MAX_NUM_THREADS]; 96 97static void *handle_ssl_connection(void *data) 98{ 99 int ret, len; 100 thread_info_t *thread_info = (thread_info_t *) data; 101 mbedtls_net_context *client_fd = &thread_info->client_fd; 102 long int thread_id = (long int) pthread_self(); 103 unsigned char buf[1024]; 104 mbedtls_ssl_context ssl; 105 106 /* Make sure memory references are valid */ 107 mbedtls_ssl_init(&ssl); 108 109 mbedtls_printf(" [ #%ld ] Setting up SSL/TLS data\n", thread_id); 110 111 /* 112 * 4. Get the SSL context ready 113 */ 114 if ((ret = mbedtls_ssl_setup(&ssl, thread_info->config)) != 0) { 115 mbedtls_printf(" [ #%ld ] failed: mbedtls_ssl_setup returned -0x%04x\n", 116 thread_id, (unsigned int) -ret); 117 goto thread_exit; 118 } 119 120 mbedtls_ssl_set_bio(&ssl, client_fd, mbedtls_net_send, mbedtls_net_recv, NULL); 121 122 /* 123 * 5. Handshake 124 */ 125 mbedtls_printf(" [ #%ld ] Performing the SSL/TLS handshake\n", thread_id); 126 127 while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) { 128 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { 129 mbedtls_printf(" [ #%ld ] failed: mbedtls_ssl_handshake returned -0x%04x\n", 130 thread_id, (unsigned int) -ret); 131 goto thread_exit; 132 } 133 } 134 135 mbedtls_printf(" [ #%ld ] ok\n", thread_id); 136 137 /* 138 * 6. Read the HTTP Request 139 */ 140 mbedtls_printf(" [ #%ld ] < Read from client\n", thread_id); 141 142 do { 143 len = sizeof(buf) - 1; 144 memset(buf, 0, sizeof(buf)); 145 ret = mbedtls_ssl_read(&ssl, buf, len); 146 147 if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) { 148 continue; 149 } 150 151 if (ret <= 0) { 152 switch (ret) { 153 case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: 154 mbedtls_printf(" [ #%ld ] connection was closed gracefully\n", 155 thread_id); 156 goto thread_exit; 157 158 case MBEDTLS_ERR_NET_CONN_RESET: 159 mbedtls_printf(" [ #%ld ] connection was reset by peer\n", 160 thread_id); 161 goto thread_exit; 162 163 default: 164 mbedtls_printf(" [ #%ld ] mbedtls_ssl_read returned -0x%04x\n", 165 thread_id, (unsigned int) -ret); 166 goto thread_exit; 167 } 168 } 169 170 len = ret; 171 mbedtls_printf(" [ #%ld ] %d bytes read\n=====\n%s\n=====\n", 172 thread_id, len, (char *) buf); 173 174 if (ret > 0) { 175 break; 176 } 177 } while (1); 178 179 /* 180 * 7. Write the 200 Response 181 */ 182 mbedtls_printf(" [ #%ld ] > Write to client:\n", thread_id); 183 184 len = sprintf((char *) buf, HTTP_RESPONSE, 185 mbedtls_ssl_get_ciphersuite(&ssl)); 186 187 while ((ret = mbedtls_ssl_write(&ssl, buf, len)) <= 0) { 188 if (ret == MBEDTLS_ERR_NET_CONN_RESET) { 189 mbedtls_printf(" [ #%ld ] failed: peer closed the connection\n", 190 thread_id); 191 goto thread_exit; 192 } 193 194 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { 195 mbedtls_printf(" [ #%ld ] failed: mbedtls_ssl_write returned -0x%04x\n", 196 thread_id, (unsigned int) ret); 197 goto thread_exit; 198 } 199 } 200 201 len = ret; 202 mbedtls_printf(" [ #%ld ] %d bytes written\n=====\n%s\n=====\n", 203 thread_id, len, (char *) buf); 204 205 mbedtls_printf(" [ #%ld ] . Closing the connection...", thread_id); 206 207 while ((ret = mbedtls_ssl_close_notify(&ssl)) < 0) { 208 if (ret != MBEDTLS_ERR_SSL_WANT_READ && 209 ret != MBEDTLS_ERR_SSL_WANT_WRITE) { 210 mbedtls_printf(" [ #%ld ] failed: mbedtls_ssl_close_notify returned -0x%04x\n", 211 thread_id, (unsigned int) ret); 212 goto thread_exit; 213 } 214 } 215 216 mbedtls_printf(" ok\n"); 217 218 ret = 0; 219 220thread_exit: 221 222#ifdef MBEDTLS_ERROR_C 223 if (ret != 0) { 224 char error_buf[100]; 225 mbedtls_strerror(ret, error_buf, 100); 226 mbedtls_printf(" [ #%ld ] Last error was: -0x%04x - %s\n\n", 227 thread_id, (unsigned int) -ret, error_buf); 228 } 229#endif 230 231 mbedtls_net_free(client_fd); 232 mbedtls_ssl_free(&ssl); 233 234 thread_info->thread_complete = 1; 235 236 return NULL; 237} 238 239static int thread_create(mbedtls_net_context *client_fd) 240{ 241 int ret, i; 242 243 /* 244 * Find in-active or finished thread slot 245 */ 246 for (i = 0; i < MAX_NUM_THREADS; i++) { 247 if (threads[i].active == 0) { 248 break; 249 } 250 251 if (threads[i].data.thread_complete == 1) { 252 mbedtls_printf(" [ main ] Cleaning up thread %d\n", i); 253 pthread_join(threads[i].thread, NULL); 254 memset(&threads[i], 0, sizeof(pthread_info_t)); 255 break; 256 } 257 } 258 259 if (i == MAX_NUM_THREADS) { 260 return -1; 261 } 262 263 /* 264 * Fill thread-info for thread 265 */ 266 memcpy(&threads[i].data, &base_info, sizeof(base_info)); 267 threads[i].active = 1; 268 memcpy(&threads[i].data.client_fd, client_fd, sizeof(mbedtls_net_context)); 269 270 if ((ret = pthread_create(&threads[i].thread, NULL, handle_ssl_connection, 271 &threads[i].data)) != 0) { 272 return ret; 273 } 274 275 return 0; 276} 277 278int main(void) 279{ 280 int ret; 281 mbedtls_net_context listen_fd, client_fd; 282 const char pers[] = "ssl_pthread_server"; 283 284 mbedtls_entropy_context entropy; 285 mbedtls_ctr_drbg_context ctr_drbg; 286 mbedtls_ssl_config conf; 287 mbedtls_x509_crt srvcert; 288 mbedtls_x509_crt cachain; 289 mbedtls_pk_context pkey; 290#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) 291 unsigned char alloc_buf[100000]; 292#endif 293#if defined(MBEDTLS_SSL_CACHE_C) 294 mbedtls_ssl_cache_context cache; 295#endif 296 297#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) 298 mbedtls_memory_buffer_alloc_init(alloc_buf, sizeof(alloc_buf)); 299#endif 300 301#if defined(MBEDTLS_SSL_CACHE_C) 302 mbedtls_ssl_cache_init(&cache); 303#endif 304 305 mbedtls_x509_crt_init(&srvcert); 306 mbedtls_x509_crt_init(&cachain); 307 308 mbedtls_ssl_config_init(&conf); 309 mbedtls_ctr_drbg_init(&ctr_drbg); 310 memset(threads, 0, sizeof(threads)); 311 mbedtls_net_init(&listen_fd); 312 mbedtls_net_init(&client_fd); 313 314 mbedtls_mutex_init(&debug_mutex); 315 316 base_info.config = &conf; 317 318 /* 319 * We use only a single entropy source that is used in all the threads. 320 */ 321 mbedtls_entropy_init(&entropy); 322 323#if defined(MBEDTLS_USE_PSA_CRYPTO) 324 psa_status_t status = psa_crypto_init(); 325 if (status != PSA_SUCCESS) { 326 mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n", 327 (int) status); 328 ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED; 329 goto exit; 330 } 331#endif /* MBEDTLS_USE_PSA_CRYPTO */ 332 333 /* 334 * 1a. Seed the random number generator 335 */ 336 mbedtls_printf(" . Seeding the random number generator..."); 337 338 if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, 339 (const unsigned char *) pers, 340 strlen(pers))) != 0) { 341 mbedtls_printf(" failed: mbedtls_ctr_drbg_seed returned -0x%04x\n", 342 (unsigned int) -ret); 343 goto exit; 344 } 345 346 mbedtls_printf(" ok\n"); 347 348 /* 349 * 1b. Load the certificates and private RSA key 350 */ 351 mbedtls_printf("\n . Loading the server cert. and key..."); 352 fflush(stdout); 353 354 /* 355 * This demonstration program uses embedded test certificates. 356 * Instead, you may want to use mbedtls_x509_crt_parse_file() to read the 357 * server and CA certificates, as well as mbedtls_pk_parse_keyfile(). 358 */ 359 ret = mbedtls_x509_crt_parse(&srvcert, (const unsigned char *) mbedtls_test_srv_crt, 360 mbedtls_test_srv_crt_len); 361 if (ret != 0) { 362 mbedtls_printf(" failed\n ! mbedtls_x509_crt_parse returned %d\n\n", ret); 363 goto exit; 364 } 365 366 ret = mbedtls_x509_crt_parse(&cachain, (const unsigned char *) mbedtls_test_cas_pem, 367 mbedtls_test_cas_pem_len); 368 if (ret != 0) { 369 mbedtls_printf(" failed\n ! mbedtls_x509_crt_parse returned %d\n\n", ret); 370 goto exit; 371 } 372 373 mbedtls_pk_init(&pkey); 374 ret = mbedtls_pk_parse_key(&pkey, (const unsigned char *) mbedtls_test_srv_key, 375 mbedtls_test_srv_key_len, NULL, 0, 376 mbedtls_ctr_drbg_random, &ctr_drbg); 377 if (ret != 0) { 378 mbedtls_printf(" failed\n ! mbedtls_pk_parse_key returned %d\n\n", ret); 379 goto exit; 380 } 381 382 mbedtls_printf(" ok\n"); 383 384 /* 385 * 1c. Prepare SSL configuration 386 */ 387 mbedtls_printf(" . Setting up the SSL data...."); 388 389 if ((ret = mbedtls_ssl_config_defaults(&conf, 390 MBEDTLS_SSL_IS_SERVER, 391 MBEDTLS_SSL_TRANSPORT_STREAM, 392 MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { 393 mbedtls_printf(" failed: mbedtls_ssl_config_defaults returned -0x%04x\n", 394 (unsigned int) -ret); 395 goto exit; 396 } 397 398 mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); 399 mbedtls_ssl_conf_dbg(&conf, my_mutexed_debug, stdout); 400 401 /* mbedtls_ssl_cache_get() and mbedtls_ssl_cache_set() are thread-safe if 402 * MBEDTLS_THREADING_C is set. 403 */ 404#if defined(MBEDTLS_SSL_CACHE_C) 405 mbedtls_ssl_conf_session_cache(&conf, &cache, 406 mbedtls_ssl_cache_get, 407 mbedtls_ssl_cache_set); 408#endif 409 410 mbedtls_ssl_conf_ca_chain(&conf, &cachain, NULL); 411 if ((ret = mbedtls_ssl_conf_own_cert(&conf, &srvcert, &pkey)) != 0) { 412 mbedtls_printf(" failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret); 413 goto exit; 414 } 415 416 mbedtls_printf(" ok\n"); 417 418 /* 419 * 2. Setup the listening TCP socket 420 */ 421 mbedtls_printf(" . Bind on https://localhost:4433/ ..."); 422 fflush(stdout); 423 424 if ((ret = mbedtls_net_bind(&listen_fd, NULL, "4433", MBEDTLS_NET_PROTO_TCP)) != 0) { 425 mbedtls_printf(" failed\n ! mbedtls_net_bind returned %d\n\n", ret); 426 goto exit; 427 } 428 429 mbedtls_printf(" ok\n"); 430 431reset: 432#ifdef MBEDTLS_ERROR_C 433 if (ret != 0) { 434 char error_buf[100]; 435 mbedtls_strerror(ret, error_buf, 100); 436 mbedtls_printf(" [ main ] Last error was: -0x%04x - %s\n", (unsigned int) -ret, 437 error_buf); 438 } 439#endif 440 441 /* 442 * 3. Wait until a client connects 443 */ 444 mbedtls_printf(" [ main ] Waiting for a remote connection\n"); 445 446 if ((ret = mbedtls_net_accept(&listen_fd, &client_fd, 447 NULL, 0, NULL)) != 0) { 448 mbedtls_printf(" [ main ] failed: mbedtls_net_accept returned -0x%04x\n", 449 (unsigned int) ret); 450 goto exit; 451 } 452 453 mbedtls_printf(" [ main ] ok\n"); 454 mbedtls_printf(" [ main ] Creating a new thread\n"); 455 456 if ((ret = thread_create(&client_fd)) != 0) { 457 mbedtls_printf(" [ main ] failed: thread_create returned %d\n", ret); 458 mbedtls_net_free(&client_fd); 459 goto reset; 460 } 461 462 ret = 0; 463 goto reset; 464 465exit: 466 mbedtls_x509_crt_free(&srvcert); 467 mbedtls_pk_free(&pkey); 468#if defined(MBEDTLS_SSL_CACHE_C) 469 mbedtls_ssl_cache_free(&cache); 470#endif 471 mbedtls_ctr_drbg_free(&ctr_drbg); 472 mbedtls_entropy_free(&entropy); 473 mbedtls_ssl_config_free(&conf); 474 mbedtls_net_free(&listen_fd); 475 mbedtls_mutex_free(&debug_mutex); 476#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) 477 mbedtls_memory_buffer_alloc_free(); 478#endif 479#if defined(MBEDTLS_USE_PSA_CRYPTO) 480 mbedtls_psa_crypto_free(); 481#endif /* MBEDTLS_USE_PSA_CRYPTO */ 482 483 mbedtls_exit(ret); 484} 485 486#endif /* MBEDTLS_BIGNUM_C && MBEDTLS_ENTROPY_C && 487 MBEDTLS_SSL_TLS_C && MBEDTLS_SSL_SRV_C && MBEDTLS_NET_C && 488 MBEDTLS_RSA_C && MBEDTLS_CTR_DRBG_C && MBEDTLS_THREADING_C && 489 MBEDTLS_THREADING_PTHREAD && MBEDTLS_PEM_PARSE_C */ 490