]>
Commit | Line | Data |
---|---|---|
d02b48c6 | 1 | /* apps/verify.c */ |
58964a49 | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
d02b48c6 RE |
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. | |
0f113f3e | 8 | * |
d02b48c6 RE |
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). | |
0f113f3e | 15 | * |
d02b48c6 RE |
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. | |
0f113f3e | 22 | * |
d02b48c6 RE |
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 :-). | |
0f113f3e | 37 | * 4. If you include any Windows specific code (or a derivative thereof) from |
d02b48c6 RE |
38 | * the apps directory (application code) you must include an acknowledgement: |
39 | * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" | |
0f113f3e | 40 | * |
d02b48c6 RE |
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. | |
0f113f3e | 52 | * |
d02b48c6 RE |
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 | #include "apps.h" | |
ec577822 BM |
63 | #include <openssl/bio.h> |
64 | #include <openssl/err.h> | |
65 | #include <openssl/x509.h> | |
d4cec6a1 | 66 | #include <openssl/x509v3.h> |
ec577822 | 67 | #include <openssl/pem.h> |
d02b48c6 RE |
68 | |
69 | #undef PROG | |
0f113f3e | 70 | #define PROG verify_main |
d02b48c6 | 71 | |
6d23cf97 | 72 | static int cb(int ok, X509_STORE_CTX *ctx); |
245d2ee3 | 73 | static int check(X509_STORE *ctx, char *file, |
0f113f3e MC |
74 | STACK_OF(X509) *uchain, STACK_OF(X509) *tchain, |
75 | STACK_OF(X509_CRL) *crls, ENGINE *e, int show_chain); | |
76 | static int v_verbose = 0, vflags = 0; | |
d02b48c6 | 77 | |
667ac4ec RE |
78 | int MAIN(int, char **); |
79 | ||
6b691a5c | 80 | int MAIN(int argc, char **argv) |
0f113f3e MC |
81 | { |
82 | ENGINE *e = NULL; | |
83 | int i, ret = 1, badarg = 0; | |
84 | char *CApath = NULL, *CAfile = NULL; | |
85 | char *untfile = NULL, *trustfile = NULL, *crlfile = NULL; | |
86 | STACK_OF(X509) *untrusted = NULL, *trusted = NULL; | |
87 | STACK_OF(X509_CRL) *crls = NULL; | |
88 | X509_STORE *cert_ctx = NULL; | |
89 | X509_LOOKUP *lookup = NULL; | |
90 | X509_VERIFY_PARAM *vpm = NULL; | |
91 | int crl_download = 0, show_chain = 0; | |
0b13e9f0 | 92 | #ifndef OPENSSL_NO_ENGINE |
0f113f3e | 93 | char *engine = NULL; |
0b13e9f0 | 94 | #endif |
d02b48c6 | 95 | |
0f113f3e MC |
96 | cert_ctx = X509_STORE_new(); |
97 | if (cert_ctx == NULL) | |
98 | goto end; | |
99 | X509_STORE_set_verify_cb(cert_ctx, cb); | |
100 | ||
101 | ERR_load_crypto_strings(); | |
102 | ||
103 | apps_startup(); | |
104 | ||
105 | if (bio_err == NULL) | |
106 | if ((bio_err = BIO_new(BIO_s_file())) != NULL) | |
107 | BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT); | |
108 | ||
109 | if (!load_config(bio_err, NULL)) | |
110 | goto end; | |
111 | ||
112 | argc--; | |
113 | argv++; | |
114 | for (;;) { | |
115 | if (argc >= 1) { | |
116 | if (strcmp(*argv, "-CApath") == 0) { | |
117 | if (argc-- < 1) | |
118 | goto end; | |
119 | CApath = *(++argv); | |
120 | } else if (strcmp(*argv, "-CAfile") == 0) { | |
121 | if (argc-- < 1) | |
122 | goto end; | |
123 | CAfile = *(++argv); | |
124 | } else if (args_verify(&argv, &argc, &badarg, bio_err, &vpm)) { | |
125 | if (badarg) | |
126 | goto end; | |
127 | continue; | |
128 | } else if (strcmp(*argv, "-untrusted") == 0) { | |
129 | if (argc-- < 1) | |
130 | goto end; | |
131 | untfile = *(++argv); | |
132 | } else if (strcmp(*argv, "-trusted") == 0) { | |
133 | if (argc-- < 1) | |
134 | goto end; | |
135 | trustfile = *(++argv); | |
136 | } else if (strcmp(*argv, "-CRLfile") == 0) { | |
137 | if (argc-- < 1) | |
138 | goto end; | |
139 | crlfile = *(++argv); | |
140 | } else if (strcmp(*argv, "-crl_download") == 0) | |
141 | crl_download = 1; | |
142 | else if (strcmp(*argv, "-show_chain") == 0) | |
143 | show_chain = 1; | |
0b13e9f0 | 144 | #ifndef OPENSSL_NO_ENGINE |
0f113f3e MC |
145 | else if (strcmp(*argv, "-engine") == 0) { |
146 | if (--argc < 1) | |
147 | goto end; | |
148 | engine = *(++argv); | |
149 | } | |
0b13e9f0 | 150 | #endif |
0f113f3e MC |
151 | else if (strcmp(*argv, "-help") == 0) |
152 | goto end; | |
153 | else if (strcmp(*argv, "-verbose") == 0) | |
154 | v_verbose = 1; | |
155 | else if (argv[0][0] == '-') | |
156 | goto end; | |
157 | else | |
158 | break; | |
159 | argc--; | |
160 | argv++; | |
161 | } else | |
162 | break; | |
163 | } | |
d02b48c6 | 164 | |
0b13e9f0 | 165 | #ifndef OPENSSL_NO_ENGINE |
0f113f3e | 166 | e = setup_engine(bio_err, engine, 0); |
0b13e9f0 | 167 | #endif |
5270e702 | 168 | |
0f113f3e MC |
169 | if (vpm) |
170 | X509_STORE_set1_param(cert_ctx, vpm); | |
171 | ||
172 | lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file()); | |
173 | if (lookup == NULL) | |
174 | abort(); | |
175 | if (CAfile) { | |
176 | i = X509_LOOKUP_load_file(lookup, CAfile, X509_FILETYPE_PEM); | |
177 | if (!i) { | |
178 | BIO_printf(bio_err, "Error loading file %s\n", CAfile); | |
179 | ERR_print_errors(bio_err); | |
180 | goto end; | |
181 | } | |
182 | } else | |
183 | X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT); | |
184 | ||
185 | lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_hash_dir()); | |
186 | if (lookup == NULL) | |
187 | abort(); | |
188 | if (CApath) { | |
189 | i = X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM); | |
190 | if (!i) { | |
191 | BIO_printf(bio_err, "Error loading directory %s\n", CApath); | |
192 | ERR_print_errors(bio_err); | |
193 | goto end; | |
194 | } | |
195 | } else | |
196 | X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT); | |
197 | ||
198 | ERR_clear_error(); | |
199 | ||
200 | if (untfile) { | |
201 | untrusted = load_certs(bio_err, untfile, FORMAT_PEM, | |
202 | NULL, e, "untrusted certificates"); | |
203 | if (!untrusted) | |
204 | goto end; | |
205 | } | |
206 | ||
207 | if (trustfile) { | |
208 | trusted = load_certs(bio_err, trustfile, FORMAT_PEM, | |
209 | NULL, e, "trusted certificates"); | |
210 | if (!trusted) | |
211 | goto end; | |
212 | } | |
213 | ||
214 | if (crlfile) { | |
215 | crls = load_crls(bio_err, crlfile, FORMAT_PEM, NULL, e, "other CRLs"); | |
216 | if (!crls) | |
217 | goto end; | |
218 | } | |
219 | ||
220 | if (crl_download) | |
221 | store_setup_crl_download(cert_ctx); | |
222 | ||
223 | ret = 0; | |
224 | if (argc < 1) { | |
225 | if (1 != | |
226 | check(cert_ctx, NULL, untrusted, trusted, crls, e, show_chain)) | |
227 | ret = -1; | |
228 | } else { | |
229 | for (i = 0; i < argc; i++) | |
230 | if (1 != | |
231 | check(cert_ctx, argv[i], untrusted, trusted, crls, e, | |
232 | show_chain)) | |
233 | ret = -1; | |
234 | } | |
235 | ||
236 | end: | |
237 | if (ret == 1) { | |
238 | BIO_printf(bio_err, | |
239 | "usage: verify [-verbose] [-CApath path] [-CAfile file] [-trusted_first] [-purpose purpose] [-crl_check]"); | |
0b13e9f0 | 240 | #ifndef OPENSSL_NO_ENGINE |
0f113f3e | 241 | BIO_printf(bio_err, " [-engine e]"); |
0b13e9f0 | 242 | #endif |
0f113f3e MC |
243 | BIO_printf(bio_err, " cert1 cert2 ...\n"); |
244 | ||
245 | BIO_printf(bio_err, "recognized usages:\n"); | |
246 | for (i = 0; i < X509_PURPOSE_get_count(); i++) { | |
247 | X509_PURPOSE *ptmp; | |
248 | ptmp = X509_PURPOSE_get0(i); | |
249 | BIO_printf(bio_err, "\t%-10s\t%s\n", | |
250 | X509_PURPOSE_get0_sname(ptmp), | |
251 | X509_PURPOSE_get0_name(ptmp)); | |
252 | } | |
253 | ||
254 | BIO_printf(bio_err, "recognized verify names:\n"); | |
255 | for (i = 0; i < X509_VERIFY_PARAM_get_count(); i++) { | |
256 | const X509_VERIFY_PARAM *vptmp; | |
257 | vptmp = X509_VERIFY_PARAM_get0(i); | |
258 | BIO_printf(bio_err, "\t%-10s\n", | |
259 | X509_VERIFY_PARAM_get0_name(vptmp)); | |
260 | } | |
261 | ||
262 | } | |
263 | if (vpm) | |
264 | X509_VERIFY_PARAM_free(vpm); | |
265 | if (cert_ctx != NULL) | |
266 | X509_STORE_free(cert_ctx); | |
267 | sk_X509_pop_free(untrusted, X509_free); | |
268 | sk_X509_pop_free(trusted, X509_free); | |
269 | sk_X509_CRL_pop_free(crls, X509_CRL_free); | |
270 | apps_shutdown(); | |
271 | OPENSSL_EXIT(ret < 0 ? 2 : ret); | |
272 | } | |
d02b48c6 | 273 | |
245d2ee3 | 274 | static int check(X509_STORE *ctx, char *file, |
0f113f3e MC |
275 | STACK_OF(X509) *uchain, STACK_OF(X509) *tchain, |
276 | STACK_OF(X509_CRL) *crls, ENGINE *e, int show_chain) | |
277 | { | |
278 | X509 *x = NULL; | |
279 | int i = 0, ret = 0; | |
280 | X509_STORE_CTX *csc; | |
281 | STACK_OF(X509) *chain = NULL; | |
282 | ||
283 | x = load_cert(bio_err, file, FORMAT_PEM, NULL, e, "certificate file"); | |
284 | if (x == NULL) | |
285 | goto end; | |
286 | fprintf(stdout, "%s: ", (file == NULL) ? "stdin" : file); | |
287 | ||
288 | csc = X509_STORE_CTX_new(); | |
289 | if (csc == NULL) { | |
290 | ERR_print_errors(bio_err); | |
291 | goto end; | |
292 | } | |
293 | X509_STORE_set_flags(ctx, vflags); | |
294 | if (!X509_STORE_CTX_init(csc, ctx, x, uchain)) { | |
295 | ERR_print_errors(bio_err); | |
296 | goto end; | |
297 | } | |
298 | if (tchain) | |
299 | X509_STORE_CTX_trusted_stack(csc, tchain); | |
300 | if (crls) | |
301 | X509_STORE_CTX_set0_crls(csc, crls); | |
302 | i = X509_verify_cert(csc); | |
303 | if (i > 0 && show_chain) | |
304 | chain = X509_STORE_CTX_get1_chain(csc); | |
305 | X509_STORE_CTX_free(csc); | |
306 | ||
307 | ret = 0; | |
308 | end: | |
309 | if (i > 0) { | |
310 | fprintf(stdout, "OK\n"); | |
311 | ret = 1; | |
312 | } else | |
313 | ERR_print_errors(bio_err); | |
314 | if (chain) { | |
315 | printf("Chain:\n"); | |
316 | for (i = 0; i < sk_X509_num(chain); i++) { | |
317 | X509 *cert = sk_X509_value(chain, i); | |
318 | printf("depth=%d: ", i); | |
319 | X509_NAME_print_ex_fp(stdout, | |
320 | X509_get_subject_name(cert), | |
321 | 0, XN_FLAG_ONELINE); | |
322 | printf("\n"); | |
323 | } | |
324 | sk_X509_pop_free(chain, X509_free); | |
325 | } | |
326 | if (x != NULL) | |
327 | X509_free(x); | |
328 | ||
329 | return (ret); | |
330 | } | |
d02b48c6 | 331 | |
6d23cf97 | 332 | static int cb(int ok, X509_STORE_CTX *ctx) |
0f113f3e MC |
333 | { |
334 | int cert_error = X509_STORE_CTX_get_error(ctx); | |
335 | X509 *current_cert = X509_STORE_CTX_get_current_cert(ctx); | |
336 | ||
337 | if (!ok) { | |
338 | if (current_cert) { | |
339 | X509_NAME_print_ex_fp(stdout, | |
340 | X509_get_subject_name(current_cert), | |
341 | 0, XN_FLAG_ONELINE); | |
342 | printf("\n"); | |
343 | } | |
344 | printf("%serror %d at %d depth lookup:%s\n", | |
345 | X509_STORE_CTX_get0_parent_ctx(ctx) ? "[CRL path]" : "", | |
346 | cert_error, | |
347 | X509_STORE_CTX_get_error_depth(ctx), | |
348 | X509_verify_cert_error_string(cert_error)); | |
349 | switch (cert_error) { | |
350 | case X509_V_ERR_NO_EXPLICIT_POLICY: | |
351 | policies_print(NULL, ctx); | |
352 | case X509_V_ERR_CERT_HAS_EXPIRED: | |
353 | ||
354 | /* | |
355 | * since we are just checking the certificates, it is ok if they | |
356 | * are self signed. But we should still warn the user. | |
357 | */ | |
358 | ||
359 | case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: | |
360 | /* Continue after extension errors too */ | |
361 | case X509_V_ERR_INVALID_CA: | |
362 | case X509_V_ERR_INVALID_NON_CA: | |
363 | case X509_V_ERR_PATH_LENGTH_EXCEEDED: | |
364 | case X509_V_ERR_INVALID_PURPOSE: | |
365 | case X509_V_ERR_CRL_HAS_EXPIRED: | |
366 | case X509_V_ERR_CRL_NOT_YET_VALID: | |
367 | case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: | |
368 | ok = 1; | |
369 | ||
370 | } | |
371 | ||
372 | return ok; | |
373 | ||
374 | } | |
375 | if (cert_error == X509_V_OK && ok == 2) | |
376 | policies_print(NULL, ctx); | |
377 | if (!v_verbose) | |
378 | ERR_clear_error(); | |
379 | return (ok); | |
380 | } |