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