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 #define MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS
9 
10 #include "mbedtls/build_info.h"
11 
12 #include "mbedtls/platform.h"
13 
14 #if !defined(MBEDTLS_BIGNUM_C) || !defined(MBEDTLS_ENTROPY_C) ||  \
15     !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_CLI_C) || \
16     !defined(MBEDTLS_NET_C) || !defined(MBEDTLS_RSA_C) ||         \
17     !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_FS_IO) ||  \
18     !defined(MBEDTLS_CTR_DRBG_C) || defined(MBEDTLS_X509_REMOVE_INFO)
main(void)19 int main(void)
20 {
21     mbedtls_printf("MBEDTLS_BIGNUM_C and/or MBEDTLS_ENTROPY_C and/or "
22                    "MBEDTLS_SSL_TLS_C and/or MBEDTLS_SSL_CLI_C and/or "
23                    "MBEDTLS_NET_C and/or MBEDTLS_RSA_C and/or "
24                    "MBEDTLS_X509_CRT_PARSE_C and/or MBEDTLS_FS_IO and/or "
25                    "MBEDTLS_CTR_DRBG_C not defined and/or MBEDTLS_X509_REMOVE_INFO defined.\n");
26     mbedtls_exit(0);
27 }
28 #else
29 
30 #include "mbedtls/entropy.h"
31 #include "mbedtls/ctr_drbg.h"
32 #include "mbedtls/net_sockets.h"
33 #include "mbedtls/ssl.h"
34 #include "mbedtls/x509.h"
35 #include "mbedtls/debug.h"
36 
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 
41 #define MODE_NONE               0
42 #define MODE_FILE               1
43 #define MODE_SSL                2
44 
45 #define DFL_MODE                MODE_NONE
46 #define DFL_FILENAME            "cert.crt"
47 #define DFL_CA_FILE             ""
48 #define DFL_CRL_FILE            ""
49 #define DFL_CA_PATH             ""
50 #define DFL_SERVER_NAME         "localhost"
51 #define DFL_SERVER_PORT         "4433"
52 #define DFL_DEBUG_LEVEL         0
53 #define DFL_PERMISSIVE          0
54 
55 #define USAGE_IO \
56     "    ca_file=%%s          The single file containing the top-level CA(s) you fully trust\n" \
57     "                        default: \"\" (none)\n" \
58     "    crl_file=%%s         The single CRL file you want to use\n" \
59     "                        default: \"\" (none)\n" \
60     "    ca_path=%%s          The path containing the top-level CA(s) you fully trust\n" \
61     "                        default: \"\" (none) (overrides ca_file)\n"
62 
63 #define USAGE \
64     "\n usage: cert_app param=<>...\n"                  \
65     "\n acceptable parameters:\n"                       \
66     "    mode=file|ssl       default: none\n"           \
67     "    filename=%%s         default: cert.crt\n"      \
68     USAGE_IO                                            \
69     "    server_name=%%s      default: localhost\n"     \
70     "    server_port=%%d      default: 4433\n"          \
71     "    debug_level=%%d      default: 0 (disabled)\n"  \
72     "    permissive=%%d       default: 0 (disabled)\n"  \
73     "\n"
74 
75 
76 /*
77  * global options
78  */
79 struct options {
80     int mode;                   /* the mode to run the application in   */
81     const char *filename;       /* filename of the certificate file     */
82     const char *ca_file;        /* the file with the CA certificate(s)  */
83     const char *crl_file;       /* the file with the CRL to use         */
84     const char *ca_path;        /* the path with the CA certificate(s) reside */
85     const char *server_name;    /* hostname of the server (client only) */
86     const char *server_port;    /* port on which the ssl service runs   */
87     int debug_level;            /* level of debugging                   */
88     int permissive;             /* permissive parsing                   */
89 } opt;
90 
my_debug(void * ctx,int level,const char * file,int line,const char * str)91 static void my_debug(void *ctx, int level,
92                      const char *file, int line,
93                      const char *str)
94 {
95     ((void) level);
96 
97     mbedtls_fprintf((FILE *) ctx, "%s:%04d: %s", file, line, str);
98     fflush((FILE *) ctx);
99 }
100 
my_verify(void * data,mbedtls_x509_crt * crt,int depth,uint32_t * flags)101 static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
102 {
103     char buf[1024];
104     ((void) data);
105 
106     mbedtls_printf("\nVerify requested for (Depth %d):\n", depth);
107     mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "", crt);
108     mbedtls_printf("%s", buf);
109 
110     if ((*flags) == 0) {
111         mbedtls_printf("  This certificate has no flags\n");
112     } else {
113         mbedtls_x509_crt_verify_info(buf, sizeof(buf), "  ! ", *flags);
114         mbedtls_printf("%s\n", buf);
115     }
116 
117     return 0;
118 }
119 
main(int argc,char * argv[])120 int main(int argc, char *argv[])
121 {
122     int ret = 1;
123     int exit_code = MBEDTLS_EXIT_FAILURE;
124     mbedtls_net_context server_fd;
125     unsigned char buf[1024];
126     mbedtls_entropy_context entropy;
127     mbedtls_ctr_drbg_context ctr_drbg;
128     mbedtls_ssl_context ssl;
129     mbedtls_ssl_config conf;
130     mbedtls_x509_crt cacert;
131     mbedtls_x509_crl cacrl;
132     int i, j;
133     uint32_t flags;
134     int verify = 0;
135     char *p, *q;
136     const char *pers = "cert_app";
137 
138     /*
139      * Set to sane values
140      */
141     mbedtls_net_init(&server_fd);
142     mbedtls_ctr_drbg_init(&ctr_drbg);
143     mbedtls_ssl_init(&ssl);
144     mbedtls_ssl_config_init(&conf);
145     mbedtls_x509_crt_init(&cacert);
146     mbedtls_entropy_init(&entropy);
147 #if defined(MBEDTLS_X509_CRL_PARSE_C)
148     mbedtls_x509_crl_init(&cacrl);
149 #else
150     /* Zeroize structure as CRL parsing is not supported and we have to pass
151        it to the verify function */
152     memset(&cacrl, 0, sizeof(mbedtls_x509_crl));
153 #endif
154 
155     psa_status_t status = psa_crypto_init();
156     if (status != PSA_SUCCESS) {
157         mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
158                         (int) status);
159         goto exit;
160     }
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_dbg(&conf, my_debug, stdout);
385 
386         if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
387             mbedtls_printf(" failed\n  ! mbedtls_ssl_setup returned %d\n\n", ret);
388             goto ssl_exit;
389         }
390 
391         if ((ret = mbedtls_ssl_set_hostname(&ssl, opt.server_name)) != 0) {
392             mbedtls_printf(" failed\n  ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
393             goto ssl_exit;
394         }
395 
396         mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
397 
398         /*
399          * 4. Handshake
400          */
401         while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
402             if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
403                 mbedtls_printf(" failed\n  ! mbedtls_ssl_handshake returned %d\n\n", ret);
404                 goto ssl_exit;
405             }
406         }
407 
408         mbedtls_printf(" ok\n");
409 
410         /*
411          * 5. Print the certificate
412          */
413 #if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
414         mbedtls_printf("  . Peer certificate information    ... skipped\n");
415 #else
416         mbedtls_printf("  . Peer certificate information    ...\n");
417         ret = mbedtls_x509_crt_info((char *) buf, sizeof(buf) - 1, "      ",
418                                     mbedtls_ssl_get_peer_cert(&ssl));
419         if (ret == -1) {
420             mbedtls_printf(" failed\n  !  mbedtls_x509_crt_info returned %d\n\n", ret);
421             goto ssl_exit;
422         }
423 
424         mbedtls_printf("%s\n", buf);
425 #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
426 
427         mbedtls_ssl_close_notify(&ssl);
428 
429 ssl_exit:
430         mbedtls_ssl_free(&ssl);
431         mbedtls_ssl_config_free(&conf);
432     } else {
433         goto usage;
434     }
435 
436     exit_code = MBEDTLS_EXIT_SUCCESS;
437 
438 exit:
439 
440     mbedtls_net_free(&server_fd);
441     mbedtls_x509_crt_free(&cacert);
442 #if defined(MBEDTLS_X509_CRL_PARSE_C)
443     mbedtls_x509_crl_free(&cacrl);
444 #endif
445     mbedtls_ctr_drbg_free(&ctr_drbg);
446     mbedtls_entropy_free(&entropy);
447     mbedtls_psa_crypto_free();
448 
449     mbedtls_exit(exit_code);
450 }
451 #endif /* MBEDTLS_BIGNUM_C && MBEDTLS_ENTROPY_C && MBEDTLS_SSL_TLS_C &&
452           MBEDTLS_SSL_CLI_C && MBEDTLS_NET_C && MBEDTLS_RSA_C &&
453           MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_FS_IO && MBEDTLS_CTR_DRBG_C */
454