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