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