mirror of
https://github.com/openssl/openssl.git
synced 2025-01-30 14:01:55 +08:00
dab2cd68e7
Everything in apps includes apps.h, because that one declares apps internal library routines. However, progs.h doesn't declare library routines, but rather the main commands and their options, and there's no reason why the library modules should include it. So, remove the inclusion of progs.h from apps.h and add that inclusion in all command source files. Reviewed-by: Rich Salz <rsalz@openssl.org> (Merged from https://github.com/openssl/openssl/pull/5222)
343 lines
11 KiB
C
343 lines
11 KiB
C
/*
|
|
* Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
|
|
*
|
|
* Licensed under the OpenSSL license (the "License"). You may not use
|
|
* this file except in compliance with the License. You can obtain a copy
|
|
* in the file LICENSE in the source distribution or at
|
|
* https://www.openssl.org/source/license.html
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "apps.h"
|
|
#include "progs.h"
|
|
#include <openssl/bio.h>
|
|
#include <openssl/err.h>
|
|
#include <openssl/x509.h>
|
|
#include <openssl/x509v3.h>
|
|
#include <openssl/pem.h>
|
|
|
|
typedef enum OPTION_choice {
|
|
OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
|
|
OPT_INFORM, OPT_IN, OPT_OUTFORM, OPT_OUT, OPT_KEYFORM, OPT_KEY,
|
|
OPT_ISSUER, OPT_LASTUPDATE, OPT_NEXTUPDATE, OPT_FINGERPRINT,
|
|
OPT_CRLNUMBER, OPT_BADSIG, OPT_GENDELTA, OPT_CAPATH, OPT_CAFILE,
|
|
OPT_NOCAPATH, OPT_NOCAFILE, OPT_VERIFY, OPT_TEXT, OPT_HASH, OPT_HASH_OLD,
|
|
OPT_NOOUT, OPT_NAMEOPT, OPT_MD
|
|
} OPTION_CHOICE;
|
|
|
|
const OPTIONS crl_options[] = {
|
|
{"help", OPT_HELP, '-', "Display this summary"},
|
|
{"inform", OPT_INFORM, 'F', "Input format; default PEM"},
|
|
{"in", OPT_IN, '<', "Input file - default stdin"},
|
|
{"outform", OPT_OUTFORM, 'F', "Output format - default PEM"},
|
|
{"out", OPT_OUT, '>', "output file - default stdout"},
|
|
{"keyform", OPT_KEYFORM, 'F', "Private key file format (PEM or ENGINE)"},
|
|
{"key", OPT_KEY, '<', "CRL signing Private key to use"},
|
|
{"issuer", OPT_ISSUER, '-', "Print issuer DN"},
|
|
{"lastupdate", OPT_LASTUPDATE, '-', "Set lastUpdate field"},
|
|
{"nextupdate", OPT_NEXTUPDATE, '-', "Set nextUpdate field"},
|
|
{"noout", OPT_NOOUT, '-', "No CRL output"},
|
|
{"fingerprint", OPT_FINGERPRINT, '-', "Print the crl fingerprint"},
|
|
{"crlnumber", OPT_CRLNUMBER, '-', "Print CRL number"},
|
|
{"badsig", OPT_BADSIG, '-', "Corrupt last byte of loaded CRL signature (for test)" },
|
|
{"gendelta", OPT_GENDELTA, '<', "Other CRL to compare/diff to the Input one"},
|
|
{"CApath", OPT_CAPATH, '/', "Verify CRL using certificates in dir"},
|
|
{"CAfile", OPT_CAFILE, '<', "Verify CRL using certificates in file name"},
|
|
{"no-CAfile", OPT_NOCAFILE, '-',
|
|
"Do not load the default certificates file"},
|
|
{"no-CApath", OPT_NOCAPATH, '-',
|
|
"Do not load certificates from the default certificates directory"},
|
|
{"verify", OPT_VERIFY, '-', "Verify CRL signature"},
|
|
{"text", OPT_TEXT, '-', "Print out a text format version"},
|
|
{"hash", OPT_HASH, '-', "Print hash value"},
|
|
{"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"},
|
|
{"", OPT_MD, '-', "Any supported digest"},
|
|
#ifndef OPENSSL_NO_MD5
|
|
{"hash_old", OPT_HASH_OLD, '-', "Print old-style (MD5) hash value"},
|
|
#endif
|
|
{NULL}
|
|
};
|
|
|
|
int crl_main(int argc, char **argv)
|
|
{
|
|
X509_CRL *x = NULL;
|
|
BIO *out = NULL;
|
|
X509_STORE *store = NULL;
|
|
X509_STORE_CTX *ctx = NULL;
|
|
X509_LOOKUP *lookup = NULL;
|
|
X509_OBJECT *xobj = NULL;
|
|
EVP_PKEY *pkey;
|
|
const EVP_MD *digest = EVP_sha1();
|
|
char *infile = NULL, *outfile = NULL, *crldiff = NULL, *keyfile = NULL;
|
|
const char *CAfile = NULL, *CApath = NULL, *prog;
|
|
OPTION_CHOICE o;
|
|
int hash = 0, issuer = 0, lastupdate = 0, nextupdate = 0, noout = 0;
|
|
int informat = FORMAT_PEM, outformat = FORMAT_PEM, keyformat = FORMAT_PEM;
|
|
int ret = 1, num = 0, badsig = 0, fingerprint = 0, crlnumber = 0;
|
|
int text = 0, do_ver = 0, noCAfile = 0, noCApath = 0;
|
|
int i;
|
|
#ifndef OPENSSL_NO_MD5
|
|
int hash_old = 0;
|
|
#endif
|
|
|
|
prog = opt_init(argc, argv, crl_options);
|
|
while ((o = opt_next()) != OPT_EOF) {
|
|
switch (o) {
|
|
case OPT_EOF:
|
|
case OPT_ERR:
|
|
opthelp:
|
|
BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
|
|
goto end;
|
|
case OPT_HELP:
|
|
opt_help(crl_options);
|
|
ret = 0;
|
|
goto end;
|
|
case OPT_INFORM:
|
|
if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat))
|
|
goto opthelp;
|
|
break;
|
|
case OPT_IN:
|
|
infile = opt_arg();
|
|
break;
|
|
case OPT_OUTFORM:
|
|
if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
|
|
goto opthelp;
|
|
break;
|
|
case OPT_OUT:
|
|
outfile = opt_arg();
|
|
break;
|
|
case OPT_KEYFORM:
|
|
if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &keyformat))
|
|
goto opthelp;
|
|
break;
|
|
case OPT_KEY:
|
|
keyfile = opt_arg();
|
|
break;
|
|
case OPT_GENDELTA:
|
|
crldiff = opt_arg();
|
|
break;
|
|
case OPT_CAPATH:
|
|
CApath = opt_arg();
|
|
do_ver = 1;
|
|
break;
|
|
case OPT_CAFILE:
|
|
CAfile = opt_arg();
|
|
do_ver = 1;
|
|
break;
|
|
case OPT_NOCAPATH:
|
|
noCApath = 1;
|
|
break;
|
|
case OPT_NOCAFILE:
|
|
noCAfile = 1;
|
|
break;
|
|
case OPT_HASH_OLD:
|
|
#ifndef OPENSSL_NO_MD5
|
|
hash_old = ++num;
|
|
#endif
|
|
break;
|
|
case OPT_VERIFY:
|
|
do_ver = 1;
|
|
break;
|
|
case OPT_TEXT:
|
|
text = 1;
|
|
break;
|
|
case OPT_HASH:
|
|
hash = ++num;
|
|
break;
|
|
case OPT_ISSUER:
|
|
issuer = ++num;
|
|
break;
|
|
case OPT_LASTUPDATE:
|
|
lastupdate = ++num;
|
|
break;
|
|
case OPT_NEXTUPDATE:
|
|
nextupdate = ++num;
|
|
break;
|
|
case OPT_NOOUT:
|
|
noout = ++num;
|
|
break;
|
|
case OPT_FINGERPRINT:
|
|
fingerprint = ++num;
|
|
break;
|
|
case OPT_CRLNUMBER:
|
|
crlnumber = ++num;
|
|
break;
|
|
case OPT_BADSIG:
|
|
badsig = 1;
|
|
break;
|
|
case OPT_NAMEOPT:
|
|
if (!set_nameopt(opt_arg()))
|
|
goto opthelp;
|
|
break;
|
|
case OPT_MD:
|
|
if (!opt_md(opt_unknown(), &digest))
|
|
goto opthelp;
|
|
}
|
|
}
|
|
argc = opt_num_rest();
|
|
if (argc != 0)
|
|
goto opthelp;
|
|
|
|
x = load_crl(infile, informat);
|
|
if (x == NULL)
|
|
goto end;
|
|
|
|
if (do_ver) {
|
|
if ((store = setup_verify(CAfile, CApath, noCAfile, noCApath)) == NULL)
|
|
goto end;
|
|
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
|
|
if (lookup == NULL)
|
|
goto end;
|
|
ctx = X509_STORE_CTX_new();
|
|
if (ctx == NULL || !X509_STORE_CTX_init(ctx, store, NULL, NULL)) {
|
|
BIO_printf(bio_err, "Error initialising X509 store\n");
|
|
goto end;
|
|
}
|
|
|
|
xobj = X509_STORE_CTX_get_obj_by_subject(ctx, X509_LU_X509,
|
|
X509_CRL_get_issuer(x));
|
|
if (xobj == NULL) {
|
|
BIO_printf(bio_err, "Error getting CRL issuer certificate\n");
|
|
goto end;
|
|
}
|
|
pkey = X509_get_pubkey(X509_OBJECT_get0_X509(xobj));
|
|
X509_OBJECT_free(xobj);
|
|
if (!pkey) {
|
|
BIO_printf(bio_err, "Error getting CRL issuer public key\n");
|
|
goto end;
|
|
}
|
|
i = X509_CRL_verify(x, pkey);
|
|
EVP_PKEY_free(pkey);
|
|
if (i < 0)
|
|
goto end;
|
|
if (i == 0)
|
|
BIO_printf(bio_err, "verify failure\n");
|
|
else
|
|
BIO_printf(bio_err, "verify OK\n");
|
|
}
|
|
|
|
if (crldiff) {
|
|
X509_CRL *newcrl, *delta;
|
|
if (!keyfile) {
|
|
BIO_puts(bio_err, "Missing CRL signing key\n");
|
|
goto end;
|
|
}
|
|
newcrl = load_crl(crldiff, informat);
|
|
if (!newcrl)
|
|
goto end;
|
|
pkey = load_key(keyfile, keyformat, 0, NULL, NULL, "CRL signing key");
|
|
if (!pkey) {
|
|
X509_CRL_free(newcrl);
|
|
goto end;
|
|
}
|
|
delta = X509_CRL_diff(x, newcrl, pkey, digest, 0);
|
|
X509_CRL_free(newcrl);
|
|
EVP_PKEY_free(pkey);
|
|
if (delta) {
|
|
X509_CRL_free(x);
|
|
x = delta;
|
|
} else {
|
|
BIO_puts(bio_err, "Error creating delta CRL\n");
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
if (badsig) {
|
|
const ASN1_BIT_STRING *sig;
|
|
|
|
X509_CRL_get0_signature(x, &sig, NULL);
|
|
corrupt_signature(sig);
|
|
}
|
|
|
|
if (num) {
|
|
for (i = 1; i <= num; i++) {
|
|
if (issuer == i) {
|
|
print_name(bio_out, "issuer=", X509_CRL_get_issuer(x),
|
|
get_nameopt());
|
|
}
|
|
if (crlnumber == i) {
|
|
ASN1_INTEGER *crlnum;
|
|
crlnum = X509_CRL_get_ext_d2i(x, NID_crl_number, NULL, NULL);
|
|
BIO_printf(bio_out, "crlNumber=");
|
|
if (crlnum) {
|
|
i2a_ASN1_INTEGER(bio_out, crlnum);
|
|
ASN1_INTEGER_free(crlnum);
|
|
} else
|
|
BIO_puts(bio_out, "<NONE>");
|
|
BIO_printf(bio_out, "\n");
|
|
}
|
|
if (hash == i) {
|
|
BIO_printf(bio_out, "%08lx\n",
|
|
X509_NAME_hash(X509_CRL_get_issuer(x)));
|
|
}
|
|
#ifndef OPENSSL_NO_MD5
|
|
if (hash_old == i) {
|
|
BIO_printf(bio_out, "%08lx\n",
|
|
X509_NAME_hash_old(X509_CRL_get_issuer(x)));
|
|
}
|
|
#endif
|
|
if (lastupdate == i) {
|
|
BIO_printf(bio_out, "lastUpdate=");
|
|
ASN1_TIME_print(bio_out, X509_CRL_get0_lastUpdate(x));
|
|
BIO_printf(bio_out, "\n");
|
|
}
|
|
if (nextupdate == i) {
|
|
BIO_printf(bio_out, "nextUpdate=");
|
|
if (X509_CRL_get0_nextUpdate(x))
|
|
ASN1_TIME_print(bio_out, X509_CRL_get0_nextUpdate(x));
|
|
else
|
|
BIO_printf(bio_out, "NONE");
|
|
BIO_printf(bio_out, "\n");
|
|
}
|
|
if (fingerprint == i) {
|
|
int j;
|
|
unsigned int n;
|
|
unsigned char md[EVP_MAX_MD_SIZE];
|
|
|
|
if (!X509_CRL_digest(x, digest, md, &n)) {
|
|
BIO_printf(bio_err, "out of memory\n");
|
|
goto end;
|
|
}
|
|
BIO_printf(bio_out, "%s Fingerprint=",
|
|
OBJ_nid2sn(EVP_MD_type(digest)));
|
|
for (j = 0; j < (int)n; j++) {
|
|
BIO_printf(bio_out, "%02X%c", md[j], (j + 1 == (int)n)
|
|
? '\n' : ':');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
out = bio_open_default(outfile, 'w', outformat);
|
|
if (out == NULL)
|
|
goto end;
|
|
|
|
if (text)
|
|
X509_CRL_print_ex(out, x, get_nameopt());
|
|
|
|
if (noout) {
|
|
ret = 0;
|
|
goto end;
|
|
}
|
|
|
|
if (outformat == FORMAT_ASN1)
|
|
i = (int)i2d_X509_CRL_bio(out, x);
|
|
else
|
|
i = PEM_write_bio_X509_CRL(out, x);
|
|
if (!i) {
|
|
BIO_printf(bio_err, "unable to write CRL\n");
|
|
goto end;
|
|
}
|
|
ret = 0;
|
|
|
|
end:
|
|
if (ret != 0)
|
|
ERR_print_errors(bio_err);
|
|
BIO_free_all(out);
|
|
X509_CRL_free(x);
|
|
X509_STORE_CTX_free(ctx);
|
|
X509_STORE_free(store);
|
|
return ret;
|
|
}
|