[BACK]Return to verify.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / openssl

Annotation of src/usr.bin/openssl/verify.c, Revision 1.17

1.17    ! tb          1: /* $OpenBSD: verify.c,v 1.16 2023/03/06 14:32:06 tb Exp $ */
1.1       jsing       2: /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
                      3:  * All rights reserved.
                      4:  *
                      5:  * This package is an SSL implementation written
                      6:  * by Eric Young (eay@cryptsoft.com).
                      7:  * The implementation was written so as to conform with Netscapes SSL.
                      8:  *
                      9:  * This library is free for commercial and non-commercial use as long as
                     10:  * the following conditions are aheared to.  The following conditions
                     11:  * apply to all code found in this distribution, be it the RC4, RSA,
                     12:  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
                     13:  * included with this distribution is covered by the same copyright terms
                     14:  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
                     15:  *
                     16:  * Copyright remains Eric Young's, and as such any Copyright notices in
                     17:  * the code are not to be removed.
                     18:  * If this package is used in a product, Eric Young should be given attribution
                     19:  * as the author of the parts of the library used.
                     20:  * This can be in the form of a textual message at program startup or
                     21:  * in documentation (online or textual) provided with the package.
                     22:  *
                     23:  * Redistribution and use in source and binary forms, with or without
                     24:  * modification, are permitted provided that the following conditions
                     25:  * are met:
                     26:  * 1. Redistributions of source code must retain the copyright
                     27:  *    notice, this list of conditions and the following disclaimer.
                     28:  * 2. Redistributions in binary form must reproduce the above copyright
                     29:  *    notice, this list of conditions and the following disclaimer in the
                     30:  *    documentation and/or other materials provided with the distribution.
                     31:  * 3. All advertising materials mentioning features or use of this software
                     32:  *    must display the following acknowledgement:
                     33:  *    "This product includes cryptographic software written by
                     34:  *     Eric Young (eay@cryptsoft.com)"
                     35:  *    The word 'cryptographic' can be left out if the rouines from the library
                     36:  *    being used are not cryptographic related :-).
                     37:  * 4. If you include any Windows specific code (or a derivative thereof) from
                     38:  *    the apps directory (application code) you must include an acknowledgement:
                     39:  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
                     40:  *
                     41:  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
                     42:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     43:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     44:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     45:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     46:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     47:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     48:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     49:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     50:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     51:  * SUCH DAMAGE.
                     52:  *
                     53:  * The licence and distribution terms for any publically available version or
                     54:  * derivative of this code cannot be changed.  i.e. this code cannot simply be
                     55:  * copied and put under another distribution licence
                     56:  * [including the GNU Public Licence.]
                     57:  */
                     58:
                     59: #include <stdio.h>
                     60: #include <stdlib.h>
                     61: #include <string.h>
                     62:
                     63: #include "apps.h"
                     64:
                     65: #include <openssl/bio.h>
                     66: #include <openssl/err.h>
                     67: #include <openssl/pem.h>
                     68: #include <openssl/x509.h>
                     69: #include <openssl/x509v3.h>
                     70:
1.11      tb         71: static int cb(int ok, X509_STORE_CTX *ctx);
                     72: static int check(X509_STORE *ctx, char *file, STACK_OF(X509) *uchain,
                     73:     STACK_OF(X509) *tchain, STACK_OF(X509_CRL) *crls);
1.8       jsing      74: static int vflags = 0;
                     75:
                     76: static struct {
                     77:        char *CAfile;
                     78:        char *CApath;
                     79:        char *crlfile;
                     80:        char *trustfile;
                     81:        char *untfile;
                     82:        int verbose;
                     83:        X509_VERIFY_PARAM *vpm;
1.16      tb         84: } cfg;
1.8       jsing      85:
                     86: static int
                     87: verify_opt_args(int argc, char **argv, int *argsused)
                     88: {
                     89:        int oargc = argc;
                     90:        int badarg = 0;
                     91:
1.16      tb         92:        if (!args_verify(&argv, &argc, &badarg, bio_err, &cfg.vpm))
1.8       jsing      93:                return (1);
                     94:        if (badarg)
                     95:                return (1);
                     96:
                     97:        *argsused = oargc - argc;
                     98:
                     99:        return (0);
                    100: }
                    101:
                    102: static const struct option verify_options[] = {
                    103:        {
                    104:                .name = "CAfile",
                    105:                .argname = "file",
                    106:                .desc = "Certificate Authority file",
                    107:                .type = OPTION_ARG,
1.16      tb        108:                .opt.arg = &cfg.CAfile,
1.8       jsing     109:        },
                    110:        {
                    111:                .name = "CApath",
                    112:                .argname = "path",
                    113:                .desc = "Certificate Authority path",
                    114:                .type = OPTION_ARG,
1.16      tb        115:                .opt.arg = &cfg.CApath,
1.8       jsing     116:        },
                    117:        {
                    118:                .name = "CRLfile",
                    119:                .argname = "file",
                    120:                .desc = "Certificate Revocation List file",
                    121:                .type = OPTION_ARG,
1.16      tb        122:                .opt.arg = &cfg.crlfile,
1.8       jsing     123:        },
                    124:        {
                    125:                .name = "trusted",
                    126:                .argname = "file",
                    127:                .desc = "Trusted certificates file",
                    128:                .type = OPTION_ARG,
1.16      tb        129:                .opt.arg = &cfg.trustfile,
1.8       jsing     130:        },
                    131:        {
                    132:                .name = "untrusted",
                    133:                .argname = "file",
                    134:                .desc = "Untrusted certificates file",
                    135:                .type = OPTION_ARG,
1.16      tb        136:                .opt.arg = &cfg.untfile,
1.8       jsing     137:        },
                    138:        {
                    139:                .name = "verbose",
                    140:                .desc = "Verbose",
                    141:                .type = OPTION_FLAG,
1.16      tb        142:                .opt.flag = &cfg.verbose,
1.8       jsing     143:        },
                    144:        {
                    145:                .name = NULL,
                    146:                .desc = "",
                    147:                .type = OPTION_ARGV_FUNC,
                    148:                .opt.argvfunc = verify_opt_args,
                    149:        },
                    150:        { NULL },
                    151: };
                    152:
                    153: static const struct option verify_shared_options[] = {
                    154:        {
                    155:                .name = "attime",
                    156:                .argname = "epoch",
                    157:                .desc = "Use epoch as the verification time",
                    158:        },
                    159:        {
                    160:                .name = "check_ss_sig",
                    161:                .desc = "Check the root CA self-signed certificate signature",
                    162:        },
                    163:        {
                    164:                .name = "crl_check",
                    165:                .desc = "Enable CRL checking for the leaf certificate",
                    166:        },
                    167:        {
                    168:                .name = "crl_check_all",
                    169:                .desc = "Enable CRL checking for the entire certificate chain",
                    170:        },
                    171:        {
                    172:                .name = "explicit_policy",
                    173:                .desc = "Require explicit policy (per RFC 3280)",
                    174:        },
                    175:        {
                    176:                .name = "extended_crl",
                    177:                .desc = "Enable extended CRL support",
                    178:        },
                    179:        {
                    180:                .name = "ignore_critical",
                    181:                .desc = "Disable critical extension checking",
                    182:        },
                    183:        {
                    184:                .name = "inhibit_any",
                    185:                .desc = "Inhibit any policy (per RFC 3280)",
                    186:        },
                    187:        {
                    188:                .name = "inhibit_map",
                    189:                .desc = "Inhibit policy mapping (per RFC 3280)",
                    190:        },
                    191:        {
                    192:                .name = "issuer_checks",
                    193:                .desc = "Enable debugging of certificate issuer checks",
1.9       tb        194:        },
                    195:        {
                    196:                .name = "legacy_verify",
                    197:                .desc = "Use legacy certificate chain verification",
1.8       jsing     198:        },
                    199:        {
                    200:                .name = "policy",
                    201:                .argname = "name",
                    202:                .desc = "Add given policy to the acceptable set",
                    203:        },
                    204:        {
                    205:                .name = "policy_check",
                    206:                .desc = "Enable certificate policy checking",
                    207:        },
                    208:        {
                    209:                .name = "policy_print",
                    210:                .desc = "Print policy",
                    211:        },
                    212:        {
                    213:                .name = "purpose",
                    214:                .argname = "name",
                    215:                .desc = "Verify for the given purpose",
                    216:        },
                    217:        {
                    218:                .name = "use_deltas",
                    219:                .desc = "Use delta CRLS (if present)",
                    220:        },
                    221:        {
                    222:                .name = "verify_depth",
                    223:                .argname = "num",
                    224:                .desc = "Limit verification to the given depth",
                    225:        },
                    226:        {
                    227:                .name = "x509_strict",
                    228:                .desc = "Use strict X.509 rules (disables workarounds)",
                    229:        },
                    230:        { NULL },
                    231: };
                    232:
                    233: static void
                    234: verify_usage(void)
                    235: {
                    236:        int i;
                    237:
                    238:        fprintf(stderr,
                    239:            "usage: verify [-CAfile file] [-CApath directory] [-check_ss_sig]\n"
                    240:            "    [-CRLfile file] [-crl_check] [-crl_check_all]\n"
                    241:            "    [-explicit_policy] [-extended_crl]\n"
                    242:            "    [-ignore_critical] [-inhibit_any] [-inhibit_map]\n"
                    243:            "    [-issuer_checks] [-policy_check] [-purpose purpose]\n"
                    244:            "    [-trusted file] [-untrusted file] [-verbose]\n"
                    245:            "    [-x509_strict] [certificates]\n\n");
                    246:
                    247:        options_usage(verify_options);
                    248:
                    249:        fprintf(stderr, "\nVerification options:\n\n");
                    250:        options_usage(verify_shared_options);
                    251:
                    252:        fprintf(stderr, "\nValid purposes:\n\n");
                    253:        for (i = 0; i < X509_PURPOSE_get_count(); i++) {
                    254:                X509_PURPOSE *ptmp = X509_PURPOSE_get0(i);
                    255:                fprintf(stderr, "  %-18s%s\n", X509_PURPOSE_get0_sname(ptmp),
                    256:                    X509_PURPOSE_get0_name(ptmp));
                    257:        }
                    258: }
1.1       jsing     259:
                    260: int
                    261: verify_main(int argc, char **argv)
                    262: {
1.8       jsing     263:        STACK_OF(X509) *untrusted = NULL, *trusted = NULL;
                    264:        STACK_OF(X509_CRL) *crls = NULL;
1.1       jsing     265:        X509_STORE *cert_ctx = NULL;
                    266:        X509_LOOKUP *lookup = NULL;
1.8       jsing     267:        char **cert_files = NULL;
                    268:        int argsused;
1.12      tb        269:        int ret = 1;
1.5       doug      270:
1.15      joshua    271:        if (pledge("stdio rpath", NULL) == -1) {
                    272:                perror("pledge");
                    273:                exit(1);
1.5       doug      274:        }
1.1       jsing     275:
1.16      tb        276:        memset(&cfg, 0, sizeof(cfg));
1.8       jsing     277:
                    278:        if (options_parse(argc, argv, verify_options, NULL, &argsused) != 0) {
                    279:                verify_usage();
                    280:                goto end;
                    281:        }
                    282:
                    283:        if (argsused < argc)
                    284:                cert_files = &argv[argsused];
                    285:
1.1       jsing     286:        cert_ctx = X509_STORE_new();
                    287:        if (cert_ctx == NULL)
                    288:                goto end;
                    289:        X509_STORE_set_verify_cb(cert_ctx, cb);
                    290:
1.16      tb        291:        if (cfg.vpm)
                    292:                X509_STORE_set1_param(cert_ctx, cfg.vpm);
1.1       jsing     293:
                    294:        lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file());
                    295:        if (lookup == NULL)
1.8       jsing     296:                abort(); /* XXX */
1.16      tb        297:        if (cfg.CAfile) {
                    298:                if (!X509_LOOKUP_load_file(lookup, cfg.CAfile,
1.12      tb        299:                    X509_FILETYPE_PEM)) {
                    300:                        BIO_printf(bio_err, "Error loading file %s\n",
1.16      tb        301:                            cfg.CAfile);
1.1       jsing     302:                        ERR_print_errors(bio_err);
                    303:                        goto end;
                    304:                }
                    305:        } else
                    306:                X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT);
                    307:
                    308:        lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_hash_dir());
                    309:        if (lookup == NULL)
1.8       jsing     310:                abort(); /* XXX */
1.16      tb        311:        if (cfg.CApath) {
                    312:                if (!X509_LOOKUP_add_dir(lookup, cfg.CApath,
1.12      tb        313:                    X509_FILETYPE_PEM)) {
                    314:                        BIO_printf(bio_err, "Error loading directory %s\n",
1.16      tb        315:                            cfg.CApath);
1.1       jsing     316:                        ERR_print_errors(bio_err);
                    317:                        goto end;
                    318:                }
                    319:        } else
                    320:                X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT);
                    321:
                    322:        ERR_clear_error();
                    323:
1.16      tb        324:        if (cfg.untfile) {
                    325:                untrusted = load_certs(bio_err, cfg.untfile,
1.13      tb        326:                    FORMAT_PEM, NULL, "untrusted certificates");
1.1       jsing     327:                if (!untrusted)
                    328:                        goto end;
                    329:        }
1.16      tb        330:        if (cfg.trustfile) {
                    331:                trusted = load_certs(bio_err, cfg.trustfile,
1.13      tb        332:                    FORMAT_PEM, NULL, "trusted certificates");
1.1       jsing     333:                if (!trusted)
                    334:                        goto end;
                    335:        }
1.16      tb        336:        if (cfg.crlfile) {
                    337:                crls = load_crls(bio_err, cfg.crlfile, FORMAT_PEM,
1.4       bcook     338:                    NULL, "other CRLs");
1.1       jsing     339:                if (!crls)
                    340:                        goto end;
                    341:        }
                    342:        ret = 0;
1.8       jsing     343:        if (cert_files == NULL) {
1.4       bcook     344:                if (1 != check(cert_ctx, NULL, untrusted, trusted, crls))
1.1       jsing     345:                        ret = -1;
                    346:        } else {
1.8       jsing     347:                do {
1.13      tb        348:                        if (1 != check(cert_ctx, *cert_files++, untrusted,
                    349:                            trusted, crls))
1.1       jsing     350:                                ret = -1;
1.8       jsing     351:                } while (*cert_files != NULL);
1.1       jsing     352:        }
                    353:
1.7       jsing     354:  end:
1.16      tb        355:        if (cfg.vpm)
                    356:                X509_VERIFY_PARAM_free(cfg.vpm);
1.1       jsing     357:        if (cert_ctx != NULL)
                    358:                X509_STORE_free(cert_ctx);
                    359:        sk_X509_pop_free(untrusted, X509_free);
                    360:        sk_X509_pop_free(trusted, X509_free);
                    361:        sk_X509_CRL_pop_free(crls, X509_CRL_free);
                    362:
                    363:        return (ret < 0 ? 2 : ret);
                    364: }
                    365:
                    366: static int
1.10      tb        367: check(X509_STORE *ctx, char *file, STACK_OF(X509) *uchain,
                    368:     STACK_OF(X509) *tchain, STACK_OF(X509_CRL) *crls)
1.1       jsing     369: {
                    370:        X509 *x = NULL;
1.10      tb        371:        X509_STORE_CTX *csc = NULL;
                    372:        const char *certfile = (file == NULL) ? "stdin" : file;
                    373:        int verify_err;
1.1       jsing     374:        int i = 0, ret = 0;
                    375:
1.4       bcook     376:        x = load_cert(bio_err, file, FORMAT_PEM, NULL, "certificate file");
1.1       jsing     377:        if (x == NULL)
                    378:                goto end;
                    379:
1.10      tb        380:        if ((csc = X509_STORE_CTX_new()) == NULL)
1.1       jsing     381:                goto end;
                    382:        X509_STORE_set_flags(ctx, vflags);
1.10      tb        383:        if (!X509_STORE_CTX_init(csc, ctx, x, uchain))
1.1       jsing     384:                goto end;
                    385:        if (tchain)
                    386:                X509_STORE_CTX_trusted_stack(csc, tchain);
                    387:        if (crls)
                    388:                X509_STORE_CTX_set0_crls(csc, crls);
1.10      tb        389:
1.1       jsing     390:        i = X509_verify_cert(csc);
1.10      tb        391:        verify_err = X509_STORE_CTX_get_error(csc);
1.1       jsing     392:
1.10      tb        393:        if (i > 0 && verify_err == X509_V_OK) {
1.14      jsing     394:                fprintf(stdout, "%s: OK\n", certfile);
1.10      tb        395:                ret = 1;
                    396:        } else {
                    397:                fprintf(stdout, "%s: verification failed: %d (%s)\n", certfile,
                    398:                    verify_err, X509_verify_cert_error_string(verify_err));
                    399:        }
1.1       jsing     400:
1.7       jsing     401:  end:
1.10      tb        402:        if (i <= 0)
1.1       jsing     403:                ERR_print_errors(bio_err);
1.10      tb        404:        X509_free(x);
                    405:        X509_STORE_CTX_free(csc);
1.1       jsing     406:
                    407:        return (ret);
                    408: }
                    409:
                    410: static int
1.11      tb        411: cb(int ok, X509_STORE_CTX *ctx)
1.1       jsing     412: {
                    413:        int cert_error = X509_STORE_CTX_get_error(ctx);
                    414:        X509 *current_cert = X509_STORE_CTX_get_current_cert(ctx);
                    415:
                    416:        if (!ok) {
                    417:                if (current_cert) {
                    418:                        X509_NAME_print_ex_fp(stdout,
                    419:                            X509_get_subject_name(current_cert),
                    420:                            0, XN_FLAG_ONELINE);
                    421:                        printf("\n");
                    422:                }
                    423:                printf("%serror %d at %d depth lookup:%s\n",
                    424:                    X509_STORE_CTX_get0_parent_ctx(ctx) ? "[CRL path]" : "",
                    425:                    cert_error,
                    426:                    X509_STORE_CTX_get_error_depth(ctx),
                    427:                    X509_verify_cert_error_string(cert_error));
                    428:                switch (cert_error) {
                    429:                case X509_V_ERR_NO_EXPLICIT_POLICY:
                    430:                case X509_V_ERR_CERT_HAS_EXPIRED:
                    431:
                    432:                        /*
                    433:                         * since we are just checking the certificates, it is
                    434:                         * ok if they are self signed. But we should still
                    435:                         * warn the user.
                    436:                         */
                    437:
                    438:                case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
                    439:                        /* Continue after extension errors too */
                    440:                case X509_V_ERR_INVALID_CA:
                    441:                case X509_V_ERR_INVALID_NON_CA:
                    442:                case X509_V_ERR_PATH_LENGTH_EXCEEDED:
                    443:                case X509_V_ERR_INVALID_PURPOSE:
                    444:                case X509_V_ERR_CRL_HAS_EXPIRED:
                    445:                case X509_V_ERR_CRL_NOT_YET_VALID:
                    446:                case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
                    447:                        ok = 1;
                    448:
                    449:                }
                    450:
                    451:                return ok;
                    452:
                    453:        }
1.16      tb        454:        if (!cfg.verbose)
1.1       jsing     455:                ERR_clear_error();
                    456:        return (ok);
                    457: }