X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=apps%2Freq.c;h=e728d5bf9511d6c501506393c2453fb42de1f210;hp=8304df8aa258e4e1fed122b0ce473d10d4482aae;hb=87d3a0cd9006f67fed0d3335d8b1c5ab94a26f8f;hpb=0b13e9f055d3f7be066dc2e89fc9f9822b12eca7 diff --git a/apps/req.c b/apps/req.c index 8304df8aa2..e728d5bf95 100644 --- a/apps/req.c +++ b/apps/req.c @@ -79,7 +79,13 @@ #include #include #include -#include "../crypto/cryptlib.h" +#include +#ifndef OPENSSL_NO_RSA +#include +#endif +#ifndef OPENSSL_NO_DSA +#include +#endif #define SECTION "req" @@ -119,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, @@ -129,44 +136,38 @@ 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; #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 + 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(STRING) *pkeyopts = 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; @@ -185,7 +186,8 @@ 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 char *to_free; @@ -228,6 +230,16 @@ int MAIN(int argc, char **argv) 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) { @@ -284,121 +296,20 @@ 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,3) == 0) - { - X509 *xtmp=NULL; - EVP_PKEY *dtmp; - - pkey_type=TYPE_EC; - p+=3; - 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 - { + if (--argc < 1) goto bad; - } - + keyalg = *(++argv); newreq=1; } + else if (strcmp(*argv,"-pkeyopt") == 0) + { + if (--argc < 1) + goto bad; + if (!pkeyopts) + pkeyopts = sk_STRING_new_null(); + if (!pkeyopts || !sk_STRING_push(pkeyopts, *(++argv))) + goto bad; + } else if (strcmp(*argv,"-batch") == 0) batch=1; else if (strcmp(*argv,"-newhdr") == 0) @@ -440,6 +351,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; @@ -511,6 +424,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"); @@ -562,13 +476,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) @@ -700,8 +617,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) @@ -718,6 +634,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) { @@ -725,49 +649,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_STRING_num(pkeyopts); i++) + { + genopt = sk_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) { @@ -866,14 +795,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(); @@ -882,7 +804,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)) { @@ -902,19 +824,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; @@ -936,7 +860,10 @@ loop: } if (!(i=X509_sign(x509ss,pkey,digest))) + { + ERR_print_errors(bio_err); goto end; + } } else { @@ -957,7 +884,10 @@ loop: goto end; } if (!(i=X509_REQ_sign(req,pkey,digest))) + { + ERR_print_errors(bio_err); goto end; + } } } @@ -975,7 +905,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; @@ -1094,7 +1024,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 @@ -1150,24 +1080,28 @@ end: BIO_free(in); BIO_free_all(out); EVP_PKEY_free(pkey); + if (genctx) + EVP_PKEY_CTX_free(genctx); + if (pkeyopts) + sk_STRING_free(pkeyopts); +#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(); 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; @@ -1217,7 +1151,7 @@ static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, char *subj, int attribs, else { if (subj) - i = build_subject(req, subj, chtype); + i = build_subject(req, subj, chtype, multirdn); else i = prompt_info(req, dn_sk, dn_sect, attr_sk, attr_sect, attribs, chtype); } @@ -1234,11 +1168,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)) @@ -1259,9 +1193,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); @@ -1302,36 +1237,43 @@ 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; - - if(strlen(v->name) > sizeof buf-9) + 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; } - sprintf(buf,"%s_default",v->name); 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(); @@ -1339,7 +1281,7 @@ start: for (;;) } 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) @@ -1369,13 +1311,13 @@ start2: for (;;) if ((nid=OBJ_txt2nid(type)) == NID_undef) goto start2; - if(strlen(v->name) > sizeof buf-9) + 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; } - sprintf(buf,"%s_default",type); if ((def=NCONF_get_string(req_conf,attr_sect,buf)) == NULL) { @@ -1384,7 +1326,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) { @@ -1392,11 +1334,11 @@ 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)) 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)) n_max = -1; @@ -1429,6 +1371,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; @@ -1445,8 +1388,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; } @@ -1468,8 +1422,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]; @@ -1478,9 +1432,8 @@ start: (void)BIO_flush(bio_err); if(value != NULL) { - OPENSSL_assert(strlen(value) < sizeof buf-2); - 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 @@ -1502,8 +1455,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); @@ -1519,14 +1472,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; @@ -1537,9 +1490,8 @@ start: (void)BIO_flush(bio_err); if (value != NULL) { - OPENSSL_assert(strlen(value) < sizeof buf-2); - 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 @@ -1561,8 +1513,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); @@ -1590,23 +1542,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)) @@ -1623,13 +1558,192 @@ 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; + } + + 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; + } + } + + 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; + }