apps/req.c: add -CA and -CAkey options; improve code and doc

Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
(Merged from https://github.com/openssl/openssl/pull/13658)
This commit is contained in:
Dr. David von Oheimb 2020-12-19 19:46:14 +01:00 committed by Dr. David von Oheimb
parent 1579594383
commit 6ad957f127
3 changed files with 288 additions and 208 deletions

View File

@ -30,22 +30,24 @@
# include <openssl/dsa.h>
#endif
#define BITS "default_bits"
#define KEYFILE "default_keyfile"
#define PROMPT "prompt"
#define DISTINGUISHED_NAME "distinguished_name"
#define ATTRIBUTES "attributes"
#define V3_EXTENSIONS "x509_extensions"
#define REQ_EXTENSIONS "req_extensions"
#define STRING_MASK "string_mask"
#define UTF8_IN "utf8"
#define BITS "default_bits"
#define KEYFILE "default_keyfile"
#define PROMPT "prompt"
#define DISTINGUISHED_NAME "distinguished_name"
#define ATTRIBUTES "attributes"
#define V3_EXTENSIONS "x509_extensions"
#define REQ_EXTENSIONS "req_extensions"
#define STRING_MASK "string_mask"
#define UTF8_IN "utf8"
#define DEFAULT_KEY_LENGTH 2048
#define MIN_KEY_LENGTH 512
#define DEFAULT_KEY_LENGTH 2048
#define MIN_KEY_LENGTH 512
#define DEFAULT_DAYS 30 /* default cert validity period in days */
#define UNSET_DAYS -2 /* -1 may be used for testing expiration checks */
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, const char *subj, unsigned long chtype,
static int build_subject(X509_REQ *req, const char *fsubj, unsigned long chtype,
int multirdn);
static int prompt_info(X509_REQ *req,
STACK_OF(CONF_VALUE) *dn_sk, const char *dn_sect,
@ -61,11 +63,9 @@ 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 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,
@ -87,6 +87,7 @@ typedef enum OPTION_choice {
OPT_PKEYOPT, OPT_SIGOPT, OPT_VFYOPT, OPT_BATCH, OPT_NEWHDR, OPT_MODULUS,
OPT_VERIFY, OPT_NOENC, OPT_NODES, OPT_NOOUT, OPT_VERBOSE, OPT_UTF8,
OPT_NAMEOPT, OPT_REQOPT, OPT_SUBJ, OPT_SUBJECT, OPT_TEXT, OPT_X509,
OPT_CA, OPT_CAKEY,
OPT_MULTIVALUE_RDN, OPT_DAYS, OPT_SET_SERIAL, OPT_ADDEXT, OPT_EXTENSIONS,
OPT_REQEXTS, OPT_PRECERT, OPT_MD,
OPT_SECTION,
@ -101,7 +102,7 @@ const OPTIONS req_options[] = {
{"keygen_engine", OPT_KEYGEN_ENGINE, 's',
"Specify engine to be used for key generation operations"},
#endif
{"in", OPT_IN, '<', "Input file"},
{"in", OPT_IN, '<', "X.509 request input file"},
{"inform", OPT_INFORM, 'F', "Input format - DER or PEM"},
{"verify", OPT_VERIFY, '-', "Verify signature on REQ"},
@ -115,9 +116,13 @@ const OPTIONS req_options[] = {
{"text", OPT_TEXT, '-', "Text form of request"},
{"x509", OPT_X509, '-',
"Output an x509 structure instead of a cert request"},
{"CA", OPT_CA, '<', "Issuer certificate to use with -x509"},
{"CAkey", OPT_CAKEY, 's',
"Issuer private key to use with -x509; default is -CA arg"},
{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"},
{"subj", OPT_SUBJ, 's', "Set or modify subject of request or cert"},
{"subject", OPT_SUBJECT, '-',
"Print the subject of the output request or cert"},
{"multivalue-rdn", OPT_MULTIVALUE_RDN, '-',
"Deprecated; multi-valued RDNs support is always on."},
{"days", OPT_DAYS, 'p', "Number of days cert is valid for"},
@ -134,8 +139,8 @@ const OPTIONS req_options[] = {
{"key", OPT_KEY, 's', "Private key to use"},
{"keyform", OPT_KEYFORM, 'f', "Key file format (ENGINE, other values ignored)"},
{"pubkey", OPT_PUBKEY, '-', "Output public key"},
{"keyout", OPT_KEYOUT, '>', "File to send the key to"},
{"passin", OPT_PASSIN, 's', "Private key password source"},
{"keyout", OPT_KEYOUT, '>', "File to save newly created private key"},
{"passin", OPT_PASSIN, 's', "Private key and certificate 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"},
@ -160,7 +165,6 @@ const OPTIONS req_options[] = {
{NULL}
};
/*
* An LHASH of strings, where each string is an extension name.
*/
@ -180,9 +184,8 @@ static void exts_cleanup(OPENSSL_STRING *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.
* 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)
{
@ -211,7 +214,7 @@ static int duplicated(LHASH_OF(OPENSSL_STRING) *addexts, char *kv)
*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);
p = (char *)lh_OPENSSL_STRING_insert(addexts, (OPENSSL_STRING *)kv);
if (p != NULL) {
OPENSSL_free(p);
return 1;
@ -228,30 +231,32 @@ int req_main(int argc, char **argv)
ASN1_INTEGER *serial = NULL;
BIO *out = NULL;
ENGINE *e = NULL, *gen_eng = NULL;
EVP_PKEY *pkey = NULL;
EVP_PKEY *pkey = NULL, *CAkey = NULL;
EVP_PKEY_CTX *genctx = NULL;
STACK_OF(OPENSSL_STRING) *pkeyopts = NULL, *sigopts = NULL, *vfyopts = NULL;
LHASH_OF(OPENSSL_STRING) *addexts = NULL;
X509 *x509ss = NULL;
X509 *new_x509 = NULL, *CAcert = NULL;
X509_REQ *req = NULL;
const EVP_CIPHER *cipher = NULL;
const EVP_MD *md_alg = NULL, *digest = NULL;
BIO *addext_bio = NULL;
char *extensions = NULL, *infile = NULL;
char *extensions = NULL;
const char *infile = NULL, *CAfile = NULL, *CAkeyfile = NULL;
char *outfile = NULL, *keyfile = NULL;
char *keyalgstr = NULL, *p, *prog, *passargin = NULL, *passargout = NULL;
char *passin = NULL, *passout = NULL;
char *nofree_passin = NULL, *nofree_passout = NULL;
char *req_exts = NULL, *subj = NULL;
char *req_exts = NULL, *fsubj = NULL;
char *template = default_config_file, *keyout = NULL;
const char *keyalg = NULL;
OPTION_CHOICE o;
int ret = 1, x509 = 0, days = 0, i = 0, newreq = 0, verbose = 0;
int pkey_type = -1, private = 0;
int days = UNSET_DAYS;
int ret = 1, gen_x509 = 0, i = 0, newreq = 0, verbose = 0;
int pkey_type = -1;
int informat = FORMAT_PEM, outformat = FORMAT_PEM, keyform = FORMAT_PEM;
int modulus = 0, multirdn = 1, verify = 0, noout = 0, text = 0;
int noenc = 0, newhdr = 0, subject = 0, pubkey = 0, precert = 0;
long newkey = -1;
long newkey_len = -1;
unsigned long chtype = MBSTRING_ASC, reqflag = 0;
#ifndef OPENSSL_NO_DES
@ -392,10 +397,21 @@ int req_main(int argc, char **argv)
text = 1;
break;
case OPT_X509:
x509 = 1;
gen_x509 = 1;
break;
case OPT_CA:
CAfile = opt_arg();
break;
case OPT_CAKEY:
CAkeyfile = opt_arg();
break;
case OPT_DAYS:
days = atoi(opt_arg());
if (days < -1) {
BIO_printf(bio_err, "%s: -days parameter arg must be >= -1\n",
prog);
goto end;
}
break;
case OPT_SET_SERIAL:
if (serial != NULL) {
@ -410,7 +426,7 @@ int req_main(int argc, char **argv)
subject = 1;
break;
case OPT_SUBJ:
subj = opt_arg();
fsubj = opt_arg();
break;
case OPT_MULTIVALUE_RDN:
/* obsolete */
@ -453,14 +469,11 @@ int req_main(int argc, char **argv)
if (argc != 0)
goto opthelp;
if (days && !x509)
if (days != UNSET_DAYS && !gen_x509)
BIO_printf(bio_err, "Ignoring -days; not generating a certificate\n");
if (x509 && infile == NULL)
if (gen_x509 && infile == NULL)
newreq = 1;
/* TODO: simplify this as pkey is still always NULL here */
private = newreq && (pkey == NULL) ? 1 : 0;
if (!app_passwd(passargin, passargout, &passin, &passout)) {
BIO_printf(bio_err, "Error getting passwords\n");
goto end;
@ -487,10 +500,11 @@ int req_main(int argc, char **argv)
oid_bio = BIO_new_file(p, "r");
if (oid_bio == NULL) {
/*-
BIO_printf(bio_err,"problems opening %s for extra oid's\n",p);
ERR_print_errors(bio_err);
*/
if (verbose) {
BIO_printf(bio_err,
"Problems opening '%s' for extra OIDs\n", p);
ERR_print_errors(bio_err);
}
} else {
OBJ_create_objects(oid_bio);
BIO_free(oid_bio);
@ -523,7 +537,8 @@ int req_main(int argc, char **argv)
X509V3_set_nconf(&ctx, req_conf);
if (!X509V3_EXT_add_nconf(req_conf, &ctx, extensions, NULL)) {
BIO_printf(bio_err,
"Error checking x509 extension section %s\n", extensions);
"Error checking x509 extension section %s\n",
extensions);
goto end;
}
}
@ -594,44 +609,46 @@ int req_main(int argc, char **argv)
app_RAND_load_conf(req_conf, section);
}
if (newreq && (pkey == NULL)) {
if (newreq && pkey == NULL) {
app_RAND_load_conf(req_conf, section);
if (!NCONF_get_number(req_conf, section, BITS, &newkey)) {
newkey = DEFAULT_KEY_LENGTH;
if (!NCONF_get_number(req_conf, section, BITS, &newkey_len)) {
newkey_len = DEFAULT_KEY_LENGTH;
}
if (keyalg != NULL) {
genctx = set_keygen_ctx(keyalg, &pkey_type, &newkey,
genctx = set_keygen_ctx(keyalg, &pkey_type, &newkey_len,
&keyalgstr, gen_eng);
if (genctx == NULL)
goto end;
}
if (newkey < MIN_KEY_LENGTH
if (newkey_len < 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 %ld\n",
MIN_KEY_LENGTH, newkey);
BIO_printf(bio_err, "Private key length is too short,\n");
BIO_printf(bio_err, "it needs to be at least %d bits, not %ld.\n",
MIN_KEY_LENGTH, newkey_len);
goto end;
}
if (pkey_type == EVP_PKEY_RSA && newkey > OPENSSL_RSA_MAX_MODULUS_BITS)
if (pkey_type == EVP_PKEY_RSA
&& newkey_len > 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);
OPENSSL_RSA_MAX_MODULUS_BITS, newkey_len);
#ifndef OPENSSL_NO_DSA
if (pkey_type == EVP_PKEY_DSA && newkey > OPENSSL_DSA_MAX_MODULUS_BITS)
if (pkey_type == EVP_PKEY_DSA
&& newkey_len > 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);
OPENSSL_DSA_MAX_MODULUS_BITS, newkey_len);
#endif
if (genctx == NULL) {
genctx = set_keygen_ctx(NULL, &pkey_type, &newkey,
genctx = set_keygen_ctx(NULL, &pkey_type, &newkey_len,
&keyalgstr, gen_eng);
if (genctx == NULL)
goto end;
@ -642,7 +659,7 @@ int req_main(int argc, char **argv)
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);
BIO_printf(bio_err, "Key parameter error \"%s\"\n", genopt);
goto end;
}
}
@ -672,10 +689,10 @@ int req_main(int argc, char **argv)
}
if (keyout == NULL)
BIO_printf(bio_err, "writing new private key to stdout\n");
BIO_printf(bio_err, "Writing new private key to stdout\n");
else
BIO_printf(bio_err, "writing new private key to '%s'\n", keyout);
out = bio_open_owner(keyout, outformat, private);
BIO_printf(bio_err, "Writing new private key to '%s'\n", keyout);
out = bio_open_owner(keyout, outformat, newreq);
if (out == NULL)
goto end;
@ -693,7 +710,7 @@ int req_main(int argc, char **argv)
i = 0;
loop:
assert(private);
assert(newreq);
if (!PEM_write_bio_PrivateKey(out, pkey, cipher,
NULL, 0, NULL, passout)) {
if ((ERR_GET_REASON(ERR_peek_error()) ==
@ -715,9 +732,41 @@ int req_main(int argc, char **argv)
goto end;
}
if (newreq || x509) {
if (pkey == NULL) {
BIO_printf(bio_err, "you need to specify a private key\n");
if (CAkeyfile == NULL)
CAkeyfile = CAfile;
if (CAkeyfile != NULL) {
if (CAfile == NULL) {
BIO_printf(bio_err,
"Ignoring -CAkey option since no -CA option is given\n");
} else {
if ((CAkey = load_key(CAkeyfile, FORMAT_PEM,
0, passin, e, "issuer private key")) == NULL)
goto end;
}
}
if (CAfile != NULL) {
if (!gen_x509) {
BIO_printf(bio_err,
"Warning: Ignoring -CA option without -x509\n");
} else {
if (CAkeyfile == NULL) {
BIO_printf(bio_err,
"Need to give the -CAkey option if using -CA\n");
goto end;
}
if ((CAcert = load_cert_pass(CAfile, 1, passin,
"issuer certificate")) == NULL)
goto end;
if (!X509_check_private_key(CAcert, CAkey)) {
BIO_printf(bio_err,
"Issuer certificate and key do not match\n");
goto end;
}
}
}
if (newreq || gen_x509) {
if (pkey == NULL /* can happen only if !newreq */) {
BIO_printf(bio_err, "Must provide the corresponding private key using -key\n");
goto end;
}
@ -727,78 +776,83 @@ int req_main(int argc, char **argv)
goto end;
}
i = make_REQ(req, pkey, subj, multirdn, !x509, chtype);
subj = NULL; /* done processing '-subj' option */
i = make_REQ(req, pkey, fsubj, multirdn, !gen_x509, chtype);
fsubj = NULL; /* done processing '-subj' option */
if (!i) {
BIO_printf(bio_err, "problems making Certificate Request\n");
BIO_printf(bio_err, "Error making certificate request\n");
goto end;
}
}
if (x509) {
if (gen_x509) {
EVP_PKEY *tmppkey;
X509V3_CTX ext_ctx;
if ((x509ss = X509_new_ex(app_get0_libctx(), app_get0_propq())) == NULL)
X509_NAME *issuer = CAcert != NULL ? X509_get_subject_name(CAcert) :
X509_REQ_get_subject_name(req);
if ((new_x509 = X509_new_ex(app_get0_libctx(),
app_get0_propq())) == NULL)
goto end;
if (serial != NULL) {
if (!X509_set_serialNumber(x509ss, serial))
if (!X509_set_serialNumber(new_x509, serial))
goto end;
} else {
if (!rand_serial(NULL, X509_get_serialNumber(x509ss)))
if (!rand_serial(NULL, X509_get_serialNumber(new_x509)))
goto end;
}
if (!X509_set_issuer_name(x509ss, X509_REQ_get_subject_name(req)))
if (!X509_set_issuer_name(new_x509, issuer))
goto end;
if (days == 0) {
/* set default days if it's not specified */
days = 30;
if (days == UNSET_DAYS) {
days = DEFAULT_DAYS;
}
if (!set_cert_times(x509ss, NULL, NULL, days))
if (!set_cert_times(new_x509, NULL, NULL, days))
goto end;
if (!X509_set_subject_name
(x509ss, X509_REQ_get_subject_name(req)))
if (!X509_set_subject_name(new_x509,
X509_REQ_get_subject_name(req)))
goto end;
tmppkey = X509_REQ_get0_pubkey(req);
if (!tmppkey || !X509_set_pubkey(x509ss, tmppkey))
if (!tmppkey || !X509_set_pubkey(new_x509, tmppkey))
goto end;
/* TODO: (optionally) copy X.509 extensions from req */
/* Set up V3 context struct */
X509V3_set_ctx(&ext_ctx, x509ss, x509ss, NULL, NULL, X509V3_CTX_REPLACE);
X509V3_set_ctx(&ext_ctx, CAcert != NULL ? CAcert : new_x509,
new_x509, NULL, NULL, X509V3_CTX_REPLACE);
X509V3_set_nconf(&ext_ctx, req_conf);
/* Add extensions */
if (extensions != NULL && !X509V3_EXT_add_nconf(req_conf,
&ext_ctx, extensions,
x509ss)) {
if (extensions != NULL
&& !X509V3_EXT_add_nconf(req_conf, &ext_ctx, extensions,
new_x509)) {
BIO_printf(bio_err, "Error adding x509 extensions from section %s\n",
extensions);
goto end;
}
if (addext_conf != NULL
&& !X509V3_EXT_add_nconf(addext_conf, &ext_ctx, "default",
x509ss)) {
new_x509)) {
BIO_printf(bio_err, "Error adding extensions defined via -addext\n");
goto end;
}
/* If a pre-cert was requested, we need to add a poison extension */
if (precert) {
if (X509_add1_ext_i2d(x509ss, NID_ct_precert_poison, NULL, 1, 0)
!= 1) {
if (X509_add1_ext_i2d(new_x509, NID_ct_precert_poison,
NULL, 1, 0) != 1) {
BIO_printf(bio_err, "Error adding poison extension\n");
goto end;
}
}
i = do_X509_sign(x509ss, pkey, digest, sigopts, &ext_ctx);
i = do_X509_sign(new_x509, CAcert != NULL ? CAkey : pkey,
digest, sigopts, &ext_ctx);
if (!i)
goto end;
} else {
X509V3_CTX ext_ctx;
/* Set up V3 context struct */
X509V3_set_ctx(&ext_ctx, NULL, NULL, req, NULL, 0);
X509V3_set_nconf(&ext_ctx, req_conf);
@ -822,31 +876,30 @@ int req_main(int argc, char **argv)
}
}
if (subj && x509) {
BIO_printf(bio_err, "Cannot modify 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), get_nameopt());
}
if (build_subject(req, subj, chtype, multirdn) == 0) {
BIO_printf(bio_err, "ERROR: cannot modify subject\n");
ret = 1;
if (fsubj != NULL){
if (gen_x509) {
BIO_printf(bio_err, "Modifying subject of cert with -x509 option is not supported\n");
goto end;
}
if (verbose) {
print_name(bio_err, "new subject=",
BIO_printf(bio_err, "Modifying subject of certificate request\n");
print_name(bio_err, "Old subject=",
X509_REQ_get_subject_name(req), get_nameopt());
}
if (build_subject(req, fsubj, chtype, multirdn) == 0) {
BIO_printf(bio_err, "Error modifying subject of certificate request\n");
goto end;
}
if (verbose) {
print_name(bio_err, "New subject=",
X509_REQ_get_subject_name(req), get_nameopt());
}
}
if (verify && !x509) {
if (verify && !gen_x509) {
EVP_PKEY *tpubkey = pkey;
if (tpubkey == NULL) {
@ -860,10 +913,10 @@ int req_main(int argc, char **argv)
if (i < 0) {
goto end;
} else if (i == 0) {
BIO_printf(bio_err, "verify failure\n");
BIO_printf(bio_err, "Certificate request self-signature verify failure\n");
ERR_print_errors(bio_err);
} else { /* if (i > 0) */
BIO_printf(bio_err, "verify OK\n");
} else { /* i > 0 */
BIO_printf(bio_err, "Certificate request self-signature verify OK\n");
}
}
@ -890,24 +943,23 @@ int req_main(int argc, char **argv)
}
if (text) {
if (x509)
ret = X509_print_ex(out, x509ss, get_nameopt(), reqflag);
if (gen_x509)
ret = X509_print_ex(out, new_x509, get_nameopt(), reqflag);
else
ret = X509_REQ_print_ex(out, req, get_nameopt(), reqflag);
if (ret == 0) {
if (x509)
BIO_printf(bio_err, "Error printing certificate\n");
if (gen_x509)
BIO_printf(bio_err, "Error printing certificate\n");
else
BIO_printf(bio_err, "Error printing certificate request\n");
BIO_printf(bio_err, "Error printing certificate request\n");
goto end;
}
}
if (subject) {
if (x509)
print_name(out, "subject=", X509_get_subject_name(x509ss),
if (gen_x509)
print_name(out, "subject=", X509_get_subject_name(new_x509),
get_nameopt());
else
print_name(out, "subject=", X509_REQ_get_subject_name(req),
@ -917,12 +969,12 @@ int req_main(int argc, char **argv)
if (modulus) {
EVP_PKEY *tpubkey;
if (x509)
tpubkey = X509_get0_pubkey(x509ss);
if (gen_x509)
tpubkey = X509_get0_pubkey(new_x509);
else
tpubkey = X509_REQ_get0_pubkey(req);
if (tpubkey == NULL) {
fprintf(stdout, "Modulus=unavailable\n");
fprintf(stdout, "Modulus is unavailable\n");
goto end;
}
fprintf(stdout, "Modulus=");
@ -939,7 +991,7 @@ int req_main(int argc, char **argv)
fprintf(stdout, "\n");
}
if (!noout && !x509) {
if (!noout && !gen_x509) {
if (outformat == FORMAT_ASN1)
i = i2d_X509_REQ_bio(out, req);
else if (newhdr)
@ -947,17 +999,17 @@ int req_main(int argc, char **argv)
else
i = PEM_write_bio_X509_REQ(out, req);
if (!i) {
BIO_printf(bio_err, "unable to write X509 request\n");
BIO_printf(bio_err, "Unable to write certificate request\n");
goto end;
}
}
if (!noout && x509 && (x509ss != NULL)) {
if (!noout && gen_x509 && new_x509 != NULL) {
if (outformat == FORMAT_ASN1)
i = i2d_X509_bio(out, x509ss);
i = i2d_X509_bio(out, new_x509);
else
i = PEM_write_bio_X509(out, x509ss);
i = PEM_write_bio_X509(out, new_x509);
if (!i) {
BIO_printf(bio_err, "unable to write X509 certificate\n");
BIO_printf(bio_err, "Unable to write X509 certificate\n");
goto end;
}
}
@ -982,7 +1034,9 @@ int req_main(int argc, char **argv)
#endif
OPENSSL_free(keyalgstr);
X509_REQ_free(req);
X509_free(x509ss);
X509_free(new_x509);
X509_free(CAcert);
EVP_PKEY_free(CAkey);
ASN1_INTEGER_free(serial);
release_engine(e);
if (passin != nofree_passin)
@ -1012,7 +1066,7 @@ static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, char *subj, int multirdn,
} else {
dn_sk = NCONF_get_section(req_conf, dn_sect);
if (dn_sk == NULL) {
BIO_printf(bio_err, "unable to get '%s' section\n", dn_sect);
BIO_printf(bio_err, "Unable to get '%s' section\n", dn_sect);
goto err;
}
}
@ -1023,14 +1077,14 @@ static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, char *subj, int multirdn,
} else {
attr_sk = NCONF_get_section(req_conf, attr_sect);
if (attr_sk == NULL) {
BIO_printf(bio_err, "unable to get '%s' section\n", attr_sect);
BIO_printf(bio_err, "Unable to get '%s' section\n", attr_sect);
goto err;
}
}
/* setup version number */
/* tentatively set X.509 version 1 */
if (!X509_REQ_set_version(req, 0L))
goto err; /* version 1 */
goto err;
if (subj)
i = build_subject(req, subj, chtype, multirdn);
@ -1054,8 +1108,8 @@ static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, char *subj, int multirdn,
* 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, const char *subject, unsigned long chtype,
int multirdn)
static int build_subject(X509_REQ *req, const char *subject,
unsigned long chtype, int multirdn)
{
X509_NAME *n;
@ -1103,7 +1157,7 @@ static int prompt_info(X509_REQ *req,
if (sk_CONF_VALUE_num(dn_sk)) {
i = -1;
start:
for ( ; ; ) {
for (;;) {
i++;
if (sk_CONF_VALUE_num(dn_sk) <= i)
break;
@ -1155,7 +1209,6 @@ static int prompt_info(X509_REQ *req,
n_min = -1;
}
if (!join(buf, sizeof(buf), v->name, "_max", "Name"))
return 0;
if (!NCONF_get_number(req_conf, dn_sect, buf, &n_max)) {
@ -1168,7 +1221,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;
}
@ -1183,7 +1236,7 @@ static int prompt_info(X509_REQ *req,
i = -1;
start2:
for ( ; ; ) {
for (;;) {
i++;
if ((attr_sk == NULL) || (sk_CONF_VALUE_num(attr_sk) <= i))
break;
@ -1209,7 +1262,7 @@ static int prompt_info(X509_REQ *req,
value = NULL;
}
if (!join(buf, sizeof(buf), type,"_min", "Name"))
if (!join(buf, sizeof(buf), type, "_min", "Name"))
return 0;
if (!NCONF_get_number(req_conf, attr_sect, buf, &n_min)) {
ERR_clear_error();
@ -1260,10 +1313,10 @@ static int auto_info(X509_REQ *req, STACK_OF(CONF_VALUE) *dn_sk,
*/
for (p = v->name; *p; p++) {
#ifndef CHARSET_EBCDIC
spec_char = ((*p == ':') || (*p == ',') || (*p == '.'));
spec_char = (*p == ':' || *p == ',' || *p == '.');
#else
spec_char = ((*p == os_toascii[':']) || (*p == os_toascii[','])
|| (*p == os_toascii['.']));
spec_char = (*p == os_toascii[':'] || *p == os_toascii[',']
|| *p == os_toascii['.']);
#endif
if (spec_char) {
p++;
@ -1291,7 +1344,7 @@ static int auto_info(X509_REQ *req, STACK_OF(CONF_VALUE) *dn_sk,
}
if (!X509_NAME_entry_count(subj)) {
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;
}
if (attribs) {
@ -1348,12 +1401,9 @@ static int add_attribute_object(X509_REQ *req, char *text, const char *def,
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
)
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:
@ -1388,7 +1438,7 @@ static int build_data(char *text, const char *def,
i = strlen(buf);
if (buf[i - 1] != '\n') {
BIO_printf(bio_err, "weird input :-(\n");
BIO_printf(bio_err, "Missing newline at end of input\n");
return 0;
}
buf[--i] = '\0';
@ -1405,16 +1455,14 @@ static int build_data(char *text, const char *def,
static int req_check_len(int len, int n_min, int n_max)
{
if ((n_min > 0) && (len < n_min)) {
if (n_min > 0 && len < n_min) {
BIO_printf(bio_err,
"string is too short, it needs to be at least %d bytes long\n",
n_min);
"String too short, must be at least %d bytes long\n", n_min);
return 0;
}
if ((n_max >= 0) && (len > n_max)) {
if (n_max >= 0 && len > n_max) {
BIO_printf(bio_err,
"string is too long, it needs to be no more than %d bytes long\n",
n_max);
"String too long, must be at most %d bytes long\n", n_max);
return 0;
}
return 1;
@ -1512,7 +1560,7 @@ static EVP_PKEY_CTX *set_keygen_ctx(const char *gstr,
if (paramfile != NULL) {
pbio = BIO_new_file(paramfile, "r");
if (pbio == NULL) {
BIO_printf(bio_err, "Can't open parameter file %s\n", paramfile);
BIO_printf(bio_err, "Cannot open parameter file %s\n", paramfile);
return NULL;
}
param = PEM_read_bio_Parameters(pbio, NULL);
@ -1537,7 +1585,7 @@ static EVP_PKEY_CTX *set_keygen_ctx(const char *gstr,
if (*pkey_type == -1) {
*pkey_type = EVP_PKEY_id(param);
} else if (*pkey_type != EVP_PKEY_base_id(param)) {
BIO_printf(bio_err, "Key Type does not match parameters\n");
BIO_printf(bio_err, "Key type does not match parameters\n");
EVP_PKEY_free(param);
return NULL;
}

View File

@ -69,15 +69,20 @@ B<openssl> B<ca>
=head1 DESCRIPTION
This command is a minimal CA application. It can be used
to sign certificate requests in a variety of forms and generate
CRLs. It also maintains a text database of issued certificates
and their status.
When signing certificates, a single certificate request can be specified
This command emulates a CA application.
See the B<WARNINGS> especially when considering to use it productively.
It can be used to sign certificate requests (CSRs) in a variety of forms
and generate certificate revocation lists (CRLs).
It also maintains a text database of issued certificates and their status.
When signing certificates, a single request can be specified
with the B<-in> option, or multiple requests can be processed by
specifying a set of B<certreq> files after all options.
The options descriptions will be divided into each purpose.
Note that there are also very lean ways of generating certificates:
the B<req> and B<x509> commands can be used for directly creating certificates.
See L<openssl-req(1)> and L<openssl-x509(1)> for details.
The descriptions of the B<ca> command options are divided into each purpose.
=head1 OPTIONS
@ -104,12 +109,12 @@ B<default_ca> in the B<ca> section).
=item B<-in> I<filename>
An input filename containing a single certificate request to be
An input filename containing a single certificate request (CSR) to be
signed by the CA.
=item B<-inform> B<DER>|B<PEM>
The format of the data in CSR input files.
The format of the data in certificate request input files.
The default is PEM.
=item B<-ss_cert> I<filename>
@ -150,7 +155,8 @@ This option has no effect and is retained for backward compatibility only.
=item B<-keyfile> I<filename>|I<uri>
The CA private key to sign requests with. This must match with B<-cert>.
The CA private key to sign certificate requests with.
This must match with B<-cert>.
=item B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>
@ -168,8 +174,8 @@ Names and values of these options are algorithm-specific.
Pass options to the signature algorithm during verify operations.
Names and values of these options are algorithm-specific.
This often needs to be given while signing too, because the input
certificate signature request is verified against its own public key,
This often needs to be given while signing too, because the self-signature of
a certificate signing request (CSR) is verified against the included public key,
and that verification may need its own set of options.
=item B<-key> I<password>
@ -192,9 +198,8 @@ see L<openssl-passphrase-options(1)>.
Indicates the issued certificates are to be signed with the key
the certificate requests were signed with (given with B<-keyfile>).
Certificate requests signed with a different key are ignored. If
B<-spkac>, B<-ss_cert> or B<-gencrl> are given, B<-selfsign> is
ignored.
Certificate requests signed with a different key are ignored.
If B<-spkac>, B<-ss_cert> or B<-gencrl> are given, B<-selfsign> is ignored.
A consequence of using B<-selfsign> is that the self-signed
certificate appears among the entries in the certificate database
@ -739,6 +744,8 @@ possible to include one SPKAC or self-signed certificate.
=head1 BUGS
This command is quirky and at times downright unfriendly.
The use of an in-memory text database can cause problems when large
numbers of certificates are present because, as the name implies
the database has to be kept in memory.
@ -760,11 +767,14 @@ create an empty file.
=head1 WARNINGS
This command is quirky and at times downright unfriendly.
This command was originally meant as an example of how to do
things in a CA. It was not supposed to be used as a full blown CA itself:
nevertheless some people are using it for this purpose.
This command was originally meant as an example of how to do things in a CA.
Its code does not have production quality.
It was not supposed to be used as a full blown CA itself,
nevertheless some people are using it for this purpose at least internally.
When doing so, specific care should be taken to
properly secure the private key(s) used for signing certificates.
It is advisable to keep them in a secure HW storage such as a smart card or HSM
and access them via a suitable engine or crypto provider.
This command command is effectively a single user command: no locking
is done on the various files and attempts to run more than one B<openssl ca>
@ -776,7 +786,6 @@ request contains a basicConstraints extension with CA:TRUE and the
B<copy_extensions> value is set to B<copyall> and the user does not spot
this when the certificate is displayed then this will hand the requester
a valid CA certificate.
This situation can be avoided by setting B<copy_extensions> to B<copy>
and including basicConstraints with CA:FALSE in the configuration file.
Then if the request contains a basicConstraints extension it will be

View File

@ -33,6 +33,8 @@ B<openssl> B<req>
[B<-config> I<filename>]
[B<-section> I<name>]
[B<-x509>]
[B<-CA> I<filename>|I<uri>]
[B<-CAkey> I<filename>|I<uri>]
[B<-days> I<n>]
[B<-set_serial> I<n>]
[B<-newhdr>]
@ -57,8 +59,8 @@ B<openssl> B<req>
=head1 DESCRIPTION
This command primarily creates and processes certificate requests
in PKCS#10 format. It can additionally create self signed certificates
This command primarily creates and processes certificate requests (CSRs)
in PKCS#10 format. It can additionally create self-signed certificates
for use as root CAs for example.
=head1 OPTIONS
@ -80,7 +82,7 @@ The data is a PKCS#10 object.
This specifies the input filename to read a request from or standard input
if this option is not specified. A request is only read if the creation
options (B<-new> and B<-newkey>) are not specified.
options (B<-new> or B<-newkey>) are not specified.
=item B<-sigopt> I<nm>:I<v>
@ -100,16 +102,21 @@ which supports both options for good reasons.
=end comment
=item B<-passin> I<arg>, B<-passout> I<arg>
=item B<-passin> I<arg>
The password source for the input and output file.
The password source for the request input file and the certificate input.
For more information about the format of B<arg>
see L<openssl-passphrase-options(1)>.
=item B<-passout> I<arg>
The password source for the output file.
For more information about the format of B<arg>
see L<openssl-passphrase-options(1)>.
=item B<-out> I<filename>
This specifies the output filename to write to or standard output by
default.
This specifies the output filename to write to or standard output by default.
=item B<-text>
@ -117,21 +124,20 @@ Prints out the certificate request in text form.
=item B<-subject>
Prints out the request subject (or certificate subject if B<-x509> is
specified)
Prints out the certificate request subject
(or certificate subject if B<-x509> is specified).
=item B<-pubkey>
Outputs the public key.
Prints out the public key.
=item B<-noout>
This option prevents output of the encoded version of the request.
This option prevents output of the encoded version of the certificate request.
=item B<-modulus>
This option prints out the value of the modulus of the public key
contained in the request.
Prints out the value of the modulus of the public key contained in the request.
=item B<-verify>
@ -144,8 +150,9 @@ the user for the relevant field values. The actual fields
prompted for and their maximum and minimum sizes are specified
in the configuration file and any requested extensions.
If the B<-key> option is not used it will generate a new RSA private
key using information specified in the configuration file.
If the B<-key> option is not given it will generate a new RSA private key
using information specified in the configuration file or given with
the B<-newkey> and B<-pkeyopt> options, else by default with 2048 bits length.
=item B<-newkey> I<arg>
@ -183,8 +190,8 @@ See L<openssl-genpkey(1)/KEY GENERATION OPTIONS> for more details.
=item B<-key> I<filename>|I<uri>
This specifies the private key to use. It also
accepts PKCS#8 format private keys for PEM format files.
This specifies the private key to use for self-signature.
It also accepts PKCS#8 format private keys for PEM format files.
=item B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>
@ -231,7 +238,7 @@ Specifies the name of the section to use; the default is B<req>.
=item B<-subj> I<arg>
Sets subject name for new request or supersedes the subject name
when processing a request.
when processing a certificate request.
The arg must be formatted as C</type0=value0/type1=value1/type2=...>.
Special characters may be escaped by C<\> (backslash), whitespace is retained.
@ -250,15 +257,31 @@ This option has been deprecated and has no effect.
=item B<-x509>
This option outputs a self signed certificate instead of a certificate
request. This is typically used to generate a test certificate or
a self signed root CA. The extensions added to the certificate
(if any) are specified in the configuration file. Unless specified
using the B<-set_serial> option, a large random number will be used for
the serial number.
This option outputs a certificate instead of a certificate request.
This is typically used to generate test certificates.
If existing request is specified with the B<-in> option, it is converted
to the self signed certificate otherwise new request is created.
If an existing request is specified with the B<-in> option, it is converted
to the a certificate; otherwise a request is created from scratch.
Unless specified using the B<-set_serial> option,
a large random number will be used for the serial number.
X.509 extensions are not copied from any provided request input file.
X.509 extensions to be added can be specified in the configuration file
or using the B<-addext> option.
=item B<-CA> I<filename>|I<uri>
Specifies the "CA" certificate to be used for signing with the B<-x509> option.
When present, this behaves like a "micro CA" as follows:
The subject name of the "CA" certificate is placed as issuer name in the new
certificate, which is then signed using the "CA" key given as specified below.
=item B<-CAkey> I<filename>|I<uri>
Sets the "CA" private key to sign a certificate with.
The private key must match the public key of the certificate given with B<-CA>.
If this option is not provided then the key must be present in the B<-CA> input.
=item B<-days> I<n>
@ -268,7 +291,7 @@ be a positive integer. The default is 30 days.
=item B<-set_serial> I<n>
Serial number to use when outputting a self signed certificate. This
Serial number to use when outputting a self-signed certificate. This
may be specified as a decimal value or a hex value if preceded by C<0x>.
=item B<-addext> I<ext>
@ -308,7 +331,7 @@ configuration file, must be valid UTF8 strings.
=item B<-reqopt> I<option>
Customise the output format used with B<-text>. The I<option> argument can be
Customise the printing format used with B<-text>. The I<option> argument can be
a single option or multiple options separated by commas.
See discussion of the B<-certopt> parameter in the L<openssl-x509(1)>
@ -533,7 +556,7 @@ The same but just using req:
openssl req -newkey rsa:2048 -keyout key.pem -out req.pem
Generate a self signed root certificate:
Generate a self-signed root certificate:
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out req.pem