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