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