1 /* 2 * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the OpenSSL license (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include "apps.h" 14 #include "progs.h" 15 #include <openssl/bio.h> 16 #include <openssl/err.h> 17 #include <openssl/x509.h> 18 #include <openssl/x509v3.h> 19 #include <openssl/pem.h> 20 21 static int cb(int ok, X509_STORE_CTX *ctx); 22 static int check(X509_STORE *ctx, const char *file, 23 STACK_OF(X509) *uchain, STACK_OF(X509) *tchain, 24 STACK_OF(X509_CRL) *crls, int show_chain); 25 static int v_verbose = 0, vflags = 0; 26 27 typedef enum OPTION_choice { 28 OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, 29 OPT_ENGINE, OPT_CAPATH, OPT_CAFILE, OPT_NOCAPATH, OPT_NOCAFILE, 30 OPT_UNTRUSTED, OPT_TRUSTED, OPT_CRLFILE, OPT_CRL_DOWNLOAD, OPT_SHOW_CHAIN, 31 OPT_V_ENUM, OPT_NAMEOPT, 32 OPT_VERBOSE 33 } OPTION_CHOICE; 34 35 const OPTIONS verify_options[] = { 36 {OPT_HELP_STR, 1, '-', "Usage: %s [options] cert.pem...\n"}, 37 {OPT_HELP_STR, 1, '-', "Valid options are:\n"}, 38 {"help", OPT_HELP, '-', "Display this summary"}, 39 {"verbose", OPT_VERBOSE, '-', 40 "Print extra information about the operations being performed."}, 41 {"CApath", OPT_CAPATH, '/', "A directory of trusted certificates"}, 42 {"CAfile", OPT_CAFILE, '<', "A file of trusted certificates"}, 43 {"no-CAfile", OPT_NOCAFILE, '-', 44 "Do not load the default certificates file"}, 45 {"no-CApath", OPT_NOCAPATH, '-', 46 "Do not load certificates from the default certificates directory"}, 47 {"untrusted", OPT_UNTRUSTED, '<', "A file of untrusted certificates"}, 48 {"trusted", OPT_TRUSTED, '<', "A file of trusted certificates"}, 49 {"CRLfile", OPT_CRLFILE, '<', 50 "File containing one or more CRL's (in PEM format) to load"}, 51 {"crl_download", OPT_CRL_DOWNLOAD, '-', 52 "Attempt to download CRL information for this certificate"}, 53 {"show_chain", OPT_SHOW_CHAIN, '-', 54 "Display information about the certificate chain"}, 55 {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"}, 56 OPT_V_OPTIONS, 57 #ifndef OPENSSL_NO_ENGINE 58 {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, 59 #endif 60 {NULL} 61 }; 62 63 int verify_main(int argc, char **argv) 64 { 65 ENGINE *e = NULL; 66 STACK_OF(X509) *untrusted = NULL, *trusted = NULL; 67 STACK_OF(X509_CRL) *crls = NULL; 68 X509_STORE *store = NULL; 69 X509_VERIFY_PARAM *vpm = NULL; 70 const char *prog, *CApath = NULL, *CAfile = NULL; 71 int noCApath = 0, noCAfile = 0; 72 int vpmtouched = 0, crl_download = 0, show_chain = 0, i = 0, ret = 1; 73 OPTION_CHOICE o; 74 75 if ((vpm = X509_VERIFY_PARAM_new()) == NULL) 76 goto end; 77 78 prog = opt_init(argc, argv, verify_options); 79 while ((o = opt_next()) != OPT_EOF) { 80 switch (o) { 81 case OPT_EOF: 82 case OPT_ERR: 83 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); 84 goto end; 85 case OPT_HELP: 86 opt_help(verify_options); 87 BIO_printf(bio_err, "Recognized usages:\n"); 88 for (i = 0; i < X509_PURPOSE_get_count(); i++) { 89 X509_PURPOSE *ptmp; 90 ptmp = X509_PURPOSE_get0(i); 91 BIO_printf(bio_err, "\t%-10s\t%s\n", 92 X509_PURPOSE_get0_sname(ptmp), 93 X509_PURPOSE_get0_name(ptmp)); 94 } 95 96 BIO_printf(bio_err, "Recognized verify names:\n"); 97 for (i = 0; i < X509_VERIFY_PARAM_get_count(); i++) { 98 const X509_VERIFY_PARAM *vptmp; 99 vptmp = X509_VERIFY_PARAM_get0(i); 100 BIO_printf(bio_err, "\t%-10s\n", 101 X509_VERIFY_PARAM_get0_name(vptmp)); 102 } 103 ret = 0; 104 goto end; 105 case OPT_V_CASES: 106 if (!opt_verify(o, vpm)) 107 goto end; 108 vpmtouched++; 109 break; 110 case OPT_CAPATH: 111 CApath = opt_arg(); 112 break; 113 case OPT_CAFILE: 114 CAfile = opt_arg(); 115 break; 116 case OPT_NOCAPATH: 117 noCApath = 1; 118 break; 119 case OPT_NOCAFILE: 120 noCAfile = 1; 121 break; 122 case OPT_UNTRUSTED: 123 /* Zero or more times */ 124 if (!load_certs(opt_arg(), &untrusted, FORMAT_PEM, NULL, 125 "untrusted certificates")) 126 goto end; 127 break; 128 case OPT_TRUSTED: 129 /* Zero or more times */ 130 noCAfile = 1; 131 noCApath = 1; 132 if (!load_certs(opt_arg(), &trusted, FORMAT_PEM, NULL, 133 "trusted certificates")) 134 goto end; 135 break; 136 case OPT_CRLFILE: 137 /* Zero or more times */ 138 if (!load_crls(opt_arg(), &crls, FORMAT_PEM, NULL, 139 "other CRLs")) 140 goto end; 141 break; 142 case OPT_CRL_DOWNLOAD: 143 crl_download = 1; 144 break; 145 case OPT_ENGINE: 146 if ((e = setup_engine(opt_arg(), 0)) == NULL) { 147 /* Failure message already displayed */ 148 goto end; 149 } 150 break; 151 case OPT_SHOW_CHAIN: 152 show_chain = 1; 153 break; 154 case OPT_NAMEOPT: 155 if (!set_nameopt(opt_arg())) 156 goto end; 157 break; 158 case OPT_VERBOSE: 159 v_verbose = 1; 160 break; 161 } 162 } 163 argc = opt_num_rest(); 164 argv = opt_rest(); 165 if (trusted != NULL && (CAfile || CApath)) { 166 BIO_printf(bio_err, 167 "%s: Cannot use -trusted with -CAfile or -CApath\n", 168 prog); 169 goto end; 170 } 171 172 if ((store = setup_verify(CAfile, CApath, noCAfile, noCApath)) == NULL) 173 goto end; 174 X509_STORE_set_verify_cb(store, cb); 175 176 if (vpmtouched) 177 X509_STORE_set1_param(store, vpm); 178 179 ERR_clear_error(); 180 181 if (crl_download) 182 store_setup_crl_download(store); 183 184 ret = 0; 185 if (argc < 1) { 186 if (check(store, NULL, untrusted, trusted, crls, show_chain) != 1) 187 ret = -1; 188 } else { 189 for (i = 0; i < argc; i++) 190 if (check(store, argv[i], untrusted, trusted, crls, 191 show_chain) != 1) 192 ret = -1; 193 } 194 195 end: 196 X509_VERIFY_PARAM_free(vpm); 197 X509_STORE_free(store); 198 sk_X509_pop_free(untrusted, X509_free); 199 sk_X509_pop_free(trusted, X509_free); 200 sk_X509_CRL_pop_free(crls, X509_CRL_free); 201 release_engine(e); 202 return (ret < 0 ? 2 : ret); 203 } 204 205 static int check(X509_STORE *ctx, const char *file, 206 STACK_OF(X509) *uchain, STACK_OF(X509) *tchain, 207 STACK_OF(X509_CRL) *crls, int show_chain) 208 { 209 X509 *x = NULL; 210 int i = 0, ret = 0; 211 X509_STORE_CTX *csc; 212 STACK_OF(X509) *chain = NULL; 213 int num_untrusted; 214 215 x = load_cert(file, FORMAT_PEM, "certificate file"); 216 if (x == NULL) 217 goto end; 218 219 csc = X509_STORE_CTX_new(); 220 if (csc == NULL) { 221 printf("error %s: X.509 store context allocation failed\n", 222 (file == NULL) ? "stdin" : file); 223 goto end; 224 } 225 226 X509_STORE_set_flags(ctx, vflags); 227 if (!X509_STORE_CTX_init(csc, ctx, x, uchain)) { 228 X509_STORE_CTX_free(csc); 229 printf("error %s: X.509 store context initialization failed\n", 230 (file == NULL) ? "stdin" : file); 231 goto end; 232 } 233 if (tchain != NULL) 234 X509_STORE_CTX_set0_trusted_stack(csc, tchain); 235 if (crls != NULL) 236 X509_STORE_CTX_set0_crls(csc, crls); 237 i = X509_verify_cert(csc); 238 if (i > 0 && X509_STORE_CTX_get_error(csc) == X509_V_OK) { 239 printf("%s: OK\n", (file == NULL) ? "stdin" : file); 240 ret = 1; 241 if (show_chain) { 242 int j; 243 244 chain = X509_STORE_CTX_get1_chain(csc); 245 num_untrusted = X509_STORE_CTX_get_num_untrusted(csc); 246 printf("Chain:\n"); 247 for (j = 0; j < sk_X509_num(chain); j++) { 248 X509 *cert = sk_X509_value(chain, j); 249 printf("depth=%d: ", j); 250 X509_NAME_print_ex_fp(stdout, 251 X509_get_subject_name(cert), 252 0, get_nameopt()); 253 if (j < num_untrusted) 254 printf(" (untrusted)"); 255 printf("\n"); 256 } 257 sk_X509_pop_free(chain, X509_free); 258 } 259 } else { 260 printf("error %s: verification failed\n", (file == NULL) ? "stdin" : file); 261 } 262 X509_STORE_CTX_free(csc); 263 264 end: 265 if (i <= 0) 266 ERR_print_errors(bio_err); 267 X509_free(x); 268 269 return ret; 270 } 271 272 static int cb(int ok, X509_STORE_CTX *ctx) 273 { 274 int cert_error = X509_STORE_CTX_get_error(ctx); 275 X509 *current_cert = X509_STORE_CTX_get_current_cert(ctx); 276 277 if (!ok) { 278 if (current_cert != NULL) { 279 X509_NAME_print_ex(bio_err, 280 X509_get_subject_name(current_cert), 281 0, get_nameopt()); 282 BIO_printf(bio_err, "\n"); 283 } 284 BIO_printf(bio_err, "%serror %d at %d depth lookup: %s\n", 285 X509_STORE_CTX_get0_parent_ctx(ctx) ? "[CRL path] " : "", 286 cert_error, 287 X509_STORE_CTX_get_error_depth(ctx), 288 X509_verify_cert_error_string(cert_error)); 289 290 /* 291 * Pretend that some errors are ok, so they don't stop further 292 * processing of the certificate chain. Setting ok = 1 does this. 293 * After X509_verify_cert() is done, we verify that there were 294 * no actual errors, even if the returned value was positive. 295 */ 296 switch (cert_error) { 297 case X509_V_ERR_NO_EXPLICIT_POLICY: 298 policies_print(ctx); 299 /* fall thru */ 300 case X509_V_ERR_CERT_HAS_EXPIRED: 301 /* Continue even if the leaf is a self signed cert */ 302 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: 303 /* Continue after extension errors too */ 304 case X509_V_ERR_INVALID_CA: 305 case X509_V_ERR_INVALID_NON_CA: 306 case X509_V_ERR_PATH_LENGTH_EXCEEDED: 307 case X509_V_ERR_INVALID_PURPOSE: 308 case X509_V_ERR_CRL_HAS_EXPIRED: 309 case X509_V_ERR_CRL_NOT_YET_VALID: 310 case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: 311 ok = 1; 312 } 313 314 return ok; 315 316 } 317 if (cert_error == X509_V_OK && ok == 2) 318 policies_print(ctx); 319 if (!v_verbose) 320 ERR_clear_error(); 321 return ok; 322 } 323