|
1 /* apps/verify.c */ |
|
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 #include "apps.h" |
|
63 #include <openssl/bio.h> |
|
64 #include <openssl/err.h> |
|
65 #include <openssl/x509.h> |
|
66 #include <openssl/x509v3.h> |
|
67 #include <openssl/pem.h> |
|
68 |
|
69 #undef PROG |
|
70 #define PROG verify_main |
|
71 |
|
72 static int MS_CALLBACK cb(int ok, X509_STORE_CTX *ctx); |
|
73 static int check(X509_STORE *ctx, char *file, STACK_OF(X509) *uchain, STACK_OF(X509) *tchain, int purpose, ENGINE *e); |
|
74 static STACK_OF(X509) *load_untrusted(char *file); |
|
75 static int v_verbose=0, vflags = 0; |
|
76 |
|
77 |
|
78 |
|
79 int MAIN(int, char **); |
|
80 |
|
81 int MAIN(int argc, char **argv) |
|
82 { |
|
83 ENGINE *e = NULL; |
|
84 int i,ret=1, badarg = 0; |
|
85 int purpose = -1; |
|
86 char *CApath=NULL,*CAfile=NULL; |
|
87 char *untfile = NULL, *trustfile = NULL; |
|
88 STACK_OF(X509) *untrusted = NULL, *trusted = NULL; |
|
89 X509_STORE *cert_ctx=NULL; |
|
90 X509_LOOKUP *lookup=NULL; |
|
91 X509_VERIFY_PARAM *vpm = NULL; |
|
92 #ifndef OPENSSL_NO_ENGINE |
|
93 char *engine=NULL; |
|
94 #endif |
|
95 |
|
96 cert_ctx=X509_STORE_new(); |
|
97 if (cert_ctx == NULL) goto end; |
|
98 X509_STORE_set_verify_cb_func(cert_ctx,cb); |
|
99 |
|
100 ERR_load_crypto_strings(); |
|
101 |
|
102 apps_startup(); |
|
103 |
|
104 if (bio_err == NULL) |
|
105 if ((bio_err=BIO_new(BIO_s_file())) != NULL) |
|
106 BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT); |
|
107 |
|
108 |
|
109 if (!load_config(bio_err, NULL)) |
|
110 goto end; |
|
111 |
|
112 argc--; |
|
113 argv++; |
|
114 for (;;) |
|
115 { |
|
116 if (argc >= 1) |
|
117 { |
|
118 if (strcmp(*argv,"-CApath") == 0) |
|
119 { |
|
120 if (argc-- < 1) goto end; |
|
121 CApath= *(++argv); |
|
122 } |
|
123 else if (strcmp(*argv,"-CAfile") == 0) |
|
124 { |
|
125 if (argc-- < 1) goto end; |
|
126 CAfile= *(++argv); |
|
127 } |
|
128 else if (args_verify(&argv, &argc, &badarg, bio_err, |
|
129 &vpm)) |
|
130 { |
|
131 if (badarg) |
|
132 goto end; |
|
133 continue; |
|
134 } |
|
135 else if (strcmp(*argv,"-untrusted") == 0) |
|
136 { |
|
137 if (argc-- < 1) goto end; |
|
138 untfile= *(++argv); |
|
139 } |
|
140 else if (strcmp(*argv,"-trusted") == 0) |
|
141 { |
|
142 if (argc-- < 1) goto end; |
|
143 trustfile= *(++argv); |
|
144 } |
|
145 #ifndef OPENSSL_NO_ENGINE |
|
146 else if (strcmp(*argv,"-engine") == 0) |
|
147 { |
|
148 if (--argc < 1) goto end; |
|
149 engine= *(++argv); |
|
150 } |
|
151 #endif |
|
152 else if (strcmp(*argv,"-help") == 0) |
|
153 goto end; |
|
154 else if (strcmp(*argv,"-verbose") == 0) |
|
155 v_verbose=1; |
|
156 else if (argv[0][0] == '-') |
|
157 goto end; |
|
158 else |
|
159 break; |
|
160 argc--; |
|
161 argv++; |
|
162 } |
|
163 else |
|
164 break; |
|
165 } |
|
166 |
|
167 #ifndef OPENSSL_NO_ENGINE |
|
168 e = setup_engine(bio_err, engine, 0); |
|
169 #endif |
|
170 |
|
171 if (vpm) |
|
172 X509_STORE_set1_param(cert_ctx, vpm); |
|
173 |
|
174 lookup=X509_STORE_add_lookup(cert_ctx,X509_LOOKUP_file()); |
|
175 if (lookup == NULL) abort(); |
|
176 if (CAfile) { |
|
177 i=X509_LOOKUP_load_file(lookup,CAfile,X509_FILETYPE_PEM); |
|
178 if(!i) { |
|
179 BIO_printf(bio_err, "Error loading file %s\n", CAfile); |
|
180 ERR_print_errors(bio_err); |
|
181 goto end; |
|
182 } |
|
183 } else 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) abort(); |
|
187 if (CApath) { |
|
188 i=X509_LOOKUP_add_dir(lookup,CApath,X509_FILETYPE_PEM); |
|
189 if(!i) { |
|
190 BIO_printf(bio_err, "Error loading directory %s\n", CApath); |
|
191 ERR_print_errors(bio_err); |
|
192 goto end; |
|
193 } |
|
194 } else X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT); |
|
195 |
|
196 ERR_clear_error(); |
|
197 |
|
198 if(untfile) { |
|
199 if(!(untrusted = load_untrusted(untfile))) { |
|
200 BIO_printf(bio_err, "Error loading untrusted file %s\n", untfile); |
|
201 ERR_print_errors(bio_err); |
|
202 goto end; |
|
203 } |
|
204 } |
|
205 |
|
206 if(trustfile) { |
|
207 if(!(trusted = load_untrusted(trustfile))) { |
|
208 BIO_printf(bio_err, "Error loading untrusted file %s\n", trustfile); |
|
209 ERR_print_errors(bio_err); |
|
210 goto end; |
|
211 } |
|
212 } |
|
213 |
|
214 if (argc < 1) check(cert_ctx, NULL, untrusted, trusted, purpose, e); |
|
215 else |
|
216 for (i=0; i<argc; i++) |
|
217 check(cert_ctx,argv[i], untrusted, trusted, purpose, e); |
|
218 ret=0; |
|
219 end: |
|
220 if (ret == 1) { |
|
221 BIO_printf(bio_err,"usage: verify [-verbose] [-CApath path] [-CAfile file] [-purpose purpose] [-crl_check]"); |
|
222 #ifndef OPENSSL_NO_ENGINE |
|
223 BIO_printf(bio_err," [-engine e]"); |
|
224 #endif |
|
225 BIO_printf(bio_err," cert1 cert2 ...\n"); |
|
226 BIO_printf(bio_err,"recognized usages:\n"); |
|
227 for(i = 0; i < X509_PURPOSE_get_count(); i++) { |
|
228 X509_PURPOSE *ptmp; |
|
229 ptmp = X509_PURPOSE_get0(i); |
|
230 BIO_printf(bio_err, "\t%-10s\t%s\n", X509_PURPOSE_get0_sname(ptmp), |
|
231 X509_PURPOSE_get0_name(ptmp)); |
|
232 } |
|
233 } |
|
234 if (vpm) X509_VERIFY_PARAM_free(vpm); |
|
235 if (cert_ctx != NULL) X509_STORE_free(cert_ctx); |
|
236 sk_X509_pop_free(untrusted, X509_free); |
|
237 sk_X509_pop_free(trusted, X509_free); |
|
238 apps_shutdown(); |
|
239 OPENSSL_EXIT(ret); |
|
240 } |
|
241 |
|
242 static int check(X509_STORE *ctx, char *file, STACK_OF(X509) *uchain, STACK_OF(X509) *tchain, int purpose, ENGINE *e) |
|
243 { |
|
244 X509 *x=NULL; |
|
245 int i=0,ret=0; |
|
246 X509_STORE_CTX *csc; |
|
247 |
|
248 x = load_cert(bio_err, file, FORMAT_PEM, NULL, e, "certificate file"); |
|
249 if (x == NULL) |
|
250 goto end; |
|
251 fprintf(stdout,"%s: ",(file == NULL)?"stdin":file); |
|
252 |
|
253 csc = X509_STORE_CTX_new(); |
|
254 if (csc == NULL) |
|
255 { |
|
256 ERR_print_errors(bio_err); |
|
257 goto end; |
|
258 } |
|
259 X509_STORE_set_flags(ctx, vflags); |
|
260 if(!X509_STORE_CTX_init(csc,ctx,x,uchain)) |
|
261 { |
|
262 ERR_print_errors(bio_err); |
|
263 goto end; |
|
264 } |
|
265 if(tchain) X509_STORE_CTX_trusted_stack(csc, tchain); |
|
266 if(purpose >= 0) X509_STORE_CTX_set_purpose(csc, purpose); |
|
267 i=X509_verify_cert(csc); |
|
268 X509_STORE_CTX_free(csc); |
|
269 |
|
270 ret=0; |
|
271 end: |
|
272 if (i) |
|
273 { |
|
274 fprintf(stdout,"OK\n"); |
|
275 ret=1; |
|
276 } |
|
277 else |
|
278 ERR_print_errors(bio_err); |
|
279 if (x != NULL) X509_free(x); |
|
280 |
|
281 return(ret); |
|
282 } |
|
283 |
|
284 static STACK_OF(X509) *load_untrusted(char *certfile) |
|
285 { |
|
286 STACK_OF(X509_INFO) *sk=NULL; |
|
287 STACK_OF(X509) *stack=NULL, *ret=NULL; |
|
288 BIO *in=NULL; |
|
289 X509_INFO *xi; |
|
290 |
|
291 if(!(stack = sk_X509_new_null())) { |
|
292 BIO_printf(bio_err,"memory allocation failure\n"); |
|
293 goto end; |
|
294 } |
|
295 |
|
296 if(!(in=BIO_new_file(certfile, "r"))) { |
|
297 BIO_printf(bio_err,"error opening the file, %s\n",certfile); |
|
298 goto end; |
|
299 } |
|
300 |
|
301 /* This loads from a file, a stack of x509/crl/pkey sets */ |
|
302 if(!(sk=PEM_X509_INFO_read_bio(in,NULL,NULL,NULL))) { |
|
303 BIO_printf(bio_err,"error reading the file, %s\n",certfile); |
|
304 goto end; |
|
305 } |
|
306 |
|
307 /* scan over it and pull out the certs */ |
|
308 while (sk_X509_INFO_num(sk)) |
|
309 { |
|
310 xi=sk_X509_INFO_shift(sk); |
|
311 if (xi->x509 != NULL) |
|
312 { |
|
313 sk_X509_push(stack,xi->x509); |
|
314 xi->x509=NULL; |
|
315 } |
|
316 X509_INFO_free(xi); |
|
317 } |
|
318 if(!sk_X509_num(stack)) { |
|
319 BIO_printf(bio_err,"no certificates in file, %s\n",certfile); |
|
320 sk_X509_free(stack); |
|
321 goto end; |
|
322 } |
|
323 ret=stack; |
|
324 end: |
|
325 BIO_free(in); |
|
326 sk_X509_INFO_free(sk); |
|
327 return(ret); |
|
328 } |
|
329 |
|
330 static int MS_CALLBACK cb(int ok, X509_STORE_CTX *ctx) |
|
331 { |
|
332 char buf[256]; |
|
333 |
|
334 if (!ok) |
|
335 { |
|
336 if (ctx->current_cert) |
|
337 { |
|
338 X509_NAME_oneline( |
|
339 X509_get_subject_name(ctx->current_cert),buf, |
|
340 sizeof buf); |
|
341 printf("%s\n",buf); |
|
342 } |
|
343 printf("error %d at %d depth lookup:%s\n",ctx->error, |
|
344 ctx->error_depth, |
|
345 X509_verify_cert_error_string(ctx->error)); |
|
346 if (ctx->error == X509_V_ERR_CERT_HAS_EXPIRED) ok=1; |
|
347 /* since we are just checking the certificates, it is |
|
348 * ok if they are self signed. But we should still warn |
|
349 * the user. |
|
350 */ |
|
351 if (ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) ok=1; |
|
352 /* Continue after extension errors too */ |
|
353 if (ctx->error == X509_V_ERR_INVALID_CA) ok=1; |
|
354 if (ctx->error == X509_V_ERR_INVALID_NON_CA) ok=1; |
|
355 if (ctx->error == X509_V_ERR_PATH_LENGTH_EXCEEDED) ok=1; |
|
356 if (ctx->error == X509_V_ERR_INVALID_PURPOSE) ok=1; |
|
357 if (ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) ok=1; |
|
358 if (ctx->error == X509_V_ERR_CRL_HAS_EXPIRED) ok=1; |
|
359 if (ctx->error == X509_V_ERR_CRL_NOT_YET_VALID) ok=1; |
|
360 if (ctx->error == X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION) ok=1; |
|
361 |
|
362 if (ctx->error == X509_V_ERR_NO_EXPLICIT_POLICY) |
|
363 policies_print(NULL, ctx); |
|
364 return ok; |
|
365 |
|
366 } |
|
367 if ((ctx->error == X509_V_OK) && (ok == 2)) |
|
368 policies_print(NULL, ctx); |
|
369 if (!v_verbose) |
|
370 ERR_clear_error(); |
|
371 return(ok); |
|
372 } |
|
373 |