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