155714Skris/* apps/verify.c */
255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
355714Skris * All rights reserved.
455714Skris *
555714Skris * This package is an SSL implementation written
655714Skris * by Eric Young (eay@cryptsoft.com).
755714Skris * The implementation was written so as to conform with Netscapes SSL.
8280304Sjkim *
955714Skris * This library is free for commercial and non-commercial use as long as
1055714Skris * the following conditions are aheared to.  The following conditions
1155714Skris * apply to all code found in this distribution, be it the RC4, RSA,
1255714Skris * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1355714Skris * included with this distribution is covered by the same copyright terms
1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15280304Sjkim *
1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in
1755714Skris * the code are not to be removed.
1855714Skris * If this package is used in a product, Eric Young should be given attribution
1955714Skris * as the author of the parts of the library used.
2055714Skris * This can be in the form of a textual message at program startup or
2155714Skris * in documentation (online or textual) provided with the package.
22280304Sjkim *
2355714Skris * Redistribution and use in source and binary forms, with or without
2455714Skris * modification, are permitted provided that the following conditions
2555714Skris * are met:
2655714Skris * 1. Redistributions of source code must retain the copyright
2755714Skris *    notice, this list of conditions and the following disclaimer.
2855714Skris * 2. Redistributions in binary form must reproduce the above copyright
2955714Skris *    notice, this list of conditions and the following disclaimer in the
3055714Skris *    documentation and/or other materials provided with the distribution.
3155714Skris * 3. All advertising materials mentioning features or use of this software
3255714Skris *    must display the following acknowledgement:
3355714Skris *    "This product includes cryptographic software written by
3455714Skris *     Eric Young (eay@cryptsoft.com)"
3555714Skris *    The word 'cryptographic' can be left out if the rouines from the library
3655714Skris *    being used are not cryptographic related :-).
37280304Sjkim * 4. If you include any Windows specific code (or a derivative thereof) from
3855714Skris *    the apps directory (application code) you must include an acknowledgement:
3955714Skris *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40280304Sjkim *
4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4455714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5155714Skris * SUCH DAMAGE.
52280304Sjkim *
5355714Skris * The licence and distribution terms for any publically available version or
5455714Skris * derivative of this code cannot be changed.  i.e. this code cannot simply be
5555714Skris * copied and put under another distribution licence
5655714Skris * [including the GNU Public Licence.]
5755714Skris */
5855714Skris
5955714Skris#include <stdio.h>
6055714Skris#include <stdlib.h>
6155714Skris#include <string.h>
6255714Skris#include "apps.h"
6355714Skris#include <openssl/bio.h>
6455714Skris#include <openssl/err.h>
6555714Skris#include <openssl/x509.h>
6659191Skris#include <openssl/x509v3.h>
6755714Skris#include <openssl/pem.h>
6855714Skris
6955714Skris#undef PROG
70280304Sjkim#define PROG    verify_main
7155714Skris
7255714Skrisstatic int MS_CALLBACK cb(int ok, X509_STORE_CTX *ctx);
73238405Sjkimstatic int check(X509_STORE *ctx, char *file,
74280304Sjkim                 STACK_OF(X509) *uchain, STACK_OF(X509) *tchain,
75280304Sjkim                 STACK_OF(X509_CRL) *crls, ENGINE *e);
76280304Sjkimstatic int v_verbose = 0, vflags = 0;
7755714Skris
7859191Skrisint MAIN(int, char **);
7959191Skris
8055714Skrisint MAIN(int argc, char **argv)
81280304Sjkim{
82280304Sjkim    ENGINE *e = NULL;
83280304Sjkim    int i, ret = 1, badarg = 0;
84280304Sjkim    char *CApath = NULL, *CAfile = NULL;
85280304Sjkim    char *untfile = NULL, *trustfile = NULL, *crlfile = NULL;
86280304Sjkim    STACK_OF(X509) *untrusted = NULL, *trusted = NULL;
87280304Sjkim    STACK_OF(X509_CRL) *crls = NULL;
88280304Sjkim    X509_STORE *cert_ctx = NULL;
89280304Sjkim    X509_LOOKUP *lookup = NULL;
90280304Sjkim    X509_VERIFY_PARAM *vpm = NULL;
91111147Snectar#ifndef OPENSSL_NO_ENGINE
92280304Sjkim    char *engine = NULL;
93111147Snectar#endif
9455714Skris
95280304Sjkim    cert_ctx = X509_STORE_new();
96280304Sjkim    if (cert_ctx == NULL)
97280304Sjkim        goto end;
98280304Sjkim    X509_STORE_set_verify_cb(cert_ctx, cb);
9955714Skris
100280304Sjkim    ERR_load_crypto_strings();
10155714Skris
102280304Sjkim    apps_startup();
10355714Skris
104280304Sjkim    if (bio_err == NULL)
105280304Sjkim        if ((bio_err = BIO_new(BIO_s_file())) != NULL)
106280304Sjkim            BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
10755714Skris
108280304Sjkim    if (!load_config(bio_err, NULL))
109280304Sjkim        goto end;
110109998Smarkm
111280304Sjkim    argc--;
112280304Sjkim    argv++;
113280304Sjkim    for (;;) {
114280304Sjkim        if (argc >= 1) {
115280304Sjkim            if (strcmp(*argv, "-CApath") == 0) {
116280304Sjkim                if (argc-- < 1)
117280304Sjkim                    goto end;
118280304Sjkim                CApath = *(++argv);
119280304Sjkim            } else if (strcmp(*argv, "-CAfile") == 0) {
120280304Sjkim                if (argc-- < 1)
121280304Sjkim                    goto end;
122280304Sjkim                CAfile = *(++argv);
123280304Sjkim            } else if (args_verify(&argv, &argc, &badarg, bio_err, &vpm)) {
124280304Sjkim                if (badarg)
125280304Sjkim                    goto end;
126280304Sjkim                continue;
127280304Sjkim            } else if (strcmp(*argv, "-untrusted") == 0) {
128280304Sjkim                if (argc-- < 1)
129280304Sjkim                    goto end;
130280304Sjkim                untfile = *(++argv);
131280304Sjkim            } else if (strcmp(*argv, "-trusted") == 0) {
132280304Sjkim                if (argc-- < 1)
133280304Sjkim                    goto end;
134280304Sjkim                trustfile = *(++argv);
135280304Sjkim            } else if (strcmp(*argv, "-CRLfile") == 0) {
136280304Sjkim                if (argc-- < 1)
137280304Sjkim                    goto end;
138280304Sjkim                crlfile = *(++argv);
139280304Sjkim            }
140111147Snectar#ifndef OPENSSL_NO_ENGINE
141280304Sjkim            else if (strcmp(*argv, "-engine") == 0) {
142280304Sjkim                if (--argc < 1)
143280304Sjkim                    goto end;
144280304Sjkim                engine = *(++argv);
145280304Sjkim            }
146111147Snectar#endif
147280304Sjkim            else if (strcmp(*argv, "-help") == 0)
148280304Sjkim                goto end;
149280304Sjkim            else if (strcmp(*argv, "-verbose") == 0)
150280304Sjkim                v_verbose = 1;
151280304Sjkim            else if (argv[0][0] == '-')
152280304Sjkim                goto end;
153280304Sjkim            else
154280304Sjkim                break;
155280304Sjkim            argc--;
156280304Sjkim            argv++;
157280304Sjkim        } else
158280304Sjkim            break;
159280304Sjkim    }
16055714Skris
161111147Snectar#ifndef OPENSSL_NO_ENGINE
162280304Sjkim    e = setup_engine(bio_err, engine, 0);
163111147Snectar#endif
164109998Smarkm
165280304Sjkim    if (vpm)
166280304Sjkim        X509_STORE_set1_param(cert_ctx, vpm);
167160814Ssimon
168280304Sjkim    lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file());
169280304Sjkim    if (lookup == NULL)
170280304Sjkim        abort();
171280304Sjkim    if (CAfile) {
172280304Sjkim        i = X509_LOOKUP_load_file(lookup, CAfile, X509_FILETYPE_PEM);
173280304Sjkim        if (!i) {
174280304Sjkim            BIO_printf(bio_err, "Error loading file %s\n", CAfile);
175280304Sjkim            ERR_print_errors(bio_err);
176280304Sjkim            goto end;
177280304Sjkim        }
178280304Sjkim    } else
179280304Sjkim        X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT);
18055714Skris
181280304Sjkim    lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_hash_dir());
182280304Sjkim    if (lookup == NULL)
183280304Sjkim        abort();
184280304Sjkim    if (CApath) {
185280304Sjkim        i = X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM);
186280304Sjkim        if (!i) {
187280304Sjkim            BIO_printf(bio_err, "Error loading directory %s\n", CApath);
188280304Sjkim            ERR_print_errors(bio_err);
189280304Sjkim            goto end;
190280304Sjkim        }
191280304Sjkim    } else
192280304Sjkim        X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT);
19355714Skris
194280304Sjkim    ERR_clear_error();
19559191Skris
196280304Sjkim    if (untfile) {
197280304Sjkim        untrusted = load_certs(bio_err, untfile, FORMAT_PEM,
198280304Sjkim                               NULL, e, "untrusted certificates");
199280304Sjkim        if (!untrusted)
200280304Sjkim            goto end;
201280304Sjkim    }
20268651Skris
203280304Sjkim    if (trustfile) {
204280304Sjkim        trusted = load_certs(bio_err, trustfile, FORMAT_PEM,
205280304Sjkim                             NULL, e, "trusted certificates");
206280304Sjkim        if (!trusted)
207280304Sjkim            goto end;
208280304Sjkim    }
209238405Sjkim
210280304Sjkim    if (crlfile) {
211280304Sjkim        crls = load_crls(bio_err, crlfile, FORMAT_PEM, NULL, e, "other CRLs");
212280304Sjkim        if (!crls)
213280304Sjkim            goto end;
214280304Sjkim    }
215246772Sjkim
216280304Sjkim    ret = 0;
217280304Sjkim    if (argc < 1) {
218280304Sjkim        if (1 != check(cert_ctx, NULL, untrusted, trusted, crls, e))
219280304Sjkim            ret = -1;
220280304Sjkim    } else {
221280304Sjkim        for (i = 0; i < argc; i++)
222280304Sjkim            if (1 != check(cert_ctx, argv[i], untrusted, trusted, crls, e))
223280304Sjkim                ret = -1;
224280304Sjkim    }
225280304Sjkim
226280304Sjkim end:
227280304Sjkim    if (ret == 1) {
228280304Sjkim        BIO_printf(bio_err,
229280304Sjkim                   "usage: verify [-verbose] [-CApath path] [-CAfile file] [-purpose purpose] [-crl_check]");
230284285Sjkim        BIO_printf(bio_err, " [-no_alt_chains] [-attime timestamp]");
231111147Snectar#ifndef OPENSSL_NO_ENGINE
232280304Sjkim        BIO_printf(bio_err, " [-engine e]");
233111147Snectar#endif
234280304Sjkim        BIO_printf(bio_err, " cert1 cert2 ...\n");
235246772Sjkim
236280304Sjkim        BIO_printf(bio_err, "recognized usages:\n");
237280304Sjkim        for (i = 0; i < X509_PURPOSE_get_count(); i++) {
238280304Sjkim            X509_PURPOSE *ptmp;
239280304Sjkim            ptmp = X509_PURPOSE_get0(i);
240280304Sjkim            BIO_printf(bio_err, "\t%-10s\t%s\n",
241280304Sjkim                       X509_PURPOSE_get0_sname(ptmp),
242280304Sjkim                       X509_PURPOSE_get0_name(ptmp));
243280304Sjkim        }
244280304Sjkim    }
245280304Sjkim    if (vpm)
246280304Sjkim        X509_VERIFY_PARAM_free(vpm);
247280304Sjkim    if (cert_ctx != NULL)
248280304Sjkim        X509_STORE_free(cert_ctx);
249280304Sjkim    sk_X509_pop_free(untrusted, X509_free);
250280304Sjkim    sk_X509_pop_free(trusted, X509_free);
251280304Sjkim    sk_X509_CRL_pop_free(crls, X509_CRL_free);
252280304Sjkim    apps_shutdown();
253280304Sjkim    OPENSSL_EXIT(ret < 0 ? 2 : ret);
254280304Sjkim}
25555714Skris
256238405Sjkimstatic int check(X509_STORE *ctx, char *file,
257280304Sjkim                 STACK_OF(X509) *uchain, STACK_OF(X509) *tchain,
258280304Sjkim                 STACK_OF(X509_CRL) *crls, ENGINE *e)
259280304Sjkim{
260280304Sjkim    X509 *x = NULL;
261280304Sjkim    int i = 0, ret = 0;
262280304Sjkim    X509_STORE_CTX *csc;
26355714Skris
264280304Sjkim    x = load_cert(bio_err, file, FORMAT_PEM, NULL, e, "certificate file");
265280304Sjkim    if (x == NULL)
266280304Sjkim        goto end;
267280304Sjkim    fprintf(stdout, "%s: ", (file == NULL) ? "stdin" : file);
26855714Skris
269280304Sjkim    csc = X509_STORE_CTX_new();
270280304Sjkim    if (csc == NULL) {
271280304Sjkim        ERR_print_errors(bio_err);
272280304Sjkim        goto end;
273280304Sjkim    }
274280304Sjkim    X509_STORE_set_flags(ctx, vflags);
275280304Sjkim    if (!X509_STORE_CTX_init(csc, ctx, x, uchain)) {
276280304Sjkim        ERR_print_errors(bio_err);
277280304Sjkim        goto end;
278280304Sjkim    }
279280304Sjkim    if (tchain)
280280304Sjkim        X509_STORE_CTX_trusted_stack(csc, tchain);
281280304Sjkim    if (crls)
282280304Sjkim        X509_STORE_CTX_set0_crls(csc, crls);
283280304Sjkim    i = X509_verify_cert(csc);
284280304Sjkim    X509_STORE_CTX_free(csc);
28555714Skris
286280304Sjkim    ret = 0;
287280304Sjkim end:
288280304Sjkim    if (i > 0) {
289280304Sjkim        fprintf(stdout, "OK\n");
290280304Sjkim        ret = 1;
291280304Sjkim    } else
292280304Sjkim        ERR_print_errors(bio_err);
293280304Sjkim    if (x != NULL)
294280304Sjkim        X509_free(x);
29555714Skris
296280304Sjkim    return (ret);
297280304Sjkim}
29855714Skris
29955714Skrisstatic int MS_CALLBACK cb(int ok, X509_STORE_CTX *ctx)
300280304Sjkim{
301280304Sjkim    int cert_error = X509_STORE_CTX_get_error(ctx);
302280304Sjkim    X509 *current_cert = X509_STORE_CTX_get_current_cert(ctx);
30355714Skris
304280304Sjkim    if (!ok) {
305280304Sjkim        if (current_cert) {
306280304Sjkim            X509_NAME_print_ex_fp(stdout,
307280304Sjkim                                  X509_get_subject_name(current_cert),
308280304Sjkim                                  0, XN_FLAG_ONELINE);
309280304Sjkim            printf("\n");
310280304Sjkim        }
311280304Sjkim        printf("%serror %d at %d depth lookup:%s\n",
312280304Sjkim               X509_STORE_CTX_get0_parent_ctx(ctx) ? "[CRL path]" : "",
313280304Sjkim               cert_error,
314280304Sjkim               X509_STORE_CTX_get_error_depth(ctx),
315280304Sjkim               X509_verify_cert_error_string(cert_error));
316280304Sjkim        switch (cert_error) {
317280304Sjkim        case X509_V_ERR_NO_EXPLICIT_POLICY:
318280304Sjkim            policies_print(NULL, ctx);
319280304Sjkim        case X509_V_ERR_CERT_HAS_EXPIRED:
320160814Ssimon
321280304Sjkim            /*
322280304Sjkim             * since we are just checking the certificates, it is ok if they
323280304Sjkim             * are self signed. But we should still warn the user.
324280304Sjkim             */
325238405Sjkim
326280304Sjkim        case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
327280304Sjkim            /* Continue after extension errors too */
328280304Sjkim        case X509_V_ERR_INVALID_CA:
329280304Sjkim        case X509_V_ERR_INVALID_NON_CA:
330280304Sjkim        case X509_V_ERR_PATH_LENGTH_EXCEEDED:
331280304Sjkim        case X509_V_ERR_INVALID_PURPOSE:
332280304Sjkim        case X509_V_ERR_CRL_HAS_EXPIRED:
333280304Sjkim        case X509_V_ERR_CRL_NOT_YET_VALID:
334280304Sjkim        case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
335280304Sjkim            ok = 1;
336238405Sjkim
337280304Sjkim        }
338238405Sjkim
339280304Sjkim        return ok;
340160814Ssimon
341280304Sjkim    }
342280304Sjkim    if (cert_error == X509_V_OK && ok == 2)
343280304Sjkim        policies_print(NULL, ctx);
344280304Sjkim    if (!v_verbose)
345280304Sjkim        ERR_clear_error();
346280304Sjkim    return (ok);
347280304Sjkim}
348