X-Git-Url: https://git.openssl.org/gitweb/?a=blobdiff_plain;f=apps%2Fca.c;h=0ef23ad79fe54a45e97f34d203191663ae10d9ad;hb=5b7249f3021cb90bcdbd336c75c7699f8b8caf19;hp=7bee4b625bdd7fd5b7b55ac2a33d2beb15829c6c;hpb=ee306a13321e11b3e4c40960ccacc3dbbe33b9c8;p=openssl.git diff --git a/apps/ca.c b/apps/ca.c index 7bee4b625b..0ef23ad79f 100644 --- a/apps/ca.c +++ b/apps/ca.c @@ -64,7 +64,6 @@ #include #include #include -#include "apps.h" #include #include #include @@ -76,12 +75,15 @@ #include #include #include -#include #ifdef OPENSSL_SYS_WINDOWS #define strcasecmp _stricmp #else -#include +# ifdef NO_STRINGS_H + int strcasecmp(); +# else +# include +# endif /* NO_STRINGS_H */ #endif #ifndef W_OK @@ -91,11 +93,13 @@ # else # include # endif -# else +# elif !defined(OPENSSL_SYS_VXWORKS) && !defined(OPENSSL_SYS_WINDOWS) # include # endif #endif +#include "apps.h" + #ifndef W_OK # define F_OK 0 # define X_OK 1 @@ -127,6 +131,7 @@ #define ENV_DEFAULT_CRL_DAYS "default_crl_days" #define ENV_DEFAULT_CRL_HOURS "default_crl_hours" #define ENV_DEFAULT_MD "default_md" +#define ENV_DEFAULT_EMAIL_DN "email_in_dn" #define ENV_PRESERVE "preserve" #define ENV_POLICY "policy" #define ENV_EXTENSIONS "x509_extensions" @@ -183,6 +188,7 @@ static char *ca_usage[]={ " -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", +" -noemailDN - Don't add the EMAIL field into certificate' subject\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", @@ -212,32 +218,31 @@ static BIGNUM *load_serial(char *serialfile); static int save_serial(char *serialfile, BIGNUM *serial); static int certify(X509 **xret, char *infile,EVP_PKEY *pkey,X509 *x509, const EVP_MD *dgst,STACK_OF(CONF_VALUE) *policy,TXT_DB *db, - BIGNUM *serial, char *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); + 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, char *startdate, - char *enddate, long days, int batch, char *ext_sect, - CONF *conf,int verbose, unsigned long certopt, + TXT_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, 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); + TXT_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, - char *startdate, char *enddate, long days, int batch, int verbose, - X509_REQ *req, char *ext_sect, CONF *conf, + 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 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); @@ -264,10 +269,12 @@ int MAIN(int argc, char **argv) { ENGINE *e = NULL; char *key=NULL,*passargin=NULL; + int free_key = 0; int total=0; int total_done=0; int badops=0; int ret=1; + int email_dn=1; int req=0; int verbose=0; int gencrl=0; @@ -294,6 +301,7 @@ int MAIN(int argc, char **argv) char *extensions=NULL; char *extfile=NULL; char *subj=NULL; + char *tmp_email_dn=NULL; char *crl_ext=NULL; int rev_type = REV_NONE; char *rev_arg = NULL; @@ -312,8 +320,9 @@ int MAIN(int argc, char **argv) char *dbfile=NULL; TXT_DB *db=NULL; X509_CRL *crl=NULL; - X509_CRL_INFO *ci=NULL; X509_REVOKED *r=NULL; + ASN1_TIME *tmptm; + ASN1_INTEGER *tmpser; char **pp,*p,*f; int i,j; long l; @@ -325,6 +334,7 @@ int MAIN(int argc, char **argv) MS_STATIC char buf[3][BSIZE]; char *randfile=NULL; char *engine = NULL; + char *tofree=NULL; #ifdef EFENCE EF_PROTECT_FREE=1; @@ -438,6 +448,8 @@ EF_ALIGNMENT=0; batch=1; else if (strcmp(*argv,"-preserveDN") == 0) preserve=1; + else if (strcmp(*argv,"-noemailDN") == 0) + email_dn=0; else if (strcmp(*argv,"-gencrl") == 0) gencrl=1; else if (strcmp(*argv,"-msie_hack") == 0) @@ -550,24 +562,26 @@ bad: ERR_load_crypto_strings(); - e = setup_engine(bio_err, engine, 0); + e = setup_engine(bio_err, engine, 0); /*****************************************************************/ + tofree=NULL; 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. */ + const char *s=X509_get_default_cert_area(); + #ifdef OPENSSL_SYS_VMS - strncpy(buf[0],X509_get_default_cert_area(), - sizeof(buf[0])-1-sizeof(CONFIG_FILE)); + tofree=OPENSSL_malloc(strlen(s)+sizeof(CONFIG_FILE)); + strcpy(tofree,s); #else - strncpy(buf[0],X509_get_default_cert_area(), - sizeof(buf[0])-2-sizeof(CONFIG_FILE)); - strcat(buf[0],"/"); + tofree=OPENSSL_malloc(strlen(s)+sizeof(CONFIG_FILE)+1); + strcpy(tofree,s); + strcat(tofree,"/"); #endif - strcat(buf[0],CONFIG_FILE); - configfile=buf[0]; + strcat(tofree,CONFIG_FILE); + configfile=tofree; } BIO_printf(bio_err,"Using configuration from %s\n",configfile); @@ -582,6 +596,14 @@ bad: ,errorline,configfile); goto err; } + if(tofree) + { + OPENSSL_free(tofree); + tofree = NULL; + } + + if (!load_config(bio_err, conf)) + goto err; /* Lets get the config section we are using */ if (section == NULL) @@ -676,14 +698,18 @@ bad: lookup_fail(section,ENV_PRIVATE_KEY); goto err; } - if (!key && !app_passwd(bio_err, passargin, NULL, &key, NULL)) + if (!key) { - BIO_printf(bio_err,"Error getting password\n"); - goto err; + free_key = 1; + if (!app_passwd(bio_err, passargin, NULL, &key, NULL)) + { + BIO_printf(bio_err,"Error getting password\n"); + goto err; + } } - pkey = load_key(bio_err, keyfile, keyform, key, e, + pkey = load_key(bio_err, keyfile, keyform, 0, key, e, "CA private key"); - if (key) memset(key,0,strlen(key)); + if (key) OPENSSL_cleanse(key,strlen(key)); if (pkey == NULL) { /* load_key() has already printed an appropriate message */ @@ -998,7 +1024,7 @@ bad: } if (verbose) - BIO_printf(bio_err, "Succesfully loaded extensions file %s\n", extfile); + BIO_printf(bio_err, "Successfully loaded extensions file %s\n", extfile); /* We can have sections in the ext file */ if (!extensions && !(extensions = NCONF_get_string(extconf, "default", "extensions"))) @@ -1036,6 +1062,12 @@ bad: lookup_fail(section,ENV_DEFAULT_MD); goto err; } + 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); @@ -1134,9 +1166,14 @@ bad: } if (verbose) { - if ((f=BN_bn2hex(serial)) == NULL) goto err; - BIO_printf(bio_err,"next serial number is %s\n",f); - OPENSSL_free(f); + if (BN_is_zero(serial)) + BIO_printf(bio_err,"next serial number is 00\n"); + else + { + if ((f=BN_bn2hex(serial)) == NULL) goto err; + BIO_printf(bio_err,"next serial number is %s\n",f); + OPENSSL_free(f); + } } if ((attribs=NCONF_get_section(conf,policy)) == NULL) @@ -1154,8 +1191,8 @@ bad: { total++; j=certify_spkac(&x,spkac_file,pkey,x509,dgst,attribs,db, - serial,subj,startdate,enddate, days,extensions,conf, - verbose, certopt, nameopt, default_op, ext_copy); + serial,subj,email_dn,startdate,enddate,days,extensions, + conf,verbose,certopt,nameopt,default_op,ext_copy); if (j < 0) goto err; if (j > 0) { @@ -1178,7 +1215,7 @@ bad: { total++; j=certify_cert(&x,ss_cert_file,pkey,x509,dgst,attribs, - db,serial,subj,startdate,enddate,days,batch, + db,serial,subj,email_dn,startdate,enddate,days,batch, extensions,conf,verbose, certopt, nameopt, default_op, ext_copy, e); if (j < 0) goto err; @@ -1198,7 +1235,7 @@ bad: { total++; j=certify(&x,infile,pkey,x509,dgst,attribs,db, - serial,subj,startdate,enddate,days,batch, + serial,subj,email_dn,startdate,enddate,days,batch, extensions,conf,verbose, certopt, nameopt, default_op, ext_copy); if (j < 0) goto err; @@ -1218,7 +1255,7 @@ bad: { total++; j=certify(&x,argv[i],pkey,x509,dgst,attribs,db, - serial,subj,startdate,enddate,days,batch, + serial,subj,email_dn,startdate,enddate,days,batch, extensions,conf,verbose, certopt, nameopt, default_op, ext_copy); if (j < 0) goto err; @@ -1256,7 +1293,13 @@ bad: BIO_printf(bio_err,"Write out database with %d new entries\n",sk_X509_num(cert_sk)); - strncpy(buf[0],serialfile,BSIZE-4); + 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"); @@ -1266,7 +1309,7 @@ bad: if (!save_serial(buf[0],serial)) goto err; - strncpy(buf[1],dbfile,BSIZE-4); + strcpy(buf[1],dbfile); #ifdef OPENSSL_SYS_VMS strcat(buf[1],"-new"); @@ -1296,7 +1339,13 @@ bad: j=x->cert_info->serialNumber->length; p=(char *)x->cert_info->serialNumber->data; - strncpy(buf[2],outdir,BSIZE-(j*2)-6); + if(strlen(outdir) >= (size_t)(j ? BSIZE-j*2-6 : BSIZE-8)) + { + BIO_printf(bio_err,"certificate file name too long\n"); + goto err; + } + + strcpy(buf[2],outdir); #ifndef OPENSSL_SYS_VMS strcat(buf[2],"/"); @@ -1334,6 +1383,7 @@ bad: { /* Rename the database and the serial file */ strncpy(buf[2],serialfile,BSIZE-4); + buf[2][BSIZE-4]='\0'; #ifdef OPENSSL_SYS_VMS strcat(buf[2],"-old"); @@ -1362,6 +1412,7 @@ bad: } strncpy(buf[2],dbfile,BSIZE-4); + buf[2][BSIZE-4]='\0'; #ifdef OPENSSL_SYS_VMS strcat(buf[2],"-old"); @@ -1425,21 +1476,22 @@ bad: } if ((crldays == 0) && (crlhours == 0)) { - BIO_printf(bio_err,"cannot lookup how long until the next CRL is issuer\n"); + BIO_printf(bio_err,"cannot lookup how long until the next CRL is issued\n"); goto err; } if (verbose) BIO_printf(bio_err,"making CRL\n"); if ((crl=X509_CRL_new()) == NULL) goto err; - ci=crl->crl; - X509_NAME_free(ci->issuer); - ci->issuer=X509_NAME_dup(x509->cert_info->subject); - if (ci->issuer == NULL) goto err; + if (!X509_CRL_set_issuer_name(crl, X509_get_subject_name(x509))) goto err; + + tmptm = ASN1_TIME_new(); + if (!tmptm) goto err; + X509_gmtime_adj(tmptm,0); + X509_CRL_set_lastUpdate(crl, tmptm); + X509_gmtime_adj(tmptm,(crldays*24+crlhours)*60*60); + X509_CRL_set_nextUpdate(crl, tmptm); - 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); + ASN1_TIME_free(tmptm); for (i=0; idata); i++) { @@ -1452,22 +1504,20 @@ bad: if (j == 2) crl_v2 = 1; if (!BN_hex2bn(&serial, pp[DB_serial])) goto err; - r->serialNumber = BN_to_ASN1_INTEGER(serial, r->serialNumber); + tmpser = BN_to_ASN1_INTEGER(serial, NULL); BN_free(serial); serial = NULL; - if (!r->serialNumber) + if (!tmpser) goto err; + X509_REVOKED_set_serialNumber(r, tmpser); + ASN1_INTEGER_free(tmpser); X509_CRL_add0_revoked(crl,r); } } + /* sort the data so it will be written in serial * number order */ - sk_X509_REVOKED_sort(ci->revoked); - for (i=0; irevoked); i++) - { - r=sk_X509_REVOKED_value(ci->revoked,i); - r->sequence=i; - } + X509_CRL_sort(crl); /* we now have a CRL */ if (verbose) BIO_printf(bio_err,"signing CRL\n"); @@ -1485,6 +1535,11 @@ bad: 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(); } @@ -1494,8 +1549,6 @@ bad: 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); @@ -1504,9 +1557,8 @@ bad: } 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_set_version(crl, 1)) + goto err; /* version 2 CRL */ } if (!X509_CRL_sign(crl,pkey,dgst)) goto err; @@ -1532,7 +1584,13 @@ bad: if (j <= 0) goto err; X509_free(revcert); - strncpy(buf[0],dbfile,BSIZE-4); + if(strlen(dbfile) > BSIZE-5) + { + BIO_printf(bio_err,"filename too long\n"); + goto err; + } + + strcpy(buf[0],dbfile); #ifndef OPENSSL_SYS_VMS strcat(buf[0],".new"); #else @@ -1547,11 +1605,16 @@ bad: 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]); @@ -1571,6 +1634,8 @@ bad: /*****************************************************************/ ret=0; err: + if(tofree) + OPENSSL_free(tofree); BIO_free_all(Cout); BIO_free_all(Sout); BIO_free_all(out); @@ -1580,6 +1645,8 @@ err: 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); EVP_PKEY_free(pkey); @@ -1588,7 +1655,7 @@ err: NCONF_free(conf); OBJ_cleanup(); apps_shutdown(); - EXIT(ret); + OPENSSL_EXIT(ret); } static void lookup_fail(char *name, char *tag) @@ -1653,7 +1720,7 @@ static BIGNUM *load_serial(char *serialfile) ret=ASN1_INTEGER_to_BN(ai,NULL); if (ret == NULL) { - BIO_printf(bio_err,"error converting number from bin to BIGNUM"); + BIO_printf(bio_err,"error converting number from bin to BIGNUM\n"); goto err; } err: @@ -1696,8 +1763,8 @@ err: 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, + 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, int ext_copy) { @@ -1746,8 +1813,8 @@ 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,startdate, enddate, - days,batch,verbose,req,ext_sect,lconf, + ok=do_body(xret,pkey,x509,dgst,policy,db,serial,subj, email_dn, + startdate,enddate,days,batch,verbose,req,ext_sect,lconf, certopt, nameopt, default_op, ext_copy); err: @@ -1758,8 +1825,8 @@ 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, char *startdate, char *enddate, long days, - int batch, char *ext_sect, CONF *lconf, int verbose, + 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, int ext_copy, ENGINE *e) { @@ -1800,9 +1867,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,startdate,enddate,days, - batch,verbose,rreq,ext_sect,lconf, certopt, nameopt, default_op, - ext_copy); + ok=do_body(xret,pkey,x509,dgst,policy,db,serial,subj,email_dn,startdate,enddate, + days,batch,verbose,rreq,ext_sect,lconf, certopt, nameopt, default_op, + ext_copy); err: if (rreq != NULL) X509_REQ_free(rreq); @@ -1812,12 +1879,12 @@ 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, - char *startdate, char *enddate, long days, int batch, int verbose, - X509_REQ *req, char *ext_sect, CONF *lconf, + 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) { - X509_NAME *name=NULL,*CAname=NULL,*subject=NULL; + X509_NAME *name=NULL,*CAname=NULL,*subject=NULL, *dn_subject=NULL; ASN1_UTCTIME *tm,*tmptm; ASN1_STRING *str,*str2; ASN1_OBJECT *obj; @@ -1844,7 +1911,7 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst, if (subj) { - X509_NAME *n = do_subject(subj); + X509_NAME *n = do_subject(subj, MBSTRING_ASC); if (!n) { @@ -1858,6 +1925,7 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst, 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; itype=V_ASN1_IA5STRING; } + /* If no EMAIL is wanted in the subject */ + if ((OBJ_obj2nid(obj) == NID_pkcs9_emailAddress) && (!email_dn)) + continue; + /* check some things */ if ((OBJ_obj2nid(obj) == NID_pkcs9_emailAddress) && (str->type != V_ASN1_IA5STRING)) @@ -1889,14 +1961,17 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst, BIO_printf(bio_err,"\nemailAddress type needs to be of type IA5STRING\n"); goto err; } - j=ASN1_PRINTABLE_type(str->data,str->length); - if ( ((j == V_ASN1_T61STRING) && - (str->type != V_ASN1_T61STRING)) || - ((j == V_ASN1_IA5STRING) && - (str->type == V_ASN1_PRINTABLESTRING))) + if ((str->type != V_ASN1_BMPSTRING) && (str->type != V_ASN1_UTF8STRING)) { - BIO_printf(bio_err,"\nThe string contains characters that are illegal for the ASN.1 type\n"); - goto err; + j=ASN1_PRINTABLE_type(str->data,str->length); + if ( ((j == V_ASN1_T61STRING) && + (str->type != V_ASN1_T61STRING)) || + ((j == V_ASN1_IA5STRING) && + (str->type == V_ASN1_PRINTABLESTRING))) + { + BIO_printf(bio_err,"\nThe string contains characters that are illegal for the ASN.1 type\n"); + goto err; + } } if (default_op) @@ -2015,16 +2090,44 @@ again2: if (preserve) { X509_NAME_free(subject); - subject=X509_NAME_dup(X509_REQ_get_subject_name(req)); + /* subject=X509_NAME_dup(X509_REQ_get_subject_name(req)); */ + subject=X509_NAME_dup(name); if (subject == NULL) goto err; } if (verbose) 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_bn2hex(serial); - if ((row[DB_name] == NULL) || (row[DB_serial] == NULL)) + /* Build the correct Subject if no e-mail is wanted in the subject */ + /* and add it later on because of the method extensions are added (altName) */ + + if (email_dn) + dn_subject = subject; + else + { + X509_NAME_ENTRY *tmpne; + /* Its best to dup the subject DN and then delete any email + * addresses because this retains its structure. + */ + if (!(dn_subject = X509_NAME_dup(subject))) + { + BIO_printf(bio_err,"Memory allocation failure\n"); + goto err; + } + while((i = X509_NAME_get_index_by_NID(dn_subject, + NID_pkcs9_emailAddress, -1)) >= 0) + { + tmpne = X509_NAME_get_entry(dn_subject, i); + X509_NAME_delete_entry(dn_subject, i); + X509_NAME_ENTRY_free(tmpne); + } + } + + if (BN_is_zero(serial)) + row[DB_serial]=BUF_strdup("00"); + else + row[DB_serial]=BN_bn2hex(serial); + if (row[DB_serial] == NULL) { BIO_printf(bio_err,"Memory allocation failure\n"); goto err; @@ -2178,6 +2281,11 @@ again2: goto err; } + /* Set the right value for the noemailDN option */ + if( email_dn == 0 ) + { + if (!X509_set_subject_name(ret,dn_subject)) goto err; + } if (!default_op) { @@ -2216,6 +2324,16 @@ again2: 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)) goto err; @@ -2232,10 +2350,10 @@ again2: /* row[DB_serial] done already */ row[DB_file]=(char *)OPENSSL_malloc(8); - /* row[DB_name] done already */ + row[DB_name]=X509_NAME_oneline(X509_get_subject_name(ret),NULL,0); if ((row[DB_type] == NULL) || (row[DB_exp_date] == NULL) || - (row[DB_file] == NULL)) + (row[DB_file] == NULL) || (row[DB_name] == NULL)) { BIO_printf(bio_err,"Memory allocation failure\n"); goto err; @@ -2272,6 +2390,8 @@ err: X509_NAME_free(CAname); if (subject != NULL) X509_NAME_free(subject); + if ((dn_subject != NULL) && !email_dn) + X509_NAME_free(dn_subject); if (tmptm != NULL) ASN1_UTCTIME_free(tmptm); if (ok <= 0) @@ -2310,8 +2430,8 @@ 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, char *startdate, char *enddate, long days, - char *ext_sect, CONF *lconf, int verbose, unsigned long certopt, + 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) { STACK_OF(CONF_VALUE) *sk=NULL; @@ -2402,6 +2522,11 @@ 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) { @@ -2446,7 +2571,7 @@ 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,startdate,enddate, + 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); err: @@ -2495,7 +2620,10 @@ 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); - row[DB_serial]=BN_bn2hex(bn); + if (BN_is_zero(bn)) + row[DB_serial]=BUF_strdup("00"); + else + row[DB_serial]=BN_bn2hex(bn); BN_free(bn); if ((row[DB_name] == NULL) || (row[DB_serial] == NULL)) { @@ -2887,12 +3015,16 @@ int make_revoked(X509_REVOKED *rev, char *str) ASN1_GENERALIZEDTIME *comp_time = NULL; ASN1_ENUMERATED *rtmp = NULL; + ASN1_TIME *revDate = NULL; - i = unpack_revinfo(&rev->revocationDate, &reason_code, &hold, &comp_time, str); + i = unpack_revinfo(&revDate, &reason_code, &hold, &comp_time, str); if (i == 0) goto err; + if (rev && !X509_REVOKED_set_revocationDate(rev, revDate)) + goto err; + if (rev && (reason_code != OCSP_REVOKED_STATUS_NOSTATUS)) { rtmp = ASN1_ENUMERATED_new(); @@ -2923,69 +3055,133 @@ int make_revoked(X509_REVOKED *rev, char *str) ASN1_OBJECT_free(hold); ASN1_GENERALIZEDTIME_free(comp_time); ASN1_ENUMERATED_free(rtmp); + ASN1_TIME_free(revDate); return ret; } -static X509_NAME *do_subject(char *subject) +/* + * 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) { - X509_NAME *n = NULL; - - int i, nid, ne_num=0; - - char *ne_name = NULL; - char *ne_value = NULL; - - char *tmp = NULL; - char *p[2]; + 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 *str_list[256]; - - p[0] = ",/"; - p[1] = "="; + char *sp = subject, *bp = buf; + int i, ne_num = 0; - n = X509_NAME_new(); + X509_NAME *n = NULL; + int nid; - tmp = strtok(subject, p[0]); - while((tmp != NULL) && (ne_num < (sizeof str_list/sizeof *str_list))) + if (!buf || !ne_types || !ne_values) { - char *token = tmp; + BIO_printf(bio_err, "malloc error\n"); + goto error; + } - while (token[0] == ' ') - token++; - str_list[ne_num] = token; + if (*subject != '/') + { + BIO_printf(bio_err, "Subject does not start with '/'.\n"); + goto error; + } + sp++; /* skip leading / */ - tmp = strtok(NULL, p[0]); + 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++) { - ne_name = strtok(str_list[i], p[1]); - ne_value = strtok(NULL, p[1]); - - if ((nid=OBJ_txt2nid(ne_name)) == NID_undef) + if ((nid=OBJ_txt2nid(ne_types[i])) == NID_undef) { - BIO_printf(bio_err, "Subject Attribute %s has no known NID, skipped\n", ne_name); + BIO_printf(bio_err, "Subject Attribute %s has no known NID, skipped\n", ne_types[i]); continue; } - if (ne_value == NULL) + if (!*ne_values[i]) { - BIO_printf(bio_err, "No value provided for Subject Attribute %s, skipped\n", ne_name); + 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, MBSTRING_ASC, (unsigned char*)ne_value, -1,-1,0)) - { - X509_NAME_free(n); - return NULL; - } + 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) { @@ -3121,6 +3317,8 @@ int unpack_revinfo(ASN1_TIME **prevtm, int *preason, ASN1_OBJECT **phold, ASN1_G if (pinvtm) *pinvtm = comp_time; else ASN1_GENERALIZEDTIME_free(comp_time); + ret = 1; + err: if (tmp) OPENSSL_free(tmp);