X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=apps%2Freq.c;h=303bbf9d1721787af8221f2287512d7e90d121ef;hp=1105e59e67755b6191f12e6ba2b257ebbb0ca95c;hb=e933f91f50108a43c0198cdc63ecdfdbc77b4d0d;hpb=64376cd8ff7ac2db8e4645a365184f782bd7b835 diff --git a/apps/req.c b/apps/req.c index 1105e59e67..303bbf9d17 100644 --- a/apps/req.c +++ b/apps/req.c @@ -56,6 +56,12 @@ * [including the GNU Public Licence.] */ +/* Until the key-gen callbacks are modified to use newer prototypes, we allow + * deprecated functions for openssl-internal code */ +#ifdef OPENSSL_NO_DEPRECATED +#undef OPENSSL_NO_DEPRECATED +#endif + #include #include #include @@ -73,6 +79,13 @@ #include #include #include +#include +#ifndef OPENSSL_NO_RSA +#include +#endif +#ifndef OPENSSL_NO_DSA +#include +#endif #define SECTION "req" @@ -112,9 +125,10 @@ * require. This format is wrong */ -static int make_REQ(X509_REQ *req,EVP_PKEY *pkey,char *dn,int attribs, - unsigned long chtype); -static int build_subject(X509_REQ *req, char *subj, unsigned long chtype); +static int make_REQ(X509_REQ *req,EVP_PKEY *pkey,char *dn,int mutlirdn, + int attribs,unsigned long chtype); +static int build_subject(X509_REQ *req, char *subj, unsigned long chtype, + int multirdn); static int prompt_info(X509_REQ *req, STACK_OF(CONF_VALUE) *dn_sk, char *dn_sect, STACK_OF(CONF_VALUE) *attr_sk, char *attr_sect, int attribs, @@ -122,51 +136,46 @@ static int prompt_info(X509_REQ *req, static int auto_info(X509_REQ *req, STACK_OF(CONF_VALUE) *sk, STACK_OF(CONF_VALUE) *attr, int attribs, unsigned long chtype); -static int add_attribute_object(X509_REQ *req, char *text, - char *def, char *value, int nid, int n_min, +static int add_attribute_object(X509_REQ *req, char *text, const char *def, + char *value, int nid, int n_min, int n_max, unsigned long chtype); -static int add_DN_object(X509_NAME *n, char *text, char *def, char *value, - int nid,int n_min,int n_max, unsigned long chtype); -#ifndef OPENSSL_NO_RSA -static void MS_CALLBACK req_cb(int p,int n,void *arg); -#endif +static int add_DN_object(X509_NAME *n, char *text, const char *def, char *value, + int nid,int n_min,int n_max, unsigned long chtype, int mval); +static int genpkey_cb(EVP_PKEY_CTX *ctx); static int req_check_len(int len,int n_min,int n_max); -static int check_end(char *str, char *end); +static int check_end(const char *str, const char *end); +static EVP_PKEY_CTX *set_keygen_ctx(BIO *err, const char *gstr, int *pkey_type, + long *pkeylen, char **palgnam, + ENGINE *keygen_engine); #ifndef MONOLITH static char *default_config_file=NULL; -static CONF *config=NULL; #endif static CONF *req_conf=NULL; static int batch=0; -#define TYPE_RSA 1 -#define TYPE_DSA 2 -#define TYPE_DH 3 -#define TYPE_EC 4 - int MAIN(int, char **); int MAIN(int argc, char **argv) { - ENGINE *e = NULL; -#ifndef OPENSSL_NO_DSA - DSA *dsa_params=NULL; -#endif -#ifndef OPENSSL_NO_ECDSA - EC_KEY *ec_params = NULL; -#endif - unsigned long nmflag = 0; + ENGINE *e = NULL, *gen_eng = NULL; + unsigned long nmflag = 0, reqflag = 0; int ex=1,x509=0,days=30; X509 *x509ss=NULL; X509_REQ *req=NULL; + EVP_PKEY_CTX *genctx = NULL; + const char *keyalg = NULL; + char *keyalgstr = NULL; + STACK_OF(OPENSSL_STRING) *pkeyopts = NULL, *sigopts = NULL; EVP_PKEY *pkey=NULL; - int i=0,badops=0,newreq=0,verbose=0,pkey_type=TYPE_RSA; + int i=0,badops=0,newreq=0,verbose=0,pkey_type=-1; long newkey = -1; BIO *in=NULL,*out=NULL; int informat,outformat,verify=0,noout=0,text=0,keyform=FORMAT_PEM; int nodes=0,kludge=0,newhdr=0,subject=0,pubkey=0; char *infile,*outfile,*prog,*keyfile=NULL,*template=NULL,*keyout=NULL; +#ifndef OPENSSL_NO_ENGINE char *engine=NULL; +#endif char *extensions = NULL; char *req_exts = NULL; const EVP_CIPHER *cipher=NULL; @@ -177,10 +186,11 @@ int MAIN(int argc, char **argv) char *passin = NULL, *passout = NULL; char *p; char *subj = NULL; - const EVP_MD *md_alg=NULL,*digest=EVP_md5(); + int multirdn = 0; + const EVP_MD *md_alg=NULL,*digest=NULL; unsigned long chtype = MBSTRING_ASC; #ifndef MONOLITH - MS_STATIC char config_name[256]; + char *to_free; long errline; #endif @@ -214,11 +224,23 @@ int MAIN(int argc, char **argv) if (--argc < 1) goto bad; outformat=str2fmt(*(++argv)); } +#ifndef OPENSSL_NO_ENGINE else if (strcmp(*argv,"-engine") == 0) { if (--argc < 1) goto bad; engine= *(++argv); } + else if (strcmp(*argv,"-keygen_engine") == 0) + { + if (--argc < 1) goto bad; + gen_eng = ENGINE_by_id(*(++argv)); + if (gen_eng == NULL) + { + BIO_printf(bio_err, "Can't find keygen engine %s\n", *argv); + goto end; + } + } +#endif else if (strcmp(*argv,"-key") == 0) { if (--argc < 1) goto bad; @@ -274,119 +296,29 @@ int MAIN(int argc, char **argv) } else if (strcmp(*argv,"-newkey") == 0) { - int is_numeric; - - if (--argc < 1) goto bad; - p= *(++argv); - is_numeric = p[0] >= '0' && p[0] <= '9'; - if (strncmp("rsa:",p,4) == 0 || is_numeric) - { - pkey_type=TYPE_RSA; - if(!is_numeric) - p+=4; - newkey= atoi(p); - } - else -#ifndef OPENSSL_NO_DSA - if (strncmp("dsa:",p,4) == 0) - { - X509 *xtmp=NULL; - EVP_PKEY *dtmp; - - pkey_type=TYPE_DSA; - p+=4; - if ((in=BIO_new_file(p,"r")) == NULL) - { - perror(p); - goto end; - } - if ((dsa_params=PEM_read_bio_DSAparams(in,NULL,NULL,NULL)) == NULL) - { - ERR_clear_error(); - (void)BIO_reset(in); - if ((xtmp=PEM_read_bio_X509(in,NULL,NULL,NULL)) == NULL) - { - BIO_printf(bio_err,"unable to load DSA parameters from file\n"); - goto end; - } - - if ((dtmp=X509_get_pubkey(xtmp)) == NULL) goto end; - if (dtmp->type == EVP_PKEY_DSA) - dsa_params=DSAparams_dup(dtmp->pkey.dsa); - EVP_PKEY_free(dtmp); - X509_free(xtmp); - if (dsa_params == NULL) - { - BIO_printf(bio_err,"Certificate does not contain DSA parameters\n"); - goto end; - } - } - BIO_free(in); - in=NULL; - newkey=BN_num_bits(dsa_params->p); - } - else -#endif -#ifndef OPENSSL_NO_ECDSA - if (strncmp("ec:",p,4) == 0) - { - X509 *xtmp=NULL; - EVP_PKEY *dtmp; - - pkey_type=TYPE_EC; - p+=6; - if ((in=BIO_new_file(p,"r")) == NULL) - { - perror(p); - goto end; - } - if ((ec_params = EC_KEY_new()) == NULL) - goto end; - if ((ec_params->group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL)) == NULL) - { - if (ec_params) - EC_KEY_free(ec_params); - ERR_clear_error(); - (void)BIO_reset(in); - if ((xtmp=PEM_read_bio_X509(in,NULL,NULL,NULL)) == NULL) - { - BIO_printf(bio_err,"unable to load EC parameters from file\n"); - goto end; - } - - if ((dtmp=X509_get_pubkey(xtmp))==NULL) - goto end; - if (dtmp->type == EVP_PKEY_EC) - ec_params = ECParameters_dup(dtmp->pkey.eckey); - EVP_PKEY_free(dtmp); - X509_free(xtmp); - if (ec_params == NULL) - { - BIO_printf(bio_err,"Certificate does not contain EC parameters\n"); - goto end; - } - } - - BIO_free(in); - in=NULL; - - newkey = EC_GROUP_get_degree(ec_params->group); - - } - else -#endif -#ifndef OPENSSL_NO_DH - if (strncmp("dh:",p,4) == 0) - { - pkey_type=TYPE_DH; - p+=3; - } - else -#endif - pkey_type=TYPE_RSA; - + if (--argc < 1) + goto bad; + keyalg = *(++argv); newreq=1; } + else if (strcmp(*argv,"-pkeyopt") == 0) + { + if (--argc < 1) + goto bad; + if (!pkeyopts) + pkeyopts = sk_OPENSSL_STRING_new_null(); + if (!pkeyopts || !sk_OPENSSL_STRING_push(pkeyopts, *(++argv))) + goto bad; + } + 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,"-batch") == 0) batch=1; else if (strcmp(*argv,"-newhdr") == 0) @@ -408,6 +340,11 @@ int MAIN(int argc, char **argv) if (--argc < 1) goto bad; if (!set_name_ex(&nmflag, *(++argv))) goto bad; } + else if (strcmp(*argv,"-reqopt") == 0) + { + if (--argc < 1) goto bad; + if (!set_cert_ex(&reqflag, *(++argv))) goto bad; + } else if (strcmp(*argv,"-subject") == 0) subject=1; else if (strcmp(*argv,"-text") == 0) @@ -423,6 +360,8 @@ int MAIN(int argc, char **argv) if (--argc < 1) goto bad; subj= *(++argv); } + else if (strcmp(*argv,"-multivalue-rdn") == 0) + multirdn=1; else if (strcmp(*argv,"-days") == 0) { if (--argc < 1) goto bad; @@ -435,11 +374,6 @@ int MAIN(int argc, char **argv) serial = s2i_ASN1_INTEGER(NULL, *(++argv)); if (!serial) goto bad; } - else if ((md_alg=EVP_get_digestbyname(&((*argv)[1]))) != NULL) - { - /* ok */ - digest=md_alg; - } else if (strcmp(*argv,"-extensions") == 0) { if (--argc < 1) goto bad; @@ -450,6 +384,11 @@ int MAIN(int argc, char **argv) if (--argc < 1) goto bad; req_exts = *(++argv); } + else if ((md_alg=EVP_get_digestbyname(&((*argv)[1]))) != NULL) + { + /* ok */ + digest=md_alg; + } else { BIO_printf(bio_err,"unknown option %s\n",*argv); @@ -475,7 +414,9 @@ bad: BIO_printf(bio_err," -verify verify signature on REQ\n"); BIO_printf(bio_err," -modulus RSA modulus\n"); BIO_printf(bio_err," -nodes don't encrypt the output key\n"); +#ifndef OPENSSL_NO_ENGINE BIO_printf(bio_err," -engine e use engine e, possibly a hardware device\n"); +#endif BIO_printf(bio_err," -subject output the request's subject\n"); BIO_printf(bio_err," -passin private key password source\n"); BIO_printf(bio_err," -key file use the private key contained in file\n"); @@ -492,6 +433,7 @@ bad: BIO_printf(bio_err," -[digest] Digest to sign with (md5, sha1, md2, mdc2, md4)\n"); BIO_printf(bio_err," -config file request template file.\n"); BIO_printf(bio_err," -subj arg set or modify request subject\n"); + BIO_printf(bio_err," -multivalue-rdn enable support for multivalued RDNs\n"); BIO_printf(bio_err," -new new request.\n"); BIO_printf(bio_err," -batch do not ask anything during request generation\n"); BIO_printf(bio_err," -x509 output a x509 structure instead of a cert. req.\n"); @@ -504,6 +446,7 @@ bad: BIO_printf(bio_err," -reqexts .. specify request extension section (override value in config file)\n"); BIO_printf(bio_err," -utf8 input characters are UTF8 (default ASCII)\n"); BIO_printf(bio_err," -nameopt arg - various certificate name options\n"); + BIO_printf(bio_err," -reqopt arg - various request text options\n\n"); goto end; } @@ -519,14 +462,7 @@ bad: if (p == NULL) p=getenv("SSLEAY_CONF"); if (p == NULL) - { - strcpy(config_name,X509_get_default_cert_area()); -#ifndef OPENSSL_SYS_VMS - strcat(config_name,"/"); -#endif - strcat(config_name,OPENSSL_CONF); - p=config_name; - } + p=to_free=make_config_name(); default_config_file=p; config=NCONF_new(NULL); i=NCONF_load(config, p, &errline); @@ -534,7 +470,7 @@ bad: if (template != NULL) { - long errline; + long errline = -1; if( verbose ) BIO_printf(bio_err,"Using configuration from %s\n",template); @@ -549,13 +485,16 @@ bad: else { req_conf=config; - if( verbose ) - BIO_printf(bio_err,"Using configuration from %s\n", - default_config_file); + if (req_conf == NULL) { - BIO_printf(bio_err,"Unable to load config info\n"); + BIO_printf(bio_err,"Unable to load config info from %s\n", default_config_file); + if (newreq) + goto end; } + else if( verbose ) + BIO_printf(bio_err,"Using configuration from %s\n", + default_config_file); } if (req_conf != NULL) @@ -673,7 +612,9 @@ bad: if ((in == NULL) || (out == NULL)) goto end; +#ifndef OPENSSL_NO_ENGINE e = setup_engine(bio_err, engine, 0); +#endif if (keyfile != NULL) { @@ -685,8 +626,7 @@ bad: message */ goto end; } - if (EVP_PKEY_type(pkey->type) == EVP_PKEY_DSA || - EVP_PKEY_type(pkey->type) == EVP_PKEY_EC) + else { char *randfile = NCONF_get_string(req_conf,SECTION,"RANDFILE"); if (randfile == NULL) @@ -703,6 +643,14 @@ bad: app_RAND_load_file(randfile, bio_err, 0); if (inrand) app_RAND_load_files(inrand); + + if (keyalg) + { + genctx = set_keygen_ctx(bio_err, keyalg, &pkey_type, &newkey, + &keyalgstr, gen_eng); + if (!genctx) + goto end; + } if (newkey <= 0) { @@ -710,49 +658,54 @@ bad: newkey=DEFAULT_KEY_LENGTH; } - if (newkey < MIN_KEY_LENGTH && (pkey_type == TYPE_RSA || pkey_type == TYPE_DSA)) + if (newkey < MIN_KEY_LENGTH && (pkey_type == EVP_PKEY_RSA || pkey_type == EVP_PKEY_DSA)) { BIO_printf(bio_err,"private key length is too short,\n"); - BIO_printf(bio_err,"it needs to be at least %d bits, not %d\n",MIN_KEY_LENGTH,newkey); + BIO_printf(bio_err,"it needs to be at least %d bits, not %ld\n",MIN_KEY_LENGTH,newkey); goto end; } - BIO_printf(bio_err,"Generating a %d bit %s private key\n", - newkey,(pkey_type == TYPE_RSA)?"RSA": - (pkey_type == TYPE_DSA)?"DSA":"EC"); - - if ((pkey=EVP_PKEY_new()) == NULL) goto end; -#ifndef OPENSSL_NO_RSA - if (pkey_type == TYPE_RSA) + if (!genctx) { - if (!EVP_PKEY_assign_RSA(pkey, - RSA_generate_key(newkey,0x10001, - req_cb,bio_err))) + genctx = set_keygen_ctx(bio_err, NULL, &pkey_type, &newkey, + &keyalgstr, gen_eng); + if (!genctx) goto end; } - else -#endif -#ifndef OPENSSL_NO_DSA - if (pkey_type == TYPE_DSA) + + if (pkeyopts) { - if (!DSA_generate_key(dsa_params)) goto end; - if (!EVP_PKEY_assign_DSA(pkey,dsa_params)) goto end; - dsa_params=NULL; + char *genopt; + for (i = 0; i < sk_OPENSSL_STRING_num(pkeyopts); i++) + { + genopt = sk_OPENSSL_STRING_value(pkeyopts, i); + if (pkey_ctrl_string(genctx, genopt) <= 0) + { + BIO_printf(bio_err, + "parameter error \"%s\"\n", + genopt); + ERR_print_errors(bio_err); + goto end; + } + } } -#endif -#ifndef OPENSSL_NO_ECDSA - if (pkey_type == TYPE_EC) + + BIO_printf(bio_err,"Generating a %ld bit %s private key\n", + newkey, keyalgstr); + + EVP_PKEY_CTX_set_cb(genctx, genpkey_cb); + EVP_PKEY_CTX_set_app_data(genctx, bio_err); + + if (EVP_PKEY_keygen(genctx, &pkey) <= 0) { - if (!EC_KEY_generate_key(ec_params)) goto end; - if (!EVP_PKEY_assign_EC_KEY(pkey, ec_params)) - goto end; - ec_params = NULL; + BIO_puts(bio_err, "Error Generating Key\n"); + goto end; } -#endif - app_RAND_write_file(randfile, bio_err); + EVP_PKEY_CTX_free(genctx); + genctx = NULL; - if (pkey == NULL) goto end; + app_RAND_write_file(randfile, bio_err); if (keyout == NULL) { @@ -851,14 +804,7 @@ loop: BIO_printf(bio_err,"you need to specify a private key\n"); goto end; } -#ifndef OPENSSL_NO_DSA - if (pkey->type == EVP_PKEY_DSA) - digest=EVP_dss1(); -#endif -#ifndef OPENSSL_NO_ECDSA - if (pkey->type == EVP_PKEY_EC) - digest=EVP_ecdsa(); -#endif + if (req == NULL) { req=X509_REQ_new(); @@ -867,7 +813,7 @@ loop: goto end; } - i=make_REQ(req,pkey,subj,!x509, chtype); + i=make_REQ(req,pkey,subj,multirdn,!x509, chtype); subj=NULL; /* done processing '-subj' option */ if ((kludge > 0) && !sk_X509_ATTRIBUTE_num(req->req_info->attributes)) { @@ -887,19 +833,21 @@ loop: if ((x509ss=X509_new()) == NULL) goto end; /* Set version to V3 */ - if(!X509_set_version(x509ss, 2)) goto end; + if(extensions && !X509_set_version(x509ss, 2)) goto end; if (serial) { if (!X509_set_serialNumber(x509ss, serial)) goto end; } else { - if (!ASN1_INTEGER_set(X509_get_serialNumber(x509ss),0L)) goto end; + if (!rand_serial(NULL, + X509_get_serialNumber(x509ss))) + goto end; } if (!X509_set_issuer_name(x509ss, X509_REQ_get_subject_name(req))) goto end; if (!X509_gmtime_adj(X509_get_notBefore(x509ss),0)) goto end; - if (!X509_gmtime_adj(X509_get_notAfter(x509ss), (long)60*60*24*days)) goto end; + if (!X509_time_adj_ex(X509_get_notAfter(x509ss), days, 0, NULL)) goto end; if (!X509_set_subject_name(x509ss, X509_REQ_get_subject_name(req))) goto end; tmppkey = X509_REQ_get_pubkey(req); if (!tmppkey || !X509_set_pubkey(x509ss,tmppkey)) goto end; @@ -919,9 +867,13 @@ loop: extensions); goto end; } - - if (!(i=X509_sign(x509ss,pkey,digest))) + + i=do_X509_sign(bio_err, x509ss, pkey, digest, sigopts); + if (!i) + { + ERR_print_errors(bio_err); goto end; + } } else { @@ -941,14 +893,18 @@ loop: req_exts); goto end; } - if (!(i=X509_REQ_sign(req,pkey,digest))) + i=do_X509_REQ_sign(bio_err, req, pkey, digest, sigopts); + if (!i) + { + ERR_print_errors(bio_err); goto end; + } } } if (subj && x509) { - BIO_printf(bio_err, "Cannot modifiy certificate subject\n"); + BIO_printf(bio_err, "Cannot modify certificate subject\n"); goto end; } @@ -960,7 +916,7 @@ loop: print_name(bio_err, "old subject=", X509_REQ_get_subject_name(req), nmflag); } - if (build_subject(req, subj, chtype) == 0) + if (build_subject(req, subj, chtype, multirdn) == 0) { BIO_printf(bio_err, "ERROR: cannot modify subject\n"); ex=1; @@ -1051,9 +1007,9 @@ loop: if (text) { if (x509) - X509_print(out,x509ss); + X509_print_ex(out, x509ss, nmflag, reqflag); else - X509_REQ_print(out,req); + X509_REQ_print_ex(out, req, nmflag, reqflag); } if(subject) @@ -1079,7 +1035,7 @@ loop: } fprintf(stdout,"Modulus="); #ifndef OPENSSL_NO_RSA - if (tpubkey->type == EVP_PKEY_RSA) + if (EVP_PKEY_base_id(tpubkey) == EVP_PKEY_RSA) BN_print(out,tpubkey->pkey.rsa->n); else #endif @@ -1123,6 +1079,10 @@ loop: } ex=0; end: +#ifndef MONOLITH + if(to_free) + OPENSSL_free(to_free); +#endif if (ex) { ERR_print_errors(bio_err); @@ -1131,24 +1091,30 @@ end: BIO_free(in); BIO_free_all(out); EVP_PKEY_free(pkey); + if (genctx) + EVP_PKEY_CTX_free(genctx); + if (pkeyopts) + sk_OPENSSL_STRING_free(pkeyopts); + if (sigopts) + sk_OPENSSL_STRING_free(sigopts); +#ifndef OPENSSL_NO_ENGINE + if (gen_eng) + ENGINE_free(gen_eng); +#endif + if (keyalgstr) + OPENSSL_free(keyalgstr); X509_REQ_free(req); X509_free(x509ss); ASN1_INTEGER_free(serial); if(passargin && passin) OPENSSL_free(passin); if(passargout && passout) OPENSSL_free(passout); OBJ_cleanup(); -#ifndef OPENSSL_NO_DSA - if (dsa_params != NULL) DSA_free(dsa_params); -#endif -#ifndef OPENSSL_NO_ECDSA - if (ec_params != NULL) EC_KEY_free(ec_params); -#endif apps_shutdown(); - EXIT(ex); + OPENSSL_EXIT(ex); } -static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, char *subj, int attribs, - unsigned long chtype) +static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, char *subj, int multirdn, + int attribs, unsigned long chtype) { int ret=0,i; char no_prompt = 0; @@ -1193,15 +1159,12 @@ static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, char *subj, int attribs, /* setup version number */ if (!X509_REQ_set_version(req,0L)) goto err; /* version 1 */ - if (no_prompt) + if (subj) + i = build_subject(req, subj, chtype, multirdn); + else if (no_prompt) i = auto_info(req, dn_sk, attr_sk, attribs, chtype); - else - { - if (subj) - i = build_subject(req, subj, chtype); - else - i = prompt_info(req, dn_sk, dn_sect, attr_sk, attr_sect, attribs, chtype); - } + else + i = prompt_info(req, dn_sk, dn_sect, attr_sk, attr_sect, attribs, chtype); if(!i) goto err; if (!X509_REQ_set_pubkey(req,pkey)) goto err; @@ -1215,11 +1178,11 @@ err: * subject is expected to be in the format /type0=value0/type1=value1/type2=... * where characters may be escaped by \ */ -static int build_subject(X509_REQ *req, char *subject, unsigned long chtype) +static int build_subject(X509_REQ *req, char *subject, unsigned long chtype, int multirdn) { X509_NAME *n; - if (!(n = do_subject(subject, chtype))) + if (!(n = parse_name(subject, chtype, multirdn))) return 0; if (!X509_REQ_set_subject_name(req, n)) @@ -1240,9 +1203,10 @@ static int prompt_info(X509_REQ *req, int i; char *p,*q; char buf[100]; - int nid; + int nid, mval; long n_min,n_max; - char *type,*def,*value; + char *type, *value; + const char *def; CONF_VALUE *v; X509_NAME *subj; subj = X509_REQ_get_subject_name(req); @@ -1283,32 +1247,51 @@ start: for (;;) if(*p) type = p; break; } + if (*type == '+') + { + mval = -1; + type++; + } + else + mval = 0; /* If OBJ not recognised ignore it */ if ((nid=OBJ_txt2nid(type)) == NID_undef) goto start; - sprintf(buf,"%s_default",v->name); + if (BIO_snprintf(buf,sizeof buf,"%s_default",v->name) + >= (int)sizeof(buf)) + { + BIO_printf(bio_err,"Name '%s' too long\n",v->name); + return 0; + } + if ((def=NCONF_get_string(req_conf,dn_sect,buf)) == NULL) { ERR_clear_error(); def=""; } - sprintf(buf,"%s_value",v->name); + BIO_snprintf(buf,sizeof buf,"%s_value",v->name); if ((value=NCONF_get_string(req_conf,dn_sect,buf)) == NULL) { ERR_clear_error(); value=NULL; } - sprintf(buf,"%s_min",v->name); + BIO_snprintf(buf,sizeof buf,"%s_min",v->name); if (!NCONF_get_number(req_conf,dn_sect,buf, &n_min)) + { + ERR_clear_error(); n_min = -1; + } - sprintf(buf,"%s_max",v->name); + BIO_snprintf(buf,sizeof buf,"%s_max",v->name); if (!NCONF_get_number(req_conf,dn_sect,buf, &n_max)) + { + ERR_clear_error(); n_max = -1; + } if (!add_DN_object(subj,v->value,def,value,nid, - n_min,n_max, chtype)) + n_min,n_max, chtype, mval)) return 0; } if (X509_NAME_entry_count(subj) == 0) @@ -1338,7 +1321,13 @@ start2: for (;;) if ((nid=OBJ_txt2nid(type)) == NID_undef) goto start2; - sprintf(buf,"%s_default",type); + if (BIO_snprintf(buf,sizeof buf,"%s_default",type) + >= (int)sizeof(buf)) + { + BIO_printf(bio_err,"Name '%s' too long\n",v->name); + return 0; + } + if ((def=NCONF_get_string(req_conf,attr_sect,buf)) == NULL) { @@ -1347,7 +1336,7 @@ start2: for (;;) } - sprintf(buf,"%s_value",type); + BIO_snprintf(buf,sizeof buf,"%s_value",type); if ((value=NCONF_get_string(req_conf,attr_sect,buf)) == NULL) { @@ -1355,13 +1344,19 @@ start2: for (;;) value=NULL; } - sprintf(buf,"%s_min",type); + BIO_snprintf(buf,sizeof buf,"%s_min",type); if (!NCONF_get_number(req_conf,attr_sect,buf, &n_min)) + { + ERR_clear_error(); n_min = -1; + } - sprintf(buf,"%s_max",type); + BIO_snprintf(buf,sizeof buf,"%s_max",type); if (!NCONF_get_number(req_conf,attr_sect,buf, &n_max)) + { + ERR_clear_error(); n_max = -1; + } if (!add_attribute_object(req, v->value,def,value,nid,n_min,n_max, chtype)) @@ -1392,6 +1387,7 @@ static int auto_info(X509_REQ *req, STACK_OF(CONF_VALUE) *dn_sk, for (i = 0; i < sk_CONF_VALUE_num(dn_sk); i++) { + int mval; v=sk_CONF_VALUE_value(dn_sk,i); p=q=NULL; type=v->name; @@ -1408,8 +1404,19 @@ static int auto_info(X509_REQ *req, STACK_OF(CONF_VALUE) *dn_sk, if(*p) type = p; break; } +#ifndef CHARSET_EBCDIC + if (*p == '+') +#else + if (*p == os_toascii['+']) +#endif + { + p++; + mval = -1; + } + else + mval = 0; if (!X509_NAME_add_entry_by_txt(subj,type, chtype, - (unsigned char *) v->value,-1,-1,0)) return 0; + (unsigned char *) v->value,-1,-1,mval)) return 0; } @@ -1431,8 +1438,8 @@ static int auto_info(X509_REQ *req, STACK_OF(CONF_VALUE) *dn_sk, } -static int add_DN_object(X509_NAME *n, char *text, char *def, char *value, - int nid, int n_min, int n_max, unsigned long chtype) +static int add_DN_object(X509_NAME *n, char *text, const char *def, char *value, + int nid, int n_min, int n_max, unsigned long chtype, int mval) { int i,ret=0; MS_STATIC char buf[1024]; @@ -1441,8 +1448,8 @@ start: (void)BIO_flush(bio_err); if(value != NULL) { - strcpy(buf,value); - strcat(buf,"\n"); + BUF_strlcpy(buf,value,sizeof buf); + BUF_strlcat(buf,"\n",sizeof buf); BIO_printf(bio_err,"%s\n",value); } else @@ -1450,7 +1457,8 @@ start: buf[0]='\0'; if (!batch) { - fgets(buf,1024,stdin); + if (!fgets(buf,sizeof buf,stdin)) + return 0; } else { @@ -1464,8 +1472,8 @@ start: { if ((def == NULL) || (def[0] == '\0')) return(1); - strcpy(buf,def); - strcat(buf,"\n"); + BUF_strlcpy(buf,def,sizeof buf); + BUF_strlcat(buf,"\n",sizeof buf); } else if ((buf[0] == '.') && (buf[1] == '\n')) return(1); @@ -1481,14 +1489,14 @@ start: #endif if(!req_check_len(i, n_min, n_max)) goto start; if (!X509_NAME_add_entry_by_NID(n,nid, chtype, - (unsigned char *) buf, -1,-1,0)) goto err; + (unsigned char *) buf, -1,-1,mval)) goto err; ret=1; err: return(ret); } -static int add_attribute_object(X509_REQ *req, char *text, - char *def, char *value, int nid, int n_min, +static int add_attribute_object(X509_REQ *req, char *text, const char *def, + char *value, int nid, int n_min, int n_max, unsigned long chtype) { int i; @@ -1499,8 +1507,8 @@ start: (void)BIO_flush(bio_err); if (value != NULL) { - strcpy(buf,value); - strcat(buf,"\n"); + BUF_strlcpy(buf,value,sizeof buf); + BUF_strlcat(buf,"\n",sizeof buf); BIO_printf(bio_err,"%s\n",value); } else @@ -1508,7 +1516,8 @@ start: buf[0]='\0'; if (!batch) { - fgets(buf,1024,stdin); + if (!fgets(buf,sizeof buf,stdin)) + return 0; } else { @@ -1522,8 +1531,8 @@ start: { if ((def == NULL) || (def[0] == '\0')) return(1); - strcpy(buf,def); - strcat(buf,"\n"); + BUF_strlcpy(buf,def,sizeof buf); + BUF_strlcat(buf,"\n",sizeof buf); } else if ((buf[0] == '.') && (buf[1] == '\n')) return(1); @@ -1551,23 +1560,6 @@ err: return(0); } -#ifndef OPENSSL_NO_RSA -static void MS_CALLBACK req_cb(int p, int n, void *arg) - { - char c='*'; - - if (p == 0) c='.'; - if (p == 1) c='+'; - if (p == 2) c='*'; - if (p == 3) c='\n'; - BIO_write((BIO *)arg,&c,1); - (void)BIO_flush((BIO *)arg); -#ifdef LINT - p=n; -#endif - } -#endif - static int req_check_len(int len, int n_min, int n_max) { if ((n_min > 0) && (len < n_min)) @@ -1584,13 +1576,258 @@ static int req_check_len(int len, int n_min, int n_max) } /* Check if the end of a string matches 'end' */ -static int check_end(char *str, char *end) +static int check_end(const char *str, const char *end) { int elen, slen; - char *tmp; + const char *tmp; elen = strlen(end); slen = strlen(str); if(elen > slen) return 1; tmp = str + slen - elen; return strcmp(tmp, end); } + +static EVP_PKEY_CTX *set_keygen_ctx(BIO *err, const char *gstr, int *pkey_type, + long *pkeylen, char **palgnam, + ENGINE *keygen_engine) + { + EVP_PKEY_CTX *gctx = NULL; + EVP_PKEY *param = NULL; + long keylen = -1; + BIO *pbio = NULL; + const char *paramfile = NULL; + + if (gstr == NULL) + { + *pkey_type = EVP_PKEY_RSA; + keylen = *pkeylen; + } + else if (gstr[0] >= '0' && gstr[0] <= '9') + { + *pkey_type = EVP_PKEY_RSA; + keylen = atol(gstr); + *pkeylen = keylen; + } + else if (!strncmp(gstr, "param:", 6)) + paramfile = gstr + 6; + else + { + const char *p = strchr(gstr, ':'); + int len; + ENGINE *tmpeng; + const EVP_PKEY_ASN1_METHOD *ameth; + + if (p) + len = p - gstr; + else + len = strlen(gstr); + /* The lookup of a the string will cover all engines so + * keep a note of the implementation. + */ + + ameth = EVP_PKEY_asn1_find_str(&tmpeng, gstr, len); + + if (!ameth) + { + BIO_printf(err, "Unknown algorithm %.*s\n", len, gstr); + return NULL; + } + + EVP_PKEY_asn1_get0_info(NULL, pkey_type, NULL, NULL, NULL, + ameth); +#ifndef OPENSSL_NO_ENGINE + if (tmpeng) + ENGINE_finish(tmpeng); +#endif + if (*pkey_type == EVP_PKEY_RSA) + { + if (p) + { + keylen = atol(p + 1); + *pkeylen = keylen; + } + } + else if (p) + paramfile = p + 1; + } + + if (paramfile) + { + pbio = BIO_new_file(paramfile, "r"); + if (!pbio) + { + BIO_printf(err, "Can't open parameter file %s\n", + paramfile); + return NULL; + } + param = PEM_read_bio_Parameters(pbio, NULL); + + if (!param) + { + X509 *x; + (void)BIO_reset(pbio); + x = PEM_read_bio_X509(pbio, NULL, NULL, NULL); + if (x) + { + param = X509_get_pubkey(x); + X509_free(x); + } + } + + BIO_free(pbio); + + if (!param) + { + BIO_printf(err, "Error reading parameter file %s\n", + paramfile); + return NULL; + } + if (*pkey_type == -1) + *pkey_type = EVP_PKEY_id(param); + else if (*pkey_type != EVP_PKEY_base_id(param)) + { + BIO_printf(err, "Key Type does not match parameters\n"); + EVP_PKEY_free(param); + return NULL; + } + } + + if (palgnam) + { + const EVP_PKEY_ASN1_METHOD *ameth; + ENGINE *tmpeng; + const char *anam; + ameth = EVP_PKEY_asn1_find(&tmpeng, *pkey_type); + if (!ameth) + { + BIO_puts(err, "Internal error: can't find key algorithm\n"); + return NULL; + } + EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, &anam, ameth); + *palgnam = BUF_strdup(anam); +#ifndef OPENSSL_NO_ENGINE + if (tmpeng) + ENGINE_finish(tmpeng); +#endif + } + + if (param) + { + gctx = EVP_PKEY_CTX_new(param, keygen_engine); + *pkeylen = EVP_PKEY_bits(param); + EVP_PKEY_free(param); + } + else + gctx = EVP_PKEY_CTX_new_id(*pkey_type, keygen_engine); + + if (!gctx) + { + BIO_puts(err, "Error allocating keygen context\n"); + ERR_print_errors(err); + return NULL; + } + + if (EVP_PKEY_keygen_init(gctx) <= 0) + { + BIO_puts(err, "Error initializing keygen context\n"); + ERR_print_errors(err); + return NULL; + } +#ifndef OPENSSL_NO_RSA + if ((*pkey_type == EVP_PKEY_RSA) && (keylen != -1)) + { + if (EVP_PKEY_CTX_set_rsa_keygen_bits(gctx, keylen) <= 0) + { + BIO_puts(err, "Error setting RSA keysize\n"); + ERR_print_errors(err); + EVP_PKEY_CTX_free(gctx); + return NULL; + } + } +#endif + + return gctx; + } + +static int genpkey_cb(EVP_PKEY_CTX *ctx) + { + char c='*'; + BIO *b = EVP_PKEY_CTX_get_app_data(ctx); + int p; + p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); + if (p == 0) c='.'; + if (p == 1) c='+'; + if (p == 2) c='*'; + if (p == 3) c='\n'; + BIO_write(b,&c,1); + (void)BIO_flush(b); +#ifdef LINT + p=n; +#endif + return 1; + } + +static int do_sign_init(BIO *err, EVP_MD_CTX *ctx, EVP_PKEY *pkey, + const EVP_MD *md, STACK_OF(OPENSSL_STRING) *sigopts) + { + EVP_PKEY_CTX *pkctx = NULL; + int i; + EVP_MD_CTX_init(ctx); + if (!EVP_DigestSignInit(ctx, &pkctx, md, NULL, pkey)) + return 0; + for (i = 0; i < sk_OPENSSL_STRING_num(sigopts); i++) + { + char *sigopt = sk_OPENSSL_STRING_value(sigopts, i); + if (pkey_ctrl_string(pkctx, sigopt) <= 0) + { + BIO_printf(err, "parameter error \"%s\"\n", sigopt); + ERR_print_errors(bio_err); + return 0; + } + } + return 1; + } + +int do_X509_sign(BIO *err, X509 *x, EVP_PKEY *pkey, const EVP_MD *md, + STACK_OF(OPENSSL_STRING) *sigopts) + { + int rv; + EVP_MD_CTX mctx; + EVP_MD_CTX_init(&mctx); + rv = do_sign_init(err, &mctx, pkey, md, sigopts); + if (rv > 0) + rv = X509_sign_ctx(x, &mctx); + EVP_MD_CTX_cleanup(&mctx); + return rv > 0 ? 1 : 0; + } + + +int do_X509_REQ_sign(BIO *err, X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md, + STACK_OF(OPENSSL_STRING) *sigopts) + { + int rv; + EVP_MD_CTX mctx; + EVP_MD_CTX_init(&mctx); + rv = do_sign_init(err, &mctx, pkey, md, sigopts); + if (rv > 0) + rv = X509_REQ_sign_ctx(x, &mctx); + EVP_MD_CTX_cleanup(&mctx); + return rv > 0 ? 1 : 0; + } + + + +int do_X509_CRL_sign(BIO *err, X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md, + STACK_OF(OPENSSL_STRING) *sigopts) + { + int rv; + EVP_MD_CTX mctx; + EVP_MD_CTX_init(&mctx); + rv = do_sign_init(err, &mctx, pkey, md, sigopts); + if (rv > 0) + rv = X509_CRL_sign_ctx(x, &mctx); + EVP_MD_CTX_cleanup(&mctx); + return rv > 0 ? 1 : 0; + } + +