On Fri, Mar 26, 1999 at 08:59:48PM +0100, [EMAIL PROTECTED] wrote: > I have the need to revoke a certificate, anyway I cannot find the revoke > facility to manage the job ( including altering the index.txt that I think > is used to manage the CRL (??)). > > Where do I find it?? ( command line tool... ). Hi, i have attached an earlier posting to ssl-users. This program works fine with SSLeay-0.8.1, maybe you have to make some modifications to compile it with OpnSSL. Ciao, Lars <[EMAIL PROTECTED]>
/* >From [EMAIL PROTECTED] Wed Dec 17 15:22:56 1997 this code is a simple/sample utility written by me and Sergio Tabanelli that put the revocation date on the "index.txt" ... after the execution of this utility you must run the ca utility (as in the standard sslEAY distribution) to obtain the crl. We have done this work using an approach "a la Tim Hudson" so it can be used and linked as a standard sslEAY "app" if placed in the "apps" directory. Remo. code follow: * Copyright (C) 1995-1997 Eric Young ([EMAIL PROTECTED]) * All rights reserved. * * This package is an SSL implementation written * by Eric Young ([EMAIL PROTECTED]). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson ([EMAIL PROTECTED]). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young ([EMAIL PROTECTED])" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson ([EMAIL PROTECTED])" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include "apps.h" #include "bio.h" #include "err.h" #include "txt_db.h" #include "evp.h" #include "x509.h" #include "objects.h" #include "pem.h" #include "conf.h" #ifndef W_OK #include <sys/file.h> #endif #undef PROG #define PROG revoke_main #define BASE_SECTION "ca" #define CONFIG_FILE "lib/ssleay.cnf" #define ENV_DEFAULT_CA "default_ca" #define ENV_DIR "dir" #define ENV_CERTS "certs" #define ENV_CRL_DIR "crl_dir" #define ENV_CA_DB "CA_DB" #define ENV_NEW_CERTS_DIR "new_certs_dir" #define ENV_CERTIFICATE "certificate" #define ENV_SERIAL "serial" #define ENV_CRL "crl" #define ENV_PRIVATE_KEY "private_key" #define ENV_RANDFILE "RANDFILE" #define ENV_DEFAULT_DAYS "default_days" #define ENV_DEFAULT_CRL_DAYS "default_crl_days" #define ENV_DEFAULT_CRL_HOURS "default_crl_hours" #define ENV_DEFAULT_MD "default_md" #define ENV_PRESERVE "preserve" #define ENV_POLICY "policy" #define ENV_EXTENSIONS "x509_extensions" #define ENV_MSIE_HACK "msie_hack" #define ENV_DATABASE "database" #define DB_type 0 #define DB_exp_date 1 #define DB_rev_date 2 #define DB_serial 3 /* index - unique */ #define DB_file 4 #define DB_name 5 /* index - unique for active */ #define DB_NUMBER 6 #define DB_TYPE_REV 'R' #define DB_TYPE_EXP 'E' #define DB_TYPE_VAL 'V' #define DB_TYPE_HID 'H' static char *revoke_usage[]={ "usage: revoke args\n", "\n", " -config file - A config file\n", " -name arg - The particular CA definition to use\n", " -chkdb - Check index.txt for expired certs and mark them\n", " -in file - The input certificate \n", " -infiles .... - The last argument, requests to process\n", NULL }; #ifndef NOPROTO static void lookup_fail(char *name,char *tag); static unsigned long index_serial_hash(char **a); static int index_serial_cmp(char **a, char **b); static unsigned long index_name_hash(char **a); static int index_name_qual(char **a); static int index_name_cmp(char **a,char **b); static int do_revoke(X509 *x509,TXT_DB *db); static void do_chkdb(TXT_DB *db); static int check_time_format(char *str); #else static void lookup_fail(); static unsigned long index_serial_hash(); static int index_serial_cmp(); static unsigned long index_name_hash(); static int index_name_qual(); static int index_name_cmp(); static int do_revoke(); static void do_chkdb(); static int check_time_format(); #endif int MAIN(argc, argv) int argc; char **argv; { int ret = 1; char *configfile = NULL; char *infile = NULL; char *dbfile = NULL; int badops = 0; LHASH *conf = (LHASH *) NULL; char *section = NULL; int files = 0; /* flag for mult. revoke */ int chk = 0; /* flag for expire check */ int i, j; char **pp, *p; BIO *in = NULL, *out = NULL; TXT_DB *db = NULL; X509 *x509 = NULL; #undef BSIZE #define BSIZE 256 MS_STATIC char buf[3][BSIZE]; long errorline = -1; apps_startup (); X509v3_add_netscape_extensions (); if ( bio_err == NULL ) if ( ( bio_err = BIO_new (BIO_s_file()) ) != NULL ) BIO_set_fp (bio_err, stderr, BIO_NOCLOSE); argc--; argv++; while ( argc >= 1 ) { if ( strcmp (*argv,"-config") == 0 ) { if ( --argc < 1 ) goto bad; configfile = *(++argv); } else if ( strcmp (*argv,"-name") == 0 ) { if ( --argc < 1 ) goto bad; section = *(++argv); } else if (strcmp(*argv,"-in") == 0) { if (--argc < 1) goto bad; infile= *(++argv); } else if ( strcmp (*argv,"-chkdb") == 0 ) { chk = 1; break; } else if (strcmp(*argv,"-infiles") == 0) { argc--; argv++; files = 1; break; } else { bad: BIO_printf (bio_err, "unknown option %s\n", *argv); badops = 1; break; } argc--; argv++; } if ( badops ) { for (pp=revoke_usage; (*pp != NULL); pp++) BIO_printf (bio_err,*pp); goto err; } ERR_load_crypto_strings (); if ( configfile == NULL ) { configfile = getenv ("SSLEAY_CONF"); if ( configfile == NULL ) { /* We will just use 'buf[0]' as a temporary buffer. */ strncpy (buf[0], X509_get_default_cert_area (), sizeof (buf[0]) - 2 - sizeof (CONFIG_FILE)); strcat (buf[0], "/"); strcat (buf[0], CONFIG_FILE); configfile = buf[0]; } } BIO_printf (bio_err, "Using configuration from %s\n", configfile); if ( ( conf = CONF_load (NULL,configfile,&errorline) ) == NULL ) { if ( errorline <= 0 ) BIO_printf (bio_err, "error loading the config file '%s'\n", configfile); else BIO_printf (bio_err, "error on line %ld of config file '%s'\n" ,errorline,configfile); goto err; } /* Lets get the config section we are using */ if ( section == NULL ) { section = CONF_get_string (conf, BASE_SECTION, ENV_DEFAULT_CA); if ( section == NULL ) { lookup_fail (BASE_SECTION,ENV_DEFAULT_CA); goto err; } } in = BIO_new (BIO_s_file()); out = BIO_new (BIO_s_file()); if ( ( in == NULL ) || ( out == NULL ) ) { ERR_print_errors (bio_err); goto err; } if ( ( dbfile = CONF_get_string (conf, section, ENV_DATABASE) ) == NULL ) { lookup_fail (section, ENV_DATABASE); goto err; } if ( BIO_read_filename (in,dbfile) <= 0 ) { perror (dbfile); BIO_printf (bio_err, "unable to open '%s'\n", dbfile); goto err; } db = TXT_DB_read (in, DB_NUMBER); if ( db == NULL ) goto err; for (i=0; i<sk_num(db->data); i++) { pp = (char **) sk_value (db->data, i); if ( ( pp[DB_type][0] != DB_TYPE_REV ) && ( pp[DB_rev_date][0] != '\0' ) ) { BIO_printf (bio_err, "entry %d: not, revoked yet has a revokation date\n", i+1); goto err; } if ( ( pp[DB_type][0] == DB_TYPE_REV ) && !check_time_format (pp[DB_rev_date]) ) { BIO_printf (bio_err, "entry %d: invalid revokation date\n", i+1 ); goto err; } if ( !check_time_format (pp[DB_exp_date]) ) { BIO_printf (bio_err, "entry %d: invalid expiry date\n", i+1); goto err; } p = pp[DB_serial]; j = strlen (p); if ( (j&1) || (j < 2) ) { BIO_printf (bio_err, "entry %d: bad serial number length (%d)\n", i+1, j); goto err; } while ( *p ) { if ( ! ( ((*p >= '0') && (*p <= '9')) || ((*p >= 'A') && (*p <= 'F')) || ((*p >= 'a') && (*p <= 'f'))) ) { BIO_printf (bio_err, "entry %d: bad serial number characters, char pos %ld, char is '%c'\n", i+1, (long) (p-pp[DB_serial]), *p); goto err; } p++; } } if ( !TXT_DB_create_index(db,DB_serial,NULL,index_serial_hash, index_serial_cmp)) { BIO_printf(bio_err,"error creating serial number index:(%ld,%ld,%ld)\n",db->error,db->arg1,db->arg2); goto err; } if ( !TXT_DB_create_index(db,DB_name,index_name_qual,index_name_hash, index_name_cmp)) { BIO_printf(bio_err,"error creating name index:(%ld,%ld,%ld)\n", db->error,db->arg1,db->arg2); goto err; } if ( chk == 1 ) { do_chkdb (db); } else { if ( (infile == NULL) && (!files)) { BIO_printf(bio_err,"no input files\n"); goto err; } if ( infile != NULL) { if ( BIO_read_filename(in,infile) <= 0) { perror(infile); BIO_printf(bio_err,"error trying to load '%s' certificate\n",infile); goto err; } x509 = PEM_read_bio_X509 (in,NULL,NULL); if ( x509 == NULL ) { BIO_printf (bio_err,"unable to load '%s' certificate\n",infile); goto err; } j = do_revoke(x509,db); } for (i=0; i<argc; i++) { if ( x509 != NULL ) X509_free (x509); if ( BIO_read_filename (in,argv[i]) <= 0 ) { perror (infile); BIO_printf (bio_err,"error trying to load '%s' certificate\n",argv[i]); goto err; } j = do_revoke (x509,db); } } strncpy (buf[0],dbfile,BSIZE-4); strcat (buf[0],".new"); if ( BIO_write_filename (out,buf[0]) <= 0) { perror (dbfile); BIO_printf (bio_err, "unable to open '%s'\n", dbfile); goto err; } j = TXT_DB_write (out,db); if ( j <= 0 ) goto err; BIO_free (in); BIO_free (out); in = NULL; out = NULL; strncpy (buf[1], dbfile, BSIZE-4); strcat (buf[1], ".old"); if ( rename (dbfile,buf[1]) < 0) { BIO_printf (bio_err, "unabel to rename %s to %s\n", dbfile,buf[1]); perror ("reason"); goto err; } if ( rename (buf[0],dbfile) < 0) { BIO_printf (bio_err, "unabel to rename %s to %s\n", buf[0], dbfile); perror ("reason"); rename (buf[1], dbfile); goto err; } BIO_printf (bio_err, "Data Base Updated\n"); ret=0; err: if ( out != NULL) BIO_free(out); if ( in != NULL) BIO_free(in); if ( db != NULL) TXT_DB_free(db); if ( x509 != NULL) X509_free(x509); if ( conf != NULL) CONF_free(conf); X509v3_cleanup_extensions (); EXIT (ret); } static void do_chkdb (db) TXT_DB *db; { ASN1_UTCTIME *a_tm = NULL; int i, c_y2k, a_y2k; /* flags = 1 if y >= 2000 */ char **rrow, *a_tm_s; /* get time and make string */ a_tm = X509_gmtime_adj (a_tm, 0); a_tm_s = (char *) Malloc (a_tm->length+1); memcpy (a_tm_s, a_tm->data, a_tm->length); a_tm_s[a_tm->length] = '\0'; printf ("\nAktuelle Zeit: %s\n", a_tm_s); /* strncmp (00time, 64time) = -1, so the flags have to be used * to check if the Years lay in the same interval * Anmerkung: 19yy | yy <- [65,99] * 20yy | yy <- [0,64] */ if ( ( strncmp (a_tm_s, "64", 2) <= 0 ) && ( strncmp (a_tm_s, "00", 2) >= 0 ) ) a_y2k = 1; else a_y2k = 0; for (i = 0; i < sk_num (db->data); i++) { rrow = (char **) sk_value (db->data, i); if ( ( rrow[DB_type][0] == 'V' ) || ( rrow[DB_type][0] == 'H' ) ) { if ( ( strncmp (rrow[DB_exp_date], "64", 2) <= 0 ) && ( strncmp (rrow[DB_exp_date], "00", 2) >= 0 ) ) c_y2k = 1; else c_y2k = 0; if ( ! (c_y2k > a_y2k) ) /* check y2k. If c>a then cert is valid */ { if ( c_y2k < a_y2k ) /* cert definitly not valid */ { rrow[DB_type][0] = 'E'; rrow[DB_type][1] = '\0'; } else if ( strcmp (rrow[DB_exp_date], a_tm_s) <= 0 ) /* now c_y2k = a_y2k, so no */ { /* problem w. strcmp */ rrow[DB_type][0] = 'E'; rrow[DB_type][1] = '\0'; } } } } ASN1_UTCTIME_free (a_tm); Free (a_tm_s); } static int do_revoke (x509,db) X509 *x509; TXT_DB *db; { ASN1_UTCTIME *tm = NULL; char *row[DB_NUMBER], **rrow; int ok = -1,i; for (i=0; i<DB_NUMBER; i++) row[i]=NULL; row[DB_name] = X509_NAME_oneline (x509->cert_info->subject, NULL, 0); row[DB_serial] = BN_bn2ascii (ASN1_INTEGER_to_BN (x509->cert_info->serialNumber, NULL)); if ( ( row[DB_name] == NULL ) || ( row[DB_serial] == NULL ) ) { BIO_printf (bio_err, "Malloc failure\n"); goto err; } rrow = TXT_DB_get_by_index (db, DB_name, row); if ( rrow == NULL ) { BIO_printf (bio_err, "ERROR:There is no certificate for %s\n", row[DB_name]); goto err; } else if ( index_serial_cmp (row, rrow) ) { BIO_printf (bio_err, "ERROR:no same serial number %s\n", row[DB_serial]); goto err; } else if (rrow[DB_type][0]=='R') { BIO_printf(bio_err, "ERROR:Already revoked, serial number %s\n", row[DB_serial]); goto err; } else { tm = X509_gmtime_adj (tm,0); rrow[DB_type][0] = 'R'; rrow[DB_type][1] = '\0'; rrow[DB_rev_date] = (char *) Malloc (tm->length+1); memcpy (rrow[DB_rev_date], tm->data, tm->length); rrow[DB_rev_date][tm->length] = '\0'; } ok = 1; err: for (i=0; i<DB_NUMBER; i++) { if ( row[i] != NULL ) Free (row[i]); } ASN1_UTCTIME_free (tm); return (ok); } static void lookup_fail (name,tag) char *name; char *tag; { BIO_printf (bio_err, "variable lookup failed for %s::%s\n", name, tag); } static unsigned long index_serial_hash (a) char **a; { char *n; n=a[DB_serial]; while (*n == '0') n++; return(lh_strhash(n)); } static int index_serial_cmp(a,b) char **a; char **b; { char *aa,*bb; for (aa=a[DB_serial]; *aa == '0'; aa++); for (bb=b[DB_serial]; *bb == '0'; bb++); return(strcmp(aa,bb)); } static unsigned long index_name_hash(a) char **a; { return(lh_strhash(a[DB_name])); } static int index_name_qual(a) char **a; { return(a[0][0] == 'V'); } static int index_name_cmp(a,b) char **a; char **b; { return(strcmp(a[DB_name],b[DB_name])); } static int check_time_format(str) char *str; { ASN1_UTCTIME tm; tm.data = (unsigned char *) str; tm.length = strlen(str); tm.type = V_ASN1_UTCTIME; return (ASN1_UTCTIME_check (&tm)); }