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