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