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