]>
Commit | Line | Data |
---|---|---|
58964a49 | 1 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
d02b48c6 RE |
2 | * All rights reserved. |
3 | * | |
4 | * This package is an SSL implementation written | |
5 | * by Eric Young (eay@cryptsoft.com). | |
6 | * The implementation was written so as to conform with Netscapes SSL. | |
0f113f3e | 7 | * |
d02b48c6 RE |
8 | * This library is free for commercial and non-commercial use as long as |
9 | * the following conditions are aheared to. The following conditions | |
10 | * apply to all code found in this distribution, be it the RC4, RSA, | |
11 | * lhash, DES, etc., code; not just the SSL code. The SSL documentation | |
12 | * included with this distribution is covered by the same copyright terms | |
13 | * except that the holder is Tim Hudson (tjh@cryptsoft.com). | |
0f113f3e | 14 | * |
d02b48c6 RE |
15 | * Copyright remains Eric Young's, and as such any Copyright notices in |
16 | * the code are not to be removed. | |
17 | * If this package is used in a product, Eric Young should be given attribution | |
18 | * as the author of the parts of the library used. | |
19 | * This can be in the form of a textual message at program startup or | |
20 | * in documentation (online or textual) provided with the package. | |
0f113f3e | 21 | * |
d02b48c6 RE |
22 | * Redistribution and use in source and binary forms, with or without |
23 | * modification, are permitted provided that the following conditions | |
24 | * are met: | |
25 | * 1. Redistributions of source code must retain the copyright | |
26 | * notice, this list of conditions and the following disclaimer. | |
27 | * 2. Redistributions in binary form must reproduce the above copyright | |
28 | * notice, this list of conditions and the following disclaimer in the | |
29 | * documentation and/or other materials provided with the distribution. | |
30 | * 3. All advertising materials mentioning features or use of this software | |
31 | * must display the following acknowledgement: | |
32 | * "This product includes cryptographic software written by | |
33 | * Eric Young (eay@cryptsoft.com)" | |
34 | * The word 'cryptographic' can be left out if the rouines from the library | |
35 | * being used are not cryptographic related :-). | |
0f113f3e | 36 | * 4. If you include any Windows specific code (or a derivative thereof) from |
d02b48c6 RE |
37 | * the apps directory (application code) you must include an acknowledgement: |
38 | * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" | |
0f113f3e | 39 | * |
d02b48c6 RE |
40 | * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND |
41 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
42 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
43 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
44 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
45 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
46 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
47 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
48 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
49 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
50 | * SUCH DAMAGE. | |
0f113f3e | 51 | * |
d02b48c6 RE |
52 | * The licence and distribution terms for any publically available version or |
53 | * derivative of this code cannot be changed. i.e. this code cannot simply be | |
54 | * copied and put under another distribution licence | |
55 | * [including the GNU Public Licence.] | |
56 | */ | |
57 | ||
58 | #include <stdio.h> | |
59 | #include <stdlib.h> | |
60 | #include <string.h> | |
61 | #include "apps.h" | |
ec577822 BM |
62 | #include <openssl/bio.h> |
63 | #include <openssl/err.h> | |
64 | #include <openssl/x509.h> | |
65 | #include <openssl/x509v3.h> | |
66 | #include <openssl/pem.h> | |
d02b48c6 | 67 | |
7e1b7485 RS |
68 | typedef enum OPTION_choice { |
69 | OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, | |
70 | OPT_INFORM, OPT_IN, OPT_OUTFORM, OPT_OUT, OPT_KEYFORM, OPT_KEY, | |
71 | OPT_ISSUER, OPT_LASTUPDATE, OPT_NEXTUPDATE, OPT_FINGERPRINT, | |
72 | OPT_CRLNUMBER, OPT_BADSIG, OPT_GENDELTA, OPT_CAPATH, OPT_CAFILE, | |
73 | OPT_VERIFY, OPT_TEXT, OPT_HASH, OPT_HASH_OLD, OPT_NOOUT, | |
74 | OPT_NAMEOPT, OPT_MD | |
75 | } OPTION_CHOICE; | |
d02b48c6 | 76 | |
7e1b7485 RS |
77 | OPTIONS crl_options[] = { |
78 | {"help", OPT_HELP, '-', "Display this summary"}, | |
79 | {"inform", OPT_INFORM, 'F', "Input format; default PEM"}, | |
80 | {"in", OPT_IN, '<', "Input file - default stdin"}, | |
81 | {"outform", OPT_OUTFORM, 'F', "Output format - default PEM"}, | |
82 | {"out", OPT_OUT, '>', "output file - default stdout"}, | |
83 | {"keyform", OPT_KEYFORM, 'F'}, | |
84 | {"key", OPT_KEY, '<'}, | |
85 | {"issuer", OPT_ISSUER, '-', "Print issuer DN"}, | |
86 | {"lastupdate", OPT_LASTUPDATE, '-', "Set lastUpdate field"}, | |
87 | {"nextupdate", OPT_NEXTUPDATE, '-', "Set nextUpdate field"}, | |
88 | {"noout", OPT_NOOUT, '-', "No CRL output"}, | |
89 | {"fingerprint", OPT_FINGERPRINT, '-', "Print the crl fingerprint"}, | |
90 | {"crlnumber", OPT_CRLNUMBER, '-', "Print CRL number"}, | |
91 | {"badsig", OPT_BADSIG, '-'}, | |
92 | {"gendelta", OPT_GENDELTA, '<'}, | |
93 | {"CApath", OPT_CAPATH, '/', "Verify CRL using certificates in dir"}, | |
94 | {"CAfile", OPT_CAFILE, '<', "Verify CRL using certificates in file name"}, | |
95 | {"verify", OPT_VERIFY, '-'}, | |
96 | {"text", OPT_TEXT, '-', "Print out a text format version"}, | |
97 | {"hash", OPT_HASH, '-', "Print hash value"}, | |
9c3bcfa0 RS |
98 | {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"}, |
99 | {"", OPT_MD, '-', "Any supported digest"}, | |
de2d97cd | 100 | #ifndef OPENSSL_NO_MD5 |
7e1b7485 | 101 | {"hash_old", OPT_HASH_OLD, '-', "Print old-style (MD5) hash value"}, |
de2d97cd | 102 | #endif |
7e1b7485 | 103 | {NULL} |
d02b48c6 RE |
104 | }; |
105 | ||
7e1b7485 | 106 | int crl_main(int argc, char **argv) |
0f113f3e | 107 | { |
0f113f3e | 108 | X509_CRL *x = NULL; |
0f113f3e | 109 | BIO *out = NULL; |
0f113f3e MC |
110 | X509_STORE *store = NULL; |
111 | X509_STORE_CTX ctx; | |
112 | X509_LOOKUP *lookup = NULL; | |
113 | X509_OBJECT xobj; | |
114 | EVP_PKEY *pkey; | |
7e1b7485 RS |
115 | const EVP_MD *digest = EVP_sha1(); |
116 | unsigned long nmflag = 0; | |
f1cece55 | 117 | char nmflag_set = 0; |
7e1b7485 RS |
118 | char *infile = NULL, *outfile = NULL, *crldiff = NULL, *keyfile = NULL; |
119 | char *CAfile = NULL, *CApath = NULL, *prog; | |
120 | OPTION_CHOICE o; | |
9c3bcfa0 | 121 | int hash = 0, issuer = 0, lastupdate = 0, nextupdate = 0, noout = 0; |
7e1b7485 | 122 | int informat = FORMAT_PEM, outformat = FORMAT_PEM, keyformat = FORMAT_PEM; |
9c3bcfa0 RS |
123 | int ret = 1, num = 0, badsig = 0, fingerprint = 0, crlnumber = 0; |
124 | int text = 0, do_ver = 0; | |
125 | int i; | |
7e1b7485 RS |
126 | #ifndef OPENSSL_NO_MD5 |
127 | int hash_old = 0; | |
645749ef | 128 | #endif |
d02b48c6 | 129 | |
7e1b7485 RS |
130 | prog = opt_init(argc, argv, crl_options); |
131 | while ((o = opt_next()) != OPT_EOF) { | |
132 | switch (o) { | |
133 | case OPT_EOF: | |
134 | case OPT_ERR: | |
135 | opthelp: | |
136 | BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); | |
137 | goto end; | |
138 | case OPT_HELP: | |
139 | opt_help(crl_options); | |
140 | ret = 0; | |
141 | goto end; | |
142 | case OPT_INFORM: | |
143 | if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat)) | |
144 | goto opthelp; | |
145 | break; | |
146 | case OPT_IN: | |
147 | infile = opt_arg(); | |
148 | break; | |
149 | case OPT_OUTFORM: | |
150 | if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat)) | |
151 | goto opthelp; | |
152 | break; | |
153 | case OPT_OUT: | |
154 | outfile = opt_arg(); | |
155 | break; | |
156 | case OPT_KEYFORM: | |
157 | if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &keyformat)) | |
158 | goto opthelp; | |
159 | break; | |
160 | case OPT_KEY: | |
161 | keyfile = opt_arg(); | |
162 | break; | |
163 | case OPT_GENDELTA: | |
164 | crldiff = opt_arg(); | |
165 | break; | |
166 | case OPT_CAPATH: | |
167 | CApath = opt_arg(); | |
0f113f3e | 168 | do_ver = 1; |
7e1b7485 RS |
169 | break; |
170 | case OPT_CAFILE: | |
171 | CAfile = opt_arg(); | |
0f113f3e | 172 | do_ver = 1; |
7e1b7485 | 173 | break; |
7e1b7485 | 174 | case OPT_HASH_OLD: |
9c3bcfa0 | 175 | #ifndef OPENSSL_NO_MD5 |
0f113f3e | 176 | hash_old = ++num; |
de2d97cd | 177 | #endif |
9c3bcfa0 | 178 | break; |
7e1b7485 RS |
179 | case OPT_VERIFY: |
180 | do_ver = 1; | |
181 | break; | |
182 | case OPT_TEXT: | |
183 | text = 1; | |
184 | break; | |
185 | case OPT_HASH: | |
186 | hash = ++num; | |
187 | break; | |
188 | case OPT_ISSUER: | |
0f113f3e | 189 | issuer = ++num; |
7e1b7485 RS |
190 | break; |
191 | case OPT_LASTUPDATE: | |
0f113f3e | 192 | lastupdate = ++num; |
7e1b7485 RS |
193 | break; |
194 | case OPT_NEXTUPDATE: | |
0f113f3e | 195 | nextupdate = ++num; |
7e1b7485 RS |
196 | break; |
197 | case OPT_NOOUT: | |
0f113f3e | 198 | noout = ++num; |
7e1b7485 RS |
199 | break; |
200 | case OPT_FINGERPRINT: | |
0f113f3e | 201 | fingerprint = ++num; |
7e1b7485 RS |
202 | break; |
203 | case OPT_CRLNUMBER: | |
0f113f3e | 204 | crlnumber = ++num; |
7e1b7485 RS |
205 | break; |
206 | case OPT_BADSIG: | |
0f113f3e | 207 | badsig = 1; |
0f113f3e | 208 | break; |
7e1b7485 | 209 | case OPT_NAMEOPT: |
f1cece55 | 210 | nmflag_set = 1; |
7e1b7485 RS |
211 | if (!set_name_ex(&nmflag, opt_arg())) |
212 | goto opthelp; | |
213 | break; | |
214 | case OPT_MD: | |
215 | if (!opt_md(opt_unknown(), &digest)) | |
216 | goto opthelp; | |
0f113f3e | 217 | } |
0f113f3e | 218 | } |
7e1b7485 RS |
219 | argc = opt_num_rest(); |
220 | argv = opt_rest(); | |
d02b48c6 | 221 | |
f1cece55 RL |
222 | if (!nmflag_set) |
223 | nmflag = XN_FLAG_ONELINE; | |
224 | ||
296f54ee RL |
225 | if (!app_load_modules(NULL)) |
226 | goto end; | |
227 | ||
0f113f3e | 228 | x = load_crl(infile, informat); |
7e1b7485 | 229 | if (x == NULL) |
0f113f3e | 230 | goto end; |
d02b48c6 | 231 | |
0f113f3e | 232 | if (do_ver) { |
75ebbd9a | 233 | if ((store = setup_verify(CAfile, CApath)) == NULL) |
0f113f3e | 234 | goto end; |
7e1b7485 | 235 | lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); |
0f113f3e MC |
236 | if (lookup == NULL) |
237 | goto end; | |
0f113f3e MC |
238 | if (!X509_STORE_CTX_init(&ctx, store, NULL, NULL)) { |
239 | BIO_printf(bio_err, "Error initialising X509 store\n"); | |
240 | goto end; | |
241 | } | |
090d848e | 242 | |
0f113f3e MC |
243 | i = X509_STORE_get_by_subject(&ctx, X509_LU_X509, |
244 | X509_CRL_get_issuer(x), &xobj); | |
245 | if (i <= 0) { | |
246 | BIO_printf(bio_err, "Error getting CRL issuer certificate\n"); | |
247 | goto end; | |
248 | } | |
249 | pkey = X509_get_pubkey(xobj.data.x509); | |
250 | X509_OBJECT_free_contents(&xobj); | |
251 | if (!pkey) { | |
252 | BIO_printf(bio_err, "Error getting CRL issuer public key\n"); | |
253 | goto end; | |
254 | } | |
255 | i = X509_CRL_verify(x, pkey); | |
256 | EVP_PKEY_free(pkey); | |
257 | if (i < 0) | |
258 | goto end; | |
259 | if (i == 0) | |
260 | BIO_printf(bio_err, "verify failure\n"); | |
261 | else | |
262 | BIO_printf(bio_err, "verify OK\n"); | |
263 | } | |
090d848e | 264 | |
0f113f3e MC |
265 | if (crldiff) { |
266 | X509_CRL *newcrl, *delta; | |
267 | if (!keyfile) { | |
268 | BIO_puts(bio_err, "Missing CRL signing key\n"); | |
269 | goto end; | |
270 | } | |
271 | newcrl = load_crl(crldiff, informat); | |
272 | if (!newcrl) | |
273 | goto end; | |
7e1b7485 | 274 | pkey = load_key(keyfile, keyformat, 0, NULL, NULL, "CRL signing key"); |
0f113f3e MC |
275 | if (!pkey) { |
276 | X509_CRL_free(newcrl); | |
277 | goto end; | |
278 | } | |
279 | delta = X509_CRL_diff(x, newcrl, pkey, digest, 0); | |
280 | X509_CRL_free(newcrl); | |
281 | EVP_PKEY_free(pkey); | |
282 | if (delta) { | |
283 | X509_CRL_free(x); | |
284 | x = delta; | |
285 | } else { | |
286 | BIO_puts(bio_err, "Error creating delta CRL\n"); | |
287 | goto end; | |
288 | } | |
289 | } | |
2e8cb108 | 290 | |
0f113f3e MC |
291 | if (num) { |
292 | for (i = 1; i <= num; i++) { | |
293 | if (issuer == i) { | |
294 | print_name(bio_out, "issuer=", X509_CRL_get_issuer(x), | |
295 | nmflag); | |
296 | } | |
297 | if (crlnumber == i) { | |
298 | ASN1_INTEGER *crlnum; | |
299 | crlnum = X509_CRL_get_ext_d2i(x, NID_crl_number, NULL, NULL); | |
300 | BIO_printf(bio_out, "crlNumber="); | |
301 | if (crlnum) { | |
302 | i2a_ASN1_INTEGER(bio_out, crlnum); | |
303 | ASN1_INTEGER_free(crlnum); | |
304 | } else | |
305 | BIO_puts(bio_out, "<NONE>"); | |
306 | BIO_printf(bio_out, "\n"); | |
307 | } | |
308 | if (hash == i) { | |
309 | BIO_printf(bio_out, "%08lx\n", | |
310 | X509_NAME_hash(X509_CRL_get_issuer(x))); | |
311 | } | |
de2d97cd | 312 | #ifndef OPENSSL_NO_MD5 |
0f113f3e MC |
313 | if (hash_old == i) { |
314 | BIO_printf(bio_out, "%08lx\n", | |
315 | X509_NAME_hash_old(X509_CRL_get_issuer(x))); | |
316 | } | |
de2d97cd | 317 | #endif |
0f113f3e MC |
318 | if (lastupdate == i) { |
319 | BIO_printf(bio_out, "lastUpdate="); | |
320 | ASN1_TIME_print(bio_out, X509_CRL_get_lastUpdate(x)); | |
321 | BIO_printf(bio_out, "\n"); | |
322 | } | |
323 | if (nextupdate == i) { | |
324 | BIO_printf(bio_out, "nextUpdate="); | |
325 | if (X509_CRL_get_nextUpdate(x)) | |
326 | ASN1_TIME_print(bio_out, X509_CRL_get_nextUpdate(x)); | |
327 | else | |
328 | BIO_printf(bio_out, "NONE"); | |
329 | BIO_printf(bio_out, "\n"); | |
330 | } | |
331 | if (fingerprint == i) { | |
332 | int j; | |
333 | unsigned int n; | |
334 | unsigned char md[EVP_MAX_MD_SIZE]; | |
439df508 | 335 | |
0f113f3e MC |
336 | if (!X509_CRL_digest(x, digest, md, &n)) { |
337 | BIO_printf(bio_err, "out of memory\n"); | |
338 | goto end; | |
339 | } | |
340 | BIO_printf(bio_out, "%s Fingerprint=", | |
341 | OBJ_nid2sn(EVP_MD_type(digest))); | |
342 | for (j = 0; j < (int)n; j++) { | |
343 | BIO_printf(bio_out, "%02X%c", md[j], (j + 1 == (int)n) | |
344 | ? '\n' : ':'); | |
345 | } | |
346 | } | |
347 | } | |
348 | } | |
7e1b7485 RS |
349 | out = bio_open_default(outfile, "w"); |
350 | if (out == NULL) | |
0f113f3e | 351 | goto end; |
d02b48c6 | 352 | |
0f113f3e MC |
353 | if (text) |
354 | X509_CRL_print(out, x); | |
2f0cd195 | 355 | |
0f113f3e MC |
356 | if (noout) { |
357 | ret = 0; | |
358 | goto end; | |
359 | } | |
2f0cd195 | 360 | |
0f113f3e MC |
361 | if (badsig) |
362 | x->signature->data[x->signature->length - 1] ^= 0x1; | |
139cd16c | 363 | |
0f113f3e MC |
364 | if (outformat == FORMAT_ASN1) |
365 | i = (int)i2d_X509_CRL_bio(out, x); | |
7e1b7485 | 366 | else |
0f113f3e | 367 | i = PEM_write_bio_X509_CRL(out, x); |
0f113f3e MC |
368 | if (!i) { |
369 | BIO_printf(bio_err, "unable to write CRL\n"); | |
370 | goto end; | |
371 | } | |
372 | ret = 0; | |
7e1b7485 | 373 | |
0f113f3e MC |
374 | end: |
375 | if (ret != 0) | |
376 | ERR_print_errors(bio_err); | |
377 | BIO_free_all(out); | |
0f113f3e MC |
378 | X509_CRL_free(x); |
379 | if (store) { | |
380 | X509_STORE_CTX_cleanup(&ctx); | |
381 | X509_STORE_free(store); | |
382 | } | |
7e1b7485 | 383 | return (ret); |
0f113f3e | 384 | } |