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