Commit c67cdb50 authored by Bodo Möller's avatar Bodo Möller
Browse files

New 'openssl ca -status <serial>' and 'openssl ca -updatedb'

commands.

Submitted by: Massimiliano Pala <madwolf@comune.modena.it>
parent af5473c4
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -3,6 +3,13 @@

 Changes between 0.9.6 and 0.9.7  [xx XXX 2000]

  *) New subcommands for 'openssl ca':
     'openssl ca -status <serial>' prints the status of the cert with
     the given serial number (according to the index file).
     'openssl ca -updatedb' updates the expiry status of certificates
     in the index file.
     [Massimiliano Pala <madwolf@comune.modena.it>]

  *) New '-newreq-nodes' command option to CA.pl.  This is like
     '-newreq', but calls 'openssl req' with the '-nodes' option
     so that the resulting key is not encrypted.
+320 −34
Original line number Diff line number Diff line
@@ -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"
@@ -170,6 +171,8 @@ static char *ca_usage[]={
" -extensions ..  - Extension section (override value in config file)\n",
" -crlexts ..     - CRL extension section (override value in config file)\n",
" -engine e       - use engine e, possibly a hardware device.\n",
" -status serial  - Shows certificate status given the serial number\n",
" -updatedb       - Updates db for expired certificates\n",
NULL
};

@@ -208,6 +211,8 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
	char *startdate, char *enddate, 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(const char *ser_status, TXT_DB *db);
static int do_updatedb(TXT_DB *db);
static int check_time_format(char *str);
static LHASH *conf=NULL;
static char *section=NULL;
@@ -235,6 +240,7 @@ int MAIN(int argc, char **argv)
	int verbose=0;
	int gencrl=0;
	int dorevoke=0;
	int doupdatedb=0;
	long crldays=0;
	long crlhours=0;
	long errorline= -1;
@@ -247,6 +253,7 @@ int MAIN(int argc, char **argv)
	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;
@@ -431,6 +438,15 @@ EF_ALIGNMENT=0;
			if (--argc < 1) goto bad;
			extensions= *(++argv);
			}
		else if (strcmp(*argv,"-status") == 0)
			{
			if (--argc < 1) goto bad;
			ser_status= *(++argv);
			}
		else if (strcmp(*argv,"-updatedb") == 0)
			{
			doupdatedb=1;
			}
		else if (strcmp(*argv,"-crlexts") == 0)
			{
			if (--argc < 1) goto bad;
@@ -567,7 +583,41 @@ bad:
		}

	/*****************************************************************/
	/* we definitely need an public key, so lets get it */
	/* report status of cert with serial number given on command line */
	if (ser_status)
	{
		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;

		if (!TXT_DB_create_index(db, DB_serial, NULL,
					LHASH_HASH_FN(index_serial_hash),
					LHASH_COMP_FN(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 (get_certificate_status(ser_status,db) != 1)
			BIO_printf(bio_err,"Error verifying serial %s!\n",
				 ser_status);
		goto err;
	}

	/*****************************************************************/
	/* we definitely need a public key, so let's get it */

	if ((keyfile == NULL) && ((keyfile=CONF_get_string(conf,
		section,ENV_PRIVATE_KEY)) == NULL))
@@ -784,6 +834,82 @@ bad:
		goto err;
		}

	/*****************************************************************/
	/* Update the db file for expired certificates */
	if (doupdatedb)
		{
		if (verbose)
			BIO_printf(bio_err, "Updating %s ...\n",
							dbfile);

		i = do_updatedb(db);
		if (i == -1)
			{
			BIO_printf(bio_err,"Malloc failure\n");
			goto err;
	        	}
		else if (i == 0)
	        	{
			if (verbose) BIO_printf(bio_err,
					"No entries found to mark expired\n"); 
			}
	    	else
			{
			out = BIO_new(BIO_s_file());
			if (out == NULL)
				{
				ERR_print_errors(bio_err);
				goto err;
				}

			j = BIO_snprintf(buf[0], sizeof buf[0], "%s.new", dbfile);
			if (j < 0 || j >= sizeof buf[0])
				{
				BIO_printf(bio_err, "file name too long\n");
				goto err;
				}
			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;
			j = BIO_snprintf(buf[1], sizeof buf[1], "%s.old", dbfile);
			if (j < 0 || j >= sizeof buf[1])
				{
				BIO_printf(bio_err, "file name too long\n");
				goto err;
				}
			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;
		  		}
				
			if (verbose) BIO_printf(bio_err,
				"Done. %d entries marked as expired\n",i); 
	      		}
			goto err;
	  	}

	/*****************************************************************/
	if (req || gencrl)
		{
@@ -1260,7 +1386,8 @@ bad:

		/* Add any extensions asked for */

		if(crl_ext) {
		if (crl_ext)
			{
			X509V3_CTX crlctx;
			if (ci->version == NULL)
				if ((ci->version=ASN1_INTEGER_new()) == NULL) goto err;
@@ -2105,7 +2232,8 @@ static int certify_spkac(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
		 * multiple instances
		 */
		for (buf = cv->name; *buf ; buf++)
			if ((*buf == ':') || (*buf == ',') || (*buf == '.')) {
			if ((*buf == ':') || (*buf == ',') || (*buf == '.'))
				{
				buf++;
				if (*buf) type = buf;
				break;
@@ -2318,3 +2446,161 @@ err:
	return(ok);
	}

static int get_certificate_status(const char *serial, TXT_DB *db)
	{
	unsigned 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] = OPENSSL_malloc(strlen(serial) + 2);
	if (row[DB_serial] == NULL)
		{
		BIO_printf(bio_err,"Malloc failure\n");
		goto err;
		}

	if (strlen(serial) % 2)
		{
		/* Set the first char to 0 */;
		row[DB_serial][0]='0';

		/* Copy String from serial to row[DB_serial] */
		memcpy(row[DB_serial]+1, serial, strlen(serial));
		row[DB_serial][strlen(serial)+1]='\0';
		}
	else
		{
		/* 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] = 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,"%s=Valid (%c)\n",
			row[DB_serial], rrow[DB_type][0]);
		goto err;
		}
	else if (rrow[DB_type][0]=='R')
		{
		BIO_printf(bio_err,"%s=Revoked (%c)\n",
			row[DB_serial], rrow[DB_type][0]);
		goto err;
		}
	else if (rrow[DB_type][0]=='E')
		{
		BIO_printf(bio_err,"%s=Expired (%c)\n",
			row[DB_serial], rrow[DB_type][0]);
		goto err;
		}
	else if (rrow[DB_type][0]=='S')
		{
		BIO_printf(bio_err,"%s=Suspended (%c)\n",
			row[DB_serial], rrow[DB_type][0]);
		goto err;
		}
	else
		{
		BIO_printf(bio_err,"%s=Unknown (%c).\n",
			row[DB_serial], rrow[DB_type][0]);
		ok=-1;
		}
err:
	for (i=0; i<DB_NUMBER; i++)
		{
		if (row[i] != NULL)
			OPENSSL_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;

	a_tm = ASN1_UTCTIME_new();

	/* get actual time and make a string */
	a_tm = X509_gmtime_adj(a_tm, 0);
	a_tm_s = (char *) OPENSSL_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 entries 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)
				{
				/* all on the same y2k side */
				if (strcmp(rrow[DB_exp_date], a_tm_s) <= 0)
				       	{
				       	rrow[DB_type][0]  = 'E';
				       	rrow[DB_type][1]  = '\0';
	  				cnt++;

					BIO_printf(bio_err, "%s=Expired\n",
							rrow[DB_serial]);
					}
				}
			else if (db_y2k < a_y2k)
				{
		  		rrow[DB_type][0]  = 'E';
		  		rrow[DB_type][1]  = '\0';
	  			cnt++;

				BIO_printf(bio_err, "%s=Expired\n",
							rrow[DB_serial]);
				}

			}
    		}

err:

	ASN1_UTCTIME_free(a_tm);
	OPENSSL_free(a_tm_s);

	return (cnt);
	}