xref: /third_party/openssl/apps/verify.c (revision e1051a39)
1/*
2 * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (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
21static int cb(int ok, X509_STORE_CTX *ctx);
22static 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                 STACK_OF(OPENSSL_STRING) *opts);
26static int v_verbose = 0, vflags = 0;
27
28typedef enum OPTION_choice {
29    OPT_COMMON,
30    OPT_ENGINE, OPT_CAPATH, OPT_CAFILE, OPT_CASTORE,
31    OPT_NOCAPATH, OPT_NOCAFILE, OPT_NOCASTORE,
32    OPT_UNTRUSTED, OPT_TRUSTED, OPT_CRLFILE, OPT_CRL_DOWNLOAD, OPT_SHOW_CHAIN,
33    OPT_V_ENUM, OPT_NAMEOPT, OPT_VFYOPT,
34    OPT_VERBOSE,
35    OPT_PROV_ENUM
36} OPTION_CHOICE;
37
38const OPTIONS verify_options[] = {
39    {OPT_HELP_STR, 1, '-', "Usage: %s [options] [cert...]\n"},
40
41    OPT_SECTION("General"),
42    {"help", OPT_HELP, '-', "Display this summary"},
43#ifndef OPENSSL_NO_ENGINE
44    {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
45#endif
46    {"verbose", OPT_VERBOSE, '-',
47        "Print extra information about the operations being performed."},
48    {"nameopt", OPT_NAMEOPT, 's', "Certificate subject/issuer name printing options"},
49
50    OPT_SECTION("Certificate chain"),
51    {"trusted", OPT_TRUSTED, '<', "A file of trusted certificates"},
52    {"CAfile", OPT_CAFILE, '<', "A file of trusted certificates"},
53    {"CApath", OPT_CAPATH, '/', "A directory of files with trusted certificates"},
54    {"CAstore", OPT_CASTORE, ':', "URI to a store of trusted certificates"},
55    {"no-CAfile", OPT_NOCAFILE, '-',
56     "Do not load the default trusted certificates file"},
57    {"no-CApath", OPT_NOCAPATH, '-',
58     "Do not load trusted certificates from the default directory"},
59    {"no-CAstore", OPT_NOCASTORE, '-',
60     "Do not load trusted certificates from the default certificates store"},
61    {"untrusted", OPT_UNTRUSTED, '<', "A file of untrusted certificates"},
62    {"CRLfile", OPT_CRLFILE, '<',
63        "File containing one or more CRL's (in PEM format) to load"},
64    {"crl_download", OPT_CRL_DOWNLOAD, '-',
65        "Try downloading CRL information for certificates via their CDP entries"},
66    {"show_chain", OPT_SHOW_CHAIN, '-',
67        "Display information about the certificate chain"},
68
69    OPT_V_OPTIONS,
70    {"vfyopt", OPT_VFYOPT, 's', "Verification parameter in n:v form"},
71
72    OPT_PROV_OPTIONS,
73
74    OPT_PARAMETERS(),
75    {"cert", 0, 0, "Certificate(s) to verify (optional; stdin used otherwise)"},
76    {NULL}
77};
78
79int verify_main(int argc, char **argv)
80{
81    ENGINE *e = NULL;
82    STACK_OF(X509) *untrusted = NULL, *trusted = NULL;
83    STACK_OF(X509_CRL) *crls = NULL;
84    STACK_OF(OPENSSL_STRING) *vfyopts = NULL;
85    X509_STORE *store = NULL;
86    X509_VERIFY_PARAM *vpm = NULL;
87    const char *prog, *CApath = NULL, *CAfile = NULL, *CAstore = NULL;
88    int noCApath = 0, noCAfile = 0, noCAstore = 0;
89    int vpmtouched = 0, crl_download = 0, show_chain = 0, i = 0, ret = 1;
90    OPTION_CHOICE o;
91
92    if ((vpm = X509_VERIFY_PARAM_new()) == NULL)
93        goto end;
94
95    prog = opt_init(argc, argv, verify_options);
96    while ((o = opt_next()) != OPT_EOF) {
97        switch (o) {
98        case OPT_EOF:
99        case OPT_ERR:
100 opthelp:
101            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
102            goto end;
103        case OPT_HELP:
104            opt_help(verify_options);
105            BIO_printf(bio_err, "\nRecognized certificate chain purposes:\n");
106            for (i = 0; i < X509_PURPOSE_get_count(); i++) {
107                X509_PURPOSE *ptmp = X509_PURPOSE_get0(i);
108
109                BIO_printf(bio_err, "  %-15s  %s\n",
110                        X509_PURPOSE_get0_sname(ptmp),
111                        X509_PURPOSE_get0_name(ptmp));
112            }
113
114            BIO_printf(bio_err, "Recognized certificate policy names:\n");
115            for (i = 0; i < X509_VERIFY_PARAM_get_count(); i++) {
116                const X509_VERIFY_PARAM *vptmp = X509_VERIFY_PARAM_get0(i);
117
118                BIO_printf(bio_err, "  %s\n",
119                        X509_VERIFY_PARAM_get0_name(vptmp));
120            }
121            ret = 0;
122            goto end;
123        case OPT_V_CASES:
124            if (!opt_verify(o, vpm))
125                goto end;
126            vpmtouched++;
127            break;
128        case OPT_CAPATH:
129            CApath = opt_arg();
130            break;
131        case OPT_CAFILE:
132            CAfile = opt_arg();
133            break;
134        case OPT_CASTORE:
135            CAstore = opt_arg();
136            break;
137        case OPT_NOCAPATH:
138            noCApath = 1;
139            break;
140        case OPT_NOCAFILE:
141            noCAfile = 1;
142            break;
143        case OPT_NOCASTORE:
144            noCAstore = 1;
145            break;
146        case OPT_UNTRUSTED:
147            /* Zero or more times */
148            if (!load_certs(opt_arg(), 0, &untrusted, NULL,
149                            "untrusted certificates"))
150                goto end;
151            break;
152        case OPT_TRUSTED:
153            /* Zero or more times */
154            noCAfile = 1;
155            noCApath = 1;
156            noCAstore = 1;
157            if (!load_certs(opt_arg(), 0, &trusted, NULL, "trusted certificates"))
158                goto end;
159            break;
160        case OPT_CRLFILE:
161            /* Zero or more times */
162            if (!load_crls(opt_arg(), &crls, NULL, "other CRLs"))
163                goto end;
164            break;
165        case OPT_CRL_DOWNLOAD:
166            crl_download = 1;
167            break;
168        case OPT_ENGINE:
169            if ((e = setup_engine(opt_arg(), 0)) == NULL) {
170                /* Failure message already displayed */
171                goto end;
172            }
173            break;
174        case OPT_SHOW_CHAIN:
175            show_chain = 1;
176            break;
177        case OPT_NAMEOPT:
178            if (!set_nameopt(opt_arg()))
179                goto end;
180            break;
181        case OPT_VFYOPT:
182            if (!vfyopts)
183                vfyopts = sk_OPENSSL_STRING_new_null();
184            if (!vfyopts || !sk_OPENSSL_STRING_push(vfyopts, opt_arg()))
185                goto opthelp;
186            break;
187        case OPT_VERBOSE:
188            v_verbose = 1;
189            break;
190        case OPT_PROV_CASES:
191            if (!opt_provider(o))
192                goto end;
193            break;
194        }
195    }
196
197    /* Extra arguments are certificates to verify. */
198    argc = opt_num_rest();
199    argv = opt_rest();
200
201    if (trusted != NULL
202        && (CAfile != NULL || CApath != NULL || CAstore != NULL)) {
203        BIO_printf(bio_err,
204                   "%s: Cannot use -trusted with -CAfile, -CApath or -CAstore\n",
205                   prog);
206        goto end;
207    }
208
209    if ((store = setup_verify(CAfile, noCAfile, CApath, noCApath,
210                              CAstore, noCAstore)) == NULL)
211        goto end;
212    X509_STORE_set_verify_cb(store, cb);
213
214    if (vpmtouched)
215        X509_STORE_set1_param(store, vpm);
216
217    ERR_clear_error();
218
219    if (crl_download)
220        store_setup_crl_download(store);
221
222    ret = 0;
223    if (argc < 1) {
224        if (check(store, NULL, untrusted, trusted, crls, show_chain,
225                  vfyopts) != 1)
226            ret = -1;
227    } else {
228        for (i = 0; i < argc; i++)
229            if (check(store, argv[i], untrusted, trusted, crls, show_chain,
230                      vfyopts) != 1)
231                ret = -1;
232    }
233
234 end:
235    X509_VERIFY_PARAM_free(vpm);
236    X509_STORE_free(store);
237    sk_X509_pop_free(untrusted, X509_free);
238    sk_X509_pop_free(trusted, X509_free);
239    sk_X509_CRL_pop_free(crls, X509_CRL_free);
240    sk_OPENSSL_STRING_free(vfyopts);
241    release_engine(e);
242    return (ret < 0 ? 2 : ret);
243}
244
245static int check(X509_STORE *ctx, const char *file,
246                 STACK_OF(X509) *uchain, STACK_OF(X509) *tchain,
247                 STACK_OF(X509_CRL) *crls, int show_chain,
248                 STACK_OF(OPENSSL_STRING) *opts)
249{
250    X509 *x = NULL;
251    int i = 0, ret = 0;
252    X509_STORE_CTX *csc;
253    STACK_OF(X509) *chain = NULL;
254    int num_untrusted;
255
256    x = load_cert(file, FORMAT_UNDEF, "certificate file");
257    if (x == NULL)
258        goto end;
259
260    if (opts != NULL) {
261        for (i = 0; i < sk_OPENSSL_STRING_num(opts); i++) {
262            char *opt = sk_OPENSSL_STRING_value(opts, i);
263            if (x509_ctrl_string(x, opt) <= 0) {
264                BIO_printf(bio_err, "parameter error \"%s\"\n", opt);
265                ERR_print_errors(bio_err);
266                X509_free(x);
267                return 0;
268            }
269        }
270    }
271
272    csc = X509_STORE_CTX_new();
273    if (csc == NULL) {
274        BIO_printf(bio_err, "error %s: X.509 store context allocation failed\n",
275                   (file == NULL) ? "stdin" : file);
276        goto end;
277    }
278
279    X509_STORE_set_flags(ctx, vflags);
280    if (!X509_STORE_CTX_init(csc, ctx, x, uchain)) {
281        X509_STORE_CTX_free(csc);
282        BIO_printf(bio_err,
283                   "error %s: X.509 store context initialization failed\n",
284                   (file == NULL) ? "stdin" : file);
285        goto end;
286    }
287    if (tchain != NULL)
288        X509_STORE_CTX_set0_trusted_stack(csc, tchain);
289    if (crls != NULL)
290        X509_STORE_CTX_set0_crls(csc, crls);
291    i = X509_verify_cert(csc);
292    if (i > 0 && X509_STORE_CTX_get_error(csc) == X509_V_OK) {
293        BIO_printf(bio_out, "%s: OK\n", (file == NULL) ? "stdin" : file);
294        ret = 1;
295        if (show_chain) {
296            int j;
297
298            chain = X509_STORE_CTX_get1_chain(csc);
299            num_untrusted = X509_STORE_CTX_get_num_untrusted(csc);
300            BIO_printf(bio_out, "Chain:\n");
301            for (j = 0; j < sk_X509_num(chain); j++) {
302                X509 *cert = sk_X509_value(chain, j);
303                BIO_printf(bio_out, "depth=%d: ", j);
304                X509_NAME_print_ex_fp(stdout,
305                                      X509_get_subject_name(cert),
306                                      0, get_nameopt());
307                if (j < num_untrusted)
308                    BIO_printf(bio_out, " (untrusted)");
309                BIO_printf(bio_out, "\n");
310            }
311            sk_X509_pop_free(chain, X509_free);
312        }
313    } else {
314        BIO_printf(bio_err,
315                   "error %s: verification failed\n",
316                   (file == NULL) ? "stdin" : file);
317    }
318    X509_STORE_CTX_free(csc);
319
320 end:
321    if (i <= 0)
322        ERR_print_errors(bio_err);
323    X509_free(x);
324
325    return ret;
326}
327
328static int cb(int ok, X509_STORE_CTX *ctx)
329{
330    int cert_error = X509_STORE_CTX_get_error(ctx);
331    X509 *current_cert = X509_STORE_CTX_get_current_cert(ctx);
332
333    if (!ok) {
334        if (current_cert != NULL) {
335            X509_NAME_print_ex(bio_err,
336                            X509_get_subject_name(current_cert),
337                            0, get_nameopt());
338            BIO_printf(bio_err, "\n");
339        }
340        BIO_printf(bio_err, "%serror %d at %d depth lookup: %s\n",
341               X509_STORE_CTX_get0_parent_ctx(ctx) ? "[CRL path] " : "",
342               cert_error,
343               X509_STORE_CTX_get_error_depth(ctx),
344               X509_verify_cert_error_string(cert_error));
345
346        /*
347         * Pretend that some errors are ok, so they don't stop further
348         * processing of the certificate chain.  Setting ok = 1 does this.
349         * After X509_verify_cert() is done, we verify that there were
350         * no actual errors, even if the returned value was positive.
351         */
352        switch (cert_error) {
353        case X509_V_ERR_NO_EXPLICIT_POLICY:
354            policies_print(ctx);
355            /* fall thru */
356        case X509_V_ERR_CERT_HAS_EXPIRED:
357            /* Continue even if the leaf is a self-signed cert */
358        case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
359            /* Continue after extension errors too */
360        case X509_V_ERR_INVALID_CA:
361        case X509_V_ERR_INVALID_NON_CA:
362        case X509_V_ERR_PATH_LENGTH_EXCEEDED:
363        case X509_V_ERR_CRL_HAS_EXPIRED:
364        case X509_V_ERR_CRL_NOT_YET_VALID:
365        case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
366            /* errors due to strict conformance checking (-x509_strict) */
367        case X509_V_ERR_INVALID_PURPOSE:
368        case X509_V_ERR_PATHLEN_INVALID_FOR_NON_CA:
369        case X509_V_ERR_PATHLEN_WITHOUT_KU_KEY_CERT_SIGN:
370        case X509_V_ERR_CA_BCONS_NOT_CRITICAL:
371        case X509_V_ERR_CA_CERT_MISSING_KEY_USAGE:
372        case X509_V_ERR_KU_KEY_CERT_SIGN_INVALID_FOR_NON_CA:
373        case X509_V_ERR_ISSUER_NAME_EMPTY:
374        case X509_V_ERR_SUBJECT_NAME_EMPTY:
375        case X509_V_ERR_EMPTY_SUBJECT_SAN_NOT_CRITICAL:
376        case X509_V_ERR_EMPTY_SUBJECT_ALT_NAME:
377        case X509_V_ERR_SIGNATURE_ALGORITHM_INCONSISTENCY:
378        case X509_V_ERR_AUTHORITY_KEY_IDENTIFIER_CRITICAL:
379        case X509_V_ERR_SUBJECT_KEY_IDENTIFIER_CRITICAL:
380        case X509_V_ERR_MISSING_AUTHORITY_KEY_IDENTIFIER:
381        case X509_V_ERR_MISSING_SUBJECT_KEY_IDENTIFIER:
382        case X509_V_ERR_EXTENSIONS_REQUIRE_VERSION_3:
383            ok = 1;
384        }
385        return ok;
386
387    }
388    if (cert_error == X509_V_OK && ok == 2)
389        policies_print(ctx);
390    if (!v_verbose)
391        ERR_clear_error();
392    return ok;
393}
394