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