Annotation of src/usr.bin/openssl/req.c, Revision 1.23
1.23 ! tb 1: /* $OpenBSD: req.c,v 1.22 2021/12/12 20:42:37 tb Exp $ */
1.1 jsing 2: /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3: * All rights reserved.
4: *
5: * This package is an SSL implementation written
6: * by Eric Young (eay@cryptsoft.com).
7: * The implementation was written so as to conform with Netscapes SSL.
8: *
9: * This library is free for commercial and non-commercial use as long as
10: * the following conditions are aheared to. The following conditions
11: * apply to all code found in this distribution, be it the RC4, RSA,
12: * lhash, DES, etc., code; not just the SSL code. The SSL documentation
13: * included with this distribution is covered by the same copyright terms
14: * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15: *
16: * Copyright remains Eric Young's, and as such any Copyright notices in
17: * the code are not to be removed.
18: * If this package is used in a product, Eric Young should be given attribution
19: * as the author of the parts of the library used.
20: * This can be in the form of a textual message at program startup or
21: * in documentation (online or textual) provided with the package.
22: *
23: * Redistribution and use in source and binary forms, with or without
24: * modification, are permitted provided that the following conditions
25: * are met:
26: * 1. Redistributions of source code must retain the copyright
27: * notice, this list of conditions and the following disclaimer.
28: * 2. Redistributions in binary form must reproduce the above copyright
29: * notice, this list of conditions and the following disclaimer in the
30: * documentation and/or other materials provided with the distribution.
31: * 3. All advertising materials mentioning features or use of this software
32: * must display the following acknowledgement:
33: * "This product includes cryptographic software written by
34: * Eric Young (eay@cryptsoft.com)"
35: * The word 'cryptographic' can be left out if the rouines from the library
36: * being used are not cryptographic related :-).
37: * 4. If you include any Windows specific code (or a derivative thereof) from
38: * the apps directory (application code) you must include an acknowledgement:
39: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40: *
41: * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51: * SUCH DAMAGE.
52: *
53: * The licence and distribution terms for any publically available version or
54: * derivative of this code cannot be changed. i.e. this code cannot simply be
55: * copied and put under another distribution licence
56: * [including the GNU Public Licence.]
57: */
58:
59: /* Until the key-gen callbacks are modified to use newer prototypes, we allow
60: * deprecated functions for openssl-internal code */
61: #ifdef OPENSSL_NO_DEPRECATED
62: #undef OPENSSL_NO_DEPRECATED
63: #endif
64:
1.17 inoguchi 65: #include <ctype.h>
66: #include <limits.h>
1.1 jsing 67: #include <stdio.h>
68: #include <stdlib.h>
69: #include <string.h>
70: #include <time.h>
71:
72: #include "apps.h"
73:
74: #include <openssl/asn1.h>
75: #include <openssl/bio.h>
76: #include <openssl/bn.h>
77: #include <openssl/conf.h>
78: #include <openssl/err.h>
79: #include <openssl/evp.h>
80: #include <openssl/objects.h>
81: #include <openssl/pem.h>
82: #include <openssl/x509.h>
83: #include <openssl/x509v3.h>
84:
85: #include <openssl/dsa.h>
86:
87: #include <openssl/rsa.h>
88:
89: #define SECTION "req"
90:
91: #define BITS "default_bits"
92: #define KEYFILE "default_keyfile"
93: #define PROMPT "prompt"
94: #define DISTINGUISHED_NAME "distinguished_name"
95: #define ATTRIBUTES "attributes"
96: #define V3_EXTENSIONS "x509_extensions"
97: #define REQ_EXTENSIONS "req_extensions"
98: #define STRING_MASK "string_mask"
99: #define UTF8_IN "utf8"
100:
1.3 sthen 101: #define DEFAULT_KEY_LENGTH 2048
1.1 jsing 102: #define MIN_KEY_LENGTH 384
103:
1.13 miod 104: static int make_REQ(X509_REQ * req, EVP_PKEY * pkey, char *dn, int multirdn,
1.1 jsing 105: int attribs, unsigned long chtype);
106: static int build_subject(X509_REQ * req, char *subj, unsigned long chtype,
107: int multirdn);
108: static int prompt_info(X509_REQ * req,
109: STACK_OF(CONF_VALUE) * dn_sk, char *dn_sect,
110: STACK_OF(CONF_VALUE) * attr_sk, char *attr_sect, int attribs,
111: unsigned long chtype);
112: static int auto_info(X509_REQ * req, STACK_OF(CONF_VALUE) * sk,
113: STACK_OF(CONF_VALUE) * attr, int attribs,
114: unsigned long chtype);
115: static int add_attribute_object(X509_REQ * req, char *text, const char *def,
116: char *value, int nid, int n_min,
117: int n_max, unsigned long chtype);
118: static int add_DN_object(X509_NAME * n, char *text, const char *def, char *value,
119: int nid, int n_min, int n_max, unsigned long chtype, int mval);
120: static int genpkey_cb(EVP_PKEY_CTX * ctx);
121: static int req_check_len(int len, int n_min, int n_max);
122: static int check_end(const char *str, const char *end);
123: static EVP_PKEY_CTX *set_keygen_ctx(BIO * err, const char *gstr, int *pkey_type,
1.7 bcook 124: long *pkeylen, char **palgnam);
1.17 inoguchi 125: static unsigned long ext_name_hash(const OPENSSL_STRING *a);
126: static int ext_name_cmp(const OPENSSL_STRING *a, const OPENSSL_STRING *b);
127: static void exts_cleanup(OPENSSL_STRING *x);
128: static int duplicated(LHASH_OF(OPENSSL_STRING) *addexts, char *kv);
1.1 jsing 129: static CONF *req_conf = NULL;
1.17 inoguchi 130: static CONF *addext_conf = NULL;
1.19 jsing 131:
132: struct {
133: LHASH_OF(OPENSSL_STRING) *addexts;
134: BIO *addext_bio;
135: int batch;
136: unsigned long chtype;
137: int days;
138: const EVP_MD *digest;
139: char *extensions;
140: char *infile;
141: int informat;
142: char *keyalg;
143: char *keyfile;
144: int keyform;
145: char *keyout;
146: int modulus;
147: int multirdn;
148: int newhdr;
149: long newkey;
150: int newreq;
151: unsigned long nmflag;
152: int nodes;
153: int noout;
154: char *outfile;
155: int outformat;
156: char *passargin;
157: char *passargout;
158: STACK_OF(OPENSSL_STRING) *pkeyopts;
159: int pubkey;
160: char *req_exts;
161: unsigned long reqflag;
162: ASN1_INTEGER *serial;
163: STACK_OF(OPENSSL_STRING) *sigopts;
164: char *subj;
165: int subject;
166: char *template;
167: int text;
168: int verbose;
169: int verify;
170: int x509;
171: } req_config;
172:
173: static int
174: req_opt_addext(char *arg)
175: {
176: int i;
177:
178: if (req_config.addexts == NULL) {
179: req_config.addexts = (LHASH_OF(OPENSSL_STRING) *)lh_new(
180: (LHASH_HASH_FN_TYPE)ext_name_hash,
181: (LHASH_COMP_FN_TYPE)ext_name_cmp);
182: req_config.addext_bio = BIO_new(BIO_s_mem());
183: if (req_config.addexts == NULL ||
184: req_config.addext_bio == NULL)
185: return (1);
186: }
187: i = duplicated(req_config.addexts, arg);
188: if (i == 1)
189: return (1);
190: if (i < 0 || BIO_printf(req_config.addext_bio, "%s\n", arg) < 0)
191: return (1);
192:
193: return (0);
194: }
195:
196: static int
197: req_opt_days(char *arg)
198: {
199: const char *errstr;
200:
201: req_config.days = strtonum(arg, 1, INT_MAX, &errstr);
202: if (errstr != NULL) {
203: BIO_printf(bio_err, "bad -days %s, using 0: %s\n",
204: arg, errstr);
205: req_config.days = 30;
206: }
207: return (0);
208: }
209:
210: static int
211: req_opt_digest(int argc, char **argv, int *argsused)
212: {
213: char *name = argv[0];
214:
215: if (*name++ != '-')
216: return (1);
217:
218: if ((req_config.digest = EVP_get_digestbyname(name)) == NULL)
219: return (1);
220:
221: *argsused = 1;
222: return (0);
223: }
224:
225: static int
226: req_opt_newkey(char *arg)
227: {
228: req_config.keyalg = arg;
229: req_config.newreq = 1;
230: return (0);
231: }
232:
233: static int
234: req_opt_nameopt(char *arg)
235: {
236: if (!set_name_ex(&req_config.nmflag, arg))
237: return (1);
238: return (0);
239: }
240:
241: static int
242: req_opt_pkeyopt(char *arg)
243: {
244: if (req_config.pkeyopts == NULL)
245: req_config.pkeyopts = sk_OPENSSL_STRING_new_null();
246: if (req_config.pkeyopts == NULL)
247: return (1);
248: if (!sk_OPENSSL_STRING_push(req_config.pkeyopts, arg))
249: return (1);
250: return (0);
251: }
252:
253: static int
254: req_opt_reqopt(char *arg)
255: {
256: if (!set_cert_ex(&req_config.reqflag, arg))
257: return (1);
258: return (0);
259: }
260:
261: static int
262: req_opt_set_serial(char *arg)
263: {
264: req_config.serial = s2i_ASN1_INTEGER(NULL, arg);
265: if (req_config.serial == NULL)
266: return (1);
267: return (0);
268: }
269:
270: static int
271: req_opt_sigopt(char *arg)
272: {
273: if (req_config.sigopts == NULL)
274: req_config.sigopts = sk_OPENSSL_STRING_new_null();
275: if (req_config.sigopts == NULL)
276: return (1);
277: if (!sk_OPENSSL_STRING_push(req_config.sigopts, arg))
278: return (1);
279: return (0);
280: }
281:
282: static int
283: req_opt_utf8(void)
284: {
285: req_config.chtype = MBSTRING_UTF8;
286: return (0);
287: }
288:
289: static const struct option req_options[] = {
290: {
291: .name = "addext",
292: .argname = "key=value",
293: .desc = "Additional certificate extension (may be repeated)",
294: .type = OPTION_ARG_FUNC,
295: .opt.argfunc = req_opt_addext,
296: },
297: {
298: .name = "batch",
299: .desc = "Operate in batch mode",
300: .type = OPTION_FLAG,
301: .opt.flag = &req_config.batch,
302: },
303: {
304: .name = "config",
305: .argname = "file",
306: .desc = "Configuration file to use as request template",
307: .type = OPTION_ARG,
308: .opt.arg = &req_config.template,
309: },
310: {
311: .name = "days",
312: .argname = "number",
313: .desc = "Number of days generated certificate is valid for",
314: .type = OPTION_ARG_FUNC,
315: .opt.argfunc = req_opt_days,
316: },
317: {
318: .name = "extensions",
319: .argname = "section",
320: .desc = "Config section to use for certificate extensions",
321: .type = OPTION_ARG,
322: .opt.arg = &req_config.extensions,
323: },
324: {
325: .name = "in",
326: .argname = "file",
327: .desc = "Input file (default stdin)",
328: .type = OPTION_ARG,
329: .opt.arg = &req_config.infile,
330: },
331: {
332: .name = "inform",
333: .argname = "format",
334: .desc = "Input format (DER or PEM (default))",
335: .type = OPTION_ARG_FORMAT,
336: .opt.value = &req_config.informat,
337: },
338: {
339: .name = "key",
340: .argname = "file",
341: .desc = "Private key file",
342: .type = OPTION_ARG,
343: .opt.arg = &req_config.keyfile,
344: },
345: {
346: .name = "keyform",
347: .argname = "format",
348: .desc = "Private key format (DER or PEM (default))",
349: .type = OPTION_ARG_FORMAT,
350: .opt.value = &req_config.keyform,
351: },
352: {
353: .name = "keyout",
354: .argname = "file",
355: .desc = "Private key output file",
356: .type = OPTION_ARG,
357: .opt.arg = &req_config.keyout,
358: },
359: {
360: .name = "modulus",
361: .desc = "Print RSA modulus",
362: .type = OPTION_FLAG,
363: .opt.flag = &req_config.modulus,
364: },
365: {
366: .name = "multivalue-rdn",
367: .desc = "Enable support for multivalued RDNs",
368: .type = OPTION_FLAG,
369: .opt.flag = &req_config.multirdn,
370: },
371: {
372: .name = "nameopt",
373: .argname = "arg",
374: .desc = "Certificate name options",
375: .type = OPTION_ARG_FUNC,
376: .opt.argfunc = req_opt_nameopt,
377: },
378: {
379: .name = "new",
380: .desc = "New request",
381: .type = OPTION_FLAG,
382: .opt.flag = &req_config.newreq,
383: },
384: {
385: .name = "newhdr",
386: .desc = "Include 'NEW' in header lines",
387: .type = OPTION_FLAG,
388: .opt.flag = &req_config.newhdr,
389: },
390: {
391: .name = "newkey",
392: .argname = "param",
393: .desc = "Generate a new key using given parameters",
394: .type = OPTION_ARG_FUNC,
395: .opt.argfunc = req_opt_newkey,
396: },
397: {
398: .name = "nodes",
399: .desc = "Do not encrypt output private key",
400: .type = OPTION_FLAG,
401: .opt.flag = &req_config.nodes,
402: },
403: {
404: .name = "noout",
405: .desc = "Do not output request",
406: .type = OPTION_FLAG,
407: .opt.flag = &req_config.noout,
408: },
409: {
410: .name = "out",
411: .argname = "file",
412: .desc = "Output file (default stdout)",
413: .type = OPTION_ARG,
414: .opt.arg = &req_config.outfile,
415: },
416: {
417: .name = "outform",
418: .argname = "format",
419: .desc = "Output format (DER or PEM (default))",
420: .type = OPTION_ARG_FORMAT,
421: .opt.value = &req_config.outformat,
422: },
423: {
424: .name = "passin",
425: .argname = "source",
426: .desc = "Private key input password source",
427: .type = OPTION_ARG,
428: .opt.arg = &req_config.passargin,
429: },
430: {
431: .name = "passout",
432: .argname = "source",
433: .desc = "Private key output password source",
434: .type = OPTION_ARG,
435: .opt.arg = &req_config.passargout,
436: },
437: {
438: .name = "pkeyopt",
439: .argname = "opt:val",
440: .desc = "Set the public key algorithm option opt to val",
441: .type = OPTION_ARG_FUNC,
442: .opt.argfunc = req_opt_pkeyopt,
443: },
444: {
445: .name = "pubkey",
446: .desc = "Output the public key",
447: .type = OPTION_FLAG,
448: .opt.flag = &req_config.pubkey,
449: },
450: {
451: .name = "reqexts",
452: .argname = "section",
453: .desc = "Config section to use for request extensions",
454: .type = OPTION_ARG,
455: .opt.arg = &req_config.req_exts,
456: },
457: {
458: .name = "reqopt",
459: .argname = "option",
460: .desc = "Request text options",
461: .type = OPTION_ARG_FUNC,
462: .opt.argfunc = req_opt_reqopt,
463: },
464: {
465: .name = "set_serial",
466: .argname = "serial",
467: .desc = "Serial number to use for generated certificate",
468: .type = OPTION_ARG_FUNC,
469: .opt.argfunc = req_opt_set_serial,
470: },
471: {
472: .name = "sigopt",
473: .argname = "name:val",
474: .desc = "Signature options",
475: .type = OPTION_ARG_FUNC,
476: .opt.argfunc = req_opt_sigopt,
477: },
478: {
479: .name = "subj",
480: .argname = "name",
481: .desc = "Set or modify the request subject",
482: .type = OPTION_ARG,
483: .opt.arg = &req_config.subj,
484: },
485: {
486: .name = "subject",
487: .desc = "Output the subject of the request",
488: .type = OPTION_FLAG,
489: .opt.flag = &req_config.subject,
490: },
491: {
492: .name = "text",
493: .desc = "Print request in text form",
494: .type = OPTION_FLAG,
495: .opt.flag = &req_config.text,
496: },
497: {
498: .name = "utf8",
499: .desc = "Input characters are in UTF-8 (default ASCII)",
500: .type = OPTION_FUNC,
501: .opt.func = req_opt_utf8,
502: },
503: {
504: .name = "verbose",
505: .desc = "Verbose",
506: .type = OPTION_FLAG,
507: .opt.flag = &req_config.verbose,
508: },
509: {
510: .name = "verify",
511: .desc = "Verify signature on request",
512: .type = OPTION_FLAG,
513: .opt.flag = &req_config.verify,
514: },
515: {
516: .name = "x509",
517: .desc = "Output an X.509 structure instead of a certificate request",
518: .type = OPTION_FLAG,
519: .opt.flag = &req_config.x509,
520: },
521: {
522: .name = NULL,
523: .desc = "",
524: .type = OPTION_ARGV_FUNC,
525: .opt.argvfunc = req_opt_digest,
526: },
527: { NULL },
528: };
529:
530: static void
531: req_usage(void)
532: {
533: fprintf(stderr,
1.21 tb 534: "usage: req [-addext ext] [-batch] [-config file]\n"
1.19 jsing 535: " [-days n] [-extensions section] [-in file]\n"
536: " [-inform der | pem] [-key keyfile] [-keyform der | pem]\n"
537: " [-keyout file] [-md4 | -md5 | -sha1] [-modulus]\n"
538: " [-multivalue-rdn] [-nameopt option] [-new] [-newhdr]\n"
1.21 tb 539: " [-newkey arg] [-nodes] [-noout]\n"
1.19 jsing 540: " [-out file] [-outform der | pem] [-passin arg]\n"
541: " [-passout arg] [-pkeyopt opt:value] [-pubkey]\n"
542: " [-reqexts section] [-reqopt option] [-set_serial n]\n"
543: " [-sigopt nm:v] [-subj arg] [-subject] [-text] [-utf8]\n"
544: " [-verbose] [-verify] [-x509]\n\n");
545:
546: options_usage(req_options);
547: fprintf(stderr, "\n");
548: }
1.1 jsing 549:
550: int
551: req_main(int argc, char **argv)
552: {
1.19 jsing 553: int ex = 1;
1.1 jsing 554: X509 *x509ss = NULL;
555: X509_REQ *req = NULL;
556: EVP_PKEY_CTX *genctx = NULL;
557: char *keyalgstr = NULL;
1.19 jsing 558: const EVP_CIPHER *cipher = NULL;
1.1 jsing 559: EVP_PKEY *pkey = NULL;
1.19 jsing 560: int i = 0, pkey_type = -1;
1.1 jsing 561: BIO *in = NULL, *out = NULL;
562: char *passin = NULL, *passout = NULL;
1.19 jsing 563: const EVP_MD *md_alg = NULL;
1.1 jsing 564: char *p;
1.10 doug 565:
566: if (single_execution) {
1.14 deraadt 567: if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
1.10 doug 568: perror("pledge");
1.12 doug 569: exit(1);
570: }
1.10 doug 571: }
1.1 jsing 572:
1.19 jsing 573: memset(&req_config, 0, sizeof(req_config));
574:
575: req_config.chtype = MBSTRING_ASC;
576: req_config.days = 30;
577: req_config.digest = EVP_sha256();
578: req_config.newkey = -1;
579: req_config.informat = FORMAT_PEM;
580: req_config.keyform = FORMAT_PEM;
581: req_config.outformat = FORMAT_PEM;
582:
583: if (options_parse(argc, argv, req_options, NULL, NULL) != 0) {
584: req_usage();
585: return (1);
586: }
587:
1.1 jsing 588: req_conf = NULL;
1.3 sthen 589: cipher = EVP_aes_256_cbc();
1.2 jsing 590:
1.19 jsing 591: if (!app_passwd(bio_err, req_config.passargin, req_config.passargout, &passin, &passout)) {
1.1 jsing 592: BIO_printf(bio_err, "Error getting passwords\n");
593: goto end;
594: }
1.19 jsing 595: if (req_config.template != NULL) {
1.1 jsing 596: long errline = -1;
597:
1.19 jsing 598: if (req_config.verbose)
599: BIO_printf(bio_err, "Using configuration from %s\n", req_config.template);
1.18 inoguchi 600: if ((req_conf = NCONF_new(NULL)) == NULL)
601: goto end;
1.19 jsing 602: if(!NCONF_load(req_conf, req_config.template, &errline)) {
603: BIO_printf(bio_err, "error on line %ld of %s\n", errline, req_config.template);
1.1 jsing 604: goto end;
605: }
606: } else {
607: req_conf = config;
608:
609: if (req_conf == NULL) {
610: BIO_printf(bio_err, "Unable to load config info from %s\n", default_config_file);
1.19 jsing 611: if (req_config.newreq)
1.1 jsing 612: goto end;
1.19 jsing 613: } else if (req_config.verbose)
1.1 jsing 614: BIO_printf(bio_err, "Using configuration from %s\n",
615: default_config_file);
616: }
617:
1.19 jsing 618: if (req_config.addext_bio != NULL) {
1.17 inoguchi 619: long errline = -1;
1.19 jsing 620: if (req_config.verbose)
1.17 inoguchi 621: BIO_printf(bio_err,
622: "Using additional configuration from command line\n");
1.18 inoguchi 623: if ((addext_conf = NCONF_new(NULL)) == NULL)
624: goto end;
1.19 jsing 625: if (!NCONF_load_bio(addext_conf, req_config.addext_bio, &errline)) {
1.17 inoguchi 626: BIO_printf(bio_err,
627: "req: Error on line %ld of config input\n",
628: errline);
629: goto end;
630: }
631: }
632:
1.1 jsing 633: if (req_conf != NULL) {
634: if (!load_config(bio_err, req_conf))
635: goto end;
636: p = NCONF_get_string(req_conf, NULL, "oid_file");
637: if (p == NULL)
638: ERR_clear_error();
639: if (p != NULL) {
640: BIO *oid_bio;
641:
642: oid_bio = BIO_new_file(p, "r");
643: if (oid_bio == NULL) {
644: /*
645: BIO_printf(bio_err,"problems opening %s for extra oid's\n",p);
646: ERR_print_errors(bio_err);
647: */
648: } else {
649: OBJ_create_objects(oid_bio);
650: BIO_free(oid_bio);
651: }
652: }
653: }
654: if (!add_oid_section(bio_err, req_conf))
655: goto end;
656:
657: if (md_alg == NULL) {
658: p = NCONF_get_string(req_conf, SECTION, "default_md");
659: if (p == NULL)
660: ERR_clear_error();
661: if (p != NULL) {
662: if ((md_alg = EVP_get_digestbyname(p)) != NULL)
1.19 jsing 663: req_config.digest = md_alg;
1.1 jsing 664: }
665: }
1.19 jsing 666: if (!req_config.extensions) {
667: req_config.extensions = NCONF_get_string(req_conf, SECTION, V3_EXTENSIONS);
668: if (!req_config.extensions)
1.1 jsing 669: ERR_clear_error();
670: }
1.19 jsing 671: if (req_config.extensions) {
1.1 jsing 672: /* Check syntax of file */
673: X509V3_CTX ctx;
674: X509V3_set_ctx_test(&ctx);
675: X509V3_set_nconf(&ctx, req_conf);
1.19 jsing 676: if (!X509V3_EXT_add_nconf(req_conf, &ctx, req_config.extensions, NULL)) {
1.1 jsing 677: BIO_printf(bio_err,
1.19 jsing 678: "Error Loading extension section %s\n", req_config.extensions);
1.1 jsing 679: goto end;
680: }
681: }
1.17 inoguchi 682: if (addext_conf != NULL) {
683: /* Check syntax of command line extensions */
684: X509V3_CTX ctx;
685: X509V3_set_ctx_test(&ctx);
686: X509V3_set_nconf(&ctx, addext_conf);
687: if (!X509V3_EXT_add_nconf(addext_conf, &ctx, "default", NULL)) {
688: BIO_printf(bio_err,
689: "Error Loading command line extensions\n");
690: goto end;
691: }
692: }
1.1 jsing 693: if (!passin) {
694: passin = NCONF_get_string(req_conf, SECTION, "input_password");
695: if (!passin)
696: ERR_clear_error();
697: }
698: if (!passout) {
699: passout = NCONF_get_string(req_conf, SECTION, "output_password");
700: if (!passout)
701: ERR_clear_error();
702: }
703: p = NCONF_get_string(req_conf, SECTION, STRING_MASK);
704: if (!p)
705: ERR_clear_error();
706:
707: if (p && !ASN1_STRING_set_default_mask_asc(p)) {
708: BIO_printf(bio_err, "Invalid global string mask setting %s\n", p);
709: goto end;
710: }
1.19 jsing 711: if (req_config.chtype != MBSTRING_UTF8) {
1.1 jsing 712: p = NCONF_get_string(req_conf, SECTION, UTF8_IN);
713: if (!p)
714: ERR_clear_error();
715: else if (!strcmp(p, "yes"))
1.19 jsing 716: req_config.chtype = MBSTRING_UTF8;
1.1 jsing 717: }
1.19 jsing 718: if (!req_config.req_exts) {
719: req_config.req_exts = NCONF_get_string(req_conf, SECTION, REQ_EXTENSIONS);
720: if (!req_config.req_exts)
1.1 jsing 721: ERR_clear_error();
722: }
1.19 jsing 723: if (req_config.req_exts) {
1.1 jsing 724: /* Check syntax of file */
725: X509V3_CTX ctx;
726: X509V3_set_ctx_test(&ctx);
727: X509V3_set_nconf(&ctx, req_conf);
1.19 jsing 728: if (!X509V3_EXT_add_nconf(req_conf, &ctx, req_config.req_exts, NULL)) {
1.1 jsing 729: BIO_printf(bio_err,
730: "Error Loading request extension section %s\n",
1.19 jsing 731: req_config.req_exts);
1.1 jsing 732: goto end;
733: }
734: }
735: in = BIO_new(BIO_s_file());
736: out = BIO_new(BIO_s_file());
737: if ((in == NULL) || (out == NULL))
738: goto end;
739:
1.19 jsing 740: if (req_config.keyfile != NULL) {
741: pkey = load_key(bio_err, req_config.keyfile, req_config.keyform, 0, passin,
1.1 jsing 742: "Private Key");
743: if (!pkey) {
744: /*
745: * load_key() has already printed an appropriate
746: * message
747: */
748: goto end;
749: }
750: }
1.19 jsing 751: if (req_config.newreq && (pkey == NULL)) {
752: if (!NCONF_get_number(req_conf, SECTION, BITS, &req_config.newkey)) {
753: req_config.newkey = DEFAULT_KEY_LENGTH;
1.1 jsing 754: }
1.19 jsing 755: if (req_config.keyalg) {
756: genctx = set_keygen_ctx(bio_err, req_config.keyalg, &pkey_type, &req_config.newkey,
1.7 bcook 757: &keyalgstr);
1.1 jsing 758: if (!genctx)
759: goto end;
760: }
1.19 jsing 761: if (req_config.newkey < MIN_KEY_LENGTH && (pkey_type == EVP_PKEY_RSA || pkey_type == EVP_PKEY_DSA)) {
1.1 jsing 762: BIO_printf(bio_err, "private key length is too short,\n");
1.19 jsing 763: BIO_printf(bio_err, "it needs to be at least %d bits, not %ld\n", MIN_KEY_LENGTH, req_config.newkey);
1.1 jsing 764: goto end;
765: }
766: if (!genctx) {
1.19 jsing 767: genctx = set_keygen_ctx(bio_err, NULL, &pkey_type, &req_config.newkey,
1.7 bcook 768: &keyalgstr);
1.1 jsing 769: if (!genctx)
770: goto end;
771: }
1.19 jsing 772: if (req_config.pkeyopts) {
1.1 jsing 773: char *genopt;
1.19 jsing 774: for (i = 0; i < sk_OPENSSL_STRING_num(req_config.pkeyopts); i++) {
775: genopt = sk_OPENSSL_STRING_value(req_config.pkeyopts, i);
1.1 jsing 776: if (pkey_ctrl_string(genctx, genopt) <= 0) {
777: BIO_printf(bio_err,
778: "parameter error \"%s\"\n",
779: genopt);
780: ERR_print_errors(bio_err);
781: goto end;
782: }
783: }
784: }
785: BIO_printf(bio_err, "Generating a %ld bit %s private key\n",
1.19 jsing 786: req_config.newkey, keyalgstr);
1.1 jsing 787:
788: EVP_PKEY_CTX_set_cb(genctx, genpkey_cb);
789: EVP_PKEY_CTX_set_app_data(genctx, bio_err);
790:
791: if (EVP_PKEY_keygen(genctx, &pkey) <= 0) {
792: BIO_puts(bio_err, "Error Generating Key\n");
793: goto end;
794: }
795: EVP_PKEY_CTX_free(genctx);
796: genctx = NULL;
797:
1.19 jsing 798: if (req_config.keyout == NULL) {
799: req_config.keyout = NCONF_get_string(req_conf, SECTION, KEYFILE);
800: if (req_config.keyout == NULL)
1.1 jsing 801: ERR_clear_error();
802: }
1.19 jsing 803: if (req_config.keyout == NULL) {
1.1 jsing 804: BIO_printf(bio_err, "writing new private key to stdout\n");
805: BIO_set_fp(out, stdout, BIO_NOCLOSE);
806: } else {
1.19 jsing 807: BIO_printf(bio_err, "writing new private key to '%s'\n", req_config.keyout);
808: if (BIO_write_filename(out, req_config.keyout) <= 0) {
809: perror(req_config.keyout);
1.1 jsing 810: goto end;
811: }
812: }
813:
814: p = NCONF_get_string(req_conf, SECTION, "encrypt_rsa_key");
815: if (p == NULL) {
816: ERR_clear_error();
817: p = NCONF_get_string(req_conf, SECTION, "encrypt_key");
818: if (p == NULL)
819: ERR_clear_error();
820: }
821: if ((p != NULL) && (strcmp(p, "no") == 0))
822: cipher = NULL;
1.19 jsing 823: if (req_config.nodes)
1.1 jsing 824: cipher = NULL;
825:
826: i = 0;
1.15 jsing 827: loop:
1.1 jsing 828: if (!PEM_write_bio_PrivateKey(out, pkey, cipher,
829: NULL, 0, NULL, passout)) {
830: if ((ERR_GET_REASON(ERR_peek_error()) ==
831: PEM_R_PROBLEMS_GETTING_PASSWORD) && (i < 3)) {
832: ERR_clear_error();
833: i++;
834: goto loop;
835: }
836: goto end;
837: }
838: BIO_printf(bio_err, "-----\n");
839: }
1.19 jsing 840: if (!req_config.newreq) {
841: if (req_config.infile == NULL)
1.1 jsing 842: BIO_set_fp(in, stdin, BIO_NOCLOSE);
843: else {
1.19 jsing 844: if (BIO_read_filename(in, req_config.infile) <= 0) {
845: perror(req_config.infile);
1.1 jsing 846: goto end;
847: }
848: }
849:
1.19 jsing 850: if (req_config.informat == FORMAT_ASN1)
1.1 jsing 851: req = d2i_X509_REQ_bio(in, NULL);
1.19 jsing 852: else if (req_config.informat == FORMAT_PEM)
1.1 jsing 853: req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL);
854: else {
855: BIO_printf(bio_err, "bad input format specified for X509 request\n");
856: goto end;
857: }
858: if (req == NULL) {
859: BIO_printf(bio_err, "unable to load X509 request\n");
860: goto end;
861: }
862: }
1.19 jsing 863: if (req_config.newreq || req_config.x509) {
1.1 jsing 864: if (pkey == NULL) {
865: BIO_printf(bio_err, "you need to specify a private key\n");
866: goto end;
867: }
868: if (req == NULL) {
869: req = X509_REQ_new();
870: if (req == NULL) {
871: goto end;
872: }
1.19 jsing 873: i = make_REQ(req, pkey, req_config.subj, req_config.multirdn, !req_config.x509, req_config.chtype);
874: req_config.subj = NULL; /* done processing '-subj' option */
1.1 jsing 875: if (!i) {
876: BIO_printf(bio_err, "problems making Certificate Request\n");
877: goto end;
878: }
879: }
1.19 jsing 880: if (req_config.x509) {
1.1 jsing 881: EVP_PKEY *tmppkey;
1.23 ! tb 882:
1.1 jsing 883: X509V3_CTX ext_ctx;
884: if ((x509ss = X509_new()) == NULL)
885: goto end;
886:
887: /* Set version to V3 */
1.19 jsing 888: if ((req_config.extensions != NULL || addext_conf != NULL) &&
1.17 inoguchi 889: !X509_set_version(x509ss, 2))
1.1 jsing 890: goto end;
1.19 jsing 891: if (req_config.serial) {
892: if (!X509_set_serialNumber(x509ss, req_config.serial))
1.1 jsing 893: goto end;
894: } else {
895: if (!rand_serial(NULL,
896: X509_get_serialNumber(x509ss)))
897: goto end;
898: }
899:
900: if (!X509_set_issuer_name(x509ss, X509_REQ_get_subject_name(req)))
901: goto end;
902: if (!X509_gmtime_adj(X509_get_notBefore(x509ss), 0))
903: goto end;
1.19 jsing 904: if (!X509_time_adj_ex(X509_get_notAfter(x509ss), req_config.days, 0, NULL))
1.1 jsing 905: goto end;
906: if (!X509_set_subject_name(x509ss, X509_REQ_get_subject_name(req)))
907: goto end;
1.23 ! tb 908: if ((tmppkey = X509_REQ_get0_pubkey(req)) == NULL)
! 909: goto end;
! 910: if (!X509_set_pubkey(x509ss, tmppkey))
1.1 jsing 911: goto end;
912:
913: /* Set up V3 context struct */
914:
915: X509V3_set_ctx(&ext_ctx, x509ss, x509ss, NULL, NULL, 0);
916: X509V3_set_nconf(&ext_ctx, req_conf);
917:
918: /* Add extensions */
1.19 jsing 919: if (req_config.extensions && !X509V3_EXT_add_nconf(req_conf,
920: &ext_ctx, req_config.extensions, x509ss)) {
1.1 jsing 921: BIO_printf(bio_err,
922: "Error Loading extension section %s\n",
1.19 jsing 923: req_config.extensions);
1.1 jsing 924: goto end;
925: }
1.17 inoguchi 926: if (addext_conf != NULL &&
927: !X509V3_EXT_add_nconf(addext_conf, &ext_ctx,
928: "default", x509ss)) {
929: BIO_printf(bio_err,
930: "Error Loading command line extensions\n");
931: goto end;
932: }
1.19 jsing 933: i = do_X509_sign(bio_err, x509ss, pkey, req_config.digest, req_config.sigopts);
1.1 jsing 934: if (!i) {
935: ERR_print_errors(bio_err);
936: goto end;
937: }
938: } else {
939: X509V3_CTX ext_ctx;
940:
941: /* Set up V3 context struct */
942:
943: X509V3_set_ctx(&ext_ctx, NULL, NULL, req, NULL, 0);
944: X509V3_set_nconf(&ext_ctx, req_conf);
945:
946: /* Add extensions */
1.19 jsing 947: if (req_config.req_exts && !X509V3_EXT_REQ_add_nconf(req_conf,
948: &ext_ctx, req_config.req_exts, req)) {
1.1 jsing 949: BIO_printf(bio_err,
950: "Error Loading extension section %s\n",
1.19 jsing 951: req_config.req_exts);
1.1 jsing 952: goto end;
953: }
1.17 inoguchi 954: if (addext_conf != NULL &&
955: !X509V3_EXT_REQ_add_nconf(addext_conf, &ext_ctx,
956: "default", req)) {
957: BIO_printf(bio_err,
958: "Error Loading command line extensions\n");
959: goto end;
960: }
1.19 jsing 961: i = do_X509_REQ_sign(bio_err, req, pkey, req_config.digest, req_config.sigopts);
1.1 jsing 962: if (!i) {
963: ERR_print_errors(bio_err);
964: goto end;
965: }
966: }
967: }
1.19 jsing 968: if (req_config.subj && req_config.x509) {
969: BIO_printf(bio_err, "Cannot modify certificate subject\n");
1.1 jsing 970: goto end;
971: }
1.19 jsing 972: if (req_config.subj && !req_config.x509) {
973: if (req_config.verbose) {
1.1 jsing 974: BIO_printf(bio_err, "Modifying Request's Subject\n");
1.19 jsing 975: print_name(bio_err, "old subject=", X509_REQ_get_subject_name(req), req_config.nmflag);
1.1 jsing 976: }
1.19 jsing 977: if (build_subject(req, req_config.subj, req_config.chtype, req_config.multirdn) == 0) {
1.1 jsing 978: BIO_printf(bio_err, "ERROR: cannot modify subject\n");
979: ex = 1;
980: goto end;
981: }
982:
1.19 jsing 983: if (req_config.verbose) {
984: print_name(bio_err, "new subject=", X509_REQ_get_subject_name(req), req_config.nmflag);
1.1 jsing 985: }
986: }
1.19 jsing 987: if (req_config.verify && !req_config.x509) {
1.23 ! tb 988: EVP_PKEY *pubkey = pkey;
1.1 jsing 989:
1.23 ! tb 990: if (pubkey == NULL)
! 991: pubkey = X509_REQ_get0_pubkey(req);
! 992: if (pubkey == NULL)
! 993: goto end;
! 994: i = X509_REQ_verify(req, pubkey);
1.1 jsing 995: if (i < 0) {
996: goto end;
997: } else if (i == 0) {
998: BIO_printf(bio_err, "verify failure\n");
999: ERR_print_errors(bio_err);
1000: } else /* if (i > 0) */
1001: BIO_printf(bio_err, "verify OK\n");
1002: }
1.19 jsing 1003: if (req_config.noout && !req_config.text && !req_config.modulus && !req_config.subject && !req_config.pubkey) {
1.1 jsing 1004: ex = 0;
1005: goto end;
1006: }
1.19 jsing 1007: if (req_config.outfile == NULL) {
1.1 jsing 1008: BIO_set_fp(out, stdout, BIO_NOCLOSE);
1009: } else {
1.19 jsing 1010: if ((req_config.keyout != NULL) && (strcmp(req_config.outfile, req_config.keyout) == 0))
1011: i = (int) BIO_append_filename(out, req_config.outfile);
1.1 jsing 1012: else
1.19 jsing 1013: i = (int) BIO_write_filename(out, req_config.outfile);
1.1 jsing 1014: if (!i) {
1.19 jsing 1015: perror(req_config.outfile);
1.1 jsing 1016: goto end;
1017: }
1018: }
1019:
1.19 jsing 1020: if (req_config.pubkey) {
1.1 jsing 1021: EVP_PKEY *tpubkey;
1.23 ! tb 1022:
! 1023: if ((tpubkey = X509_REQ_get0_pubkey(req)) == NULL) {
1.1 jsing 1024: BIO_printf(bio_err, "Error getting public key\n");
1025: ERR_print_errors(bio_err);
1026: goto end;
1027: }
1028: PEM_write_bio_PUBKEY(out, tpubkey);
1029: }
1.19 jsing 1030: if (req_config.text) {
1031: if (req_config.x509)
1032: X509_print_ex(out, x509ss, req_config.nmflag, req_config.reqflag);
1.1 jsing 1033: else
1.19 jsing 1034: X509_REQ_print_ex(out, req, req_config.nmflag, req_config.reqflag);
1.1 jsing 1035: }
1.19 jsing 1036: if (req_config.subject) {
1037: if (req_config.x509)
1038: print_name(out, "subject=", X509_get_subject_name(x509ss), req_config.nmflag);
1.1 jsing 1039: else
1.19 jsing 1040: print_name(out, "subject=", X509_REQ_get_subject_name(req), req_config.nmflag);
1.1 jsing 1041: }
1.19 jsing 1042: if (req_config.modulus) {
1.1 jsing 1043: EVP_PKEY *tpubkey;
1044:
1.19 jsing 1045: if (req_config.x509)
1.22 tb 1046: tpubkey = X509_get0_pubkey(x509ss);
1.1 jsing 1047: else
1.22 tb 1048: tpubkey = X509_REQ_get0_pubkey(req);
1.1 jsing 1049: if (tpubkey == NULL) {
1050: fprintf(stdout, "Modulus=unavailable\n");
1051: goto end;
1052: }
1053: fprintf(stdout, "Modulus=");
1.22 tb 1054: if (EVP_PKEY_base_id(tpubkey) == EVP_PKEY_RSA) {
1055: const BIGNUM *n = NULL;
1056:
1057: RSA_get0_key(EVP_PKEY_get0_RSA(tpubkey), &n, NULL, NULL);
1058:
1059: BN_print(out, n);
1060: } else
1.1 jsing 1061: fprintf(stdout, "Wrong Algorithm type");
1062: fprintf(stdout, "\n");
1063: }
1.19 jsing 1064: if (!req_config.noout && !req_config.x509) {
1065: if (req_config.outformat == FORMAT_ASN1)
1.1 jsing 1066: i = i2d_X509_REQ_bio(out, req);
1.19 jsing 1067: else if (req_config.outformat == FORMAT_PEM) {
1068: if (req_config.newhdr)
1.1 jsing 1069: i = PEM_write_bio_X509_REQ_NEW(out, req);
1070: else
1071: i = PEM_write_bio_X509_REQ(out, req);
1072: } else {
1073: BIO_printf(bio_err, "bad output format specified for outfile\n");
1074: goto end;
1075: }
1076: if (!i) {
1077: BIO_printf(bio_err, "unable to write X509 request\n");
1078: goto end;
1079: }
1080: }
1.19 jsing 1081: if (!req_config.noout && req_config.x509 && (x509ss != NULL)) {
1082: if (req_config.outformat == FORMAT_ASN1)
1.1 jsing 1083: i = i2d_X509_bio(out, x509ss);
1.19 jsing 1084: else if (req_config.outformat == FORMAT_PEM)
1.1 jsing 1085: i = PEM_write_bio_X509(out, x509ss);
1086: else {
1087: BIO_printf(bio_err, "bad output format specified for outfile\n");
1088: goto end;
1089: }
1090: if (!i) {
1091: BIO_printf(bio_err, "unable to write X509 certificate\n");
1092: goto end;
1093: }
1094: }
1095: ex = 0;
1.15 jsing 1096: end:
1.1 jsing 1097: if (ex) {
1098: ERR_print_errors(bio_err);
1099: }
1100: if ((req_conf != NULL) && (req_conf != config))
1101: NCONF_free(req_conf);
1.17 inoguchi 1102: NCONF_free(addext_conf);
1.19 jsing 1103: BIO_free(req_config.addext_bio);
1.1 jsing 1104: BIO_free(in);
1105: BIO_free_all(out);
1106: EVP_PKEY_free(pkey);
1107: if (genctx)
1108: EVP_PKEY_CTX_free(genctx);
1.19 jsing 1109: if (req_config.pkeyopts)
1110: sk_OPENSSL_STRING_free(req_config.pkeyopts);
1111: if (req_config.sigopts)
1112: sk_OPENSSL_STRING_free(req_config.sigopts);
1113: lh_OPENSSL_STRING_doall(req_config.addexts, (LHASH_DOALL_FN_TYPE)exts_cleanup);
1114: lh_OPENSSL_STRING_free(req_config.addexts);
1.1 jsing 1115: free(keyalgstr);
1116: X509_REQ_free(req);
1117: X509_free(x509ss);
1.19 jsing 1118: ASN1_INTEGER_free(req_config.serial);
1119: if (req_config.passargin && passin)
1.1 jsing 1120: free(passin);
1.19 jsing 1121: if (req_config.passargout && passout)
1.1 jsing 1122: free(passout);
1123: OBJ_cleanup();
1124:
1125: return (ex);
1126: }
1127:
1128: static int
1129: make_REQ(X509_REQ * req, EVP_PKEY * pkey, char *subj, int multirdn,
1130: int attribs, unsigned long chtype)
1131: {
1132: int ret = 0, i;
1133: char no_prompt = 0;
1134: STACK_OF(CONF_VALUE) * dn_sk, *attr_sk = NULL;
1135: char *tmp, *dn_sect, *attr_sect;
1136:
1137: tmp = NCONF_get_string(req_conf, SECTION, PROMPT);
1138: if (tmp == NULL)
1139: ERR_clear_error();
1140: if ((tmp != NULL) && !strcmp(tmp, "no"))
1141: no_prompt = 1;
1142:
1143: dn_sect = NCONF_get_string(req_conf, SECTION, DISTINGUISHED_NAME);
1144: if (dn_sect == NULL) {
1145: BIO_printf(bio_err, "unable to find '%s' in config\n",
1146: DISTINGUISHED_NAME);
1147: goto err;
1148: }
1149: dn_sk = NCONF_get_section(req_conf, dn_sect);
1150: if (dn_sk == NULL) {
1151: BIO_printf(bio_err, "unable to get '%s' section\n", dn_sect);
1152: goto err;
1153: }
1154: attr_sect = NCONF_get_string(req_conf, SECTION, ATTRIBUTES);
1155: if (attr_sect == NULL) {
1156: ERR_clear_error();
1157: attr_sk = NULL;
1158: } else {
1159: attr_sk = NCONF_get_section(req_conf, attr_sect);
1160: if (attr_sk == NULL) {
1161: BIO_printf(bio_err, "unable to get '%s' section\n", attr_sect);
1162: goto err;
1163: }
1164: }
1165:
1166: /* setup version number */
1167: if (!X509_REQ_set_version(req, 0L))
1168: goto err; /* version 1 */
1169:
1170: if (no_prompt)
1171: i = auto_info(req, dn_sk, attr_sk, attribs, chtype);
1172: else {
1173: if (subj)
1174: i = build_subject(req, subj, chtype, multirdn);
1175: else
1176: i = prompt_info(req, dn_sk, dn_sect, attr_sk, attr_sect, attribs, chtype);
1177: }
1178: if (!i)
1179: goto err;
1180:
1181: if (!X509_REQ_set_pubkey(req, pkey))
1182: goto err;
1183:
1184: ret = 1;
1.15 jsing 1185: err:
1.1 jsing 1186: return (ret);
1187: }
1188:
1189: /*
1190: * subject is expected to be in the format /type0=value0/type1=value1/type2=...
1191: * where characters may be escaped by \
1192: */
1193: static int
1194: build_subject(X509_REQ * req, char *subject, unsigned long chtype, int multirdn)
1195: {
1196: X509_NAME *n;
1197:
1198: if (!(n = parse_name(subject, chtype, multirdn)))
1199: return 0;
1200:
1201: if (!X509_REQ_set_subject_name(req, n)) {
1202: X509_NAME_free(n);
1203: return 0;
1204: }
1205: X509_NAME_free(n);
1206: return 1;
1207: }
1208:
1209:
1210: static int
1211: prompt_info(X509_REQ * req,
1212: STACK_OF(CONF_VALUE) * dn_sk, char *dn_sect,
1213: STACK_OF(CONF_VALUE) * attr_sk, char *attr_sect, int attribs,
1214: unsigned long chtype)
1215: {
1216: int i;
1217: char *p, *q;
1218: char buf[100];
1219: int nid, mval;
1220: long n_min, n_max;
1221: char *type, *value;
1222: const char *def;
1223: CONF_VALUE *v;
1224: X509_NAME *subj;
1225: subj = X509_REQ_get_subject_name(req);
1226:
1.19 jsing 1227: if (!req_config.batch) {
1.1 jsing 1228: BIO_printf(bio_err, "You are about to be asked to enter information that will be incorporated\n");
1229: BIO_printf(bio_err, "into your certificate request.\n");
1230: BIO_printf(bio_err, "What you are about to enter is what is called a Distinguished Name or a DN.\n");
1231: BIO_printf(bio_err, "There are quite a few fields but you can leave some blank\n");
1232: BIO_printf(bio_err, "For some fields there will be a default value,\n");
1233: BIO_printf(bio_err, "If you enter '.', the field will be left blank.\n");
1234: BIO_printf(bio_err, "-----\n");
1235: }
1236: if (sk_CONF_VALUE_num(dn_sk)) {
1237: i = -1;
1.15 jsing 1238: start: for (;;) {
1.1 jsing 1239: int ret;
1240: i++;
1241: if (sk_CONF_VALUE_num(dn_sk) <= i)
1242: break;
1243:
1244: v = sk_CONF_VALUE_value(dn_sk, i);
1245: p = q = NULL;
1246: type = v->name;
1247: if (!check_end(type, "_min") || !check_end(type, "_max") ||
1248: !check_end(type, "_default") ||
1249: !check_end(type, "_value"))
1250: continue;
1251: /*
1252: * Skip past any leading X. X: X, etc to allow for
1253: * multiple instances
1254: */
1255: for (p = v->name; *p; p++)
1256: if ((*p == ':') || (*p == ',') ||
1257: (*p == '.')) {
1258: p++;
1259: if (*p)
1260: type = p;
1261: break;
1262: }
1263: if (*type == '+') {
1264: mval = -1;
1265: type++;
1266: } else
1267: mval = 0;
1268: /* If OBJ not recognised ignore it */
1269: if ((nid = OBJ_txt2nid(type)) == NID_undef)
1270: goto start;
1271: ret = snprintf(buf, sizeof buf, "%s_default", v->name);
1.16 deraadt 1272: if (ret < 0 || ret >= sizeof(buf)) {
1.1 jsing 1273: BIO_printf(bio_err, "Name '%s' too long for default\n",
1274: v->name);
1275: return 0;
1276: }
1277: if ((def = NCONF_get_string(req_conf, dn_sect, buf)) == NULL) {
1278: ERR_clear_error();
1279: def = "";
1280: }
1281: ret = snprintf(buf, sizeof buf, "%s_value", v->name);
1.16 deraadt 1282: if (ret < 0 || ret >= sizeof(buf)) {
1.1 jsing 1283: BIO_printf(bio_err, "Name '%s' too long for value\n",
1284: v->name);
1285: return 0;
1286: }
1287: if ((value = NCONF_get_string(req_conf, dn_sect, buf)) == NULL) {
1288: ERR_clear_error();
1289: value = NULL;
1290: }
1291: ret = snprintf(buf, sizeof buf, "%s_min", v->name);
1.16 deraadt 1292: if (ret < 0 || ret >= sizeof(buf)) {
1.1 jsing 1293: BIO_printf(bio_err, "Name '%s' too long for min\n",
1294: v->name);
1295: return 0;
1296: }
1297: if (!NCONF_get_number(req_conf, dn_sect, buf, &n_min)) {
1298: ERR_clear_error();
1299: n_min = -1;
1300: }
1301: ret = snprintf(buf, sizeof buf, "%s_max", v->name);
1.16 deraadt 1302: if (ret < 0 || ret >= sizeof(buf)) {
1.1 jsing 1303: BIO_printf(bio_err, "Name '%s' too long for max\n",
1304: v->name);
1305: return 0;
1306: }
1307: if (!NCONF_get_number(req_conf, dn_sect, buf, &n_max)) {
1308: ERR_clear_error();
1309: n_max = -1;
1310: }
1311: if (!add_DN_object(subj, v->value, def, value, nid,
1312: n_min, n_max, chtype, mval))
1313: return 0;
1314: }
1315: if (X509_NAME_entry_count(subj) == 0) {
1316: BIO_printf(bio_err, "error, no objects specified in config file\n");
1317: return 0;
1318: }
1319: if (attribs) {
1320: if ((attr_sk != NULL) && (sk_CONF_VALUE_num(attr_sk) > 0) &&
1.19 jsing 1321: (!req_config.batch)) {
1.1 jsing 1322: BIO_printf(bio_err,
1323: "\nPlease enter the following 'extra' attributes\n");
1324: BIO_printf(bio_err,
1325: "to be sent with your certificate request\n");
1326: }
1327: i = -1;
1328: start2: for (;;) {
1329: int ret;
1330: i++;
1331: if ((attr_sk == NULL) ||
1332: (sk_CONF_VALUE_num(attr_sk) <= i))
1333: break;
1334:
1335: v = sk_CONF_VALUE_value(attr_sk, i);
1336: type = v->name;
1337: if ((nid = OBJ_txt2nid(type)) == NID_undef)
1338: goto start2;
1339: ret = snprintf(buf, sizeof buf, "%s_default", type);
1.16 deraadt 1340: if (ret < 0 || ret >= sizeof(buf)) {
1.1 jsing 1341: BIO_printf(bio_err, "Name '%s' too long for default\n",
1342: v->name);
1343: return 0;
1344: }
1345: if ((def = NCONF_get_string(req_conf, attr_sect, buf))
1346: == NULL) {
1347: ERR_clear_error();
1348: def = "";
1349: }
1350: ret = snprintf(buf, sizeof buf, "%s_value", type);
1.16 deraadt 1351: if (ret < 0 || ret >= sizeof(buf)) {
1.1 jsing 1352: BIO_printf(bio_err, "Name '%s' too long for value\n",
1353: v->name);
1354: return 0;
1355: }
1356: if ((value = NCONF_get_string(req_conf, attr_sect, buf))
1357: == NULL) {
1358: ERR_clear_error();
1359: value = NULL;
1360: }
1361: ret = snprintf(buf, sizeof buf, "%s_min", type);
1.16 deraadt 1362: if (ret < 0 || ret >= sizeof(buf)) {
1.1 jsing 1363: BIO_printf(bio_err, "Name '%s' too long for min\n",
1364: v->name);
1365: return 0;
1366: }
1367: if (!NCONF_get_number(req_conf, attr_sect, buf, &n_min)) {
1368: ERR_clear_error();
1369: n_min = -1;
1370: }
1371: ret = snprintf(buf, sizeof buf, "%s_max", type);
1.16 deraadt 1372: if (ret < 0 || ret >= sizeof(buf)) {
1.1 jsing 1373: BIO_printf(bio_err, "Name '%s' too long for max\n",
1374: v->name);
1375: return 0;
1376: }
1377: if (!NCONF_get_number(req_conf, attr_sect, buf, &n_max)) {
1378: ERR_clear_error();
1379: n_max = -1;
1380: }
1381: if (!add_attribute_object(req,
1382: v->value, def, value, nid, n_min, n_max, chtype))
1383: return 0;
1384: }
1385: }
1386: } else {
1387: BIO_printf(bio_err, "No template, please set one up.\n");
1388: return 0;
1389: }
1390:
1391: return 1;
1392:
1393: }
1394:
1395: static int
1396: auto_info(X509_REQ * req, STACK_OF(CONF_VALUE) * dn_sk,
1397: STACK_OF(CONF_VALUE) * attr_sk, int attribs, unsigned long chtype)
1398: {
1399: int i;
1400: char *p, *q;
1401: char *type;
1402: CONF_VALUE *v;
1403: X509_NAME *subj;
1404:
1405: subj = X509_REQ_get_subject_name(req);
1406:
1407: for (i = 0; i < sk_CONF_VALUE_num(dn_sk); i++) {
1408: int mval;
1409: v = sk_CONF_VALUE_value(dn_sk, i);
1410: p = q = NULL;
1411: type = v->name;
1412: /*
1413: * Skip past any leading X. X: X, etc to allow for multiple
1414: * instances
1415: */
1416: for (p = v->name; *p; p++)
1417: if ((*p == ':') || (*p == ',') || (*p == '.')) {
1418: p++;
1419: if (*p)
1420: type = p;
1421: break;
1422: }
1423: if (*p == '+') {
1424: p++;
1425: mval = -1;
1426: } else
1427: mval = 0;
1428: if (!X509_NAME_add_entry_by_txt(subj, type, chtype,
1429: (unsigned char *) v->value, -1, -1, mval))
1430: return 0;
1431:
1432: }
1433:
1434: if (!X509_NAME_entry_count(subj)) {
1435: BIO_printf(bio_err, "error, no objects specified in config file\n");
1436: return 0;
1437: }
1438: if (attribs) {
1439: for (i = 0; i < sk_CONF_VALUE_num(attr_sk); i++) {
1440: v = sk_CONF_VALUE_value(attr_sk, i);
1441: if (!X509_REQ_add1_attr_by_txt(req, v->name, chtype,
1442: (unsigned char *) v->value, -1))
1443: return 0;
1444: }
1445: }
1446: return 1;
1447: }
1448:
1449:
1450: static int
1451: add_DN_object(X509_NAME * n, char *text, const char *def, char *value,
1452: int nid, int n_min, int n_max, unsigned long chtype, int mval)
1453: {
1454: int i, ret = 0;
1455: char buf[1024];
1.15 jsing 1456: start:
1.19 jsing 1457: if (!req_config.batch)
1.1 jsing 1458: BIO_printf(bio_err, "%s [%s]:", text, def);
1459: (void) BIO_flush(bio_err);
1460: if (value != NULL) {
1461: strlcpy(buf, value, sizeof buf);
1462: strlcat(buf, "\n", sizeof buf);
1463: BIO_printf(bio_err, "%s\n", value);
1464: } else {
1465: buf[0] = '\0';
1.19 jsing 1466: if (!req_config.batch) {
1.1 jsing 1467: if (!fgets(buf, sizeof buf, stdin))
1468: return 0;
1469: } else {
1470: buf[0] = '\n';
1471: buf[1] = '\0';
1472: }
1473: }
1474:
1475: if (buf[0] == '\0')
1476: return (0);
1477: else if (buf[0] == '\n') {
1478: if ((def == NULL) || (def[0] == '\0'))
1479: return (1);
1480: strlcpy(buf, def, sizeof buf);
1481: strlcat(buf, "\n", sizeof buf);
1482: } else if ((buf[0] == '.') && (buf[1] == '\n'))
1483: return (1);
1484:
1485: i = strlen(buf);
1486: if (buf[i - 1] != '\n') {
1487: BIO_printf(bio_err, "weird input :-(\n");
1488: return (0);
1489: }
1490: buf[--i] = '\0';
1491: if (!req_check_len(i, n_min, n_max))
1492: goto start;
1493: if (!X509_NAME_add_entry_by_NID(n, nid, chtype,
1494: (unsigned char *) buf, -1, -1, mval))
1495: goto err;
1496: ret = 1;
1.15 jsing 1497: err:
1.1 jsing 1498: return (ret);
1499: }
1500:
1501: static int
1502: add_attribute_object(X509_REQ * req, char *text, const char *def,
1503: char *value, int nid, int n_min,
1504: int n_max, unsigned long chtype)
1505: {
1506: int i;
1507: static char buf[1024];
1508:
1.15 jsing 1509: start:
1.19 jsing 1510: if (!req_config.batch)
1.1 jsing 1511: BIO_printf(bio_err, "%s [%s]:", text, def);
1512: (void) BIO_flush(bio_err);
1513: if (value != NULL) {
1514: strlcpy(buf, value, sizeof buf);
1515: strlcat(buf, "\n", sizeof buf);
1516: BIO_printf(bio_err, "%s\n", value);
1517: } else {
1518: buf[0] = '\0';
1.19 jsing 1519: if (!req_config.batch) {
1.1 jsing 1520: if (!fgets(buf, sizeof buf, stdin))
1521: return 0;
1522: } else {
1523: buf[0] = '\n';
1524: buf[1] = '\0';
1525: }
1526: }
1527:
1528: if (buf[0] == '\0')
1529: return (0);
1530: else if (buf[0] == '\n') {
1531: if ((def == NULL) || (def[0] == '\0'))
1532: return (1);
1533: strlcpy(buf, def, sizeof buf);
1534: strlcat(buf, "\n", sizeof buf);
1535: } else if ((buf[0] == '.') && (buf[1] == '\n'))
1536: return (1);
1537:
1538: i = strlen(buf);
1539: if (buf[i - 1] != '\n') {
1540: BIO_printf(bio_err, "weird input :-(\n");
1541: return (0);
1542: }
1543: buf[--i] = '\0';
1544: if (!req_check_len(i, n_min, n_max))
1545: goto start;
1546:
1547: if (!X509_REQ_add1_attr_by_NID(req, nid, chtype,
1548: (unsigned char *) buf, -1)) {
1549: BIO_printf(bio_err, "Error adding attribute\n");
1550: ERR_print_errors(bio_err);
1551: goto err;
1552: }
1553: return (1);
1.15 jsing 1554: err:
1.1 jsing 1555: return (0);
1556: }
1557:
1558: static int
1559: req_check_len(int len, int n_min, int n_max)
1560: {
1561: if ((n_min > 0) && (len < n_min)) {
1562: BIO_printf(bio_err, "string is too short, it needs to be at least %d bytes long\n", n_min);
1563: return (0);
1564: }
1565: if ((n_max >= 0) && (len > n_max)) {
1566: BIO_printf(bio_err, "string is too long, it needs to be less than %d bytes long\n", n_max);
1567: return (0);
1568: }
1569: return (1);
1570: }
1571:
1572: /* Check if the end of a string matches 'end' */
1573: static int
1574: check_end(const char *str, const char *end)
1575: {
1576: int elen, slen;
1577: const char *tmp;
1578: elen = strlen(end);
1579: slen = strlen(str);
1580: if (elen > slen)
1581: return 1;
1582: tmp = str + slen - elen;
1583: return strcmp(tmp, end);
1584: }
1585:
1586: static EVP_PKEY_CTX *
1587: set_keygen_ctx(BIO * err, const char *gstr, int *pkey_type,
1.7 bcook 1588: long *pkeylen, char **palgnam)
1.1 jsing 1589: {
1590: EVP_PKEY_CTX *gctx = NULL;
1591: EVP_PKEY *param = NULL;
1592: long keylen = -1;
1593: BIO *pbio = NULL;
1594: const char *paramfile = NULL;
1595: const char *errstr;
1596:
1597: if (gstr == NULL) {
1598: *pkey_type = EVP_PKEY_RSA;
1599: keylen = *pkeylen;
1600: } else if (gstr[0] >= '0' && gstr[0] <= '9') {
1601: *pkey_type = EVP_PKEY_RSA;
1602: keylen = strtonum(gstr, 0, LONG_MAX, &errstr);
1603: if (errstr) {
1604: BIO_printf(err, "bad algorithm %s: %s\n", gstr, errstr);
1605: return NULL;
1606: }
1607: *pkeylen = keylen;
1608: } else if (!strncmp(gstr, "param:", 6))
1609: paramfile = gstr + 6;
1610: else {
1611: const char *p = strchr(gstr, ':');
1612: int len;
1613: const EVP_PKEY_ASN1_METHOD *ameth;
1614:
1615: if (p)
1616: len = p - gstr;
1617: else
1618: len = strlen(gstr);
1619:
1.7 bcook 1620: ameth = EVP_PKEY_asn1_find_str(NULL, gstr, len);
1.1 jsing 1621:
1622: if (!ameth) {
1623: BIO_printf(err, "Unknown algorithm %.*s\n", len, gstr);
1624: return NULL;
1625: }
1626: EVP_PKEY_asn1_get0_info(NULL, pkey_type, NULL, NULL, NULL,
1627: ameth);
1628: if (*pkey_type == EVP_PKEY_RSA) {
1629: if (p) {
1630: keylen = strtonum(p + 1, 0, LONG_MAX, &errstr);
1631: if (errstr) {
1632: BIO_printf(err, "bad algorithm %s: %s\n",
1633: p + 1, errstr);
1634: return NULL;
1635: }
1636: *pkeylen = keylen;
1637: } else
1638: keylen = *pkeylen;
1639: } else if (p)
1640: paramfile = p + 1;
1641: }
1642:
1643: if (paramfile) {
1644: pbio = BIO_new_file(paramfile, "r");
1645: if (!pbio) {
1646: BIO_printf(err, "Can't open parameter file %s\n",
1647: paramfile);
1648: return NULL;
1649: }
1650: param = PEM_read_bio_Parameters(pbio, NULL);
1651:
1652: if (!param) {
1653: X509 *x;
1654: (void) BIO_reset(pbio);
1655: x = PEM_read_bio_X509(pbio, NULL, NULL, NULL);
1656: if (x) {
1657: param = X509_get_pubkey(x);
1658: X509_free(x);
1659: }
1660: }
1661: BIO_free(pbio);
1662:
1663: if (!param) {
1664: BIO_printf(err, "Error reading parameter file %s\n",
1665: paramfile);
1666: return NULL;
1667: }
1668: if (*pkey_type == -1)
1669: *pkey_type = EVP_PKEY_id(param);
1670: else if (*pkey_type != EVP_PKEY_base_id(param)) {
1671: BIO_printf(err, "Key Type does not match parameters\n");
1672: EVP_PKEY_free(param);
1673: return NULL;
1674: }
1675: }
1676: if (palgnam) {
1677: const EVP_PKEY_ASN1_METHOD *ameth;
1678: const char *anam;
1.7 bcook 1679: ameth = EVP_PKEY_asn1_find(NULL, *pkey_type);
1.1 jsing 1680: if (!ameth) {
1681: BIO_puts(err, "Internal error: can't find key algorithm\n");
1682: return NULL;
1683: }
1684: EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, &anam, ameth);
1.4 jsing 1685: *palgnam = strdup(anam);
1.1 jsing 1686: }
1687: if (param) {
1.7 bcook 1688: gctx = EVP_PKEY_CTX_new(param, NULL);
1.1 jsing 1689: *pkeylen = EVP_PKEY_bits(param);
1690: EVP_PKEY_free(param);
1691: } else
1.7 bcook 1692: gctx = EVP_PKEY_CTX_new_id(*pkey_type, NULL);
1.1 jsing 1693:
1694: if (!gctx) {
1695: BIO_puts(err, "Error allocating keygen context\n");
1696: ERR_print_errors(err);
1697: return NULL;
1698: }
1699: if (EVP_PKEY_keygen_init(gctx) <= 0) {
1700: BIO_puts(err, "Error initializing keygen context\n");
1701: ERR_print_errors(err);
1702: return NULL;
1703: }
1704: if ((*pkey_type == EVP_PKEY_RSA) && (keylen != -1)) {
1705: if (EVP_PKEY_CTX_set_rsa_keygen_bits(gctx, keylen) <= 0) {
1706: BIO_puts(err, "Error setting RSA keysize\n");
1707: ERR_print_errors(err);
1708: EVP_PKEY_CTX_free(gctx);
1709: return NULL;
1710: }
1711: }
1712:
1713: return gctx;
1714: }
1715:
1716: static int
1717: genpkey_cb(EVP_PKEY_CTX * ctx)
1718: {
1719: char c = '*';
1720: BIO *b = EVP_PKEY_CTX_get_app_data(ctx);
1721: int p;
1722: p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
1723: if (p == 0)
1724: c = '.';
1725: if (p == 1)
1726: c = '+';
1727: if (p == 2)
1728: c = '*';
1729: if (p == 3)
1730: c = '\n';
1731: BIO_write(b, &c, 1);
1732: (void) BIO_flush(b);
1733: return 1;
1734: }
1735:
1736: static int
1737: do_sign_init(BIO * err, EVP_MD_CTX * ctx, EVP_PKEY * pkey,
1738: const EVP_MD * md, STACK_OF(OPENSSL_STRING) * sigopts)
1739: {
1740: EVP_PKEY_CTX *pkctx = NULL;
1741: int i;
1742: EVP_MD_CTX_init(ctx);
1743: if (!EVP_DigestSignInit(ctx, &pkctx, md, NULL, pkey))
1744: return 0;
1745: for (i = 0; i < sk_OPENSSL_STRING_num(sigopts); i++) {
1746: char *sigopt = sk_OPENSSL_STRING_value(sigopts, i);
1747: if (pkey_ctrl_string(pkctx, sigopt) <= 0) {
1748: BIO_printf(err, "parameter error \"%s\"\n", sigopt);
1749: ERR_print_errors(bio_err);
1750: return 0;
1751: }
1752: }
1753: return 1;
1754: }
1755:
1756: int
1757: do_X509_sign(BIO * err, X509 * x, EVP_PKEY * pkey, const EVP_MD * md,
1758: STACK_OF(OPENSSL_STRING) * sigopts)
1759: {
1.22 tb 1760: EVP_MD_CTX *mctx;
1.1 jsing 1761: int rv;
1.22 tb 1762:
1763: if ((mctx = EVP_MD_CTX_new()) == NULL)
1764: return 0;
1765:
1766: rv = do_sign_init(err, mctx, pkey, md, sigopts);
1.1 jsing 1767: if (rv > 0)
1.22 tb 1768: rv = X509_sign_ctx(x, mctx);
1769:
1770: EVP_MD_CTX_free(mctx);
1771:
1772: return rv > 0;
1.1 jsing 1773: }
1774:
1775:
1776: int
1777: do_X509_REQ_sign(BIO * err, X509_REQ * x, EVP_PKEY * pkey, const EVP_MD * md,
1778: STACK_OF(OPENSSL_STRING) * sigopts)
1779: {
1.22 tb 1780: EVP_MD_CTX *mctx;
1.1 jsing 1781: int rv;
1.22 tb 1782:
1783: if ((mctx = EVP_MD_CTX_new()) == NULL)
1784: return 0;
1785:
1786: rv = do_sign_init(err, mctx, pkey, md, sigopts);
1.1 jsing 1787: if (rv > 0)
1.22 tb 1788: rv = X509_REQ_sign_ctx(x, mctx);
1789:
1790: EVP_MD_CTX_free(mctx);
1791:
1792: return rv > 0;
1.1 jsing 1793: }
1794:
1795:
1796:
1797: int
1798: do_X509_CRL_sign(BIO * err, X509_CRL * x, EVP_PKEY * pkey, const EVP_MD * md,
1799: STACK_OF(OPENSSL_STRING) * sigopts)
1800: {
1801: int rv;
1.22 tb 1802: EVP_MD_CTX *mctx;
1803:
1804: if ((mctx = EVP_MD_CTX_new()) == NULL)
1805: return 0;
1806:
1807: rv = do_sign_init(err, mctx, pkey, md, sigopts);
1.1 jsing 1808: if (rv > 0)
1.22 tb 1809: rv = X509_CRL_sign_ctx(x, mctx);
1810:
1811: EVP_MD_CTX_free(mctx);
1812:
1813: return rv > 0;
1.17 inoguchi 1814: }
1815:
1816: static unsigned long
1817: ext_name_hash(const OPENSSL_STRING *a)
1818: {
1819: return lh_strhash((const char *)a);
1820: }
1821:
1822: static int
1823: ext_name_cmp(const OPENSSL_STRING *a, const OPENSSL_STRING *b)
1824: {
1825: return strcmp((const char *)a, (const char *)b);
1826: }
1827:
1828: static void
1829: exts_cleanup(OPENSSL_STRING *x)
1830: {
1831: free((char *)x);
1832: }
1833:
1834: /*
1835: * Is the |kv| key already duplicated ? This is remarkably tricky to get right.
1836: * Return 0 if unique, -1 on runtime error; 1 if found or a syntax error.
1837: */
1838: static int
1839: duplicated(LHASH_OF(OPENSSL_STRING) *addexts, char *kv)
1840: {
1841: char *p;
1842: size_t off;
1843:
1844: /* Check syntax. */
1845: /* Skip leading whitespace, make a copy. */
1846: while (*kv && isspace(*kv))
1847: if (*++kv == '\0')
1848: return 1;
1849: if ((p = strchr(kv, '=')) == NULL)
1850: return 1;
1851: off = p - kv;
1852: if ((kv = strdup(kv)) == NULL)
1853: return -1;
1854:
1855: /* Skip trailing space before the equal sign. */
1856: for (p = kv + off; p > kv; --p)
1857: if (!isspace(p[-1]))
1858: break;
1859: if (p == kv) {
1860: free(kv);
1861: return 1;
1862: }
1863: *p = '\0';
1864:
1865: /* See if "key" is there by attempting to add it. */
1866: if ((p = (char *)lh_OPENSSL_STRING_insert(addexts, (OPENSSL_STRING*)kv))
1867: != NULL || lh_OPENSSL_STRING_error(addexts)) {
1868: free(p != NULL ? p : kv);
1869: return -1;
1870: }
1871:
1872: return 0;
1.1 jsing 1873: }