From bad4058574a110c972616e4b2f629a6268322eb3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bodo=20M=C3=B6ller?= Date: Mon, 5 Mar 2001 11:09:43 +0000 Subject: [PATCH] New option '-subj arg' for 'openssl req' and 'openssl ca'. This sets the subject name for a new request or supersedes the subject name in a given request. Add options '-batch' and '-verbose' to 'openssl req'. Submitted by: Massimiliano Pala Reviewed by: Bodo Moeller --- CHANGES | 10 +++ apps/ca.c | 126 +++++++++++++++++++++----- apps/req.c | 209 +++++++++++++++++++++++++++++++++++-------- crypto/asn1/x_name.c | 9 +- doc/apps/ca.pod | 6 ++ doc/apps/req.pod | 16 ++++ 6 files changed, 315 insertions(+), 61 deletions(-) diff --git a/CHANGES b/CHANGES index 18c984c5c2..ec67a937da 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,16 @@ Changes between 0.9.6 and 0.9.7 [xx XXX 2000] + *) New option '-subj arg' for 'openssl req' and 'openssl ca'. This + sets the subject name for a new request or supersedes the + subject name in a given request. Formats that can be parsed are + 'CN=Some Name, OU=myOU, C=IT' + and + 'CN=Some Name/OU=myOU/C=IT'. + + Add options '-batch' and '-verbose' to 'openssl req'. + [Massimiliano Pala ] + *) Introduce the possibility to access global variables through functions on platform were that's the best way to handle exporting global variables in shared libraries. To enable this functionality, diff --git a/apps/ca.c b/apps/ca.c index d13b08f7e3..f0ed07feb1 100644 --- a/apps/ca.c +++ b/apps/ca.c @@ -183,6 +183,7 @@ static char *ca_usage[]={ " -batch - Don't ask questions\n", " -msie_hack - msie modifications to handle all those universal strings\n", " -revoke file - Revoke a certificate (given in file)\n", +" -subj arg - Use arg instead of request's subject\n", " -extensions .. - Extension section (override value in config file)\n", " -extfile file - Configuration file with X509v3 extentions to add\n", " -crlexts .. - CRL extension section (override value in config file)\n", @@ -208,24 +209,25 @@ static BIGNUM *load_serial(char *serialfile); static int save_serial(char *serialfile, BIGNUM *serial); static int certify(X509 **xret, char *infile,EVP_PKEY *pkey,X509 *x509, const EVP_MD *dgst,STACK_OF(CONF_VALUE) *policy,TXT_DB *db, - BIGNUM *serial, char *startdate,char *enddate, int days, - int batch, char *ext_sect, LHASH *conf,int verbose); + BIGNUM *serial, char *subj, char *startdate,char *enddate, + int days, int batch, char *ext_sect, LHASH *conf,int verbose); static int certify_cert(X509 **xret, char *infile,EVP_PKEY *pkey,X509 *x509, const EVP_MD *dgst,STACK_OF(CONF_VALUE) *policy, - TXT_DB *db, BIGNUM *serial,char *startdate, + TXT_DB *db, BIGNUM *serial, char *subj, char *startdate, char *enddate, int days, int batch, char *ext_sect, LHASH *conf,int verbose); static int certify_spkac(X509 **xret, char *infile,EVP_PKEY *pkey,X509 *x509, const EVP_MD *dgst,STACK_OF(CONF_VALUE) *policy, - TXT_DB *db, BIGNUM *serial,char *startdate, + TXT_DB *db, BIGNUM *serial,char *subj, char *startdate, char *enddate, int days, char *ext_sect,LHASH *conf, int verbose); static int fix_data(int nid, int *type); static void write_new_certificate(BIO *bp, X509 *x, int output_der, int notext); static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst, - STACK_OF(CONF_VALUE) *policy, TXT_DB *db, BIGNUM *serial, + STACK_OF(CONF_VALUE) *policy, TXT_DB *db, BIGNUM *serial,char *subj, char *startdate, char *enddate, int days, int batch, int verbose, X509_REQ *req, char *ext_sect, LHASH *conf); +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); @@ -280,6 +282,7 @@ int MAIN(int argc, char **argv) char *serialfile=NULL; char *extensions=NULL; char *extfile=NULL; + char *subj=NULL; char *crl_ext=NULL; int rev_type = REV_NONE; char *rev_arg = NULL; @@ -343,6 +346,12 @@ EF_ALIGNMENT=0; if (--argc < 1) goto bad; section= *(++argv); } + else if (strcmp(*argv,"-subj") == 0) + { + if (--argc < 1) goto bad; + subj= *(++argv); + /* preserve=1; */ + } else if (strcmp(*argv,"-startdate") == 0) { if (--argc < 1) goto bad; @@ -719,7 +728,7 @@ bad: lookup_fail(section,ENV_CERTIFICATE); goto err; } - if (BIO_read_filename(in,certfile) <= 0) + if (BIO_read_filename(in,certfile) <= 0) { perror(certfile); BIO_printf(bio_err,"trying to load CA certificate\n"); @@ -771,7 +780,7 @@ bad: C routines to convert the directory syntax to Unixly, and give that to access(). However, time's too short to do that just now. - */ + */ if (access(outdir,R_OK|W_OK|X_OK) != 0) { BIO_printf(bio_err,"I am unable to access the %s directory\n",outdir); @@ -902,9 +911,9 @@ bad: { BIO_printf(bio_err,"Malloc failure\n"); goto err; - } + } else if (i == 0) - { + { if (verbose) BIO_printf(bio_err, "No entries found to mark expired\n"); } @@ -987,7 +996,7 @@ bad: /* We can have sections in the ext file */ if (!extensions && !(extensions = CONF_get_string(extconf, "default", "extensions"))) extensions = "default"; - } + } /*****************************************************************/ if (req || gencrl) @@ -1138,7 +1147,7 @@ bad: { total++; j=certify_spkac(&x,spkac_file,pkey,x509,dgst,attribs,db, - serial,startdate,enddate, days,extensions,conf, + serial,subj,startdate,enddate, days,extensions,conf, verbose); if (j < 0) goto err; if (j > 0) @@ -1162,7 +1171,7 @@ bad: { total++; j=certify_cert(&x,ss_cert_file,pkey,x509,dgst,attribs, - db,serial,startdate,enddate,days,batch, + db,serial,subj,startdate,enddate,days,batch, extensions,conf,verbose); if (j < 0) goto err; if (j > 0) @@ -1181,7 +1190,7 @@ bad: { total++; j=certify(&x,infile,pkey,x509,dgst,attribs,db, - serial,startdate,enddate,days,batch, + serial,subj,startdate,enddate,days,batch, extensions,conf,verbose); if (j < 0) goto err; if (j > 0) @@ -1200,7 +1209,7 @@ bad: { total++; j=certify(&x,argv[i],pkey,x509,dgst,attribs,db, - serial,startdate,enddate,days,batch, + serial,subj,startdate,enddate,days,batch, extensions,conf,verbose); if (j < 0) goto err; if (j > 0) @@ -1674,7 +1683,7 @@ 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 *startdate, char *enddate, int days, + BIGNUM *serial, char *subj, char *startdate, char *enddate, int days, int batch, char *ext_sect, LHASH *lconf, int verbose) { X509_REQ *req=NULL; @@ -1722,7 +1731,7 @@ 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,startdate, enddate, + ok=do_body(xret,pkey,x509,dgst,policy,db,serial,subj,startdate, enddate, days,batch,verbose,req,ext_sect,lconf); err: @@ -1733,7 +1742,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, - BIGNUM *serial, char *startdate, char *enddate, int days, + BIGNUM *serial, char *subj, char *startdate, char *enddate, int days, int batch, char *ext_sect, LHASH *lconf, int verbose) { X509 *req=NULL; @@ -1784,7 +1793,7 @@ 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,startdate,enddate,days, + ok=do_body(xret,pkey,x509,dgst,policy,db,serial,subj,startdate,enddate,days, batch,verbose,rreq,ext_sect,lconf); err: @@ -1795,7 +1804,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, + STACK_OF(CONF_VALUE) *policy, TXT_DB *db, BIGNUM *serial, char *subj, char *startdate, char *enddate, int days, int batch, int verbose, X509_REQ *req, char *ext_sect, LHASH *lconf) { @@ -1824,7 +1833,21 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst, for (i=0; ireq_info->enc.modified = 1; + X509_NAME_free(n); + } + + BIO_printf(bio_err,"The Subject's Distinguished Name is as follows\n"); name=X509_REQ_get_subject_name(req); for (i=0; itype) == EVP_PKEY_DSA) + if (EVP_PKEY_type(pkey->type) == EVP_PKEY_DSA) { char *randfile = CONF_get_string(req_conf,SECTION,"RANDFILE"); if (randfile == NULL) ERR_clear_error(); app_RAND_load_file(randfile, bio_err, 0); - } + } } if (newreq && (pkey == NULL)) @@ -795,7 +810,8 @@ loop: goto end; } - i=make_REQ(req,pkey,!x509); + i=make_REQ(req,pkey,subj,!x509); + subj=NULL; /* done processing '-subj' option */ if ((kludge > 0) && !sk_X509_ATTRIBUTE_num(req->req_info->attributes)) { sk_X509_ATTRIBUTE_free(req->req_info->attributes); @@ -839,13 +855,13 @@ loop: /* Add extensions */ if(extensions && !X509V3_EXT_add_conf(req_conf, &ext_ctx, extensions, x509ss)) - { - BIO_printf(bio_err, - "Error Loading extension section %s\n", - extensions); - goto end; - } - + { + BIO_printf(bio_err, + "Error Loading extension section %s\n", + extensions); + goto end; + } + if (!(i=X509_sign(x509ss,pkey,digest))) goto end; } @@ -861,17 +877,46 @@ loop: /* Add extensions */ if(req_exts && !X509V3_EXT_REQ_add_conf(req_conf, &ext_ctx, req_exts, req)) - { - BIO_printf(bio_err, - "Error Loading extension section %s\n", - req_exts); - goto end; - } + { + BIO_printf(bio_err, + "Error Loading extension section %s\n", + req_exts); + goto end; + } if (!(i=X509_REQ_sign(req,pkey,digest))) goto end; } } + if (subj && x509) + { + BIO_printf(bio_err, "Cannot modifiy certificate subject\n"); + goto end; + } + + if (subj && !x509) + { + if (verbose) + { + BIO_printf(bio_err, "Modifying Request's Subject\n"); + print_name(bio_err, "old subject=", X509_REQ_get_subject_name(req), nmflag); + } + + if (build_subject(req, subj) == 0) + { + BIO_printf(bio_err, "ERROR: cannot modify subject\n"); + ex=1; + goto end; + } + + req->req_info->enc.modified = 1; + + if (verbose) + { + print_name(bio_err, "new subject=", X509_REQ_get_subject_name(req), nmflag); + } + } + if (verify && !x509) { int tmp=0; @@ -1024,7 +1069,7 @@ end: EXIT(ex); } -static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, int attribs) +static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, char *subj, int attribs) { int ret=0,i; char no_prompt = 0; @@ -1069,8 +1114,15 @@ static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, int attribs) /* setup version number */ if (!X509_REQ_set_version(req,0L)) goto err; /* version 1 */ - if(no_prompt) i = auto_info(req, dn_sk, attr_sk, attribs); - else i = prompt_info(req, dn_sk, dn_sect, attr_sk, attr_sect, attribs); + if (no_prompt) + i = auto_info(req, dn_sk, attr_sk, attribs); + else + { + if (subj) + i = build_subject(req, subj); + else + i = prompt_info(req, dn_sk, dn_sect, attr_sk, attr_sect, attribs); + } if(!i) goto err; X509_REQ_set_pubkey(req,pkey); @@ -1080,6 +1132,68 @@ err: return(ret); } +static int build_subject(X509_REQ *req, char *subject) + { + X509_NAME *n = NULL; + + int i, nid, ne_num=0; + + char *ne_name = NULL; + char *ne_value = NULL; + + char *tmp = NULL; + char *p[2]; + + char *str_list[256]; + + p[0] = ",/"; + p[1] = "="; + + n = X509_NAME_new(); + + tmp = strtok(subject, p[0]); + while((tmp != NULL) && (ne_num < (sizeof str_list/sizeof *str_list))) + { + char *token = tmp; + + while (token[0] == ' ') + token++; + str_list[ne_num] = token; + + tmp = strtok(NULL, p[0]); + ne_num++; + } + + for(i = 0; i < ne_num; i++) + { + ne_name = strtok(str_list[i], p[1]); + ne_value = strtok(NULL, p[1]); + + if ((nid=OBJ_txt2nid(ne_name)) == NID_undef) + { + BIO_printf(bio_err, "Subject Attribute %s has no known NID, skipped\n", ne_name); + continue; + } + + if (ne_value == NULL) + { + BIO_printf(bio_err, "No value provided for Subject Attribute %s, skipped\n", ne_name); + continue; + } + + if (!X509_NAME_add_entry_by_NID(n, nid, MBSTRING_ASC, (unsigned char*)ne_value, -1,-1,0)) + { + X509_NAME_free(n); + return 0; + } + } + + if (!X509_REQ_set_subject_name(req, n)) + return 0; + X509_NAME_free(n); + return 1; +} + static int prompt_info(X509_REQ *req, STACK_OF(CONF_VALUE) *dn_sk, char *dn_sect, @@ -1093,13 +1207,17 @@ static int prompt_info(X509_REQ *req, CONF_VALUE *v; X509_NAME *subj; subj = X509_REQ_get_subject_name(req); - BIO_printf(bio_err,"You are about to be asked to enter information that will be incorporated\n"); - BIO_printf(bio_err,"into your certificate request.\n"); - BIO_printf(bio_err,"What you are about to enter is what is called a Distinguished Name or a DN.\n"); - BIO_printf(bio_err,"There are quite a few fields but you can leave some blank\n"); - BIO_printf(bio_err,"For some fields there will be a default value,\n"); - BIO_printf(bio_err,"If you enter '.', the field will be left blank.\n"); - BIO_printf(bio_err,"-----\n"); + + if(!batch) + { + BIO_printf(bio_err,"You are about to be asked to enter information that will be incorporated\n"); + BIO_printf(bio_err,"into your certificate request.\n"); + BIO_printf(bio_err,"What you are about to enter is what is called a Distinguished Name or a DN.\n"); + BIO_printf(bio_err,"There are quite a few fields but you can leave some blank\n"); + BIO_printf(bio_err,"For some fields there will be a default value,\n"); + BIO_printf(bio_err,"If you enter '.', the field will be left blank.\n"); + BIO_printf(bio_err,"-----\n"); + } if (sk_CONF_VALUE_num(dn_sk)) @@ -1160,7 +1278,7 @@ start: for (;;) if (attribs) { - if ((attr_sk != NULL) && (sk_CONF_VALUE_num(attr_sk) > 0)) + if ((attr_sk != NULL) && (sk_CONF_VALUE_num(attr_sk) > 0) && (!batch)) { BIO_printf(bio_err,"\nPlease enter the following 'extra' attributes\n"); BIO_printf(bio_err,"to be sent with your certificate request\n"); @@ -1276,9 +1394,9 @@ static int add_DN_object(X509_NAME *n, char *text, char *def, char *value, int i,ret=0; MS_STATIC char buf[1024]; start: - BIO_printf(bio_err,"%s [%s]:",text,def); + if (!batch) BIO_printf(bio_err,"%s [%s]:",text,def); (void)BIO_flush(bio_err); - if (value != NULL) + if(value != NULL) { strcpy(buf,value); strcat(buf,"\n"); @@ -1287,7 +1405,15 @@ start: else { buf[0]='\0'; - fgets(buf,1024,stdin); + if (!batch) + { + fgets(buf,1024,stdin); + } + else + { + buf[0] = '\n'; + buf[1] = '\0'; + } } if (buf[0] == '\0') return(0); @@ -1307,7 +1433,6 @@ start: return(0); } buf[--i]='\0'; - #ifdef CHARSET_EBCDIC ebcdic2ascii(buf, buf, i); #endif @@ -1327,7 +1452,7 @@ static int add_attribute_object(X509_REQ *req, char *text, static char buf[1024]; start: - BIO_printf(bio_err,"%s [%s]:",text,def); + if (!batch) BIO_printf(bio_err,"%s [%s]:",text,def); (void)BIO_flush(bio_err); if (value != NULL) { @@ -1338,7 +1463,15 @@ start: else { buf[0]='\0'; - fgets(buf,1024,stdin); + if (!batch) + { + fgets(buf,1024,stdin); + } + else + { + buf[0] = '\n'; + buf[1] = '\0'; + } } if (buf[0] == '\0') return(0); diff --git a/crypto/asn1/x_name.c b/crypto/asn1/x_name.c index 34f4e4c3f6..9a111a3d05 100644 --- a/crypto/asn1/x_name.c +++ b/crypto/asn1/x_name.c @@ -119,8 +119,15 @@ static int x509_name_ex_new(ASN1_VALUE **val, const ASN1_ITEM *it) ret->modified=1; *val = (ASN1_VALUE *)ret; return 1; - memerr: + + memerr: ASN1err(ASN1_F_X509_NAME_NEW, ERR_R_MALLOC_FAILURE); + if (ret) + { + if (ret->entries) + sk_X509_NAME_ENTRY_free(ret->entries); + OPENSSL_free(ret); + } return 0; } diff --git a/doc/apps/ca.pod b/doc/apps/ca.pod index 8121886ebb..5adf805a94 100644 --- a/doc/apps/ca.pod +++ b/doc/apps/ca.pod @@ -13,6 +13,7 @@ B B [B<-name section>] [B<-gencrl>] [B<-revoke file>] +[B<-subj arg>] [B<-crldays days>] [B<-crlhours hours>] [B<-crlexts section>] @@ -105,6 +106,7 @@ the 'ps' utility) this option should be used with caution. the key password source. For more information about the format of B see the B section in L. + =item B<-verbose> this prints extra details about the operations being performed. @@ -197,6 +199,10 @@ the number of hours before the next CRL is due. a filename containing a certificate to revoke. +=item B<-subj arg> + +supersedes subject name given in the request + =item B<-crlexts section> the section of the configuration file containing CRL extensions to diff --git a/doc/apps/req.pod b/doc/apps/req.pod index a3f54f45a3..c486c2be74 100644 --- a/doc/apps/req.pod +++ b/doc/apps/req.pod @@ -28,12 +28,15 @@ B B [B<-keyout filename>] [B<-[md5|sha1|md2|mdc2]>] [B<-config filename>] +[B<-subj arg>] [B<-x509>] [B<-days n>] [B<-asn1-kludge>] [B<-newhdr>] [B<-extensions section>] [B<-reqexts section>] +[B<-batch>] +[B<-verbose>] =head1 DESCRIPTION @@ -154,6 +157,11 @@ this allows an alternative configuration file to be specified, this overrides the compile time filename or any specified in the B environment variable. +=item B<-subj arg> + +sets subject name for new request or supersedes the subject name +when processing a request. + =item B<-x509> this option outputs a self signed certificate instead of a certificate @@ -196,6 +204,14 @@ It should be noted that very few CAs still require the use of this option. Adds the word B to the PEM file header and footer lines on the outputed request. Some software (Netscape certificate server) and some CAs need this. +=item B<-batch> + +non-interactive mode. + +=item B<-verbose> + +print extra details about the operations being performed. + =back =head1 CONFIGURATION FILE FORMAT -- 2.25.1