1 /*
2  *  Certificate reading application
3  *
4  *  Copyright The Mbed TLS Contributors
5  *  SPDX-License-Identifier: Apache-2.0
6  *
7  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8  *  not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at
10  *
11  *  http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License.
18  */
19 
20 #if !defined(MBEDTLS_CONFIG_FILE)
21 #include "mbedtls/config.h"
22 #else
23 #include MBEDTLS_CONFIG_FILE
24 #endif
25 
26 #if defined(MBEDTLS_PLATFORM_C)
27 #include "mbedtls/platform.h"
28 #else
29 #include <stdio.h>
30 #include <stdlib.h>
31 #define mbedtls_time            time
32 #define mbedtls_time_t          time_t
33 #define mbedtls_fprintf         fprintf
34 #define mbedtls_printf          printf
35 #define mbedtls_exit            exit
36 #define MBEDTLS_EXIT_SUCCESS    EXIT_SUCCESS
37 #define MBEDTLS_EXIT_FAILURE    EXIT_FAILURE
38 #endif /* MBEDTLS_PLATFORM_C */
39 
40 #if !defined(MBEDTLS_BIGNUM_C) || !defined(MBEDTLS_ENTROPY_C) ||  \
41     !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_CLI_C) || \
42     !defined(MBEDTLS_NET_C) || !defined(MBEDTLS_RSA_C) ||         \
43     !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_FS_IO) ||  \
44     !defined(MBEDTLS_CTR_DRBG_C)
main(void)45 int main( void )
46 {
47     mbedtls_printf("MBEDTLS_BIGNUM_C and/or MBEDTLS_ENTROPY_C and/or "
48            "MBEDTLS_SSL_TLS_C and/or MBEDTLS_SSL_CLI_C and/or "
49            "MBEDTLS_NET_C and/or MBEDTLS_RSA_C and/or "
50            "MBEDTLS_X509_CRT_PARSE_C and/or MBEDTLS_FS_IO and/or "
51            "MBEDTLS_CTR_DRBG_C not defined.\n");
52     mbedtls_exit( 0 );
53 }
54 #else
55 
56 #include "mbedtls/entropy.h"
57 #include "mbedtls/ctr_drbg.h"
58 #include "mbedtls/net_sockets.h"
59 #include "mbedtls/ssl.h"
60 #include "mbedtls/x509.h"
61 #include "mbedtls/debug.h"
62 
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <string.h>
66 
67 #define MODE_NONE               0
68 #define MODE_FILE               1
69 #define MODE_SSL                2
70 
71 #define DFL_MODE                MODE_NONE
72 #define DFL_FILENAME            "cert.crt"
73 #define DFL_CA_FILE             ""
74 #define DFL_CRL_FILE            ""
75 #define DFL_CA_PATH             ""
76 #define DFL_SERVER_NAME         "localhost"
77 #define DFL_SERVER_PORT         "4433"
78 #define DFL_DEBUG_LEVEL         0
79 #define DFL_PERMISSIVE          0
80 
81 #define USAGE_IO \
82     "    ca_file=%%s          The single file containing the top-level CA(s) you fully trust\n" \
83     "                        default: \"\" (none)\n" \
84     "    crl_file=%%s         The single CRL file you want to use\n" \
85     "                        default: \"\" (none)\n" \
86     "    ca_path=%%s          The path containing the top-level CA(s) you fully trust\n" \
87     "                        default: \"\" (none) (overrides ca_file)\n"
88 
89 #define USAGE \
90     "\n usage: cert_app param=<>...\n"                  \
91     "\n acceptable parameters:\n"                       \
92     "    mode=file|ssl       default: none\n"           \
93     "    filename=%%s         default: cert.crt\n"      \
94     USAGE_IO                                            \
95     "    server_name=%%s      default: localhost\n"     \
96     "    server_port=%%d      default: 4433\n"          \
97     "    debug_level=%%d      default: 0 (disabled)\n"  \
98     "    permissive=%%d       default: 0 (disabled)\n"  \
99     "\n"
100 
101 
102 /*
103  * global options
104  */
105 struct options
106 {
107     int mode;                   /* the mode to run the application in   */
108     const char *filename;       /* filename of the certificate file     */
109     const char *ca_file;        /* the file with the CA certificate(s)  */
110     const char *crl_file;       /* the file with the CRL to use         */
111     const char *ca_path;        /* the path with the CA certificate(s) reside */
112     const char *server_name;    /* hostname of the server (client only) */
113     const char *server_port;    /* port on which the ssl service runs   */
114     int debug_level;            /* level of debugging                   */
115     int permissive;             /* permissive parsing                   */
116 } opt;
117 
my_debug(void * ctx,int level,const char * file,int line,const char * str)118 static void my_debug( void *ctx, int level,
119                       const char *file, int line,
120                       const char *str )
121 {
122     ((void) level);
123 
124     mbedtls_fprintf( (FILE *) ctx, "%s:%04d: %s", file, line, str );
125     fflush(  (FILE *) ctx  );
126 }
127 
my_verify(void * data,mbedtls_x509_crt * crt,int depth,uint32_t * flags)128 static int my_verify( void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags )
129 {
130     char buf[1024];
131     ((void) data);
132 
133     mbedtls_printf( "\nVerify requested for (Depth %d):\n", depth );
134     mbedtls_x509_crt_info( buf, sizeof( buf ) - 1, "", crt );
135     mbedtls_printf( "%s", buf );
136 
137     if ( ( *flags ) == 0 )
138         mbedtls_printf( "  This certificate has no flags\n" );
139     else
140     {
141         mbedtls_x509_crt_verify_info( buf, sizeof( buf ), "  ! ", *flags );
142         mbedtls_printf( "%s\n", buf );
143     }
144 
145     return( 0 );
146 }
147 
main(int argc,char * argv[])148 int main( int argc, char *argv[] )
149 {
150     int ret = 1;
151     int exit_code = MBEDTLS_EXIT_FAILURE;
152     mbedtls_net_context server_fd;
153     unsigned char buf[1024];
154     mbedtls_entropy_context entropy;
155     mbedtls_ctr_drbg_context ctr_drbg;
156     mbedtls_ssl_context ssl;
157     mbedtls_ssl_config conf;
158     mbedtls_x509_crt cacert;
159     mbedtls_x509_crl cacrl;
160     int i, j;
161     uint32_t flags;
162     int verify = 0;
163     char *p, *q;
164     const char *pers = "cert_app";
165 
166     /*
167      * Set to sane values
168      */
169     mbedtls_net_init( &server_fd );
170     mbedtls_ctr_drbg_init( &ctr_drbg );
171     mbedtls_ssl_init( &ssl );
172     mbedtls_ssl_config_init( &conf );
173     mbedtls_x509_crt_init( &cacert );
174 #if defined(MBEDTLS_X509_CRL_PARSE_C)
175     mbedtls_x509_crl_init( &cacrl );
176 #else
177     /* Zeroize structure as CRL parsing is not supported and we have to pass
178        it to the verify function */
179     memset( &cacrl, 0, sizeof(mbedtls_x509_crl) );
180 #endif
181 
182     if( argc == 0 )
183     {
184     usage:
185         mbedtls_printf( USAGE );
186         goto exit;
187     }
188 
189     opt.mode                = DFL_MODE;
190     opt.filename            = DFL_FILENAME;
191     opt.ca_file             = DFL_CA_FILE;
192     opt.crl_file            = DFL_CRL_FILE;
193     opt.ca_path             = DFL_CA_PATH;
194     opt.server_name         = DFL_SERVER_NAME;
195     opt.server_port         = DFL_SERVER_PORT;
196     opt.debug_level         = DFL_DEBUG_LEVEL;
197     opt.permissive          = DFL_PERMISSIVE;
198 
199     for( i = 1; i < argc; i++ )
200     {
201         p = argv[i];
202         if( ( q = strchr( p, '=' ) ) == NULL )
203             goto usage;
204         *q++ = '\0';
205 
206         for( j = 0; p + j < q; j++ )
207         {
208             if( argv[i][j] >= 'A' && argv[i][j] <= 'Z' )
209                 argv[i][j] |= 0x20;
210         }
211 
212         if( strcmp( p, "mode" ) == 0 )
213         {
214             if( strcmp( q, "file" ) == 0 )
215                 opt.mode = MODE_FILE;
216             else if( strcmp( q, "ssl" ) == 0 )
217                 opt.mode = MODE_SSL;
218             else
219                 goto usage;
220         }
221         else if( strcmp( p, "filename" ) == 0 )
222             opt.filename = q;
223         else if( strcmp( p, "ca_file" ) == 0 )
224             opt.ca_file = q;
225         else if( strcmp( p, "crl_file" ) == 0 )
226             opt.crl_file = q;
227         else if( strcmp( p, "ca_path" ) == 0 )
228             opt.ca_path = q;
229         else if( strcmp( p, "server_name" ) == 0 )
230             opt.server_name = q;
231         else if( strcmp( p, "server_port" ) == 0 )
232             opt.server_port = q;
233         else if( strcmp( p, "debug_level" ) == 0 )
234         {
235             opt.debug_level = atoi( q );
236             if( opt.debug_level < 0 || opt.debug_level > 65535 )
237                 goto usage;
238         }
239         else if( strcmp( p, "permissive" ) == 0 )
240         {
241             opt.permissive = atoi( q );
242             if( opt.permissive < 0 || opt.permissive > 1 )
243                 goto usage;
244         }
245         else
246             goto usage;
247     }
248 
249     /*
250      * 1.1. Load the trusted CA
251      */
252     mbedtls_printf( "  . Loading the CA root certificate ..." );
253     fflush( stdout );
254 
255     if( strlen( opt.ca_path ) )
256     {
257         if( ( ret = mbedtls_x509_crt_parse_path( &cacert, opt.ca_path ) ) < 0 )
258         {
259             mbedtls_printf( " failed\n  !  mbedtls_x509_crt_parse_path returned -0x%x\n\n", (unsigned int) -ret );
260             goto exit;
261         }
262 
263         verify = 1;
264     }
265     else if( strlen( opt.ca_file ) )
266     {
267         if( ( ret = mbedtls_x509_crt_parse_file( &cacert, opt.ca_file ) ) < 0 )
268         {
269             mbedtls_printf( " failed\n  !  mbedtls_x509_crt_parse_file returned -0x%x\n\n", (unsigned int) -ret );
270             goto exit;
271         }
272 
273         verify = 1;
274     }
275 
276     mbedtls_printf( " ok (%d skipped)\n", ret );
277 
278 #if defined(MBEDTLS_X509_CRL_PARSE_C)
279     if( strlen( opt.crl_file ) )
280     {
281         if( ( ret = mbedtls_x509_crl_parse_file( &cacrl, opt.crl_file ) ) != 0 )
282         {
283             mbedtls_printf( " failed\n  !  mbedtls_x509_crl_parse returned -0x%x\n\n", (unsigned int) -ret );
284             goto exit;
285         }
286 
287         verify = 1;
288     }
289 #endif
290 
291     if( opt.mode == MODE_FILE )
292     {
293         mbedtls_x509_crt crt;
294         mbedtls_x509_crt *cur = &crt;
295         mbedtls_x509_crt_init( &crt );
296 
297         /*
298          * 1.1. Load the certificate(s)
299          */
300         mbedtls_printf( "\n  . Loading the certificate(s) ..." );
301         fflush( stdout );
302 
303         ret = mbedtls_x509_crt_parse_file( &crt, opt.filename );
304 
305         if( ret < 0 )
306         {
307             mbedtls_printf( " failed\n  !  mbedtls_x509_crt_parse_file returned %d\n\n", ret );
308             mbedtls_x509_crt_free( &crt );
309             goto exit;
310         }
311 
312         if( opt.permissive == 0 && ret > 0 )
313         {
314             mbedtls_printf( " failed\n  !  mbedtls_x509_crt_parse failed to parse %d certificates\n\n", ret );
315             mbedtls_x509_crt_free( &crt );
316             goto exit;
317         }
318 
319         mbedtls_printf( " ok\n" );
320 
321         /*
322          * 1.2 Print the certificate(s)
323          */
324         while( cur != NULL )
325         {
326             mbedtls_printf( "  . Peer certificate information    ...\n" );
327             ret = mbedtls_x509_crt_info( (char *) buf, sizeof( buf ) - 1, "      ",
328                                  cur );
329             if( ret == -1 )
330             {
331                 mbedtls_printf( " failed\n  !  mbedtls_x509_crt_info returned %d\n\n", ret );
332                 mbedtls_x509_crt_free( &crt );
333                 goto exit;
334             }
335 
336             mbedtls_printf( "%s\n", buf );
337 
338             cur = cur->next;
339         }
340 
341         /*
342          * 1.3 Verify the certificate
343          */
344         if( verify )
345         {
346             mbedtls_printf( "  . Verifying X.509 certificate..." );
347 
348             if( ( ret = mbedtls_x509_crt_verify( &crt, &cacert, &cacrl, NULL, &flags,
349                                          my_verify, NULL ) ) != 0 )
350             {
351                 char vrfy_buf[512];
352 
353                 mbedtls_printf( " failed\n" );
354 
355                 mbedtls_x509_crt_verify_info( vrfy_buf, sizeof( vrfy_buf ), "  ! ", flags );
356 
357                 mbedtls_printf( "%s\n", vrfy_buf );
358             }
359             else
360                 mbedtls_printf( " ok\n" );
361         }
362 
363         mbedtls_x509_crt_free( &crt );
364     }
365     else if( opt.mode == MODE_SSL )
366     {
367         /*
368          * 1. Initialize the RNG and the session data
369          */
370         mbedtls_printf( "\n  . Seeding the random number generator..." );
371         fflush( stdout );
372 
373         mbedtls_entropy_init( &entropy );
374         if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
375                                    (const unsigned char *) pers,
376                                    strlen( pers ) ) ) != 0 )
377         {
378             mbedtls_printf( " failed\n  ! mbedtls_ctr_drbg_seed returned %d\n", ret );
379             goto ssl_exit;
380         }
381 
382         mbedtls_printf( " ok\n" );
383 
384 #if defined(MBEDTLS_DEBUG_C)
385         mbedtls_debug_set_threshold( opt.debug_level );
386 #endif
387 
388         /*
389          * 2. Start the connection
390          */
391         mbedtls_printf( "  . SSL connection to tcp/%s/%s...", opt.server_name,
392                                                               opt.server_port );
393         fflush( stdout );
394 
395         if( ( ret = mbedtls_net_connect( &server_fd, opt.server_name,
396                                  opt.server_port, MBEDTLS_NET_PROTO_TCP ) ) != 0 )
397         {
398             mbedtls_printf( " failed\n  ! mbedtls_net_connect returned %d\n\n", ret );
399             goto ssl_exit;
400         }
401 
402         /*
403          * 3. Setup stuff
404          */
405         if( ( ret = mbedtls_ssl_config_defaults( &conf,
406                         MBEDTLS_SSL_IS_CLIENT,
407                         MBEDTLS_SSL_TRANSPORT_STREAM,
408                         MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 )
409         {
410             mbedtls_printf( " failed\n  ! mbedtls_ssl_config_defaults returned %d\n\n", ret );
411             goto exit;
412         }
413 
414         if( verify )
415         {
416             mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_REQUIRED );
417             mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL );
418             mbedtls_ssl_conf_verify( &conf, my_verify, NULL );
419         }
420         else
421             mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_NONE );
422 
423         mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
424         mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
425 
426         if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
427         {
428             mbedtls_printf( " failed\n  ! mbedtls_ssl_setup returned %d\n\n", ret );
429             goto ssl_exit;
430         }
431 
432         if( ( ret = mbedtls_ssl_set_hostname( &ssl, opt.server_name ) ) != 0 )
433         {
434             mbedtls_printf( " failed\n  ! mbedtls_ssl_set_hostname returned %d\n\n", ret );
435             goto ssl_exit;
436         }
437 
438         mbedtls_ssl_set_bio( &ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL );
439 
440         /*
441          * 4. Handshake
442          */
443         while( ( ret = mbedtls_ssl_handshake( &ssl ) ) != 0 )
444         {
445             if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE )
446             {
447                 mbedtls_printf( " failed\n  ! mbedtls_ssl_handshake returned %d\n\n", ret );
448                 goto ssl_exit;
449             }
450         }
451 
452         mbedtls_printf( " ok\n" );
453 
454         /*
455          * 5. Print the certificate
456          */
457 #if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
458         mbedtls_printf( "  . Peer certificate information    ... skipped\n" );
459 #else
460         mbedtls_printf( "  . Peer certificate information    ...\n" );
461         ret = mbedtls_x509_crt_info( (char *) buf, sizeof( buf ) - 1, "      ",
462                                      mbedtls_ssl_get_peer_cert( &ssl ) );
463         if( ret == -1 )
464         {
465             mbedtls_printf( " failed\n  !  mbedtls_x509_crt_info returned %d\n\n", ret );
466             goto ssl_exit;
467         }
468 
469         mbedtls_printf( "%s\n", buf );
470 #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
471 
472         mbedtls_ssl_close_notify( &ssl );
473 
474 ssl_exit:
475         mbedtls_ssl_free( &ssl );
476         mbedtls_ssl_config_free( &conf );
477     }
478     else
479         goto usage;
480 
481     exit_code = MBEDTLS_EXIT_SUCCESS;
482 
483 exit:
484 
485     mbedtls_net_free( &server_fd );
486     mbedtls_x509_crt_free( &cacert );
487 #if defined(MBEDTLS_X509_CRL_PARSE_C)
488     mbedtls_x509_crl_free( &cacrl );
489 #endif
490     mbedtls_ctr_drbg_free( &ctr_drbg );
491     mbedtls_entropy_free( &entropy );
492 
493 #if defined(_WIN32)
494     mbedtls_printf( "  + Press Enter to exit this program.\n" );
495     fflush( stdout ); getchar();
496 #endif
497 
498     mbedtls_exit( exit_code );
499 }
500 #endif /* MBEDTLS_BIGNUM_C && MBEDTLS_ENTROPY_C && MBEDTLS_SSL_TLS_C &&
501           MBEDTLS_SSL_CLI_C && MBEDTLS_NET_C && MBEDTLS_RSA_C &&
502           MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_FS_IO && MBEDTLS_CTR_DRBG_C */
503