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)
main(void)19 int 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 
64 mbedtls_threading_mutex_t debug_mutex;
65 
my_mutexed_debug(void * ctx,int level,const char * file,int line,const char * str)66 static 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 
82 typedef struct {
83     mbedtls_net_context client_fd;
84     int thread_complete;
85     const mbedtls_ssl_config *config;
86 } thread_info_t;
87 
88 typedef struct {
89     int active;
90     thread_info_t   data;
91     pthread_t       thread;
92 } pthread_info_t;
93 
94 static thread_info_t    base_info;
95 static pthread_info_t   threads[MAX_NUM_THREADS];
96 
handle_ssl_connection(void * data)97 static 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 
220 thread_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 
thread_create(mbedtls_net_context * client_fd)239 static 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 
main(void)278 int 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 
431 reset:
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 
465 exit:
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