xref: /freebsd/crypto/openssl/apps/req.c (revision 6f1af0d7d2af54b339b5212434cd6d4fda628d80)
16f9291ceSJung-uk Kim /*
2aa795734SPierre Pronchery  * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
3e71b7053SJung-uk Kim  *
4b077aed3SPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5e71b7053SJung-uk Kim  * this file except in compliance with the License.  You can obtain a copy
6e71b7053SJung-uk Kim  * in the file LICENSE in the source distribution or at
7e71b7053SJung-uk Kim  * https://www.openssl.org/source/license.html
86f9291ceSJung-uk Kim  */
93b4e3dcbSSimon L. B. Nielsen 
1074664626SKris Kennaway #include <stdio.h>
1174664626SKris Kennaway #include <stdlib.h>
1274664626SKris Kennaway #include <time.h>
1374664626SKris Kennaway #include <string.h>
14e71b7053SJung-uk Kim #include <ctype.h>
1574664626SKris Kennaway #include "apps.h"
16e71b7053SJung-uk Kim #include "progs.h"
17b077aed3SPierre Pronchery #include <openssl/core_names.h>
1874664626SKris Kennaway #include <openssl/bio.h>
1974664626SKris Kennaway #include <openssl/evp.h>
2074664626SKris Kennaway #include <openssl/conf.h>
2174664626SKris Kennaway #include <openssl/err.h>
2274664626SKris Kennaway #include <openssl/asn1.h>
2374664626SKris Kennaway #include <openssl/x509.h>
2474664626SKris Kennaway #include <openssl/x509v3.h>
2574664626SKris Kennaway #include <openssl/objects.h>
2674664626SKris Kennaway #include <openssl/pem.h>
273b4e3dcbSSimon L. B. Nielsen #include <openssl/bn.h>
28e71b7053SJung-uk Kim #include <openssl/lhash.h>
293b4e3dcbSSimon L. B. Nielsen #include <openssl/rsa.h>
303b4e3dcbSSimon L. B. Nielsen #ifndef OPENSSL_NO_DSA
313b4e3dcbSSimon L. B. Nielsen # include <openssl/dsa.h>
323b4e3dcbSSimon L. B. Nielsen #endif
3374664626SKris Kennaway 
3474664626SKris Kennaway #define BITS               "default_bits"
3574664626SKris Kennaway #define KEYFILE            "default_keyfile"
36f579bf8eSKris Kennaway #define PROMPT             "prompt"
3774664626SKris Kennaway #define DISTINGUISHED_NAME "distinguished_name"
3874664626SKris Kennaway #define ATTRIBUTES         "attributes"
3974664626SKris Kennaway #define V3_EXTENSIONS      "x509_extensions"
40f579bf8eSKris Kennaway #define REQ_EXTENSIONS     "req_extensions"
41f579bf8eSKris Kennaway #define STRING_MASK        "string_mask"
425c87c606SMark Murray #define UTF8_IN            "utf8"
4374664626SKris Kennaway 
444c6a0400SJung-uk Kim #define DEFAULT_KEY_LENGTH 2048
454c6a0400SJung-uk Kim #define MIN_KEY_LENGTH     512
46b077aed3SPierre Pronchery #define DEFAULT_DAYS       30 /* default cert validity period in days */
47b077aed3SPierre Pronchery #define UNSET_DAYS         -2 /* -1 may be used for testing expiration checks */
48b077aed3SPierre Pronchery #define EXT_COPY_UNSET     -1
4974664626SKris Kennaway 
50b077aed3SPierre Pronchery static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, X509_NAME *fsubj,
51b077aed3SPierre Pronchery                     int mutlirdn, int attribs, unsigned long chtype);
52f579bf8eSKris Kennaway static int prompt_info(X509_REQ *req,
53e71b7053SJung-uk Kim                        STACK_OF(CONF_VALUE) *dn_sk, const char *dn_sect,
54e71b7053SJung-uk Kim                        STACK_OF(CONF_VALUE) *attr_sk, const char *attr_sect,
556f9291ceSJung-uk Kim                        int attribs, unsigned long chtype);
56f579bf8eSKris Kennaway static int auto_info(X509_REQ *req, STACK_OF(CONF_VALUE) *sk,
575c87c606SMark Murray                      STACK_OF(CONF_VALUE) *attr, int attribs,
585c87c606SMark Murray                      unsigned long chtype);
593b4e3dcbSSimon L. B. Nielsen static int add_attribute_object(X509_REQ *req, char *text, const char *def,
606f9291ceSJung-uk Kim                                 char *value, int nid, int n_min, int n_max,
616f9291ceSJung-uk Kim                                 unsigned long chtype);
626f9291ceSJung-uk Kim static int add_DN_object(X509_NAME *n, char *text, const char *def,
636f9291ceSJung-uk Kim                          char *value, int nid, int n_min, int n_max,
646f9291ceSJung-uk Kim                          unsigned long chtype, int mval);
651f13597dSJung-uk Kim static int genpkey_cb(EVP_PKEY_CTX *ctx);
66b077aed3SPierre Pronchery static int build_data(char *text, const char *def, char *value,
67b077aed3SPierre Pronchery                       int n_min, int n_max, char *buf, const int buf_size,
68b077aed3SPierre Pronchery                       const char *desc1, const char *desc2);
695c87c606SMark Murray static int req_check_len(int len, int n_min, int n_max);
703b4e3dcbSSimon L. B. Nielsen static int check_end(const char *str, const char *end);
71e71b7053SJung-uk Kim static int join(char buf[], size_t buf_size, const char *name,
72e71b7053SJung-uk Kim                 const char *tail, const char *desc);
73e71b7053SJung-uk Kim static EVP_PKEY_CTX *set_keygen_ctx(const char *gstr,
74b077aed3SPierre Pronchery                                     char **pkeytype, long *pkeylen,
75b077aed3SPierre Pronchery                                     ENGINE *keygen_engine);
76b077aed3SPierre Pronchery 
77b077aed3SPierre Pronchery static const char *section = "req";
785c87c606SMark Murray static CONF *req_conf = NULL;
79e71b7053SJung-uk Kim static CONF *addext_conf = NULL;
805c87c606SMark Murray static int batch = 0;
8174664626SKris Kennaway 
82e71b7053SJung-uk Kim typedef enum OPTION_choice {
83b077aed3SPierre Pronchery     OPT_COMMON,
84e71b7053SJung-uk Kim     OPT_INFORM, OPT_OUTFORM, OPT_ENGINE, OPT_KEYGEN_ENGINE, OPT_KEY,
85e71b7053SJung-uk Kim     OPT_PUBKEY, OPT_NEW, OPT_CONFIG, OPT_KEYFORM, OPT_IN, OPT_OUT,
86e71b7053SJung-uk Kim     OPT_KEYOUT, OPT_PASSIN, OPT_PASSOUT, OPT_NEWKEY,
87b077aed3SPierre Pronchery     OPT_PKEYOPT, OPT_SIGOPT, OPT_VFYOPT, OPT_BATCH, OPT_NEWHDR, OPT_MODULUS,
88b077aed3SPierre Pronchery     OPT_VERIFY, OPT_NOENC, OPT_NODES, OPT_NOOUT, OPT_VERBOSE, OPT_UTF8,
89e71b7053SJung-uk Kim     OPT_NAMEOPT, OPT_REQOPT, OPT_SUBJ, OPT_SUBJECT, OPT_TEXT, OPT_X509,
90b077aed3SPierre Pronchery     OPT_CA, OPT_CAKEY,
91b077aed3SPierre Pronchery     OPT_MULTIVALUE_RDN, OPT_DAYS, OPT_SET_SERIAL,
92b077aed3SPierre Pronchery     OPT_COPY_EXTENSIONS, OPT_ADDEXT, OPT_EXTENSIONS,
93e71b7053SJung-uk Kim     OPT_REQEXTS, OPT_PRECERT, OPT_MD,
94b077aed3SPierre Pronchery     OPT_SECTION,
95b077aed3SPierre Pronchery     OPT_R_ENUM, OPT_PROV_ENUM
96e71b7053SJung-uk Kim } OPTION_CHOICE;
97f579bf8eSKris Kennaway 
98e71b7053SJung-uk Kim const OPTIONS req_options[] = {
99b077aed3SPierre Pronchery     OPT_SECTION("General"),
100e71b7053SJung-uk Kim     {"help", OPT_HELP, '-', "Display this summary"},
101b077aed3SPierre Pronchery #ifndef OPENSSL_NO_ENGINE
102b077aed3SPierre Pronchery     {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
103b077aed3SPierre Pronchery     {"keygen_engine", OPT_KEYGEN_ENGINE, 's',
104b077aed3SPierre Pronchery      "Specify engine to be used for key generation operations"},
105b077aed3SPierre Pronchery #endif
106b077aed3SPierre Pronchery     {"in", OPT_IN, '<', "X.509 request input file (default stdin)"},
107e71b7053SJung-uk Kim     {"inform", OPT_INFORM, 'F', "Input format - DER or PEM"},
108b077aed3SPierre Pronchery     {"verify", OPT_VERIFY, '-', "Verify self-signature on the request"},
109b077aed3SPierre Pronchery 
110b077aed3SPierre Pronchery     OPT_SECTION("Certificate"),
111e71b7053SJung-uk Kim     {"new", OPT_NEW, '-', "New request"},
112e71b7053SJung-uk Kim     {"config", OPT_CONFIG, '<', "Request template file"},
113b077aed3SPierre Pronchery     {"section", OPT_SECTION, 's', "Config section to use (default \"req\")"},
114e71b7053SJung-uk Kim     {"utf8", OPT_UTF8, '-', "Input characters are UTF8 (default ASCII)"},
115b077aed3SPierre Pronchery     {"nameopt", OPT_NAMEOPT, 's', "Certificate subject/issuer name printing options"},
116e71b7053SJung-uk Kim     {"reqopt", OPT_REQOPT, 's', "Various request text options"},
117e71b7053SJung-uk Kim     {"text", OPT_TEXT, '-', "Text form of request"},
118e71b7053SJung-uk Kim     {"x509", OPT_X509, '-',
119b077aed3SPierre Pronchery      "Output an X.509 certificate structure instead of a cert request"},
120b077aed3SPierre Pronchery     {"CA", OPT_CA, '<', "Issuer cert to use for signing a cert, implies -x509"},
121b077aed3SPierre Pronchery     {"CAkey", OPT_CAKEY, 's',
122b077aed3SPierre Pronchery      "Issuer private key to use with -CA; default is -CA arg"},
123e71b7053SJung-uk Kim     {OPT_MORE_STR, 1, 1, "(Required by some CA's)"},
124b077aed3SPierre Pronchery     {"subj", OPT_SUBJ, 's', "Set or modify subject of request or cert"},
125b077aed3SPierre Pronchery     {"subject", OPT_SUBJECT, '-',
126b077aed3SPierre Pronchery      "Print the subject of the output request or cert"},
127e71b7053SJung-uk Kim     {"multivalue-rdn", OPT_MULTIVALUE_RDN, '-',
128b077aed3SPierre Pronchery      "Deprecated; multi-valued RDNs support is always on."},
129e71b7053SJung-uk Kim     {"days", OPT_DAYS, 'p', "Number of days cert is valid for"},
130e71b7053SJung-uk Kim     {"set_serial", OPT_SET_SERIAL, 's', "Serial number to use"},
131b077aed3SPierre Pronchery     {"copy_extensions", OPT_COPY_EXTENSIONS, 's',
132b077aed3SPierre Pronchery      "copy extensions from request when using -x509"},
133e71b7053SJung-uk Kim     {"addext", OPT_ADDEXT, 's',
134e71b7053SJung-uk Kim      "Additional cert extension key=value pair (may be given more than once)"},
135e71b7053SJung-uk Kim     {"extensions", OPT_EXTENSIONS, 's',
136e71b7053SJung-uk Kim      "Cert extension section (override value in config file)"},
137e71b7053SJung-uk Kim     {"reqexts", OPT_REQEXTS, 's',
138e71b7053SJung-uk Kim      "Request extension section (override value in config file)"},
139b077aed3SPierre Pronchery     {"precert", OPT_PRECERT, '-',
140b077aed3SPierre Pronchery      "Add a poison extension to the generated cert (implies -new)"},
141b077aed3SPierre Pronchery 
142b077aed3SPierre Pronchery     OPT_SECTION("Keys and Signing"),
143b077aed3SPierre Pronchery     {"key", OPT_KEY, 's', "Key for signing, and to include unless -in given"},
144b077aed3SPierre Pronchery     {"keyform", OPT_KEYFORM, 'f', "Key file format (ENGINE, other values ignored)"},
145b077aed3SPierre Pronchery     {"pubkey", OPT_PUBKEY, '-', "Output public key"},
146b077aed3SPierre Pronchery     {"keyout", OPT_KEYOUT, '>', "File to write private key to"},
147b077aed3SPierre Pronchery     {"passin", OPT_PASSIN, 's', "Private key and certificate password source"},
148b077aed3SPierre Pronchery     {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"},
149b077aed3SPierre Pronchery     {"newkey", OPT_NEWKEY, 's',
150b077aed3SPierre Pronchery      "Generate new key with [<alg>:]<nbits> or <alg>[:<file>] or param:<file>"},
151b077aed3SPierre Pronchery     {"pkeyopt", OPT_PKEYOPT, 's', "Public key options as opt:value"},
152b077aed3SPierre Pronchery     {"sigopt", OPT_SIGOPT, 's', "Signature parameter in n:v form"},
153b077aed3SPierre Pronchery     {"vfyopt", OPT_VFYOPT, 's', "Verification parameter in n:v form"},
154e71b7053SJung-uk Kim     {"", OPT_MD, '-', "Any supported digest"},
155b077aed3SPierre Pronchery 
156b077aed3SPierre Pronchery     OPT_SECTION("Output"),
157b077aed3SPierre Pronchery     {"out", OPT_OUT, '>', "Output file"},
158b077aed3SPierre Pronchery     {"outform", OPT_OUTFORM, 'F', "Output format - DER or PEM"},
159b077aed3SPierre Pronchery     {"batch", OPT_BATCH, '-',
160b077aed3SPierre Pronchery      "Do not ask anything during request generation"},
161b077aed3SPierre Pronchery     {"verbose", OPT_VERBOSE, '-', "Verbose output"},
162b077aed3SPierre Pronchery     {"noenc", OPT_NOENC, '-', "Don't encrypt private keys"},
163b077aed3SPierre Pronchery     {"nodes", OPT_NODES, '-', "Don't encrypt private keys; deprecated"},
164b077aed3SPierre Pronchery     {"noout", OPT_NOOUT, '-', "Do not output REQ"},
165b077aed3SPierre Pronchery     {"newhdr", OPT_NEWHDR, '-', "Output \"NEW\" in the header lines"},
166b077aed3SPierre Pronchery     {"modulus", OPT_MODULUS, '-', "RSA modulus"},
167b077aed3SPierre Pronchery 
168b077aed3SPierre Pronchery     OPT_R_OPTIONS,
169b077aed3SPierre Pronchery     OPT_PROV_OPTIONS,
170e71b7053SJung-uk Kim     {NULL}
171e71b7053SJung-uk Kim };
172e71b7053SJung-uk Kim 
173e71b7053SJung-uk Kim /*
174e71b7053SJung-uk Kim  * An LHASH of strings, where each string is an extension name.
175e71b7053SJung-uk Kim  */
176e71b7053SJung-uk Kim static unsigned long ext_name_hash(const OPENSSL_STRING *a)
17774664626SKris Kennaway {
178e71b7053SJung-uk Kim     return OPENSSL_LH_strhash((const char *)a);
179e71b7053SJung-uk Kim }
180e71b7053SJung-uk Kim 
181e71b7053SJung-uk Kim static int ext_name_cmp(const OPENSSL_STRING *a, const OPENSSL_STRING *b)
182e71b7053SJung-uk Kim {
183e71b7053SJung-uk Kim     return strcmp((const char *)a, (const char *)b);
184e71b7053SJung-uk Kim }
185e71b7053SJung-uk Kim 
186e71b7053SJung-uk Kim static void exts_cleanup(OPENSSL_STRING *x)
187e71b7053SJung-uk Kim {
188e71b7053SJung-uk Kim     OPENSSL_free((char *)x);
189e71b7053SJung-uk Kim }
190e71b7053SJung-uk Kim 
191e71b7053SJung-uk Kim /*
192b077aed3SPierre Pronchery  * Is the |kv| key already duplicated? This is remarkably tricky to get right.
193b077aed3SPierre Pronchery  * Return 0 if unique, -1 on runtime error; 1 if found or a syntax error.
194e71b7053SJung-uk Kim  */
195e71b7053SJung-uk Kim static int duplicated(LHASH_OF(OPENSSL_STRING) *addexts, char *kv)
196e71b7053SJung-uk Kim {
197e71b7053SJung-uk Kim     char *p;
198e71b7053SJung-uk Kim     size_t off;
199e71b7053SJung-uk Kim 
200e71b7053SJung-uk Kim     /* Check syntax. */
201e71b7053SJung-uk Kim     /* Skip leading whitespace, make a copy. */
202aa795734SPierre Pronchery     while (*kv && isspace(_UC(*kv)))
203e71b7053SJung-uk Kim         if (*++kv == '\0')
204e71b7053SJung-uk Kim             return 1;
205e71b7053SJung-uk Kim     if ((p = strchr(kv, '=')) == NULL)
206e71b7053SJung-uk Kim         return 1;
207e71b7053SJung-uk Kim     off = p - kv;
208e71b7053SJung-uk Kim     if ((kv = OPENSSL_strdup(kv)) == NULL)
209e71b7053SJung-uk Kim         return -1;
210e71b7053SJung-uk Kim 
211e71b7053SJung-uk Kim     /* Skip trailing space before the equal sign. */
212e71b7053SJung-uk Kim     for (p = kv + off; p > kv; --p)
213aa795734SPierre Pronchery         if (!isspace(_UC(p[-1])))
214e71b7053SJung-uk Kim             break;
215e71b7053SJung-uk Kim     if (p == kv) {
216e71b7053SJung-uk Kim         OPENSSL_free(kv);
217e71b7053SJung-uk Kim         return 1;
218e71b7053SJung-uk Kim     }
219e71b7053SJung-uk Kim     *p = '\0';
220e71b7053SJung-uk Kim 
221e71b7053SJung-uk Kim     /* Finally have a clean "key"; see if it's there [by attempt to add it]. */
22217f01e99SJung-uk Kim     p = (char *)lh_OPENSSL_STRING_insert(addexts, (OPENSSL_STRING *)kv);
22317f01e99SJung-uk Kim     if (p != NULL) {
22417f01e99SJung-uk Kim         OPENSSL_free(p);
22517f01e99SJung-uk Kim         return 1;
22617f01e99SJung-uk Kim     } else if (lh_OPENSSL_STRING_error(addexts)) {
22717f01e99SJung-uk Kim         OPENSSL_free(kv);
228e71b7053SJung-uk Kim         return -1;
229e71b7053SJung-uk Kim     }
230e71b7053SJung-uk Kim 
231e71b7053SJung-uk Kim     return 0;
232e71b7053SJung-uk Kim }
233e71b7053SJung-uk Kim 
234e71b7053SJung-uk Kim int req_main(int argc, char **argv)
235e71b7053SJung-uk Kim {
236e71b7053SJung-uk Kim     ASN1_INTEGER *serial = NULL;
237b077aed3SPierre Pronchery     BIO *out = NULL;
2381f13597dSJung-uk Kim     ENGINE *e = NULL, *gen_eng = NULL;
239b077aed3SPierre Pronchery     EVP_PKEY *pkey = NULL, *CAkey = NULL;
240e71b7053SJung-uk Kim     EVP_PKEY_CTX *genctx = NULL;
241b077aed3SPierre Pronchery     STACK_OF(OPENSSL_STRING) *pkeyopts = NULL, *sigopts = NULL, *vfyopts = NULL;
242e71b7053SJung-uk Kim     LHASH_OF(OPENSSL_STRING) *addexts = NULL;
243b077aed3SPierre Pronchery     X509 *new_x509 = NULL, *CAcert = NULL;
24474664626SKris Kennaway     X509_REQ *req = NULL;
245b077aed3SPierre Pronchery     EVP_CIPHER *cipher = NULL;
246b077aed3SPierre Pronchery     EVP_MD *md = NULL;
247b077aed3SPierre Pronchery     int ext_copy = EXT_COPY_UNSET;
248e71b7053SJung-uk Kim     BIO *addext_bio = NULL;
249b077aed3SPierre Pronchery     char *extensions = NULL;
250b077aed3SPierre Pronchery     const char *infile = NULL, *CAfile = NULL, *CAkeyfile = NULL;
251b077aed3SPierre Pronchery     char *outfile = NULL, *keyfile = NULL, *digest = NULL;
252e71b7053SJung-uk Kim     char *keyalgstr = NULL, *p, *prog, *passargin = NULL, *passargout = NULL;
253e71b7053SJung-uk Kim     char *passin = NULL, *passout = NULL;
254e71b7053SJung-uk Kim     char *nofree_passin = NULL, *nofree_passout = NULL;
255e71b7053SJung-uk Kim     char *req_exts = NULL, *subj = NULL;
256b077aed3SPierre Pronchery     X509_NAME *fsubj = NULL;
257e71b7053SJung-uk Kim     char *template = default_config_file, *keyout = NULL;
258e71b7053SJung-uk Kim     const char *keyalg = NULL;
259e71b7053SJung-uk Kim     OPTION_CHOICE o;
260b077aed3SPierre Pronchery     int days = UNSET_DAYS;
261b077aed3SPierre Pronchery     int ret = 1, gen_x509 = 0, i = 0, newreq = 0, verbose = 0;
262b077aed3SPierre Pronchery     int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, keyform = FORMAT_UNDEF;
263b077aed3SPierre Pronchery     int modulus = 0, multirdn = 1, verify = 0, noout = 0, text = 0;
264b077aed3SPierre Pronchery     int noenc = 0, newhdr = 0, subject = 0, pubkey = 0, precert = 0;
265b077aed3SPierre Pronchery     long newkey_len = -1;
266e71b7053SJung-uk Kim     unsigned long chtype = MBSTRING_ASC, reqflag = 0;
26774664626SKris Kennaway 
2685c87c606SMark Murray #ifndef OPENSSL_NO_DES
269b077aed3SPierre Pronchery     cipher = (EVP_CIPHER *)EVP_des_ede3_cbc();
27074664626SKris Kennaway #endif
27174664626SKris Kennaway 
272e71b7053SJung-uk Kim     prog = opt_init(argc, argv, req_options);
273e71b7053SJung-uk Kim     while ((o = opt_next()) != OPT_EOF) {
274e71b7053SJung-uk Kim         switch (o) {
275e71b7053SJung-uk Kim         case OPT_EOF:
276e71b7053SJung-uk Kim         case OPT_ERR:
277e71b7053SJung-uk Kim  opthelp:
278e71b7053SJung-uk Kim             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
279e71b7053SJung-uk Kim             goto end;
280e71b7053SJung-uk Kim         case OPT_HELP:
281e71b7053SJung-uk Kim             opt_help(req_options);
282e71b7053SJung-uk Kim             ret = 0;
283e71b7053SJung-uk Kim             goto end;
284e71b7053SJung-uk Kim         case OPT_INFORM:
285e71b7053SJung-uk Kim             if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &informat))
286e71b7053SJung-uk Kim                 goto opthelp;
287e71b7053SJung-uk Kim             break;
288e71b7053SJung-uk Kim         case OPT_OUTFORM:
289e71b7053SJung-uk Kim             if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
290e71b7053SJung-uk Kim                 goto opthelp;
291e71b7053SJung-uk Kim             break;
292e71b7053SJung-uk Kim         case OPT_ENGINE:
293e71b7053SJung-uk Kim             e = setup_engine(opt_arg(), 0);
294e71b7053SJung-uk Kim             break;
295e71b7053SJung-uk Kim         case OPT_KEYGEN_ENGINE:
296fceca8a3SJacques Vidrine #ifndef OPENSSL_NO_ENGINE
297b077aed3SPierre Pronchery             gen_eng = setup_engine(opt_arg(), 0);
2986f9291ceSJung-uk Kim             if (gen_eng == NULL) {
2991f13597dSJung-uk Kim                 BIO_printf(bio_err, "Can't find keygen engine %s\n", *argv);
300e71b7053SJung-uk Kim                 goto opthelp;
3011f13597dSJung-uk Kim             }
302fceca8a3SJacques Vidrine #endif
303e71b7053SJung-uk Kim             break;
304e71b7053SJung-uk Kim         case OPT_KEY:
305e71b7053SJung-uk Kim             keyfile = opt_arg();
306e71b7053SJung-uk Kim             break;
307e71b7053SJung-uk Kim         case OPT_PUBKEY:
3085c87c606SMark Murray             pubkey = 1;
309e71b7053SJung-uk Kim             break;
310e71b7053SJung-uk Kim         case OPT_NEW:
31174664626SKris Kennaway             newreq = 1;
312e71b7053SJung-uk Kim             break;
313e71b7053SJung-uk Kim         case OPT_CONFIG:
314e71b7053SJung-uk Kim             template = opt_arg();
315e71b7053SJung-uk Kim             break;
316b077aed3SPierre Pronchery         case OPT_SECTION:
317b077aed3SPierre Pronchery             section = opt_arg();
318b077aed3SPierre Pronchery             break;
319e71b7053SJung-uk Kim         case OPT_KEYFORM:
320e71b7053SJung-uk Kim             if (!opt_format(opt_arg(), OPT_FMT_ANY, &keyform))
321e71b7053SJung-uk Kim                 goto opthelp;
322e71b7053SJung-uk Kim             break;
323e71b7053SJung-uk Kim         case OPT_IN:
324e71b7053SJung-uk Kim             infile = opt_arg();
325e71b7053SJung-uk Kim             break;
326e71b7053SJung-uk Kim         case OPT_OUT:
327e71b7053SJung-uk Kim             outfile = opt_arg();
328e71b7053SJung-uk Kim             break;
329e71b7053SJung-uk Kim         case OPT_KEYOUT:
330e71b7053SJung-uk Kim             keyout = opt_arg();
331e71b7053SJung-uk Kim             break;
332e71b7053SJung-uk Kim         case OPT_PASSIN:
333e71b7053SJung-uk Kim             passargin = opt_arg();
334e71b7053SJung-uk Kim             break;
335e71b7053SJung-uk Kim         case OPT_PASSOUT:
336e71b7053SJung-uk Kim             passargout = opt_arg();
337e71b7053SJung-uk Kim             break;
338e71b7053SJung-uk Kim         case OPT_R_CASES:
339e71b7053SJung-uk Kim             if (!opt_rand(o))
340e71b7053SJung-uk Kim                 goto end;
341e71b7053SJung-uk Kim             break;
342b077aed3SPierre Pronchery         case OPT_PROV_CASES:
343b077aed3SPierre Pronchery             if (!opt_provider(o))
344b077aed3SPierre Pronchery                 goto end;
345b077aed3SPierre Pronchery             break;
346e71b7053SJung-uk Kim         case OPT_NEWKEY:
347e71b7053SJung-uk Kim             keyalg = opt_arg();
3481f13597dSJung-uk Kim             newreq = 1;
349e71b7053SJung-uk Kim             break;
350e71b7053SJung-uk Kim         case OPT_PKEYOPT:
351b077aed3SPierre Pronchery             if (pkeyopts == NULL)
3521f13597dSJung-uk Kim                 pkeyopts = sk_OPENSSL_STRING_new_null();
353b077aed3SPierre Pronchery             if (pkeyopts == NULL
354b077aed3SPierre Pronchery                     || !sk_OPENSSL_STRING_push(pkeyopts, opt_arg()))
355e71b7053SJung-uk Kim                 goto opthelp;
356e71b7053SJung-uk Kim             break;
357e71b7053SJung-uk Kim         case OPT_SIGOPT:
3581f13597dSJung-uk Kim             if (!sigopts)
3591f13597dSJung-uk Kim                 sigopts = sk_OPENSSL_STRING_new_null();
360e71b7053SJung-uk Kim             if (!sigopts || !sk_OPENSSL_STRING_push(sigopts, opt_arg()))
361e71b7053SJung-uk Kim                 goto opthelp;
36274664626SKris Kennaway             break;
363b077aed3SPierre Pronchery         case OPT_VFYOPT:
364b077aed3SPierre Pronchery             if (!vfyopts)
365b077aed3SPierre Pronchery                 vfyopts = sk_OPENSSL_STRING_new_null();
366b077aed3SPierre Pronchery             if (!vfyopts || !sk_OPENSSL_STRING_push(vfyopts, opt_arg()))
367b077aed3SPierre Pronchery                 goto opthelp;
368b077aed3SPierre Pronchery             break;
369e71b7053SJung-uk Kim         case OPT_BATCH:
370e71b7053SJung-uk Kim             batch = 1;
371e71b7053SJung-uk Kim             break;
372e71b7053SJung-uk Kim         case OPT_NEWHDR:
373e71b7053SJung-uk Kim             newhdr = 1;
374e71b7053SJung-uk Kim             break;
375e71b7053SJung-uk Kim         case OPT_MODULUS:
376e71b7053SJung-uk Kim             modulus = 1;
377e71b7053SJung-uk Kim             break;
378e71b7053SJung-uk Kim         case OPT_VERIFY:
379e71b7053SJung-uk Kim             verify = 1;
380e71b7053SJung-uk Kim             break;
381e71b7053SJung-uk Kim         case OPT_NODES:
382b077aed3SPierre Pronchery         case OPT_NOENC:
383b077aed3SPierre Pronchery             noenc = 1;
384e71b7053SJung-uk Kim             break;
385e71b7053SJung-uk Kim         case OPT_NOOUT:
386e71b7053SJung-uk Kim             noout = 1;
387e71b7053SJung-uk Kim             break;
388e71b7053SJung-uk Kim         case OPT_VERBOSE:
389e71b7053SJung-uk Kim             verbose = 1;
390e71b7053SJung-uk Kim             break;
391e71b7053SJung-uk Kim         case OPT_UTF8:
392e71b7053SJung-uk Kim             chtype = MBSTRING_UTF8;
393e71b7053SJung-uk Kim             break;
394e71b7053SJung-uk Kim         case OPT_NAMEOPT:
395e71b7053SJung-uk Kim             if (!set_nameopt(opt_arg()))
396e71b7053SJung-uk Kim                 goto opthelp;
397e71b7053SJung-uk Kim             break;
398e71b7053SJung-uk Kim         case OPT_REQOPT:
399e71b7053SJung-uk Kim             if (!set_cert_ex(&reqflag, opt_arg()))
400e71b7053SJung-uk Kim                 goto opthelp;
401e71b7053SJung-uk Kim             break;
402e71b7053SJung-uk Kim         case OPT_TEXT:
403e71b7053SJung-uk Kim             text = 1;
404e71b7053SJung-uk Kim             break;
405e71b7053SJung-uk Kim         case OPT_X509:
406b077aed3SPierre Pronchery             gen_x509 = 1;
407b077aed3SPierre Pronchery             break;
408b077aed3SPierre Pronchery         case OPT_CA:
409b077aed3SPierre Pronchery             CAfile = opt_arg();
410b077aed3SPierre Pronchery             gen_x509 = 1;
411b077aed3SPierre Pronchery             break;
412b077aed3SPierre Pronchery         case OPT_CAKEY:
413b077aed3SPierre Pronchery             CAkeyfile = opt_arg();
414e71b7053SJung-uk Kim             break;
415e71b7053SJung-uk Kim         case OPT_DAYS:
416e71b7053SJung-uk Kim             days = atoi(opt_arg());
417b077aed3SPierre Pronchery             if (days < -1) {
418b077aed3SPierre Pronchery                 BIO_printf(bio_err, "%s: -days parameter arg must be >= -1\n",
419b077aed3SPierre Pronchery                            prog);
420b077aed3SPierre Pronchery                 goto end;
421b077aed3SPierre Pronchery             }
422e71b7053SJung-uk Kim             break;
423e71b7053SJung-uk Kim         case OPT_SET_SERIAL:
424e71b7053SJung-uk Kim             if (serial != NULL) {
425e71b7053SJung-uk Kim                 BIO_printf(bio_err, "Serial number supplied twice\n");
426e71b7053SJung-uk Kim                 goto opthelp;
42774664626SKris Kennaway             }
428e71b7053SJung-uk Kim             serial = s2i_ASN1_INTEGER(NULL, opt_arg());
429e71b7053SJung-uk Kim             if (serial == NULL)
430e71b7053SJung-uk Kim                 goto opthelp;
431e71b7053SJung-uk Kim             break;
432e71b7053SJung-uk Kim         case OPT_SUBJECT:
433e71b7053SJung-uk Kim             subject = 1;
434e71b7053SJung-uk Kim             break;
435e71b7053SJung-uk Kim         case OPT_SUBJ:
436e71b7053SJung-uk Kim             subj = opt_arg();
437e71b7053SJung-uk Kim             break;
438e71b7053SJung-uk Kim         case OPT_MULTIVALUE_RDN:
439b077aed3SPierre Pronchery             /* obsolete */
440b077aed3SPierre Pronchery             break;
441b077aed3SPierre Pronchery         case OPT_COPY_EXTENSIONS:
442b077aed3SPierre Pronchery             if (!set_ext_copy(&ext_copy, opt_arg())) {
443b077aed3SPierre Pronchery                 BIO_printf(bio_err, "Invalid extension copy option: \"%s\"\n",
444b077aed3SPierre Pronchery                            opt_arg());
445b077aed3SPierre Pronchery                 goto end;
446b077aed3SPierre Pronchery             }
447e71b7053SJung-uk Kim             break;
448e71b7053SJung-uk Kim         case OPT_ADDEXT:
449e71b7053SJung-uk Kim             p = opt_arg();
450e71b7053SJung-uk Kim             if (addexts == NULL) {
451e71b7053SJung-uk Kim                 addexts = lh_OPENSSL_STRING_new(ext_name_hash, ext_name_cmp);
452e71b7053SJung-uk Kim                 addext_bio = BIO_new(BIO_s_mem());
453e71b7053SJung-uk Kim                 if (addexts == NULL || addext_bio == NULL)
45474664626SKris Kennaway                     goto end;
45574664626SKris Kennaway             }
456e71b7053SJung-uk Kim             i = duplicated(addexts, p);
457b077aed3SPierre Pronchery             if (i == 1) {
458b077aed3SPierre Pronchery                 BIO_printf(bio_err, "Duplicate extension: %s\n", p);
459e71b7053SJung-uk Kim                 goto opthelp;
460b077aed3SPierre Pronchery             }
461b077aed3SPierre Pronchery             if (i < 0 || BIO_printf(addext_bio, "%s\n", p) < 0)
462e71b7053SJung-uk Kim                 goto end;
463e71b7053SJung-uk Kim             break;
464e71b7053SJung-uk Kim         case OPT_EXTENSIONS:
465e71b7053SJung-uk Kim             extensions = opt_arg();
466e71b7053SJung-uk Kim             break;
467e71b7053SJung-uk Kim         case OPT_REQEXTS:
468e71b7053SJung-uk Kim             req_exts = opt_arg();
469e71b7053SJung-uk Kim             break;
470e71b7053SJung-uk Kim         case OPT_PRECERT:
471e71b7053SJung-uk Kim             newreq = precert = 1;
472e71b7053SJung-uk Kim             break;
473e71b7053SJung-uk Kim         case OPT_MD:
474b077aed3SPierre Pronchery             digest = opt_unknown();
475e71b7053SJung-uk Kim             break;
476e71b7053SJung-uk Kim         }
477e71b7053SJung-uk Kim     }
478b077aed3SPierre Pronchery 
479b077aed3SPierre Pronchery     /* No extra arguments. */
480e71b7053SJung-uk Kim     argc = opt_num_rest();
481e71b7053SJung-uk Kim     if (argc != 0)
482e71b7053SJung-uk Kim         goto opthelp;
48374664626SKris Kennaway 
484b077aed3SPierre Pronchery     if (!app_RAND_load())
485b077aed3SPierre Pronchery         goto end;
486ed7112f0SJung-uk Kim 
487b077aed3SPierre Pronchery     if (!gen_x509) {
488b077aed3SPierre Pronchery         if (days != UNSET_DAYS)
489b077aed3SPierre Pronchery             BIO_printf(bio_err, "Ignoring -days without -x509; not generating a certificate\n");
490b077aed3SPierre Pronchery         if (ext_copy == EXT_COPY_NONE)
491b077aed3SPierre Pronchery             BIO_printf(bio_err, "Ignoring -copy_extensions 'none' when -x509 is not given\n");
492b077aed3SPierre Pronchery     }
493b077aed3SPierre Pronchery     if (gen_x509 && infile == NULL)
494b077aed3SPierre Pronchery         newreq = 1;
495e71b7053SJung-uk Kim 
496e71b7053SJung-uk Kim     if (!app_passwd(passargin, passargout, &passin, &passout)) {
497f579bf8eSKris Kennaway         BIO_printf(bio_err, "Error getting passwords\n");
498f579bf8eSKris Kennaway         goto end;
499f579bf8eSKris Kennaway     }
50074664626SKris Kennaway 
501b077aed3SPierre Pronchery     if ((req_conf = app_load_config_verbose(template, verbose)) == NULL)
50217f01e99SJung-uk Kim         goto end;
503b077aed3SPierre Pronchery     if (addext_bio != NULL) {
504e71b7053SJung-uk Kim         if (verbose)
505e71b7053SJung-uk Kim             BIO_printf(bio_err,
506b077aed3SPierre Pronchery                        "Using additional configuration from -addext options\n");
50717f01e99SJung-uk Kim         if ((addext_conf = app_load_config_bio(addext_bio, NULL)) == NULL)
50817f01e99SJung-uk Kim             goto end;
50974664626SKris Kennaway     }
510e71b7053SJung-uk Kim     if (template != default_config_file && !app_load_modules(req_conf))
5113b4e3dcbSSimon L. B. Nielsen         goto end;
51274664626SKris Kennaway 
5136f9291ceSJung-uk Kim     if (req_conf != NULL) {
5145c87c606SMark Murray         p = NCONF_get_string(req_conf, NULL, "oid_file");
5155c87c606SMark Murray         if (p == NULL)
5165c87c606SMark Murray             ERR_clear_error();
5176f9291ceSJung-uk Kim         if (p != NULL) {
518b077aed3SPierre Pronchery             BIO *oid_bio = BIO_new_file(p, "r");
51974664626SKris Kennaway 
5206f9291ceSJung-uk Kim             if (oid_bio == NULL) {
521b077aed3SPierre Pronchery                 if (verbose)
522b077aed3SPierre Pronchery                     BIO_printf(bio_err,
523b077aed3SPierre Pronchery                                "Problems opening '%s' for extra OIDs\n", p);
5246f9291ceSJung-uk Kim             } else {
52574664626SKris Kennaway                 OBJ_create_objects(oid_bio);
52674664626SKris Kennaway                 BIO_free(oid_bio);
52774664626SKris Kennaway             }
52874664626SKris Kennaway         }
52974664626SKris Kennaway     }
530e71b7053SJung-uk Kim     if (!add_oid_section(req_conf))
5316f9291ceSJung-uk Kim         goto end;
53274664626SKris Kennaway 
533b077aed3SPierre Pronchery     /* Check that any specified digest is fetchable */
534b077aed3SPierre Pronchery     if (digest != NULL) {
535b077aed3SPierre Pronchery         if (!opt_md(digest, &md)) {
5365c87c606SMark Murray             ERR_clear_error();
537e71b7053SJung-uk Kim             goto opthelp;
53874664626SKris Kennaway         }
539b077aed3SPierre Pronchery         EVP_MD_free(md);
540b077aed3SPierre Pronchery     } else {
541b077aed3SPierre Pronchery         /* No digest specified, default to configuration */
542b077aed3SPierre Pronchery         p = NCONF_get_string(req_conf, section, "default_md");
543b077aed3SPierre Pronchery         if (p == NULL)
544b077aed3SPierre Pronchery             ERR_clear_error();
545b077aed3SPierre Pronchery         else
546b077aed3SPierre Pronchery             digest = p;
5475c87c606SMark Murray     }
54874664626SKris Kennaway 
549e71b7053SJung-uk Kim     if (extensions == NULL) {
550b077aed3SPierre Pronchery         extensions = NCONF_get_string(req_conf, section, V3_EXTENSIONS);
551e71b7053SJung-uk Kim         if (extensions == NULL)
5525c87c606SMark Murray             ERR_clear_error();
5535c87c606SMark Murray     }
554e71b7053SJung-uk Kim     if (extensions != NULL) {
55574664626SKris Kennaway         /* Check syntax of file */
55674664626SKris Kennaway         X509V3_CTX ctx;
557b077aed3SPierre Pronchery 
55874664626SKris Kennaway         X509V3_set_ctx_test(&ctx);
5595c87c606SMark Murray         X509V3_set_nconf(&ctx, req_conf);
5605c87c606SMark Murray         if (!X509V3_EXT_add_nconf(req_conf, &ctx, extensions, NULL)) {
56174664626SKris Kennaway             BIO_printf(bio_err,
562b077aed3SPierre Pronchery                        "Error checking x509 extension section %s\n",
563b077aed3SPierre Pronchery                        extensions);
56474664626SKris Kennaway             goto end;
56574664626SKris Kennaway         }
56674664626SKris Kennaway     }
567e71b7053SJung-uk Kim     if (addext_conf != NULL) {
568e71b7053SJung-uk Kim         /* Check syntax of command line extensions */
569e71b7053SJung-uk Kim         X509V3_CTX ctx;
570b077aed3SPierre Pronchery 
571e71b7053SJung-uk Kim         X509V3_set_ctx_test(&ctx);
572e71b7053SJung-uk Kim         X509V3_set_nconf(&ctx, addext_conf);
573e71b7053SJung-uk Kim         if (!X509V3_EXT_add_nconf(addext_conf, &ctx, "default", NULL)) {
574b077aed3SPierre Pronchery             BIO_printf(bio_err, "Error checking extensions defined using -addext\n");
575e71b7053SJung-uk Kim             goto end;
576e71b7053SJung-uk Kim         }
577e71b7053SJung-uk Kim     }
57874664626SKris Kennaway 
579e71b7053SJung-uk Kim     if (passin == NULL) {
580e71b7053SJung-uk Kim         passin = nofree_passin =
581b077aed3SPierre Pronchery             NCONF_get_string(req_conf, section, "input_password");
582e71b7053SJung-uk Kim         if (passin == NULL)
5835c87c606SMark Murray             ERR_clear_error();
5845c87c606SMark Murray     }
585f579bf8eSKris Kennaway 
586e71b7053SJung-uk Kim     if (passout == NULL) {
587e71b7053SJung-uk Kim         passout = nofree_passout =
588b077aed3SPierre Pronchery             NCONF_get_string(req_conf, section, "output_password");
589e71b7053SJung-uk Kim         if (passout == NULL)
5905c87c606SMark Murray             ERR_clear_error();
5915c87c606SMark Murray     }
592f579bf8eSKris Kennaway 
593b077aed3SPierre Pronchery     p = NCONF_get_string(req_conf, section, STRING_MASK);
594e71b7053SJung-uk Kim     if (p == NULL)
5955c87c606SMark Murray         ERR_clear_error();
596f579bf8eSKris Kennaway 
597e71b7053SJung-uk Kim     if (p != NULL && !ASN1_STRING_set_default_mask_asc(p)) {
598f579bf8eSKris Kennaway         BIO_printf(bio_err, "Invalid global string mask setting %s\n", p);
599f579bf8eSKris Kennaway         goto end;
600f579bf8eSKris Kennaway     }
601f579bf8eSKris Kennaway 
6026f9291ceSJung-uk Kim     if (chtype != MBSTRING_UTF8) {
603b077aed3SPierre Pronchery         p = NCONF_get_string(req_conf, section, UTF8_IN);
604e71b7053SJung-uk Kim         if (p == NULL)
6055c87c606SMark Murray             ERR_clear_error();
606e71b7053SJung-uk Kim         else if (strcmp(p, "yes") == 0)
6075c87c606SMark Murray             chtype = MBSTRING_UTF8;
6085c87c606SMark Murray     }
6095c87c606SMark Murray 
610e71b7053SJung-uk Kim     if (req_exts == NULL) {
611b077aed3SPierre Pronchery         req_exts = NCONF_get_string(req_conf, section, REQ_EXTENSIONS);
612e71b7053SJung-uk Kim         if (req_exts == NULL)
6135c87c606SMark Murray             ERR_clear_error();
6145c87c606SMark Murray     }
615e71b7053SJung-uk Kim     if (req_exts != NULL) {
616f579bf8eSKris Kennaway         /* Check syntax of file */
617f579bf8eSKris Kennaway         X509V3_CTX ctx;
618b077aed3SPierre Pronchery 
619f579bf8eSKris Kennaway         X509V3_set_ctx_test(&ctx);
6205c87c606SMark Murray         X509V3_set_nconf(&ctx, req_conf);
6215c87c606SMark Murray         if (!X509V3_EXT_add_nconf(req_conf, &ctx, req_exts, NULL)) {
622f579bf8eSKris Kennaway             BIO_printf(bio_err,
623b077aed3SPierre Pronchery                        "Error checking request extension section %s\n",
624f579bf8eSKris Kennaway                        req_exts);
625f579bf8eSKris Kennaway             goto end;
626f579bf8eSKris Kennaway         }
627f579bf8eSKris Kennaway     }
628f579bf8eSKris Kennaway 
6296f9291ceSJung-uk Kim     if (keyfile != NULL) {
630b077aed3SPierre Pronchery         pkey = load_key(keyfile, keyform, 0, passin, e, "private key");
631b077aed3SPierre Pronchery         if (pkey == NULL)
63274664626SKris Kennaway             goto end;
633b077aed3SPierre Pronchery         app_RAND_load_conf(req_conf, section);
634ddd58736SKris Kennaway     }
635b077aed3SPierre Pronchery     if (newreq && pkey == NULL) {
636b077aed3SPierre Pronchery         app_RAND_load_conf(req_conf, section);
63774664626SKris Kennaway 
638aa795734SPierre Pronchery         if (!NCONF_get_number(req_conf, section, BITS, &newkey_len)) {
639aa795734SPierre Pronchery             ERR_clear_error();
640b077aed3SPierre Pronchery             newkey_len = DEFAULT_KEY_LENGTH;
641aa795734SPierre Pronchery         }
64274664626SKris Kennaway 
643b077aed3SPierre Pronchery         genctx = set_keygen_ctx(keyalg, &keyalgstr, &newkey_len, gen_eng);
644e71b7053SJung-uk Kim         if (genctx == NULL)
6451f13597dSJung-uk Kim             goto end;
6461f13597dSJung-uk Kim 
647b077aed3SPierre Pronchery         if (newkey_len < MIN_KEY_LENGTH
648b077aed3SPierre Pronchery             && (EVP_PKEY_CTX_is_a(genctx, "RSA")
649b077aed3SPierre Pronchery                 || EVP_PKEY_CTX_is_a(genctx, "RSA-PSS")
650b077aed3SPierre Pronchery                 || EVP_PKEY_CTX_is_a(genctx, "DSA"))) {
651b077aed3SPierre Pronchery             BIO_printf(bio_err, "Private key length too short, needs to be at least %d bits, not %ld.\n",
652b077aed3SPierre Pronchery                        MIN_KEY_LENGTH, newkey_len);
65374664626SKris Kennaway             goto end;
65474664626SKris Kennaway         }
6551f13597dSJung-uk Kim 
656b077aed3SPierre Pronchery         if (newkey_len > OPENSSL_RSA_MAX_MODULUS_BITS
657b077aed3SPierre Pronchery             && (EVP_PKEY_CTX_is_a(genctx, "RSA")
658b077aed3SPierre Pronchery                 || EVP_PKEY_CTX_is_a(genctx, "RSA-PSS")))
659e71b7053SJung-uk Kim             BIO_printf(bio_err,
660e71b7053SJung-uk Kim                        "Warning: It is not recommended to use more than %d bit for RSA keys.\n"
661e71b7053SJung-uk Kim                        "         Your key size is %ld! Larger key size may behave not as expected.\n",
662b077aed3SPierre Pronchery                        OPENSSL_RSA_MAX_MODULUS_BITS, newkey_len);
663e71b7053SJung-uk Kim 
664e71b7053SJung-uk Kim #ifndef OPENSSL_NO_DSA
665b077aed3SPierre Pronchery         if (EVP_PKEY_CTX_is_a(genctx, "DSA")
666b077aed3SPierre Pronchery                 && newkey_len > OPENSSL_DSA_MAX_MODULUS_BITS)
667e71b7053SJung-uk Kim             BIO_printf(bio_err,
668e71b7053SJung-uk Kim                        "Warning: It is not recommended to use more than %d bit for DSA keys.\n"
669e71b7053SJung-uk Kim                        "         Your key size is %ld! Larger key size may behave not as expected.\n",
670b077aed3SPierre Pronchery                        OPENSSL_DSA_MAX_MODULUS_BITS, newkey_len);
671e71b7053SJung-uk Kim #endif
672e71b7053SJung-uk Kim 
673e71b7053SJung-uk Kim         if (pkeyopts != NULL) {
6741f13597dSJung-uk Kim             char *genopt;
6756f9291ceSJung-uk Kim             for (i = 0; i < sk_OPENSSL_STRING_num(pkeyopts); i++) {
6761f13597dSJung-uk Kim                 genopt = sk_OPENSSL_STRING_value(pkeyopts, i);
6776f9291ceSJung-uk Kim                 if (pkey_ctrl_string(genctx, genopt) <= 0) {
678b077aed3SPierre Pronchery                     BIO_printf(bio_err, "Key parameter error \"%s\"\n", genopt);
6791f13597dSJung-uk Kim                     goto end;
6801f13597dSJung-uk Kim                 }
6811f13597dSJung-uk Kim             }
6821f13597dSJung-uk Kim         }
6831f13597dSJung-uk Kim 
6841f13597dSJung-uk Kim         EVP_PKEY_CTX_set_cb(genctx, genpkey_cb);
6851f13597dSJung-uk Kim         EVP_PKEY_CTX_set_app_data(genctx, bio_err);
68674664626SKris Kennaway 
687b077aed3SPierre Pronchery         pkey = app_keygen(genctx, keyalgstr, newkey_len, verbose);
6881f13597dSJung-uk Kim 
6891f13597dSJung-uk Kim         EVP_PKEY_CTX_free(genctx);
6901f13597dSJung-uk Kim         genctx = NULL;
691b077aed3SPierre Pronchery     }
692b077aed3SPierre Pronchery     if (keyout == NULL && keyfile == NULL) {
693b077aed3SPierre Pronchery         keyout = NCONF_get_string(req_conf, section, KEYFILE);
6945c87c606SMark Murray         if (keyout == NULL)
6955c87c606SMark Murray             ERR_clear_error();
6965c87c606SMark Murray     }
69774664626SKris Kennaway 
698b077aed3SPierre Pronchery     if (pkey != NULL && (keyfile == NULL || keyout != NULL)) {
699b077aed3SPierre Pronchery         if (verbose) {
700b077aed3SPierre Pronchery             BIO_printf(bio_err, "Writing private key to ");
701e71b7053SJung-uk Kim             if (keyout == NULL)
702b077aed3SPierre Pronchery                 BIO_printf(bio_err, "stdout\n");
703e71b7053SJung-uk Kim             else
704b077aed3SPierre Pronchery                 BIO_printf(bio_err, "'%s'\n", keyout);
705b077aed3SPierre Pronchery         }
706b077aed3SPierre Pronchery         out = bio_open_owner(keyout, outformat, newreq);
707e71b7053SJung-uk Kim         if (out == NULL)
70874664626SKris Kennaway             goto end;
70974664626SKris Kennaway 
710b077aed3SPierre Pronchery         p = NCONF_get_string(req_conf, section, "encrypt_rsa_key");
7116f9291ceSJung-uk Kim         if (p == NULL) {
7125c87c606SMark Murray             ERR_clear_error();
713b077aed3SPierre Pronchery             p = NCONF_get_string(req_conf, section, "encrypt_key");
7145c87c606SMark Murray             if (p == NULL)
7155c87c606SMark Murray                 ERR_clear_error();
7165c87c606SMark Murray         }
71774664626SKris Kennaway         if ((p != NULL) && (strcmp(p, "no") == 0))
71874664626SKris Kennaway             cipher = NULL;
719b077aed3SPierre Pronchery         if (noenc)
7206f9291ceSJung-uk Kim             cipher = NULL;
72174664626SKris Kennaway 
72274664626SKris Kennaway         i = 0;
72374664626SKris Kennaway  loop:
72474664626SKris Kennaway         if (!PEM_write_bio_PrivateKey(out, pkey, cipher,
7256f9291ceSJung-uk Kim                                       NULL, 0, NULL, passout)) {
72674664626SKris Kennaway             if ((ERR_GET_REASON(ERR_peek_error()) ==
7276f9291ceSJung-uk Kim                  PEM_R_PROBLEMS_GETTING_PASSWORD) && (i < 3)) {
72874664626SKris Kennaway                 ERR_clear_error();
72974664626SKris Kennaway                 i++;
73074664626SKris Kennaway                 goto loop;
73174664626SKris Kennaway             }
73274664626SKris Kennaway             goto end;
73374664626SKris Kennaway         }
734e71b7053SJung-uk Kim         BIO_free(out);
735e71b7053SJung-uk Kim         out = NULL;
73674664626SKris Kennaway         BIO_printf(bio_err, "-----\n");
73774664626SKris Kennaway     }
73874664626SKris Kennaway 
739b077aed3SPierre Pronchery     /*
740b077aed3SPierre Pronchery      * subj is expected to be in the format /type0=value0/type1=value1/type2=...
741b077aed3SPierre Pronchery      * where characters may be escaped by \
742b077aed3SPierre Pronchery      */
743b077aed3SPierre Pronchery     if (subj != NULL
744b077aed3SPierre Pronchery             && (fsubj = parse_name(subj, chtype, multirdn, "subject")) == NULL)
745b077aed3SPierre Pronchery         goto end;
746b077aed3SPierre Pronchery 
7476f9291ceSJung-uk Kim     if (!newreq) {
748b077aed3SPierre Pronchery         req = load_csr(infile /* if NULL, reads from stdin */,
749b077aed3SPierre Pronchery                        informat, "X509 request");
750b077aed3SPierre Pronchery         if (req == NULL)
75174664626SKris Kennaway             goto end;
752b077aed3SPierre Pronchery     }
75374664626SKris Kennaway 
754b077aed3SPierre Pronchery     if (CAkeyfile == NULL)
755b077aed3SPierre Pronchery         CAkeyfile = CAfile;
756b077aed3SPierre Pronchery     if (CAkeyfile != NULL) {
757b077aed3SPierre Pronchery         if (CAfile == NULL) {
758b077aed3SPierre Pronchery             BIO_printf(bio_err,
759b077aed3SPierre Pronchery                        "Warning: Ignoring -CAkey option since no -CA option is given\n");
760b077aed3SPierre Pronchery         } else {
761b077aed3SPierre Pronchery             if ((CAkey = load_key(CAkeyfile, FORMAT_UNDEF,
762b077aed3SPierre Pronchery                                   0, passin, e,
763b077aed3SPierre Pronchery                                   CAkeyfile != CAfile
764b077aed3SPierre Pronchery                                   ? "issuer private key from -CAkey arg"
765b077aed3SPierre Pronchery                                   : "issuer private key from -CA arg")) == NULL)
76674664626SKris Kennaway                 goto end;
76774664626SKris Kennaway         }
76874664626SKris Kennaway     }
769b077aed3SPierre Pronchery     if (CAfile != NULL) {
770b077aed3SPierre Pronchery         if ((CAcert = load_cert_pass(CAfile, FORMAT_UNDEF, 1, passin,
771b077aed3SPierre Pronchery                                      "issuer cert from -CA arg")) == NULL)
772b077aed3SPierre Pronchery             goto end;
773b077aed3SPierre Pronchery         if (!X509_check_private_key(CAcert, CAkey)) {
774b077aed3SPierre Pronchery             BIO_printf(bio_err,
775b077aed3SPierre Pronchery                        "Issuer CA certificate and key do not match\n");
776b077aed3SPierre Pronchery             goto end;
777b077aed3SPierre Pronchery         }
778b077aed3SPierre Pronchery     }
779b077aed3SPierre Pronchery     if (newreq || gen_x509) {
780b077aed3SPierre Pronchery         if (CAcert == NULL && pkey == NULL) {
781b077aed3SPierre Pronchery             BIO_printf(bio_err, "Must provide a signature key using -key or"
782b077aed3SPierre Pronchery                 " provide -CA / -CAkey\n");
78374664626SKris Kennaway             goto end;
78474664626SKris Kennaway         }
7851f13597dSJung-uk Kim 
7866f9291ceSJung-uk Kim         if (req == NULL) {
787b077aed3SPierre Pronchery             req = X509_REQ_new_ex(app_get0_libctx(), app_get0_propq());
7886f9291ceSJung-uk Kim             if (req == NULL) {
78974664626SKris Kennaway                 goto end;
79074664626SKris Kennaway             }
79174664626SKris Kennaway 
792b077aed3SPierre Pronchery             if (!make_REQ(req, pkey, fsubj, multirdn, !gen_x509, chtype)){
793b077aed3SPierre Pronchery                 BIO_printf(bio_err, "Error making certificate request\n");
79474664626SKris Kennaway                 goto end;
79574664626SKris Kennaway             }
796b077aed3SPierre Pronchery             /* Note that -x509 can take over -key and -subj option values. */
79774664626SKris Kennaway         }
798b077aed3SPierre Pronchery         if (gen_x509) {
799b077aed3SPierre Pronchery             EVP_PKEY *pub_key = X509_REQ_get0_pubkey(req);
800b077aed3SPierre Pronchery             EVP_PKEY *issuer_key = CAcert != NULL ? CAkey : pkey;
80174664626SKris Kennaway             X509V3_CTX ext_ctx;
802b077aed3SPierre Pronchery             X509_NAME *issuer = CAcert != NULL ? X509_get_subject_name(CAcert) :
803b077aed3SPierre Pronchery                 X509_REQ_get_subject_name(req);
804b077aed3SPierre Pronchery             X509_NAME *n_subj = fsubj != NULL ? fsubj :
805b077aed3SPierre Pronchery                 X509_REQ_get_subject_name(req);
806b077aed3SPierre Pronchery 
807b077aed3SPierre Pronchery             if ((new_x509 = X509_new_ex(app_get0_libctx(),
808b077aed3SPierre Pronchery                                         app_get0_propq())) == NULL)
8096f9291ceSJung-uk Kim                 goto end;
81074664626SKris Kennaway 
811e71b7053SJung-uk Kim             if (serial != NULL) {
812b077aed3SPierre Pronchery                 if (!X509_set_serialNumber(new_x509, serial))
8136f9291ceSJung-uk Kim                     goto end;
8146f9291ceSJung-uk Kim             } else {
815b077aed3SPierre Pronchery                 if (!rand_serial(NULL, X509_get_serialNumber(new_x509)))
8166be8ae07SJacques Vidrine                     goto end;
8175c87c606SMark Murray             }
81874664626SKris Kennaway 
819b077aed3SPierre Pronchery             if (!X509_set_issuer_name(new_x509, issuer))
8206f9291ceSJung-uk Kim                 goto end;
821b077aed3SPierre Pronchery             if (days == UNSET_DAYS) {
822b077aed3SPierre Pronchery                 days = DEFAULT_DAYS;
823e71b7053SJung-uk Kim             }
824b077aed3SPierre Pronchery             if (!set_cert_times(new_x509, NULL, NULL, days))
8256f9291ceSJung-uk Kim                 goto end;
826b077aed3SPierre Pronchery             if (!X509_set_subject_name(new_x509, n_subj))
8276f9291ceSJung-uk Kim                 goto end;
828b077aed3SPierre Pronchery             if (!pub_key || !X509_set_pubkey(new_x509, pub_key))
8296f9291ceSJung-uk Kim                 goto end;
830b077aed3SPierre Pronchery             if (ext_copy == EXT_COPY_UNSET) {
831b077aed3SPierre Pronchery                 if (infile != NULL)
832b077aed3SPierre Pronchery                     BIO_printf(bio_err, "Warning: No -copy_extensions given; ignoring any extensions in the request\n");
833b077aed3SPierre Pronchery             } else if (!copy_extensions(new_x509, req, ext_copy)) {
834b077aed3SPierre Pronchery                 BIO_printf(bio_err, "Error copying extensions from request\n");
835b077aed3SPierre Pronchery                 goto end;
836b077aed3SPierre Pronchery             }
83774664626SKris Kennaway 
83874664626SKris Kennaway             /* Set up V3 context struct */
839b077aed3SPierre Pronchery             X509V3_set_ctx(&ext_ctx, CAcert != NULL ? CAcert : new_x509,
840b077aed3SPierre Pronchery                            new_x509, NULL, NULL, X509V3_CTX_REPLACE);
841b077aed3SPierre Pronchery             /* prepare fallback for AKID, but only if issuer cert == new_x509 */
842b077aed3SPierre Pronchery             if (CAcert == NULL) {
843b077aed3SPierre Pronchery                 if (!X509V3_set_issuer_pkey(&ext_ctx, issuer_key))
844b077aed3SPierre Pronchery                     goto end;
845b077aed3SPierre Pronchery                 ERR_set_mark();
846b077aed3SPierre Pronchery                 if (!X509_check_private_key(new_x509, issuer_key))
847b077aed3SPierre Pronchery                     BIO_printf(bio_err,
848b077aed3SPierre Pronchery                                "Warning: Signature key and public key of cert do not match\n");
849b077aed3SPierre Pronchery                 ERR_pop_to_mark();
850b077aed3SPierre Pronchery             }
8515c87c606SMark Murray             X509V3_set_nconf(&ext_ctx, req_conf);
85274664626SKris Kennaway 
85374664626SKris Kennaway             /* Add extensions */
854b077aed3SPierre Pronchery             if (extensions != NULL
855b077aed3SPierre Pronchery                     && !X509V3_EXT_add_nconf(req_conf, &ext_ctx, extensions,
856b077aed3SPierre Pronchery                                              new_x509)) {
857b077aed3SPierre Pronchery                 BIO_printf(bio_err, "Error adding x509 extensions from section %s\n",
85874664626SKris Kennaway                            extensions);
85974664626SKris Kennaway                 goto end;
86074664626SKris Kennaway             }
861e71b7053SJung-uk Kim             if (addext_conf != NULL
862e71b7053SJung-uk Kim                 && !X509V3_EXT_add_nconf(addext_conf, &ext_ctx, "default",
863b077aed3SPierre Pronchery                                          new_x509)) {
864b077aed3SPierre Pronchery                 BIO_printf(bio_err, "Error adding extensions defined via -addext\n");
865e71b7053SJung-uk Kim                 goto end;
866e71b7053SJung-uk Kim             }
86774664626SKris Kennaway 
868e71b7053SJung-uk Kim             /* If a pre-cert was requested, we need to add a poison extension */
869e71b7053SJung-uk Kim             if (precert) {
870b077aed3SPierre Pronchery                 if (X509_add1_ext_i2d(new_x509, NID_ct_precert_poison,
871b077aed3SPierre Pronchery                                       NULL, 1, 0) != 1) {
872e71b7053SJung-uk Kim                     BIO_printf(bio_err, "Error adding poison extension\n");
873e71b7053SJung-uk Kim                     goto end;
874e71b7053SJung-uk Kim                 }
875e71b7053SJung-uk Kim             }
876e71b7053SJung-uk Kim 
877b077aed3SPierre Pronchery             i = do_X509_sign(new_x509, issuer_key, digest, sigopts, &ext_ctx);
878b077aed3SPierre Pronchery             if (!i)
87974664626SKris Kennaway                 goto end;
8806f9291ceSJung-uk Kim         } else {
881f579bf8eSKris Kennaway             X509V3_CTX ext_ctx;
882f579bf8eSKris Kennaway 
883f579bf8eSKris Kennaway             /* Set up V3 context struct */
884f579bf8eSKris Kennaway             X509V3_set_ctx(&ext_ctx, NULL, NULL, req, NULL, 0);
8855c87c606SMark Murray             X509V3_set_nconf(&ext_ctx, req_conf);
886f579bf8eSKris Kennaway 
887f579bf8eSKris Kennaway             /* Add extensions */
888e71b7053SJung-uk Kim             if (req_exts != NULL
889e71b7053SJung-uk Kim                 && !X509V3_EXT_REQ_add_nconf(req_conf, &ext_ctx,
890e71b7053SJung-uk Kim                                              req_exts, req)) {
891b077aed3SPierre Pronchery                 BIO_printf(bio_err, "Error adding request extensions from section %s\n",
892f579bf8eSKris Kennaway                            req_exts);
893f579bf8eSKris Kennaway                 goto end;
894f579bf8eSKris Kennaway             }
895e71b7053SJung-uk Kim             if (addext_conf != NULL
896e71b7053SJung-uk Kim                 && !X509V3_EXT_REQ_add_nconf(addext_conf, &ext_ctx, "default",
897e71b7053SJung-uk Kim                                              req)) {
898b077aed3SPierre Pronchery                 BIO_printf(bio_err, "Error adding extensions defined via -addext\n");
899e71b7053SJung-uk Kim                 goto end;
900e71b7053SJung-uk Kim             }
901e71b7053SJung-uk Kim             i = do_X509_REQ_sign(req, pkey, digest, sigopts);
902b077aed3SPierre Pronchery             if (!i)
90374664626SKris Kennaway                 goto end;
90474664626SKris Kennaway         }
90574664626SKris Kennaway     }
90674664626SKris Kennaway 
907b077aed3SPierre Pronchery     if (subj != NULL && !newreq && !gen_x509) {
9086f9291ceSJung-uk Kim         if (verbose) {
909b077aed3SPierre Pronchery             BIO_printf(out, "Modifying subject of certificate request\n");
910b077aed3SPierre Pronchery             print_name(out, "Old subject=", X509_REQ_get_subject_name(req));
9115c87c606SMark Murray         }
9125c87c606SMark Murray 
913b077aed3SPierre Pronchery         if (!X509_REQ_set_subject_name(req, fsubj)) {
914b077aed3SPierre Pronchery             BIO_printf(bio_err, "Error modifying subject of certificate request\n");
9155c87c606SMark Murray             goto end;
9165c87c606SMark Murray         }
9175c87c606SMark Murray 
9186f9291ceSJung-uk Kim         if (verbose) {
919b077aed3SPierre Pronchery             print_name(out, "New subject=", X509_REQ_get_subject_name(req));
9205c87c606SMark Murray         }
9215c87c606SMark Murray     }
9225c87c606SMark Murray 
923b077aed3SPierre Pronchery     if (verify) {
924e71b7053SJung-uk Kim         EVP_PKEY *tpubkey = pkey;
92574664626SKris Kennaway 
926e71b7053SJung-uk Kim         if (tpubkey == NULL) {
927e71b7053SJung-uk Kim             tpubkey = X509_REQ_get0_pubkey(req);
928e71b7053SJung-uk Kim             if (tpubkey == NULL)
9296f9291ceSJung-uk Kim                 goto end;
93074664626SKris Kennaway         }
93174664626SKris Kennaway 
932b077aed3SPierre Pronchery         i = do_X509_REQ_verify(req, tpubkey, vfyopts);
93374664626SKris Kennaway 
934b077aed3SPierre Pronchery         if (i < 0)
93574664626SKris Kennaway             goto end;
936b077aed3SPierre Pronchery         if (i == 0)
937b077aed3SPierre Pronchery             BIO_printf(bio_err, "Certificate request self-signature verify failure\n");
938b077aed3SPierre Pronchery         else /* i > 0 */
939b077aed3SPierre Pronchery             BIO_printf(bio_err, "Certificate request self-signature verify OK\n");
940e71b7053SJung-uk Kim     }
94174664626SKris Kennaway 
9426f9291ceSJung-uk Kim     if (noout && !text && !modulus && !subject && !pubkey) {
943e71b7053SJung-uk Kim         ret = 0;
94474664626SKris Kennaway         goto end;
94574664626SKris Kennaway     }
94674664626SKris Kennaway 
947e71b7053SJung-uk Kim     out = bio_open_default(outfile,
948e71b7053SJung-uk Kim                            keyout != NULL && outfile != NULL &&
949e71b7053SJung-uk Kim                            strcmp(keyout, outfile) == 0 ? 'a' : 'w',
950e71b7053SJung-uk Kim                            outformat);
951e71b7053SJung-uk Kim     if (out == NULL)
95274664626SKris Kennaway         goto end;
95374664626SKris Kennaway 
9546f9291ceSJung-uk Kim     if (pubkey) {
955e71b7053SJung-uk Kim         EVP_PKEY *tpubkey = X509_REQ_get0_pubkey(req);
956e71b7053SJung-uk Kim 
9576f9291ceSJung-uk Kim         if (tpubkey == NULL) {
9585c87c606SMark Murray             BIO_printf(bio_err, "Error getting public key\n");
9595c87c606SMark Murray             goto end;
9605c87c606SMark Murray         }
9615c87c606SMark Murray         PEM_write_bio_PUBKEY(out, tpubkey);
9625c87c606SMark Murray     }
9635c87c606SMark Murray 
9646f9291ceSJung-uk Kim     if (text) {
965b077aed3SPierre Pronchery         if (gen_x509)
966b077aed3SPierre Pronchery             ret = X509_print_ex(out, new_x509, get_nameopt(), reqflag);
96774664626SKris Kennaway         else
968da327cd2SJung-uk Kim             ret = X509_REQ_print_ex(out, req, get_nameopt(), reqflag);
969da327cd2SJung-uk Kim 
970da327cd2SJung-uk Kim         if (ret == 0) {
971b077aed3SPierre Pronchery             if (gen_x509)
972da327cd2SJung-uk Kim                 BIO_printf(bio_err, "Error printing certificate\n");
973da327cd2SJung-uk Kim             else
974da327cd2SJung-uk Kim                 BIO_printf(bio_err, "Error printing certificate request\n");
975da327cd2SJung-uk Kim             goto end;
976da327cd2SJung-uk Kim         }
9775c87c606SMark Murray     }
9785c87c606SMark Murray 
9796f9291ceSJung-uk Kim     if (subject) {
980b077aed3SPierre Pronchery         print_name(out, "subject=", gen_x509
981b077aed3SPierre Pronchery                    ? X509_get_subject_name(new_x509)
982b077aed3SPierre Pronchery                    : X509_REQ_get_subject_name(req));
98374664626SKris Kennaway     }
98474664626SKris Kennaway 
9856f9291ceSJung-uk Kim     if (modulus) {
9865c87c606SMark Murray         EVP_PKEY *tpubkey;
98774664626SKris Kennaway 
988b077aed3SPierre Pronchery         if (gen_x509)
989b077aed3SPierre Pronchery             tpubkey = X509_get0_pubkey(new_x509);
99074664626SKris Kennaway         else
991e71b7053SJung-uk Kim             tpubkey = X509_REQ_get0_pubkey(req);
9926f9291ceSJung-uk Kim         if (tpubkey == NULL) {
993*6f1af0d7SPierre Pronchery             BIO_puts(bio_err, "Modulus is unavailable\n");
99474664626SKris Kennaway             goto end;
99574664626SKris Kennaway         }
996*6f1af0d7SPierre Pronchery         BIO_puts(out, "Modulus=");
997b077aed3SPierre Pronchery         if (EVP_PKEY_is_a(tpubkey, "RSA") || EVP_PKEY_is_a(tpubkey, "RSA-PSS")) {
998b077aed3SPierre Pronchery             BIGNUM *n = NULL;
999b077aed3SPierre Pronchery 
1000b077aed3SPierre Pronchery             if (!EVP_PKEY_get_bn_param(tpubkey, "n", &n))
1001b077aed3SPierre Pronchery                 goto end;
1002e71b7053SJung-uk Kim             BN_print(out, n);
1003b077aed3SPierre Pronchery             BN_free(n);
1004b077aed3SPierre Pronchery         } else {
1005*6f1af0d7SPierre Pronchery             BIO_puts(out, "Wrong Algorithm type");
1006b077aed3SPierre Pronchery         }
1007*6f1af0d7SPierre Pronchery         BIO_puts(out, "\n");
100874664626SKris Kennaway     }
100974664626SKris Kennaway 
1010b077aed3SPierre Pronchery     if (!noout && !gen_x509) {
101174664626SKris Kennaway         if (outformat == FORMAT_ASN1)
101274664626SKris Kennaway             i = i2d_X509_REQ_bio(out, req);
1013e71b7053SJung-uk Kim         else if (newhdr)
10146f9291ceSJung-uk Kim             i = PEM_write_bio_X509_REQ_NEW(out, req);
10156f9291ceSJung-uk Kim         else
10166f9291ceSJung-uk Kim             i = PEM_write_bio_X509_REQ(out, req);
10176f9291ceSJung-uk Kim         if (!i) {
1018b077aed3SPierre Pronchery             BIO_printf(bio_err, "Unable to write certificate request\n");
101974664626SKris Kennaway             goto end;
102074664626SKris Kennaway         }
102174664626SKris Kennaway     }
1022b077aed3SPierre Pronchery     if (!noout && gen_x509 && new_x509 != NULL) {
102374664626SKris Kennaway         if (outformat == FORMAT_ASN1)
1024b077aed3SPierre Pronchery             i = i2d_X509_bio(out, new_x509);
1025e71b7053SJung-uk Kim         else
1026b077aed3SPierre Pronchery             i = PEM_write_bio_X509(out, new_x509);
10276f9291ceSJung-uk Kim         if (!i) {
1028b077aed3SPierre Pronchery             BIO_printf(bio_err, "Unable to write X509 certificate\n");
102974664626SKris Kennaway             goto end;
103074664626SKris Kennaway         }
103174664626SKris Kennaway     }
1032e71b7053SJung-uk Kim     ret = 0;
103374664626SKris Kennaway  end:
1034e71b7053SJung-uk Kim     if (ret) {
103574664626SKris Kennaway         ERR_print_errors(bio_err);
103674664626SKris Kennaway     }
10376f9291ceSJung-uk Kim     NCONF_free(req_conf);
1038e71b7053SJung-uk Kim     NCONF_free(addext_conf);
1039e71b7053SJung-uk Kim     BIO_free(addext_bio);
1040ddd58736SKris Kennaway     BIO_free_all(out);
104174664626SKris Kennaway     EVP_PKEY_free(pkey);
10421f13597dSJung-uk Kim     EVP_PKEY_CTX_free(genctx);
10431f13597dSJung-uk Kim     sk_OPENSSL_STRING_free(pkeyopts);
10441f13597dSJung-uk Kim     sk_OPENSSL_STRING_free(sigopts);
1045b077aed3SPierre Pronchery     sk_OPENSSL_STRING_free(vfyopts);
1046e71b7053SJung-uk Kim     lh_OPENSSL_STRING_doall(addexts, exts_cleanup);
1047e71b7053SJung-uk Kim     lh_OPENSSL_STRING_free(addexts);
10481f13597dSJung-uk Kim #ifndef OPENSSL_NO_ENGINE
1049b077aed3SPierre Pronchery     release_engine(gen_eng);
10501f13597dSJung-uk Kim #endif
10511f13597dSJung-uk Kim     OPENSSL_free(keyalgstr);
105274664626SKris Kennaway     X509_REQ_free(req);
1053b077aed3SPierre Pronchery     X509_NAME_free(fsubj);
1054b077aed3SPierre Pronchery     X509_free(new_x509);
1055b077aed3SPierre Pronchery     X509_free(CAcert);
1056b077aed3SPierre Pronchery     EVP_PKEY_free(CAkey);
10575c87c606SMark Murray     ASN1_INTEGER_free(serial);
10586cf8931aSJung-uk Kim     release_engine(e);
1059e71b7053SJung-uk Kim     if (passin != nofree_passin)
10606f9291ceSJung-uk Kim         OPENSSL_free(passin);
1061e71b7053SJung-uk Kim     if (passout != nofree_passout)
10626f9291ceSJung-uk Kim         OPENSSL_free(passout);
1063e71b7053SJung-uk Kim     return ret;
106474664626SKris Kennaway }
106574664626SKris Kennaway 
1066b077aed3SPierre Pronchery static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, X509_NAME *fsubj,
1067b077aed3SPierre Pronchery                     int multirdn, int attribs, unsigned long chtype)
106874664626SKris Kennaway {
106974664626SKris Kennaway     int ret = 0, i;
1070f579bf8eSKris Kennaway     char no_prompt = 0;
1071b077aed3SPierre Pronchery     STACK_OF(CONF_VALUE) *dn_sk = NULL, *attr_sk = NULL;
1072f579bf8eSKris Kennaway     char *tmp, *dn_sect, *attr_sect;
107374664626SKris Kennaway 
1074b077aed3SPierre Pronchery     tmp = NCONF_get_string(req_conf, section, PROMPT);
10755c87c606SMark Murray     if (tmp == NULL)
10765c87c606SMark Murray         ERR_clear_error();
1077e71b7053SJung-uk Kim     if ((tmp != NULL) && strcmp(tmp, "no") == 0)
10786f9291ceSJung-uk Kim         no_prompt = 1;
1079f579bf8eSKris Kennaway 
1080b077aed3SPierre Pronchery     dn_sect = NCONF_get_string(req_conf, section, DISTINGUISHED_NAME);
10816f9291ceSJung-uk Kim     if (dn_sect == NULL) {
1082b077aed3SPierre Pronchery         ERR_clear_error();
1083b077aed3SPierre Pronchery     } else {
10845c87c606SMark Murray         dn_sk = NCONF_get_section(req_conf, dn_sect);
10856f9291ceSJung-uk Kim         if (dn_sk == NULL) {
1086b077aed3SPierre Pronchery             BIO_printf(bio_err, "Unable to get '%s' section\n", dn_sect);
108774664626SKris Kennaway             goto err;
108874664626SKris Kennaway         }
1089b077aed3SPierre Pronchery     }
109074664626SKris Kennaway 
1091b077aed3SPierre Pronchery     attr_sect = NCONF_get_string(req_conf, section, ATTRIBUTES);
10926f9291ceSJung-uk Kim     if (attr_sect == NULL) {
10935c87c606SMark Murray         ERR_clear_error();
10946f9291ceSJung-uk Kim     } else {
10955c87c606SMark Murray         attr_sk = NCONF_get_section(req_conf, attr_sect);
10966f9291ceSJung-uk Kim         if (attr_sk == NULL) {
1097b077aed3SPierre Pronchery             BIO_printf(bio_err, "Unable to get '%s' section\n", attr_sect);
109874664626SKris Kennaway             goto err;
109974664626SKris Kennaway         }
110074664626SKris Kennaway     }
110174664626SKris Kennaway 
1102b077aed3SPierre Pronchery     /* so far there is only version 1 */
1103b077aed3SPierre Pronchery     if (!X509_REQ_set_version(req, X509_REQ_VERSION_1))
1104b077aed3SPierre Pronchery         goto err;
110574664626SKris Kennaway 
1106b077aed3SPierre Pronchery     if (fsubj != NULL)
1107b077aed3SPierre Pronchery         i = X509_REQ_set_subject_name(req, fsubj);
1108e71b7053SJung-uk Kim     else if (no_prompt)
1109e71b7053SJung-uk Kim         i = auto_info(req, dn_sk, attr_sk, attribs, chtype);
11105c87c606SMark Murray     else
11116f9291ceSJung-uk Kim         i = prompt_info(req, dn_sk, dn_sect, attr_sk, attr_sect, attribs,
11126f9291ceSJung-uk Kim                         chtype);
11136f9291ceSJung-uk Kim     if (!i)
11146f9291ceSJung-uk Kim         goto err;
1115f579bf8eSKris Kennaway 
11166f9291ceSJung-uk Kim     if (!X509_REQ_set_pubkey(req, pkey))
11176f9291ceSJung-uk Kim         goto err;
1118f579bf8eSKris Kennaway 
1119f579bf8eSKris Kennaway     ret = 1;
1120f579bf8eSKris Kennaway  err:
1121e71b7053SJung-uk Kim     return ret;
1122f579bf8eSKris Kennaway }
1123f579bf8eSKris Kennaway 
1124f579bf8eSKris Kennaway static int prompt_info(X509_REQ *req,
1125e71b7053SJung-uk Kim                        STACK_OF(CONF_VALUE) *dn_sk, const char *dn_sect,
1126e71b7053SJung-uk Kim                        STACK_OF(CONF_VALUE) *attr_sk, const char *attr_sect,
11276f9291ceSJung-uk Kim                        int attribs, unsigned long chtype)
1128f579bf8eSKris Kennaway {
1129f579bf8eSKris Kennaway     int i;
1130f579bf8eSKris Kennaway     char *p, *q;
1131f579bf8eSKris Kennaway     char buf[100];
11323b4e3dcbSSimon L. B. Nielsen     int nid, mval;
11335c87c606SMark Murray     long n_min, n_max;
11343b4e3dcbSSimon L. B. Nielsen     char *type, *value;
11353b4e3dcbSSimon L. B. Nielsen     const char *def;
1136f579bf8eSKris Kennaway     CONF_VALUE *v;
1137b077aed3SPierre Pronchery     X509_NAME *subj = X509_REQ_get_subject_name(req);
11385c87c606SMark Murray 
11396f9291ceSJung-uk Kim     if (!batch) {
11406f9291ceSJung-uk Kim         BIO_printf(bio_err,
11416f9291ceSJung-uk Kim                    "You are about to be asked to enter information that will be incorporated\n");
114274664626SKris Kennaway         BIO_printf(bio_err, "into your certificate request.\n");
11436f9291ceSJung-uk Kim         BIO_printf(bio_err,
11446f9291ceSJung-uk Kim                    "What you are about to enter is what is called a Distinguished Name or a DN.\n");
11456f9291ceSJung-uk Kim         BIO_printf(bio_err,
11466f9291ceSJung-uk Kim                    "There are quite a few fields but you can leave some blank\n");
11476f9291ceSJung-uk Kim         BIO_printf(bio_err,
11486f9291ceSJung-uk Kim                    "For some fields there will be a default value,\n");
11496f9291ceSJung-uk Kim         BIO_printf(bio_err,
11506f9291ceSJung-uk Kim                    "If you enter '.', the field will be left blank.\n");
115174664626SKris Kennaway         BIO_printf(bio_err, "-----\n");
11525c87c606SMark Murray     }
115374664626SKris Kennaway 
11546f9291ceSJung-uk Kim     if (sk_CONF_VALUE_num(dn_sk)) {
115574664626SKris Kennaway         i = -1;
1156e71b7053SJung-uk Kim  start:
1157e71b7053SJung-uk Kim         for (;;) {
115874664626SKris Kennaway             i++;
11596f9291ceSJung-uk Kim             if (sk_CONF_VALUE_num(dn_sk) <= i)
11606f9291ceSJung-uk Kim                 break;
116174664626SKris Kennaway 
1162f579bf8eSKris Kennaway             v = sk_CONF_VALUE_value(dn_sk, i);
116374664626SKris Kennaway             p = q = NULL;
116474664626SKris Kennaway             type = v->name;
116574664626SKris Kennaway             if (!check_end(type, "_min") || !check_end(type, "_max") ||
11666f9291ceSJung-uk Kim                 !check_end(type, "_default") || !check_end(type, "_value"))
11676f9291ceSJung-uk Kim                 continue;
11686f9291ceSJung-uk Kim             /*
11696f9291ceSJung-uk Kim              * Skip past any leading X. X: X, etc to allow for multiple
11706f9291ceSJung-uk Kim              * instances
117174664626SKris Kennaway              */
117274664626SKris Kennaway             for (p = v->name; *p; p++)
11736f9291ceSJung-uk Kim                 if ((*p == ':') || (*p == ',') || (*p == '.')) {
117474664626SKris Kennaway                     p++;
11756f9291ceSJung-uk Kim                     if (*p)
11766f9291ceSJung-uk Kim                         type = p;
117774664626SKris Kennaway                     break;
117874664626SKris Kennaway                 }
11796f9291ceSJung-uk Kim             if (*type == '+') {
11803b4e3dcbSSimon L. B. Nielsen                 mval = -1;
11813b4e3dcbSSimon L. B. Nielsen                 type++;
1182e71b7053SJung-uk Kim             } else {
11833b4e3dcbSSimon L. B. Nielsen                 mval = 0;
1184e71b7053SJung-uk Kim             }
118574664626SKris Kennaway             /* If OBJ not recognised ignore it */
11866f9291ceSJung-uk Kim             if ((nid = OBJ_txt2nid(type)) == NID_undef)
11876f9291ceSJung-uk Kim                 goto start;
1188e71b7053SJung-uk Kim             if (!join(buf, sizeof(buf), v->name, "_default", "Name"))
11895c87c606SMark Murray                 return 0;
11906f9291ceSJung-uk Kim             if ((def = NCONF_get_string(req_conf, dn_sect, buf)) == NULL) {
11915c87c606SMark Murray                 ERR_clear_error();
11925c87c606SMark Murray                 def = "";
11935c87c606SMark Murray             }
1194ced566fdSJacques Vidrine 
1195e71b7053SJung-uk Kim             if (!join(buf, sizeof(buf), v->name, "_value", "Name"))
1196e71b7053SJung-uk Kim                 return 0;
11976f9291ceSJung-uk Kim             if ((value = NCONF_get_string(req_conf, dn_sect, buf)) == NULL) {
11985c87c606SMark Murray                 ERR_clear_error();
119974664626SKris Kennaway                 value = NULL;
12005c87c606SMark Murray             }
120174664626SKris Kennaway 
1202e71b7053SJung-uk Kim             if (!join(buf, sizeof(buf), v->name, "_min", "Name"))
1203e71b7053SJung-uk Kim                 return 0;
12046f9291ceSJung-uk Kim             if (!NCONF_get_number(req_conf, dn_sect, buf, &n_min)) {
1205fceca8a3SJacques Vidrine                 ERR_clear_error();
12065c87c606SMark Murray                 n_min = -1;
1207fceca8a3SJacques Vidrine             }
120874664626SKris Kennaway 
1209e71b7053SJung-uk Kim             if (!join(buf, sizeof(buf), v->name, "_max", "Name"))
1210e71b7053SJung-uk Kim                 return 0;
12116f9291ceSJung-uk Kim             if (!NCONF_get_number(req_conf, dn_sect, buf, &n_max)) {
1212fceca8a3SJacques Vidrine                 ERR_clear_error();
12135c87c606SMark Murray                 n_max = -1;
1214fceca8a3SJacques Vidrine             }
121574664626SKris Kennaway 
1216f579bf8eSKris Kennaway             if (!add_DN_object(subj, v->value, def, value, nid,
12173b4e3dcbSSimon L. B. Nielsen                                n_min, n_max, chtype, mval))
1218f579bf8eSKris Kennaway                 return 0;
121974664626SKris Kennaway         }
12206f9291ceSJung-uk Kim         if (X509_NAME_entry_count(subj) == 0) {
1221b077aed3SPierre Pronchery             BIO_printf(bio_err, "Error: No objects specified in config file\n");
1222f579bf8eSKris Kennaway             return 0;
122374664626SKris Kennaway         }
122474664626SKris Kennaway 
12256f9291ceSJung-uk Kim         if (attribs) {
12266f9291ceSJung-uk Kim             if ((attr_sk != NULL) && (sk_CONF_VALUE_num(attr_sk) > 0)
12276f9291ceSJung-uk Kim                 && (!batch)) {
12286f9291ceSJung-uk Kim                 BIO_printf(bio_err,
12296f9291ceSJung-uk Kim                            "\nPlease enter the following 'extra' attributes\n");
12306f9291ceSJung-uk Kim                 BIO_printf(bio_err,
12316f9291ceSJung-uk Kim                            "to be sent with your certificate request\n");
123274664626SKris Kennaway             }
123374664626SKris Kennaway 
123474664626SKris Kennaway             i = -1;
1235e71b7053SJung-uk Kim  start2:
1236e71b7053SJung-uk Kim             for (;;) {
123774664626SKris Kennaway                 i++;
12386f9291ceSJung-uk Kim                 if ((attr_sk == NULL) || (sk_CONF_VALUE_num(attr_sk) <= i))
123974664626SKris Kennaway                     break;
124074664626SKris Kennaway 
1241f579bf8eSKris Kennaway                 v = sk_CONF_VALUE_value(attr_sk, i);
124274664626SKris Kennaway                 type = v->name;
124374664626SKris Kennaway                 if ((nid = OBJ_txt2nid(type)) == NID_undef)
124474664626SKris Kennaway                     goto start2;
124574664626SKris Kennaway 
1246e71b7053SJung-uk Kim                 if (!join(buf, sizeof(buf), type, "_default", "Name"))
12475c87c606SMark Murray                     return 0;
12485c87c606SMark Murray                 if ((def = NCONF_get_string(req_conf, attr_sect, buf))
12496f9291ceSJung-uk Kim                     == NULL) {
12505c87c606SMark Murray                     ERR_clear_error();
125174664626SKris Kennaway                     def = "";
12525c87c606SMark Murray                 }
12535c87c606SMark Murray 
1254e71b7053SJung-uk Kim                 if (!join(buf, sizeof(buf), type, "_value", "Name"))
1255e71b7053SJung-uk Kim                     return 0;
12565c87c606SMark Murray                 if ((value = NCONF_get_string(req_conf, attr_sect, buf))
12576f9291ceSJung-uk Kim                     == NULL) {
12585c87c606SMark Murray                     ERR_clear_error();
125974664626SKris Kennaway                     value = NULL;
12605c87c606SMark Murray                 }
126174664626SKris Kennaway 
1262e71b7053SJung-uk Kim                 if (!join(buf, sizeof(buf), type, "_min", "Name"))
1263e71b7053SJung-uk Kim                     return 0;
12646f9291ceSJung-uk Kim                 if (!NCONF_get_number(req_conf, attr_sect, buf, &n_min)) {
1265ab8565e2SSimon L. B. Nielsen                     ERR_clear_error();
12665c87c606SMark Murray                     n_min = -1;
1267ab8565e2SSimon L. B. Nielsen                 }
126874664626SKris Kennaway 
1269e71b7053SJung-uk Kim                 if (!join(buf, sizeof(buf), type, "_max", "Name"))
1270e71b7053SJung-uk Kim                     return 0;
12716f9291ceSJung-uk Kim                 if (!NCONF_get_number(req_conf, attr_sect, buf, &n_max)) {
1272ab8565e2SSimon L. B. Nielsen                     ERR_clear_error();
12735c87c606SMark Murray                     n_max = -1;
1274ab8565e2SSimon L. B. Nielsen                 }
127574664626SKris Kennaway 
1276f579bf8eSKris Kennaway                 if (!add_attribute_object(req,
12776f9291ceSJung-uk Kim                                           v->value, def, value, nid, n_min,
12786f9291ceSJung-uk Kim                                           n_max, chtype))
1279f579bf8eSKris Kennaway                     return 0;
128074664626SKris Kennaway             }
128174664626SKris Kennaway         }
12826f9291ceSJung-uk Kim     } else {
128374664626SKris Kennaway         BIO_printf(bio_err, "No template, please set one up.\n");
1284f579bf8eSKris Kennaway         return 0;
128574664626SKris Kennaway     }
128674664626SKris Kennaway 
1287f579bf8eSKris Kennaway     return 1;
128874664626SKris Kennaway 
128974664626SKris Kennaway }
129074664626SKris Kennaway 
1291f579bf8eSKris Kennaway static int auto_info(X509_REQ *req, STACK_OF(CONF_VALUE) *dn_sk,
12926f9291ceSJung-uk Kim                      STACK_OF(CONF_VALUE) *attr_sk, int attribs,
12936f9291ceSJung-uk Kim                      unsigned long chtype)
1294f579bf8eSKris Kennaway {
1295e71b7053SJung-uk Kim     int i, spec_char, plus_char;
1296f579bf8eSKris Kennaway     char *p, *q;
1297f579bf8eSKris Kennaway     char *type;
1298f579bf8eSKris Kennaway     CONF_VALUE *v;
1299f579bf8eSKris Kennaway     X509_NAME *subj;
1300f579bf8eSKris Kennaway 
1301f579bf8eSKris Kennaway     subj = X509_REQ_get_subject_name(req);
1302f579bf8eSKris Kennaway 
13036f9291ceSJung-uk Kim     for (i = 0; i < sk_CONF_VALUE_num(dn_sk); i++) {
13043b4e3dcbSSimon L. B. Nielsen         int mval;
1305f579bf8eSKris Kennaway         v = sk_CONF_VALUE_value(dn_sk, i);
1306f579bf8eSKris Kennaway         p = q = NULL;
1307f579bf8eSKris Kennaway         type = v->name;
13086f9291ceSJung-uk Kim         /*
13096f9291ceSJung-uk Kim          * Skip past any leading X. X: X, etc to allow for multiple instances
1310f579bf8eSKris Kennaway          */
1311e71b7053SJung-uk Kim         for (p = v->name; *p; p++) {
1312ddd58736SKris Kennaway #ifndef CHARSET_EBCDIC
1313b077aed3SPierre Pronchery             spec_char = (*p == ':' || *p == ',' || *p == '.');
1314ddd58736SKris Kennaway #else
1315b077aed3SPierre Pronchery             spec_char = (*p == os_toascii[':'] || *p == os_toascii[',']
1316b077aed3SPierre Pronchery                          || *p == os_toascii['.']);
1317ddd58736SKris Kennaway #endif
1318e71b7053SJung-uk Kim             if (spec_char) {
1319f579bf8eSKris Kennaway                 p++;
13206f9291ceSJung-uk Kim                 if (*p)
13216f9291ceSJung-uk Kim                     type = p;
1322f579bf8eSKris Kennaway                 break;
1323f579bf8eSKris Kennaway             }
1324e71b7053SJung-uk Kim         }
13253b4e3dcbSSimon L. B. Nielsen #ifndef CHARSET_EBCDIC
1326e71b7053SJung-uk Kim         plus_char = (*type == '+');
13273b4e3dcbSSimon L. B. Nielsen #else
1328e71b7053SJung-uk Kim         plus_char = (*type == os_toascii['+']);
13293b4e3dcbSSimon L. B. Nielsen #endif
1330e71b7053SJung-uk Kim         if (plus_char) {
1331aeb5019cSJung-uk Kim             type++;
13323b4e3dcbSSimon L. B. Nielsen             mval = -1;
1333e71b7053SJung-uk Kim         } else {
13343b4e3dcbSSimon L. B. Nielsen             mval = 0;
1335e71b7053SJung-uk Kim         }
13365c87c606SMark Murray         if (!X509_NAME_add_entry_by_txt(subj, type, chtype,
13376f9291ceSJung-uk Kim                                         (unsigned char *)v->value, -1, -1,
13386f9291ceSJung-uk Kim                                         mval))
13396f9291ceSJung-uk Kim             return 0;
1340f579bf8eSKris Kennaway 
1341f579bf8eSKris Kennaway     }
1342f579bf8eSKris Kennaway 
13436f9291ceSJung-uk Kim     if (!X509_NAME_entry_count(subj)) {
1344b077aed3SPierre Pronchery         BIO_printf(bio_err, "Error: No objects specified in config file\n");
1345f579bf8eSKris Kennaway         return 0;
1346f579bf8eSKris Kennaway     }
13476f9291ceSJung-uk Kim     if (attribs) {
13486f9291ceSJung-uk Kim         for (i = 0; i < sk_CONF_VALUE_num(attr_sk); i++) {
1349f579bf8eSKris Kennaway             v = sk_CONF_VALUE_value(attr_sk, i);
13505c87c606SMark Murray             if (!X509_REQ_add1_attr_by_txt(req, v->name, chtype,
13516f9291ceSJung-uk Kim                                            (unsigned char *)v->value, -1))
13526f9291ceSJung-uk Kim                 return 0;
1353f579bf8eSKris Kennaway         }
1354f579bf8eSKris Kennaway     }
1355f579bf8eSKris Kennaway     return 1;
1356f579bf8eSKris Kennaway }
1357f579bf8eSKris Kennaway 
13586f9291ceSJung-uk Kim static int add_DN_object(X509_NAME *n, char *text, const char *def,
13596f9291ceSJung-uk Kim                          char *value, int nid, int n_min, int n_max,
13606f9291ceSJung-uk Kim                          unsigned long chtype, int mval)
136174664626SKris Kennaway {
1362e71b7053SJung-uk Kim     int ret = 0;
1363e71b7053SJung-uk Kim     char buf[1024];
136474664626SKris Kennaway 
1365e71b7053SJung-uk Kim     ret = build_data(text, def, value, n_min, n_max, buf, sizeof(buf),
1366e71b7053SJung-uk Kim                      "DN value", "DN default");
1367e71b7053SJung-uk Kim     if ((ret == 0) || (ret == 1))
1368e71b7053SJung-uk Kim         return ret;
1369e71b7053SJung-uk Kim     ret = 1;
137094ad176cSJung-uk Kim 
13715c87c606SMark Murray     if (!X509_NAME_add_entry_by_NID(n, nid, chtype,
13726f9291ceSJung-uk Kim                                     (unsigned char *)buf, -1, -1, mval))
1373e71b7053SJung-uk Kim         ret = 0;
1374e71b7053SJung-uk Kim 
1375e71b7053SJung-uk Kim     return ret;
137674664626SKris Kennaway }
137774664626SKris Kennaway 
13783b4e3dcbSSimon L. B. Nielsen static int add_attribute_object(X509_REQ *req, char *text, const char *def,
13793b4e3dcbSSimon L. B. Nielsen                                 char *value, int nid, int n_min,
13805c87c606SMark Murray                                 int n_max, unsigned long chtype)
1381f579bf8eSKris Kennaway {
1382e71b7053SJung-uk Kim     int ret = 0;
1383e71b7053SJung-uk Kim     char buf[1024];
138474664626SKris Kennaway 
1385e71b7053SJung-uk Kim     ret = build_data(text, def, value, n_min, n_max, buf, sizeof(buf),
1386e71b7053SJung-uk Kim                      "Attribute value", "Attribute default");
1387e71b7053SJung-uk Kim     if ((ret == 0) || (ret == 1))
1388e71b7053SJung-uk Kim         return ret;
1389e71b7053SJung-uk Kim     ret = 1;
1390e71b7053SJung-uk Kim 
1391e71b7053SJung-uk Kim     if (!X509_REQ_add1_attr_by_NID(req, nid, chtype,
1392e71b7053SJung-uk Kim                                    (unsigned char *)buf, -1)) {
1393e71b7053SJung-uk Kim         BIO_printf(bio_err, "Error adding attribute\n");
1394e71b7053SJung-uk Kim         ret = 0;
1395e71b7053SJung-uk Kim     }
1396e71b7053SJung-uk Kim 
1397e71b7053SJung-uk Kim     return ret;
1398e71b7053SJung-uk Kim }
1399e71b7053SJung-uk Kim 
1400b077aed3SPierre Pronchery static int build_data(char *text, const char *def, char *value,
1401b077aed3SPierre Pronchery                       int n_min, int n_max, char *buf, const int buf_size,
1402b077aed3SPierre Pronchery                       const char *desc1, const char *desc2)
1403e71b7053SJung-uk Kim {
1404e71b7053SJung-uk Kim     int i;
1405f579bf8eSKris Kennaway  start:
14066f9291ceSJung-uk Kim     if (!batch)
14076f9291ceSJung-uk Kim         BIO_printf(bio_err, "%s [%s]:", text, def);
1408f579bf8eSKris Kennaway     (void)BIO_flush(bio_err);
14096f9291ceSJung-uk Kim     if (value != NULL) {
1410e71b7053SJung-uk Kim         if (!join(buf, buf_size, value, "\n", desc1))
1411e71b7053SJung-uk Kim             return 0;
1412f579bf8eSKris Kennaway         BIO_printf(bio_err, "%s\n", value);
14136f9291ceSJung-uk Kim     } else {
1414f579bf8eSKris Kennaway         buf[0] = '\0';
14156f9291ceSJung-uk Kim         if (!batch) {
1416e71b7053SJung-uk Kim             if (!fgets(buf, buf_size, stdin))
14176a599222SSimon L. B. Nielsen                 return 0;
14186f9291ceSJung-uk Kim         } else {
14195c87c606SMark Murray             buf[0] = '\n';
14205c87c606SMark Murray             buf[1] = '\0';
14215c87c606SMark Murray         }
1422f579bf8eSKris Kennaway     }
142374664626SKris Kennaway 
14246f9291ceSJung-uk Kim     if (buf[0] == '\0')
1425e71b7053SJung-uk Kim         return 0;
1426e71b7053SJung-uk Kim     if (buf[0] == '\n') {
1427f579bf8eSKris Kennaway         if ((def == NULL) || (def[0] == '\0'))
1428e71b7053SJung-uk Kim             return 1;
1429e71b7053SJung-uk Kim         if (!join(buf, buf_size, def, "\n", desc2))
1430e71b7053SJung-uk Kim             return 0;
1431e71b7053SJung-uk Kim     } else if ((buf[0] == '.') && (buf[1] == '\n')) {
1432e71b7053SJung-uk Kim         return 1;
1433e71b7053SJung-uk Kim     }
143474664626SKris Kennaway 
1435f579bf8eSKris Kennaway     i = strlen(buf);
14366f9291ceSJung-uk Kim     if (buf[i - 1] != '\n') {
1437b077aed3SPierre Pronchery         BIO_printf(bio_err, "Missing newline at end of input\n");
1438e71b7053SJung-uk Kim         return 0;
1439f579bf8eSKris Kennaway     }
1440f579bf8eSKris Kennaway     buf[--i] = '\0';
1441ddd58736SKris Kennaway #ifdef CHARSET_EBCDIC
1442ddd58736SKris Kennaway     ebcdic2ascii(buf, buf, i);
1443ddd58736SKris Kennaway #endif
14446f9291ceSJung-uk Kim     if (!req_check_len(i, n_min, n_max)) {
144594ad176cSJung-uk Kim         if (batch || value)
144694ad176cSJung-uk Kim             return 0;
144794ad176cSJung-uk Kim         goto start;
144894ad176cSJung-uk Kim     }
1449e71b7053SJung-uk Kim     return 2;
145074664626SKris Kennaway }
145174664626SKris Kennaway 
14525c87c606SMark Murray static int req_check_len(int len, int n_min, int n_max)
145374664626SKris Kennaway {
1454b077aed3SPierre Pronchery     if (n_min > 0 && len < n_min) {
14556f9291ceSJung-uk Kim         BIO_printf(bio_err,
1456b077aed3SPierre Pronchery                    "String too short, must be at least %d bytes long\n", n_min);
1457e71b7053SJung-uk Kim         return 0;
145874664626SKris Kennaway     }
1459b077aed3SPierre Pronchery     if (n_max >= 0 && len > n_max) {
14606f9291ceSJung-uk Kim         BIO_printf(bio_err,
1461b077aed3SPierre Pronchery                    "String too long, must be at most %d bytes long\n", n_max);
1462e71b7053SJung-uk Kim         return 0;
146374664626SKris Kennaway     }
1464e71b7053SJung-uk Kim     return 1;
146574664626SKris Kennaway }
146674664626SKris Kennaway 
146774664626SKris Kennaway /* Check if the end of a string matches 'end' */
14683b4e3dcbSSimon L. B. Nielsen static int check_end(const char *str, const char *end)
146974664626SKris Kennaway {
1470e71b7053SJung-uk Kim     size_t elen, slen;
14713b4e3dcbSSimon L. B. Nielsen     const char *tmp;
1472e71b7053SJung-uk Kim 
147374664626SKris Kennaway     elen = strlen(end);
147474664626SKris Kennaway     slen = strlen(str);
14756f9291ceSJung-uk Kim     if (elen > slen)
14766f9291ceSJung-uk Kim         return 1;
147774664626SKris Kennaway     tmp = str + slen - elen;
147874664626SKris Kennaway     return strcmp(tmp, end);
147974664626SKris Kennaway }
14801f13597dSJung-uk Kim 
1481e71b7053SJung-uk Kim /*
1482e71b7053SJung-uk Kim  * Merge the two strings together into the result buffer checking for
1483e71b7053SJung-uk Kim  * overflow and producing an error message if there is.
1484e71b7053SJung-uk Kim  */
1485e71b7053SJung-uk Kim static int join(char buf[], size_t buf_size, const char *name,
1486e71b7053SJung-uk Kim                 const char *tail, const char *desc)
1487e71b7053SJung-uk Kim {
1488e71b7053SJung-uk Kim     const size_t name_len = strlen(name), tail_len = strlen(tail);
1489e71b7053SJung-uk Kim 
1490e71b7053SJung-uk Kim     if (name_len + tail_len + 1 > buf_size) {
1491e71b7053SJung-uk Kim         BIO_printf(bio_err, "%s '%s' too long\n", desc, name);
1492e71b7053SJung-uk Kim         return 0;
1493e71b7053SJung-uk Kim     }
1494e71b7053SJung-uk Kim     memcpy(buf, name, name_len);
1495e71b7053SJung-uk Kim     memcpy(buf + name_len, tail, tail_len + 1);
1496e71b7053SJung-uk Kim     return 1;
1497e71b7053SJung-uk Kim }
1498e71b7053SJung-uk Kim 
1499e71b7053SJung-uk Kim static EVP_PKEY_CTX *set_keygen_ctx(const char *gstr,
1500b077aed3SPierre Pronchery                                     char **pkeytype, long *pkeylen,
1501b077aed3SPierre Pronchery                                     ENGINE *keygen_engine)
15021f13597dSJung-uk Kim {
15031f13597dSJung-uk Kim     EVP_PKEY_CTX *gctx = NULL;
15041f13597dSJung-uk Kim     EVP_PKEY *param = NULL;
15051f13597dSJung-uk Kim     long keylen = -1;
15061f13597dSJung-uk Kim     BIO *pbio = NULL;
1507b077aed3SPierre Pronchery     const char *keytype = NULL;
1508b077aed3SPierre Pronchery     size_t keytypelen = 0;
1509b077aed3SPierre Pronchery     int expect_paramfile = 0;
15101f13597dSJung-uk Kim     const char *paramfile = NULL;
15111f13597dSJung-uk Kim 
1512b077aed3SPierre Pronchery     /* Treat the first part of gstr, and only that */
15136f9291ceSJung-uk Kim     if (gstr == NULL) {
1514b077aed3SPierre Pronchery         /*
1515b077aed3SPierre Pronchery          * Special case: when no string given, default to RSA and the
1516b077aed3SPierre Pronchery          * key length given by |*pkeylen|.
1517b077aed3SPierre Pronchery          */
1518b077aed3SPierre Pronchery         keytype = "RSA";
15191f13597dSJung-uk Kim         keylen = *pkeylen;
15206f9291ceSJung-uk Kim     } else if (gstr[0] >= '0' && gstr[0] <= '9') {
1521b077aed3SPierre Pronchery         /* Special case: only keylength given from string, so default to RSA */
1522b077aed3SPierre Pronchery         keytype = "RSA";
1523b077aed3SPierre Pronchery         /* The second part treatment will do the rest */
1524e71b7053SJung-uk Kim     } else {
15251f13597dSJung-uk Kim         const char *p = strchr(gstr, ':');
15261f13597dSJung-uk Kim         int len;
15271f13597dSJung-uk Kim 
1528e71b7053SJung-uk Kim         if (p != NULL)
15291f13597dSJung-uk Kim             len = p - gstr;
15301f13597dSJung-uk Kim         else
15311f13597dSJung-uk Kim             len = strlen(gstr);
15321f13597dSJung-uk Kim 
1533b077aed3SPierre Pronchery         if (strncmp(gstr, "param", len) == 0) {
1534b077aed3SPierre Pronchery             expect_paramfile = 1;
1535b077aed3SPierre Pronchery             if (p == NULL) {
1536b077aed3SPierre Pronchery                 BIO_printf(bio_err,
1537b077aed3SPierre Pronchery                            "Parameter file requested but no path given: %s\n",
1538b077aed3SPierre Pronchery                            gstr);
15391f13597dSJung-uk Kim                 return NULL;
15401f13597dSJung-uk Kim             }
1541e71b7053SJung-uk Kim         } else {
1542b077aed3SPierre Pronchery             keytype = gstr;
1543b077aed3SPierre Pronchery             keytypelen = len;
1544e71b7053SJung-uk Kim         }
1545b077aed3SPierre Pronchery 
1546b077aed3SPierre Pronchery         if (p != NULL)
1547b077aed3SPierre Pronchery             gstr = gstr + len + 1;
1548b077aed3SPierre Pronchery         else
1549b077aed3SPierre Pronchery             gstr = NULL;
15501f13597dSJung-uk Kim     }
1551b077aed3SPierre Pronchery 
1552b077aed3SPierre Pronchery     /* Treat the second part of gstr, if there is one */
1553b077aed3SPierre Pronchery     if (gstr != NULL) {
1554b077aed3SPierre Pronchery         /* If the second part starts with a digit, we assume it's a size */
1555b077aed3SPierre Pronchery         if (!expect_paramfile && gstr[0] >= '0' && gstr[0] <= '9')
1556b077aed3SPierre Pronchery             keylen = atol(gstr);
1557b077aed3SPierre Pronchery         else
1558b077aed3SPierre Pronchery             paramfile = gstr;
1559e71b7053SJung-uk Kim     }
15601f13597dSJung-uk Kim 
1561e71b7053SJung-uk Kim     if (paramfile != NULL) {
15621f13597dSJung-uk Kim         pbio = BIO_new_file(paramfile, "r");
1563e71b7053SJung-uk Kim         if (pbio == NULL) {
1564b077aed3SPierre Pronchery             BIO_printf(bio_err, "Cannot open parameter file %s\n", paramfile);
15651f13597dSJung-uk Kim             return NULL;
15661f13597dSJung-uk Kim         }
15671f13597dSJung-uk Kim         param = PEM_read_bio_Parameters(pbio, NULL);
15681f13597dSJung-uk Kim 
1569e71b7053SJung-uk Kim         if (param == NULL) {
15701f13597dSJung-uk Kim             X509 *x;
1571e71b7053SJung-uk Kim 
15721f13597dSJung-uk Kim             (void)BIO_reset(pbio);
15731f13597dSJung-uk Kim             x = PEM_read_bio_X509(pbio, NULL, NULL, NULL);
1574e71b7053SJung-uk Kim             if (x != NULL) {
15751f13597dSJung-uk Kim                 param = X509_get_pubkey(x);
15761f13597dSJung-uk Kim                 X509_free(x);
15771f13597dSJung-uk Kim             }
15781f13597dSJung-uk Kim         }
15791f13597dSJung-uk Kim 
15801f13597dSJung-uk Kim         BIO_free(pbio);
15811f13597dSJung-uk Kim 
1582e71b7053SJung-uk Kim         if (param == NULL) {
1583e71b7053SJung-uk Kim             BIO_printf(bio_err, "Error reading parameter file %s\n", paramfile);
15841f13597dSJung-uk Kim             return NULL;
15851f13597dSJung-uk Kim         }
1586b077aed3SPierre Pronchery         if (keytype == NULL) {
1587b077aed3SPierre Pronchery             keytype = EVP_PKEY_get0_type_name(param);
1588b077aed3SPierre Pronchery             if (keytype == NULL) {
1589b077aed3SPierre Pronchery                 EVP_PKEY_free(param);
1590b077aed3SPierre Pronchery                 BIO_puts(bio_err, "Unable to determine key type\n");
1591b077aed3SPierre Pronchery                 return NULL;
1592b077aed3SPierre Pronchery             }
1593b077aed3SPierre Pronchery         }
1594b077aed3SPierre Pronchery     }
1595b077aed3SPierre Pronchery 
1596b077aed3SPierre Pronchery     if (keytypelen > 0)
1597b077aed3SPierre Pronchery         *pkeytype = OPENSSL_strndup(keytype, keytypelen);
1598b077aed3SPierre Pronchery     else
1599b077aed3SPierre Pronchery         *pkeytype = OPENSSL_strdup(keytype);
1600b077aed3SPierre Pronchery 
1601b077aed3SPierre Pronchery     if (*pkeytype == NULL) {
1602b077aed3SPierre Pronchery         BIO_printf(bio_err, "Out of memory\n");
16031f13597dSJung-uk Kim         EVP_PKEY_free(param);
16041f13597dSJung-uk Kim         return NULL;
16051f13597dSJung-uk Kim     }
16061f13597dSJung-uk Kim 
1607b077aed3SPierre Pronchery     if (keylen >= 0)
1608b077aed3SPierre Pronchery         *pkeylen = keylen;
16091f13597dSJung-uk Kim 
1610e71b7053SJung-uk Kim     if (param != NULL) {
1611b077aed3SPierre Pronchery         if (!EVP_PKEY_is_a(param, *pkeytype)) {
1612b077aed3SPierre Pronchery             BIO_printf(bio_err, "Key type does not match parameters\n");
1613b077aed3SPierre Pronchery             EVP_PKEY_free(param);
1614b077aed3SPierre Pronchery             return NULL;
1615b077aed3SPierre Pronchery         }
1616b077aed3SPierre Pronchery 
1617b077aed3SPierre Pronchery         if (keygen_engine != NULL)
16181f13597dSJung-uk Kim             gctx = EVP_PKEY_CTX_new(param, keygen_engine);
1619b077aed3SPierre Pronchery         else
1620b077aed3SPierre Pronchery             gctx = EVP_PKEY_CTX_new_from_pkey(app_get0_libctx(),
1621b077aed3SPierre Pronchery                                               param, app_get0_propq());
1622b077aed3SPierre Pronchery         *pkeylen = EVP_PKEY_get_bits(param);
16231f13597dSJung-uk Kim         EVP_PKEY_free(param);
1624e71b7053SJung-uk Kim     } else {
1625b077aed3SPierre Pronchery         if (keygen_engine != NULL) {
1626b077aed3SPierre Pronchery             int pkey_id = get_legacy_pkey_id(app_get0_libctx(), *pkeytype,
1627b077aed3SPierre Pronchery                                              keygen_engine);
1628b077aed3SPierre Pronchery 
1629b077aed3SPierre Pronchery             if (pkey_id != NID_undef)
1630b077aed3SPierre Pronchery                 gctx = EVP_PKEY_CTX_new_id(pkey_id, keygen_engine);
1631b077aed3SPierre Pronchery         } else {
1632b077aed3SPierre Pronchery             gctx = EVP_PKEY_CTX_new_from_name(app_get0_libctx(),
1633b077aed3SPierre Pronchery                                               *pkeytype, app_get0_propq());
1634b077aed3SPierre Pronchery         }
1635e71b7053SJung-uk Kim     }
16361f13597dSJung-uk Kim 
1637e71b7053SJung-uk Kim     if (gctx == NULL) {
1638e71b7053SJung-uk Kim         BIO_puts(bio_err, "Error allocating keygen context\n");
16391f13597dSJung-uk Kim         return NULL;
16401f13597dSJung-uk Kim     }
16411f13597dSJung-uk Kim 
16426f9291ceSJung-uk Kim     if (EVP_PKEY_keygen_init(gctx) <= 0) {
1643e71b7053SJung-uk Kim         BIO_puts(bio_err, "Error initializing keygen context\n");
1644e71b7053SJung-uk Kim         EVP_PKEY_CTX_free(gctx);
16451f13597dSJung-uk Kim         return NULL;
16461f13597dSJung-uk Kim     }
1647b077aed3SPierre Pronchery     if (keylen == -1 && (EVP_PKEY_CTX_is_a(gctx, "RSA")
1648b077aed3SPierre Pronchery         || EVP_PKEY_CTX_is_a(gctx, "RSA-PSS")))
1649b077aed3SPierre Pronchery         keylen = *pkeylen;
1650b077aed3SPierre Pronchery 
1651b077aed3SPierre Pronchery     if (keylen != -1) {
1652b077aed3SPierre Pronchery         OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END };
1653b077aed3SPierre Pronchery         size_t bits = keylen;
1654b077aed3SPierre Pronchery 
1655b077aed3SPierre Pronchery         params[0] =
1656b077aed3SPierre Pronchery             OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_BITS, &bits);
1657b077aed3SPierre Pronchery         if (EVP_PKEY_CTX_set_params(gctx, params) <= 0) {
1658b077aed3SPierre Pronchery             BIO_puts(bio_err, "Error setting keysize\n");
16591f13597dSJung-uk Kim             EVP_PKEY_CTX_free(gctx);
16601f13597dSJung-uk Kim             return NULL;
16611f13597dSJung-uk Kim         }
16621f13597dSJung-uk Kim     }
16631f13597dSJung-uk Kim 
16641f13597dSJung-uk Kim     return gctx;
16651f13597dSJung-uk Kim }
16661f13597dSJung-uk Kim 
16671f13597dSJung-uk Kim static int genpkey_cb(EVP_PKEY_CTX *ctx)
16681f13597dSJung-uk Kim {
16691f13597dSJung-uk Kim     char c = '*';
16701f13597dSJung-uk Kim     BIO *b = EVP_PKEY_CTX_get_app_data(ctx);
16711f13597dSJung-uk Kim     int p;
16721f13597dSJung-uk Kim     p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
16736f9291ceSJung-uk Kim     if (p == 0)
16746f9291ceSJung-uk Kim         c = '.';
16756f9291ceSJung-uk Kim     if (p == 1)
16766f9291ceSJung-uk Kim         c = '+';
16776f9291ceSJung-uk Kim     if (p == 2)
16786f9291ceSJung-uk Kim         c = '*';
16796f9291ceSJung-uk Kim     if (p == 3)
16806f9291ceSJung-uk Kim         c = '\n';
16811f13597dSJung-uk Kim     BIO_write(b, &c, 1);
16821f13597dSJung-uk Kim     (void)BIO_flush(b);
16831f13597dSJung-uk Kim     return 1;
16841f13597dSJung-uk Kim }
1685