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