]>
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, | |
2b6bcb70 MC |
73 | OPT_NOCAPATH, OPT_NOCAFILE, OPT_VERIFY, OPT_TEXT, OPT_HASH, OPT_HASH_OLD, |
74 | OPT_NOOUT, OPT_NAMEOPT, OPT_MD | |
7e1b7485 | 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"}, | |
2b6bcb70 MC |
95 | {"no-CAfile", OPT_NOCAFILE, '-', |
96 | "Do not load the default certificates file"}, | |
97 | {"no-CApath", OPT_NOCAPATH, '-', | |
98 | "Do not load certificates from the default certificates directory"}, | |
7e1b7485 RS |
99 | {"verify", OPT_VERIFY, '-'}, |
100 | {"text", OPT_TEXT, '-', "Print out a text format version"}, | |
101 | {"hash", OPT_HASH, '-', "Print hash value"}, | |
9c3bcfa0 RS |
102 | {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"}, |
103 | {"", OPT_MD, '-', "Any supported digest"}, | |
de2d97cd | 104 | #ifndef OPENSSL_NO_MD5 |
7e1b7485 | 105 | {"hash_old", OPT_HASH_OLD, '-', "Print old-style (MD5) hash value"}, |
de2d97cd | 106 | #endif |
7e1b7485 | 107 | {NULL} |
d02b48c6 RE |
108 | }; |
109 | ||
7e1b7485 | 110 | int crl_main(int argc, char **argv) |
0f113f3e | 111 | { |
0f113f3e | 112 | X509_CRL *x = NULL; |
0f113f3e | 113 | BIO *out = NULL; |
0f113f3e | 114 | X509_STORE *store = NULL; |
f0e0fd51 | 115 | X509_STORE_CTX *ctx = NULL; |
0f113f3e | 116 | X509_LOOKUP *lookup = NULL; |
f0e0fd51 | 117 | X509_OBJECT *xobj = NULL; |
0f113f3e | 118 | EVP_PKEY *pkey; |
7e1b7485 RS |
119 | const EVP_MD *digest = EVP_sha1(); |
120 | unsigned long nmflag = 0; | |
f1cece55 | 121 | char nmflag_set = 0; |
7e1b7485 RS |
122 | char *infile = NULL, *outfile = NULL, *crldiff = NULL, *keyfile = NULL; |
123 | char *CAfile = NULL, *CApath = NULL, *prog; | |
124 | OPTION_CHOICE o; | |
9c3bcfa0 | 125 | int hash = 0, issuer = 0, lastupdate = 0, nextupdate = 0, noout = 0; |
7e1b7485 | 126 | int informat = FORMAT_PEM, outformat = FORMAT_PEM, keyformat = FORMAT_PEM; |
9c3bcfa0 | 127 | int ret = 1, num = 0, badsig = 0, fingerprint = 0, crlnumber = 0; |
2b6bcb70 | 128 | int text = 0, do_ver = 0, noCAfile = 0, noCApath = 0; |
9c3bcfa0 | 129 | int i; |
7e1b7485 RS |
130 | #ifndef OPENSSL_NO_MD5 |
131 | int hash_old = 0; | |
645749ef | 132 | #endif |
d02b48c6 | 133 | |
7e1b7485 RS |
134 | prog = opt_init(argc, argv, crl_options); |
135 | while ((o = opt_next()) != OPT_EOF) { | |
136 | switch (o) { | |
137 | case OPT_EOF: | |
138 | case OPT_ERR: | |
139 | opthelp: | |
140 | BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); | |
141 | goto end; | |
142 | case OPT_HELP: | |
143 | opt_help(crl_options); | |
144 | ret = 0; | |
145 | goto end; | |
146 | case OPT_INFORM: | |
147 | if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat)) | |
148 | goto opthelp; | |
149 | break; | |
150 | case OPT_IN: | |
151 | infile = opt_arg(); | |
152 | break; | |
153 | case OPT_OUTFORM: | |
154 | if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat)) | |
155 | goto opthelp; | |
156 | break; | |
157 | case OPT_OUT: | |
158 | outfile = opt_arg(); | |
159 | break; | |
160 | case OPT_KEYFORM: | |
161 | if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &keyformat)) | |
162 | goto opthelp; | |
163 | break; | |
164 | case OPT_KEY: | |
165 | keyfile = opt_arg(); | |
166 | break; | |
167 | case OPT_GENDELTA: | |
168 | crldiff = opt_arg(); | |
169 | break; | |
170 | case OPT_CAPATH: | |
171 | CApath = opt_arg(); | |
0f113f3e | 172 | do_ver = 1; |
7e1b7485 RS |
173 | break; |
174 | case OPT_CAFILE: | |
175 | CAfile = opt_arg(); | |
0f113f3e | 176 | do_ver = 1; |
7e1b7485 | 177 | break; |
2b6bcb70 MC |
178 | case OPT_NOCAPATH: |
179 | noCApath = 1; | |
180 | break; | |
181 | case OPT_NOCAFILE: | |
182 | noCAfile = 1; | |
183 | break; | |
7e1b7485 | 184 | case OPT_HASH_OLD: |
9c3bcfa0 | 185 | #ifndef OPENSSL_NO_MD5 |
0f113f3e | 186 | hash_old = ++num; |
de2d97cd | 187 | #endif |
9c3bcfa0 | 188 | break; |
7e1b7485 RS |
189 | case OPT_VERIFY: |
190 | do_ver = 1; | |
191 | break; | |
192 | case OPT_TEXT: | |
193 | text = 1; | |
194 | break; | |
195 | case OPT_HASH: | |
196 | hash = ++num; | |
197 | break; | |
198 | case OPT_ISSUER: | |
0f113f3e | 199 | issuer = ++num; |
7e1b7485 RS |
200 | break; |
201 | case OPT_LASTUPDATE: | |
0f113f3e | 202 | lastupdate = ++num; |
7e1b7485 RS |
203 | break; |
204 | case OPT_NEXTUPDATE: | |
0f113f3e | 205 | nextupdate = ++num; |
7e1b7485 RS |
206 | break; |
207 | case OPT_NOOUT: | |
0f113f3e | 208 | noout = ++num; |
7e1b7485 RS |
209 | break; |
210 | case OPT_FINGERPRINT: | |
0f113f3e | 211 | fingerprint = ++num; |
7e1b7485 RS |
212 | break; |
213 | case OPT_CRLNUMBER: | |
0f113f3e | 214 | crlnumber = ++num; |
7e1b7485 RS |
215 | break; |
216 | case OPT_BADSIG: | |
0f113f3e | 217 | badsig = 1; |
0f113f3e | 218 | break; |
7e1b7485 | 219 | case OPT_NAMEOPT: |
f1cece55 | 220 | nmflag_set = 1; |
7e1b7485 RS |
221 | if (!set_name_ex(&nmflag, opt_arg())) |
222 | goto opthelp; | |
223 | break; | |
224 | case OPT_MD: | |
225 | if (!opt_md(opt_unknown(), &digest)) | |
226 | goto opthelp; | |
0f113f3e | 227 | } |
0f113f3e | 228 | } |
7e1b7485 | 229 | argc = opt_num_rest(); |
03358517 KR |
230 | if (argc != 0) |
231 | goto opthelp; | |
d02b48c6 | 232 | |
f1cece55 RL |
233 | if (!nmflag_set) |
234 | nmflag = XN_FLAG_ONELINE; | |
235 | ||
0f113f3e | 236 | x = load_crl(infile, informat); |
7e1b7485 | 237 | if (x == NULL) |
0f113f3e | 238 | goto end; |
d02b48c6 | 239 | |
0f113f3e | 240 | if (do_ver) { |
2b6bcb70 | 241 | if ((store = setup_verify(CAfile, CApath, noCAfile, noCApath)) == NULL) |
0f113f3e | 242 | goto end; |
7e1b7485 | 243 | lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); |
0f113f3e MC |
244 | if (lookup == NULL) |
245 | goto end; | |
f0e0fd51 | 246 | ctx = X509_STORE_CTX_new(); |
70015713 | 247 | if (ctx == NULL || !X509_STORE_CTX_init(ctx, store, NULL, NULL)) { |
0f113f3e MC |
248 | BIO_printf(bio_err, "Error initialising X509 store\n"); |
249 | goto end; | |
250 | } | |
090d848e | 251 | |
f0e0fd51 RS |
252 | xobj = X509_STORE_get_X509_by_subject(ctx, X509_LU_X509, |
253 | X509_CRL_get_issuer(x)); | |
254 | if (xobj == NULL) { | |
0f113f3e MC |
255 | BIO_printf(bio_err, "Error getting CRL issuer certificate\n"); |
256 | goto end; | |
257 | } | |
f0e0fd51 RS |
258 | pkey = X509_get_pubkey(X509_OBJECT_get0_X509(xobj)); |
259 | X509_OBJECT_free(xobj); | |
0f113f3e MC |
260 | if (!pkey) { |
261 | BIO_printf(bio_err, "Error getting CRL issuer public key\n"); | |
262 | goto end; | |
263 | } | |
264 | i = X509_CRL_verify(x, pkey); | |
f0e0fd51 | 265 | EVP_PKEY_free(pkey); |
0f113f3e MC |
266 | if (i < 0) |
267 | goto end; | |
268 | if (i == 0) | |
269 | BIO_printf(bio_err, "verify failure\n"); | |
270 | else | |
271 | BIO_printf(bio_err, "verify OK\n"); | |
272 | } | |
090d848e | 273 | |
0f113f3e MC |
274 | if (crldiff) { |
275 | X509_CRL *newcrl, *delta; | |
276 | if (!keyfile) { | |
277 | BIO_puts(bio_err, "Missing CRL signing key\n"); | |
278 | goto end; | |
279 | } | |
280 | newcrl = load_crl(crldiff, informat); | |
281 | if (!newcrl) | |
282 | goto end; | |
7e1b7485 | 283 | pkey = load_key(keyfile, keyformat, 0, NULL, NULL, "CRL signing key"); |
0f113f3e MC |
284 | if (!pkey) { |
285 | X509_CRL_free(newcrl); | |
286 | goto end; | |
287 | } | |
288 | delta = X509_CRL_diff(x, newcrl, pkey, digest, 0); | |
289 | X509_CRL_free(newcrl); | |
290 | EVP_PKEY_free(pkey); | |
291 | if (delta) { | |
292 | X509_CRL_free(x); | |
293 | x = delta; | |
294 | } else { | |
295 | BIO_puts(bio_err, "Error creating delta CRL\n"); | |
296 | goto end; | |
297 | } | |
298 | } | |
2e8cb108 | 299 | |
0f113f3e MC |
300 | if (num) { |
301 | for (i = 1; i <= num; i++) { | |
302 | if (issuer == i) { | |
303 | print_name(bio_out, "issuer=", X509_CRL_get_issuer(x), | |
304 | nmflag); | |
305 | } | |
306 | if (crlnumber == i) { | |
307 | ASN1_INTEGER *crlnum; | |
308 | crlnum = X509_CRL_get_ext_d2i(x, NID_crl_number, NULL, NULL); | |
309 | BIO_printf(bio_out, "crlNumber="); | |
310 | if (crlnum) { | |
311 | i2a_ASN1_INTEGER(bio_out, crlnum); | |
312 | ASN1_INTEGER_free(crlnum); | |
313 | } else | |
314 | BIO_puts(bio_out, "<NONE>"); | |
315 | BIO_printf(bio_out, "\n"); | |
316 | } | |
317 | if (hash == i) { | |
318 | BIO_printf(bio_out, "%08lx\n", | |
319 | X509_NAME_hash(X509_CRL_get_issuer(x))); | |
320 | } | |
de2d97cd | 321 | #ifndef OPENSSL_NO_MD5 |
0f113f3e MC |
322 | if (hash_old == i) { |
323 | BIO_printf(bio_out, "%08lx\n", | |
324 | X509_NAME_hash_old(X509_CRL_get_issuer(x))); | |
325 | } | |
de2d97cd | 326 | #endif |
0f113f3e MC |
327 | if (lastupdate == i) { |
328 | BIO_printf(bio_out, "lastUpdate="); | |
329 | ASN1_TIME_print(bio_out, X509_CRL_get_lastUpdate(x)); | |
330 | BIO_printf(bio_out, "\n"); | |
331 | } | |
332 | if (nextupdate == i) { | |
333 | BIO_printf(bio_out, "nextUpdate="); | |
334 | if (X509_CRL_get_nextUpdate(x)) | |
335 | ASN1_TIME_print(bio_out, X509_CRL_get_nextUpdate(x)); | |
336 | else | |
337 | BIO_printf(bio_out, "NONE"); | |
338 | BIO_printf(bio_out, "\n"); | |
339 | } | |
340 | if (fingerprint == i) { | |
341 | int j; | |
342 | unsigned int n; | |
343 | unsigned char md[EVP_MAX_MD_SIZE]; | |
439df508 | 344 | |
0f113f3e MC |
345 | if (!X509_CRL_digest(x, digest, md, &n)) { |
346 | BIO_printf(bio_err, "out of memory\n"); | |
347 | goto end; | |
348 | } | |
349 | BIO_printf(bio_out, "%s Fingerprint=", | |
350 | OBJ_nid2sn(EVP_MD_type(digest))); | |
351 | for (j = 0; j < (int)n; j++) { | |
352 | BIO_printf(bio_out, "%02X%c", md[j], (j + 1 == (int)n) | |
353 | ? '\n' : ':'); | |
354 | } | |
355 | } | |
356 | } | |
357 | } | |
bdd58d98 | 358 | out = bio_open_default(outfile, 'w', outformat); |
7e1b7485 | 359 | if (out == NULL) |
0f113f3e | 360 | goto end; |
d02b48c6 | 361 | |
0f113f3e MC |
362 | if (text) |
363 | X509_CRL_print(out, x); | |
2f0cd195 | 364 | |
0f113f3e MC |
365 | if (noout) { |
366 | ret = 0; | |
367 | goto end; | |
368 | } | |
2f0cd195 | 369 | |
e3e57192 DSH |
370 | if (badsig) { |
371 | ASN1_BIT_STRING *sig; | |
372 | unsigned char *psig; | |
373 | X509_CRL_get0_signature(&sig, NULL, x); | |
374 | psig = ASN1_STRING_data(sig); | |
375 | psig[ASN1_STRING_length(sig) - 1] ^= 0x1; | |
376 | } | |
139cd16c | 377 | |
0f113f3e MC |
378 | if (outformat == FORMAT_ASN1) |
379 | i = (int)i2d_X509_CRL_bio(out, x); | |
7e1b7485 | 380 | else |
0f113f3e | 381 | i = PEM_write_bio_X509_CRL(out, x); |
0f113f3e MC |
382 | if (!i) { |
383 | BIO_printf(bio_err, "unable to write CRL\n"); | |
384 | goto end; | |
385 | } | |
386 | ret = 0; | |
7e1b7485 | 387 | |
0f113f3e MC |
388 | end: |
389 | if (ret != 0) | |
390 | ERR_print_errors(bio_err); | |
391 | BIO_free_all(out); | |
0f113f3e | 392 | X509_CRL_free(x); |
f0e0fd51 RS |
393 | X509_STORE_CTX_free(ctx); |
394 | X509_STORE_free(store); | |
7e1b7485 | 395 | return (ret); |
0f113f3e | 396 | } |