Home | History | Annotate | Line # | Download | only in apps
      1  1.1.1.2  christos /*
      2  1.1.1.2  christos  * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
      3      1.1  christos  *
      4  1.1.1.2  christos  * Licensed under the OpenSSL license (the "License").  You may not use
      5  1.1.1.2  christos  * this file except in compliance with the License.  You can obtain a copy
      6  1.1.1.2  christos  * in the file LICENSE in the source distribution or at
      7  1.1.1.2  christos  * https://www.openssl.org/source/license.html
      8      1.1  christos  */
      9      1.1  christos 
     10      1.1  christos #include <stdio.h>
     11      1.1  christos #include <stdlib.h>
     12      1.1  christos #include <string.h>
     13      1.1  christos #include "apps.h"
     14  1.1.1.2  christos #include "progs.h"
     15      1.1  christos #include <openssl/bio.h>
     16      1.1  christos #include <openssl/err.h>
     17      1.1  christos #include <openssl/x509.h>
     18      1.1  christos #include <openssl/x509v3.h>
     19      1.1  christos #include <openssl/pem.h>
     20      1.1  christos 
     21  1.1.1.2  christos typedef enum OPTION_choice {
     22  1.1.1.2  christos     OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
     23  1.1.1.2  christos     OPT_INFORM, OPT_IN, OPT_OUTFORM, OPT_OUT, OPT_KEYFORM, OPT_KEY,
     24  1.1.1.2  christos     OPT_ISSUER, OPT_LASTUPDATE, OPT_NEXTUPDATE, OPT_FINGERPRINT,
     25  1.1.1.2  christos     OPT_CRLNUMBER, OPT_BADSIG, OPT_GENDELTA, OPT_CAPATH, OPT_CAFILE,
     26  1.1.1.2  christos     OPT_NOCAPATH, OPT_NOCAFILE, OPT_VERIFY, OPT_TEXT, OPT_HASH, OPT_HASH_OLD,
     27  1.1.1.2  christos     OPT_NOOUT, OPT_NAMEOPT, OPT_MD
     28  1.1.1.2  christos } OPTION_CHOICE;
     29  1.1.1.2  christos 
     30  1.1.1.2  christos const OPTIONS crl_options[] = {
     31  1.1.1.2  christos     {"help", OPT_HELP, '-', "Display this summary"},
     32  1.1.1.2  christos     {"inform", OPT_INFORM, 'F', "Input format; default PEM"},
     33  1.1.1.2  christos     {"in", OPT_IN, '<', "Input file - default stdin"},
     34  1.1.1.2  christos     {"outform", OPT_OUTFORM, 'F', "Output format - default PEM"},
     35  1.1.1.2  christos     {"out", OPT_OUT, '>', "output file - default stdout"},
     36  1.1.1.2  christos     {"keyform", OPT_KEYFORM, 'F', "Private key file format (PEM or ENGINE)"},
     37  1.1.1.2  christos     {"key", OPT_KEY, '<', "CRL signing Private key to use"},
     38  1.1.1.2  christos     {"issuer", OPT_ISSUER, '-', "Print issuer DN"},
     39  1.1.1.2  christos     {"lastupdate", OPT_LASTUPDATE, '-', "Set lastUpdate field"},
     40  1.1.1.2  christos     {"nextupdate", OPT_NEXTUPDATE, '-', "Set nextUpdate field"},
     41  1.1.1.2  christos     {"noout", OPT_NOOUT, '-', "No CRL output"},
     42  1.1.1.2  christos     {"fingerprint", OPT_FINGERPRINT, '-', "Print the crl fingerprint"},
     43  1.1.1.2  christos     {"crlnumber", OPT_CRLNUMBER, '-', "Print CRL number"},
     44  1.1.1.2  christos     {"badsig", OPT_BADSIG, '-', "Corrupt last byte of loaded CRL signature (for test)" },
     45  1.1.1.2  christos     {"gendelta", OPT_GENDELTA, '<', "Other CRL to compare/diff to the Input one"},
     46  1.1.1.2  christos     {"CApath", OPT_CAPATH, '/', "Verify CRL using certificates in dir"},
     47  1.1.1.2  christos     {"CAfile", OPT_CAFILE, '<', "Verify CRL using certificates in file name"},
     48  1.1.1.2  christos     {"no-CAfile", OPT_NOCAFILE, '-',
     49  1.1.1.2  christos      "Do not load the default certificates file"},
     50  1.1.1.2  christos     {"no-CApath", OPT_NOCAPATH, '-',
     51  1.1.1.2  christos      "Do not load certificates from the default certificates directory"},
     52  1.1.1.2  christos     {"verify", OPT_VERIFY, '-', "Verify CRL signature"},
     53  1.1.1.2  christos     {"text", OPT_TEXT, '-', "Print out a text format version"},
     54  1.1.1.2  christos     {"hash", OPT_HASH, '-', "Print hash value"},
     55  1.1.1.2  christos     {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"},
     56  1.1.1.2  christos     {"", OPT_MD, '-', "Any supported digest"},
     57      1.1  christos #ifndef OPENSSL_NO_MD5
     58  1.1.1.2  christos     {"hash_old", OPT_HASH_OLD, '-', "Print old-style (MD5) hash value"},
     59      1.1  christos #endif
     60  1.1.1.2  christos     {NULL}
     61      1.1  christos };
     62      1.1  christos 
     63  1.1.1.2  christos int crl_main(int argc, char **argv)
     64      1.1  christos {
     65      1.1  christos     X509_CRL *x = NULL;
     66      1.1  christos     BIO *out = NULL;
     67      1.1  christos     X509_STORE *store = NULL;
     68  1.1.1.2  christos     X509_STORE_CTX *ctx = NULL;
     69      1.1  christos     X509_LOOKUP *lookup = NULL;
     70  1.1.1.2  christos     X509_OBJECT *xobj = NULL;
     71      1.1  christos     EVP_PKEY *pkey;
     72  1.1.1.2  christos     const EVP_MD *digest = EVP_sha1();
     73  1.1.1.2  christos     char *infile = NULL, *outfile = NULL, *crldiff = NULL, *keyfile = NULL;
     74  1.1.1.2  christos     const char *CAfile = NULL, *CApath = NULL, *prog;
     75  1.1.1.2  christos     OPTION_CHOICE o;
     76  1.1.1.2  christos     int hash = 0, issuer = 0, lastupdate = 0, nextupdate = 0, noout = 0;
     77  1.1.1.2  christos     int informat = FORMAT_PEM, outformat = FORMAT_PEM, keyformat = FORMAT_PEM;
     78  1.1.1.2  christos     int ret = 1, num = 0, badsig = 0, fingerprint = 0, crlnumber = 0;
     79  1.1.1.2  christos     int text = 0, do_ver = 0, noCAfile = 0, noCApath = 0;
     80  1.1.1.2  christos     int i;
     81  1.1.1.2  christos #ifndef OPENSSL_NO_MD5
     82  1.1.1.2  christos     int hash_old = 0;
     83      1.1  christos #endif
     84      1.1  christos 
     85  1.1.1.2  christos     prog = opt_init(argc, argv, crl_options);
     86  1.1.1.2  christos     while ((o = opt_next()) != OPT_EOF) {
     87  1.1.1.2  christos         switch (o) {
     88  1.1.1.2  christos         case OPT_EOF:
     89  1.1.1.2  christos         case OPT_ERR:
     90  1.1.1.2  christos  opthelp:
     91  1.1.1.2  christos             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
     92  1.1.1.2  christos             goto end;
     93  1.1.1.2  christos         case OPT_HELP:
     94  1.1.1.2  christos             opt_help(crl_options);
     95  1.1.1.2  christos             ret = 0;
     96  1.1.1.2  christos             goto end;
     97  1.1.1.2  christos         case OPT_INFORM:
     98  1.1.1.2  christos             if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat))
     99  1.1.1.2  christos                 goto opthelp;
    100  1.1.1.2  christos             break;
    101  1.1.1.2  christos         case OPT_IN:
    102  1.1.1.2  christos             infile = opt_arg();
    103  1.1.1.2  christos             break;
    104  1.1.1.2  christos         case OPT_OUTFORM:
    105  1.1.1.2  christos             if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
    106  1.1.1.2  christos                 goto opthelp;
    107  1.1.1.2  christos             break;
    108  1.1.1.2  christos         case OPT_OUT:
    109  1.1.1.2  christos             outfile = opt_arg();
    110  1.1.1.2  christos             break;
    111  1.1.1.2  christos         case OPT_KEYFORM:
    112  1.1.1.2  christos             if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &keyformat))
    113  1.1.1.2  christos                 goto opthelp;
    114  1.1.1.2  christos             break;
    115  1.1.1.2  christos         case OPT_KEY:
    116  1.1.1.2  christos             keyfile = opt_arg();
    117  1.1.1.2  christos             break;
    118  1.1.1.2  christos         case OPT_GENDELTA:
    119  1.1.1.2  christos             crldiff = opt_arg();
    120  1.1.1.2  christos             break;
    121  1.1.1.2  christos         case OPT_CAPATH:
    122  1.1.1.2  christos             CApath = opt_arg();
    123      1.1  christos             do_ver = 1;
    124  1.1.1.2  christos             break;
    125  1.1.1.2  christos         case OPT_CAFILE:
    126  1.1.1.2  christos             CAfile = opt_arg();
    127      1.1  christos             do_ver = 1;
    128  1.1.1.2  christos             break;
    129  1.1.1.2  christos         case OPT_NOCAPATH:
    130  1.1.1.2  christos             noCApath =  1;
    131  1.1.1.2  christos             break;
    132  1.1.1.2  christos         case OPT_NOCAFILE:
    133  1.1.1.2  christos             noCAfile =  1;
    134  1.1.1.2  christos             break;
    135  1.1.1.2  christos         case OPT_HASH_OLD:
    136      1.1  christos #ifndef OPENSSL_NO_MD5
    137      1.1  christos             hash_old = ++num;
    138      1.1  christos #endif
    139  1.1.1.2  christos             break;
    140  1.1.1.2  christos         case OPT_VERIFY:
    141  1.1.1.2  christos             do_ver = 1;
    142  1.1.1.2  christos             break;
    143  1.1.1.2  christos         case OPT_TEXT:
    144  1.1.1.2  christos             text = 1;
    145  1.1.1.2  christos             break;
    146  1.1.1.2  christos         case OPT_HASH:
    147  1.1.1.2  christos             hash = ++num;
    148  1.1.1.2  christos             break;
    149  1.1.1.2  christos         case OPT_ISSUER:
    150      1.1  christos             issuer = ++num;
    151  1.1.1.2  christos             break;
    152  1.1.1.2  christos         case OPT_LASTUPDATE:
    153      1.1  christos             lastupdate = ++num;
    154  1.1.1.2  christos             break;
    155  1.1.1.2  christos         case OPT_NEXTUPDATE:
    156      1.1  christos             nextupdate = ++num;
    157  1.1.1.2  christos             break;
    158  1.1.1.2  christos         case OPT_NOOUT:
    159      1.1  christos             noout = ++num;
    160  1.1.1.2  christos             break;
    161  1.1.1.2  christos         case OPT_FINGERPRINT:
    162      1.1  christos             fingerprint = ++num;
    163  1.1.1.2  christos             break;
    164  1.1.1.2  christos         case OPT_CRLNUMBER:
    165      1.1  christos             crlnumber = ++num;
    166  1.1.1.2  christos             break;
    167  1.1.1.2  christos         case OPT_BADSIG:
    168      1.1  christos             badsig = 1;
    169      1.1  christos             break;
    170  1.1.1.2  christos         case OPT_NAMEOPT:
    171  1.1.1.2  christos             if (!set_nameopt(opt_arg()))
    172  1.1.1.2  christos                 goto opthelp;
    173  1.1.1.2  christos             break;
    174  1.1.1.2  christos         case OPT_MD:
    175  1.1.1.2  christos             if (!opt_md(opt_unknown(), &digest))
    176  1.1.1.2  christos                 goto opthelp;
    177      1.1  christos         }
    178      1.1  christos     }
    179  1.1.1.2  christos     argc = opt_num_rest();
    180  1.1.1.2  christos     if (argc != 0)
    181  1.1.1.2  christos         goto opthelp;
    182      1.1  christos 
    183      1.1  christos     x = load_crl(infile, informat);
    184  1.1.1.2  christos     if (x == NULL)
    185      1.1  christos         goto end;
    186      1.1  christos 
    187      1.1  christos     if (do_ver) {
    188  1.1.1.2  christos         if ((store = setup_verify(CAfile, CApath, noCAfile, noCApath)) == NULL)
    189      1.1  christos             goto end;
    190  1.1.1.2  christos         lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
    191      1.1  christos         if (lookup == NULL)
    192      1.1  christos             goto end;
    193  1.1.1.2  christos         ctx = X509_STORE_CTX_new();
    194  1.1.1.2  christos         if (ctx == NULL || !X509_STORE_CTX_init(ctx, store, NULL, NULL)) {
    195      1.1  christos             BIO_printf(bio_err, "Error initialising X509 store\n");
    196      1.1  christos             goto end;
    197      1.1  christos         }
    198      1.1  christos 
    199  1.1.1.2  christos         xobj = X509_STORE_CTX_get_obj_by_subject(ctx, X509_LU_X509,
    200  1.1.1.2  christos                                                  X509_CRL_get_issuer(x));
    201  1.1.1.2  christos         if (xobj == NULL) {
    202      1.1  christos             BIO_printf(bio_err, "Error getting CRL issuer certificate\n");
    203      1.1  christos             goto end;
    204      1.1  christos         }
    205  1.1.1.2  christos         pkey = X509_get_pubkey(X509_OBJECT_get0_X509(xobj));
    206  1.1.1.2  christos         X509_OBJECT_free(xobj);
    207      1.1  christos         if (!pkey) {
    208      1.1  christos             BIO_printf(bio_err, "Error getting CRL issuer public key\n");
    209      1.1  christos             goto end;
    210      1.1  christos         }
    211      1.1  christos         i = X509_CRL_verify(x, pkey);
    212      1.1  christos         EVP_PKEY_free(pkey);
    213      1.1  christos         if (i < 0)
    214      1.1  christos             goto end;
    215      1.1  christos         if (i == 0)
    216      1.1  christos             BIO_printf(bio_err, "verify failure\n");
    217      1.1  christos         else
    218      1.1  christos             BIO_printf(bio_err, "verify OK\n");
    219      1.1  christos     }
    220      1.1  christos 
    221      1.1  christos     if (crldiff) {
    222      1.1  christos         X509_CRL *newcrl, *delta;
    223      1.1  christos         if (!keyfile) {
    224      1.1  christos             BIO_puts(bio_err, "Missing CRL signing key\n");
    225      1.1  christos             goto end;
    226      1.1  christos         }
    227      1.1  christos         newcrl = load_crl(crldiff, informat);
    228      1.1  christos         if (!newcrl)
    229      1.1  christos             goto end;
    230  1.1.1.2  christos         pkey = load_key(keyfile, keyformat, 0, NULL, NULL, "CRL signing key");
    231      1.1  christos         if (!pkey) {
    232      1.1  christos             X509_CRL_free(newcrl);
    233      1.1  christos             goto end;
    234      1.1  christos         }
    235      1.1  christos         delta = X509_CRL_diff(x, newcrl, pkey, digest, 0);
    236      1.1  christos         X509_CRL_free(newcrl);
    237      1.1  christos         EVP_PKEY_free(pkey);
    238      1.1  christos         if (delta) {
    239      1.1  christos             X509_CRL_free(x);
    240      1.1  christos             x = delta;
    241      1.1  christos         } else {
    242      1.1  christos             BIO_puts(bio_err, "Error creating delta CRL\n");
    243      1.1  christos             goto end;
    244      1.1  christos         }
    245      1.1  christos     }
    246      1.1  christos 
    247  1.1.1.2  christos     if (badsig) {
    248  1.1.1.2  christos         const ASN1_BIT_STRING *sig;
    249  1.1.1.2  christos 
    250  1.1.1.2  christos         X509_CRL_get0_signature(x, &sig, NULL);
    251  1.1.1.2  christos         corrupt_signature(sig);
    252  1.1.1.2  christos     }
    253  1.1.1.2  christos 
    254      1.1  christos     if (num) {
    255      1.1  christos         for (i = 1; i <= num; i++) {
    256      1.1  christos             if (issuer == i) {
    257      1.1  christos                 print_name(bio_out, "issuer=", X509_CRL_get_issuer(x),
    258  1.1.1.2  christos                            get_nameopt());
    259      1.1  christos             }
    260      1.1  christos             if (crlnumber == i) {
    261      1.1  christos                 ASN1_INTEGER *crlnum;
    262      1.1  christos                 crlnum = X509_CRL_get_ext_d2i(x, NID_crl_number, NULL, NULL);
    263      1.1  christos                 BIO_printf(bio_out, "crlNumber=");
    264      1.1  christos                 if (crlnum) {
    265      1.1  christos                     i2a_ASN1_INTEGER(bio_out, crlnum);
    266      1.1  christos                     ASN1_INTEGER_free(crlnum);
    267      1.1  christos                 } else
    268      1.1  christos                     BIO_puts(bio_out, "<NONE>");
    269      1.1  christos                 BIO_printf(bio_out, "\n");
    270      1.1  christos             }
    271      1.1  christos             if (hash == i) {
    272      1.1  christos                 BIO_printf(bio_out, "%08lx\n",
    273      1.1  christos                            X509_NAME_hash(X509_CRL_get_issuer(x)));
    274      1.1  christos             }
    275      1.1  christos #ifndef OPENSSL_NO_MD5
    276      1.1  christos             if (hash_old == i) {
    277      1.1  christos                 BIO_printf(bio_out, "%08lx\n",
    278      1.1  christos                            X509_NAME_hash_old(X509_CRL_get_issuer(x)));
    279      1.1  christos             }
    280      1.1  christos #endif
    281      1.1  christos             if (lastupdate == i) {
    282      1.1  christos                 BIO_printf(bio_out, "lastUpdate=");
    283  1.1.1.2  christos                 ASN1_TIME_print(bio_out, X509_CRL_get0_lastUpdate(x));
    284      1.1  christos                 BIO_printf(bio_out, "\n");
    285      1.1  christos             }
    286      1.1  christos             if (nextupdate == i) {
    287      1.1  christos                 BIO_printf(bio_out, "nextUpdate=");
    288  1.1.1.2  christos                 if (X509_CRL_get0_nextUpdate(x))
    289  1.1.1.2  christos                     ASN1_TIME_print(bio_out, X509_CRL_get0_nextUpdate(x));
    290      1.1  christos                 else
    291      1.1  christos                     BIO_printf(bio_out, "NONE");
    292      1.1  christos                 BIO_printf(bio_out, "\n");
    293      1.1  christos             }
    294      1.1  christos             if (fingerprint == i) {
    295      1.1  christos                 int j;
    296      1.1  christos                 unsigned int n;
    297      1.1  christos                 unsigned char md[EVP_MAX_MD_SIZE];
    298      1.1  christos 
    299      1.1  christos                 if (!X509_CRL_digest(x, digest, md, &n)) {
    300      1.1  christos                     BIO_printf(bio_err, "out of memory\n");
    301      1.1  christos                     goto end;
    302      1.1  christos                 }
    303      1.1  christos                 BIO_printf(bio_out, "%s Fingerprint=",
    304      1.1  christos                            OBJ_nid2sn(EVP_MD_type(digest)));
    305      1.1  christos                 for (j = 0; j < (int)n; j++) {
    306      1.1  christos                     BIO_printf(bio_out, "%02X%c", md[j], (j + 1 == (int)n)
    307      1.1  christos                                ? '\n' : ':');
    308      1.1  christos                 }
    309      1.1  christos             }
    310      1.1  christos         }
    311      1.1  christos     }
    312  1.1.1.2  christos     out = bio_open_default(outfile, 'w', outformat);
    313  1.1.1.2  christos     if (out == NULL)
    314      1.1  christos         goto end;
    315      1.1  christos 
    316      1.1  christos     if (text)
    317  1.1.1.2  christos         X509_CRL_print_ex(out, x, get_nameopt());
    318      1.1  christos 
    319      1.1  christos     if (noout) {
    320      1.1  christos         ret = 0;
    321      1.1  christos         goto end;
    322      1.1  christos     }
    323      1.1  christos 
    324      1.1  christos     if (outformat == FORMAT_ASN1)
    325      1.1  christos         i = (int)i2d_X509_CRL_bio(out, x);
    326  1.1.1.2  christos     else
    327      1.1  christos         i = PEM_write_bio_X509_CRL(out, x);
    328      1.1  christos     if (!i) {
    329      1.1  christos         BIO_printf(bio_err, "unable to write CRL\n");
    330      1.1  christos         goto end;
    331      1.1  christos     }
    332      1.1  christos     ret = 0;
    333  1.1.1.2  christos 
    334      1.1  christos  end:
    335      1.1  christos     if (ret != 0)
    336      1.1  christos         ERR_print_errors(bio_err);
    337      1.1  christos     BIO_free_all(out);
    338      1.1  christos     X509_CRL_free(x);
    339  1.1.1.2  christos     X509_STORE_CTX_free(ctx);
    340  1.1.1.2  christos     X509_STORE_free(store);
    341  1.1.1.2  christos     return ret;
    342      1.1  christos }
    343