Lars Weber wrote:
>
> Dear OpenSSL-Devlopers !
>
> As I have wrote in a mail to openssl-users I would like to add a new
> functionality in openssl. As Massimiliano Pala has suggested I send my patch
> to this list.
>
> I have attached a patch to enhance the "ca"-application to check "index.txt"
> for expired certs and (if found) mark them. The idea is to run
> "openssl ca -updatedb" (new switch) periodically by a cron-job to keep
> index.txt up-to-date.
>
> The patch is a diff -cb against openssl-SNAP-19990505/apps/ca.c.
>
> Some annotations:
>
> I have basically adapted the revoke-parts in ca.c for my needs. I have added a
> new subroutine called "do_updatedb" which does the checking of index.txt. The
> routine returns the number of new marked entry�s or -1 for an Malloc-error.
>
> To avoid asking for the pass-phrase for the ca-cert I had to wrap this part
> with an if-clause.
>
> The basic problem in checking index.txt was to avoid year 2000 problems:
>
> I use two flags "db_y2k" and "a_y2k". db_y2k is set to 1 if the year part
> of the date-entry in index.txt is less or equal 49, otherwise db_y2k is set to
> 0. Same for a_y2k and the actual date. This implies that 00,01,...,49 are
> 20xx-years. I hope I have got this right...
>
> Then db_y2k and a_y2k will be compared:
>
> db_y2k > a_y2k => cert is valid
> db_y2k < a_y2k => cert is not valid
> db_y2k = a_y2k => The dates lay in the same interval. Now it is save to
> use the standard "strcmp()"-function to compare the
> the date-entry in index.txt and the actual date.
>
> That�s all.
>
> I am not an advanced C-programmer so feel free to change everything
> or reject it completely ;-)
>
Hi!
I am trying and actually succeded to patch the ca.c program (last snapshot) to
work with your -updatedb and my -status serialnume switches to the ca-app.
I had to move the whole if(updatedb) ... to upper level actually avoiding the
password request ( thus removing your if(updatedb = 0 ) on the certificate
loading stage). I actually get errors when lounching the -updatedb because a
newly issued certificate with the following entry in db gets the 'Expired'
flag set (while it shouldn't). Here it is:
V 000509111506Z 01 unknown
/C=IT/O=OpenCA/OU=Developer/CN=Massimiliano
[EMAIL PROTECTED]
Do you have some ideas ? Anyway I post the ca.diff patch (use patch -p1 ca.c ca.diff)
so we ca work toghether to the problem.
I start reviewing your code, if you find out what the problem is, please tell me!
Thanks,
See you on the bit Stream,
Massimiliano Pala ([EMAIL PROTECTED])
--- ca.c Mon May 10 13:27:34 1999
+++ ca-patched.c Mon May 10 13:27:26 1999
@@ -1,4 +1,4 @@
-/* apps/ca.c */
+#/* apps/ca.c */
/* Copyright (C) 1995-1998 Eric Young ([EMAIL PROTECTED])
* All rights reserved.
*
@@ -61,6 +61,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "apps.h"
@@ -147,6 +148,8 @@
" -batch - Don't ask questions\n",
" -msie_hack - msie modifications to handle all those universal strings\n",
" -revoke file - Revoke a certificate (given in file)\n",
+" -status serial - Shows certificate' status given the serial number\n",
+" -updatedb - Checks index.txt for expired certificates and mark them\n",
NULL
};
@@ -185,6 +188,8 @@
int days, int batch, int verbose, X509_REQ *req, char *ext_sect,
LHASH *conf);
static int do_revoke(X509 *x509, TXT_DB *db);
+static int get_certificate_status(char *ser_status, TXT_DB *db);
+static int do_updatedb(TXT_DB *db);
static int check_time_format(char *str);
static LHASH *conf;
static char *key=NULL;
@@ -203,6 +208,7 @@
int verbose=0;
int gencrl=0;
int dorevoke=0;
+ int doupdatedb=0;
long crldays=0;
long crlhours=0;
long errorline= -1;
@@ -214,6 +220,7 @@
char *infile=NULL;
char *spkac_file=NULL;
char *ss_cert_file=NULL;
+ char *ser_status=NULL;
EVP_PKEY *pkey=NULL;
int output_der = 0;
char *outfile=NULL;
@@ -369,6 +376,15 @@
infile= *(++argv);
dorevoke=1;
}
+ else if (strcmp(*argv,"-status") == 0)
+ {
+ if (--argc < 1) goto bad;
+ ser_status= *(++argv);
+ }
+ else if (strcmp(*argv,"-updatedb") == 0)
+ {
+ doupdatedb=1;
+ }
else
{
bad:
@@ -464,6 +480,150 @@
}
/*****************************************************************/
+ /* we need to load the database file */
+ 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;
+
+ /* Lets check some fields */
+ 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, but has a
+revocation 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 revocation 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 (verbose)
+ {
+ BIO_set_fp(out,stdout,BIO_NOCLOSE|BIO_FP_TEXT); /* cannot fail */
+ TXT_DB_write(out,db);
+ BIO_printf(bio_err,"%d entries loaded from the database\n",
+ db->data->num);
+ BIO_printf(bio_err,"generating indexs\n");
+ }
+
+ 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 the certificate status is required we give it */
+ if (ser_status)
+ {
+ if( get_certificate_status(ser_status,db) != 1)
+ BIO_printf(bio_err,"Error verifying serial %s!\n",
+ ser_status);
+ goto err;
+ }
+
+ /*****************************************************************/
+ /* Update the db file for expired certificates */
+ if (doupdatedb)
+ {
+ i = do_updatedb (db);
+ if ( i == -1)
+ {
+ BIO_printf(bio_err,"Malloc failure\n");
+ goto err;
+ }
+ else if ( i == 0 )
+ BIO_printf(bio_err,"No entry's found to mark expired - will not touch
+index.txt\n");
+ else
+ {
+ out = BIO_new (BIO_s_file());
+ if (out == NULL)
+ {
+ ERR_print_errors (bio_err);
+ goto err;
+ }
+
+ 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(out);
+ out = NULL;
+ strncpy (buf[1],dbfile,BSIZE-4);
+ strcat (buf[1],".old");
+ if (rename(dbfile,buf[1]) < 0)
+ {
+ BIO_printf(bio_err,"unable to rename %s to %s\n", dbfile, buf[1]);
+ perror("reason");
+ goto err;
+ }
+ if (rename(buf[0],dbfile) < 0)
+ {
+ BIO_printf(bio_err,"unable to rename %s to %s\n", buf[0],dbfile);
+ perror("reason");
+ rename(buf[1],dbfile);
+ goto err;
+ }
+ BIO_printf(bio_err,"%d entry's marked as expired\n", i);
+ }
+ goto err;
+ }
+
+ /*****************************************************************/
/* we definitly need an public key, so lets get it */
if ((keyfile == NULL) && ((keyfile=CONF_get_string(conf,
@@ -558,86 +718,6 @@
}
}
- /*****************************************************************/
- /* we need to load the database file */
- 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;
-
- /* Lets check some fields */
- 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, but has a
revocation 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 revocation 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 (verbose)
- {
- BIO_set_fp(out,stdout,BIO_NOCLOSE|BIO_FP_TEXT); /* cannot fail */
- TXT_DB_write(out,db);
- BIO_printf(bio_err,"%d entries loaded from the database\n",
- db->data->num);
- BIO_printf(bio_err,"generating indexs\n");
- }
-
- 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 (req || gencrl)
@@ -1134,6 +1214,7 @@
BIO_printf(bio_err,"Data Base Updated\n");
}
}
+
/*****************************************************************/
ret=0;
err:
@@ -2161,3 +2242,126 @@
return(ok);
}
+static int get_certificate_status ( char *serial, TXT_DB *db )
+{
+ char *row[DB_NUMBER],**rrow;
+ int ok=-1,i;
+
+ /* Free Resources */
+ for (i=0; i<DB_NUMBER; i++)
+ row[i]=NULL;
+ /* Malloc needed char spaces */
+ row[DB_serial]=( char * ) Malloc ( strlen(serial) +1);
+ if (row[DB_serial] == NULL)
+ {
+ BIO_printf(bio_err,"Malloc failure\n");
+ goto err;
+ }
+
+ /* Copy String from serial to row[DB_serial] */
+ memcpy( row[DB_serial], serial, strlen(serial));
+ row[DB_serial][strlen(serial)]='\0';
+
+ /* Make it Upper Case */
+ for( i=0; row[DB_serial][i] != '\0'; i++ )
+ row[DB_serial][i] = (char) toupper( row[DB_serial][i] );
+
+ ok=1;
+
+ /* Search for the certificate */
+ rrow=TXT_DB_get_by_index(db,DB_serial,row);
+ if (rrow == NULL)
+ {
+ BIO_printf(bio_err,"Serial %s not present in db.\n",
+ row[DB_serial]);
+ ok=-1;
+ goto err;
+ }
+ else if (rrow[DB_type][0]=='V')
+ {
+ BIO_printf(bio_err,"STATUS: Valid (%c)\n",
+ rrow[DB_type][0]);
+ goto err;
+ }
+ else if (rrow[DB_type][0]=='R')
+ {
+ BIO_printf(bio_err,"STATUS: Revoked (%c)\n",
+ rrow[DB_type][0]);
+ goto err;
+ }
+ else if (rrow[DB_type][0]=='E')
+ {
+ BIO_printf(bio_err,"STATUS: Expired (%c)\n",
+ rrow[DB_type][0]);
+ goto err;
+ }
+ else
+ {
+ BIO_printf(bio_err,"ERROR: Unknown status (%c).\n",
+ rrow[DB_type][0]);
+ ok=-1;
+ }
+err:
+ for (i=0; i<DB_NUMBER; i++)
+ {
+ if ((row[i] != NULL) && (row[i] != serial) )
+ Free(row[i]);
+ }
+ return(ok);
+}
+
+static int do_updatedb (TXT_DB *db)
+{
+ ASN1_UTCTIME *a_tm = NULL;
+ int i, cnt = 0;
+ int db_y2k, a_y2k; /* flags = 1 if y >= 2000 */
+ char **rrow, *a_tm_s;
+
+
+ /* get actual time and make a string */
+ a_tm = X509_gmtime_adj( a_tm, 0 );
+ a_tm_s = (char *) Malloc( a_tm->length+1 );
+ if ( a_tm_s == NULL )
+ {
+ cnt = -1;
+ goto err;
+ }
+ memcpy( a_tm_s, a_tm->data, a_tm->length );
+ a_tm_s[a_tm->length] = '\0';
+
+ if ( strncmp( a_tm_s, "49", 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' ) /* ignore entry's that are not valid */
+ {
+ if ( strncmp( rrow[DB_exp_date], "49", 2 ) <= 0 )
+ db_y2k = 1;
+ else
+ db_y2k = 0;
+ if ( db_y2k > a_y2k ) /* db > a => cert is valid */
+ {
+ if ( db_y2k < a_y2k ) /* db < a => cert is expired */
+ {
+ rrow[DB_type][0] = 'E';
+ rrow[DB_type][1] = '\0';
+ cnt++;
+ }
+ else if ( strcmp( rrow[DB_exp_date], a_tm_s ) <= 0 ) /* db = a */
+ {
+ rrow[DB_type][0] = 'E';
+ rrow[DB_type][1] = '\0';
+ cnt++;
+ }
+ }
+ }
+ }
+ err:
+ ASN1_UTCTIME_free( a_tm );
+ Free( a_tm_s );
+ return (cnt);
+}