From f85b68cd4982c28c02070c2e036da1c84cf0e7af Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Thu, 3 Apr 2003 16:33:03 +0000 Subject: [PATCH] Make it possible to have multiple active certificates with the same subject. --- CHANGES | 8 + apps/apps.c | 442 +++++++++++++++++++++++++++++++++++++++++++++++ apps/apps.h | 32 +++- apps/ca.c | 425 +++++++++------------------------------------ apps/ocsp.c | 46 ++--- apps/openssl.cnf | 2 + apps/x509.c | 78 +-------- 7 files changed, 585 insertions(+), 448 deletions(-) diff --git a/CHANGES b/CHANGES index 77da6273c4..505ef51880 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,14 @@ Changes between 0.9.7a and 0.9.8 [xx XXX xxxx] + *) Make it possible to have multiple active certificates with the same + subject in the CA index file. This is done only if the keyword + 'unique_subject' is set to 'no' in the main CA section (default + if 'CA_default') of the configuration file. The value is saved + with the database itself in a separate index attribute file, + named like the index file with '.attr' appended to the name. + [Richard Levitte] + *) Generate muti valued AVAs using '+' notation in config files for req and dirName. [Steve Henson] diff --git a/apps/apps.c b/apps/apps.c index 007e3e06c3..475e47e570 100644 --- a/apps/apps.c +++ b/apps/apps.c @@ -1422,3 +1422,445 @@ char *make_config_name() return p; } + +static unsigned long index_serial_hash(const char **a) + { + const char *n; + + n=a[DB_serial]; + while (*n == '0') n++; + return(lh_strhash(n)); + } + +static int index_serial_cmp(const char **a, const char **b) + { + 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 int index_name_qual(char **a) + { return(a[0][0] == 'V'); } + +static unsigned long index_name_hash(const char **a) + { return(lh_strhash(a[DB_name])); } + +int index_name_cmp(const char **a, const char **b) + { return(strcmp(a[DB_name], + b[DB_name])); } + +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 **) + +#undef BSIZE +#define BSIZE 256 + +BIGNUM *load_serial(char *serialfile, int create, ASN1_INTEGER **retai) + { + BIO *in=NULL; + BIGNUM *ret=NULL; + MS_STATIC char buf[1024]; + ASN1_INTEGER *ai=NULL; + + ai=ASN1_INTEGER_new(); + if (ai == NULL) goto err; + + if ((in=BIO_new(BIO_s_file())) == NULL) + { + ERR_print_errors(bio_err); + goto err; + } + + if (BIO_read_filename(in,serialfile) <= 0) + { + if (!create) + { + perror(serialfile); + goto err; + } + else + { + ASN1_INTEGER_set(ai,1); + ret=BN_new(); + if (ret == NULL) + BIO_printf(bio_err, "Out of memory\n"); + else + BN_one(ret); + } + } + else + { + if (!a2i_ASN1_INTEGER(in,ai,buf,1024)) + { + BIO_printf(bio_err,"unable to load number from %s\n", + serialfile); + goto err; + } + ret=ASN1_INTEGER_to_BN(ai,NULL); + if (ret == NULL) + { + BIO_printf(bio_err,"error converting number from bin to BIGNUM\n"); + goto err; + } + } + + if (ret && retai) + { + *retai = ai; + ai = NULL; + } + err: + if (in != NULL) BIO_free(in); + if (ai != NULL) ASN1_INTEGER_free(ai); + return(ret); + } + +int save_serial(char *serialfile, BIGNUM *serial, ASN1_INTEGER **retai) + { + BIO *out; + int ret=0; + ASN1_INTEGER *ai=NULL; + + out=BIO_new(BIO_s_file()); + if (out == NULL) + { + ERR_print_errors(bio_err); + goto err; + } + if (BIO_write_filename(out,serialfile) <= 0) + { + perror(serialfile); + goto err; + } + + if ((ai=BN_to_ASN1_INTEGER(serial,NULL)) == NULL) + { + BIO_printf(bio_err,"error converting serial to ASN.1 format\n"); + goto err; + } + i2a_ASN1_INTEGER(out,ai); + BIO_puts(out,"\n"); + ret=1; + if (retai) + { + *retai = ai; + ai = NULL; + } +err: + if (out != NULL) BIO_free_all(out); + if (ai != NULL) ASN1_INTEGER_free(ai); + return(ret); + } + +CA_DB *load_index(char *dbfile, DB_ATTR *db_attr) + { + CA_DB *retdb = NULL; + TXT_DB *tmpdb = NULL; + BIO *in = BIO_new(BIO_s_file()); + CONF *dbattr_conf = NULL; + char buf[1][BSIZE]; + long errorline= -1; + + if (in == NULL) + { + ERR_print_errors(bio_err); + goto err; + } + if (BIO_read_filename(in,dbfile) <= 0) + { + perror(dbfile); + BIO_printf(bio_err,"unable to open '%s'\n",dbfile); + goto err; + } + if ((tmpdb = TXT_DB_read(in,DB_NUMBER)) == NULL) + { + if (tmpdb != NULL) TXT_DB_free(tmpdb); + goto err; + } + +#ifndef OPENSSL_SYS_VMS + BIO_snprintf(buf[0], sizeof buf[0], "%s.attr", dbfile); +#else + BIO_snprintf(buf[0], sizeof buf[0], "%s-attr", dbfile); +#endif + dbattr_conf = NCONF_new(NULL); + if (NCONF_load(dbattr_conf,buf[0],&errorline) <= 0) + { + if (errorline > 0) + { + BIO_printf(bio_err, + "error on line %ld of db attribute file '%s'\n" + ,errorline,buf[0]); + goto err; + } + else + { + NCONF_free(dbattr_conf); + dbattr_conf = NULL; + } + } + + if ((retdb = OPENSSL_malloc(sizeof(CA_DB))) == NULL) + { + fprintf(stderr, "Out of memory\n"); + goto err; + } + + retdb->db = tmpdb; + tmpdb = NULL; + if (db_attr) + retdb->attributes = *db_attr; + else + { + retdb->attributes.unique_subject = 1; + } + + if (dbattr_conf) + { + char *p = NCONF_get_string(dbattr_conf,NULL,"unique_subject"); + if (p) + { + BIO_printf(bio_err, "DEBUG[load_index]: unique_subject = \"%s\"\n", p); + switch(*p) + { + case 'f': /* false */ + case 'F': /* FALSE */ + case 'n': /* no */ + case 'N': /* NO */ + retdb->attributes.unique_subject = 0; + break; + case 't': /* true */ + case 'T': /* TRUE */ + case 'y': /* yes */ + case 'Y': /* YES */ + default: + retdb->attributes.unique_subject = 1; + break; + } + } + } + + err: + if (dbattr_conf) NCONF_free(dbattr_conf); + if (tmpdb) TXT_DB_free(tmpdb); + if (in) BIO_free_all(in); + return retdb; + } + +int index_index(CA_DB *db) + { + if (!TXT_DB_create_index(db->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->db->error,db->db->arg1,db->db->arg2); + return 0; + } + + if (db->attributes.unique_subject + && !TXT_DB_create_index(db->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->db->error,db->db->arg1,db->db->arg2); + return 0; + } + return 1; + } + +int save_index(char *dbfile, char *suffix, CA_DB *db) + { + char buf[3][BSIZE]; + BIO *out = BIO_new(BIO_s_file()); + int j; + + if (out == NULL) + { + ERR_print_errors(bio_err); + goto err; + } + + j = strlen(dbfile) + strlen(suffix); + if (j + 6 >= BSIZE) + { + BIO_printf(bio_err,"file name too long\n"); + goto err; + } + +#ifndef OPENSSL_SYS_VMS + j = BIO_snprintf(buf[2], sizeof buf[2], "%s.attr", dbfile); +#else + j = BIO_snprintf(buf[2], sizeof buf[2], "%s-attr", dbfile); +#endif +#ifndef OPENSSL_SYS_VMS + j = BIO_snprintf(buf[1], sizeof buf[1], "%s.attr.%s", dbfile, suffix); +#else + j = BIO_snprintf(buf[1], sizeof buf[1], "%s-attr-%s", dbfile, suffix); +#endif +#ifndef OPENSSL_SYS_VMS + j = BIO_snprintf(buf[0], sizeof buf[0], "%s.%s", dbfile, suffix); +#else + j = BIO_snprintf(buf[0], sizeof buf[0], "%s-%s", dbfile, suffix); +#endif + BIO_printf(bio_err, "DEBUG: writing \"%s\"\n", buf[0]); + 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->db); + if (j <= 0) goto err; + + BIO_free(out); + + out = BIO_new(BIO_s_file()); + BIO_printf(bio_err, "DEBUG: writing \"%s\"\n", buf[1]); + if (BIO_write_filename(out,buf[1]) <= 0) + { + perror(buf[2]); + BIO_printf(bio_err,"unable to open '%s'\n", buf[2]); + goto err; + } + BIO_printf(out,"unique_subject = %s\n", + db->attributes.unique_subject ? "yes" : "no"); + BIO_free(out); + + return 1; + err: + return 0; + } + +int rotate_index(char *dbfile, char *new_suffix, char *old_suffix) + { + char buf[5][BSIZE]; + int i,j; + struct stat sb; + + i = strlen(dbfile) + strlen(old_suffix); + j = strlen(dbfile) + strlen(new_suffix); + if (i > j) j = i; + if (j + 6 >= BSIZE) + { + BIO_printf(bio_err,"file name too long\n"); + goto err; + } + +#ifndef OPENSSL_SYS_VMS + j = BIO_snprintf(buf[4], sizeof buf[4], "%s.attr", dbfile); +#else + j = BIO_snprintf(buf[4], sizeof buf[4], "%s-attr", dbfile); +#endif +#ifndef OPENSSL_SYS_VMS + j = BIO_snprintf(buf[2], sizeof buf[2], "%s.attr.%s", + dbfile, new_suffix); +#else + j = BIO_snprintf(buf[2], sizeof buf[2], "%s-attr-%s", + dbfile, new_suffix); +#endif +#ifndef OPENSSL_SYS_VMS + j = BIO_snprintf(buf[0], sizeof buf[0], "%s.%s", + dbfile, new_suffix); +#else + j = BIO_snprintf(buf[0], sizeof buf[0], "%s-%s", + dbfile, new_suffix); +#endif +#ifndef OPENSSL_SYS_VMS + j = BIO_snprintf(buf[1], sizeof buf[1], "%s.%s", + dbfile, old_suffix); +#else + j = BIO_snprintf(buf[1], sizeof buf[1], "%s-%s", + dbfile, old_suffix); +#endif +#ifndef OPENSSL_SYS_VMS + j = BIO_snprintf(buf[3], sizeof buf[3], "%s.attr.%s", + dbfile, old_suffix); +#else + j = BIO_snprintf(buf[3], sizeof buf[3], "%s-attr-%s", + dbfile, old_suffix); +#endif + if (stat(dbfile,&sb) < 0) + { + if (errno != ENOENT +#ifdef ENOTDIR + && errno != ENOTDIR) +#endif + goto err; + } + else + { + BIO_printf(bio_err, "DEBUG: renaming \"%s\" to \"%s\"\n", + dbfile, buf[1]); + if (rename(dbfile,buf[1]) < 0) + { + BIO_printf(bio_err, + "unable to rename %s to %s\n", + dbfile, buf[1]); + perror("reason"); + goto err; + } + } + BIO_printf(bio_err, "DEBUG: renaming \"%s\" to \"%s\"\n", + buf[0],dbfile); + 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 (stat(buf[4],&sb) < 0) + { + if (errno != ENOENT +#ifdef ENOTDIR + && errno != ENOTDIR) +#endif + goto err; + } + else + { + BIO_printf(bio_err, "DEBUG: renaming \"%s\" to \"%s\"\n", + buf[4],buf[3]); + if (rename(buf[4],buf[3]) < 0) + { + BIO_printf(bio_err, + "unable to rename %s to %s\n", + buf[4], buf[3]); + perror("reason"); + rename(dbfile,buf[0]); + rename(buf[1],dbfile); + goto err; + } + } + BIO_printf(bio_err, "DEBUG: renaming \"%s\" to \"%s\"\n", + buf[2],buf[4]); + if (rename(buf[2],buf[4]) < 0) + { + BIO_printf(bio_err, + "unable to rename %s to %s\n", + buf[2],buf[4]); + perror("reason"); + rename(buf[3],buf[4]); + rename(dbfile,buf[0]); + rename(buf[1],dbfile); + goto err; + } + return 1; + err: + return 0; + } + +void free_index(CA_DB *db) + { + TXT_DB_free(db->db); + OPENSSL_free(db); + } diff --git a/apps/apps.h b/apps/apps.h index c36b9d2566..974eb4f1c9 100644 --- a/apps/apps.h +++ b/apps/apps.h @@ -287,7 +287,37 @@ char *make_config_name(void); /* Functions defined in ca.c and also used in ocsp.c */ int unpack_revinfo(ASN1_TIME **prevtm, int *preason, ASN1_OBJECT **phold, ASN1_GENERALIZEDTIME **pinvtm, char *str); -int make_serial_index(TXT_DB *db); + +#define DB_type 0 +#define DB_exp_date 1 +#define DB_rev_date 2 +#define DB_serial 3 /* index - unique */ +#define DB_file 4 +#define DB_name 5 /* index - unique when active and not disabled */ +#define DB_NUMBER 6 + +#define DB_TYPE_REV 'R' +#define DB_TYPE_EXP 'E' +#define DB_TYPE_VAL 'V' + +typedef struct db_attr_st + { + int unique_subject; + } DB_ATTR; +typedef struct ca_db_st + { + DB_ATTR attributes; + TXT_DB *db; + } CA_DB; + +BIGNUM *load_serial(char *serialfile, int create, ASN1_INTEGER **retai); +int save_serial(char *serialfile, BIGNUM *serial, ASN1_INTEGER **retai); +CA_DB *load_index(char *dbfile, DB_ATTR *dbattr); +int index_index(CA_DB *db); +int save_index(char *dbfile, char *suffix, CA_DB *db); +int rotate_index(char *dbfile, char *new_suffix, char *old_suffix); +void free_index(CA_DB *db); +int index_name_cmp(const char **a, const char **b); X509_NAME *do_subject(char *str, long chtype); diff --git a/apps/ca.c b/apps/ca.c index 6722c5dbc9..574cdd7fdc 100644 --- a/apps/ca.c +++ b/apps/ca.c @@ -143,18 +143,6 @@ #define ENV_DATABASE "database" -#define DB_type 0 -#define DB_exp_date 1 -#define DB_rev_date 2 -#define DB_serial 3 /* index - unique */ -#define DB_file 4 -#define DB_name 5 /* index - unique for active */ -#define DB_NUMBER 6 - -#define DB_TYPE_REV 'R' -#define DB_TYPE_EXP 'E' -#define DB_TYPE_VAL 'V' - /* Additional revocation information types */ #define REV_NONE 0 /* No addditional information */ @@ -211,43 +199,36 @@ extern int EF_ALIGNMENT; #endif static void lookup_fail(char *name,char *tag); -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(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, + const EVP_MD *dgst,STACK_OF(CONF_VALUE) *policy,CA_DB *db, BIGNUM *serial, char *subj, int email_dn, 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, int email_dn, + CA_DB *db, BIGNUM *serial, char *subj, int email_dn, 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, const EVP_MD *dgst,STACK_OF(CONF_VALUE) *policy, - TXT_DB *db, BIGNUM *serial,char *subj, int email_dn, + CA_DB *db, BIGNUM *serial,char *subj, int email_dn, 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, 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, + STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial,char *subj, int email_dn, 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 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 do_revoke(X509 *x509, CA_DB *db, int ext, char *extval); +static int get_certificate_status(const char *ser_status, CA_DB *db); +static int do_updatedb(CA_DB *db); 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); @@ -259,11 +240,6 @@ 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 **); @@ -320,14 +296,13 @@ int MAIN(int argc, char **argv) X509 *x=NULL; BIO *in=NULL,*out=NULL,*Sout=NULL,*Cout=NULL; char *dbfile=NULL; - TXT_DB *db=NULL; + CA_DB *db=NULL; X509_CRL *crl=NULL; X509_REVOKED *r=NULL; ASN1_TIME *tmptm; ASN1_INTEGER *tmpser; char **pp,*p,*f; int i,j; - long l; const EVP_MD *dgst=NULL; STACK_OF(CONF_VALUE) *attribs=NULL; STACK_OF(X509) *cert_sk=NULL; @@ -339,6 +314,7 @@ int MAIN(int argc, char **argv) char *engine = NULL; #endif char *tofree=NULL; + DB_ATTR db_attr; #ifdef EFENCE EF_PROTECT_FREE=1; @@ -659,6 +635,33 @@ bad: if (randfile == NULL) ERR_clear_error(); app_RAND_load_file(randfile, bio_err, 0); + + db_attr.unique_subject = 1; + p = NCONF_get_string(conf, section, "unique_subject"); + if (p) + { + BIO_printf(bio_err, "DEBUG: unique_subject = \"%s\"\n", p); + switch(*p) + { + case 'f': /* false */ + case 'F': /* FALSE */ + case 'n': /* no */ + case 'N': /* NO */ + db_attr.unique_subject = 0; + break; + case 't': /* true */ + case 'T': /* TRUE */ + case 'y': /* yes */ + case 'Y': /* YES */ + default: + db_attr.unique_subject = 1; + break; + } + } + else + BIO_printf(bio_err, "DEBUG: unique_subject undefined\n", p); + BIO_printf(bio_err, "DEBUG: configured unique_subject is %d\n", + db_attr.unique_subject); in=BIO_new(BIO_s_file()); out=BIO_new(BIO_s_file()); @@ -679,17 +682,10 @@ bad: 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); + db = load_index(dbfile,&db_attr); if (db == NULL) goto err; - if (!make_serial_index(db)) - goto err; + if (!index_index(db)) goto err; if (get_certificate_status(ser_status,db) != 1) BIO_printf(bio_err,"Error verifying serial %s!\n", @@ -849,19 +845,13 @@ bad: 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); + db = load_index(dbfile, &db_attr); if (db == NULL) goto err; /* Lets check some fields */ - for (i=0; idata); i++) + for (i=0; idb->data); i++) { - pp=(char **)sk_value(db->data,i); + pp=(char **)sk_value(db->db->data,i); if ((pp[DB_type][0] != DB_TYPE_REV) && (pp[DB_rev_date][0] != '\0')) { @@ -912,23 +902,13 @@ bad: out = BIO_push(tmpbio, out); } #endif - TXT_DB_write(out,db); + TXT_DB_write(out,db->db); BIO_printf(bio_err,"%d entries loaded from the database\n", - db->data->num); + db->db->data->num); BIO_printf(bio_err,"generating index\n"); } - if (!make_serial_index(db)) - goto err; - - 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; - } + if (!index_index(db)) goto err; /*****************************************************************/ /* Update the db file for expired certificates */ @@ -951,62 +931,9 @@ bad: } 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 (!save_index(dbfile,"new",db)) goto err; + + if (!rotate_index(dbfile,"new","old")) goto err; if (verbose) BIO_printf(bio_err, "Done. %d entries marked as expired\n",i); @@ -1167,7 +1094,7 @@ bad: goto err; } - if ((serial=load_serial(serialfile)) == NULL) + if ((serial=load_serial(serialfile, 0, NULL)) == NULL) { BIO_printf(bio_err,"error while loading serial number\n"); goto err; @@ -1315,24 +1242,9 @@ bad: strcat(buf[0],".new"); #endif - if (!save_serial(buf[0],serial)) goto err; - - strcpy(buf[1],dbfile); - -#ifdef OPENSSL_SYS_VMS - strcat(buf[1],"-new"); -#else - strcat(buf[1],".new"); -#endif + if (!save_serial(buf[0],serial,NULL)) goto err; - if (BIO_write_filename(out,buf[1]) <= 0) - { - perror(dbfile); - BIO_printf(bio_err,"unable to open '%s'\n",dbfile); - goto err; - } - l=TXT_DB_write(out,db); - if (l <= 0) goto err; + if (!save_index(dbfile, "new", db)) goto err; } if (verbose) @@ -1419,30 +1331,8 @@ bad: goto err; } - strncpy(buf[2],dbfile,BSIZE-4); - buf[2][BSIZE-4]='\0'; - -#ifdef OPENSSL_SYS_VMS - strcat(buf[2],"-old"); -#else - strcat(buf[2],".old"); -#endif + if (!rotate_index(dbfile,"new","old")) goto err; - if (rename(dbfile,buf[2]) < 0) - { - BIO_printf(bio_err,"unable to rename %s to %s\n", - dbfile,buf[2]); - perror("reason"); - goto err; - } - if (rename(buf[1],dbfile) < 0) - { - BIO_printf(bio_err,"unable to rename %s to %s\n", - buf[1],dbfile); - perror("reason"); - rename(buf[2],dbfile); - goto err; - } BIO_printf(bio_err,"Data Base Updated\n"); } } @@ -1501,9 +1391,9 @@ bad: ASN1_TIME_free(tmptm); - for (i=0; idata); i++) + for (i=0; idb->data); i++) { - pp=(char **)sk_value(db->data,i); + pp=(char **)sk_value(db->db->data,i); if (pp[DB_type][0] == DB_TYPE_REV) { if ((r=X509_REVOKED_new()) == NULL) goto err; @@ -1592,50 +1482,10 @@ bad: if (j <= 0) goto err; X509_free(revcert); - if(strlen(dbfile) > BSIZE-5) - { - BIO_printf(bio_err,"filename too long\n"); - goto err; - } + if (!save_index(dbfile, "new", db)) goto err; + + if (!rotate_index(dbfile, "new", "old")) goto err; - strcpy(buf[0],dbfile); -#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); - buf[1][BSIZE-4]='\0'; -#ifndef OPENSSL_SYS_VMS - strcat(buf[1],".old"); -#else - strcat(buf[1],"-old"); -#endif - BIO_free(in); - in = NULL; - BIO_free(out); - out = NULL; - 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"); } } @@ -1657,7 +1507,7 @@ err: if (free_key && key) OPENSSL_free(key); BN_free(serial); - TXT_DB_free(db); + free_index(db); EVP_PKEY_free(pkey); X509_free(x509); X509_CRL_free(crl); @@ -1672,106 +1522,8 @@ static void lookup_fail(char *name, char *tag) BIO_printf(bio_err,"variable lookup failed for %s::%s\n",name,tag); } -static unsigned long index_serial_hash(const char **a) - { - const char *n; - - n=a[DB_serial]; - while (*n == '0') n++; - return(lh_strhash(n)); - } - -static int index_serial_cmp(const char **a, const char **b) - { - 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(const char **a) - { return(lh_strhash(a[DB_name])); } - -static int index_name_qual(char **a) - { return(a[0][0] == 'V'); } - -static int index_name_cmp(const char **a, const char **b) - { return(strcmp(a[DB_name], - b[DB_name])); } - -static BIGNUM *load_serial(char *serialfile) - { - BIO *in=NULL; - BIGNUM *ret=NULL; - MS_STATIC char buf[1024]; - ASN1_INTEGER *ai=NULL; - - if ((in=BIO_new(BIO_s_file())) == NULL) - { - ERR_print_errors(bio_err); - goto err; - } - - if (BIO_read_filename(in,serialfile) <= 0) - { - perror(serialfile); - goto err; - } - ai=ASN1_INTEGER_new(); - if (ai == NULL) goto err; - if (!a2i_ASN1_INTEGER(in,ai,buf,1024)) - { - BIO_printf(bio_err,"unable to load number from %s\n", - serialfile); - goto err; - } - ret=ASN1_INTEGER_to_BN(ai,NULL); - if (ret == NULL) - { - BIO_printf(bio_err,"error converting number from bin to BIGNUM\n"); - goto err; - } -err: - if (in != NULL) BIO_free(in); - if (ai != NULL) ASN1_INTEGER_free(ai); - return(ret); - } - -static int save_serial(char *serialfile, BIGNUM *serial) - { - BIO *out; - int ret=0; - ASN1_INTEGER *ai=NULL; - - out=BIO_new(BIO_s_file()); - if (out == NULL) - { - ERR_print_errors(bio_err); - goto err; - } - if (BIO_write_filename(out,serialfile) <= 0) - { - perror(serialfile); - goto err; - } - - if ((ai=BN_to_ASN1_INTEGER(serial,NULL)) == NULL) - { - BIO_printf(bio_err,"error converting serial to ASN.1 format\n"); - goto err; - } - i2a_ASN1_INTEGER(out,ai); - BIO_puts(out,"\n"); - ret=1; -err: - 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, + const EVP_MD *dgst, STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, char *subj, int email_dn, char *startdate, char *enddate, long days, int batch, char *ext_sect, CONF *lconf, int verbose, unsigned long certopt, unsigned long nameopt, int default_op, @@ -1833,7 +1585,7 @@ 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, + const EVP_MD *dgst, STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, char *subj, int email_dn, char *startdate, char *enddate, long days, int batch, char *ext_sect, CONF *lconf, int verbose, unsigned long certopt, unsigned long nameopt, int default_op, @@ -1887,7 +1639,7 @@ err: } 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, + STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, char *subj, int email_dn, 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, @@ -1905,7 +1657,7 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst, int ok= -1,i,j,last,nid; char *p; CONF_VALUE *cv; - char *row[DB_NUMBER],**rrow,**irow=NULL; + char *row[DB_NUMBER],**rrow=NULL,**irow=NULL; char buf[25]; tmptm=ASN1_UTCTIME_new(); @@ -2142,15 +1894,19 @@ again2: goto err; } - rrow=TXT_DB_get_by_index(db,DB_name,row); - if (rrow != NULL) + if (db->attributes.unique_subject) { - BIO_printf(bio_err,"ERROR:There is already a certificate for %s\n", - row[DB_name]); + rrow=TXT_DB_get_by_index(db->db,DB_name,row); + if (rrow != NULL) + { + BIO_printf(bio_err, + "ERROR:There is already a certificate for %s\n", + row[DB_name]); + } } - else + if (rrow == NULL) { - rrow=TXT_DB_get_by_index(db,DB_serial,row); + rrow=TXT_DB_get_by_index(db->db,DB_serial,row); if (rrow != NULL) { BIO_printf(bio_err,"ERROR:Serial number %s has already been issued,\n", @@ -2384,10 +2140,10 @@ again2: } irow[DB_NUMBER]=NULL; - if (!TXT_DB_insert(db,irow)) + if (!TXT_DB_insert(db->db,irow)) { BIO_printf(bio_err,"failed to update database\n"); - BIO_printf(bio_err,"TXT_DB error number %ld\n",db->error); + BIO_printf(bio_err,"TXT_DB error number %ld\n",db->db->error); goto err; } ok=1; @@ -2438,7 +2194,7 @@ static void write_new_certificate(BIO *bp, X509 *x, int output_der, int notext) } 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, + const EVP_MD *dgst, STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, char *subj, int email_dn, 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) @@ -2617,7 +2373,7 @@ static int check_time_format(char *str) return(ASN1_UTCTIME_check(&tm)); } -static int do_revoke(X509 *x509, TXT_DB *db, int type, char *value) +static int do_revoke(X509 *x509, CA_DB *db, int type, char *value) { ASN1_UTCTIME *tm=NULL; char *row[DB_NUMBER],**rrow,**irow; @@ -2642,10 +2398,10 @@ static int do_revoke(X509 *x509, TXT_DB *db, int type, char *value) /* We have to lookup by serial number because name lookup * skips revoked certs */ - rrow=TXT_DB_get_by_index(db,DB_serial,row); + rrow=TXT_DB_get_by_index(db->db,DB_serial,row); if (rrow == NULL) { - BIO_printf(bio_err,"Adding Entry to DB for %s\n", row[DB_name]); + BIO_printf(bio_err,"Adding Entry with serial number %s to DB for %s\n", row[DB_serial], row[DB_name]); /* We now just add it to the database */ row[DB_type]=(char *)OPENSSL_malloc(2); @@ -2685,10 +2441,10 @@ static int do_revoke(X509 *x509, TXT_DB *db, int type, char *value) } irow[DB_NUMBER]=NULL; - if (!TXT_DB_insert(db,irow)) + if (!TXT_DB_insert(db->db,irow)) { BIO_printf(bio_err,"failed to update database\n"); - BIO_printf(bio_err,"TXT_DB error number %ld\n",db->error); + BIO_printf(bio_err,"TXT_DB error number %ld\n",db->db->error); goto err; } @@ -2733,7 +2489,7 @@ err: return(ok); } -static int get_certificate_status(const char *serial, TXT_DB *db) +static int get_certificate_status(const char *serial, CA_DB *db) { char *row[DB_NUMBER],**rrow; int ok=-1,i; @@ -2774,7 +2530,7 @@ static int get_certificate_status(const char *serial, TXT_DB *db) ok=1; /* Search for the certificate */ - rrow=TXT_DB_get_by_index(db,DB_serial,row); + rrow=TXT_DB_get_by_index(db->db,DB_serial,row); if (rrow == NULL) { BIO_printf(bio_err,"Serial %s not present in db.\n", @@ -2821,7 +2577,7 @@ err: return(ok); } -static int do_updatedb (TXT_DB *db) +static int do_updatedb (CA_DB *db) { ASN1_UTCTIME *a_tm = NULL; int i, cnt = 0; @@ -2847,9 +2603,9 @@ static int do_updatedb (TXT_DB *db) else a_y2k = 0; - for (i = 0; i < sk_num(db->data); i++) + for (i = 0; i < sk_num(db->db->data); i++) { - rrow = (char **) sk_value(db->data, i); + rrow = (char **) sk_value(db->db->data, i); if (rrow[DB_type][0] == 'V') { @@ -3337,16 +3093,3 @@ int unpack_revinfo(ASN1_TIME **prevtm, int *preason, ASN1_OBJECT **phold, ASN1_G return ret; } -int make_serial_index(TXT_DB *db) - { - 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); - return 0; - } - return 1; - } diff --git a/apps/ocsp.c b/apps/ocsp.c index 17e84366d9..885e68e363 100644 --- a/apps/ocsp.c +++ b/apps/ocsp.c @@ -68,19 +68,6 @@ /* Maximum leeway in validity period: default 5 minutes */ #define MAX_VALIDITY_PERIOD (5 * 60) -/* CA index.txt definitions */ -#define DB_type 0 -#define DB_exp_date 1 -#define DB_rev_date 2 -#define DB_serial 3 /* index - unique */ -#define DB_file 4 -#define DB_name 5 /* index - unique for active */ -#define DB_NUMBER 6 - -#define DB_TYPE_REV 'R' -#define DB_TYPE_EXP 'E' -#define DB_TYPE_VAL 'V' - static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, X509 *issuer, STACK_OF(OCSP_CERTID) *ids); static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, X509 *issuer, @@ -89,12 +76,12 @@ static int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req, STACK *names, STACK_OF(OCSP_CERTID) *ids, long nsec, long maxage); -static int make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req, TXT_DB *db, +static int make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req, CA_DB *db, X509 *ca, X509 *rcert, EVP_PKEY *rkey, STACK_OF(X509) *rother, unsigned long flags, int nmin, int ndays); -static char **lookup_serial(TXT_DB *db, ASN1_INTEGER *ser); +static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser); static BIO *init_responder(char *port); static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, char *port); static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp); @@ -142,7 +129,7 @@ int MAIN(int argc, char **argv) X509 *rca_cert = NULL; char *ridx_filename = NULL; char *rca_filename = NULL; - TXT_DB *rdb = NULL; + CA_DB *rdb = NULL; int nmin = 0, ndays = -1; if (bio_err == NULL) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); @@ -697,22 +684,9 @@ int MAIN(int argc, char **argv) if (ridx_filename && !rdb) { - BIO *db_bio = NULL; - db_bio = BIO_new_file(ridx_filename, "r"); - if (!db_bio) - { - BIO_printf(bio_err, "Error opening index file %s\n", ridx_filename); - goto end; - } - rdb = TXT_DB_read(db_bio, DB_NUMBER); - BIO_free(db_bio); - if (!rdb) - { - BIO_printf(bio_err, "Error reading index file %s\n", ridx_filename); - goto end; - } - if (!make_serial_index(rdb)) - goto end; + rdb = load_index(ridx_filename, NULL); + if (!rdb) goto end; + if (!index_index(rdb)) goto end; } if (rdb) @@ -894,7 +868,7 @@ end: X509_free(cert); X509_free(rsigner); X509_free(rca_cert); - TXT_DB_free(rdb); + free_index(rdb); BIO_free_all(cbio); BIO_free_all(acbio); BIO_free(out); @@ -1036,7 +1010,7 @@ static int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req, } -static int make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req, TXT_DB *db, +static int make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req, CA_DB *db, X509 *ca, X509 *rcert, EVP_PKEY *rkey, STACK_OF(X509) *rother, unsigned long flags, int nmin, int ndays) @@ -1128,7 +1102,7 @@ static int make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req, TXT_DB *d } -static char **lookup_serial(TXT_DB *db, ASN1_INTEGER *ser) +static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser) { int i; BIGNUM *bn = NULL; @@ -1141,7 +1115,7 @@ static char **lookup_serial(TXT_DB *db, ASN1_INTEGER *ser) itmp = BN_bn2hex(bn); row[DB_serial] = itmp; BN_free(bn); - rrow=TXT_DB_get_by_index(db,DB_serial,row); + rrow=TXT_DB_get_by_index(db->db,DB_serial,row); OPENSSL_free(itmp); return rrow; } diff --git a/apps/openssl.cnf b/apps/openssl.cnf index eca51c3322..2696044cf1 100644 --- a/apps/openssl.cnf +++ b/apps/openssl.cnf @@ -38,6 +38,8 @@ dir = ./demoCA # Where everything is kept certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. new_certs_dir = $dir/newcerts # default place for new certs. certificate = $dir/cacert.pem # The CA certificate diff --git a/apps/x509.c b/apps/x509.c index 9a6f981790..64eb83dd6e 100644 --- a/apps/x509.c +++ b/apps/x509.c @@ -1034,12 +1034,11 @@ end: OPENSSL_EXIT(ret); } -static ASN1_INTEGER *load_serial(char *CAfile, char *serialfile, int create) +static ASN1_INTEGER *x509_load_serial(char *CAfile, char *serialfile, int create) { char *buf = NULL, *p; MS_STATIC char buf2[1024]; - ASN1_INTEGER *bs = NULL, *bs2 = NULL; - BIO *io = NULL; + ASN1_INTEGER *bs = NULL; BIGNUM *serial = NULL; buf=OPENSSL_malloc( ((serialfile == NULL) @@ -1059,80 +1058,19 @@ static ASN1_INTEGER *load_serial(char *CAfile, char *serialfile, int create) } else strcpy(buf,serialfile); - serial=BN_new(); - bs=ASN1_INTEGER_new(); - if ((serial == NULL) || (bs == NULL)) - { - ERR_print_errors(bio_err); - goto end; - } - io=BIO_new(BIO_s_file()); - if (io == NULL) - { - ERR_print_errors(bio_err); - goto end; - } - - if (BIO_read_filename(io,buf) <= 0) - { - if (!create) - { - perror(buf); - goto end; - } - else - { - ASN1_INTEGER_set(bs,1); - BN_one(serial); - } - } - else - { - if (!a2i_ASN1_INTEGER(io,bs,buf2,sizeof buf2)) - { - BIO_printf(bio_err,"unable to load serial number from %s\n",buf); - ERR_print_errors(bio_err); - goto end; - } - else - { - serial=BN_bin2bn(bs->data,bs->length,serial); - if (serial == NULL) - { - BIO_printf(bio_err,"error converting bin 2 bn"); - goto end; - } - } - } + serial = load_serial(buf, create, NULL); + if (serial == NULL) goto end; if (!BN_add_word(serial,1)) { BIO_printf(bio_err,"add_word failure\n"); goto end; } - if (!(bs2 = BN_to_ASN1_INTEGER(serial, NULL))) - { BIO_printf(bio_err,"error converting bn 2 asn1_integer\n"); goto end; } - if (BIO_write_filename(io,buf) <= 0) - { - BIO_printf(bio_err,"error attempting to write serial number file\n"); - perror(buf); - goto end; - } - i2a_ASN1_INTEGER(io,bs2); - BIO_puts(io,"\n"); - BIO_free(io); - if (buf) OPENSSL_free(buf); - ASN1_INTEGER_free(bs2); - BN_free(serial); - io=NULL; - return bs; + if (!save_serial(buf, serial, &bs)) goto end; - end: + end: if (buf) OPENSSL_free(buf); - BIO_free(io); - ASN1_INTEGER_free(bs); BN_free(serial); - return NULL; - + return bs; } static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest, @@ -1154,7 +1092,7 @@ static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest, goto end; } if (sno) bs = sno; - else if (!(bs = load_serial(CAfile, serialfile, create))) + else if (!(bs = x509_load_serial(CAfile, serialfile, create))) goto end; if (!X509_STORE_add_cert(ctx,x)) goto end; -- 2.40.0