#define TYPE_RSA 1
#define TYPE_DSA 2
#define TYPE_DH 3
+#define TYPE_ECDSA 4
int MAIN(int, char **);
ENGINE *e = NULL;
#ifndef OPENSSL_NO_DSA
DSA *dsa_params=NULL;
+#endif
+#ifndef OPENSSL_NO_ECDSA
+ ECDSA *ecdsa_params = NULL;
#endif
unsigned long nmflag = 0;
int ex=1,x509=0,days=30;
unsigned long chtype = MBSTRING_ASC;
#ifndef MONOLITH
MS_STATIC char config_name[256];
+ long errline;
#endif
req_conf = NULL;
goto end;
}
- dtmp=X509_get_pubkey(xtmp);
+ 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);
}
}
BIO_free(in);
- newkey=BN_num_bits(dsa_params->p);
in=NULL;
+ newkey=BN_num_bits(dsa_params->p);
}
else
#endif
+#ifndef OPENSSL_NO_ECDSA
+ if (strncmp("ecdsa:",p,4) == 0)
+ {
+ X509 *xtmp=NULL;
+ EVP_PKEY *dtmp;
+
+ pkey_type=TYPE_ECDSA;
+ p+=6;
+ if ((in=BIO_new_file(p,"r")) == NULL)
+ {
+ perror(p);
+ goto end;
+ }
+ if ((ecdsa_params = PEM_read_bio_ECDSAParameters(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 ECDSA parameters from file\n");
+ goto end;
+ }
+
+ if ((dtmp=X509_get_pubkey(xtmp)) == NULL) goto end;
+ if (dtmp->type == EVP_PKEY_ECDSA)
+ ecdsa_params = ECDSAParameters_dup(dtmp->pkey.ecdsa);
+ EVP_PKEY_free(dtmp);
+ X509_free(xtmp);
+ if (ecdsa_params == NULL)
+ {
+ BIO_printf(bio_err,"Certificate does not contain ECDSA parameters\n");
+ goto end;
+ }
+ }
+
+ BIO_free(in);
+ in=NULL;
+
+ {
+ BIGNUM *order = BN_new();
+
+ if (!order)
+ goto end;
+ if (!EC_GROUP_get_order(ecdsa_params->group, order, NULL))
+ goto end;
+ newkey = BN_num_bits(order);
+ BN_free(order);
+ }
+
+ }
+ else
+#endif
#ifndef OPENSSL_NO_DH
if (strncmp("dh:",p,4) == 0)
{
BIO_printf(bio_err," the random number generator\n");
BIO_printf(bio_err," -newkey rsa:bits generate a new RSA key of 'bits' in size\n");
BIO_printf(bio_err," -newkey dsa:file generate a new DSA key, parameters taken from CA in 'file'\n");
+ BIO_printf(bio_err," -newkey ecdsa:file generate a new ECDSA key, parameters taken from CA in 'file'\n");
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," -extensions .. specify certificate extension section (override value in config file)\n");
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");
goto end;
}
}
default_config_file=p;
config=NCONF_new(NULL);
- i=NCONF_load(config, p);
+ i=NCONF_load(config, p, &errline);
#endif
if (template != NULL)
if (req_conf != NULL)
{
+ if (!load_config(bio_err, req_conf))
+ goto end;
p=NCONF_get_string(req_conf,NULL,"oid_file");
if (p == NULL)
ERR_clear_error();
message */
goto end;
}
- if (EVP_PKEY_type(pkey->type) == EVP_PKEY_DSA)
+ if (EVP_PKEY_type(pkey->type) == EVP_PKEY_DSA || EVP_PKEY_type(pkey->type) == EVP_PKEY_ECDSA)
{
char *randfile = NCONF_get_string(req_conf,SECTION,"RANDFILE");
if (randfile == NULL)
newkey=DEFAULT_KEY_LENGTH;
}
- if (newkey < MIN_KEY_LENGTH)
+ if (newkey < MIN_KEY_LENGTH && (pkey_type == TYPE_RSA || pkey_type == TYPE_DSA))
+ /* TODO: appropriate minimal keylength for the different algorithm (esp. ECDSA) */
{
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);
goto end;
}
BIO_printf(bio_err,"Generating a %d bit %s private key\n",
- newkey,(pkey_type == TYPE_RSA)?"RSA":"DSA");
+ newkey,(pkey_type == TYPE_RSA)?"RSA":(pkey_type == TYPE_DSA)?"DSA":"ECDSA");
if ((pkey=EVP_PKEY_new()) == NULL) goto end;
dsa_params=NULL;
}
#endif
+#ifndef OPENSSL_NO_ECDSA
+ if (pkey_type == TYPE_ECDSA)
+ {
+ if (!ECDSA_generate_key(ecdsa_params)) goto end;
+ if (!EVP_PKEY_assign_ECDSA(pkey, ecdsa_params)) goto end;
+ ecdsa_params = NULL;
+ }
+#endif
app_RAND_write_file(randfile, bio_err);
#ifndef OPENSSL_NO_DSA
if (pkey->type == EVP_PKEY_DSA)
digest=EVP_dss1();
+#endif
+#ifndef OPENSSL_NO_ECDSA
+ if (pkey->type == EVP_PKEY_ECDSA)
+ digest=EVP_ecdsa();
#endif
if (req == NULL)
{
/* Set version to V3 */
if(!X509_set_version(x509ss, 2)) goto end;
if (serial)
- X509_set_serialNumber(x509ss, serial);
+ {
+ if (!X509_set_serialNumber(x509ss, serial)) goto end;
+ }
else
- ASN1_INTEGER_set(X509_get_serialNumber(x509ss),0L);
-
- X509_set_issuer_name(x509ss,
- X509_REQ_get_subject_name(req));
- X509_gmtime_adj(X509_get_notBefore(x509ss),0);
- X509_gmtime_adj(X509_get_notAfter(x509ss),
- (long)60*60*24*days);
- X509_set_subject_name(x509ss,
- X509_REQ_get_subject_name(req));
+ {
+ if (!ASN1_INTEGER_set(X509_get_serialNumber(x509ss),0L)) 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_set_subject_name(x509ss, X509_REQ_get_subject_name(req))) goto end;
tmppkey = X509_REQ_get_pubkey(req);
- X509_set_pubkey(x509ss,tmppkey);
+ if (!tmppkey || !X509_set_pubkey(x509ss,tmppkey)) goto end;
EVP_PKEY_free(tmppkey);
/* Set up V3 context struct */
OBJ_cleanup();
#ifndef OPENSSL_NO_DSA
if (dsa_params != NULL) DSA_free(dsa_params);
+#endif
+#ifndef OPENSSL_NO_ECDSA
+ if (ecdsa_params != NULL) ECDSA_free(ecdsa_params);
#endif
apps_shutdown();
EXIT(ex);
}
if(!i) goto err;
- X509_REQ_set_pubkey(req,pkey);
+ if (!X509_REQ_set_pubkey(req,pkey)) goto err;
ret=1;
err:
return(ret);
}
+/*
+ * 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)
{
- X509_NAME *n = NULL;
+ size_t buflen = strlen (subject)+1; /* to copy the types and values into. due to escaping, the copy can only become shorter */
+ char *buf = malloc (buflen);
+ size_t max_ne = buflen / 2 + 1; /* maximum number of name elements */
+ char **ne_types = malloc (max_ne * sizeof (char *));
+ char **ne_values = malloc (max_ne * sizeof (char *));
- int i, nid, ne_num=0;
+ char *sp = subject, *bp = buf;
+ int i, ne_num = 0;
- char *ne_name = NULL;
- char *ne_value = NULL;
-
- char *tmp = NULL;
- char *p[2];
+ X509_NAME *n = NULL;
+ int nid;
- char *str_list[256];
-
- p[0] = ",/";
- p[1] = "=";
+ if (!buf || !ne_types || !ne_values)
+ {
+ BIO_printf(bio_err, "malloc error\n");
+ goto error0;
+ }
- n = X509_NAME_new();
+ if (*subject != '/')
+ {
+ BIO_printf(bio_err, "Subject does not start with '/'.\n");
+ goto error0;
+ }
+ sp++; /* skip leading / */
- tmp = strtok(subject, p[0]);
- while((tmp != NULL) && (ne_num < (sizeof str_list/sizeof *str_list)))
+ while (*sp)
+ {
+ /* collect type */
+ ne_types[ne_num] = bp;
+ while (*sp)
{
- char *token = tmp;
-
- while (token[0] == ' ')
- token++;
- str_list[ne_num] = token;
-
- tmp = strtok(NULL, p[0]);
- ne_num++;
+ 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 error0;
+ }
+ 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 error0;
+ }
+ 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 error0;
+ }
+ else if (*sp == '/')
+ {
+ sp++;
+ *bp++ = '\0';
+ break;
+ }
+ else
+ *bp++ = *sp++;
}
+ *bp++ = '\0';
+ ne_num++;
+ }
+
+ if (!(n = X509_NAME_new()))
+ goto error0;
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, chtype, (unsigned char*)ne_value, -1,-1,0))
- {
- X509_NAME_free(n);
- return 0;
- }
+ if (!X509_NAME_add_entry_by_NID(n, nid, chtype, (unsigned char*)ne_values[i], -1,-1,0))
+ goto error1;
+
}
if (!X509_REQ_set_subject_name(req, n))
- return 0;
+ goto error1;
X509_NAME_free(n);
+ free (ne_values);
+ free (ne_types);
+ free (buf);
return 1;
+
+error1:
+ X509_NAME_free(n);
+error0:
+ free (ne_values);
+ free (ne_types);
+ free (buf);
+ return 0;
}