X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=apps%2Fca.c;h=e0a9ef9eae26da0d9ad992720d589fc970d12cf2;hp=3e10d6c275d6d6de23efd50dc730fca4fb84e575;hb=b7a26e6dafdbf97513e968a45757a4d4e9843ba2;hpb=b7896b3cb86d80206af14a14d69b0717786f2729 diff --git a/apps/ca.c b/apps/ca.c index 3e10d6c275..e0a9ef9eae 100644 --- a/apps/ca.c +++ b/apps/ca.c @@ -1,5 +1,5 @@ /* apps/ca.c */ -/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written @@ -61,28 +61,53 @@ #include #include #include +#include #include #include #include "apps.h" -#include "bio.h" -#include "err.h" -#include "bn.h" -#include "txt_db.h" -#include "evp.h" -#include "x509.h" -#include "objects.h" -#include "pem.h" -#include "conf.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef OPENSSL_SYS_WINDOWS +#define strcasecmp _stricmp +#else +#include +#endif + +#ifndef W_OK +# ifdef OPENSSL_SYS_VMS +# if defined(__DECC) +# include +# else +# include +# endif +# else +# include +# endif +#endif #ifndef W_OK -#include +# define F_OK 0 +# define X_OK 1 +# define W_OK 2 +# define R_OK 4 #endif #undef PROG #define PROG ca_main #define BASE_SECTION "ca" -#define CONFIG_FILE "lib/ssleay.cnf" +#define CONFIG_FILE "openssl.cnf" #define ENV_DEFAULT_CA "default_ca" @@ -97,13 +122,19 @@ #define ENV_PRIVATE_KEY "private_key" #define ENV_RANDFILE "RANDFILE" #define ENV_DEFAULT_DAYS "default_days" +#define ENV_DEFAULT_STARTDATE "default_startdate" +#define ENV_DEFAULT_ENDDATE "default_enddate" #define ENV_DEFAULT_CRL_DAYS "default_crl_days" #define ENV_DEFAULT_CRL_HOURS "default_crl_hours" #define ENV_DEFAULT_MD "default_md" #define ENV_PRESERVE "preserve" #define ENV_POLICY "policy" #define ENV_EXTENSIONS "x509_extensions" +#define ENV_CRLEXT "crl_extensions" #define ENV_MSIE_HACK "msie_hack" +#define ENV_NAMEOPT "name_opt" +#define ENV_CERTOPT "cert_opt" +#define ENV_EXTCOPY "copy_extensions" #define ENV_DATABASE "database" @@ -119,6 +150,14 @@ #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", @@ -128,20 +167,32 @@ static char *ca_usage[]={ " -gencrl - Generate a new CRL\n", " -crldays days - Days is when the next CRL is due\n", " -crlhours hours - Hours is when the next CRL is due\n", +" -startdate YYMMDDHHMMSSZ - certificate validity notBefore\n", +" -enddate YYMMDDHHMMSSZ - certificate validity notAfter (overrides -days)\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 - The CA certificate\n", +" -cert file - The CA certificate\n", " -in file - The input PEM encoded certificate request(s)\n", " -out file - Where to put the output file(s)\n", " -outdir dir - Where to put output certificates\n", " -infiles .... - The last argument, requests to process\n", " -spkac file - File contains DN and signed public key and challenge\n", +" -ss_cert file - File contains a self signed cert to sign\n", " -preserveDN - Don't re-order the DN\n", -" -batch - Don't ask questions\n", -" -msie_hack - msie modifications to handle all thos universal strings\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", +" -extfile file - Configuration file with X509v3 extentions to add\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 }; @@ -151,59 +202,68 @@ extern int EF_PROTECT_BELOW; extern int EF_ALIGNMENT; #endif -#ifndef NOPROTO -static STACK *load_extensions(char *section); static void lookup_fail(char *name,char *tag); -static int MS_CALLBACK key_callback(char *buf,int len,int verify); -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_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, - EVP_MD *dgst,STACK *policy,TXT_DB *db,BIGNUM *serial,int days, - int batch, STACK *extensions,int verbose); + const EVP_MD *dgst,STACK_OF(CONF_VALUE) *policy,TXT_DB *db, + BIGNUM *serial, char *subj, char *startdate,char *enddate, + long days, int batch, char *ext_sect, CONF *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, + TXT_DB *db, BIGNUM *serial, char *subj, char *startdate, + char *enddate, long days, int batch, char *ext_sect, + CONF *conf,int verbose, unsigned long certopt, + unsigned long nameopt, int default_op, int ext_copy, + ENGINE *e); static int certify_spkac(X509 **xret, char *infile,EVP_PKEY *pkey,X509 *x509, - EVP_MD *dgst,STACK *policy,TXT_DB *db,BIGNUM *serial,int days, - STACK *extensions,int verbose); + const EVP_MD *dgst,STACK_OF(CONF_VALUE) *policy, + TXT_DB *db, BIGNUM *serial,char *subj, char *startdate, + char *enddate, long days, char *ext_sect,CONF *conf, + 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); -static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, EVP_MD *dgst, - STACK *policy, TXT_DB *db, BIGNUM *serial, int days, int batch, - int verbose, X509_REQ *req, STACK *extensions); +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,char *subj, + char *startdate, char *enddate, long days, int batch, int verbose, + X509_REQ *req, char *ext_sect, CONF *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); -#else -static STACK *load_extensions(); -static void lookup_fail(); -static int MS_CALLBACK key_callback(); -static unsigned long index_serial_hash(); -static int index_serial_cmp(); -static unsigned long index_name_hash(); -static int index_name_qual(); -static int index_name_cmp(); -static int fix_data(); -static BIGNUM *load_serial(); -static int save_serial(); -static int certify(); -static int certify_spkac(); -static void write_new_certificate(); -static int do_body(); -static int check_time_format(); -#endif - -static LHASH *conf; -static char *key=NULL; +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 CONF *conf=NULL; +static CONF *extconf=NULL; static char *section=NULL; static int preserve=0; static int msie_hack=0; -int MAIN(argc, argv) -int argc; -char **argv; +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) { + ENGINE *e = NULL; + char *key=NULL,*passargin=NULL; int total=0; int total_done=0; int badops=0; @@ -211,6 +271,8 @@ char **argv; int req=0; int verbose=0; int gencrl=0; + int dorevoke=0; + int doupdatedb=0; long crldays=0; long crlhours=0; long errorline= -1; @@ -219,17 +281,31 @@ char **argv; 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 *ser_status=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; + int rev_type = REV_NONE; + char *rev_arg = NULL; BIGNUM *serial=NULL; - int days=0; + char *startdate=NULL; + char *enddate=NULL; + long days=0; int batch=0; + int notext=0; + unsigned long nameopt = 0, certopt = 0; + int default_op = 1; + int ext_copy = EXT_COPY_NONE; X509 *x509=NULL; X509 *x=NULL; BIO *in=NULL,*out=NULL,*Sout=NULL,*Cout=NULL; @@ -241,14 +317,14 @@ char **argv; char **pp,*p,*f; int i,j; long l; - EVP_MD *dgst=NULL; - STACK *attribs=NULL; - STACK *extensions_sk=NULL; - STACK *cert_sk=NULL; - BIO *hex=NULL; + const EVP_MD *dgst=NULL; + STACK_OF(CONF_VALUE) *attribs=NULL; + STACK_OF(X509) *cert_sk=NULL; #undef BSIZE #define BSIZE 256 MS_STATIC char buf[3][BSIZE]; + char *randfile=NULL; + char *engine = NULL; #ifdef EFENCE EF_PROTECT_FREE=1; @@ -258,12 +334,15 @@ EF_ALIGNMENT=0; apps_startup(); - X509v3_add_netscape_extensions(); + conf = NULL; + key = NULL; + section = NULL; preserve=0; + msie_hack=0; if (bio_err == NULL) if ((bio_err=BIO_new(BIO_s_file())) != NULL) - BIO_set_fp(bio_err,stderr,BIO_NOCLOSE); + BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT); argc--; argv++; @@ -281,6 +360,22 @@ EF_ALIGNMENT=0; 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; + startdate= *(++argv); + } + else if (strcmp(*argv,"-enddate") == 0) + { + if (--argc < 1) goto bad; + enddate= *(++argv); + } else if (strcmp(*argv,"-days") == 0) { if (--argc < 1) goto bad; @@ -301,6 +396,16 @@ EF_ALIGNMENT=0; 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; @@ -327,6 +432,8 @@ EF_ALIGNMENT=0; if (--argc < 1) goto bad; outdir= *(++argv); } + else if (strcmp(*argv,"-notext") == 0) + notext=1; else if (strcmp(*argv,"-batch") == 0) batch=1; else if (strcmp(*argv,"-preserveDN") == 0) @@ -352,12 +459,77 @@ EF_ALIGNMENT=0; req=1; break; } + else if (strcmp(*argv, "-ss_cert") == 0) + { + if (--argc < 1) goto bad; + ss_cert_file = *(++argv); + req=1; + } else if (strcmp(*argv, "-spkac") == 0) { if (--argc < 1) goto bad; spkac_file = *(++argv); req=1; } + else if (strcmp(*argv,"-revoke") == 0) + { + if (--argc < 1) goto bad; + infile= *(++argv); + dorevoke=1; + } + else if (strcmp(*argv,"-extensions") == 0) + { + 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,"-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: @@ -372,25 +544,35 @@ bad: 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(); + e = setup_engine(bio_err, engine, 0); + /*****************************************************************/ + 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 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])-2-sizeof(CONFIG_FILE)); strcat(buf[0],"/"); +#endif strcat(buf[0],CONFIG_FILE); configfile=buf[0]; } BIO_printf(bio_err,"Using configuration from %s\n",configfile); - if ((conf=CONF_load(NULL,configfile,&errorline)) == NULL) + conf = NCONF_new(NULL); + if (NCONF_load(conf,configfile,&errorline) <= 0) { if (errorline <= 0) BIO_printf(bio_err,"error loading the config file '%s'\n", @@ -404,7 +586,7 @@ bad: /* Lets get the config section we are using */ if (section == NULL) { - section=CONF_get_string(conf,BASE_SECTION,ENV_DEFAULT_CA); + section=NCONF_get_string(conf,BASE_SECTION,ENV_DEFAULT_CA); if (section == NULL) { lookup_fail(BASE_SECTION,ENV_DEFAULT_CA); @@ -412,6 +594,42 @@ bad: } } + if (conf != NULL) + { + p=NCONF_get_string(conf,NULL,"oid_file"); + if (p == NULL) + ERR_clear_error(); + if (p != NULL) + { + BIO *oid_bio; + + oid_bio=BIO_new_file(p,"r"); + if (oid_bio == NULL) + { + /* + BIO_printf(bio_err,"problems opening %s for extra oid's\n",p); + ERR_print_errors(bio_err); + */ + ERR_clear_error(); + } + else + { + OBJ_create_objects(oid_bio); + BIO_free(oid_bio); + } + } + if (!add_oid_section(bio_err,conf)) + { + ERR_print_errors(bio_err); + goto err; + } + } + + randfile = NCONF_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()); out=BIO_new(BIO_s_file()); Sout=BIO_new(BIO_s_file()); @@ -423,76 +641,159 @@ bad: } /*****************************************************************/ - /* we definitly need an public key, so lets get it */ + /* report status of cert with serial number given on command line */ + if (ser_status) + { + if ((dbfile=NCONF_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, + if ((keyfile == NULL) && ((keyfile=NCONF_get_string(conf, section,ENV_PRIVATE_KEY)) == NULL)) { 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; } - if (key == NULL) - pkey=PEM_read_bio_PrivateKey(in,NULL,NULL); - else - { - pkey=PEM_read_bio_PrivateKey(in,NULL,key_callback); - memset(key,0,strlen(key)); - } + pkey = load_key(bio_err, keyfile, keyform, key, e, + "CA private key"); + if (key) memset(key,0,strlen(key)); if (pkey == NULL) { - BIO_printf(bio_err,"unable to load CA private key\n"); + /* load_key() has already printed an appropriate message */ goto err; } /*****************************************************************/ /* we need a certificate */ - if ((certfile == NULL) && ((certfile=CONF_get_string(conf, + if ((certfile == NULL) && ((certfile=NCONF_get_string(conf, section,ENV_CERTIFICATE)) == NULL)) { lookup_fail(section,ENV_CERTIFICATE); goto err; } - if (BIO_read_filename(in,certfile) <= 0) - { - perror(certfile); - BIO_printf(bio_err,"trying to load CA certificate\n"); - goto err; - } - x509=PEM_read_bio_X509(in,NULL,NULL); + x509=load_cert(bio_err, certfile, FORMAT_PEM, NULL, e, + "CA certificate"); if (x509 == NULL) + goto err; + + if (!X509_check_private_key(x509,pkey)) { - BIO_printf(bio_err,"unable to load CA certificate\n"); + BIO_printf(bio_err,"CA certificate and CA private key do not match\n"); goto err; } - f=CONF_get_string(conf,BASE_SECTION,ENV_PRESERVE); + f=NCONF_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); + f=NCONF_get_string(conf,BASE_SECTION,ENV_MSIE_HACK); + if (f == NULL) + ERR_clear_error(); if ((f != NULL) && ((*f == 'y') || (*f == 'Y'))) msie_hack=1; + f=NCONF_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=NCONF_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(); + + f=NCONF_get_string(conf,section,ENV_EXTCOPY); + + if (f) + { + if (!set_ext_copy(&ext_copy, f)) + { + BIO_printf(bio_err, "Invalid extension copy option: \"%s\"\n", f); + goto err; + } + } + else + ERR_clear_error(); + /*****************************************************************/ /* lookup where to write new certificates */ if ((outdir == NULL) && (req)) { struct stat sb; - if ((outdir=CONF_get_string(conf,section,ENV_NEW_CERTS_DIR)) + if ((outdir=NCONF_get_string(conf,section,ENV_NEW_CERTS_DIR)) == NULL) { BIO_printf(bio_err,"there needs to be defined a directory for new certificate to be placed in\n"); goto err; } +#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. + + Presumably, this problem could also be solved by using the DEC + 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 acces the %s directory\n",outdir); + BIO_printf(bio_err,"I am unable to access the %s directory\n",outdir); perror(outdir); goto err; } @@ -503,22 +804,25 @@ bad: perror(outdir); goto err; } +#ifdef S_IFDIR if (!(sb.st_mode & S_IFDIR)) { BIO_printf(bio_err,"%s need to be a directory\n",outdir); perror(outdir); goto err; } +#endif +#endif } /*****************************************************************/ /* we need to load the database file */ - if ((dbfile=CONF_get_string(conf,section,ENV_DATABASE)) == NULL) + if ((dbfile=NCONF_get_string(conf,section,ENV_DATABASE)) == NULL) { lookup_fail(section,ENV_DATABASE); goto err; } - if (BIO_read_filename(in,dbfile) <= 0) + if (BIO_read_filename(in,dbfile) <= 0) { perror(dbfile); BIO_printf(bio_err,"unable to open '%s'\n",dbfile); @@ -534,14 +838,13 @@ bad: if ((pp[DB_type][0] != DB_TYPE_REV) && (pp[DB_rev_date][0] != '\0')) { - BIO_printf(bio_err,"entry %d: not, revoked yet has a revokation date\n",i+1); + BIO_printf(bio_err,"entry %d: not revoked yet, but has a revocation date\n",i+1); goto err; } if ((pp[DB_type][0] == DB_TYPE_REV) && - !check_time_format(pp[DB_rev_date])) + !make_revoked(NULL, pp[DB_rev_date])) { - BIO_printf(bio_err,"entry %d: invalid revokation date\n", - i+1); + BIO_printf(bio_err," in entry %d\n", i+1); goto err; } if (!check_time_format(pp[DB_exp_date])) @@ -551,6 +854,11 @@ bad: } 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); @@ -570,34 +878,150 @@ bad: } if (verbose) { - BIO_set_fp(out,stdout,BIO_NOCLOSE); /* cannot fail */ + 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 indexs\n"); + 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; } - 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; } + /*****************************************************************/ + /* 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; + } + +#ifndef OPENSSL_SYS_VMS + j = BIO_snprintf(buf[0], sizeof buf[0], "%s.new", dbfile); +#else + j = BIO_snprintf(buf[0], sizeof buf[0], "%s-new", dbfile); +#endif + 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; +#ifndef OPENSSL_SYS_VMS + j = BIO_snprintf(buf[1], sizeof buf[1], "%s.old", dbfile); +#else + j = BIO_snprintf(buf[1], sizeof buf[1], "%s-old", dbfile); +#endif + 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) + { + extconf = NCONF_new(NULL); + if (NCONF_load(extconf,extfile,&errorline) <= 0) + { + 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 = NCONF_get_string(extconf, "default", "extensions"))) + extensions = "default"; + } + /*****************************************************************/ if (req || gencrl) { if (outfile != NULL) { - if (BIO_write_filename(Sout,outfile) <= 0) { perror(outfile); @@ -605,12 +1029,20 @@ bad: } } else - BIO_set_fp(Sout,stdout,BIO_NOCLOSE); + { + 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 ((md == NULL) && ((md=CONF_get_string(conf, + if ((md == NULL) && ((md=NCONF_get_string(conf, section,ENV_DEFAULT_MD)) == NULL)) { lookup_fail(section,ENV_DEFAULT_MD); @@ -624,7 +1056,7 @@ bad: if (verbose) BIO_printf(bio_err,"message digest is %s\n", OBJ_nid2ln(dgst->type)); - if ((policy == NULL) && ((policy=CONF_get_string(conf, + if ((policy == NULL) && ((policy=NCONF_get_string(conf, section,ENV_POLICY)) == NULL)) { lookup_fail(section,ENV_POLICY); @@ -633,26 +1065,75 @@ bad: if (verbose) BIO_printf(bio_err,"policy is %s\n",policy); - if ((serialfile=CONF_get_string(conf,section,ENV_SERIAL)) + if ((serialfile=NCONF_get_string(conf,section,ENV_SERIAL)) == NULL) { lookup_fail(section,ENV_SERIAL); goto err; } - if ((extensions=CONF_get_string(conf,section,ENV_EXTENSIONS)) - != NULL) + if (!extconf) { - if ((extensions_sk=load_extensions(extensions)) == NULL) - goto err; + /* no '-extfile' option, so we look for extensions + * in the main configuration file */ + if (!extensions) + { + extensions=NCONF_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_nconf(&ctx, conf); + if (!X509V3_EXT_add_nconf(conf, &ctx, extensions, + NULL)) + { + BIO_printf(bio_err, + "Error Loading extension section %s\n", + extensions); + ret = 1; + goto err; + } + } } - if (days == 0) + if (startdate == NULL) + { + startdate=NCONF_get_string(conf,section, + ENV_DEFAULT_STARTDATE); + if (startdate == NULL) + ERR_clear_error(); + } + if (startdate && !ASN1_UTCTIME_set_string(NULL,startdate)) + { + BIO_printf(bio_err,"start date is invalid, it should be YYMMDDHHMMSSZ\n"); + goto err; + } + if (startdate == NULL) startdate="today"; + + if (enddate == NULL) + { + enddate=NCONF_get_string(conf,section, + ENV_DEFAULT_ENDDATE); + if (enddate == NULL) + ERR_clear_error(); + } + if (enddate && !ASN1_UTCTIME_set_string(NULL,enddate)) { - days=(int)CONF_get_number(conf,section, - ENV_DEFAULT_DAYS); + BIO_printf(bio_err,"end date is invalid, it should be YYMMDDHHMMSSZ\n"); + goto err; } + if (days == 0) + { + if(!NCONF_get_number(conf,section, ENV_DEFAULT_DAYS, &days)) + days = 0; + } + if (!enddate && (days == 0)) { BIO_printf(bio_err,"cannot lookup how many days to certify for\n"); goto err; @@ -665,36 +1146,37 @@ bad: } if (verbose) { - if ((f=BN_bn2ascii(serial)) == NULL) goto err; + if ((f=BN_bn2hex(serial)) == NULL) goto err; BIO_printf(bio_err,"next serial number is %s\n",f); - Free(f); + OPENSSL_free(f); } - if ((attribs=CONF_get_section(conf,policy)) == NULL) + if ((attribs=NCONF_get_section(conf,policy)) == NULL) { BIO_printf(bio_err,"unable to find 'section' for %s\n",policy); goto err; } - if ((cert_sk=sk_new_null()) == NULL) + if ((cert_sk=sk_X509_new_null()) == NULL) { - BIO_printf(bio_err,"Malloc failure\n"); + BIO_printf(bio_err,"Memory allocation failure\n"); goto err; } if (spkac_file != NULL) { total++; j=certify_spkac(&x,spkac_file,pkey,x509,dgst,attribs,db, - serial,days,extensions_sk,verbose); + serial,subj,startdate,enddate, days,extensions,conf, + verbose, certopt, nameopt, default_op, ext_copy); if (j < 0) goto err; if (j > 0) { total_done++; BIO_printf(bio_err,"\n"); if (!BN_add_word(serial,1)) goto err; - if (!sk_push(cert_sk,(char *)x)) + if (!sk_X509_push(cert_sk,x)) { - BIO_printf(bio_err,"Malloc failure\n"); + BIO_printf(bio_err,"Memory allocation failure\n"); goto err; } if (outfile) @@ -704,20 +1186,42 @@ bad: } } } + if (ss_cert_file != NULL) + { + total++; + j=certify_cert(&x,ss_cert_file,pkey,x509,dgst,attribs, + db,serial,subj,startdate,enddate,days,batch, + extensions,conf,verbose, certopt, nameopt, + default_op, ext_copy, e); + if (j < 0) goto err; + if (j > 0) + { + total_done++; + BIO_printf(bio_err,"\n"); + if (!BN_add_word(serial,1)) goto err; + if (!sk_X509_push(cert_sk,x)) + { + BIO_printf(bio_err,"Memory allocation failure\n"); + goto err; + } + } + } if (infile != NULL) { total++; j=certify(&x,infile,pkey,x509,dgst,attribs,db, - serial,days,batch,extensions_sk,verbose); + serial,subj,startdate,enddate,days,batch, + extensions,conf,verbose, certopt, nameopt, + default_op, ext_copy); if (j < 0) goto err; if (j > 0) { total_done++; BIO_printf(bio_err,"\n"); if (!BN_add_word(serial,1)) goto err; - if (!sk_push(cert_sk,(char *)x)) + if (!sk_X509_push(cert_sk,x)) { - BIO_printf(bio_err,"Malloc failure\n"); + BIO_printf(bio_err,"Memory allocation failure\n"); goto err; } } @@ -726,16 +1230,18 @@ bad: { total++; j=certify(&x,argv[i],pkey,x509,dgst,attribs,db, - serial,days,batch,extensions_sk,verbose); + serial,subj,startdate,enddate,days,batch, + extensions,conf,verbose, certopt, nameopt, + default_op, ext_copy); if (j < 0) goto err; if (j > 0) { total_done++; BIO_printf(bio_err,"\n"); if (!BN_add_word(serial,1)) goto err; - if (!sk_push(cert_sk,(char *)x)) + if (!sk_X509_push(cert_sk,x)) { - BIO_printf(bio_err,"Malloc failure\n"); + BIO_printf(bio_err,"Memory allocation failure\n"); goto err; } } @@ -744,12 +1250,12 @@ bad: * and a data base and serial number that need * updating */ - if (sk_num(cert_sk) > 0) + if (sk_X509_num(cert_sk) > 0) { if (!batch) { BIO_printf(bio_err,"\n%d out of %d certificate requests certified, commit? [y/n]",total_done,total); - BIO_flush(bio_err); + (void)BIO_flush(bio_err); buf[0][0]='\0'; fgets(buf[0],10,stdin); if ((buf[0][0] != 'y') && (buf[0][0] != 'Y')) @@ -760,15 +1266,26 @@ bad: } } - BIO_printf(bio_err,"Write out database with %d new entries\n",sk_num(cert_sk)); + BIO_printf(bio_err,"Write out database with %d new entries\n",sk_X509_num(cert_sk)); strncpy(buf[0],serialfile,BSIZE-4); + +#ifdef OPENSSL_SYS_VMS + strcat(buf[0],"-new"); +#else strcat(buf[0],".new"); +#endif if (!save_serial(buf[0],serial)) goto err; strncpy(buf[1],dbfile,BSIZE-4); + +#ifdef OPENSSL_SYS_VMS + strcat(buf[1],"-new"); +#else strcat(buf[1],".new"); +#endif + if (BIO_write_filename(out,buf[1]) <= 0) { perror(dbfile); @@ -781,24 +1298,28 @@ bad: if (verbose) BIO_printf(bio_err,"writing new certificates\n"); - for (i=0; icert_info->serialNumber->length; p=(char *)x->cert_info->serialNumber->data; strncpy(buf[2],outdir,BSIZE-(j*2)-6); + +#ifndef OPENSSL_SYS_VMS strcat(buf[2],"/"); +#endif + n=(unsigned char *)&(buf[2][strlen(buf[2])]); if (j > 0) { for (k=0; kissuer == NULL) goto err; X509_gmtime_adj(ci->lastUpdate,0); + if (ci->nextUpdate == NULL) + ci->nextUpdate=ASN1_UTCTIME_new(); X509_gmtime_adj(ci->nextUpdate,(crldays*24+crlhours)*60*60); for (i=0; idata); i++) @@ -901,31 +1459,29 @@ bad: 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]);*/ - - 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; - if (!a2i_ASN1_INTEGER(hex,r->serialNumber, - buf[0],BSIZE)) goto err; - - sk_push(ci->revoked,(char *)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 * number order */ - sk_find(ci->revoked,NULL); - for (i=0; irevoked); i++) + sk_X509_REVOKED_sort(ci->revoked); + for (i=0; irevoked); i++) { - r=(X509_REVOKED *)sk_value(ci->revoked,i); + r=sk_X509_REVOKED_value(ci->revoked,i); r->sequence=i; } - /* we how have a CRL */ + /* we now have a CRL */ if (verbose) BIO_printf(bio_err,"signing CRL\n"); if (md != NULL) { @@ -936,91 +1492,151 @@ bad: } } else - dgst=EVP_md5(); - if (!X509_CRL_sign(crl,pkey,dgst)) goto err; + { +#ifndef OPENSSL_NO_DSA + if (pkey->type == EVP_PKEY_DSA) + dgst=EVP_dss1(); + else +#endif + dgst=EVP_md5(); + } - PEM_write_bio_X509_CRL(Sout,crl); + /* Add any extensions asked for */ + + 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_nconf(&crlctx, conf); + + if (!X509V3_EXT_CRL_add_nconf(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; + + PEM_write_bio_X509_CRL(Sout,crl); + } + /*****************************************************************/ + if (dorevoke) + { + if (infile == NULL) + { + BIO_printf(bio_err,"no input files\n"); + goto err; + } + else + { + X509 *revcert; + revcert=load_cert(bio_err, infile, FORMAT_PEM, + NULL, e, infile); + if (revcert == NULL) + goto err; + j=do_revoke(revcert,db, rev_type, rev_arg); + if (j <= 0) goto err; + X509_free(revcert); + + strncpy(buf[0],dbfile,BSIZE-4); +#ifndef OPENSSL_SYS_VMS + strcat(buf[0],".new"); +#else + strcat(buf[0],"-new"); +#endif + 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; + strncpy(buf[1],dbfile,BSIZE-4); +#ifndef OPENSSL_SYS_VMS + strcat(buf[1],".old"); +#else + strcat(buf[1],"-old"); +#endif + if (rename(dbfile,buf[1]) < 0) + { + BIO_printf(bio_err,"unable to rename %s to %s\n", dbfile, buf[1]); + perror("reason"); + goto err; + } + if (rename(buf[0],dbfile) < 0) + { + BIO_printf(bio_err,"unable to rename %s to %s\n", buf[0],dbfile); + perror("reason"); + rename(buf[1],dbfile); + goto err; + } + BIO_printf(bio_err,"Data Base Updated\n"); + } } /*****************************************************************/ ret=0; err: - if (hex != NULL) BIO_free(hex); - if (Cout != NULL) BIO_free(Cout); - if (Sout != NULL) BIO_free(Sout); - if (out != NULL) BIO_free(out); - if (in != NULL) BIO_free(in); + BIO_free_all(Cout); + BIO_free_all(Sout); + BIO_free_all(out); + BIO_free_all(in); - if (cert_sk != NULL) sk_pop_free(cert_sk,X509_free); - if (extensions_sk != NULL) - sk_pop_free(extensions_sk,X509_EXTENSION_free); + sk_X509_pop_free(cert_sk,X509_free); if (ret) ERR_print_errors(bio_err); - if (serial != NULL) BN_free(serial); - if (db != NULL) TXT_DB_free(db); - if (pkey != NULL) EVP_PKEY_free(pkey); - if (x509 != NULL) X509_free(x509); - if (crl != NULL) X509_CRL_free(crl); - if (conf != NULL) CONF_free(conf); - X509v3_cleanup_extensions(); + app_RAND_write_file(randfile, bio_err); + BN_free(serial); + TXT_DB_free(db); + EVP_PKEY_free(pkey); + X509_free(x509); + X509_CRL_free(crl); + NCONF_free(conf); + OBJ_cleanup(); + apps_shutdown(); EXIT(ret); } -static void lookup_fail(name,tag) -char *name; -char *tag; +static void lookup_fail(char *name, char *tag) { BIO_printf(bio_err,"variable lookup failed for %s::%s\n",name,tag); } -static int MS_CALLBACK key_callback(buf,len,verify) -char *buf; -int len,verify; - { - int i; - - if (key == NULL) return(0); - i=strlen(key); - i=(i > len)?len:i; - memcpy(buf,key,i); - return(i); - } - -static unsigned long index_serial_hash(a) -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)); } -static int index_serial_cmp(a,b) -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)); } -static unsigned long index_name_hash(a) -char **a; +static unsigned long index_name_hash(const char **a) { return(lh_strhash(a[DB_name])); } -static int index_name_qual(a) -char **a; +static int index_name_qual(char **a) { return(a[0][0] == 'V'); } -static int index_name_cmp(a,b) -char **a; -char **b; - { return(strcmp(a[DB_name],b[DB_name])); } +static int index_name_cmp(const char **a, const char **b) + { return(strcmp(a[DB_name], + b[DB_name])); } -static BIGNUM *load_serial(serialfile) -char *serialfile; +static BIGNUM *load_serial(char *serialfile) { BIO *in=NULL; BIGNUM *ret=NULL; @@ -1058,9 +1674,7 @@ err: return(ret); } -static int save_serial(serialfile,serial) -char *serialfile; -BIGNUM *serial; +static int save_serial(char *serialfile, BIGNUM *serial) { BIO *out; int ret=0; @@ -1087,25 +1701,17 @@ BIGNUM *serial; 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(xret,infile,pkey,x509,dgst,policy,db,serial,days, - batch,extensions,verbose) -X509 **xret; -char *infile; -EVP_PKEY *pkey; -X509 *x509; -EVP_MD *dgst; -STACK *policy; -TXT_DB *db; -BIGNUM *serial; -int days; -int batch; -STACK *extensions; -int verbose; +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 *subj, char *startdate, char *enddate, long days, + int batch, char *ext_sect, CONF *lconf, int verbose, + unsigned long certopt, unsigned long nameopt, int default_op, + int ext_copy) { X509_REQ *req=NULL; BIO *in=NULL; @@ -1119,7 +1725,7 @@ int verbose; perror(infile); goto err; } - if ((req=PEM_read_bio_X509_REQ(in,NULL,NULL)) == NULL) + if ((req=PEM_read_bio_X509_REQ(in,NULL,NULL,NULL)) == NULL) { BIO_printf(bio_err,"Error reading certificate request in %s\n", infile); @@ -1130,21 +1736,13 @@ int verbose; BIO_printf(bio_err,"Check that the request matches the signature\n"); - if ( (req->req_info == NULL) || - (req->req_info->pubkey == NULL) || - (req->req_info->pubkey->public_key == NULL) || - (req->req_info->pubkey->public_key->data == NULL)) - { - BIO_printf(bio_err,"The certificate request appears to corrupted\n"); - BIO_printf(bio_err,"It does not contain a public key\n"); - goto err; - } if ((pktmp=X509_REQ_get_pubkey(req)) == NULL) { BIO_printf(bio_err,"error unpacking public key\n"); goto err; } i=X509_REQ_verify(req,pktmp); + EVP_PKEY_free(pktmp); if (i < 0) { ok=0; @@ -1160,8 +1758,9 @@ int verbose; else BIO_printf(bio_err,"Signature ok\n"); - ok=do_body(xret,pkey,x509,dgst,policy,db,serial,days,batch,verbose,req, - extensions); + 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); @@ -1169,54 +1768,114 @@ err: return(ok); } -static int do_body(xret,pkey,x509,dgst,policy,db,serial,days,batch,verbose,req, - extensions) -X509 **xret; -EVP_PKEY *pkey; -X509 *x509; -EVP_MD *dgst; -STACK *policy; -TXT_DB *db; -BIGNUM *serial; -int days; -int batch; -int verbose; -X509_REQ *req; -STACK *extensions; +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 *subj, char *startdate, char *enddate, long days, + int batch, char *ext_sect, CONF *lconf, int verbose, + unsigned long certopt, unsigned long nameopt, int default_op, + int ext_copy, ENGINE *e) + { + X509 *req=NULL; + X509_REQ *rreq=NULL; + EVP_PKEY *pktmp=NULL; + int ok= -1,i; + + if ((req=load_cert(bio_err, infile, FORMAT_PEM, NULL, e, infile)) == NULL) + goto err; + if (verbose) + X509_print(bio_err,req); + + BIO_printf(bio_err,"Check that the request matches the signature\n"); + + if ((pktmp=X509_get_pubkey(req)) == NULL) + { + BIO_printf(bio_err,"error unpacking public key\n"); + goto err; + } + i=X509_verify(req,pktmp); + EVP_PKEY_free(pktmp); + if (i < 0) + { + ok=0; + BIO_printf(bio_err,"Signature verification problems....\n"); + goto err; + } + if (i == 0) + { + ok=0; + BIO_printf(bio_err,"Signature did not match the certificate\n"); + goto err; + } + else + BIO_printf(bio_err,"Signature ok\n"); + + if ((rreq=X509_to_X509_REQ(req,NULL,EVP_md5())) == NULL) + goto err; + + 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); + if (req != NULL) X509_free(req); + return(ok); + } + +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, char *subj, + char *startdate, char *enddate, long days, int batch, int verbose, + X509_REQ *req, char *ext_sect, CONF *lconf, + unsigned long certopt, unsigned long nameopt, int default_op, + int ext_copy) { X509_NAME *name=NULL,*CAname=NULL,*subject=NULL; - ASN1_UTCTIME *tm; + ASN1_UTCTIME *tm,*tmptm; ASN1_STRING *str,*str2; ASN1_OBJECT *obj; X509 *ret=NULL; X509_CINF *ci; X509_NAME_ENTRY *ne; X509_NAME_ENTRY *tne,*push; - X509_EXTENSION *ex=NULL; EVP_PKEY *pktmp; int ok= -1,i,j,last,nid; 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) + { + BIO_printf(bio_err,"malloc error\n"); + return(0); + } for (i=0; ireq_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; i0; j--) - *(pbuf++)=' '; - *(pbuf++)=':'; - *(pbuf++)='\0'; - BIO_puts(bio_err,buf); + obj=X509_NAME_ENTRY_get_object(ne); if (msie_hack) { @@ -1235,17 +1894,6 @@ STACK *extensions; 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)) @@ -1262,26 +1910,15 @@ STACK *extensions; BIO_printf(bio_err,"\nThe string contains characters that are illegal for the ASN.1 type\n"); goto err; } - - p=(char *)str->data; - for (j=str->length; j>0; j--) - { - if ((*p >= ' ') && (*p <= '~')) - BIO_printf(bio_err,"%c",*p); - else if (*p & 0x80) - BIO_printf(bio_err,"\\0x%02X",*p); - else if ((unsigned char)*p == 0xf7) - BIO_printf(bio_err,"^?"); - else BIO_printf(bio_err,"^%c",*p+'@'); - p++; - } - BIO_printf(bio_err,"'\n"); + + if (default_op) + old_entry_print(bio_err, obj, str); } /* Ok, now we check the 'policy' stuff. */ if ((subject=X509_NAME_new()) == NULL) { - BIO_printf(bio_err,"Malloc failure\n"); + BIO_printf(bio_err,"Memory allocation failure\n"); goto err; } @@ -1290,9 +1927,9 @@ STACK *extensions; if (CAname == NULL) goto err; str=str2=NULL; - for (i=0; iname)) == NID_undef) { BIO_printf(bio_err,"%s:unknown object type in 'policy' configuration\n",cv->name); @@ -1363,7 +2000,7 @@ again2: } if (j < 0) { - BIO_printf(bio_err,"The %s field needed to be the same in the\nCA certificate (%s) and the request (%s)\n",cv->name,((str == NULL)?"NULL":(char *)str->data),((str2 == NULL)?"NULL":(char *)str2->data)); + BIO_printf(bio_err,"The %s field needed to be the same in the\nCA certificate (%s) and the request (%s)\n",cv->name,((str2 == NULL)?"NULL":(char *)str2->data),((str == NULL)?"NULL":(char *)str->data)); goto err; } } @@ -1375,12 +2012,11 @@ again2: if (push != NULL) { - if (!X509_NAME_add_entry(subject,push, - X509_NAME_entry_count(subject),0)) + if (!X509_NAME_add_entry(subject,push, -1, 0)) { if (push != NULL) X509_NAME_ENTRY_free(push); - BIO_printf(bio_err,"Malloc failure\n"); + BIO_printf(bio_err,"Memory allocation failure\n"); goto err; } } @@ -1396,13 +2032,13 @@ again2: } if (verbose) - BIO_printf(bio_err,"The subject name apears to be ok, checking data base for clashes\n"); + BIO_printf(bio_err,"The subject name appears to be ok, checking data base for clashes\n"); row[DB_name]=X509_NAME_oneline(subject,NULL,0); - row[DB_serial]=BN_bn2ascii(serial); + row[DB_serial]=BN_bn2hex(serial); if ((row[DB_name] == NULL) || (row[DB_serial] == NULL)) { - BIO_printf(bio_err,"Malloc failure\n"); + BIO_printf(bio_err,"Memory allocation failure\n"); goto err; } @@ -1435,7 +2071,7 @@ again2: p="Valid"; else p="\ninvalid type, Data base error\n"; - BIO_printf(bio_err,"Type :%s\n",p);; + BIO_printf(bio_err,"Type :%s\n",p);; if (rrow[DB_type][0] == 'R') { p=rrow[DB_exp_date]; if (p == NULL) p="undef"; @@ -1453,7 +2089,7 @@ again2: goto err; } - /* We are now totaly happy, lets make and sign the certificate */ + /* We are now totally happy, lets make and sign the certificate */ if (verbose) BIO_printf(bio_err,"Everything appears to be ok, creating and signing the certificate\n"); @@ -1470,48 +2106,109 @@ again2: if (!X509_set_issuer_name(ret,X509_get_subject_name(x509))) goto err; - BIO_printf(bio_err,"Certificate is to be certified until "); - X509_gmtime_adj(X509_get_notBefore(ret),0); - X509_gmtime_adj(X509_get_notAfter(ret),(long)60*60*24*days); - ASN1_UTCTIME_print(bio_err,X509_get_notAfter(ret)); - BIO_printf(bio_err," (%d days)\n",days); + if (strcmp(startdate,"today") == 0) + X509_gmtime_adj(X509_get_notBefore(ret),0); + else ASN1_UTCTIME_set_string(X509_get_notBefore(ret),startdate); + + if (enddate == NULL) + X509_gmtime_adj(X509_get_notAfter(ret),(long)60*60*24*days); + else ASN1_UTCTIME_set_string(X509_get_notAfter(ret),enddate); if (!X509_set_subject_name(ret,subject)) goto err; pktmp=X509_REQ_get_pubkey(req); - if (!X509_set_pubkey(ret,pktmp)) goto err; + i = X509_set_pubkey(ret,pktmp); + EVP_PKEY_free(pktmp); + if (!i) goto err; /* Lets add the extensions, if there are any */ - if ((extensions != NULL) && (sk_num(extensions) > 0)) + if (ext_sect) { + X509V3_CTX ctx; if (ci->version == NULL) if ((ci->version=ASN1_INTEGER_new()) == NULL) goto err; ASN1_INTEGER_set(ci->version,2); /* version 3 certificate */ /* Free the current entries if any, there should not - * be any I belive */ + * be any I believe */ if (ci->extensions != NULL) - sk_pop_free(ci->extensions,X509_EXTENSION_free); + sk_X509_EXTENSION_pop_free(ci->extensions, + X509_EXTENSION_free); - if ((ci->extensions=sk_new_null()) == NULL) - goto err; + ci->extensions = NULL; + + /* Initialize the context structure */ + X509V3_set_ctx(&ctx, x509, ret, req, NULL, 0); - /* Lets 'copy' in the new ones */ - for (i=0; iextensions,(char *)ex)) goto err; + if (verbose) + BIO_printf(bio_err, "Extra configuration file found\n"); + + /* Use the extconf configuration db LHASH */ + X509V3_set_nconf(&ctx, extconf); + + /* Test the structure (needed?) */ + /* X509V3_set_ctx_test(&ctx); */ + + /* Adds exts contained in the configuration file */ + if (!X509V3_EXT_add_nconf(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_nconf(&ctx, lconf); + + if(!X509V3_EXT_add_nconf(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"); } } + /* Copy extensions from request (if any) */ + + if (!copy_extensions(ret, req, ext_copy)) + { + BIO_printf(bio_err, "ERROR: adding extensions from request\n"); + ERR_print_errors(bio_err); + goto err; + } + + + 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,"Certificate is to be certified until "); + ASN1_UTCTIME_print(bio_err,X509_get_notAfter(ret)); + if (days) BIO_printf(bio_err," (%d days)",days); + BIO_printf(bio_err, "\n"); if (!batch) { + BIO_printf(bio_err,"Sign the certificate? [y/n]:"); - BIO_flush(bio_err); + (void)BIO_flush(bio_err); buf[0]='\0'; fgets(buf,sizeof(buf)-1,stdin); if (!((buf[0] == 'y') || (buf[0] == 'Y'))) @@ -1522,43 +2219,46 @@ again2: } } -#ifndef NO_DSA - pktmp=X509_get_pubkey(ret); - if (EVP_PKEY_missing_parameters(pktmp) && + +#ifndef OPENSSL_NO_DSA + if (pkey->type == EVP_PKEY_DSA) dgst=EVP_dss1(); + pktmp=X509_get_pubkey(ret); + if (EVP_PKEY_missing_parameters(pktmp) && !EVP_PKEY_missing_parameters(pkey)) EVP_PKEY_copy_parameters(pktmp,pkey); + EVP_PKEY_free(pktmp); #endif if (!X509_sign(ret,pkey,dgst)) goto err; /* We now just add it to the database */ - row[DB_type]=(char *)Malloc(2); + row[DB_type]=(char *)OPENSSL_malloc(2); tm=X509_get_notAfter(ret); - row[DB_exp_date]=(char *)Malloc(tm->length+1); + row[DB_exp_date]=(char *)OPENSSL_malloc(tm->length+1); memcpy(row[DB_exp_date],tm->data,tm->length); row[DB_exp_date][tm->length]='\0'; row[DB_rev_date]=NULL; /* row[DB_serial] done already */ - row[DB_file]=(char *)Malloc(8); + row[DB_file]=(char *)OPENSSL_malloc(8); /* row[DB_name] done already */ if ((row[DB_type] == NULL) || (row[DB_exp_date] == NULL) || (row[DB_file] == NULL)) { - BIO_printf(bio_err,"Malloc failure\n"); + BIO_printf(bio_err,"Memory allocation failure\n"); goto err; } strcpy(row[DB_file],"unknown"); row[DB_type][0]='V'; row[DB_type][1]='\0'; - if ((irow=(char **)Malloc(sizeof(char *)*(DB_NUMBER+1))) == NULL) + if ((irow=(char **)OPENSSL_malloc(sizeof(char *)*(DB_NUMBER+1))) == NULL) { - BIO_printf(bio_err,"Malloc failure\n"); + BIO_printf(bio_err,"Memory allocation failure\n"); goto err; } @@ -1578,12 +2278,14 @@ again2: ok=1; err: for (i=0; icert_info->serialNumber); BIO_puts(bp,"\n\n"); - X509_print(bp,x); - BIO_puts(bp,"\n"); +#endif + if (!notext)X509_print(bp,x); PEM_write_bio_X509(bp,x); - BIO_puts(bp,"\n"); } -static int certify_spkac(xret,infile,pkey,x509,dgst,policy,db,serial,days, - extensions,verbose) -X509 **xret; -char *infile; -EVP_PKEY *pkey; -X509 *x509; -EVP_MD *dgst; -STACK *policy; -TXT_DB *db; -BIGNUM *serial; -int days; -STACK *extensions; -int verbose; +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 *subj, char *startdate, char *enddate, long days, + char *ext_sect, CONF *lconf, int verbose, unsigned long certopt, + unsigned long nameopt, int default_op, int ext_copy) { - STACK *sk=NULL; + STACK_OF(CONF_VALUE) *sk=NULL; LHASH *parms=NULL; X509_REQ *req=NULL; CONF_VALUE *cv=NULL; NETSCAPE_SPKI *spki = NULL; - unsigned char *spki_der = NULL,*p; X509_REQ_INFO *ri; char *type,*buf; EVP_PKEY *pktmp=NULL; @@ -1666,7 +2354,7 @@ int verbose; } sk=CONF_get_section(parms, "default"); - if (sk_num(sk) == 0) + if (sk_CONF_VALUE_num(sk) == 0) { BIO_printf(bio_err, "no name/value pairs found in %s\n", infile); CONF_free(parms); @@ -1695,35 +2383,27 @@ int verbose; for (i = 0; ; i++) { - if ((int)sk_num(sk) <= i) break; + if (sk_CONF_VALUE_num(sk) <= i) break; - cv=(CONF_VALUE *)sk_value(sk,i); + cv=sk_CONF_VALUE_value(sk,i); type=cv->name; - buf=cv->value; + /* 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; + } + buf=cv->value; if ((nid=OBJ_txt2nid(type)) == NID_undef) { if (strcmp(type, "SPKAC") == 0) { - spki_der=(unsigned char *)Malloc( - strlen(cv->value)+1); - if (spki_der == NULL) - { - BIO_printf(bio_err,"Malloc failure\n"); - goto err; - } - j = EVP_DecodeBlock(spki_der, (unsigned char *)cv->value, - strlen(cv->value)); - if (j <= 0) - { - BIO_printf(bio_err, "Can't b64 decode SPKAC structure\n"); - goto err; - } - - p=spki_der; - spki = d2i_NETSCAPE_SPKI(&spki, &p, j); - Free(spki_der); - spki_der = NULL; + spki = NETSCAPE_SPKI_b64_decode(cv->value, -1); if (spki == NULL) { BIO_printf(bio_err,"unable to load Netscape SPKAC structure\n"); @@ -1747,8 +2427,7 @@ int verbose; strlen(buf))) == NULL) goto err; - if (!X509_NAME_add_entry(n,ne,X509_NAME_entry_count(n),0)) - goto err; + if (!X509_NAME_add_entry(n,ne,-1, 0)) goto err; } if (spki == NULL) { @@ -1763,7 +2442,7 @@ int verbose; BIO_printf(bio_err,"Check that the SPKAC request matches the signature\n"); - if ((pktmp=X509_PUBKEY_get(spki->spkac->pubkey)) == NULL) + if ((pktmp=NETSCAPE_SPKI_get_pubkey(spki)) == NULL) { BIO_printf(bio_err,"error unpacking SPKAC public key\n"); goto err; @@ -1778,21 +2457,20 @@ int verbose; BIO_printf(bio_err,"Signature ok\n"); X509_REQ_set_pubkey(req,pktmp); - ok=do_body(xret,pkey,x509,dgst,policy,db,serial,days,1,verbose,req, - extensions); + EVP_PKEY_free(pktmp); + 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); - if (spki_der != NULL) Free(spki_der); if (spki != NULL) NETSCAPE_SPKI_free(spki); if (ne != NULL) X509_NAME_ENTRY_free(ne); return(ok); } -static int fix_data(nid,type) -int nid; -int *type; +static int fix_data(int nid, int *type) { if (nid == NID_pkcs9_emailAddress) *type=V_ASN1_IA5STRING; @@ -1807,110 +2485,626 @@ int *type; return(1); } +static int check_time_format(char *str) + { + ASN1_UTCTIME tm; -static STACK *load_extensions(sec) -char *sec; + tm.data=(unsigned char *)str; + tm.length=strlen(str); + tm.type=V_ASN1_UTCTIME; + return(ASN1_UTCTIME_check(&tm)); + } + +static int do_revoke(X509 *x509, TXT_DB *db, int type, char *value) { - STACK *ext; - STACK *ret=NULL; - CONF_VALUE *cv; - ASN1_OCTET_STRING *str=NULL; - ASN1_STRING *tmp=NULL; - X509_EXTENSION *x; - BIO *mem=NULL; - BUF_MEM *buf=NULL; - int i,nid,len; - unsigned char *ptr; - int pack_type; - int data_type; + ASN1_UTCTIME *tm=NULL; + char *row[DB_NUMBER],**rrow,**irow; + char *rev_str = NULL; + BIGNUM *bn = NULL; + int ok=-1,i; - if ((ext=CONF_get_section(conf,sec)) == NULL) + for (i=0; ilength+1); + memcpy(row[DB_exp_date],tm->data,tm->length); + row[DB_exp_date][tm->length]='\0'; + + row[DB_rev_date]=NULL; - if ((ret=sk_new_null()) == NULL) return(NULL); + /* row[DB_serial] done already */ + row[DB_file]=(char *)OPENSSL_malloc(8); - for (i=0; ierror); + goto err; + } + + /* Revoke Certificate */ + ok = do_revoke(x509,db, type, value); + + goto err; + + } + 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]); + goto err; + } + else if (rrow[DB_type][0]=='R') + { + BIO_printf(bio_err,"ERROR:Already revoked, serial number %s\n", + row[DB_serial]); + goto err; + } + else { - cv=(CONF_VALUE *)sk_value(ext,i); /* get the object id */ - if ((nid=OBJ_txt2nid(cv->name)) == NID_undef) + BIO_printf(bio_err,"Revoking Certificate %s.\n", rrow[DB_serial]); + rev_str = make_revocation_str(type, value); + if (!rev_str) { - BIO_printf(bio_err,"%s:unknown object type in section, '%s'\n",sec,cv->name); + BIO_printf(bio_err, "Error in revocation arguments\n"); goto err; } + rrow[DB_type][0]='R'; + rrow[DB_type][1]='\0'; + rrow[DB_rev_date] = rev_str; + } + ok=1; +err: + for (i=0; i= 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]); + } + + } + } - pack_type=X509v3_pack_type_by_NID(nid); - data_type=X509v3_data_type_by_NID(nid); +err: - /* pack up the input bytes */ - ptr=(unsigned char *)cv->value; - len=strlen((char *)ptr); - if ((len > 2) && (cv->value[0] == '0') && - (cv->value[1] == 'x')) + 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 (data_type == V_ASN1_UNDEF) + if (!strcasecmp(rev_arg, crl_reasons[i])) { - BIO_printf(bio_err,"data type for extension %s is unknown\n",cv->name); - goto err; + reason = crl_reasons[i]; + break; } - if (mem == NULL) - if ((mem=BIO_new(BIO_s_mem())) == NULL) - goto err; - if (((buf=BUF_MEM_new()) == NULL) || - !BUF_MEM_grow(buf,128)) + } + 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; - if ((tmp=ASN1_STRING_new()) == NULL) goto err; + } + reason_code = OCSP_REVOKED_STATUS_CERTIFICATEHOLD; + hold = OBJ_txt2obj(arg_str, 0); - BIO_reset(mem); - BIO_write(mem,(char *)&(ptr[2]),len-2); - if (!a2i_ASN1_STRING(mem,tmp,buf->data,buf->max)) + if (!hold) + { + BIO_printf(bio_err, "invalid object identifier %s\n", arg_str); goto err; - len=tmp->length; - ptr=tmp->data; + } } - - switch (pack_type) + else if ((reason_code == 9) || (reason_code == 10)) { - case X509_EXT_PACK_STRING: - if ((str=X509v3_pack_string(&str, - data_type,ptr,len)) == NULL) + if (!arg_str) + { + BIO_printf(bio_err, "missing compromised time\n"); goto err; - break; - case X509_EXT_PACK_UNKNOWN: - default: - BIO_printf(bio_err,"Don't know how to pack extension %s\n",cv->name); - goto err; - break; + } + 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 ((x=X509_EXTENSION_create_by_NID(NULL,nid,0,str)) == NULL) + 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; - sk_push(ret,(char *)x); } - if (0) + if (rev && comp_time) { -err: - if (ret != NULL) sk_pop_free(ret,X509_EXTENSION_free); - ret=NULL; + if (!X509_REVOKED_add1_ext_i2d(rev, NID_invalidity_date, comp_time, 0, 0)) + goto err; } - if (str != NULL) ASN1_OCTET_STRING_free(str); - if (tmp != NULL) ASN1_STRING_free(tmp); - if (buf != NULL) BUF_MEM_free(buf); - if (mem != NULL) BIO_free(mem); - return(ret); + 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 int check_time_format(str) -char *str; +static X509_NAME *do_subject(char *subject) { - ASN1_UTCTIME tm; + X509_NAME *n = NULL; - tm.data=(unsigned char *)str; - tm.length=strlen(str); - tm.type=V_ASN1_UTCTIME; - return(ASN1_UTCTIME_check(&tm)); + 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; + }