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);
+}

Reply via email to