Add 'align' option to nameopt.
[openssl.git] / apps / ca.c
index 69352654e2e1fd0bbd356f399c91399b8b0e3059..41850098b6755e88a9bbd65f42012d49839631dc 100644 (file)
--- a/apps/ca.c
+++ b/apps/ca.c
@@ -61,6 +61,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include "apps.h"
 #include <sys/types.h>
 #include <sys/stat.h>
 #include "apps.h"
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 #include <openssl/objects.h>
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 #include <openssl/objects.h>
+#include <openssl/ocsp.h>
 #include <openssl/pem.h>
 #include <openssl/pem.h>
+#include <openssl/engine.h>
+
+#ifdef OPENSSL_SYS_WINDOWS
+#define strcasecmp _stricmp
+#else
+#include <strings.h>
+#endif
 
 #ifndef W_OK
 
 #ifndef W_OK
-#  ifdef VMS
+#  ifdef OPENSSL_SYS_VMS
 #    if defined(__DECC)
 #      include <unistd.h>
 #    else
 #    if defined(__DECC)
 #      include <unistd.h>
 #    else
 #define ENV_EXTENSIONS         "x509_extensions"
 #define ENV_CRLEXT             "crl_extensions"
 #define ENV_MSIE_HACK          "msie_hack"
 #define ENV_EXTENSIONS         "x509_extensions"
 #define ENV_CRLEXT             "crl_extensions"
 #define ENV_MSIE_HACK          "msie_hack"
+#define ENV_NAMEOPT            "name_opt"
+#define ENV_CERTOPT            "cert_opt"
 
 #define ENV_DATABASE           "database"
 
 
 #define ENV_DATABASE           "database"
 
 #define DB_TYPE_EXP    'E'
 #define DB_TYPE_VAL    'V'
 
 #define DB_TYPE_EXP    'E'
 #define DB_TYPE_VAL    'V'
 
+/* Additional revocation information types */
+
+#define REV_NONE               0       /* No addditional information */
+#define REV_CRL_REASON         1       /* Value is CRL reason code */
+#define REV_HOLD               2       /* Value is hold instruction */
+#define REV_KEY_COMPROMISE     3       /* Value is cert key compromise time */
+#define REV_CA_COMPROMISE      4       /* Value is CA key compromise time */
+
 static char *ca_usage[]={
 "usage: ca args\n",
 "\n",
 static char *ca_usage[]={
 "usage: ca args\n",
 "\n",
@@ -152,7 +171,8 @@ static char *ca_usage[]={
 " -days arg       - number of days to certify the certificate for\n",
 " -md arg         - md to use, one of md2, md5, sha or sha1\n",
 " -policy arg     - The CA 'policy' to support\n",
 " -days arg       - number of days to certify the certificate for\n",
 " -md arg         - md to use, one of md2, md5, sha or sha1\n",
 " -policy arg     - The CA 'policy' to support\n",
-" -keyfile arg    - PEM private key file\n",
+" -keyfile arg    - private key file\n",
+" -keyform arg    - private key file format (PEM or ENGINE)\n",
 " -key arg        - key to decode the private key if it is encrypted\n",
 " -cert file      - The CA certificate\n",
 " -in file        - The input PEM encoded certificate request(s)\n",
 " -key arg        - key to decode the private key if it is encrypted\n",
 " -cert file      - The CA certificate\n",
 " -in file        - The input PEM encoded certificate request(s)\n",
@@ -165,8 +185,13 @@ static char *ca_usage[]={
 " -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",
 " -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",
+" -subj arg       - Use arg instead of request's subject\n",
 " -extensions ..  - Extension section (override value in config file)\n",
 " -extensions ..  - Extension section (override value in config file)\n",
+" -extfile file   - Configuration file with X509v3 extentions to add\n",
 " -crlexts ..     - CRL 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
 };
 
 NULL
 };
 
@@ -176,48 +201,67 @@ extern int EF_PROTECT_BELOW;
 extern int EF_ALIGNMENT;
 #endif
 
 extern int EF_ALIGNMENT;
 #endif
 
-static int add_oid_section(LHASH *conf);
 static void lookup_fail(char *name,char *tag);
 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 unsigned long index_serial_hash(const char **a);
+static int index_serial_cmp(const char **a, const char **b);
+static unsigned long index_name_hash(const char **a);
 static int index_name_qual(char **a);
 static int index_name_qual(char **a);
-static int index_name_cmp(char **a,char **b);
+static int index_name_cmp(const char **a,const char **b);
 static BIGNUM *load_serial(char *serialfile);
 static int save_serial(char *serialfile, BIGNUM *serial);
 static int certify(X509 **xret, char *infile,EVP_PKEY *pkey,X509 *x509,
                   const EVP_MD *dgst,STACK_OF(CONF_VALUE) *policy,TXT_DB *db,
 static BIGNUM *load_serial(char *serialfile);
 static int save_serial(char *serialfile, BIGNUM *serial);
 static int certify(X509 **xret, char *infile,EVP_PKEY *pkey,X509 *x509,
                   const EVP_MD *dgst,STACK_OF(CONF_VALUE) *policy,TXT_DB *db,
-                  BIGNUM *serial, char *startdate,char *enddate, int days,
-                  int batch, char *ext_sect, LHASH *conf,int verbose);
+                  BIGNUM *serial, char *subj, char *startdate,char *enddate,
+                  int days, int batch, char *ext_sect, LHASH *conf,int verbose,
+                  unsigned long certopt, unsigned long nameopt, int default_op,
+                  int ext_copy);
 static int certify_cert(X509 **xret, char *infile,EVP_PKEY *pkey,X509 *x509,
                        const EVP_MD *dgst,STACK_OF(CONF_VALUE) *policy,
 static int certify_cert(X509 **xret, char *infile,EVP_PKEY *pkey,X509 *x509,
                        const EVP_MD *dgst,STACK_OF(CONF_VALUE) *policy,
-                       TXT_DB *db, BIGNUM *serial,char *startdate,
+                       TXT_DB *db, BIGNUM *serial, char *subj, char *startdate,
                        char *enddate, int days, int batch, char *ext_sect,
                        char *enddate, int days, int batch, char *ext_sect,
-                       LHASH *conf,int verbose);
+                       LHASH *conf,int verbose, unsigned long certopt,
+                       unsigned long nameopt, int default_op, int ext_copy);
 static int certify_spkac(X509 **xret, char *infile,EVP_PKEY *pkey,X509 *x509,
                         const EVP_MD *dgst,STACK_OF(CONF_VALUE) *policy,
 static int certify_spkac(X509 **xret, char *infile,EVP_PKEY *pkey,X509 *x509,
                         const EVP_MD *dgst,STACK_OF(CONF_VALUE) *policy,
-                        TXT_DB *db, BIGNUM *serial,char *startdate,
+                        TXT_DB *db, BIGNUM *serial,char *subj, char *startdate,
                         char *enddate, int days, char *ext_sect,LHASH *conf,
                         char *enddate, int days, char *ext_sect,LHASH *conf,
-                               int verbose);
+                        int verbose, unsigned long certopt, unsigned long nameopt,
+                        int default_op, int ext_copy);
 static int fix_data(int nid, int *type);
 static void write_new_certificate(BIO *bp, X509 *x, int output_der, int notext);
 static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
 static int fix_data(int nid, int *type);
 static void write_new_certificate(BIO *bp, X509 *x, int output_der, int notext);
 static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
-       STACK_OF(CONF_VALUE) *policy, TXT_DB *db, BIGNUM *serial,
+       STACK_OF(CONF_VALUE) *policy, TXT_DB *db, BIGNUM *serial,char *subj,
        char *startdate, char *enddate, int days, int batch, int verbose,
        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);
+       X509_REQ *req, char *ext_sect, LHASH *conf,
+       unsigned long certopt, unsigned long nameopt, int default_op,
+       int ext_copy);
+static X509_NAME *do_subject(char *subject);
+static int do_revoke(X509 *x509, TXT_DB *db, int ext, char *extval);
+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 int check_time_format(char *str);
+char *make_revocation_str(int rev_type, char *rev_arg);
+int make_revoked(X509_REVOKED *rev, char *str);
+int old_entry_print(BIO *bp, ASN1_OBJECT *obj, ASN1_STRING *str);
 static LHASH *conf=NULL;
 static LHASH *conf=NULL;
+static LHASH *extconf=NULL;
 static char *section=NULL;
 
 static int preserve=0;
 static int msie_hack=0;
 
 static char *section=NULL;
 
 static int preserve=0;
 static int msie_hack=0;
 
+static IMPLEMENT_LHASH_HASH_FN(index_serial_hash,const char **)
+static IMPLEMENT_LHASH_COMP_FN(index_serial_cmp,const char **)
+static IMPLEMENT_LHASH_HASH_FN(index_name_hash,const char **)
+static IMPLEMENT_LHASH_COMP_FN(index_name_cmp,const char **)
+
+
 int MAIN(int, char **);
 
 int MAIN(int argc, char **argv)
        {
 int MAIN(int, char **);
 
 int MAIN(int argc, char **argv)
        {
-       char *key=NULL;
+       ENGINE *e = NULL;
+       char *key=NULL,*passargin=NULL;
        int total=0;
        int total_done=0;
        int badops=0;
        int total=0;
        int total_done=0;
        int badops=0;
@@ -226,6 +270,7 @@ int MAIN(int argc, char **argv)
        int verbose=0;
        int gencrl=0;
        int dorevoke=0;
        int verbose=0;
        int gencrl=0;
        int dorevoke=0;
+       int doupdatedb=0;
        long crldays=0;
        long crlhours=0;
        long errorline= -1;
        long crldays=0;
        long crlhours=0;
        long errorline= -1;
@@ -234,22 +279,31 @@ int MAIN(int argc, char **argv)
        char *policy=NULL;
        char *keyfile=NULL;
        char *certfile=NULL;
        char *policy=NULL;
        char *keyfile=NULL;
        char *certfile=NULL;
+       int keyform=FORMAT_PEM;
        char *infile=NULL;
        char *spkac_file=NULL;
        char *ss_cert_file=NULL;
        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;
        char *outdir=NULL;
        char *serialfile=NULL;
        char *extensions=NULL;
        EVP_PKEY *pkey=NULL;
        int output_der = 0;
        char *outfile=NULL;
        char *outdir=NULL;
        char *serialfile=NULL;
        char *extensions=NULL;
+       char *extfile=NULL;
+       char *subj=NULL;
        char *crl_ext=NULL;
        char *crl_ext=NULL;
+       int rev_type = REV_NONE;
+       char *rev_arg = NULL;
        BIGNUM *serial=NULL;
        char *startdate=NULL;
        char *enddate=NULL;
        int days=0;
        int batch=0;
        int notext=0;
        BIGNUM *serial=NULL;
        char *startdate=NULL;
        char *enddate=NULL;
        int days=0;
        int batch=0;
        int notext=0;
+       unsigned long nameopt = 0, certopt = 0;
+       int default_op = 1;
+       int ext_copy = 0;
        X509 *x509=NULL;
        X509 *x=NULL;
        BIO *in=NULL,*out=NULL,*Sout=NULL,*Cout=NULL;
        X509 *x509=NULL;
        X509 *x=NULL;
        BIO *in=NULL,*out=NULL,*Sout=NULL,*Cout=NULL;
@@ -264,11 +318,11 @@ int MAIN(int argc, char **argv)
        const EVP_MD *dgst=NULL;
        STACK_OF(CONF_VALUE) *attribs=NULL;
        STACK_OF(X509) *cert_sk=NULL;
        const EVP_MD *dgst=NULL;
        STACK_OF(CONF_VALUE) *attribs=NULL;
        STACK_OF(X509) *cert_sk=NULL;
-       BIO *hex=NULL;
 #undef BSIZE
 #define BSIZE 256
        MS_STATIC char buf[3][BSIZE];
        char *randfile=NULL;
 #undef BSIZE
 #define BSIZE 256
        MS_STATIC char buf[3][BSIZE];
        char *randfile=NULL;
+       char *engine = NULL;
 
 #ifdef EFENCE
 EF_PROTECT_FREE=1;
 
 #ifdef EFENCE
 EF_PROTECT_FREE=1;
@@ -304,6 +358,12 @@ EF_ALIGNMENT=0;
                        if (--argc < 1) goto bad;
                        section= *(++argv);
                        }
                        if (--argc < 1) goto bad;
                        section= *(++argv);
                        }
+               else if (strcmp(*argv,"-subj") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       subj= *(++argv);
+                       /* preserve=1; */
+                       }
                else if (strcmp(*argv,"-startdate") == 0)
                        {
                        if (--argc < 1) goto bad;
                else if (strcmp(*argv,"-startdate") == 0)
                        {
                        if (--argc < 1) goto bad;
@@ -334,6 +394,16 @@ EF_ALIGNMENT=0;
                        if (--argc < 1) goto bad;
                        keyfile= *(++argv);
                        }
                        if (--argc < 1) goto bad;
                        keyfile= *(++argv);
                        }
+               else if (strcmp(*argv,"-keyform") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       keyform=str2fmt(*(++argv));
+                       }
+               else if (strcmp(*argv,"-passin") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       passargin= *(++argv);
+                       }
                else if (strcmp(*argv,"-key") == 0)
                        {
                        if (--argc < 1) goto bad;
                else if (strcmp(*argv,"-key") == 0)
                        {
                        if (--argc < 1) goto bad;
@@ -410,11 +480,54 @@ EF_ALIGNMENT=0;
                        if (--argc < 1) goto bad;
                        extensions= *(++argv);
                        }
                        if (--argc < 1) goto bad;
                        extensions= *(++argv);
                        }
+               else if (strcmp(*argv,"-extfile") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       extfile= *(++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;
                        crl_ext= *(++argv);
                        }
                else if (strcmp(*argv,"-crlexts") == 0)
                        {
                        if (--argc < 1) goto bad;
                        crl_ext= *(++argv);
                        }
+               else if (strcmp(*argv,"-crl_reason") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       rev_arg = *(++argv);
+                       rev_type = REV_CRL_REASON;
+                       }
+               else if (strcmp(*argv,"-crl_hold") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       rev_arg = *(++argv);
+                       rev_type = REV_HOLD;
+                       }
+               else if (strcmp(*argv,"-crl_compromise") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       rev_arg = *(++argv);
+                       rev_type = REV_KEY_COMPROMISE;
+                       }
+               else if (strcmp(*argv,"-crl_CA_compromise") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       rev_arg = *(++argv);
+                       rev_type = REV_CA_COMPROMISE;
+                       }
+               else if (strcmp(*argv,"-engine") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       engine= *(++argv);
+                       }
                else
                        {
 bad:
                else
                        {
 bad:
@@ -429,19 +542,37 @@ bad:
        if (badops)
                {
                for (pp=ca_usage; (*pp != NULL); pp++)
        if (badops)
                {
                for (pp=ca_usage; (*pp != NULL); pp++)
-                       BIO_printf(bio_err,*pp);
+                       BIO_printf(bio_err,"%s",*pp);
                goto err;
                }
 
        ERR_load_crypto_strings();
 
                goto err;
                }
 
        ERR_load_crypto_strings();
 
+       if (engine != NULL)
+               {
+               if ((e = ENGINE_by_id(engine)) == NULL)
+                       {
+                       BIO_printf(bio_err,"invalid engine \"%s\"\n",
+                               engine);
+                       goto err;
+                       }
+               if (!ENGINE_set_default(e, ENGINE_METHOD_ALL))
+                       {
+                       BIO_printf(bio_err,"can't use that engine\n");
+                       goto err;
+                       }
+               BIO_printf(bio_err,"engine \"%s\" set.\n", engine);
+               /* Free our "structural" reference. */
+               ENGINE_free(e);
+               }
+
        /*****************************************************************/
        if (configfile == NULL) configfile = getenv("OPENSSL_CONF");
        if (configfile == NULL) configfile = getenv("SSLEAY_CONF");
        if (configfile == NULL)
                {
                /* We will just use 'buf[0]' as a temporary buffer.  */
        /*****************************************************************/
        if (configfile == NULL) configfile = getenv("OPENSSL_CONF");
        if (configfile == NULL) configfile = getenv("SSLEAY_CONF");
        if (configfile == NULL)
                {
                /* We will just use 'buf[0]' as a temporary buffer.  */
-#ifdef VMS
+#ifdef OPENSSL_SYS_VMS
                strncpy(buf[0],X509_get_default_cert_area(),
                        sizeof(buf[0])-1-sizeof(CONFIG_FILE));
 #else
                strncpy(buf[0],X509_get_default_cert_area(),
                        sizeof(buf[0])-1-sizeof(CONFIG_FILE));
 #else
@@ -479,6 +610,8 @@ bad:
        if (conf != NULL)
                {
                p=CONF_get_string(conf,NULL,"oid_file");
        if (conf != NULL)
                {
                p=CONF_get_string(conf,NULL,"oid_file");
+               if (p == NULL)
+                       ERR_clear_error();
                if (p != NULL)
                        {
                        BIO *oid_bio;
                if (p != NULL)
                        {
                        BIO *oid_bio;
@@ -498,7 +631,7 @@ bad:
                                BIO_free(oid_bio);
                                }
                        }
                                BIO_free(oid_bio);
                                }
                        }
-               if(!add_oid_section(conf)) 
+               if (!add_oid_section(bio_err,conf)) 
                        {
                        ERR_print_errors(bio_err);
                        goto err;
                        {
                        ERR_print_errors(bio_err);
                        goto err;
@@ -506,6 +639,8 @@ bad:
                }
 
        randfile = CONF_get_string(conf, BASE_SECTION, "RANDFILE");
                }
 
        randfile = CONF_get_string(conf, BASE_SECTION, "RANDFILE");
+       if (randfile == NULL)
+               ERR_clear_error();
        app_RAND_load_file(randfile, bio_err, 0);
        
        in=BIO_new(BIO_s_file());
        app_RAND_load_file(randfile, bio_err, 0);
        
        in=BIO_new(BIO_s_file());
@@ -519,7 +654,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))
 
        if ((keyfile == NULL) && ((keyfile=CONF_get_string(conf,
                section,ENV_PRIVATE_KEY)) == NULL))
@@ -527,14 +696,36 @@ bad:
                lookup_fail(section,ENV_PRIVATE_KEY);
                goto err;
                }
                lookup_fail(section,ENV_PRIVATE_KEY);
                goto err;
                }
-       if (BIO_read_filename(in,keyfile) <= 0)
+       if (!key && !app_passwd(bio_err, passargin, NULL, &key, NULL))
                {
                {
-               perror(keyfile);
-               BIO_printf(bio_err,"trying to load CA private key\n");
+               BIO_printf(bio_err,"Error getting password\n");
                goto err;
                }
                goto err;
                }
+       if (keyform == FORMAT_ENGINE)
+               {
+               if (!e)
+                       {
+                       BIO_printf(bio_err,"no engine specified\n");
+                       goto err;
+                       }
+               pkey = ENGINE_load_private_key(e, keyfile, key);
+               }
+       else if (keyform == FORMAT_PEM)
+               {
+               if (BIO_read_filename(in,keyfile) <= 0)
+                       {
+                       perror(keyfile);
+                       BIO_printf(bio_err,"trying to load CA private key\n");
+                       goto err;
+                       }
                pkey=PEM_read_bio_PrivateKey(in,NULL,NULL,key);
                pkey=PEM_read_bio_PrivateKey(in,NULL,NULL,key);
-               if(key) memset(key,0,strlen(key));
+               }
+       else
+               {
+               BIO_printf(bio_err,"bad input format specified for key file\n");
+               goto err;
+               }
+       if (key) memset(key,0,strlen(key));
        if (pkey == NULL)
                {
                BIO_printf(bio_err,"unable to load CA private key\n");
        if (pkey == NULL)
                {
                BIO_printf(bio_err,"unable to load CA private key\n");
@@ -549,7 +740,7 @@ bad:
                lookup_fail(section,ENV_CERTIFICATE);
                goto err;
                }
                lookup_fail(section,ENV_CERTIFICATE);
                goto err;
                }
-        if (BIO_read_filename(in,certfile) <= 0)
+       if (BIO_read_filename(in,certfile) <= 0)
                {
                perror(certfile);
                BIO_printf(bio_err,"trying to load CA certificate\n");
                {
                perror(certfile);
                BIO_printf(bio_err,"trying to load CA certificate\n");
@@ -569,12 +760,45 @@ bad:
                }
 
        f=CONF_get_string(conf,BASE_SECTION,ENV_PRESERVE);
                }
 
        f=CONF_get_string(conf,BASE_SECTION,ENV_PRESERVE);
+       if (f == NULL)
+               ERR_clear_error();
        if ((f != NULL) && ((*f == 'y') || (*f == 'Y')))
                preserve=1;
        f=CONF_get_string(conf,BASE_SECTION,ENV_MSIE_HACK);
        if ((f != NULL) && ((*f == 'y') || (*f == 'Y')))
                preserve=1;
        f=CONF_get_string(conf,BASE_SECTION,ENV_MSIE_HACK);
+       if (f == NULL)
+               ERR_clear_error();
        if ((f != NULL) && ((*f == 'y') || (*f == 'Y')))
                msie_hack=1;
 
        if ((f != NULL) && ((*f == 'y') || (*f == 'Y')))
                msie_hack=1;
 
+       f=CONF_get_string(conf,section,ENV_NAMEOPT);
+
+       if (f)
+               {
+               if (!set_name_ex(&nameopt, f))
+                       {
+                       BIO_printf(bio_err, "Invalid name options: \"%s\"\n", f);
+                       goto err;
+                       }
+               default_op = 0;
+               }
+       else
+               ERR_clear_error();
+
+       f=CONF_get_string(conf,section,ENV_CERTOPT);
+
+       if (f)
+               {
+               if (!set_cert_ex(&certopt, f))
+                       {
+                       BIO_printf(bio_err, "Invalid certificate options: \"%s\"\n", f);
+                       goto err;
+                       }
+               default_op = 0;
+               }
+       else
+               ERR_clear_error();
+
+
        /*****************************************************************/
        /* lookup where to write new certificates */
        if ((outdir == NULL) && (req))
        /*****************************************************************/
        /* lookup where to write new certificates */
        if ((outdir == NULL) && (req))
@@ -587,7 +811,8 @@ bad:
                        BIO_printf(bio_err,"there needs to be defined a directory for new certificate to be placed in\n");
                        goto err;
                        }
                        BIO_printf(bio_err,"there needs to be defined a directory for new certificate to be placed in\n");
                        goto err;
                        }
-#ifndef VMS /* outdir is a directory spec, but access() for VMS demands a
+#ifndef OPENSSL_SYS_VMS
+           /* outdir is a directory spec, but access() for VMS demands a
               filename.  In any case, stat(), below, will catch the problem
               if outdir is not a directory spec, and the fopen() or open()
               will catch an error if there is no write access.
               filename.  In any case, stat(), below, will catch the problem
               if outdir is not a directory spec, and the fopen() or open()
               will catch an error if there is no write access.
@@ -596,7 +821,7 @@ bad:
               C routines to convert the directory syntax to Unixly, and give
               that to access().  However, time's too short to do that just
               now.
               C routines to convert the directory syntax to Unixly, and give
               that to access().  However, time's too short to do that just
               now.
-            */
+           */
                if (access(outdir,R_OK|W_OK|X_OK) != 0)
                        {
                        BIO_printf(bio_err,"I am unable to access the %s directory\n",outdir);
                if (access(outdir,R_OK|W_OK|X_OK) != 0)
                        {
                        BIO_printf(bio_err,"I am unable to access the %s directory\n",outdir);
@@ -648,10 +873,9 @@ bad:
                        goto err;
                        }
                if ((pp[DB_type][0] == DB_TYPE_REV) &&
                        goto err;
                        }
                if ((pp[DB_type][0] == DB_TYPE_REV) &&
-                       !check_time_format(pp[DB_rev_date]))
+                       !make_revoked(NULL, pp[DB_rev_date]))
                        {
                        {
-                       BIO_printf(bio_err,"entry %d: invalid revocation date\n",
-                               i+1);
+                       BIO_printf(bio_err," in entry %d\n", i+1);
                        goto err;
                        }
                if (!check_time_format(pp[DB_exp_date]))
                        goto err;
                        }
                if (!check_time_format(pp[DB_exp_date]))
@@ -661,6 +885,11 @@ bad:
                        }
                p=pp[DB_serial];
                j=strlen(p);
                        }
                p=pp[DB_serial];
                j=strlen(p);
+               if (*p == '-')
+                       {
+                       p++;
+                       j--;
+                       }
                if ((j&1) || (j < 2))
                        {
                        BIO_printf(bio_err,"entry %d: bad serial number length (%d)\n",i+1,j);
                if ((j&1) || (j < 2))
                        {
                        BIO_printf(bio_err,"entry %d: bad serial number length (%d)\n",i+1,j);
@@ -681,33 +910,140 @@ bad:
        if (verbose)
                {
                BIO_set_fp(out,stdout,BIO_NOCLOSE|BIO_FP_TEXT); /* cannot fail */
        if (verbose)
                {
                BIO_set_fp(out,stdout,BIO_NOCLOSE|BIO_FP_TEXT); /* cannot fail */
+#ifdef OPENSSL_SYS_VMS
+               {
+               BIO *tmpbio = BIO_new(BIO_f_linebuffer());
+               out = BIO_push(tmpbio, out);
+               }
+#endif
                TXT_DB_write(out,db);
                BIO_printf(bio_err,"%d entries loaded from the database\n",
                        db->data->num);
                BIO_printf(bio_err,"generating index\n");
                }
        
                TXT_DB_write(out,db);
                BIO_printf(bio_err,"%d entries loaded from the database\n",
                        db->data->num);
                BIO_printf(bio_err,"generating index\n");
                }
        
-       if (!TXT_DB_create_index(db,DB_serial,NULL,index_serial_hash,
-               index_serial_cmp))
+       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;
                }
 
                {
                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))
+       if (!TXT_DB_create_index(db, DB_name, index_name_qual,
+                       LHASH_HASH_FN(index_name_hash),
+                       LHASH_COMP_FN(index_name_cmp)))
                {
                BIO_printf(bio_err,"error creating name index:(%ld,%ld,%ld)\n",
                        db->error,db->arg1,db->arg2);
                goto err;
                }
 
                {
                BIO_printf(bio_err,"error creating name index:(%ld,%ld,%ld)\n",
                        db->error,db->arg1,db->arg2);
                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;
+               }
+
+       /*****************************************************************/
+       /* Read extentions config file                                   */
+       if (extfile)
+               {
+               if (!(extconf=CONF_load(NULL,extfile,&errorline)))
+                       {
+                       if (errorline <= 0)
+                               BIO_printf(bio_err, "ERROR: loading the config file '%s'\n",
+                                       extfile);
+                       else
+                               BIO_printf(bio_err, "ERROR: on line %ld of config file '%s'\n",
+                                       errorline,extfile);
+                       ret = 1;
+                       goto err;
+                       }
+
+               if (verbose)
+                       BIO_printf(bio_err, "Succesfully loaded extensions file %s\n", extfile);
+
+               /* We can have sections in the ext file */
+               if (!extensions && !(extensions = CONF_get_string(extconf, "default", "extensions")))
+                       extensions = "default";
+               }
+
        /*****************************************************************/
        if (req || gencrl)
                {
                if (outfile != NULL)
                        {
        /*****************************************************************/
        if (req || gencrl)
                {
                if (outfile != NULL)
                        {
-
                        if (BIO_write_filename(Sout,outfile) <= 0)
                                {
                                perror(outfile);
                        if (BIO_write_filename(Sout,outfile) <= 0)
                                {
                                perror(outfile);
@@ -715,7 +1051,15 @@ bad:
                                }
                        }
                else
                                }
                        }
                else
+                       {
                        BIO_set_fp(Sout,stdout,BIO_NOCLOSE|BIO_FP_TEXT);
                        BIO_set_fp(Sout,stdout,BIO_NOCLOSE|BIO_FP_TEXT);
+#ifdef OPENSSL_SYS_VMS
+                       {
+                       BIO *tmpbio = BIO_new(BIO_f_linebuffer());
+                       Sout = BIO_push(tmpbio, Sout);
+                       }
+#endif
+                       }
                }
 
        if (req)
                }
 
        if (req)
@@ -749,26 +1093,42 @@ bad:
                        lookup_fail(section,ENV_SERIAL);
                        goto err;
                        }
                        lookup_fail(section,ENV_SERIAL);
                        goto err;
                        }
-               if(!extensions)
-                       extensions=CONF_get_string(conf,section,ENV_EXTENSIONS);
-               if(extensions) {
-                       /* Check syntax of file */
-                       X509V3_CTX ctx;
-                       X509V3_set_ctx_test(&ctx);
-                       X509V3_set_conf_lhash(&ctx, conf);
-                       if(!X509V3_EXT_add_conf(conf, &ctx, extensions, NULL)) {
-                               BIO_printf(bio_err,
-                                "Error Loading extension section %s\n",
+
+               if (!extconf)
+                       {
+                       /* no '-extfile' option, so we look for extensions
+                        * in the main configuration file */
+                       if (!extensions)
+                               {
+                               extensions=CONF_get_string(conf,section,
+                                                               ENV_EXTENSIONS);
+                               if (!extensions)
+                                       ERR_clear_error();
+                               }
+                       if (extensions)
+                               {
+                               /* Check syntax of file */
+                               X509V3_CTX ctx;
+                               X509V3_set_ctx_test(&ctx);
+                               X509V3_set_conf_lhash(&ctx, conf);
+                               if (!X509V3_EXT_add_conf(conf, &ctx, extensions,
+                                                               NULL))
+                                       {
+                                       BIO_printf(bio_err,
+                                       "Error Loading extension section %s\n",
                                                                 extensions);
                                                                 extensions);
-                               ret = 1;
-                               goto err;
+                                       ret = 1;
+                                       goto err;
+                                       }
+                               }
                        }
                        }
-               }
 
                if (startdate == NULL)
                        {
                        startdate=CONF_get_string(conf,section,
                                ENV_DEFAULT_STARTDATE);
 
                if (startdate == NULL)
                        {
                        startdate=CONF_get_string(conf,section,
                                ENV_DEFAULT_STARTDATE);
+                       if (startdate == NULL)
+                               ERR_clear_error();
                        }
                if (startdate && !ASN1_UTCTIME_set_string(NULL,startdate))
                        {
                        }
                if (startdate && !ASN1_UTCTIME_set_string(NULL,startdate))
                        {
@@ -781,6 +1141,8 @@ bad:
                        {
                        enddate=CONF_get_string(conf,section,
                                ENV_DEFAULT_ENDDATE);
                        {
                        enddate=CONF_get_string(conf,section,
                                ENV_DEFAULT_ENDDATE);
+                       if (enddate == NULL)
+                               ERR_clear_error();
                        }
                if (enddate && !ASN1_UTCTIME_set_string(NULL,enddate))
                        {
                        }
                if (enddate && !ASN1_UTCTIME_set_string(NULL,enddate))
                        {
@@ -826,8 +1188,8 @@ bad:
                        {
                        total++;
                        j=certify_spkac(&x,spkac_file,pkey,x509,dgst,attribs,db,
                        {
                        total++;
                        j=certify_spkac(&x,spkac_file,pkey,x509,dgst,attribs,db,
-                               serial,startdate,enddate, days,extensions,conf,
-                               verbose);
+                               serial,subj,startdate,enddate, days,extensions,conf,
+                               verbose, certopt, nameopt, default_op, ext_copy);
                        if (j < 0) goto err;
                        if (j > 0)
                                {
                        if (j < 0) goto err;
                        if (j > 0)
                                {
@@ -850,8 +1212,9 @@ bad:
                        {
                        total++;
                        j=certify_cert(&x,ss_cert_file,pkey,x509,dgst,attribs,
                        {
                        total++;
                        j=certify_cert(&x,ss_cert_file,pkey,x509,dgst,attribs,
-                               db,serial,startdate,enddate,days,batch,
-                               extensions,conf,verbose);
+                               db,serial,subj,startdate,enddate,days,batch,
+                               extensions,conf,verbose, certopt, nameopt,
+                                                       default_op, ext_copy);
                        if (j < 0) goto err;
                        if (j > 0)
                                {
                        if (j < 0) goto err;
                        if (j > 0)
                                {
@@ -869,8 +1232,9 @@ bad:
                        {
                        total++;
                        j=certify(&x,infile,pkey,x509,dgst,attribs,db,
                        {
                        total++;
                        j=certify(&x,infile,pkey,x509,dgst,attribs,db,
-                               serial,startdate,enddate,days,batch,
-                               extensions,conf,verbose);
+                               serial,subj,startdate,enddate,days,batch,
+                               extensions,conf,verbose, certopt, nameopt,
+                               default_op, ext_copy);
                        if (j < 0) goto err;
                        if (j > 0)
                                {
                        if (j < 0) goto err;
                        if (j > 0)
                                {
@@ -888,8 +1252,9 @@ bad:
                        {
                        total++;
                        j=certify(&x,argv[i],pkey,x509,dgst,attribs,db,
                        {
                        total++;
                        j=certify(&x,argv[i],pkey,x509,dgst,attribs,db,
-                               serial,startdate,enddate,days,batch,
-                               extensions,conf,verbose);
+                               serial,subj,startdate,enddate,days,batch,
+                               extensions,conf,verbose, certopt, nameopt,
+                               default_op, ext_copy);
                        if (j < 0) goto err;
                        if (j > 0)
                                {
                        if (j < 0) goto err;
                        if (j > 0)
                                {
@@ -927,7 +1292,7 @@ bad:
 
                        strncpy(buf[0],serialfile,BSIZE-4);
 
 
                        strncpy(buf[0],serialfile,BSIZE-4);
 
-#ifdef VMS
+#ifdef OPENSSL_SYS_VMS
                        strcat(buf[0],"-new");
 #else
                        strcat(buf[0],".new");
                        strcat(buf[0],"-new");
 #else
                        strcat(buf[0],".new");
@@ -937,7 +1302,7 @@ bad:
 
                        strncpy(buf[1],dbfile,BSIZE-4);
 
 
                        strncpy(buf[1],dbfile,BSIZE-4);
 
-#ifdef VMS
+#ifdef OPENSSL_SYS_VMS
                        strcat(buf[1],"-new");
 #else
                        strcat(buf[1],".new");
                        strcat(buf[1],"-new");
 #else
                        strcat(buf[1],".new");
@@ -967,7 +1332,7 @@ bad:
                        
                        strncpy(buf[2],outdir,BSIZE-(j*2)-6);
 
                        
                        strncpy(buf[2],outdir,BSIZE-(j*2)-6);
 
-#ifndef VMS
+#ifndef OPENSSL_SYS_VMS
                        strcat(buf[2],"/");
 #endif
 
                        strcat(buf[2],"/");
 #endif
 
@@ -1004,14 +1369,14 @@ bad:
                        /* Rename the database and the serial file */
                        strncpy(buf[2],serialfile,BSIZE-4);
 
                        /* Rename the database and the serial file */
                        strncpy(buf[2],serialfile,BSIZE-4);
 
-#ifdef VMS
+#ifdef OPENSSL_SYS_VMS
                        strcat(buf[2],"-old");
 #else
                        strcat(buf[2],".old");
 #endif
 
                        BIO_free(in);
                        strcat(buf[2],"-old");
 #else
                        strcat(buf[2],".old");
 #endif
 
                        BIO_free(in);
-                       BIO_free(out);
+                       BIO_free_all(out);
                        in=NULL;
                        out=NULL;
                        if (rename(serialfile,buf[2]) < 0)
                        in=NULL;
                        out=NULL;
                        if (rename(serialfile,buf[2]) < 0)
@@ -1032,7 +1397,7 @@ bad:
 
                        strncpy(buf[2],dbfile,BSIZE-4);
 
 
                        strncpy(buf[2],dbfile,BSIZE-4);
 
-#ifdef VMS
+#ifdef OPENSSL_SYS_VMS
                        strcat(buf[2],"-old");
 #else
                        strcat(buf[2],".old");
                        strcat(buf[2],"-old");
 #else
                        strcat(buf[2],".old");
@@ -1060,21 +1425,28 @@ bad:
        /*****************************************************************/
        if (gencrl)
                {
        /*****************************************************************/
        if (gencrl)
                {
-               if(!crl_ext) crl_ext=CONF_get_string(conf,section,ENV_CRLEXT);
-               if(crl_ext) {
+               int crl_v2 = 0;
+               if (!crl_ext)
+                       {
+                       crl_ext=CONF_get_string(conf,section,ENV_CRLEXT);
+                       if (!crl_ext)
+                               ERR_clear_error();
+                       }
+               if (crl_ext)
+                       {
                        /* Check syntax of file */
                        X509V3_CTX ctx;
                        X509V3_set_ctx_test(&ctx);
                        X509V3_set_conf_lhash(&ctx, conf);
                        /* Check syntax of file */
                        X509V3_CTX ctx;
                        X509V3_set_ctx_test(&ctx);
                        X509V3_set_conf_lhash(&ctx, conf);
-                       if(!X509V3_EXT_add_conf(conf, &ctx, crl_ext, NULL)) {
+                       if (!X509V3_EXT_add_conf(conf, &ctx, crl_ext, NULL))
+                               {
                                BIO_printf(bio_err,
                                 "Error Loading CRL extension section %s\n",
                                                                 crl_ext);
                                ret = 1;
                                goto err;
                                BIO_printf(bio_err,
                                 "Error Loading CRL extension section %s\n",
                                                                 crl_ext);
                                ret = 1;
                                goto err;
+                               }
                        }
                        }
-               }
-               if ((hex=BIO_new(BIO_s_mem())) == NULL) goto err;
 
                if (!crldays && !crlhours)
                        {
 
                if (!crldays && !crlhours)
                        {
@@ -1107,19 +1479,17 @@ bad:
                        if (pp[DB_type][0] == DB_TYPE_REV)
                                {
                                if ((r=X509_REVOKED_new()) == NULL) goto err;
                        if (pp[DB_type][0] == DB_TYPE_REV)
                                {
                                if ((r=X509_REVOKED_new()) == NULL) goto err;
-                               ASN1_STRING_set((ASN1_STRING *)
-                                       r->revocationDate,
-                                       (unsigned char *)pp[DB_rev_date],
-                                       strlen(pp[DB_rev_date]));
-                               /* strcpy(r->revocationDate,pp[DB_rev_date]);*/
-
-                               (void)BIO_reset(hex);
-                               if (!BIO_puts(hex,pp[DB_serial]))
+                               j = make_revoked(r, pp[DB_rev_date]);
+                               if (!j) goto err;
+                               if (j == 2) crl_v2 = 1;
+                               if (!BN_hex2bn(&serial, pp[DB_serial]))
                                        goto err;
                                        goto err;
-                               if (!a2i_ASN1_INTEGER(hex,r->serialNumber,
-                                       buf[0],BSIZE)) goto err;
-
-                               sk_X509_REVOKED_push(ci->revoked,r);
+                               r->serialNumber = BN_to_ASN1_INTEGER(serial, r->serialNumber);
+                               BN_free(serial);
+                               serial = NULL;
+                               if (!r->serialNumber)
+                                       goto err;
+                               X509_CRL_add0_revoked(crl,r);
                                }
                        }
                /* sort the data so it will be written in serial
                                }
                        }
                /* sort the data so it will be written in serial
@@ -1142,28 +1512,34 @@ bad:
                                }
                        }
                else
                                }
                        }
                else
-                   {
-#ifndef NO_DSA
-                   if (pkey->type == EVP_PKEY_DSA) 
-                       dgst=EVP_dss1();
-                   else
+                       {
+#ifndef OPENSSL_NO_DSA
+                       if (pkey->type == EVP_PKEY_DSA) 
+                               dgst=EVP_dss1();
+                       else
 #endif
 #endif
-                       dgst=EVP_md5();
-                   }
+                               dgst=EVP_md5();
+                       }
 
                /* Add any extensions asked for */
 
 
                /* Add any extensions asked for */
 
-               if(crl_ext) {
-                   X509V3_CTX crlctx;
-                   if (ci->version == NULL)
-                   if ((ci->version=ASN1_INTEGER_new()) == NULL) goto err;
-                   ASN1_INTEGER_set(ci->version,1); /* version 2 CRL */
-                   X509V3_set_ctx(&crlctx, x509, NULL, NULL, crl, 0);
-                   X509V3_set_conf_lhash(&crlctx, conf);
+               if (crl_ext)
+                       {
+                       X509V3_CTX crlctx;
+                       if (ci->version == NULL)
+                               if ((ci->version=ASN1_INTEGER_new()) == NULL) goto err;
+                       X509V3_set_ctx(&crlctx, x509, NULL, NULL, crl, 0);
+                       X509V3_set_conf_lhash(&crlctx, conf);
 
 
-                   if(!X509V3_EXT_CRL_add_conf(conf, &crlctx,
-                                                crl_ext, crl)) goto err;
-               }
+                       if (!X509V3_EXT_CRL_add_conf(conf, &crlctx,
+                               crl_ext, crl)) goto err;
+                       }
+               if (crl_ext || crl_v2)
+                       {
+                       if (ci->version == NULL)
+                               if ((ci->version=ASN1_INTEGER_new()) == NULL) goto err;
+                       ASN1_INTEGER_set(ci->version,1); /* version 2 CRL */
+                       }
 
                if (!X509_CRL_sign(crl,pkey,dgst)) goto err;
 
 
                if (!X509_CRL_sign(crl,pkey,dgst)) goto err;
 
@@ -1192,7 +1568,7 @@ bad:
                                BIO_printf(bio_err,"unable to load '%s' certificate\n",infile);
                                goto err;
                                }
                                BIO_printf(bio_err,"unable to load '%s' certificate\n",infile);
                                goto err;
                                }
-                       j=do_revoke(revcert,db);
+                       j=do_revoke(revcert,db, rev_type, rev_arg);
                        if (j <= 0) goto err;
                        X509_free(revcert);
 
                        if (j <= 0) goto err;
                        X509_free(revcert);
 
@@ -1227,10 +1603,9 @@ bad:
        /*****************************************************************/
        ret=0;
 err:
        /*****************************************************************/
        ret=0;
 err:
-       BIO_free(hex);
-       BIO_free(Cout);
-       BIO_free(Sout);
-       BIO_free(out);
+       BIO_free_all(Cout);
+       BIO_free_all(Sout);
+       BIO_free_all(out);
        BIO_free(in);
 
        sk_X509_pop_free(cert_sk,X509_free);
        BIO_free(in);
 
        sk_X509_pop_free(cert_sk,X509_free);
@@ -1252,31 +1627,31 @@ static void lookup_fail(char *name, char *tag)
        BIO_printf(bio_err,"variable lookup failed for %s::%s\n",name,tag);
        }
 
        BIO_printf(bio_err,"variable lookup failed for %s::%s\n",name,tag);
        }
 
-static unsigned long index_serial_hash(char **a)
+static unsigned long index_serial_hash(const char **a)
        {
        {
-       char *n;
+       const char *n;
 
        n=a[DB_serial];
        while (*n == '0') n++;
        return(lh_strhash(n));
        }
 
 
        n=a[DB_serial];
        while (*n == '0') n++;
        return(lh_strhash(n));
        }
 
-static int index_serial_cmp(char **a, char **b)
+static int index_serial_cmp(const char **a, const char **b)
        {
        {
-       char *aa,*bb;
+       const char *aa,*bb;
 
        for (aa=a[DB_serial]; *aa == '0'; aa++);
        for (bb=b[DB_serial]; *bb == '0'; bb++);
        return(strcmp(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(char **a)
+static unsigned long index_name_hash(const char **a)
        { return(lh_strhash(a[DB_name])); }
 
 static int index_name_qual(char **a)
        { return(a[0][0] == 'V'); }
 
        { return(lh_strhash(a[DB_name])); }
 
 static int index_name_qual(char **a)
        { return(a[0][0] == 'V'); }
 
-static int index_name_cmp(char **a, char **b)
+static int index_name_cmp(const char **a, const char **b)
        { return(strcmp(a[DB_name],
             b[DB_name])); }
 
        { return(strcmp(a[DB_name],
             b[DB_name])); }
 
@@ -1345,15 +1720,17 @@ static int save_serial(char *serialfile, BIGNUM *serial)
        BIO_puts(out,"\n");
        ret=1;
 err:
        BIO_puts(out,"\n");
        ret=1;
 err:
-       if (out != NULL) BIO_free(out);
+       if (out != NULL) BIO_free_all(out);
        if (ai != NULL) ASN1_INTEGER_free(ai);
        return(ret);
        }
 
 static int certify(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
             const EVP_MD *dgst, STACK_OF(CONF_VALUE) *policy, TXT_DB *db,
        if (ai != NULL) ASN1_INTEGER_free(ai);
        return(ret);
        }
 
 static int certify(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
             const EVP_MD *dgst, STACK_OF(CONF_VALUE) *policy, TXT_DB *db,
-            BIGNUM *serial, char *startdate, char *enddate, int days,
-            int batch, char *ext_sect, LHASH *lconf, int verbose)
+            BIGNUM *serial, char *subj, char *startdate, char *enddate, int days,
+            int batch, char *ext_sect, LHASH *lconf, int verbose,
+            unsigned long certopt, unsigned long nameopt, int default_op,
+            int ext_copy)
        {
        X509_REQ *req=NULL;
        BIO *in=NULL;
        {
        X509_REQ *req=NULL;
        BIO *in=NULL;
@@ -1400,8 +1777,9 @@ static int certify(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
        else
                BIO_printf(bio_err,"Signature ok\n");
 
        else
                BIO_printf(bio_err,"Signature ok\n");
 
-       ok=do_body(xret,pkey,x509,dgst,policy,db,serial,startdate, enddate,
-               days,batch,verbose,req,ext_sect,lconf);
+       ok=do_body(xret,pkey,x509,dgst,policy,db,serial,subj,startdate, enddate,
+               days,batch,verbose,req,ext_sect,lconf,
+               certopt, nameopt, default_op, ext_copy);
 
 err:
        if (req != NULL) X509_REQ_free(req);
 
 err:
        if (req != NULL) X509_REQ_free(req);
@@ -1411,8 +1789,10 @@ err:
 
 static int certify_cert(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
             const EVP_MD *dgst, STACK_OF(CONF_VALUE) *policy, TXT_DB *db,
 
 static int certify_cert(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
             const EVP_MD *dgst, STACK_OF(CONF_VALUE) *policy, TXT_DB *db,
-            BIGNUM *serial, char *startdate, char *enddate, int days,
-            int batch, char *ext_sect, LHASH *lconf, int verbose)
+            BIGNUM *serial, char *subj, char *startdate, char *enddate, int days,
+            int batch, char *ext_sect, LHASH *lconf, int verbose,
+            unsigned long certopt, unsigned long nameopt, int default_op,
+            int ext_copy)
        {
        X509 *req=NULL;
        X509_REQ *rreq=NULL;
        {
        X509 *req=NULL;
        X509_REQ *rreq=NULL;
@@ -1462,8 +1842,9 @@ static int certify_cert(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
        if ((rreq=X509_to_X509_REQ(req,NULL,EVP_md5())) == NULL)
                goto err;
 
        if ((rreq=X509_to_X509_REQ(req,NULL,EVP_md5())) == NULL)
                goto err;
 
-       ok=do_body(xret,pkey,x509,dgst,policy,db,serial,startdate,enddate,days,
-               batch,verbose,rreq,ext_sect,lconf);
+       ok=do_body(xret,pkey,x509,dgst,policy,db,serial,subj,startdate,enddate,days,
+               batch,verbose,rreq,ext_sect,lconf, certopt, nameopt, default_op,
+                       ext_copy);
 
 err:
        if (rreq != NULL) X509_REQ_free(rreq);
 
 err:
        if (rreq != NULL) X509_REQ_free(rreq);
@@ -1473,9 +1854,11 @@ err:
        }
 
 static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
        }
 
 static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
-            STACK_OF(CONF_VALUE) *policy, TXT_DB *db, BIGNUM *serial,
+            STACK_OF(CONF_VALUE) *policy, TXT_DB *db, BIGNUM *serial, char *subj,
             char *startdate, char *enddate, int days, int batch, int verbose,
             char *startdate, char *enddate, int days, int batch, int verbose,
-            X509_REQ *req, char *ext_sect, LHASH *lconf)
+            X509_REQ *req, char *ext_sect, LHASH *lconf,
+            unsigned long certopt, unsigned long nameopt, int default_op,
+            int ext_copy)
        {
        X509_NAME *name=NULL,*CAname=NULL,*subject=NULL;
        ASN1_UTCTIME *tm,*tmptm;
        {
        X509_NAME *name=NULL,*CAname=NULL,*subject=NULL;
        ASN1_UTCTIME *tm,*tmptm;
@@ -1490,7 +1873,7 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
        char *p;
        CONF_VALUE *cv;
        char *row[DB_NUMBER],**rrow,**irow=NULL;
        char *p;
        CONF_VALUE *cv;
        char *row[DB_NUMBER],**rrow,**irow=NULL;
-       char buf[25],*pbuf;
+       char buf[25];
 
        tmptm=ASN1_UTCTIME_new();
        if (tmptm == NULL)
 
        tmptm=ASN1_UTCTIME_new();
        if (tmptm == NULL)
@@ -1502,20 +1885,28 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
        for (i=0; i<DB_NUMBER; i++)
                row[i]=NULL;
 
        for (i=0; i<DB_NUMBER; i++)
                row[i]=NULL;
 
-       BIO_printf(bio_err,"The Subjects Distinguished Name is as follows\n");
+       if (subj)
+               {
+               X509_NAME *n = do_subject(subj);
+
+               if (!n)
+                       {
+                       ERR_print_errors(bio_err);
+                       goto err;
+                       }
+               X509_REQ_set_subject_name(req,n);
+               req->req_info->enc.modified = 1;
+               X509_NAME_free(n);
+               }
+
+       if (default_op)
+               BIO_printf(bio_err,"The Subject's Distinguished Name is as follows\n");
        name=X509_REQ_get_subject_name(req);
        for (i=0; i<X509_NAME_entry_count(name); i++)
                {
        name=X509_REQ_get_subject_name(req);
        for (i=0; i<X509_NAME_entry_count(name); i++)
                {
-               ne=(X509_NAME_ENTRY *)X509_NAME_get_entry(name,i);
-               obj=X509_NAME_ENTRY_get_object(ne);
-               j=i2a_ASN1_OBJECT(bio_err,obj);
+               ne= X509_NAME_get_entry(name,i);
                str=X509_NAME_ENTRY_get_data(ne);
                str=X509_NAME_ENTRY_get_data(ne);
-               pbuf=buf;
-               for (j=22-j; j>0; j--)
-                       *(pbuf++)=' ';
-               *(pbuf++)=':';
-               *(pbuf++)='\0';
-               BIO_puts(bio_err,buf);
+               obj=X509_NAME_ENTRY_get_object(ne);
 
                if (msie_hack)
                        {
 
                if (msie_hack)
                        {
@@ -1534,17 +1925,6 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
                                str->type=V_ASN1_IA5STRING;
                        }
 
                                str->type=V_ASN1_IA5STRING;
                        }
 
-               if (str->type == V_ASN1_PRINTABLESTRING)
-                       BIO_printf(bio_err,"PRINTABLE:'");
-               else if (str->type == V_ASN1_T61STRING)
-                       BIO_printf(bio_err,"T61STRING:'");
-               else if (str->type == V_ASN1_IA5STRING)
-                       BIO_printf(bio_err,"IA5STRING:'");
-               else if (str->type == V_ASN1_UNIVERSALSTRING)
-                       BIO_printf(bio_err,"UNIVERSALSTRING:'");
-               else
-                       BIO_printf(bio_err,"ASN.1 %2d:'",str->type);
-
                /* check some things */
                if ((OBJ_obj2nid(obj) == NID_pkcs9_emailAddress) &&
                        (str->type != V_ASN1_IA5STRING))
                /* check some things */
                if ((OBJ_obj2nid(obj) == NID_pkcs9_emailAddress) &&
                        (str->type != V_ASN1_IA5STRING))
@@ -1561,6 +1941,28 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
                        BIO_printf(bio_err,"\nThe string contains characters that are illegal for the ASN.1 type\n");
                        goto err;
                        }
                        BIO_printf(bio_err,"\nThe string contains characters that are illegal for the ASN.1 type\n");
                        goto err;
                        }
+
+               if (default_op)
+                       old_entry_print(bio_err, obj, str);
+#if 0
+               j=i2a_ASN1_OBJECT(bio_err,obj);
+               pbuf=buf;
+               for (j=22-j; j>0; j--)
+                       *(pbuf++)=' ';
+               *(pbuf++)=':';
+               *(pbuf++)='\0';
+               BIO_puts(bio_err,buf);
+
+               if (str->type == V_ASN1_PRINTABLESTRING)
+                       BIO_printf(bio_err,"PRINTABLE:'");
+               else if (str->type == V_ASN1_T61STRING)
+                       BIO_printf(bio_err,"T61STRING:'");
+               else if (str->type == V_ASN1_IA5STRING)
+                       BIO_printf(bio_err,"IA5STRING:'");
+               else if (str->type == V_ASN1_UNIVERSALSTRING)
+                       BIO_printf(bio_err,"UNIVERSALSTRING:'");
+               else
+                       BIO_printf(bio_err,"ASN.1 %2d:'",str->type);
                        
                p=(char *)str->data;
                for (j=str->length; j>0; j--)
                        
                p=(char *)str->data;
                for (j=str->length; j>0; j--)
@@ -1575,6 +1977,7 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
                        p++;
                        }
                BIO_printf(bio_err,"'\n");
                        p++;
                        }
                BIO_printf(bio_err,"'\n");
+#endif
                }
 
        /* Ok, now we check the 'policy' stuff. */
                }
 
        /* Ok, now we check the 'policy' stuff. */
@@ -1778,7 +2181,7 @@ again2:
        else ASN1_UTCTIME_set_string(X509_get_notAfter(ret),enddate);
 
        ASN1_UTCTIME_print(bio_err,X509_get_notAfter(ret));
        else ASN1_UTCTIME_set_string(X509_get_notAfter(ret),enddate);
 
        ASN1_UTCTIME_print(bio_err,X509_get_notAfter(ret));
-       if(days) BIO_printf(bio_err," (%d days)",days);
+       if (days) BIO_printf(bio_err," (%d days)",days);
        BIO_printf(bio_err, "\n");
 
        if (!X509_set_subject_name(ret,subject)) goto err;
        BIO_printf(bio_err, "\n");
 
        if (!X509_set_subject_name(ret,subject)) goto err;
@@ -1805,16 +2208,59 @@ again2:
 
                ci->extensions = NULL;
 
 
                ci->extensions = NULL;
 
+               /* Initialize the context structure */
                X509V3_set_ctx(&ctx, x509, ret, req, NULL, 0);
                X509V3_set_ctx(&ctx, x509, ret, req, NULL, 0);
-               X509V3_set_conf_lhash(&ctx, lconf);
 
 
-               if(!X509V3_EXT_add_conf(lconf, &ctx, ext_sect, ret)) goto err;
+               if (extconf)
+                       {
+                       if (verbose)
+                               BIO_printf(bio_err, "Extra configuration file found\n");
+                       /* Use the extconf configuration db LHASH */
+                       X509V3_set_conf_lhash(&ctx, extconf);
+                       /* Test the structure (needed?) */
+                       /* X509V3_set_ctx_test(&ctx); */
+
+                       /* Adds exts contained in the configuration file */
+                       if (!X509V3_EXT_add_conf(extconf, &ctx, ext_sect,ret))
+                               {
+                               BIO_printf(bio_err,
+                                   "ERROR: adding extensions in section %s\n",
+                                                               ext_sect);
+                               ERR_print_errors(bio_err);
+                               goto err;
+                               }
+                       if (verbose)
+                               BIO_printf(bio_err, "Successfully added extensions from file.\n");
+                       }
+               else if (ext_sect)
+                       {
+                       /* We found extensions to be set from config file */
+                       X509V3_set_conf_lhash(&ctx, lconf);
 
 
+                       if(!X509V3_EXT_add_conf(lconf, &ctx, ext_sect, ret))
+                               {
+                               BIO_printf(bio_err, "ERROR: adding extensions in section %s\n", ext_sect);
+                               ERR_print_errors(bio_err);
+                               goto err;
+                               }
+
+                       if (verbose) 
+                               BIO_printf(bio_err, "Successfully added extensions from config\n");
+                       }
                }
 
 
        if (!batch)
                {
                }
 
 
        if (!batch)
                {
+               if (!default_op)
+                       {
+                       BIO_printf(bio_err, "Certificate Details:\n");
+                       /* Never print signature details because signature not present */
+                       certopt |= X509_FLAG_NO_SIGDUMP | X509_FLAG_NO_SIGNAME;
+                       X509_print_ex(bio_err, ret, nameopt, certopt); 
+                       }
                BIO_printf(bio_err,"Sign the certificate? [y/n]:");
                (void)BIO_flush(bio_err);
                buf[0]='\0';
                BIO_printf(bio_err,"Sign the certificate? [y/n]:");
                (void)BIO_flush(bio_err);
                buf[0]='\0';
@@ -1828,7 +2274,7 @@ again2:
                }
 
 
                }
 
 
-#ifndef NO_DSA
+#ifndef OPENSSL_NO_DSA
        if (pkey->type == EVP_PKEY_DSA) dgst=EVP_dss1();
        pktmp=X509_get_pubkey(ret);
        if (EVP_PKEY_missing_parameters(pktmp) &&
        if (pkey->type == EVP_PKEY_DSA) dgst=EVP_dss1();
        pktmp=X509_get_pubkey(ret);
        if (EVP_PKEY_missing_parameters(pktmp) &&
@@ -1924,14 +2370,15 @@ static void write_new_certificate(BIO *bp, X509 *x, int output_der, int notext)
        i2a_ASN1_INTEGER(bp,x->cert_info->serialNumber);
        BIO_puts(bp,"\n\n");
 #endif
        i2a_ASN1_INTEGER(bp,x->cert_info->serialNumber);
        BIO_puts(bp,"\n\n");
 #endif
-       if(!notext)X509_print(bp,x);
+       if (!notext)X509_print(bp,x);
        PEM_write_bio_X509(bp,x);
        }
 
 static int certify_spkac(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
             const EVP_MD *dgst, STACK_OF(CONF_VALUE) *policy, TXT_DB *db,
        PEM_write_bio_X509(bp,x);
        }
 
 static int certify_spkac(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
             const EVP_MD *dgst, STACK_OF(CONF_VALUE) *policy, TXT_DB *db,
-            BIGNUM *serial, char *startdate, char *enddate, int days,
-            char *ext_sect, LHASH *lconf, int verbose)
+            BIGNUM *serial, char *subj, char *startdate, char *enddate, int days,
+            char *ext_sect, LHASH *lconf, int verbose, unsigned long certopt,
+            unsigned long nameopt, int default_op, int ext_copy)
        {
        STACK_OF(CONF_VALUE) *sk=NULL;
        LHASH *parms=NULL;
        {
        STACK_OF(CONF_VALUE) *sk=NULL;
        LHASH *parms=NULL;
@@ -1997,12 +2444,13 @@ static int certify_spkac(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
                /* Skip past any leading X. X: X, etc to allow for
                 * multiple instances
                 */
                /* Skip past any leading X. X: X, etc to allow for
                 * multiple instances
                 */
-               for(buf = cv->name; *buf ; buf++)
-                       if ((*buf == ':') || (*buf == ',') || (*buf == '.')) {
-                                       buf++;
-                                       if(*buf) type = buf;
-                                       break;
-               }
+               for (buf = cv->name; *buf ; buf++)
+                       if ((*buf == ':') || (*buf == ',') || (*buf == '.'))
+                               {
+                               buf++;
+                               if (*buf) type = buf;
+                               break;
+                               }
 
                buf=cv->value;
                if ((nid=OBJ_txt2nid(type)) == NID_undef)
 
                buf=cv->value;
                if ((nid=OBJ_txt2nid(type)) == NID_undef)
@@ -2064,8 +2512,9 @@ static int certify_spkac(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
 
        X509_REQ_set_pubkey(req,pktmp);
        EVP_PKEY_free(pktmp);
 
        X509_REQ_set_pubkey(req,pktmp);
        EVP_PKEY_free(pktmp);
-       ok=do_body(xret,pkey,x509,dgst,policy,db,serial,startdate,enddate,
-                  days,1,verbose,req,ext_sect,lconf);
+       ok=do_body(xret,pkey,x509,dgst,policy,db,serial,subj,startdate,enddate,
+                  days,1,verbose,req,ext_sect,lconf, certopt, nameopt, default_op,
+                       ext_copy);
 err:
        if (req != NULL) X509_REQ_free(req);
        if (parms != NULL) CONF_free(parms);
 err:
        if (req != NULL) X509_REQ_free(req);
        if (parms != NULL) CONF_free(parms);
@@ -2100,32 +2549,11 @@ static int check_time_format(char *str)
        return(ASN1_UTCTIME_check(&tm));
        }
 
        return(ASN1_UTCTIME_check(&tm));
        }
 
-static int add_oid_section(LHASH *hconf)
-{      
-       char *p;
-       STACK_OF(CONF_VALUE) *sktmp;
-       CONF_VALUE *cnf;
-       int i;
-       if(!(p=CONF_get_string(hconf,NULL,"oid_section"))) return 1;
-       if(!(sktmp = CONF_get_section(hconf, p))) {
-               BIO_printf(bio_err, "problem loading oid section %s\n", p);
-               return 0;
-       }
-       for(i = 0; i < sk_CONF_VALUE_num(sktmp); i++) {
-               cnf = sk_CONF_VALUE_value(sktmp, i);
-               if(OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) {
-                       BIO_printf(bio_err, "problem creating object %s=%s\n",
-                                                        cnf->name, cnf->value);
-                       return 0;
-               }
-       }
-       return 1;
-}
-
-static int do_revoke(X509 *x509, TXT_DB *db)
-{
-       ASN1_UTCTIME *tm=NULL, *revtm=NULL;
+static int do_revoke(X509 *x509, TXT_DB *db, int type, char *value)
+       {
+       ASN1_UTCTIME *tm=NULL;
        char *row[DB_NUMBER],**rrow,**irow;
        char *row[DB_NUMBER],**rrow,**irow;
+       char *rev_str = NULL;
        BIGNUM *bn = NULL;
        int ok=-1,i;
 
        BIGNUM *bn = NULL;
        int ok=-1,i;
 
@@ -2194,12 +2622,12 @@ static int do_revoke(X509 *x509, TXT_DB *db)
                        }
 
                /* Revoke Certificate */
                        }
 
                /* Revoke Certificate */
-               ok = do_revoke(x509,db);
+               ok = do_revoke(x509,db, type, value);
 
                goto err;
 
                }
 
                goto err;
 
                }
-       else if (index_name_cmp(row,rrow))
+       else if (index_name_cmp((const char **)row,(const char **)rrow))
                {
                BIO_printf(bio_err,"ERROR:name does not match %s\n",
                           row[DB_name]);
                {
                BIO_printf(bio_err,"ERROR:name does not match %s\n",
                           row[DB_name]);
@@ -2214,14 +2642,15 @@ static int do_revoke(X509 *x509, TXT_DB *db)
        else
                {
                BIO_printf(bio_err,"Revoking Certificate %s.\n", rrow[DB_serial]);
        else
                {
                BIO_printf(bio_err,"Revoking Certificate %s.\n", rrow[DB_serial]);
-               revtm = ASN1_UTCTIME_new();
-               revtm=X509_gmtime_adj(revtm,0);
+               rev_str = make_revocation_str(type, value);
+               if (!rev_str)
+                       {
+                       BIO_printf(bio_err, "Error in revocation arguments\n");
+                       goto err;
+                       }
                rrow[DB_type][0]='R';
                rrow[DB_type][1]='\0';
                rrow[DB_type][0]='R';
                rrow[DB_type][1]='\0';
-               rrow[DB_rev_date]=(char *)OPENSSL_malloc(revtm->length+1);
-               memcpy(rrow[DB_rev_date],revtm->data,revtm->length);
-               rrow[DB_rev_date][revtm->length]='\0';
-               ASN1_UTCTIME_free(revtm);
+               rrow[DB_rev_date] = rev_str;
                }
        ok=1;
 err:
                }
        ok=1;
 err:
@@ -2231,5 +2660,505 @@ err:
                        OPENSSL_free(row[i]);
                }
        return(ok);
                        OPENSSL_free(row[i]);
                }
        return(ok);
-}
+       }
 
 
+static int get_certificate_status(const 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] = 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);
+       }
+
+static char *crl_reasons[] = {
+       /* CRL reason strings */
+       "unspecified",
+       "keyCompromise",
+       "CACompromise",
+       "affiliationChanged",
+       "superseded", 
+       "cessationOfOperation",
+       "certificateHold",
+       "removeFromCRL",
+       /* Additional pseudo reasons */
+       "holdInstruction",
+       "keyTime",
+       "CAkeyTime"
+};
+
+#define NUM_REASONS (sizeof(crl_reasons) / sizeof(char *))
+
+/* Given revocation information convert to a DB string.
+ * The format of the string is:
+ * revtime[,reason,extra]. Where 'revtime' is the
+ * revocation time (the current time). 'reason' is the
+ * optional CRL reason and 'extra' is any additional
+ * argument
+ */
+
+char *make_revocation_str(int rev_type, char *rev_arg)
+       {
+       char *reason = NULL, *other = NULL, *str;
+       ASN1_OBJECT *otmp;
+       ASN1_UTCTIME *revtm = NULL;
+       int i;
+       switch (rev_type)
+               {
+       case REV_NONE:
+               break;
+
+       case REV_CRL_REASON:
+               for (i = 0; i < 8; i++)
+                       {
+                       if (!strcasecmp(rev_arg, crl_reasons[i]))
+                               {
+                               reason = crl_reasons[i];
+                               break;
+                               }
+                       }
+               if (reason == NULL)
+                       {
+                       BIO_printf(bio_err, "Unknown CRL reason %s\n", rev_arg);
+                       return NULL;
+                       }
+               break;
+
+       case REV_HOLD:
+               /* Argument is an OID */
+
+               otmp = OBJ_txt2obj(rev_arg, 0);
+               ASN1_OBJECT_free(otmp);
+
+               if (otmp == NULL)
+                       {
+                       BIO_printf(bio_err, "Invalid object identifier %s\n", rev_arg);
+                       return NULL;
+                       }
+
+               reason = "holdInstruction";
+               other = rev_arg;
+               break;
+               
+       case REV_KEY_COMPROMISE:
+       case REV_CA_COMPROMISE:
+
+               /* Argument is the key compromise time  */
+               if (!ASN1_GENERALIZEDTIME_set_string(NULL, rev_arg))
+                       {       
+                       BIO_printf(bio_err, "Invalid time format %s. Need YYYYMMDDHHMMSSZ\n", rev_arg);
+                       return NULL;
+                       }
+               other = rev_arg;
+               if (rev_type == REV_KEY_COMPROMISE)
+                       reason = "keyTime";
+               else 
+                       reason = "CAkeyTime";
+
+               break;
+
+               }
+
+       revtm = X509_gmtime_adj(NULL, 0);
+
+       i = revtm->length + 1;
+
+       if (reason) i += strlen(reason) + 1;
+       if (other) i += strlen(other) + 1;
+
+       str = OPENSSL_malloc(i);
+
+       if (!str) return NULL;
+
+       strcpy(str, (char *)revtm->data);
+       if (reason)
+               {
+               strcat(str, ",");
+               strcat(str, reason);
+               }
+       if (other)
+               {
+               strcat(str, ",");
+               strcat(str, other);
+               }
+       ASN1_UTCTIME_free(revtm);
+       return str;
+       }
+
+/* Convert revocation field to X509_REVOKED entry 
+ * return code:
+ * 0 error
+ * 1 OK
+ * 2 OK and some extensions added (i.e. V2 CRL)
+ */
+
+int make_revoked(X509_REVOKED *rev, char *str)
+       {
+       char *tmp = NULL;
+       char *rtime_str, *reason_str = NULL, *arg_str = NULL, *p;
+       int reason_code = -1;
+       int i, ret = 0;
+       ASN1_OBJECT *hold = NULL;
+       ASN1_GENERALIZEDTIME *comp_time = NULL;
+       ASN1_ENUMERATED *rtmp = NULL;
+       tmp = BUF_strdup(str);
+
+       p = strchr(tmp, ',');
+
+       rtime_str = tmp;
+
+       if (p)
+               {
+               *p = '\0';
+               p++;
+               reason_str = p;
+               p = strchr(p, ',');
+               if (p)
+                       {
+                       *p = '\0';
+                       arg_str = p + 1;
+                       }
+               }
+
+       if (rev && !ASN1_UTCTIME_set_string(rev->revocationDate, rtime_str))
+               {
+               BIO_printf(bio_err, "invalid revocation date %s\n", rtime_str);
+               goto err;
+               }
+       if (reason_str)
+               {
+               for (i = 0; i < NUM_REASONS; i++)
+                       {
+                       if(!strcasecmp(reason_str, crl_reasons[i]))
+                               {
+                               reason_code = i;
+                               break;
+                               }
+                       }
+               if (reason_code == OCSP_REVOKED_STATUS_NOSTATUS)
+                       {
+                       BIO_printf(bio_err, "invalid reason code %s\n", reason_str);
+                       goto err;
+                       }
+
+               if (reason_code == 7)
+                       reason_code = OCSP_REVOKED_STATUS_REMOVEFROMCRL;
+               else if (reason_code == 8)              /* Hold instruction */
+                       {
+                       if (!arg_str)
+                               {       
+                               BIO_printf(bio_err, "missing hold instruction\n");
+                               goto err;
+                               }
+                       reason_code = OCSP_REVOKED_STATUS_CERTIFICATEHOLD;
+                       hold = OBJ_txt2obj(arg_str, 0);
+
+                       if (!hold)
+                               {
+                               BIO_printf(bio_err, "invalid object identifier %s\n", arg_str);
+                               goto err;
+                               }
+                       }
+               else if ((reason_code == 9) || (reason_code == 10))
+                       {
+                       if (!arg_str)
+                               {       
+                               BIO_printf(bio_err, "missing compromised time\n");
+                               goto err;
+                               }
+                       comp_time = ASN1_GENERALIZEDTIME_new();
+                       if (!ASN1_GENERALIZEDTIME_set_string(comp_time, arg_str))
+                               {       
+                               BIO_printf(bio_err, "invalid compromised time %s\n", arg_str);
+                               goto err;
+                               }
+                       if (reason_code == 9)
+                               reason_code = OCSP_REVOKED_STATUS_KEYCOMPROMISE;
+                       else
+                               reason_code = OCSP_REVOKED_STATUS_CACOMPROMISE;
+                       }
+               }
+
+       if (rev && (reason_code != OCSP_REVOKED_STATUS_NOSTATUS))
+               {
+               rtmp = ASN1_ENUMERATED_new();
+               if (!rtmp || !ASN1_ENUMERATED_set(rtmp, reason_code))
+                       goto err;
+               if (!X509_REVOKED_add1_ext_i2d(rev, NID_crl_reason, rtmp, 0, 0))
+                       goto err;
+               }
+
+       if (rev && comp_time)
+               {
+               if (!X509_REVOKED_add1_ext_i2d(rev, NID_invalidity_date, comp_time, 0, 0))
+                       goto err;
+               }
+       if (rev && hold)
+               {
+               if (!X509_REVOKED_add1_ext_i2d(rev, NID_hold_instruction_code, hold, 0, 0))
+                       goto err;
+               }
+
+       if (reason_code != OCSP_REVOKED_STATUS_NOSTATUS)
+               ret = 2;
+       else ret = 1;
+
+       err:
+
+       if (tmp) OPENSSL_free(tmp);
+       ASN1_OBJECT_free(hold);
+       ASN1_GENERALIZEDTIME_free(comp_time);
+       ASN1_ENUMERATED_free(rtmp);
+
+       return ret;
+       }
+
+static X509_NAME *do_subject(char *subject)
+       {
+       X509_NAME *n = NULL;
+
+       int i, nid, ne_num=0;
+
+       char *ne_name = NULL;
+       char *ne_value = NULL;
+
+       char *tmp = NULL;
+       char *p[2];
+
+       char *str_list[256];
+       
+       p[0] = ",/";
+       p[1] = "=";
+
+       n = X509_NAME_new();
+
+       tmp = strtok(subject, p[0]);
+       while((tmp != NULL) && (ne_num < (sizeof str_list/sizeof *str_list)))
+               {
+               char *token = tmp;
+
+               while (token[0] == ' ')
+                       token++;
+               str_list[ne_num] = token;
+
+               tmp = strtok(NULL, p[0]);
+               ne_num++;
+               }
+
+       for (i = 0; i < ne_num; i++)
+               {
+               ne_name  = strtok(str_list[i], p[1]);
+               ne_value = strtok(NULL, p[1]);
+
+               if ((nid=OBJ_txt2nid(ne_name)) == NID_undef)
+                       {
+                       BIO_printf(bio_err, "Subject Attribute %s has no known NID, skipped\n", ne_name);
+                       continue;
+                       }
+
+               if (ne_value == NULL)
+                       {
+                       BIO_printf(bio_err, "No value provided for Subject Attribute %s, skipped\n", ne_name);
+                       continue;
+                       }
+
+               if (!X509_NAME_add_entry_by_NID(n, nid, MBSTRING_ASC, (unsigned char*)ne_value, -1,-1,0))
+                       {
+                       X509_NAME_free(n);
+                       return NULL;
+                       }
+               }
+
+       return n;
+       }
+
+
+int old_entry_print(BIO *bp, ASN1_OBJECT *obj, ASN1_STRING *str)
+       {
+       char buf[25],*pbuf, *p;
+       int j;
+       j=i2a_ASN1_OBJECT(bp,obj);
+       pbuf=buf;
+       for (j=22-j; j>0; j--)
+               *(pbuf++)=' ';
+       *(pbuf++)=':';
+       *(pbuf++)='\0';
+       BIO_puts(bp,buf);
+
+       if (str->type == V_ASN1_PRINTABLESTRING)
+               BIO_printf(bp,"PRINTABLE:'");
+       else if (str->type == V_ASN1_T61STRING)
+               BIO_printf(bp,"T61STRING:'");
+       else if (str->type == V_ASN1_IA5STRING)
+               BIO_printf(bp,"IA5STRING:'");
+       else if (str->type == V_ASN1_UNIVERSALSTRING)
+               BIO_printf(bp,"UNIVERSALSTRING:'");
+       else
+               BIO_printf(bp,"ASN.1 %2d:'",str->type);
+                       
+       p=(char *)str->data;
+       for (j=str->length; j>0; j--)
+               {
+               if ((*p >= ' ') && (*p <= '~'))
+                       BIO_printf(bp,"%c",*p);
+               else if (*p & 0x80)
+                       BIO_printf(bp,"\\0x%02X",*p);
+               else if ((unsigned char)*p == 0xf7)
+                       BIO_printf(bp,"^?");
+               else    BIO_printf(bp,"^%c",*p+'@');
+               p++;
+               }
+       BIO_printf(bp,"'\n");
+       return 1;
+       }