Home | History | Annotate | Line # | Download | only in apps
      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