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)
17int 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 */
77struct 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
89static 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
99static 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
118int 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) {
163usage:
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
430ssl_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
439exit:
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