X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=apps%2Fca.c;h=0cb498b9d967fd348ec83b7442e337ae2cbb07e0;hp=028dd98d31cf40bc5b1dd9e73f6bd70ac354c4d7;hb=b5cadfb564a604c0ba1c49984ac796cfd8310731;hpb=09ad2458b8c7974acead6438ea38fd1a7515b8e9 diff --git a/apps/ca.c b/apps/ca.c index 028dd98d31..0cb498b9d9 100644 --- a/apps/ca.c +++ b/apps/ca.c @@ -63,7 +63,6 @@ #include #include #include -#include #include #include #include @@ -76,16 +75,6 @@ #include #include -#ifdef OPENSSL_SYS_WINDOWS -#define strcasecmp _stricmp -#else -# ifdef NO_STRINGS_H - int strcasecmp(); -# else -# include -# endif /* NO_STRINGS_H */ -#endif - #ifndef W_OK # ifdef OPENSSL_SYS_VMS # if defined(__DECC) @@ -93,7 +82,7 @@ # else # include # endif -# elif !defined(OPENSSL_SYS_VXWORKS) && !defined(OPENSSL_SYS_WINDOWS) +# elif !defined(OPENSSL_SYS_VXWORKS) && !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_NETWARE) # include # endif #endif @@ -115,6 +104,9 @@ #define ENV_DEFAULT_CA "default_ca" +#define STRING_MASK "string_mask" +#define UTF8_IN "utf8" + #define ENV_DIR "dir" #define ENV_CERTS "certs" #define ENV_CRL_DIR "crl_dir" @@ -122,6 +114,7 @@ #define ENV_NEW_CERTS_DIR "new_certs_dir" #define ENV_CERTIFICATE "certificate" #define ENV_SERIAL "serial" +#define ENV_CRLNUMBER "crlnumber" #define ENV_CRL "crl" #define ENV_PRIVATE_KEY "private_key" #define ENV_RANDFILE "RANDFILE" @@ -140,21 +133,10 @@ #define ENV_NAMEOPT "name_opt" #define ENV_CERTOPT "cert_opt" #define ENV_EXTCOPY "copy_extensions" +#define ENV_UNIQUE_SUBJECT "unique_subject" #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 */ @@ -163,7 +145,7 @@ #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[]={ +static const char *ca_usage[]={ "usage: ca args\n", "\n", " -verbose - Talk alot while doing things\n", @@ -181,6 +163,7 @@ static char *ca_usage[]={ " -keyform arg - private key file format (PEM or ENGINE)\n", " -key arg - key to decode the private key if it is encrypted\n", " -cert file - The CA certificate\n", +" -selfsign - sign a certificate with the key associated with it\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", @@ -193,10 +176,14 @@ static char *ca_usage[]={ " -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", +" -utf8 - input characters are UTF8 (default ASCII)\n", +" -multivalue-rdn - enable support for multivalued RDNs\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", +#ifndef OPENSSL_NO_ENGINE " -engine e - use engine e, possibly a hardware device.\n", +#endif " -status serial - Shows certificate status given the serial number\n", " -updatedb - Updates db for expired certificates\n", NULL @@ -208,47 +195,43 @@ extern int EF_PROTECT_BELOW; 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 void lookup_fail(const char *name, const char *tag); 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, int email_dn, char *startdate, + const EVP_MD *dgst,STACK_OF(OPENSSL_STRING) *sigopts, + STACK_OF(CONF_VALUE) *policy,CA_DB *db, + BIGNUM *serial, char *subj,unsigned long chtype, int multirdn, 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); + int default_op, int ext_copy, int selfsign); 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, + const EVP_MD *dgst,STACK_OF(OPENSSL_STRING) *sigopts, + STACK_OF(CONF_VALUE) *policy, + CA_DB *db, BIGNUM *serial, char *subj,unsigned long chtype, int multirdn, 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, + const EVP_MD *dgst,STACK_OF(OPENSSL_STRING) *sigopts, + STACK_OF(CONF_VALUE) *policy, + CA_DB *db, BIGNUM *serial,char *subj,unsigned long chtype, int multirdn, 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(OPENSSL_STRING) *sigopts, + STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial,char *subj,unsigned long chtype, int multirdn, 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 check_time_format(char *str); + int ext_copy, int selfsign); +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(const char *str); char *make_revocation_str(int rev_type, char *rev_arg); -int make_revoked(X509_REVOKED *rev, char *str); +int make_revoked(X509_REVOKED *rev, const char *str); int old_entry_print(BIO *bp, ASN1_OBJECT *obj, ASN1_STRING *str); static CONF *conf=NULL; static CONF *extconf=NULL; @@ -257,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 **); @@ -269,6 +247,7 @@ int MAIN(int argc, char **argv) { ENGINE *e = NULL; char *key=NULL,*passargin=NULL; + int create_ser = 0; int free_key = 0; int total=0; int total_done=0; @@ -282,6 +261,7 @@ int MAIN(int argc, char **argv) int doupdatedb=0; long crldays=0; long crlhours=0; + long crlsec=0; long errorline= -1; char *configfile=NULL; char *md=NULL; @@ -298,14 +278,18 @@ int MAIN(int argc, char **argv) char *outfile=NULL; char *outdir=NULL; char *serialfile=NULL; + char *crlnumberfile=NULL; char *extensions=NULL; char *extfile=NULL; char *subj=NULL; + unsigned long chtype = MBSTRING_ASC; + int multirdn = 0; char *tmp_email_dn=NULL; char *crl_ext=NULL; int rev_type = REV_NONE; char *rev_arg = NULL; BIGNUM *serial=NULL; + BIGNUM *crlnumber=NULL; char *startdate=NULL; char *enddate=NULL; long days=0; @@ -314,27 +298,33 @@ int MAIN(int argc, char **argv) unsigned long nameopt = 0, certopt = 0; int default_op = 1; int ext_copy = EXT_COPY_NONE; - X509 *x509=NULL; + int selfsign = 0; + X509 *x509=NULL, *x509p = NULL; 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; + char *f; + const char *p; + char * const *pp; int i,j; - long l; const EVP_MD *dgst=NULL; STACK_OF(CONF_VALUE) *attribs=NULL; STACK_OF(X509) *cert_sk=NULL; + STACK_OF(OPENSSL_STRING) *sigopts = NULL; #undef BSIZE #define BSIZE 256 MS_STATIC char buf[3][BSIZE]; char *randfile=NULL; +#ifndef OPENSSL_NO_ENGINE char *engine = NULL; +#endif char *tofree=NULL; + DB_ATTR db_attr; #ifdef EFENCE EF_PROTECT_FREE=1; @@ -376,6 +366,12 @@ EF_ALIGNMENT=0; subj= *(++argv); /* preserve=1; */ } + else if (strcmp(*argv,"-utf8") == 0) + chtype = MBSTRING_UTF8; + else if (strcmp(*argv,"-create_serial") == 0) + create_ser = 1; + else if (strcmp(*argv,"-multivalue-rdn") == 0) + multirdn=1; else if (strcmp(*argv,"-startdate") == 0) { if (--argc < 1) goto bad; @@ -426,6 +422,8 @@ EF_ALIGNMENT=0; if (--argc < 1) goto bad; certfile= *(++argv); } + else if (strcmp(*argv,"-selfsign") == 0) + selfsign=1; else if (strcmp(*argv,"-in") == 0) { if (--argc < 1) goto bad; @@ -442,6 +440,15 @@ EF_ALIGNMENT=0; if (--argc < 1) goto bad; outdir= *(++argv); } + else if (strcmp(*argv,"-sigopt") == 0) + { + if (--argc < 1) + goto bad; + if (!sigopts) + sigopts = sk_OPENSSL_STRING_new_null(); + if (!sigopts || !sk_OPENSSL_STRING_push(sigopts, *(++argv))) + goto bad; + } else if (strcmp(*argv,"-notext") == 0) notext=1; else if (strcmp(*argv,"-batch") == 0) @@ -464,6 +471,11 @@ EF_ALIGNMENT=0; if (--argc < 1) goto bad; crlhours= atol(*(++argv)); } + else if (strcmp(*argv,"-crlsec") == 0) + { + if (--argc < 1) goto bad; + crlsec = atol(*(++argv)); + } else if (strcmp(*argv,"-infiles") == 0) { argc--; @@ -489,6 +501,12 @@ EF_ALIGNMENT=0; infile= *(++argv); dorevoke=1; } + else if (strcmp(*argv,"-valid") == 0) + { + if (--argc < 1) goto bad; + infile= *(++argv); + dorevoke=2; + } else if (strcmp(*argv,"-extensions") == 0) { if (--argc < 1) goto bad; @@ -537,11 +555,13 @@ EF_ALIGNMENT=0; rev_arg = *(++argv); rev_type = REV_CA_COMPROMISE; } +#ifndef OPENSSL_NO_ENGINE else if (strcmp(*argv,"-engine") == 0) { if (--argc < 1) goto bad; engine= *(++argv); } +#endif else { bad: @@ -555,15 +575,15 @@ bad: if (badops) { - for (pp=ca_usage; (*pp != NULL); pp++) - BIO_printf(bio_err,"%s",*pp); + const char **pp2; + + for (pp2=ca_usage; (*pp2 != NULL); pp2++) + BIO_printf(bio_err,"%s",*pp2); goto err; } ERR_load_crypto_strings(); - e = setup_engine(bio_err, engine, 0); - /*****************************************************************/ tofree=NULL; if (configfile == NULL) configfile = getenv("OPENSSL_CONF"); @@ -571,16 +591,19 @@ bad: if (configfile == NULL) { const char *s=X509_get_default_cert_area(); + size_t len; #ifdef OPENSSL_SYS_VMS - tofree=OPENSSL_malloc(strlen(s)+sizeof(CONFIG_FILE)); + len = strlen(s)+sizeof(CONFIG_FILE); + tofree=OPENSSL_malloc(len); strcpy(tofree,s); #else - tofree=OPENSSL_malloc(strlen(s)+sizeof(CONFIG_FILE)+1); - strcpy(tofree,s); - strcat(tofree,"/"); + len = strlen(s)+sizeof(CONFIG_FILE)+1; + tofree=OPENSSL_malloc(len); + BUF_strlcpy(tofree,s,len); + BUF_strlcat(tofree,"/",len); #endif - strcat(tofree,CONFIG_FILE); + BUF_strlcat(tofree,CONFIG_FILE,len); configfile=tofree; } @@ -605,6 +628,10 @@ bad: if (!load_config(bio_err, conf)) goto err; +#ifndef OPENSSL_NO_ENGINE + e = setup_engine(bio_err, engine, 0); +#endif + /* Lets get the config section we are using */ if (section == NULL) { @@ -651,6 +678,43 @@ bad: if (randfile == NULL) ERR_clear_error(); app_RAND_load_file(randfile, bio_err, 0); + + f = NCONF_get_string(conf, section, STRING_MASK); + if (!f) + ERR_clear_error(); + + if(f && !ASN1_STRING_set_default_mask_asc(f)) { + BIO_printf(bio_err, "Invalid global string mask setting %s\n", f); + goto err; + } + + if (chtype != MBSTRING_UTF8){ + f = NCONF_get_string(conf, section, UTF8_IN); + if (!f) + ERR_clear_error(); + else if (!strcmp(f, "yes")) + chtype = MBSTRING_UTF8; + } + + db_attr.unique_subject = 1; + p = NCONF_get_string(conf, section, ENV_UNIQUE_SUBJECT); + if (p) + { +#ifdef RL_DEBUG + BIO_printf(bio_err, "DEBUG: unique_subject = \"%s\"\n", p); +#endif + db_attr.unique_subject = parse_yesno(p,1); + } + else + ERR_clear_error(); +#ifdef RL_DEBUG + if (!p) + BIO_printf(bio_err, "DEBUG: unique_subject undefined\n", p); +#endif +#ifdef RL_DEBUG + BIO_printf(bio_err, "DEBUG: configured unique_subject is %d\n", + db_attr.unique_subject); +#endif in=BIO_new(BIO_s_file()); out=BIO_new(BIO_s_file()); @@ -671,17 +735,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", @@ -690,7 +747,7 @@ bad: } /*****************************************************************/ - /* we definitely need a public key, so let's get it */ + /* we definitely need a private key, so let's get it */ if ((keyfile == NULL) && ((keyfile=NCONF_get_string(conf, section,ENV_PRIVATE_KEY)) == NULL)) @@ -718,22 +775,27 @@ bad: /*****************************************************************/ /* we need a certificate */ - if ((certfile == NULL) && ((certfile=NCONF_get_string(conf, - section,ENV_CERTIFICATE)) == NULL)) + if (!selfsign || spkac_file || ss_cert_file || gencrl) { - lookup_fail(section,ENV_CERTIFICATE); - goto err; - } - x509=load_cert(bio_err, certfile, FORMAT_PEM, NULL, e, - "CA certificate"); - if (x509 == NULL) - goto err; + if ((certfile == NULL) + && ((certfile=NCONF_get_string(conf, + section,ENV_CERTIFICATE)) == NULL)) + { + lookup_fail(section,ENV_CERTIFICATE); + goto err; + } + 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,"CA certificate and CA private key do not match\n"); - goto err; + if (!X509_check_private_key(x509,pkey)) + { + BIO_printf(bio_err,"CA certificate and CA private key do not match\n"); + goto err; + } } + if (!selfsign) x509p = x509; f=NCONF_get_string(conf,BASE_SECTION,ENV_PRESERVE); if (f == NULL) @@ -791,7 +853,6 @@ bad: /* lookup where to write new certificates */ if ((outdir == NULL) && (req)) { - struct stat sb; if ((outdir=NCONF_get_string(conf,section,ENV_NEW_CERTS_DIR)) == NULL) @@ -810,27 +871,23 @@ bad: that to access(). However, time's too short to do that just now. */ +#ifndef _WIN32 if (access(outdir,R_OK|W_OK|X_OK) != 0) +#else + if (_access(outdir,R_OK|W_OK|X_OK) != 0) +#endif { BIO_printf(bio_err,"I am unable to access the %s directory\n",outdir); perror(outdir); goto err; } - if (stat(outdir,&sb) != 0) - { - BIO_printf(bio_err,"unable to stat(%s)\n",outdir); - perror(outdir); - goto err; - } -#ifdef S_IFDIR - if (!(sb.st_mode & S_IFDIR)) + if (app_isdir(outdir)<=0) { BIO_printf(bio_err,"%s need to be a directory\n",outdir); perror(outdir); goto err; } -#endif #endif } @@ -841,19 +898,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=sk_OPENSSL_PSTRING_value(db->db->data,i); if ((pp[DB_type][0] != DB_TYPE_REV) && (pp[DB_rev_date][0] != '\0')) { @@ -866,7 +917,7 @@ bad: BIO_printf(bio_err," in entry %d\n", i+1); goto err; } - if (!check_time_format(pp[DB_exp_date])) + if (!check_time_format((char *)pp[DB_exp_date])) { BIO_printf(bio_err,"entry %d: invalid expiry date\n",i+1); goto err; @@ -904,23 +955,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); + sk_OPENSSL_PSTRING_num(db->db->data)); 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 */ @@ -943,67 +984,13 @@ 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); } - goto err; } /*****************************************************************/ @@ -1054,25 +1041,38 @@ bad: } } - if (req) + if ((md == NULL) && ((md=NCONF_get_string(conf, + section,ENV_DEFAULT_MD)) == NULL)) { - if ((md == NULL) && ((md=NCONF_get_string(conf, - section,ENV_DEFAULT_MD)) == NULL)) + lookup_fail(section,ENV_DEFAULT_MD); + goto err; + } + + if (!strcmp(md, "default")) + { + int def_nid; + if (EVP_PKEY_get_default_digest_nid(pkey, &def_nid) <= 0) { - lookup_fail(section,ENV_DEFAULT_MD); + BIO_puts(bio_err,"no default digest\n"); goto err; } + md = (char *)OBJ_nid2sn(def_nid); + } + + if ((dgst=EVP_get_digestbyname(md)) == NULL) + { + BIO_printf(bio_err,"%s is an unsupported message digest type\n",md); + goto err; + } + + if (req) + { if ((email_dn == 1) && ((tmp_email_dn=NCONF_get_string(conf, section,ENV_DEFAULT_EMAIL_DN)) != NULL )) { if(strcmp(tmp_email_dn,"no") == 0) email_dn=0; } - if ((dgst=EVP_get_digestbyname(md)) == NULL) - { - BIO_printf(bio_err,"%s is an unsupported message digest type\n",md); - goto err; - } if (verbose) BIO_printf(bio_err,"message digest is %s\n", OBJ_nid2ln(dgst->type)); @@ -1128,9 +1128,9 @@ bad: if (startdate == NULL) ERR_clear_error(); } - if (startdate && !ASN1_UTCTIME_set_string(NULL,startdate)) + if (startdate && !ASN1_TIME_set_string(NULL, startdate)) { - BIO_printf(bio_err,"start date is invalid, it should be YYMMDDHHMMSSZ\n"); + BIO_printf(bio_err,"start date is invalid, it should be YYMMDDHHMMSSZ or YYYYMMDDHHMMSSZ\n"); goto err; } if (startdate == NULL) startdate="today"; @@ -1142,9 +1142,9 @@ bad: if (enddate == NULL) ERR_clear_error(); } - if (enddate && !ASN1_UTCTIME_set_string(NULL,enddate)) + if (enddate && !ASN1_TIME_set_string(NULL, enddate)) { - BIO_printf(bio_err,"end date is invalid, it should be YYMMDDHHMMSSZ\n"); + BIO_printf(bio_err,"end date is invalid, it should be YYMMDDHHMMSSZ or YYYYMMDDHHMMSSZ\n"); goto err; } @@ -1159,7 +1159,7 @@ bad: goto err; } - if ((serial=load_serial(serialfile)) == NULL) + if ((serial=load_serial(serialfile, create_ser, NULL)) == NULL) { BIO_printf(bio_err,"error while loading serial number\n"); goto err; @@ -1190,8 +1190,9 @@ bad: if (spkac_file != NULL) { total++; - j=certify_spkac(&x,spkac_file,pkey,x509,dgst,attribs,db, - serial,subj,email_dn,startdate,enddate,days,extensions, + j=certify_spkac(&x,spkac_file,pkey,x509,dgst,sigopts, + attribs,db, serial,subj,chtype,multirdn, + email_dn,startdate,enddate,days,extensions, conf,verbose,certopt,nameopt,default_op,ext_copy); if (j < 0) goto err; if (j > 0) @@ -1214,8 +1215,9 @@ bad: if (ss_cert_file != NULL) { total++; - j=certify_cert(&x,ss_cert_file,pkey,x509,dgst,attribs, - db,serial,subj,email_dn,startdate,enddate,days,batch, + j=certify_cert(&x,ss_cert_file,pkey,x509,dgst,sigopts, + attribs, + db,serial,subj,chtype,multirdn,email_dn,startdate,enddate,days,batch, extensions,conf,verbose, certopt, nameopt, default_op, ext_copy, e); if (j < 0) goto err; @@ -1234,10 +1236,10 @@ bad: if (infile != NULL) { total++; - j=certify(&x,infile,pkey,x509,dgst,attribs,db, - serial,subj,email_dn,startdate,enddate,days,batch, + j=certify(&x,infile,pkey,x509p,dgst,sigopts, attribs,db, + serial,subj,chtype,multirdn,email_dn,startdate,enddate,days,batch, extensions,conf,verbose, certopt, nameopt, - default_op, ext_copy); + default_op, ext_copy, selfsign); if (j < 0) goto err; if (j > 0) { @@ -1254,10 +1256,10 @@ bad: for (i=0; i 0) { @@ -1282,7 +1284,12 @@ bad: BIO_printf(bio_err,"\n%d out of %d certificate requests certified, commit? [y/n]",total_done,total); (void)BIO_flush(bio_err); buf[0][0]='\0'; - fgets(buf[0],10,stdin); + if (!fgets(buf[0],10,stdin)) + { + BIO_printf(bio_err,"CERTIFICATION CANCELED: I/O error\n"); + ret=0; + goto err; + } if ((buf[0][0] != 'y') && (buf[0][0] != 'Y')) { BIO_printf(bio_err,"CERTIFICATION CANCELED\n"); @@ -1293,38 +1300,9 @@ bad: BIO_printf(bio_err,"Write out database with %d new entries\n",sk_X509_num(cert_sk)); - if(strlen(serialfile) > BSIZE-5 || strlen(dbfile) > BSIZE-5) - { - BIO_printf(bio_err,"file name too long\n"); - goto err; - } - - strcpy(buf[0],serialfile); - -#ifdef OPENSSL_SYS_VMS - strcat(buf[0],"-new"); -#else - strcat(buf[0],".new"); -#endif - - if (!save_serial(buf[0],serial)) goto err; - - strcpy(buf[1],dbfile); + if (!save_serial(serialfile,"new",serial,NULL)) goto err; -#ifdef OPENSSL_SYS_VMS - strcat(buf[1],"-new"); -#else - strcat(buf[1],".new"); -#endif - - 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) @@ -1332,12 +1310,12 @@ bad: for (i=0; icert_info->serialNumber->length; - p=(char *)x->cert_info->serialNumber->data; + p=(const char *)x->cert_info->serialNumber->data; if(strlen(outdir) >= (size_t)(j ? BSIZE-j*2-6 : BSIZE-8)) { @@ -1348,15 +1326,19 @@ bad: strcpy(buf[2],outdir); #ifndef OPENSSL_SYS_VMS - strcat(buf[2],"/"); + BUF_strlcat(buf[2],"/",sizeof(buf[2])); #endif - n=(unsigned char *)&(buf[2][strlen(buf[2])]); + n=(char *)&(buf[2][strlen(buf[2])]); if (j > 0) { for (k=0; k= &(buf[2][sizeof(buf[2])])) + break; + BIO_snprintf(n, + &buf[2][0] + sizeof(buf[2]) - n, + "%02X",(unsigned char)*(p++)); n+=2; } } @@ -1382,59 +1364,10 @@ bad: if (sk_X509_num(cert_sk)) { /* Rename the database and the serial file */ - strncpy(buf[2],serialfile,BSIZE-4); - buf[2][BSIZE-4]='\0'; + if (!rotate_serial(serialfile,"new","old")) goto err; -#ifdef OPENSSL_SYS_VMS - strcat(buf[2],"-old"); -#else - strcat(buf[2],".old"); -#endif + if (!rotate_index(dbfile,"new","old")) goto err; - BIO_free(in); - BIO_free_all(out); - in=NULL; - out=NULL; - if (rename(serialfile,buf[2]) < 0) - { - BIO_printf(bio_err,"unable to rename %s to %s\n", - serialfile,buf[2]); - perror("reason"); - goto err; - } - if (rename(buf[0],serialfile) < 0) - { - BIO_printf(bio_err,"unable to rename %s to %s\n", - buf[0],serialfile); - perror("reason"); - rename(buf[2],serialfile); - 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 (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"); } } @@ -1465,7 +1398,15 @@ bad: } } - if (!crldays && !crlhours) + if ((crlnumberfile=NCONF_get_string(conf,section,ENV_CRLNUMBER)) + != NULL) + if ((crlnumber=load_serial(crlnumberfile,0,NULL)) == NULL) + { + BIO_printf(bio_err,"error while loading CRL number\n"); + goto err; + } + + if (!crldays && !crlhours && !crlsec) { if (!NCONF_get_number(conf,section, ENV_DEFAULT_CRL_DAYS, &crldays)) @@ -1473,8 +1414,9 @@ bad: if (!NCONF_get_number(conf,section, ENV_DEFAULT_CRL_HOURS, &crlhours)) crlhours = 0; + ERR_clear_error(); } - if ((crldays == 0) && (crlhours == 0)) + if ((crldays == 0) && (crlhours == 0) && (crlsec == 0)) { BIO_printf(bio_err,"cannot lookup how long until the next CRL is issued\n"); goto err; @@ -1488,14 +1430,19 @@ bad: if (!tmptm) goto err; X509_gmtime_adj(tmptm,0); X509_CRL_set_lastUpdate(crl, tmptm); - X509_gmtime_adj(tmptm,(crldays*24+crlhours)*60*60); + if (!X509_time_adj_ex(tmptm, crldays, crlhours*60*60 + crlsec, + NULL)) + { + BIO_puts(bio_err, "error setting CRL nextUpdate\n"); + goto err; + } X509_CRL_set_nextUpdate(crl, tmptm); ASN1_TIME_free(tmptm); - for (i=0; idata); i++) + for (i=0; idb->data); i++) { - pp=(char **)sk_value(db->data,i); + pp=sk_OPENSSL_PSTRING_value(db->db->data,i); if (pp[DB_type][0] == DB_TYPE_REV) { if ((r=X509_REVOKED_new()) == NULL) goto err; @@ -1521,39 +1468,27 @@ bad: /* we now have a CRL */ if (verbose) BIO_printf(bio_err,"signing CRL\n"); - if (md != NULL) - { - if ((dgst=EVP_get_digestbyname(md)) == NULL) - { - BIO_printf(bio_err,"%s is an unsupported message digest type\n",md); - goto err; - } - } - else - { -#ifndef OPENSSL_NO_DSA - if (pkey->type == EVP_PKEY_DSA) - dgst=EVP_dss1(); - else -#endif -#ifndef OPENSSL_NO_ECDSA - if (pkey->type == EVP_PKEY_EC) - dgst=EVP_ecdsa(); - else -#endif - dgst=EVP_md5(); - } /* Add any extensions asked for */ - if (crl_ext) + if (crl_ext || crlnumberfile != NULL) { X509V3_CTX crlctx; 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) + if (!X509V3_EXT_CRL_add_nconf(conf, &crlctx, + crl_ext, crl)) goto err; + if (crlnumberfile != NULL) + { + tmpser = BN_to_ASN1_INTEGER(crlnumber, NULL); + if (!tmpser) goto err; + X509_CRL_add1_ext_i2d(crl,NID_crl_number,tmpser,0,0); + ASN1_INTEGER_free(tmpser); + crl_v2 = 1; + if (!BN_add_word(crlnumber,1)) goto err; + } } if (crl_ext || crl_v2) { @@ -1561,9 +1496,23 @@ bad: goto err; /* version 2 CRL */ } - if (!X509_CRL_sign(crl,pkey,dgst)) goto err; + + if (crlnumberfile != NULL) /* we have a CRL number that need updating */ + if (!save_serial(crlnumberfile,"new",crlnumber,NULL)) goto err; + + if (crlnumber) + { + BN_free(crlnumber); + crlnumber = NULL; + } + + if (!do_X509_CRL_sign(bio_err,crl,pkey,dgst,sigopts)) goto err; PEM_write_bio_X509_CRL(Sout,crl); + + if (crlnumberfile != NULL) /* Rename the crlnumber file */ + if (!rotate_serial(crlnumberfile,"new","old")) goto err; + } /*****************************************************************/ if (dorevoke) @@ -1580,54 +1529,16 @@ bad: NULL, e, infile); if (revcert == NULL) goto err; + if (dorevoke == 2) + rev_type = -1; j=do_revoke(revcert,db, rev_type, rev_arg); 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"); } } @@ -1641,132 +1552,41 @@ err: BIO_free_all(out); BIO_free_all(in); - sk_X509_pop_free(cert_sk,X509_free); + if (cert_sk) + sk_X509_pop_free(cert_sk,X509_free); if (ret) ERR_print_errors(bio_err); app_RAND_write_file(randfile, bio_err); if (free_key && key) OPENSSL_free(key); BN_free(serial); - TXT_DB_free(db); + BN_free(crlnumber); + free_index(db); + if (sigopts) + sk_OPENSSL_STRING_free(sigopts); EVP_PKEY_free(pkey); - X509_free(x509); + if (x509) X509_free(x509); X509_CRL_free(crl); NCONF_free(conf); + NCONF_free(extconf); OBJ_cleanup(); apps_shutdown(); OPENSSL_EXIT(ret); } -static void lookup_fail(char *name, char *tag) +static void lookup_fail(const char *name, const 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, - BIGNUM *serial, char *subj, int email_dn, char *startdate, char *enddate, + const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts, + STACK_OF(CONF_VALUE) *policy, CA_DB *db, + BIGNUM *serial, char *subj,unsigned long chtype, int multirdn, + 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, - int ext_copy) + int ext_copy, int selfsign) { X509_REQ *req=NULL; BIO *in=NULL; @@ -1791,6 +1611,12 @@ static int certify(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509, BIO_printf(bio_err,"Check that the request matches the signature\n"); + if (selfsign && !X509_REQ_check_private_key(req,pkey)) + { + BIO_printf(bio_err,"Certificate request and CA private key do not match\n"); + ok=0; + goto err; + } if ((pktmp=X509_REQ_get_pubkey(req)) == NULL) { BIO_printf(bio_err,"error unpacking public key\n"); @@ -1813,9 +1639,10 @@ static int certify(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509, else BIO_printf(bio_err,"Signature ok\n"); - ok=do_body(xret,pkey,x509,dgst,policy,db,serial,subj, email_dn, + ok=do_body(xret,pkey,x509,dgst,sigopts, policy,db,serial,subj,chtype, + multirdn, email_dn, startdate,enddate,days,batch,verbose,req,ext_sect,lconf, - certopt, nameopt, default_op, ext_copy); + certopt, nameopt, default_op, ext_copy, selfsign); err: if (req != NULL) X509_REQ_free(req); @@ -1824,8 +1651,9 @@ 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, - BIGNUM *serial, char *subj, int email_dn, char *startdate, char *enddate, + const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts, + STACK_OF(CONF_VALUE) *policy, CA_DB *db, + BIGNUM *serial, char *subj, unsigned long chtype, int multirdn, 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, int ext_copy, ENGINE *e) @@ -1867,9 +1695,9 @@ static int certify_cert(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509, if ((rreq=X509_to_X509_REQ(req,NULL,EVP_md5())) == NULL) goto err; - ok=do_body(xret,pkey,x509,dgst,policy,db,serial,subj,email_dn,startdate,enddate, + ok=do_body(xret,pkey,x509,dgst,sigopts,policy,db,serial,subj,chtype,multirdn,email_dn,startdate,enddate, days,batch,verbose,rreq,ext_sect,lconf, certopt, nameopt, default_op, - ext_copy); + ext_copy, 0); err: if (rreq != NULL) X509_REQ_free(rreq); @@ -1878,11 +1706,13 @@ 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(OPENSSL_STRING) *sigopts, STACK_OF(CONF_VALUE) *policy, + CA_DB *db, BIGNUM *serial, char *subj, + unsigned long chtype, int multirdn, 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, - int ext_copy) + int ext_copy, int selfsign) { X509_NAME *name=NULL,*CAname=NULL,*subject=NULL, *dn_subject=NULL; ASN1_UTCTIME *tm,*tmptm; @@ -1894,9 +1724,11 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst, X509_NAME_ENTRY *tne,*push; EVP_PKEY *pktmp; int ok= -1,i,j,last,nid; - char *p; + const char *p; CONF_VALUE *cv; - char *row[DB_NUMBER],**rrow,**irow=NULL; + OPENSSL_STRING row[DB_NUMBER]; + OPENSSL_STRING *irow=NULL; + OPENSSL_STRING *rrow=NULL; char buf[25]; tmptm=ASN1_UTCTIME_new(); @@ -1911,7 +1743,7 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst, if (subj) { - X509_NAME *n = do_subject(subj, MBSTRING_ASC); + X509_NAME *n = parse_name(subj, chtype, multirdn); if (!n) { @@ -1986,7 +1818,10 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst, } /* take a copy of the issuer name before we mess with it. */ - CAname=X509_NAME_dup(x509->cert_info->subject); + if (selfsign) + CAname=X509_NAME_dup(name); + else + CAname=X509_NAME_dup(x509->cert_info->subject); if (CAname == NULL) goto err; str=str2=NULL; @@ -2133,15 +1968,21 @@ 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]); + OPENSSL_STRING *crow=row; + + rrow=TXT_DB_get_by_index(db->db,DB_name,crow); + 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", @@ -2189,21 +2030,29 @@ again2: #ifdef X509_V3 /* Make it an X509 v3 certificate. */ - if (!X509_set_version(x509,2)) goto err; + if (!X509_set_version(ret,2)) goto err; #endif if (BN_to_ASN1_INTEGER(serial,ci->serialNumber) == NULL) goto err; - if (!X509_set_issuer_name(ret,X509_get_subject_name(x509))) - goto err; + if (selfsign) + { + if (!X509_set_issuer_name(ret,subject)) + goto err; + } + else + { + if (!X509_set_issuer_name(ret,X509_get_subject_name(x509))) + goto err; + } if (strcmp(startdate,"today") == 0) X509_gmtime_adj(X509_get_notBefore(ret),0); - else ASN1_UTCTIME_set_string(X509_get_notBefore(ret),startdate); + else ASN1_TIME_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); + X509_time_adj_ex(X509_get_notAfter(ret),days, 0, NULL); + else ASN1_TIME_set_string(X509_get_notAfter(ret),enddate); if (!X509_set_subject_name(ret,subject)) goto err; @@ -2230,7 +2079,10 @@ again2: ci->extensions = NULL; /* Initialize the context structure */ - X509V3_set_ctx(&ctx, x509, ret, req, NULL, 0); + if (selfsign) + X509V3_set_ctx(&ctx, ret, ret, req, NULL, 0); + else + X509V3_set_ctx(&ctx, x509, ret, req, NULL, 0); if (extconf) { @@ -2296,8 +2148,8 @@ again2: } 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); + ASN1_TIME_print(bio_err,X509_get_notAfter(ret)); + if (days) BIO_printf(bio_err," (%ld days)",days); BIO_printf(bio_err, "\n"); if (!batch) @@ -2306,7 +2158,12 @@ again2: BIO_printf(bio_err,"Sign the certificate? [y/n]:"); (void)BIO_flush(bio_err); buf[0]='\0'; - fgets(buf,sizeof(buf)-1,stdin); + if (!fgets(buf,sizeof(buf)-1,stdin)) + { + BIO_printf(bio_err,"CERTIFICATE WILL NOT BE CERTIFIED: I/O error\n"); + ok=0; + goto err; + } if (!((buf[0] == 'y') || (buf[0] == 'Y'))) { BIO_printf(bio_err,"CERTIFICATE WILL NOT BE CERTIFIED\n"); @@ -2315,27 +2172,13 @@ again2: } } - -#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 -#ifndef OPENSSL_NO_ECDSA - if (pkey->type == EVP_PKEY_EC) - dgst = EVP_ecdsa(); - 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)) + if (!do_X509_sign(bio_err, ret,pkey,dgst, sigopts)) goto err; /* We now just add it to the database */ @@ -2358,7 +2201,7 @@ again2: BIO_printf(bio_err,"Memory allocation failure\n"); goto err; } - strcpy(row[DB_file],"unknown"); + BUF_strlcpy(row[DB_file],"unknown",8); row[DB_type][0]='V'; row[DB_type][1]='\0'; @@ -2375,10 +2218,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; @@ -2429,13 +2272,14 @@ 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, - BIGNUM *serial, char *subj, int email_dn, char *startdate, char *enddate, + const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts, + STACK_OF(CONF_VALUE) *policy, CA_DB *db, + BIGNUM *serial, char *subj,unsigned long chtype, int multirdn, 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) { STACK_OF(CONF_VALUE) *sk=NULL; - LHASH *parms=NULL; + LHASH_OF(CONF_VALUE) *parms=NULL; X509_REQ *req=NULL; CONF_VALUE *cv=NULL; NETSCAPE_SPKI *spki = NULL; @@ -2522,25 +2366,9 @@ static int certify_spkac(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509, continue; } - /* - if ((nid == NID_pkcs9_emailAddress) && (email_dn == 0)) - continue; - */ - - j=ASN1_PRINTABLE_type((unsigned char *)buf,-1); - if (fix_data(nid, &j) == 0) - { - BIO_printf(bio_err, - "invalid characters in string %s\n",buf); + if (!X509_NAME_add_entry_by_NID(n, nid, chtype, + (unsigned char *)buf, -1, -1, 0)) goto err; - } - - if ((ne=X509_NAME_ENTRY_create_by_NID(&ne,nid,j, - (unsigned char *)buf, - strlen(buf))) == NULL) - goto err; - - if (!X509_NAME_add_entry(n,ne,-1, 0)) goto err; } if (spki == NULL) { @@ -2571,9 +2399,9 @@ static int certify_spkac(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509, X509_REQ_set_pubkey(req,pktmp); EVP_PKEY_free(pktmp); - ok=do_body(xret,pkey,x509,dgst,policy,db,serial,subj,email_dn,startdate,enddate, - days,1,verbose,req,ext_sect,lconf, certopt, nameopt, default_op, - ext_copy); + ok=do_body(xret,pkey,x509,dgst,sigopts,policy,db,serial,subj,chtype, + multirdn,email_dn,startdate,enddate, days,1,verbose,req, + ext_sect,lconf, certopt, nameopt, default_op, ext_copy, 0); err: if (req != NULL) X509_REQ_free(req); if (parms != NULL) CONF_free(parms); @@ -2583,32 +2411,12 @@ err: return(ok); } -static int fix_data(int nid, int *type) +static int check_time_format(const char *str) { - if (nid == NID_pkcs9_emailAddress) - *type=V_ASN1_IA5STRING; - if ((nid == NID_commonName) && (*type == V_ASN1_IA5STRING)) - *type=V_ASN1_T61STRING; - if ((nid == NID_pkcs9_challengePassword) && (*type == V_ASN1_IA5STRING)) - *type=V_ASN1_T61STRING; - if ((nid == NID_pkcs9_unstructuredName) && (*type == V_ASN1_T61STRING)) - return(0); - if (nid == NID_pkcs9_unstructuredName) - *type=V_ASN1_IA5STRING; - return(1); + return ASN1_TIME_set_string(NULL, str); } -static int check_time_format(char *str) - { - ASN1_UTCTIME tm; - - 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) +static int do_revoke(X509 *x509, CA_DB *db, int type, char *value) { ASN1_UTCTIME *tm=NULL; char *row[DB_NUMBER],**rrow,**irow; @@ -2620,6 +2428,8 @@ static int do_revoke(X509 *x509, TXT_DB *db, int type, char *value) row[i]=NULL; row[DB_name]=X509_NAME_oneline(X509_get_subject_name(x509),NULL,0); bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(x509),NULL); + if (!bn) + goto err; if (BN_is_zero(bn)) row[DB_serial]=BUF_strdup("00"); else @@ -2633,10 +2443,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); @@ -2659,7 +2469,7 @@ static int do_revoke(X509 *x509, TXT_DB *db, int type, char *value) BIO_printf(bio_err,"Memory allocation failure\n"); goto err; } - strcpy(row[DB_file],"unknown"); + BUF_strlcpy(row[DB_file],"unknown",8); row[DB_type][0]='V'; row[DB_type][1]='\0'; @@ -2676,25 +2486,34 @@ 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; } /* Revoke Certificate */ - ok = do_revoke(x509,db, type, value); + if (type == -1) + ok = 1; + else + ok = do_revoke(x509,db, type, value); goto err; } - else if (index_name_cmp((const char **)row,(const char **)rrow)) + else if (index_name_cmp_noconst(row, rrow)) { BIO_printf(bio_err,"ERROR:name does not match %s\n", row[DB_name]); goto err; } + else if (type == -1) + { + BIO_printf(bio_err,"ERROR:Already present, serial number %s\n", + row[DB_serial]); + goto err; + } else if (rrow[DB_type][0]=='R') { BIO_printf(bio_err,"ERROR:Already revoked, serial number %s\n", @@ -2724,7 +2543,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; @@ -2759,13 +2578,13 @@ static int get_certificate_status(const char *serial, TXT_DB *db) /* Make it Upper Case */ for (i=0; row[DB_serial][i] != '\0'; i++) - row[DB_serial][i] = toupper(row[DB_serial][i]); + row[DB_serial][i] = toupper((unsigned char)row[DB_serial][i]); 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", @@ -2812,7 +2631,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; @@ -2838,9 +2657,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_OPENSSL_PSTRING_num(db->db->data); i++) { - rrow = (char **) sk_value(db->data, i); + rrow = sk_OPENSSL_PSTRING_value(db->db->data, i); if (rrow[DB_type][0] == 'V') { @@ -2884,7 +2703,7 @@ err: return (cnt); } -static char *crl_reasons[] = { +static const char *crl_reasons[] = { /* CRL reason strings */ "unspecified", "keyCompromise", @@ -2912,7 +2731,8 @@ static char *crl_reasons[] = { char *make_revocation_str(int rev_type, char *rev_arg) { - char *reason = NULL, *other = NULL, *str; + char *other = NULL, *str; + const char *reason = NULL; ASN1_OBJECT *otmp; ASN1_UTCTIME *revtm = NULL; int i; @@ -2983,16 +2803,16 @@ char *make_revocation_str(int rev_type, char *rev_arg) if (!str) return NULL; - strcpy(str, (char *)revtm->data); + BUF_strlcpy(str, (char *)revtm->data, i); if (reason) { - strcat(str, ","); - strcat(str, reason); + BUF_strlcat(str, ",", i); + BUF_strlcat(str, reason, i); } if (other) { - strcat(str, ","); - strcat(str, other); + BUF_strlcat(str, ",", i); + BUF_strlcat(str, other, i); } ASN1_UTCTIME_free(revtm); return str; @@ -3006,7 +2826,7 @@ char *make_revocation_str(int rev_type, char *rev_arg) */ -int make_revoked(X509_REVOKED *rev, char *str) +int make_revoked(X509_REVOKED *rev, const char *str) { char *tmp = NULL; int reason_code = -1; @@ -3060,129 +2880,6 @@ int make_revoked(X509_REVOKED *rev, char *str) return ret; } -/* - * subject is expected to be in the format /type0=value0/type1=value1/type2=... - * where characters may be escaped by \ - */ -X509_NAME *do_subject(char *subject, long chtype) - { - size_t buflen = strlen(subject)+1; /* to copy the types and values into. due to escaping, the copy can only become shorter */ - char *buf = OPENSSL_malloc(buflen); - size_t max_ne = buflen / 2 + 1; /* maximum number of name elements */ - char **ne_types = OPENSSL_malloc(max_ne * sizeof (char *)); - char **ne_values = OPENSSL_malloc(max_ne * sizeof (char *)); - - char *sp = subject, *bp = buf; - int i, ne_num = 0; - - X509_NAME *n = NULL; - int nid; - - if (!buf || !ne_types || !ne_values) - { - BIO_printf(bio_err, "malloc error\n"); - goto error; - } - - if (*subject != '/') - { - BIO_printf(bio_err, "Subject does not start with '/'.\n"); - goto error; - } - sp++; /* skip leading / */ - - while (*sp) - { - /* collect type */ - ne_types[ne_num] = bp; - while (*sp) - { - if (*sp == '\\') /* is there anything to escape in the type...? */ - { - if (*++sp) - *bp++ = *sp++; - else - { - BIO_printf(bio_err, "escape character at end of string\n"); - goto error; - } - } - else if (*sp == '=') - { - sp++; - *bp++ = '\0'; - break; - } - else - *bp++ = *sp++; - } - if (!*sp) - { - BIO_printf(bio_err, "end of string encountered while processing type of subject name element #%d\n", ne_num); - goto error; - } - ne_values[ne_num] = bp; - while (*sp) - { - if (*sp == '\\') - { - if (*++sp) - *bp++ = *sp++; - else - { - BIO_printf(bio_err, "escape character at end of string\n"); - goto error; - } - } - else if (*sp == '/') - { - sp++; - break; - } - else - *bp++ = *sp++; - } - *bp++ = '\0'; - ne_num++; - } - - if (!(n = X509_NAME_new())) - goto error; - - for (i = 0; i < ne_num; i++) - { - if ((nid=OBJ_txt2nid(ne_types[i])) == NID_undef) - { - BIO_printf(bio_err, "Subject Attribute %s has no known NID, skipped\n", ne_types[i]); - continue; - } - - if (!*ne_values[i]) - { - BIO_printf(bio_err, "No value provided for Subject Attribute %s, skipped\n", ne_types[i]); - continue; - } - - if (!X509_NAME_add_entry_by_NID(n, nid, chtype, (unsigned char*)ne_values[i], -1,-1,0)) - goto error; - } - - OPENSSL_free(ne_values); - OPENSSL_free(ne_types); - OPENSSL_free(buf); - return n; - -error: - X509_NAME_free(n); - if (ne_values) - OPENSSL_free(ne_values); - if (ne_types) - OPENSSL_free(ne_types); - if (buf) - OPENSSL_free(buf); - return NULL; -} - int old_entry_print(BIO *bp, ASN1_OBJECT *obj, ASN1_STRING *str) { char buf[25],*pbuf, *p; @@ -3222,12 +2919,13 @@ int old_entry_print(BIO *bp, ASN1_OBJECT *obj, ASN1_STRING *str) return 1; } -int unpack_revinfo(ASN1_TIME **prevtm, int *preason, ASN1_OBJECT **phold, ASN1_GENERALIZEDTIME **pinvtm, char *str) +int unpack_revinfo(ASN1_TIME **prevtm, int *preason, ASN1_OBJECT **phold, ASN1_GENERALIZEDTIME **pinvtm, const char *str) { char *tmp = NULL; char *rtime_str, *reason_str = NULL, *arg_str = NULL, *p; int reason_code = -1; - int i, ret = 0; + int ret = 0; + unsigned int i; ASN1_OBJECT *hold = NULL; ASN1_GENERALIZEDTIME *comp_time = NULL; tmp = BUF_strdup(str); @@ -3327,17 +3025,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; - }