X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=apps%2Freq.c;h=e2555b6fbe9d31e9a0f6aa838df9dc5ddaeb3b2b;hp=ac14fdb8c67436a2b1d35ffc55c91ab8785b433a;hb=2b264aee6f3b92f14cb3e3dc5b27d14831870923;hpb=6738bf1417289a14758590fca5a26b62c9b2c0be diff --git a/apps/req.c b/apps/req.c index ac14fdb8c6..e2555b6fbe 100644 --- a/apps/req.c +++ b/apps/req.c @@ -1,7 +1,7 @@ /* * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html @@ -11,6 +11,7 @@ #include #include #include +#include #include "apps.h" #include "progs.h" #include @@ -23,6 +24,7 @@ #include #include #include +#include #ifndef OPENSSL_NO_RSA # include #endif @@ -30,7 +32,6 @@ # include #endif -#define SECTION "req" #define BITS "default_bits" #define KEYFILE "default_keyfile" @@ -63,6 +64,11 @@ 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 build_data(char *text, const char *def, + char *value, int n_min, int n_max, + char *buf, const int buf_size, + const char *desc1, const char *desc2 + ); static int req_check_len(int len, int n_min, int n_max); static int check_end(const char *str, const char *end); static int join(char buf[], size_t buf_size, const char *name, @@ -70,6 +76,8 @@ static int join(char buf[], size_t buf_size, const char *name, static EVP_PKEY_CTX *set_keygen_ctx(const char *gstr, int *pkey_type, long *pkeylen, char **palgnam, ENGINE *keygen_engine); + +static const char *section = "req"; static CONF *req_conf = NULL; static CONF *addext_conf = NULL; static int batch = 0; @@ -79,46 +87,37 @@ typedef enum OPTION_choice { OPT_INFORM, OPT_OUTFORM, OPT_ENGINE, OPT_KEYGEN_ENGINE, OPT_KEY, OPT_PUBKEY, OPT_NEW, OPT_CONFIG, OPT_KEYFORM, OPT_IN, OPT_OUT, OPT_KEYOUT, OPT_PASSIN, OPT_PASSOUT, OPT_NEWKEY, - OPT_PKEYOPT, OPT_SIGOPT, OPT_BATCH, OPT_NEWHDR, OPT_MODULUS, + OPT_PKEYOPT, OPT_SIGOPT, OPT_VFYOPT, OPT_BATCH, OPT_NEWHDR, OPT_MODULUS, OPT_VERIFY, OPT_NODES, OPT_NOOUT, OPT_VERBOSE, OPT_UTF8, OPT_NAMEOPT, OPT_REQOPT, OPT_SUBJ, OPT_SUBJECT, OPT_TEXT, OPT_X509, OPT_MULTIVALUE_RDN, OPT_DAYS, OPT_SET_SERIAL, OPT_ADDEXT, OPT_EXTENSIONS, OPT_REQEXTS, OPT_PRECERT, OPT_MD, - OPT_R_ENUM + OPT_SECTION, + OPT_R_ENUM, OPT_PROV_ENUM } OPTION_CHOICE; const OPTIONS req_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, - {"inform", OPT_INFORM, 'F', "Input format - DER or PEM"}, - {"outform", OPT_OUTFORM, 'F', "Output format - DER or PEM"}, +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, + {"keygen_engine", OPT_KEYGEN_ENGINE, 's', + "Specify engine to be used for key generation operations"}, +#endif {"in", OPT_IN, '<', "Input file"}, - {"out", OPT_OUT, '>', "Output file"}, - {"key", OPT_KEY, 's', "Private key to use"}, - {"keyform", OPT_KEYFORM, 'f', "Key file format"}, - {"pubkey", OPT_PUBKEY, '-', "Output public key"}, + {"inform", OPT_INFORM, 'F', "Input format - DER or PEM"}, + {"verify", OPT_VERIFY, '-', "Verify signature on REQ"}, + + OPT_SECTION("Certificate"), {"new", OPT_NEW, '-', "New request"}, {"config", OPT_CONFIG, '<', "Request template file"}, - {"keyout", OPT_KEYOUT, '>', "File to send the key to"}, - {"passin", OPT_PASSIN, 's', "Private key password source"}, - {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, - OPT_R_OPTIONS, - {"newkey", OPT_NEWKEY, 's', "Specify as type:bits"}, - {"pkeyopt", OPT_PKEYOPT, 's', "Public key options as opt:value"}, - {"sigopt", OPT_SIGOPT, 's', "Signature parameter in n:v form"}, - {"batch", OPT_BATCH, '-', - "Do not ask anything during request generation"}, - {"newhdr", OPT_NEWHDR, '-', "Output \"NEW\" in the header lines"}, - {"modulus", OPT_MODULUS, '-', "RSA modulus"}, - {"verify", OPT_VERIFY, '-', "Verify signature on REQ"}, - {"nodes", OPT_NODES, '-', "Don't encrypt the output key"}, - {"noout", OPT_NOOUT, '-', "Do not output REQ"}, - {"verbose", OPT_VERBOSE, '-', "Verbose output"}, + {"section", OPT_SECTION, 's', "Config section to use (default \"req\")"}, {"utf8", OPT_UTF8, '-', "Input characters are UTF8 (default ASCII)"}, - {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"}, + {"nameopt", OPT_NAMEOPT, 's', "Certificate subject/issuer name printing options"}, {"reqopt", OPT_REQOPT, 's', "Various request text options"}, {"text", OPT_TEXT, '-', "Text form of request"}, {"x509", OPT_X509, '-', - "Output a x509 structure instead of a cert request"}, + "Output an x509 structure instead of a cert request"}, {OPT_MORE_STR, 1, 1, "(Required by some CA's)"}, {"subj", OPT_SUBJ, 's', "Set or modify request subject"}, {"subject", OPT_SUBJECT, '-', "Output the request's subject"}, @@ -133,15 +132,99 @@ const OPTIONS req_options[] = { {"reqexts", OPT_REQEXTS, 's', "Request extension section (override value in config file)"}, {"precert", OPT_PRECERT, '-', "Add a poison extension (implies -new)"}, + + OPT_SECTION("Keys and Signing"), + {"key", OPT_KEY, 's', "Private key to use"}, + {"keyform", OPT_KEYFORM, 'f', "Key file format"}, + {"pubkey", OPT_PUBKEY, '-', "Output public key"}, + {"keyout", OPT_KEYOUT, '>', "File to send the key to"}, + {"passin", OPT_PASSIN, 's', "Private key password source"}, + {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, + {"newkey", OPT_NEWKEY, 's', "Specify as type:bits"}, + {"pkeyopt", OPT_PKEYOPT, 's', "Public key options as opt:value"}, + {"sigopt", OPT_SIGOPT, 's', "Signature parameter in n:v form"}, + {"vfyopt", OPT_VFYOPT, 's', "Verification parameter in n:v form"}, {"", OPT_MD, '-', "Any supported digest"}, -#ifndef OPENSSL_NO_ENGINE - {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, - {"keygen_engine", OPT_KEYGEN_ENGINE, 's', - "Specify engine to be used for key generation operations"}, -#endif + + OPT_SECTION("Output"), + {"out", OPT_OUT, '>', "Output file"}, + {"outform", OPT_OUTFORM, 'F', "Output format - DER or PEM"}, + {"batch", OPT_BATCH, '-', + "Do not ask anything during request generation"}, + {"verbose", OPT_VERBOSE, '-', "Verbose output"}, + {"nodes", OPT_NODES, '-', "Don't encrypt the output key"}, + {"noout", OPT_NOOUT, '-', "Do not output REQ"}, + {"newhdr", OPT_NEWHDR, '-', "Output \"NEW\" in the header lines"}, + {"modulus", OPT_MODULUS, '-', "RSA modulus"}, + + OPT_R_OPTIONS, + OPT_PROV_OPTIONS, {NULL} }; + +/* + * An LHASH of strings, where each string is an extension name. + */ +static unsigned long ext_name_hash(const OPENSSL_STRING *a) +{ + return OPENSSL_LH_strhash((const char *)a); +} + +static int ext_name_cmp(const OPENSSL_STRING *a, const OPENSSL_STRING *b) +{ + return strcmp((const char *)a, (const char *)b); +} + +static void exts_cleanup(OPENSSL_STRING *x) +{ + OPENSSL_free((char *)x); +} + +/* + * Is the |kv| key already duplicated? This is remarkably tricky to get + * right. Return 0 if unique, -1 on runtime error; 1 if found or a syntax + * error. + */ +static int duplicated(LHASH_OF(OPENSSL_STRING) *addexts, char *kv) +{ + char *p; + size_t off; + + /* Check syntax. */ + /* Skip leading whitespace, make a copy. */ + while (*kv && isspace(*kv)) + if (*++kv == '\0') + return 1; + if ((p = strchr(kv, '=')) == NULL) + return 1; + off = p - kv; + if ((kv = OPENSSL_strdup(kv)) == NULL) + return -1; + + /* Skip trailing space before the equal sign. */ + for (p = kv + off; p > kv; --p) + if (!isspace(p[-1])) + break; + if (p == kv) { + OPENSSL_free(kv); + return 1; + } + *p = '\0'; + + /* Finally have a clean "key"; see if it's there [by attempt to add it]. */ + p = (char *)lh_OPENSSL_STRING_insert(addexts, (OPENSSL_STRING*)kv); + if (p != NULL) { + OPENSSL_free(p); + return 1; + } else if (lh_OPENSSL_STRING_error(addexts)) { + OPENSSL_free(kv); + return -1; + } + + return 0; +} + int req_main(int argc, char **argv) { ASN1_INTEGER *serial = NULL; @@ -149,7 +232,8 @@ int req_main(int argc, char **argv) ENGINE *e = NULL, *gen_eng = NULL; EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *genctx = NULL; - STACK_OF(OPENSSL_STRING) *pkeyopts = NULL, *sigopts = NULL; + STACK_OF(OPENSSL_STRING) *pkeyopts = NULL, *sigopts = NULL, *vfyopts = NULL; + LHASH_OF(OPENSSL_STRING) *addexts = NULL; X509 *x509ss = NULL; X509_REQ *req = NULL; const EVP_CIPHER *cipher = NULL; @@ -220,6 +304,9 @@ int req_main(int argc, char **argv) case OPT_CONFIG: template = opt_arg(); break; + case OPT_SECTION: + section = opt_arg(); + break; case OPT_KEYFORM: if (!opt_format(opt_arg(), OPT_FMT_ANY, &keyform)) goto opthelp; @@ -243,14 +330,19 @@ int req_main(int argc, char **argv) if (!opt_rand(o)) goto end; break; + case OPT_PROV_CASES: + if (!opt_provider(o)) + goto end; + break; case OPT_NEWKEY: keyalg = opt_arg(); newreq = 1; break; case OPT_PKEYOPT: - if (!pkeyopts) + if (pkeyopts == NULL) pkeyopts = sk_OPENSSL_STRING_new_null(); - if (!pkeyopts || !sk_OPENSSL_STRING_push(pkeyopts, opt_arg())) + if (pkeyopts == NULL + || !sk_OPENSSL_STRING_push(pkeyopts, opt_arg())) goto opthelp; break; case OPT_SIGOPT: @@ -259,6 +351,12 @@ int req_main(int argc, char **argv) if (!sigopts || !sk_OPENSSL_STRING_push(sigopts, opt_arg())) goto opthelp; break; + case OPT_VFYOPT: + if (!vfyopts) + vfyopts = sk_OPENSSL_STRING_new_null(); + if (!vfyopts || !sk_OPENSSL_STRING_push(vfyopts, opt_arg())) + goto opthelp; + break; case OPT_BATCH: batch = 1; break; @@ -319,11 +417,17 @@ int req_main(int argc, char **argv) multirdn = 1; break; case OPT_ADDEXT: - if (addext_bio == NULL) { + p = opt_arg(); + if (addexts == NULL) { + addexts = lh_OPENSSL_STRING_new(ext_name_hash, ext_name_cmp); addext_bio = BIO_new(BIO_s_mem()); + if (addexts == NULL || addext_bio == NULL) + goto end; } - if (addext_bio == NULL - || BIO_printf(addext_bio, "%s\n", opt_arg()) < 0) + i = duplicated(addexts, p); + if (i == 1) + goto opthelp; + if (i < 0 || BIO_printf(addext_bio, "%s\n", opt_arg()) < 0) goto end; break; case OPT_EXTENSIONS: @@ -361,12 +465,14 @@ int req_main(int argc, char **argv) if (verbose) BIO_printf(bio_err, "Using configuration from %s\n", template); - req_conf = app_load_config(template); + if ((req_conf = app_load_config(template)) == NULL) + goto end; if (addext_bio) { if (verbose) BIO_printf(bio_err, - "Using additional configuraton from command line\n"); - addext_conf = app_load_config_bio(addext_bio, NULL); + "Using additional configuration from command line\n"); + if ((addext_conf = app_load_config_bio(addext_bio, NULL)) == NULL) + goto end; } if (template != default_config_file && !app_load_modules(req_conf)) goto end; @@ -394,7 +500,7 @@ int req_main(int argc, char **argv) goto end; if (md_alg == NULL) { - p = NCONF_get_string(req_conf, SECTION, "default_md"); + p = NCONF_get_string(req_conf, section, "default_md"); if (p == NULL) { ERR_clear_error(); } else { @@ -405,7 +511,7 @@ int req_main(int argc, char **argv) } if (extensions == NULL) { - extensions = NCONF_get_string(req_conf, SECTION, V3_EXTENSIONS); + extensions = NCONF_get_string(req_conf, section, V3_EXTENSIONS); if (extensions == NULL) ERR_clear_error(); } @@ -433,19 +539,19 @@ int req_main(int argc, char **argv) if (passin == NULL) { passin = nofree_passin = - NCONF_get_string(req_conf, SECTION, "input_password"); + NCONF_get_string(req_conf, section, "input_password"); if (passin == NULL) ERR_clear_error(); } if (passout == NULL) { passout = nofree_passout = - NCONF_get_string(req_conf, SECTION, "output_password"); + NCONF_get_string(req_conf, section, "output_password"); if (passout == NULL) ERR_clear_error(); } - p = NCONF_get_string(req_conf, SECTION, STRING_MASK); + p = NCONF_get_string(req_conf, section, STRING_MASK); if (p == NULL) ERR_clear_error(); @@ -455,7 +561,7 @@ int req_main(int argc, char **argv) } if (chtype != MBSTRING_UTF8) { - p = NCONF_get_string(req_conf, SECTION, UTF8_IN); + p = NCONF_get_string(req_conf, section, UTF8_IN); if (p == NULL) ERR_clear_error(); else if (strcmp(p, "yes") == 0) @@ -463,7 +569,7 @@ int req_main(int argc, char **argv) } if (req_exts == NULL) { - req_exts = NCONF_get_string(req_conf, SECTION, REQ_EXTENSIONS); + req_exts = NCONF_get_string(req_conf, section, REQ_EXTENSIONS); if (req_exts == NULL) ERR_clear_error(); } @@ -486,14 +592,14 @@ int req_main(int argc, char **argv) /* load_key() has already printed an appropriate message */ goto end; } else { - app_RAND_load_conf(req_conf, SECTION); + app_RAND_load_conf(req_conf, section); } } if (newreq && (pkey == NULL)) { - app_RAND_load_conf(req_conf, SECTION); + app_RAND_load_conf(req_conf, section); - if (!NCONF_get_number(req_conf, SECTION, BITS, &newkey)) { + if (!NCONF_get_number(req_conf, section, BITS, &newkey)) { newkey = DEFAULT_KEY_LENGTH; } @@ -512,6 +618,20 @@ int req_main(int argc, char **argv) goto end; } + if (pkey_type == EVP_PKEY_RSA && newkey > OPENSSL_RSA_MAX_MODULUS_BITS) + BIO_printf(bio_err, + "Warning: It is not recommended to use more than %d bit for RSA keys.\n" + " Your key size is %ld! Larger key size may behave not as expected.\n", + OPENSSL_RSA_MAX_MODULUS_BITS, newkey); + +#ifndef OPENSSL_NO_DSA + if (pkey_type == EVP_PKEY_DSA && newkey > OPENSSL_DSA_MAX_MODULUS_BITS) + BIO_printf(bio_err, + "Warning: It is not recommended to use more than %d bit for DSA keys.\n" + " Your key size is %ld! Larger key size may behave not as expected.\n", + OPENSSL_DSA_MAX_MODULUS_BITS, newkey); +#endif + if (genctx == NULL) { genctx = set_keygen_ctx(NULL, &pkey_type, &newkey, &keyalgstr, gen_eng); @@ -534,8 +654,7 @@ int req_main(int argc, char **argv) if (pkey_type == EVP_PKEY_EC) { BIO_printf(bio_err, "Generating an EC private key\n"); } else { - BIO_printf(bio_err, "Generating a %ld bit %s private key\n", - newkey, keyalgstr); + BIO_printf(bio_err, "Generating a %s private key\n", keyalgstr); } EVP_PKEY_CTX_set_cb(genctx, genpkey_cb); @@ -550,7 +669,7 @@ int req_main(int argc, char **argv) genctx = NULL; if (keyout == NULL) { - keyout = NCONF_get_string(req_conf, SECTION, KEYFILE); + keyout = NCONF_get_string(req_conf, section, KEYFILE); if (keyout == NULL) ERR_clear_error(); } @@ -563,10 +682,10 @@ int req_main(int argc, char **argv) if (out == NULL) goto end; - p = NCONF_get_string(req_conf, SECTION, "encrypt_rsa_key"); + p = NCONF_get_string(req_conf, section, "encrypt_rsa_key"); if (p == NULL) { ERR_clear_error(); - p = NCONF_get_string(req_conf, SECTION, "encrypt_key"); + p = NCONF_get_string(req_conf, section, "encrypt_key"); if (p == NULL) ERR_clear_error(); } @@ -757,7 +876,7 @@ int req_main(int argc, char **argv) goto end; } - i = X509_REQ_verify(req, tpubkey); + i = do_X509_REQ_verify(req, tpubkey, vfyopts); if (i < 0) { goto end; @@ -794,9 +913,19 @@ int req_main(int argc, char **argv) if (text) { if (x509) - X509_print_ex(out, x509ss, get_nameopt(), reqflag); + ret = X509_print_ex(out, x509ss, get_nameopt(), reqflag); else - X509_REQ_print_ex(out, req, get_nameopt(), reqflag); + ret = X509_REQ_print_ex(out, req, get_nameopt(), reqflag); + + if (ret == 0) { + if (x509) + BIO_printf(bio_err, "Error printing certificate\n"); + else + BIO_printf(bio_err, "Error printing certificate request\n"); + + ERR_print_errors(bio_err); + goto end; + } } if (subject) { @@ -859,6 +988,7 @@ int req_main(int argc, char **argv) ERR_print_errors(bio_err); } NCONF_free(req_conf); + NCONF_free(addext_conf); BIO_free(addext_bio); BIO_free(in); BIO_free_all(out); @@ -866,6 +996,9 @@ int req_main(int argc, char **argv) EVP_PKEY_CTX_free(genctx); sk_OPENSSL_STRING_free(pkeyopts); sk_OPENSSL_STRING_free(sigopts); + sk_OPENSSL_STRING_free(vfyopts); + lh_OPENSSL_STRING_doall(addexts, exts_cleanup); + lh_OPENSSL_STRING_free(addexts); #ifndef OPENSSL_NO_ENGINE ENGINE_free(gen_eng); #endif @@ -889,13 +1022,13 @@ static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, char *subj, int multirdn, STACK_OF(CONF_VALUE) *dn_sk, *attr_sk = NULL; char *tmp, *dn_sect, *attr_sect; - tmp = NCONF_get_string(req_conf, SECTION, PROMPT); + tmp = NCONF_get_string(req_conf, section, PROMPT); if (tmp == NULL) ERR_clear_error(); if ((tmp != NULL) && strcmp(tmp, "no") == 0) no_prompt = 1; - dn_sect = NCONF_get_string(req_conf, SECTION, DISTINGUISHED_NAME); + dn_sect = NCONF_get_string(req_conf, section, DISTINGUISHED_NAME); if (dn_sect == NULL) { BIO_printf(bio_err, "unable to find '%s' in config\n", DISTINGUISHED_NAME); @@ -907,7 +1040,7 @@ static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, char *subj, int multirdn, goto err; } - attr_sect = NCONF_get_string(req_conf, SECTION, ATTRIBUTES); + attr_sect = NCONF_get_string(req_conf, section, ATTRIBUTES); if (attr_sect == NULL) { ERR_clear_error(); attr_sk = NULL; @@ -974,8 +1107,7 @@ static int prompt_info(X509_REQ *req, char *type, *value; const char *def; CONF_VALUE *v; - X509_NAME *subj; - subj = X509_REQ_get_subject_name(req); + X509_NAME *subj = X509_REQ_get_subject_name(req); if (!batch) { BIO_printf(bio_err, @@ -1060,8 +1192,7 @@ static int prompt_info(X509_REQ *req, return 0; } if (X509_NAME_entry_count(subj) == 0) { - BIO_printf(bio_err, - "error, no objects specified in config file\n"); + BIO_printf(bio_err, "error, no objects specified in config file\n"); return 0; } @@ -1202,58 +1333,19 @@ 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; + int ret = 0; char buf[1024]; - start: - if (!batch) - BIO_printf(bio_err, "%s [%s]:", text, def); - (void)BIO_flush(bio_err); - if (value != NULL) { - if (!join(buf, sizeof(buf), value, "\n", "DN value")) - return 0; - BIO_printf(bio_err, "%s\n", value); - } else { - buf[0] = '\0'; - if (!batch) { - if (!fgets(buf, sizeof(buf), stdin)) - return 0; - } else { - buf[0] = '\n'; - buf[1] = '\0'; - } - } - - if (buf[0] == '\0') - return 0; - if (buf[0] == '\n') { - if ((def == NULL) || (def[0] == '\0')) - return 1; - if (!join(buf, sizeof(buf), def, "\n", "DN default")) - return 0; - } else if ((buf[0] == '.') && (buf[1] == '\n')) { - return 1; - } - i = strlen(buf); - if (buf[i - 1] != '\n') { - BIO_printf(bio_err, "weird input :-(\n"); - return 0; - } - buf[--i] = '\0'; -#ifdef CHARSET_EBCDIC - ebcdic2ascii(buf, buf, i); -#endif - if (!req_check_len(i, n_min, n_max)) { - if (batch || value) - return 0; - goto start; - } + ret = build_data(text, def, value, n_min, n_max, buf, sizeof(buf), + "DN value", "DN default"); + if ((ret == 0) || (ret == 1)) + return ret; + ret = 1; if (!X509_NAME_add_entry_by_NID(n, nid, chtype, (unsigned char *)buf, -1, -1, mval)) - goto err; - ret = 1; - err: + ret = 0; + return ret; } @@ -1261,21 +1353,45 @@ 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; - static char buf[1024]; + int ret = 0; + char buf[1024]; + + ret = build_data(text, def, value, n_min, n_max, buf, sizeof(buf), + "Attribute value", "Attribute default"); + if ((ret == 0) || (ret == 1)) + return ret; + ret = 1; + + if (!X509_REQ_add1_attr_by_NID(req, nid, chtype, + (unsigned char *)buf, -1)) { + BIO_printf(bio_err, "Error adding attribute\n"); + ERR_print_errors(bio_err); + ret = 0; + } + + return ret; +} + +static int build_data(char *text, const char *def, + char *value, int n_min, int n_max, + char *buf, const int buf_size, + const char *desc1, const char *desc2 + ) +{ + int i; start: if (!batch) BIO_printf(bio_err, "%s [%s]:", text, def); (void)BIO_flush(bio_err); if (value != NULL) { - if (!join(buf, sizeof(buf), value, "\n", "Attribute value")) + if (!join(buf, buf_size, value, "\n", desc1)) return 0; BIO_printf(bio_err, "%s\n", value); } else { buf[0] = '\0'; if (!batch) { - if (!fgets(buf, sizeof(buf), stdin)) + if (!fgets(buf, buf_size, stdin)) return 0; } else { buf[0] = '\n'; @@ -1288,7 +1404,7 @@ static int add_attribute_object(X509_REQ *req, char *text, const char *def, if (buf[0] == '\n') { if ((def == NULL) || (def[0] == '\0')) return 1; - if (!join(buf, sizeof(buf), def, "\n", "Attribute default")) + if (!join(buf, buf_size, def, "\n", desc2)) return 0; } else if ((buf[0] == '.') && (buf[1] == '\n')) { return 1; @@ -1308,17 +1424,7 @@ static int add_attribute_object(X509_REQ *req, char *text, const char *def, return 0; goto start; } - - if (!X509_REQ_add1_attr_by_NID(req, nid, chtype, - (unsigned char *)buf, -1)) { - BIO_printf(bio_err, "Error adding attribute\n"); - ERR_print_errors(bio_err); - goto err; - } - - return 1; - err: - return 0; + return 2; } static int req_check_len(int len, int n_min, int n_max) @@ -1531,60 +1637,135 @@ static int genpkey_cb(EVP_PKEY_CTX *ctx) return 1; } -static int do_sign_init(EVP_MD_CTX *ctx, EVP_PKEY *pkey, - const EVP_MD *md, STACK_OF(OPENSSL_STRING) *sigopts) +static int do_pkey_ctx_init(EVP_PKEY_CTX *pkctx, STACK_OF(OPENSSL_STRING) *opts) { - EVP_PKEY_CTX *pkctx = NULL; int i; - if (ctx == NULL) - return 0; - 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(bio_err, "parameter error \"%s\"\n", sigopt); + if (opts == NULL) + return 1; + + for (i = 0; i < sk_OPENSSL_STRING_num(opts); i++) { + char *opt = sk_OPENSSL_STRING_value(opts, i); + if (pkey_ctrl_string(pkctx, opt) <= 0) { + BIO_printf(bio_err, "parameter error \"%s\"\n", opt); + ERR_print_errors(bio_err); + return 0; + } + } + + return 1; +} + +static int do_x509_init(X509 *x, STACK_OF(OPENSSL_STRING) *opts) +{ + int i; + + if (opts == NULL) + return 1; + + for (i = 0; i < sk_OPENSSL_STRING_num(opts); i++) { + char *opt = sk_OPENSSL_STRING_value(opts, i); + if (x509_ctrl_string(x, opt) <= 0) { + BIO_printf(bio_err, "parameter error \"%s\"\n", opt); ERR_print_errors(bio_err); return 0; } } + return 1; } +static int do_x509_req_init(X509_REQ *x, STACK_OF(OPENSSL_STRING) *opts) +{ + int i; + + if (opts == NULL) + return 1; + + for (i = 0; i < sk_OPENSSL_STRING_num(opts); i++) { + char *opt = sk_OPENSSL_STRING_value(opts, i); + if (x509_req_ctrl_string(x, opt) <= 0) { + BIO_printf(bio_err, "parameter error \"%s\"\n", opt); + ERR_print_errors(bio_err); + return 0; + } + } + + return 1; +} + +static int do_sign_init(EVP_MD_CTX *ctx, EVP_PKEY *pkey, + const EVP_MD *md, STACK_OF(OPENSSL_STRING) *sigopts) +{ + EVP_PKEY_CTX *pkctx = NULL; + int def_nid; + + if (ctx == NULL) + return 0; + /* + * EVP_PKEY_get_default_digest_nid() returns 2 if the digest is mandatory + * for this algorithm. + */ + if (EVP_PKEY_get_default_digest_nid(pkey, &def_nid) == 2 + && def_nid == NID_undef) { + /* The signing algorithm requires there to be no digest */ + md = NULL; + } + return EVP_DigestSignInit(ctx, &pkctx, md, NULL, pkey) + && do_pkey_ctx_init(pkctx, sigopts); +} + int do_X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md, STACK_OF(OPENSSL_STRING) *sigopts) { - int rv; + int rv = 0; EVP_MD_CTX *mctx = EVP_MD_CTX_new(); - rv = do_sign_init(mctx, pkey, md, sigopts); - if (rv > 0) - rv = X509_sign_ctx(x, mctx); + if (do_sign_init(mctx, pkey, md, sigopts) > 0) + rv = (X509_sign_ctx(x, mctx) > 0); EVP_MD_CTX_free(mctx); - return rv > 0 ? 1 : 0; + return rv; } int do_X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md, STACK_OF(OPENSSL_STRING) *sigopts) { - int rv; + int rv = 0; EVP_MD_CTX *mctx = EVP_MD_CTX_new(); - rv = do_sign_init(mctx, pkey, md, sigopts); - if (rv > 0) - rv = X509_REQ_sign_ctx(x, mctx); + + if (do_sign_init(mctx, pkey, md, sigopts) > 0) + rv = (X509_REQ_sign_ctx(x, mctx) > 0); EVP_MD_CTX_free(mctx); - return rv > 0 ? 1 : 0; + return rv; +} + +int do_X509_verify(X509 *x, EVP_PKEY *pkey, STACK_OF(OPENSSL_STRING) *vfyopts) +{ + int rv = 0; + + if (do_x509_init(x, vfyopts) > 0) + rv = (X509_verify(x, pkey) > 0); + return rv; +} + +int do_X509_REQ_verify(X509_REQ *x, EVP_PKEY *pkey, + STACK_OF(OPENSSL_STRING) *vfyopts) +{ + int rv = 0; + + if (do_x509_req_init(x, vfyopts) > 0) + rv = (X509_REQ_verify(x, pkey) > 0); + return rv; } int do_X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md, STACK_OF(OPENSSL_STRING) *sigopts) { - int rv; + int rv = 0; EVP_MD_CTX *mctx = EVP_MD_CTX_new(); - rv = do_sign_init(mctx, pkey, md, sigopts); - if (rv > 0) - rv = X509_CRL_sign_ctx(x, mctx); + + if (do_sign_init(mctx, pkey, md, sigopts) > 0) + rv = (X509_CRL_sign_ctx(x, mctx) > 0); EVP_MD_CTX_free(mctx); - return rv > 0 ? 1 : 0; + return rv; }