blob: 3847faa427ff452ae3049f7cedeb4cfd0a0decef [file] [log] [blame]
Rich Salz846e33c2016-05-17 14:18:30 -04001/*
2 * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
Ralf S. Engelschalld02b48c1998-12-21 10:52:47 +00003 *
Rich Salz846e33c2016-05-17 14:18:30 -04004 * Licensed under the OpenSSL license (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
Ralf S. Engelschalld02b48c1998-12-21 10:52:47 +00008 */
9
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include "apps.h"
Bodo Möllerec577821999-04-23 22:13:45 +000014#include <openssl/bio.h>
15#include <openssl/err.h>
16#include <openssl/x509.h>
17#include <openssl/x509v3.h>
18#include <openssl/pem.h>
Ralf S. Engelschalld02b48c1998-12-21 10:52:47 +000019
Rich Salz7e1b7482015-04-24 15:26:15 -040020typedef enum OPTION_choice {
21 OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
22 OPT_INFORM, OPT_IN, OPT_OUTFORM, OPT_OUT, OPT_KEYFORM, OPT_KEY,
23 OPT_ISSUER, OPT_LASTUPDATE, OPT_NEXTUPDATE, OPT_FINGERPRINT,
24 OPT_CRLNUMBER, OPT_BADSIG, OPT_GENDELTA, OPT_CAPATH, OPT_CAFILE,
Matt Caswell2b6bcb72015-09-22 16:00:52 +010025 OPT_NOCAPATH, OPT_NOCAFILE, OPT_VERIFY, OPT_TEXT, OPT_HASH, OPT_HASH_OLD,
26 OPT_NOOUT, OPT_NAMEOPT, OPT_MD
Rich Salz7e1b7482015-04-24 15:26:15 -040027} OPTION_CHOICE;
Ralf S. Engelschalld02b48c1998-12-21 10:52:47 +000028
FdaSilvaYY44c83eb2016-03-13 14:07:50 +010029const OPTIONS crl_options[] = {
Rich Salz7e1b7482015-04-24 15:26:15 -040030 {"help", OPT_HELP, '-', "Display this summary"},
31 {"inform", OPT_INFORM, 'F', "Input format; default PEM"},
32 {"in", OPT_IN, '<', "Input file - default stdin"},
33 {"outform", OPT_OUTFORM, 'F', "Output format - default PEM"},
34 {"out", OPT_OUT, '>', "output file - default stdout"},
FdaSilvaYY16e1b282016-03-20 21:14:10 +010035 {"keyform", OPT_KEYFORM, 'F', "Private key file format (PEM or ENGINE)"},
36 {"key", OPT_KEY, '<', "CRL signing Private key to use"},
Rich Salz7e1b7482015-04-24 15:26:15 -040037 {"issuer", OPT_ISSUER, '-', "Print issuer DN"},
38 {"lastupdate", OPT_LASTUPDATE, '-', "Set lastUpdate field"},
39 {"nextupdate", OPT_NEXTUPDATE, '-', "Set nextUpdate field"},
40 {"noout", OPT_NOOUT, '-', "No CRL output"},
41 {"fingerprint", OPT_FINGERPRINT, '-', "Print the crl fingerprint"},
42 {"crlnumber", OPT_CRLNUMBER, '-', "Print CRL number"},
FdaSilvaYY16e1b282016-03-20 21:14:10 +010043 {"badsig", OPT_BADSIG, '-', "Corrupt last byte of loaded CRL signature (for test)" },
FdaSilvaYY12d56b22016-07-31 19:02:50 +020044 {"gendelta", OPT_GENDELTA, '<', "Other CRL to compare/diff to the Input one"},
Rich Salz7e1b7482015-04-24 15:26:15 -040045 {"CApath", OPT_CAPATH, '/', "Verify CRL using certificates in dir"},
46 {"CAfile", OPT_CAFILE, '<', "Verify CRL using certificates in file name"},
Matt Caswell2b6bcb72015-09-22 16:00:52 +010047 {"no-CAfile", OPT_NOCAFILE, '-',
48 "Do not load the default certificates file"},
49 {"no-CApath", OPT_NOCAPATH, '-',
50 "Do not load certificates from the default certificates directory"},
FdaSilvaYY16e1b282016-03-20 21:14:10 +010051 {"verify", OPT_VERIFY, '-', "Verify CRL signature"},
Rich Salz7e1b7482015-04-24 15:26:15 -040052 {"text", OPT_TEXT, '-', "Print out a text format version"},
53 {"hash", OPT_HASH, '-', "Print hash value"},
Rich Salz9c3bcfa2015-05-15 13:50:38 -040054 {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"},
55 {"", OPT_MD, '-', "Any supported digest"},
Tim Hudsonde2d97c2014-04-03 13:23:51 +010056#ifndef OPENSSL_NO_MD5
Rich Salz7e1b7482015-04-24 15:26:15 -040057 {"hash_old", OPT_HASH_OLD, '-', "Print old-style (MD5) hash value"},
Tim Hudsonde2d97c2014-04-03 13:23:51 +010058#endif
Rich Salz7e1b7482015-04-24 15:26:15 -040059 {NULL}
Ralf S. Engelschalld02b48c1998-12-21 10:52:47 +000060};
61
Rich Salz7e1b7482015-04-24 15:26:15 -040062int crl_main(int argc, char **argv)
Matt Caswell0f113f32015-01-22 03:40:55 +000063{
Matt Caswell0f113f32015-01-22 03:40:55 +000064 X509_CRL *x = NULL;
Matt Caswell0f113f32015-01-22 03:40:55 +000065 BIO *out = NULL;
Matt Caswell0f113f32015-01-22 03:40:55 +000066 X509_STORE *store = NULL;
Rich Salzf0e0fd52016-04-14 23:59:26 -040067 X509_STORE_CTX *ctx = NULL;
Matt Caswell0f113f32015-01-22 03:40:55 +000068 X509_LOOKUP *lookup = NULL;
Rich Salzf0e0fd52016-04-14 23:59:26 -040069 X509_OBJECT *xobj = NULL;
Matt Caswell0f113f32015-01-22 03:40:55 +000070 EVP_PKEY *pkey;
Rich Salz7e1b7482015-04-24 15:26:15 -040071 const EVP_MD *digest = EVP_sha1();
72 unsigned long nmflag = 0;
Richard Levittef1cece52015-07-07 11:13:20 +020073 char nmflag_set = 0;
Rich Salz7e1b7482015-04-24 15:26:15 -040074 char *infile = NULL, *outfile = NULL, *crldiff = NULL, *keyfile = NULL;
FdaSilvaYYcc696292016-08-04 23:52:22 +020075 const char *CAfile = NULL, *CApath = NULL, *prog;
Rich Salz7e1b7482015-04-24 15:26:15 -040076 OPTION_CHOICE o;
Rich Salz9c3bcfa2015-05-15 13:50:38 -040077 int hash = 0, issuer = 0, lastupdate = 0, nextupdate = 0, noout = 0;
Rich Salz7e1b7482015-04-24 15:26:15 -040078 int informat = FORMAT_PEM, outformat = FORMAT_PEM, keyformat = FORMAT_PEM;
Rich Salz9c3bcfa2015-05-15 13:50:38 -040079 int ret = 1, num = 0, badsig = 0, fingerprint = 0, crlnumber = 0;
Matt Caswell2b6bcb72015-09-22 16:00:52 +010080 int text = 0, do_ver = 0, noCAfile = 0, noCApath = 0;
Rich Salz9c3bcfa2015-05-15 13:50:38 -040081 int i;
Tim Hudsonde2d97c2014-04-03 13:23:51 +010082#ifndef OPENSSL_NO_MD5
Rich Salz7e1b7482015-04-24 15:26:15 -040083 int hash_old = 0;
Tim Hudsonde2d97c2014-04-03 13:23:51 +010084#endif
Rich Salz7e1b7482015-04-24 15:26:15 -040085
86 prog = opt_init(argc, argv, crl_options);
87 while ((o = opt_next()) != OPT_EOF) {
88 switch (o) {
89 case OPT_EOF:
90 case OPT_ERR:
91 opthelp:
92 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
93 goto end;
94 case OPT_HELP:
95 opt_help(crl_options);
96 ret = 0;
97 goto end;
98 case OPT_INFORM:
99 if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat))
100 goto opthelp;
Matt Caswell0f113f32015-01-22 03:40:55 +0000101 break;
Rich Salz7e1b7482015-04-24 15:26:15 -0400102 case OPT_IN:
103 infile = opt_arg();
104 break;
105 case OPT_OUTFORM:
106 if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
107 goto opthelp;
108 break;
109 case OPT_OUT:
110 outfile = opt_arg();
111 break;
112 case OPT_KEYFORM:
113 if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &keyformat))
114 goto opthelp;
115 break;
116 case OPT_KEY:
117 keyfile = opt_arg();
118 break;
119 case OPT_GENDELTA:
120 crldiff = opt_arg();
121 break;
122 case OPT_CAPATH:
123 CApath = opt_arg();
124 do_ver = 1;
125 break;
126 case OPT_CAFILE:
127 CAfile = opt_arg();
128 do_ver = 1;
129 break;
Matt Caswell2b6bcb72015-09-22 16:00:52 +0100130 case OPT_NOCAPATH:
131 noCApath = 1;
132 break;
133 case OPT_NOCAFILE:
134 noCAfile = 1;
135 break;
Rich Salz7e1b7482015-04-24 15:26:15 -0400136 case OPT_HASH_OLD:
Rich Salz9c3bcfa2015-05-15 13:50:38 -0400137#ifndef OPENSSL_NO_MD5
Rich Salz7e1b7482015-04-24 15:26:15 -0400138 hash_old = ++num;
Rich Salz7e1b7482015-04-24 15:26:15 -0400139#endif
Rich Salz9c3bcfa2015-05-15 13:50:38 -0400140 break;
Rich Salz7e1b7482015-04-24 15:26:15 -0400141 case OPT_VERIFY:
142 do_ver = 1;
143 break;
144 case OPT_TEXT:
145 text = 1;
146 break;
147 case OPT_HASH:
148 hash = ++num;
149 break;
150 case OPT_ISSUER:
151 issuer = ++num;
152 break;
153 case OPT_LASTUPDATE:
154 lastupdate = ++num;
155 break;
156 case OPT_NEXTUPDATE:
157 nextupdate = ++num;
158 break;
159 case OPT_NOOUT:
160 noout = ++num;
161 break;
162 case OPT_FINGERPRINT:
163 fingerprint = ++num;
164 break;
165 case OPT_CRLNUMBER:
166 crlnumber = ++num;
167 break;
168 case OPT_BADSIG:
169 badsig = 1;
170 break;
171 case OPT_NAMEOPT:
Richard Levittef1cece52015-07-07 11:13:20 +0200172 nmflag_set = 1;
Rich Salz7e1b7482015-04-24 15:26:15 -0400173 if (!set_name_ex(&nmflag, opt_arg()))
174 goto opthelp;
175 break;
176 case OPT_MD:
177 if (!opt_md(opt_unknown(), &digest))
178 goto opthelp;
Matt Caswell0f113f32015-01-22 03:40:55 +0000179 }
Matt Caswell0f113f32015-01-22 03:40:55 +0000180 }
Rich Salz7e1b7482015-04-24 15:26:15 -0400181 argc = opt_num_rest();
Kurt Roeckx03358512016-02-14 20:45:02 +0100182 if (argc != 0)
183 goto opthelp;
Ralf S. Engelschalld02b48c1998-12-21 10:52:47 +0000184
Richard Levittef1cece52015-07-07 11:13:20 +0200185 if (!nmflag_set)
186 nmflag = XN_FLAG_ONELINE;
187
Matt Caswell0f113f32015-01-22 03:40:55 +0000188 x = load_crl(infile, informat);
Rich Salz7e1b7482015-04-24 15:26:15 -0400189 if (x == NULL)
Matt Caswell0f113f32015-01-22 03:40:55 +0000190 goto end;
Ralf S. Engelschalld02b48c1998-12-21 10:52:47 +0000191
Matt Caswell0f113f32015-01-22 03:40:55 +0000192 if (do_ver) {
Matt Caswell2b6bcb72015-09-22 16:00:52 +0100193 if ((store = setup_verify(CAfile, CApath, noCAfile, noCApath)) == NULL)
Rich Salz7e1b7482015-04-24 15:26:15 -0400194 goto end;
Matt Caswell0f113f32015-01-22 03:40:55 +0000195 lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
196 if (lookup == NULL)
197 goto end;
Rich Salzf0e0fd52016-04-14 23:59:26 -0400198 ctx = X509_STORE_CTX_new();
Matt Caswell70015712016-04-29 11:29:50 +0100199 if (ctx == NULL || !X509_STORE_CTX_init(ctx, store, NULL, NULL)) {
Matt Caswell0f113f32015-01-22 03:40:55 +0000200 BIO_printf(bio_err, "Error initialising X509 store\n");
201 goto end;
202 }
Dr. Stephen Henson090d8481999-09-18 01:42:02 +0000203
Rich Salz6ddbb4c2016-05-17 16:06:09 -0400204 xobj = X509_STORE_CTX_get_obj_by_subject(ctx, X509_LU_X509,
205 X509_CRL_get_issuer(x));
Rich Salzf0e0fd52016-04-14 23:59:26 -0400206 if (xobj == NULL) {
Matt Caswell0f113f32015-01-22 03:40:55 +0000207 BIO_printf(bio_err, "Error getting CRL issuer certificate\n");
208 goto end;
209 }
Rich Salzf0e0fd52016-04-14 23:59:26 -0400210 pkey = X509_get_pubkey(X509_OBJECT_get0_X509(xobj));
211 X509_OBJECT_free(xobj);
Matt Caswell0f113f32015-01-22 03:40:55 +0000212 if (!pkey) {
213 BIO_printf(bio_err, "Error getting CRL issuer public key\n");
214 goto end;
215 }
216 i = X509_CRL_verify(x, pkey);
Rich Salzf0e0fd52016-04-14 23:59:26 -0400217 EVP_PKEY_free(pkey);
Matt Caswell0f113f32015-01-22 03:40:55 +0000218 if (i < 0)
219 goto end;
220 if (i == 0)
221 BIO_printf(bio_err, "verify failure\n");
222 else
223 BIO_printf(bio_err, "verify OK\n");
224 }
Dr. Stephen Henson2e8cb102012-12-04 18:35:36 +0000225
Matt Caswell0f113f32015-01-22 03:40:55 +0000226 if (crldiff) {
227 X509_CRL *newcrl, *delta;
228 if (!keyfile) {
229 BIO_puts(bio_err, "Missing CRL signing key\n");
230 goto end;
231 }
232 newcrl = load_crl(crldiff, informat);
233 if (!newcrl)
234 goto end;
Rich Salz7e1b7482015-04-24 15:26:15 -0400235 pkey = load_key(keyfile, keyformat, 0, NULL, NULL, "CRL signing key");
Matt Caswell0f113f32015-01-22 03:40:55 +0000236 if (!pkey) {
237 X509_CRL_free(newcrl);
238 goto end;
239 }
240 delta = X509_CRL_diff(x, newcrl, pkey, digest, 0);
241 X509_CRL_free(newcrl);
242 EVP_PKEY_free(pkey);
243 if (delta) {
244 X509_CRL_free(x);
245 x = delta;
246 } else {
247 BIO_puts(bio_err, "Error creating delta CRL\n");
248 goto end;
249 }
250 }
251
Dr. Stephen Henson0f022f52016-08-16 15:19:55 +0100252 if (badsig) {
Matt Caswell5e6089f2016-08-13 14:44:07 +0100253 const ASN1_BIT_STRING *sig;
Dr. Stephen Henson0f022f52016-08-16 15:19:55 +0100254
Matt Caswell5e6089f2016-08-13 14:44:07 +0100255 X509_CRL_get0_signature(x, &sig, NULL);
Dr. Stephen Hensona0754082016-08-17 12:34:22 +0100256 corrupt_signature(sig);
Dr. Stephen Henson0f022f52016-08-16 15:19:55 +0100257 }
258
Matt Caswell0f113f32015-01-22 03:40:55 +0000259 if (num) {
260 for (i = 1; i <= num; i++) {
261 if (issuer == i) {
262 print_name(bio_out, "issuer=", X509_CRL_get_issuer(x),
263 nmflag);
264 }
265 if (crlnumber == i) {
266 ASN1_INTEGER *crlnum;
267 crlnum = X509_CRL_get_ext_d2i(x, NID_crl_number, NULL, NULL);
268 BIO_printf(bio_out, "crlNumber=");
269 if (crlnum) {
270 i2a_ASN1_INTEGER(bio_out, crlnum);
271 ASN1_INTEGER_free(crlnum);
272 } else
273 BIO_puts(bio_out, "<NONE>");
274 BIO_printf(bio_out, "\n");
275 }
276 if (hash == i) {
277 BIO_printf(bio_out, "%08lx\n",
278 X509_NAME_hash(X509_CRL_get_issuer(x)));
279 }
Tim Hudsonde2d97c2014-04-03 13:23:51 +0100280#ifndef OPENSSL_NO_MD5
Matt Caswell0f113f32015-01-22 03:40:55 +0000281 if (hash_old == i) {
282 BIO_printf(bio_out, "%08lx\n",
283 X509_NAME_hash_old(X509_CRL_get_issuer(x)));
284 }
Tim Hudsonde2d97c2014-04-03 13:23:51 +0100285#endif
Matt Caswell0f113f32015-01-22 03:40:55 +0000286 if (lastupdate == i) {
287 BIO_printf(bio_out, "lastUpdate=");
Dr. Stephen Henson568ce3a2016-08-19 12:39:57 +0100288 ASN1_TIME_print(bio_out, X509_CRL_get0_lastUpdate(x));
Matt Caswell0f113f32015-01-22 03:40:55 +0000289 BIO_printf(bio_out, "\n");
290 }
291 if (nextupdate == i) {
292 BIO_printf(bio_out, "nextUpdate=");
Dr. Stephen Henson568ce3a2016-08-19 12:39:57 +0100293 if (X509_CRL_get0_nextUpdate(x))
294 ASN1_TIME_print(bio_out, X509_CRL_get0_nextUpdate(x));
Matt Caswell0f113f32015-01-22 03:40:55 +0000295 else
296 BIO_printf(bio_out, "NONE");
297 BIO_printf(bio_out, "\n");
298 }
299 if (fingerprint == i) {
300 int j;
301 unsigned int n;
302 unsigned char md[EVP_MAX_MD_SIZE];
Dr. Stephen Henson439df502000-05-18 00:33:00 +0000303
Matt Caswell0f113f32015-01-22 03:40:55 +0000304 if (!X509_CRL_digest(x, digest, md, &n)) {
305 BIO_printf(bio_err, "out of memory\n");
306 goto end;
307 }
308 BIO_printf(bio_out, "%s Fingerprint=",
309 OBJ_nid2sn(EVP_MD_type(digest)));
310 for (j = 0; j < (int)n; j++) {
311 BIO_printf(bio_out, "%02X%c", md[j], (j + 1 == (int)n)
312 ? '\n' : ':');
313 }
314 }
315 }
316 }
Richard Levittebdd58d92015-09-04 12:49:06 +0200317 out = bio_open_default(outfile, 'w', outformat);
Rich Salz7e1b7482015-04-24 15:26:15 -0400318 if (out == NULL)
Matt Caswell0f113f32015-01-22 03:40:55 +0000319 goto end;
Ralf S. Engelschalld02b48c1998-12-21 10:52:47 +0000320
Matt Caswell0f113f32015-01-22 03:40:55 +0000321 if (text)
322 X509_CRL_print(out, x);
Ralf S. Engelschall2f0cd191999-04-12 10:36:16 +0000323
Matt Caswell0f113f32015-01-22 03:40:55 +0000324 if (noout) {
325 ret = 0;
326 goto end;
327 }
Ralf S. Engelschall2f0cd191999-04-12 10:36:16 +0000328
Matt Caswell0f113f32015-01-22 03:40:55 +0000329 if (outformat == FORMAT_ASN1)
330 i = (int)i2d_X509_CRL_bio(out, x);
Rich Salz7e1b7482015-04-24 15:26:15 -0400331 else
Matt Caswell0f113f32015-01-22 03:40:55 +0000332 i = PEM_write_bio_X509_CRL(out, x);
Matt Caswell0f113f32015-01-22 03:40:55 +0000333 if (!i) {
334 BIO_printf(bio_err, "unable to write CRL\n");
335 goto end;
336 }
337 ret = 0;
Rich Salz7e1b7482015-04-24 15:26:15 -0400338
Matt Caswell0f113f32015-01-22 03:40:55 +0000339 end:
340 if (ret != 0)
341 ERR_print_errors(bio_err);
342 BIO_free_all(out);
Matt Caswell0f113f32015-01-22 03:40:55 +0000343 X509_CRL_free(x);
Rich Salzf0e0fd52016-04-14 23:59:26 -0400344 X509_STORE_CTX_free(ctx);
345 X509_STORE_free(store);
Rich Salz7e1b7482015-04-24 15:26:15 -0400346 return (ret);
Matt Caswell0f113f32015-01-22 03:40:55 +0000347}