Annotation of src/usr.bin/openssl/req.c, Revision 1.24
1.24 ! joshua 1: /* $OpenBSD: req.c,v 1.23 2022/02/03 17:44:04 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:
1.24 ! joshua 566: if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
! 567: perror("pledge");
! 568: exit(1);
1.10 doug 569: }
1.1 jsing 570:
1.19 jsing 571: memset(&req_config, 0, sizeof(req_config));
572:
573: req_config.chtype = MBSTRING_ASC;
574: req_config.days = 30;
575: req_config.digest = EVP_sha256();
576: req_config.newkey = -1;
577: req_config.informat = FORMAT_PEM;
578: req_config.keyform = FORMAT_PEM;
579: req_config.outformat = FORMAT_PEM;
580:
581: if (options_parse(argc, argv, req_options, NULL, NULL) != 0) {
582: req_usage();
583: return (1);
584: }
585:
1.1 jsing 586: req_conf = NULL;
1.3 sthen 587: cipher = EVP_aes_256_cbc();
1.2 jsing 588:
1.19 jsing 589: if (!app_passwd(bio_err, req_config.passargin, req_config.passargout, &passin, &passout)) {
1.1 jsing 590: BIO_printf(bio_err, "Error getting passwords\n");
591: goto end;
592: }
1.19 jsing 593: if (req_config.template != NULL) {
1.1 jsing 594: long errline = -1;
595:
1.19 jsing 596: if (req_config.verbose)
597: BIO_printf(bio_err, "Using configuration from %s\n", req_config.template);
1.18 inoguchi 598: if ((req_conf = NCONF_new(NULL)) == NULL)
599: goto end;
1.19 jsing 600: if(!NCONF_load(req_conf, req_config.template, &errline)) {
601: BIO_printf(bio_err, "error on line %ld of %s\n", errline, req_config.template);
1.1 jsing 602: goto end;
603: }
604: } else {
605: req_conf = config;
606:
607: if (req_conf == NULL) {
608: BIO_printf(bio_err, "Unable to load config info from %s\n", default_config_file);
1.19 jsing 609: if (req_config.newreq)
1.1 jsing 610: goto end;
1.19 jsing 611: } else if (req_config.verbose)
1.1 jsing 612: BIO_printf(bio_err, "Using configuration from %s\n",
613: default_config_file);
614: }
615:
1.19 jsing 616: if (req_config.addext_bio != NULL) {
1.17 inoguchi 617: long errline = -1;
1.19 jsing 618: if (req_config.verbose)
1.17 inoguchi 619: BIO_printf(bio_err,
620: "Using additional configuration from command line\n");
1.18 inoguchi 621: if ((addext_conf = NCONF_new(NULL)) == NULL)
622: goto end;
1.19 jsing 623: if (!NCONF_load_bio(addext_conf, req_config.addext_bio, &errline)) {
1.17 inoguchi 624: BIO_printf(bio_err,
625: "req: Error on line %ld of config input\n",
626: errline);
627: goto end;
628: }
629: }
630:
1.1 jsing 631: if (req_conf != NULL) {
632: if (!load_config(bio_err, req_conf))
633: goto end;
634: p = NCONF_get_string(req_conf, NULL, "oid_file");
635: if (p == NULL)
636: ERR_clear_error();
637: if (p != NULL) {
638: BIO *oid_bio;
639:
640: oid_bio = BIO_new_file(p, "r");
641: if (oid_bio == NULL) {
642: /*
643: BIO_printf(bio_err,"problems opening %s for extra oid's\n",p);
644: ERR_print_errors(bio_err);
645: */
646: } else {
647: OBJ_create_objects(oid_bio);
648: BIO_free(oid_bio);
649: }
650: }
651: }
652: if (!add_oid_section(bio_err, req_conf))
653: goto end;
654:
655: if (md_alg == NULL) {
656: p = NCONF_get_string(req_conf, SECTION, "default_md");
657: if (p == NULL)
658: ERR_clear_error();
659: if (p != NULL) {
660: if ((md_alg = EVP_get_digestbyname(p)) != NULL)
1.19 jsing 661: req_config.digest = md_alg;
1.1 jsing 662: }
663: }
1.19 jsing 664: if (!req_config.extensions) {
665: req_config.extensions = NCONF_get_string(req_conf, SECTION, V3_EXTENSIONS);
666: if (!req_config.extensions)
1.1 jsing 667: ERR_clear_error();
668: }
1.19 jsing 669: if (req_config.extensions) {
1.1 jsing 670: /* Check syntax of file */
671: X509V3_CTX ctx;
672: X509V3_set_ctx_test(&ctx);
673: X509V3_set_nconf(&ctx, req_conf);
1.19 jsing 674: if (!X509V3_EXT_add_nconf(req_conf, &ctx, req_config.extensions, NULL)) {
1.1 jsing 675: BIO_printf(bio_err,
1.19 jsing 676: "Error Loading extension section %s\n", req_config.extensions);
1.1 jsing 677: goto end;
678: }
679: }
1.17 inoguchi 680: if (addext_conf != NULL) {
681: /* Check syntax of command line extensions */
682: X509V3_CTX ctx;
683: X509V3_set_ctx_test(&ctx);
684: X509V3_set_nconf(&ctx, addext_conf);
685: if (!X509V3_EXT_add_nconf(addext_conf, &ctx, "default", NULL)) {
686: BIO_printf(bio_err,
687: "Error Loading command line extensions\n");
688: goto end;
689: }
690: }
1.1 jsing 691: if (!passin) {
692: passin = NCONF_get_string(req_conf, SECTION, "input_password");
693: if (!passin)
694: ERR_clear_error();
695: }
696: if (!passout) {
697: passout = NCONF_get_string(req_conf, SECTION, "output_password");
698: if (!passout)
699: ERR_clear_error();
700: }
701: p = NCONF_get_string(req_conf, SECTION, STRING_MASK);
702: if (!p)
703: ERR_clear_error();
704:
705: if (p && !ASN1_STRING_set_default_mask_asc(p)) {
706: BIO_printf(bio_err, "Invalid global string mask setting %s\n", p);
707: goto end;
708: }
1.19 jsing 709: if (req_config.chtype != MBSTRING_UTF8) {
1.1 jsing 710: p = NCONF_get_string(req_conf, SECTION, UTF8_IN);
711: if (!p)
712: ERR_clear_error();
713: else if (!strcmp(p, "yes"))
1.19 jsing 714: req_config.chtype = MBSTRING_UTF8;
1.1 jsing 715: }
1.19 jsing 716: if (!req_config.req_exts) {
717: req_config.req_exts = NCONF_get_string(req_conf, SECTION, REQ_EXTENSIONS);
718: if (!req_config.req_exts)
1.1 jsing 719: ERR_clear_error();
720: }
1.19 jsing 721: if (req_config.req_exts) {
1.1 jsing 722: /* Check syntax of file */
723: X509V3_CTX ctx;
724: X509V3_set_ctx_test(&ctx);
725: X509V3_set_nconf(&ctx, req_conf);
1.19 jsing 726: if (!X509V3_EXT_add_nconf(req_conf, &ctx, req_config.req_exts, NULL)) {
1.1 jsing 727: BIO_printf(bio_err,
728: "Error Loading request extension section %s\n",
1.19 jsing 729: req_config.req_exts);
1.1 jsing 730: goto end;
731: }
732: }
733: in = BIO_new(BIO_s_file());
734: out = BIO_new(BIO_s_file());
735: if ((in == NULL) || (out == NULL))
736: goto end;
737:
1.19 jsing 738: if (req_config.keyfile != NULL) {
739: pkey = load_key(bio_err, req_config.keyfile, req_config.keyform, 0, passin,
1.1 jsing 740: "Private Key");
741: if (!pkey) {
742: /*
743: * load_key() has already printed an appropriate
744: * message
745: */
746: goto end;
747: }
748: }
1.19 jsing 749: if (req_config.newreq && (pkey == NULL)) {
750: if (!NCONF_get_number(req_conf, SECTION, BITS, &req_config.newkey)) {
751: req_config.newkey = DEFAULT_KEY_LENGTH;
1.1 jsing 752: }
1.19 jsing 753: if (req_config.keyalg) {
754: genctx = set_keygen_ctx(bio_err, req_config.keyalg, &pkey_type, &req_config.newkey,
1.7 bcook 755: &keyalgstr);
1.1 jsing 756: if (!genctx)
757: goto end;
758: }
1.19 jsing 759: if (req_config.newkey < MIN_KEY_LENGTH && (pkey_type == EVP_PKEY_RSA || pkey_type == EVP_PKEY_DSA)) {
1.1 jsing 760: BIO_printf(bio_err, "private key length is too short,\n");
1.19 jsing 761: BIO_printf(bio_err, "it needs to be at least %d bits, not %ld\n", MIN_KEY_LENGTH, req_config.newkey);
1.1 jsing 762: goto end;
763: }
764: if (!genctx) {
1.19 jsing 765: genctx = set_keygen_ctx(bio_err, NULL, &pkey_type, &req_config.newkey,
1.7 bcook 766: &keyalgstr);
1.1 jsing 767: if (!genctx)
768: goto end;
769: }
1.19 jsing 770: if (req_config.pkeyopts) {
1.1 jsing 771: char *genopt;
1.19 jsing 772: for (i = 0; i < sk_OPENSSL_STRING_num(req_config.pkeyopts); i++) {
773: genopt = sk_OPENSSL_STRING_value(req_config.pkeyopts, i);
1.1 jsing 774: if (pkey_ctrl_string(genctx, genopt) <= 0) {
775: BIO_printf(bio_err,
776: "parameter error \"%s\"\n",
777: genopt);
778: ERR_print_errors(bio_err);
779: goto end;
780: }
781: }
782: }
783: BIO_printf(bio_err, "Generating a %ld bit %s private key\n",
1.19 jsing 784: req_config.newkey, keyalgstr);
1.1 jsing 785:
786: EVP_PKEY_CTX_set_cb(genctx, genpkey_cb);
787: EVP_PKEY_CTX_set_app_data(genctx, bio_err);
788:
789: if (EVP_PKEY_keygen(genctx, &pkey) <= 0) {
790: BIO_puts(bio_err, "Error Generating Key\n");
791: goto end;
792: }
793: EVP_PKEY_CTX_free(genctx);
794: genctx = NULL;
795:
1.19 jsing 796: if (req_config.keyout == NULL) {
797: req_config.keyout = NCONF_get_string(req_conf, SECTION, KEYFILE);
798: if (req_config.keyout == NULL)
1.1 jsing 799: ERR_clear_error();
800: }
1.19 jsing 801: if (req_config.keyout == NULL) {
1.1 jsing 802: BIO_printf(bio_err, "writing new private key to stdout\n");
803: BIO_set_fp(out, stdout, BIO_NOCLOSE);
804: } else {
1.19 jsing 805: BIO_printf(bio_err, "writing new private key to '%s'\n", req_config.keyout);
806: if (BIO_write_filename(out, req_config.keyout) <= 0) {
807: perror(req_config.keyout);
1.1 jsing 808: goto end;
809: }
810: }
811:
812: p = NCONF_get_string(req_conf, SECTION, "encrypt_rsa_key");
813: if (p == NULL) {
814: ERR_clear_error();
815: p = NCONF_get_string(req_conf, SECTION, "encrypt_key");
816: if (p == NULL)
817: ERR_clear_error();
818: }
819: if ((p != NULL) && (strcmp(p, "no") == 0))
820: cipher = NULL;
1.19 jsing 821: if (req_config.nodes)
1.1 jsing 822: cipher = NULL;
823:
824: i = 0;
1.15 jsing 825: loop:
1.1 jsing 826: if (!PEM_write_bio_PrivateKey(out, pkey, cipher,
827: NULL, 0, NULL, passout)) {
828: if ((ERR_GET_REASON(ERR_peek_error()) ==
829: PEM_R_PROBLEMS_GETTING_PASSWORD) && (i < 3)) {
830: ERR_clear_error();
831: i++;
832: goto loop;
833: }
834: goto end;
835: }
836: BIO_printf(bio_err, "-----\n");
837: }
1.19 jsing 838: if (!req_config.newreq) {
839: if (req_config.infile == NULL)
1.1 jsing 840: BIO_set_fp(in, stdin, BIO_NOCLOSE);
841: else {
1.19 jsing 842: if (BIO_read_filename(in, req_config.infile) <= 0) {
843: perror(req_config.infile);
1.1 jsing 844: goto end;
845: }
846: }
847:
1.19 jsing 848: if (req_config.informat == FORMAT_ASN1)
1.1 jsing 849: req = d2i_X509_REQ_bio(in, NULL);
1.19 jsing 850: else if (req_config.informat == FORMAT_PEM)
1.1 jsing 851: req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL);
852: else {
853: BIO_printf(bio_err, "bad input format specified for X509 request\n");
854: goto end;
855: }
856: if (req == NULL) {
857: BIO_printf(bio_err, "unable to load X509 request\n");
858: goto end;
859: }
860: }
1.19 jsing 861: if (req_config.newreq || req_config.x509) {
1.1 jsing 862: if (pkey == NULL) {
863: BIO_printf(bio_err, "you need to specify a private key\n");
864: goto end;
865: }
866: if (req == NULL) {
867: req = X509_REQ_new();
868: if (req == NULL) {
869: goto end;
870: }
1.19 jsing 871: i = make_REQ(req, pkey, req_config.subj, req_config.multirdn, !req_config.x509, req_config.chtype);
872: req_config.subj = NULL; /* done processing '-subj' option */
1.1 jsing 873: if (!i) {
874: BIO_printf(bio_err, "problems making Certificate Request\n");
875: goto end;
876: }
877: }
1.19 jsing 878: if (req_config.x509) {
1.1 jsing 879: EVP_PKEY *tmppkey;
1.23 tb 880:
1.1 jsing 881: X509V3_CTX ext_ctx;
882: if ((x509ss = X509_new()) == NULL)
883: goto end;
884:
885: /* Set version to V3 */
1.19 jsing 886: if ((req_config.extensions != NULL || addext_conf != NULL) &&
1.17 inoguchi 887: !X509_set_version(x509ss, 2))
1.1 jsing 888: goto end;
1.19 jsing 889: if (req_config.serial) {
890: if (!X509_set_serialNumber(x509ss, req_config.serial))
1.1 jsing 891: goto end;
892: } else {
893: if (!rand_serial(NULL,
894: X509_get_serialNumber(x509ss)))
895: goto end;
896: }
897:
898: if (!X509_set_issuer_name(x509ss, X509_REQ_get_subject_name(req)))
899: goto end;
900: if (!X509_gmtime_adj(X509_get_notBefore(x509ss), 0))
901: goto end;
1.19 jsing 902: if (!X509_time_adj_ex(X509_get_notAfter(x509ss), req_config.days, 0, NULL))
1.1 jsing 903: goto end;
904: if (!X509_set_subject_name(x509ss, X509_REQ_get_subject_name(req)))
905: goto end;
1.23 tb 906: if ((tmppkey = X509_REQ_get0_pubkey(req)) == NULL)
907: goto end;
908: if (!X509_set_pubkey(x509ss, tmppkey))
1.1 jsing 909: goto end;
910:
911: /* Set up V3 context struct */
912:
913: X509V3_set_ctx(&ext_ctx, x509ss, x509ss, NULL, NULL, 0);
914: X509V3_set_nconf(&ext_ctx, req_conf);
915:
916: /* Add extensions */
1.19 jsing 917: if (req_config.extensions && !X509V3_EXT_add_nconf(req_conf,
918: &ext_ctx, req_config.extensions, x509ss)) {
1.1 jsing 919: BIO_printf(bio_err,
920: "Error Loading extension section %s\n",
1.19 jsing 921: req_config.extensions);
1.1 jsing 922: goto end;
923: }
1.17 inoguchi 924: if (addext_conf != NULL &&
925: !X509V3_EXT_add_nconf(addext_conf, &ext_ctx,
926: "default", x509ss)) {
927: BIO_printf(bio_err,
928: "Error Loading command line extensions\n");
929: goto end;
930: }
1.19 jsing 931: i = do_X509_sign(bio_err, x509ss, pkey, req_config.digest, req_config.sigopts);
1.1 jsing 932: if (!i) {
933: ERR_print_errors(bio_err);
934: goto end;
935: }
936: } else {
937: X509V3_CTX ext_ctx;
938:
939: /* Set up V3 context struct */
940:
941: X509V3_set_ctx(&ext_ctx, NULL, NULL, req, NULL, 0);
942: X509V3_set_nconf(&ext_ctx, req_conf);
943:
944: /* Add extensions */
1.19 jsing 945: if (req_config.req_exts && !X509V3_EXT_REQ_add_nconf(req_conf,
946: &ext_ctx, req_config.req_exts, req)) {
1.1 jsing 947: BIO_printf(bio_err,
948: "Error Loading extension section %s\n",
1.19 jsing 949: req_config.req_exts);
1.1 jsing 950: goto end;
951: }
1.17 inoguchi 952: if (addext_conf != NULL &&
953: !X509V3_EXT_REQ_add_nconf(addext_conf, &ext_ctx,
954: "default", req)) {
955: BIO_printf(bio_err,
956: "Error Loading command line extensions\n");
957: goto end;
958: }
1.19 jsing 959: i = do_X509_REQ_sign(bio_err, req, pkey, req_config.digest, req_config.sigopts);
1.1 jsing 960: if (!i) {
961: ERR_print_errors(bio_err);
962: goto end;
963: }
964: }
965: }
1.19 jsing 966: if (req_config.subj && req_config.x509) {
967: BIO_printf(bio_err, "Cannot modify certificate subject\n");
1.1 jsing 968: goto end;
969: }
1.19 jsing 970: if (req_config.subj && !req_config.x509) {
971: if (req_config.verbose) {
1.1 jsing 972: BIO_printf(bio_err, "Modifying Request's Subject\n");
1.19 jsing 973: print_name(bio_err, "old subject=", X509_REQ_get_subject_name(req), req_config.nmflag);
1.1 jsing 974: }
1.19 jsing 975: if (build_subject(req, req_config.subj, req_config.chtype, req_config.multirdn) == 0) {
1.1 jsing 976: BIO_printf(bio_err, "ERROR: cannot modify subject\n");
977: ex = 1;
978: goto end;
979: }
980:
1.19 jsing 981: if (req_config.verbose) {
982: print_name(bio_err, "new subject=", X509_REQ_get_subject_name(req), req_config.nmflag);
1.1 jsing 983: }
984: }
1.19 jsing 985: if (req_config.verify && !req_config.x509) {
1.23 tb 986: EVP_PKEY *pubkey = pkey;
1.1 jsing 987:
1.23 tb 988: if (pubkey == NULL)
989: pubkey = X509_REQ_get0_pubkey(req);
990: if (pubkey == NULL)
991: goto end;
992: i = X509_REQ_verify(req, pubkey);
1.1 jsing 993: if (i < 0) {
994: goto end;
995: } else if (i == 0) {
996: BIO_printf(bio_err, "verify failure\n");
997: ERR_print_errors(bio_err);
998: } else /* if (i > 0) */
999: BIO_printf(bio_err, "verify OK\n");
1000: }
1.19 jsing 1001: if (req_config.noout && !req_config.text && !req_config.modulus && !req_config.subject && !req_config.pubkey) {
1.1 jsing 1002: ex = 0;
1003: goto end;
1004: }
1.19 jsing 1005: if (req_config.outfile == NULL) {
1.1 jsing 1006: BIO_set_fp(out, stdout, BIO_NOCLOSE);
1007: } else {
1.19 jsing 1008: if ((req_config.keyout != NULL) && (strcmp(req_config.outfile, req_config.keyout) == 0))
1009: i = (int) BIO_append_filename(out, req_config.outfile);
1.1 jsing 1010: else
1.19 jsing 1011: i = (int) BIO_write_filename(out, req_config.outfile);
1.1 jsing 1012: if (!i) {
1.19 jsing 1013: perror(req_config.outfile);
1.1 jsing 1014: goto end;
1015: }
1016: }
1017:
1.19 jsing 1018: if (req_config.pubkey) {
1.1 jsing 1019: EVP_PKEY *tpubkey;
1.23 tb 1020:
1021: if ((tpubkey = X509_REQ_get0_pubkey(req)) == NULL) {
1.1 jsing 1022: BIO_printf(bio_err, "Error getting public key\n");
1023: ERR_print_errors(bio_err);
1024: goto end;
1025: }
1026: PEM_write_bio_PUBKEY(out, tpubkey);
1027: }
1.19 jsing 1028: if (req_config.text) {
1029: if (req_config.x509)
1030: X509_print_ex(out, x509ss, req_config.nmflag, req_config.reqflag);
1.1 jsing 1031: else
1.19 jsing 1032: X509_REQ_print_ex(out, req, req_config.nmflag, req_config.reqflag);
1.1 jsing 1033: }
1.19 jsing 1034: if (req_config.subject) {
1035: if (req_config.x509)
1036: print_name(out, "subject=", X509_get_subject_name(x509ss), req_config.nmflag);
1.1 jsing 1037: else
1.19 jsing 1038: print_name(out, "subject=", X509_REQ_get_subject_name(req), req_config.nmflag);
1.1 jsing 1039: }
1.19 jsing 1040: if (req_config.modulus) {
1.1 jsing 1041: EVP_PKEY *tpubkey;
1042:
1.19 jsing 1043: if (req_config.x509)
1.22 tb 1044: tpubkey = X509_get0_pubkey(x509ss);
1.1 jsing 1045: else
1.22 tb 1046: tpubkey = X509_REQ_get0_pubkey(req);
1.1 jsing 1047: if (tpubkey == NULL) {
1048: fprintf(stdout, "Modulus=unavailable\n");
1049: goto end;
1050: }
1051: fprintf(stdout, "Modulus=");
1.22 tb 1052: if (EVP_PKEY_base_id(tpubkey) == EVP_PKEY_RSA) {
1053: const BIGNUM *n = NULL;
1054:
1055: RSA_get0_key(EVP_PKEY_get0_RSA(tpubkey), &n, NULL, NULL);
1056:
1057: BN_print(out, n);
1058: } else
1.1 jsing 1059: fprintf(stdout, "Wrong Algorithm type");
1060: fprintf(stdout, "\n");
1061: }
1.19 jsing 1062: if (!req_config.noout && !req_config.x509) {
1063: if (req_config.outformat == FORMAT_ASN1)
1.1 jsing 1064: i = i2d_X509_REQ_bio(out, req);
1.19 jsing 1065: else if (req_config.outformat == FORMAT_PEM) {
1066: if (req_config.newhdr)
1.1 jsing 1067: i = PEM_write_bio_X509_REQ_NEW(out, req);
1068: else
1069: i = PEM_write_bio_X509_REQ(out, req);
1070: } else {
1071: BIO_printf(bio_err, "bad output format specified for outfile\n");
1072: goto end;
1073: }
1074: if (!i) {
1075: BIO_printf(bio_err, "unable to write X509 request\n");
1076: goto end;
1077: }
1078: }
1.19 jsing 1079: if (!req_config.noout && req_config.x509 && (x509ss != NULL)) {
1080: if (req_config.outformat == FORMAT_ASN1)
1.1 jsing 1081: i = i2d_X509_bio(out, x509ss);
1.19 jsing 1082: else if (req_config.outformat == FORMAT_PEM)
1.1 jsing 1083: i = PEM_write_bio_X509(out, x509ss);
1084: else {
1085: BIO_printf(bio_err, "bad output format specified for outfile\n");
1086: goto end;
1087: }
1088: if (!i) {
1089: BIO_printf(bio_err, "unable to write X509 certificate\n");
1090: goto end;
1091: }
1092: }
1093: ex = 0;
1.15 jsing 1094: end:
1.1 jsing 1095: if (ex) {
1096: ERR_print_errors(bio_err);
1097: }
1098: if ((req_conf != NULL) && (req_conf != config))
1099: NCONF_free(req_conf);
1.17 inoguchi 1100: NCONF_free(addext_conf);
1.19 jsing 1101: BIO_free(req_config.addext_bio);
1.1 jsing 1102: BIO_free(in);
1103: BIO_free_all(out);
1104: EVP_PKEY_free(pkey);
1105: if (genctx)
1106: EVP_PKEY_CTX_free(genctx);
1.19 jsing 1107: if (req_config.pkeyopts)
1108: sk_OPENSSL_STRING_free(req_config.pkeyopts);
1109: if (req_config.sigopts)
1110: sk_OPENSSL_STRING_free(req_config.sigopts);
1111: lh_OPENSSL_STRING_doall(req_config.addexts, (LHASH_DOALL_FN_TYPE)exts_cleanup);
1112: lh_OPENSSL_STRING_free(req_config.addexts);
1.1 jsing 1113: free(keyalgstr);
1114: X509_REQ_free(req);
1115: X509_free(x509ss);
1.19 jsing 1116: ASN1_INTEGER_free(req_config.serial);
1117: if (req_config.passargin && passin)
1.1 jsing 1118: free(passin);
1.19 jsing 1119: if (req_config.passargout && passout)
1.1 jsing 1120: free(passout);
1121: OBJ_cleanup();
1122:
1123: return (ex);
1124: }
1125:
1126: static int
1127: make_REQ(X509_REQ * req, EVP_PKEY * pkey, char *subj, int multirdn,
1128: int attribs, unsigned long chtype)
1129: {
1130: int ret = 0, i;
1131: char no_prompt = 0;
1132: STACK_OF(CONF_VALUE) * dn_sk, *attr_sk = NULL;
1133: char *tmp, *dn_sect, *attr_sect;
1134:
1135: tmp = NCONF_get_string(req_conf, SECTION, PROMPT);
1136: if (tmp == NULL)
1137: ERR_clear_error();
1138: if ((tmp != NULL) && !strcmp(tmp, "no"))
1139: no_prompt = 1;
1140:
1141: dn_sect = NCONF_get_string(req_conf, SECTION, DISTINGUISHED_NAME);
1142: if (dn_sect == NULL) {
1143: BIO_printf(bio_err, "unable to find '%s' in config\n",
1144: DISTINGUISHED_NAME);
1145: goto err;
1146: }
1147: dn_sk = NCONF_get_section(req_conf, dn_sect);
1148: if (dn_sk == NULL) {
1149: BIO_printf(bio_err, "unable to get '%s' section\n", dn_sect);
1150: goto err;
1151: }
1152: attr_sect = NCONF_get_string(req_conf, SECTION, ATTRIBUTES);
1153: if (attr_sect == NULL) {
1154: ERR_clear_error();
1155: attr_sk = NULL;
1156: } else {
1157: attr_sk = NCONF_get_section(req_conf, attr_sect);
1158: if (attr_sk == NULL) {
1159: BIO_printf(bio_err, "unable to get '%s' section\n", attr_sect);
1160: goto err;
1161: }
1162: }
1163:
1164: /* setup version number */
1165: if (!X509_REQ_set_version(req, 0L))
1166: goto err; /* version 1 */
1167:
1168: if (no_prompt)
1169: i = auto_info(req, dn_sk, attr_sk, attribs, chtype);
1170: else {
1171: if (subj)
1172: i = build_subject(req, subj, chtype, multirdn);
1173: else
1174: i = prompt_info(req, dn_sk, dn_sect, attr_sk, attr_sect, attribs, chtype);
1175: }
1176: if (!i)
1177: goto err;
1178:
1179: if (!X509_REQ_set_pubkey(req, pkey))
1180: goto err;
1181:
1182: ret = 1;
1.15 jsing 1183: err:
1.1 jsing 1184: return (ret);
1185: }
1186:
1187: /*
1188: * subject is expected to be in the format /type0=value0/type1=value1/type2=...
1189: * where characters may be escaped by \
1190: */
1191: static int
1192: build_subject(X509_REQ * req, char *subject, unsigned long chtype, int multirdn)
1193: {
1194: X509_NAME *n;
1195:
1196: if (!(n = parse_name(subject, chtype, multirdn)))
1197: return 0;
1198:
1199: if (!X509_REQ_set_subject_name(req, n)) {
1200: X509_NAME_free(n);
1201: return 0;
1202: }
1203: X509_NAME_free(n);
1204: return 1;
1205: }
1206:
1207:
1208: static int
1209: prompt_info(X509_REQ * req,
1210: STACK_OF(CONF_VALUE) * dn_sk, char *dn_sect,
1211: STACK_OF(CONF_VALUE) * attr_sk, char *attr_sect, int attribs,
1212: unsigned long chtype)
1213: {
1214: int i;
1215: char *p, *q;
1216: char buf[100];
1217: int nid, mval;
1218: long n_min, n_max;
1219: char *type, *value;
1220: const char *def;
1221: CONF_VALUE *v;
1222: X509_NAME *subj;
1223: subj = X509_REQ_get_subject_name(req);
1224:
1.19 jsing 1225: if (!req_config.batch) {
1.1 jsing 1226: BIO_printf(bio_err, "You are about to be asked to enter information that will be incorporated\n");
1227: BIO_printf(bio_err, "into your certificate request.\n");
1228: BIO_printf(bio_err, "What you are about to enter is what is called a Distinguished Name or a DN.\n");
1229: BIO_printf(bio_err, "There are quite a few fields but you can leave some blank\n");
1230: BIO_printf(bio_err, "For some fields there will be a default value,\n");
1231: BIO_printf(bio_err, "If you enter '.', the field will be left blank.\n");
1232: BIO_printf(bio_err, "-----\n");
1233: }
1234: if (sk_CONF_VALUE_num(dn_sk)) {
1235: i = -1;
1.15 jsing 1236: start: for (;;) {
1.1 jsing 1237: int ret;
1238: i++;
1239: if (sk_CONF_VALUE_num(dn_sk) <= i)
1240: break;
1241:
1242: v = sk_CONF_VALUE_value(dn_sk, i);
1243: p = q = NULL;
1244: type = v->name;
1245: if (!check_end(type, "_min") || !check_end(type, "_max") ||
1246: !check_end(type, "_default") ||
1247: !check_end(type, "_value"))
1248: continue;
1249: /*
1250: * Skip past any leading X. X: X, etc to allow for
1251: * multiple instances
1252: */
1253: for (p = v->name; *p; p++)
1254: if ((*p == ':') || (*p == ',') ||
1255: (*p == '.')) {
1256: p++;
1257: if (*p)
1258: type = p;
1259: break;
1260: }
1261: if (*type == '+') {
1262: mval = -1;
1263: type++;
1264: } else
1265: mval = 0;
1266: /* If OBJ not recognised ignore it */
1267: if ((nid = OBJ_txt2nid(type)) == NID_undef)
1268: goto start;
1269: ret = snprintf(buf, sizeof buf, "%s_default", v->name);
1.16 deraadt 1270: if (ret < 0 || ret >= sizeof(buf)) {
1.1 jsing 1271: BIO_printf(bio_err, "Name '%s' too long for default\n",
1272: v->name);
1273: return 0;
1274: }
1275: if ((def = NCONF_get_string(req_conf, dn_sect, buf)) == NULL) {
1276: ERR_clear_error();
1277: def = "";
1278: }
1279: ret = snprintf(buf, sizeof buf, "%s_value", v->name);
1.16 deraadt 1280: if (ret < 0 || ret >= sizeof(buf)) {
1.1 jsing 1281: BIO_printf(bio_err, "Name '%s' too long for value\n",
1282: v->name);
1283: return 0;
1284: }
1285: if ((value = NCONF_get_string(req_conf, dn_sect, buf)) == NULL) {
1286: ERR_clear_error();
1287: value = NULL;
1288: }
1289: ret = snprintf(buf, sizeof buf, "%s_min", v->name);
1.16 deraadt 1290: if (ret < 0 || ret >= sizeof(buf)) {
1.1 jsing 1291: BIO_printf(bio_err, "Name '%s' too long for min\n",
1292: v->name);
1293: return 0;
1294: }
1295: if (!NCONF_get_number(req_conf, dn_sect, buf, &n_min)) {
1296: ERR_clear_error();
1297: n_min = -1;
1298: }
1299: ret = snprintf(buf, sizeof buf, "%s_max", v->name);
1.16 deraadt 1300: if (ret < 0 || ret >= sizeof(buf)) {
1.1 jsing 1301: BIO_printf(bio_err, "Name '%s' too long for max\n",
1302: v->name);
1303: return 0;
1304: }
1305: if (!NCONF_get_number(req_conf, dn_sect, buf, &n_max)) {
1306: ERR_clear_error();
1307: n_max = -1;
1308: }
1309: if (!add_DN_object(subj, v->value, def, value, nid,
1310: n_min, n_max, chtype, mval))
1311: return 0;
1312: }
1313: if (X509_NAME_entry_count(subj) == 0) {
1314: BIO_printf(bio_err, "error, no objects specified in config file\n");
1315: return 0;
1316: }
1317: if (attribs) {
1318: if ((attr_sk != NULL) && (sk_CONF_VALUE_num(attr_sk) > 0) &&
1.19 jsing 1319: (!req_config.batch)) {
1.1 jsing 1320: BIO_printf(bio_err,
1321: "\nPlease enter the following 'extra' attributes\n");
1322: BIO_printf(bio_err,
1323: "to be sent with your certificate request\n");
1324: }
1325: i = -1;
1326: start2: for (;;) {
1327: int ret;
1328: i++;
1329: if ((attr_sk == NULL) ||
1330: (sk_CONF_VALUE_num(attr_sk) <= i))
1331: break;
1332:
1333: v = sk_CONF_VALUE_value(attr_sk, i);
1334: type = v->name;
1335: if ((nid = OBJ_txt2nid(type)) == NID_undef)
1336: goto start2;
1337: ret = snprintf(buf, sizeof buf, "%s_default", type);
1.16 deraadt 1338: if (ret < 0 || ret >= sizeof(buf)) {
1.1 jsing 1339: BIO_printf(bio_err, "Name '%s' too long for default\n",
1340: v->name);
1341: return 0;
1342: }
1343: if ((def = NCONF_get_string(req_conf, attr_sect, buf))
1344: == NULL) {
1345: ERR_clear_error();
1346: def = "";
1347: }
1348: ret = snprintf(buf, sizeof buf, "%s_value", type);
1.16 deraadt 1349: if (ret < 0 || ret >= sizeof(buf)) {
1.1 jsing 1350: BIO_printf(bio_err, "Name '%s' too long for value\n",
1351: v->name);
1352: return 0;
1353: }
1354: if ((value = NCONF_get_string(req_conf, attr_sect, buf))
1355: == NULL) {
1356: ERR_clear_error();
1357: value = NULL;
1358: }
1359: ret = snprintf(buf, sizeof buf, "%s_min", type);
1.16 deraadt 1360: if (ret < 0 || ret >= sizeof(buf)) {
1.1 jsing 1361: BIO_printf(bio_err, "Name '%s' too long for min\n",
1362: v->name);
1363: return 0;
1364: }
1365: if (!NCONF_get_number(req_conf, attr_sect, buf, &n_min)) {
1366: ERR_clear_error();
1367: n_min = -1;
1368: }
1369: ret = snprintf(buf, sizeof buf, "%s_max", type);
1.16 deraadt 1370: if (ret < 0 || ret >= sizeof(buf)) {
1.1 jsing 1371: BIO_printf(bio_err, "Name '%s' too long for max\n",
1372: v->name);
1373: return 0;
1374: }
1375: if (!NCONF_get_number(req_conf, attr_sect, buf, &n_max)) {
1376: ERR_clear_error();
1377: n_max = -1;
1378: }
1379: if (!add_attribute_object(req,
1380: v->value, def, value, nid, n_min, n_max, chtype))
1381: return 0;
1382: }
1383: }
1384: } else {
1385: BIO_printf(bio_err, "No template, please set one up.\n");
1386: return 0;
1387: }
1388:
1389: return 1;
1390:
1391: }
1392:
1393: static int
1394: auto_info(X509_REQ * req, STACK_OF(CONF_VALUE) * dn_sk,
1395: STACK_OF(CONF_VALUE) * attr_sk, int attribs, unsigned long chtype)
1396: {
1397: int i;
1398: char *p, *q;
1399: char *type;
1400: CONF_VALUE *v;
1401: X509_NAME *subj;
1402:
1403: subj = X509_REQ_get_subject_name(req);
1404:
1405: for (i = 0; i < sk_CONF_VALUE_num(dn_sk); i++) {
1406: int mval;
1407: v = sk_CONF_VALUE_value(dn_sk, i);
1408: p = q = NULL;
1409: type = v->name;
1410: /*
1411: * Skip past any leading X. X: X, etc to allow for multiple
1412: * instances
1413: */
1414: for (p = v->name; *p; p++)
1415: if ((*p == ':') || (*p == ',') || (*p == '.')) {
1416: p++;
1417: if (*p)
1418: type = p;
1419: break;
1420: }
1421: if (*p == '+') {
1422: p++;
1423: mval = -1;
1424: } else
1425: mval = 0;
1426: if (!X509_NAME_add_entry_by_txt(subj, type, chtype,
1427: (unsigned char *) v->value, -1, -1, mval))
1428: return 0;
1429:
1430: }
1431:
1432: if (!X509_NAME_entry_count(subj)) {
1433: BIO_printf(bio_err, "error, no objects specified in config file\n");
1434: return 0;
1435: }
1436: if (attribs) {
1437: for (i = 0; i < sk_CONF_VALUE_num(attr_sk); i++) {
1438: v = sk_CONF_VALUE_value(attr_sk, i);
1439: if (!X509_REQ_add1_attr_by_txt(req, v->name, chtype,
1440: (unsigned char *) v->value, -1))
1441: return 0;
1442: }
1443: }
1444: return 1;
1445: }
1446:
1447:
1448: static int
1449: add_DN_object(X509_NAME * n, char *text, const char *def, char *value,
1450: int nid, int n_min, int n_max, unsigned long chtype, int mval)
1451: {
1452: int i, ret = 0;
1453: char buf[1024];
1.15 jsing 1454: start:
1.19 jsing 1455: if (!req_config.batch)
1.1 jsing 1456: BIO_printf(bio_err, "%s [%s]:", text, def);
1457: (void) BIO_flush(bio_err);
1458: if (value != NULL) {
1459: strlcpy(buf, value, sizeof buf);
1460: strlcat(buf, "\n", sizeof buf);
1461: BIO_printf(bio_err, "%s\n", value);
1462: } else {
1463: buf[0] = '\0';
1.19 jsing 1464: if (!req_config.batch) {
1.1 jsing 1465: if (!fgets(buf, sizeof buf, stdin))
1466: return 0;
1467: } else {
1468: buf[0] = '\n';
1469: buf[1] = '\0';
1470: }
1471: }
1472:
1473: if (buf[0] == '\0')
1474: return (0);
1475: else if (buf[0] == '\n') {
1476: if ((def == NULL) || (def[0] == '\0'))
1477: return (1);
1478: strlcpy(buf, def, sizeof buf);
1479: strlcat(buf, "\n", sizeof buf);
1480: } else if ((buf[0] == '.') && (buf[1] == '\n'))
1481: return (1);
1482:
1483: i = strlen(buf);
1484: if (buf[i - 1] != '\n') {
1485: BIO_printf(bio_err, "weird input :-(\n");
1486: return (0);
1487: }
1488: buf[--i] = '\0';
1489: if (!req_check_len(i, n_min, n_max))
1490: goto start;
1491: if (!X509_NAME_add_entry_by_NID(n, nid, chtype,
1492: (unsigned char *) buf, -1, -1, mval))
1493: goto err;
1494: ret = 1;
1.15 jsing 1495: err:
1.1 jsing 1496: return (ret);
1497: }
1498:
1499: static int
1500: add_attribute_object(X509_REQ * req, char *text, const char *def,
1501: char *value, int nid, int n_min,
1502: int n_max, unsigned long chtype)
1503: {
1504: int i;
1505: static char buf[1024];
1506:
1.15 jsing 1507: start:
1.19 jsing 1508: if (!req_config.batch)
1.1 jsing 1509: BIO_printf(bio_err, "%s [%s]:", text, def);
1510: (void) BIO_flush(bio_err);
1511: if (value != NULL) {
1512: strlcpy(buf, value, sizeof buf);
1513: strlcat(buf, "\n", sizeof buf);
1514: BIO_printf(bio_err, "%s\n", value);
1515: } else {
1516: buf[0] = '\0';
1.19 jsing 1517: if (!req_config.batch) {
1.1 jsing 1518: if (!fgets(buf, sizeof buf, stdin))
1519: return 0;
1520: } else {
1521: buf[0] = '\n';
1522: buf[1] = '\0';
1523: }
1524: }
1525:
1526: if (buf[0] == '\0')
1527: return (0);
1528: else if (buf[0] == '\n') {
1529: if ((def == NULL) || (def[0] == '\0'))
1530: return (1);
1531: strlcpy(buf, def, sizeof buf);
1532: strlcat(buf, "\n", sizeof buf);
1533: } else if ((buf[0] == '.') && (buf[1] == '\n'))
1534: return (1);
1535:
1536: i = strlen(buf);
1537: if (buf[i - 1] != '\n') {
1538: BIO_printf(bio_err, "weird input :-(\n");
1539: return (0);
1540: }
1541: buf[--i] = '\0';
1542: if (!req_check_len(i, n_min, n_max))
1543: goto start;
1544:
1545: if (!X509_REQ_add1_attr_by_NID(req, nid, chtype,
1546: (unsigned char *) buf, -1)) {
1547: BIO_printf(bio_err, "Error adding attribute\n");
1548: ERR_print_errors(bio_err);
1549: goto err;
1550: }
1551: return (1);
1.15 jsing 1552: err:
1.1 jsing 1553: return (0);
1554: }
1555:
1556: static int
1557: req_check_len(int len, int n_min, int n_max)
1558: {
1559: if ((n_min > 0) && (len < n_min)) {
1560: BIO_printf(bio_err, "string is too short, it needs to be at least %d bytes long\n", n_min);
1561: return (0);
1562: }
1563: if ((n_max >= 0) && (len > n_max)) {
1564: BIO_printf(bio_err, "string is too long, it needs to be less than %d bytes long\n", n_max);
1565: return (0);
1566: }
1567: return (1);
1568: }
1569:
1570: /* Check if the end of a string matches 'end' */
1571: static int
1572: check_end(const char *str, const char *end)
1573: {
1574: int elen, slen;
1575: const char *tmp;
1576: elen = strlen(end);
1577: slen = strlen(str);
1578: if (elen > slen)
1579: return 1;
1580: tmp = str + slen - elen;
1581: return strcmp(tmp, end);
1582: }
1583:
1584: static EVP_PKEY_CTX *
1585: set_keygen_ctx(BIO * err, const char *gstr, int *pkey_type,
1.7 bcook 1586: long *pkeylen, char **palgnam)
1.1 jsing 1587: {
1588: EVP_PKEY_CTX *gctx = NULL;
1589: EVP_PKEY *param = NULL;
1590: long keylen = -1;
1591: BIO *pbio = NULL;
1592: const char *paramfile = NULL;
1593: const char *errstr;
1594:
1595: if (gstr == NULL) {
1596: *pkey_type = EVP_PKEY_RSA;
1597: keylen = *pkeylen;
1598: } else if (gstr[0] >= '0' && gstr[0] <= '9') {
1599: *pkey_type = EVP_PKEY_RSA;
1600: keylen = strtonum(gstr, 0, LONG_MAX, &errstr);
1601: if (errstr) {
1602: BIO_printf(err, "bad algorithm %s: %s\n", gstr, errstr);
1603: return NULL;
1604: }
1605: *pkeylen = keylen;
1606: } else if (!strncmp(gstr, "param:", 6))
1607: paramfile = gstr + 6;
1608: else {
1609: const char *p = strchr(gstr, ':');
1610: int len;
1611: const EVP_PKEY_ASN1_METHOD *ameth;
1612:
1613: if (p)
1614: len = p - gstr;
1615: else
1616: len = strlen(gstr);
1617:
1.7 bcook 1618: ameth = EVP_PKEY_asn1_find_str(NULL, gstr, len);
1.1 jsing 1619:
1620: if (!ameth) {
1621: BIO_printf(err, "Unknown algorithm %.*s\n", len, gstr);
1622: return NULL;
1623: }
1624: EVP_PKEY_asn1_get0_info(NULL, pkey_type, NULL, NULL, NULL,
1625: ameth);
1626: if (*pkey_type == EVP_PKEY_RSA) {
1627: if (p) {
1628: keylen = strtonum(p + 1, 0, LONG_MAX, &errstr);
1629: if (errstr) {
1630: BIO_printf(err, "bad algorithm %s: %s\n",
1631: p + 1, errstr);
1632: return NULL;
1633: }
1634: *pkeylen = keylen;
1635: } else
1636: keylen = *pkeylen;
1637: } else if (p)
1638: paramfile = p + 1;
1639: }
1640:
1641: if (paramfile) {
1642: pbio = BIO_new_file(paramfile, "r");
1643: if (!pbio) {
1644: BIO_printf(err, "Can't open parameter file %s\n",
1645: paramfile);
1646: return NULL;
1647: }
1648: param = PEM_read_bio_Parameters(pbio, NULL);
1649:
1650: if (!param) {
1651: X509 *x;
1652: (void) BIO_reset(pbio);
1653: x = PEM_read_bio_X509(pbio, NULL, NULL, NULL);
1654: if (x) {
1655: param = X509_get_pubkey(x);
1656: X509_free(x);
1657: }
1658: }
1659: BIO_free(pbio);
1660:
1661: if (!param) {
1662: BIO_printf(err, "Error reading parameter file %s\n",
1663: paramfile);
1664: return NULL;
1665: }
1666: if (*pkey_type == -1)
1667: *pkey_type = EVP_PKEY_id(param);
1668: else if (*pkey_type != EVP_PKEY_base_id(param)) {
1669: BIO_printf(err, "Key Type does not match parameters\n");
1670: EVP_PKEY_free(param);
1671: return NULL;
1672: }
1673: }
1674: if (palgnam) {
1675: const EVP_PKEY_ASN1_METHOD *ameth;
1676: const char *anam;
1.7 bcook 1677: ameth = EVP_PKEY_asn1_find(NULL, *pkey_type);
1.1 jsing 1678: if (!ameth) {
1679: BIO_puts(err, "Internal error: can't find key algorithm\n");
1680: return NULL;
1681: }
1682: EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, &anam, ameth);
1.4 jsing 1683: *palgnam = strdup(anam);
1.1 jsing 1684: }
1685: if (param) {
1.7 bcook 1686: gctx = EVP_PKEY_CTX_new(param, NULL);
1.1 jsing 1687: *pkeylen = EVP_PKEY_bits(param);
1688: EVP_PKEY_free(param);
1689: } else
1.7 bcook 1690: gctx = EVP_PKEY_CTX_new_id(*pkey_type, NULL);
1.1 jsing 1691:
1692: if (!gctx) {
1693: BIO_puts(err, "Error allocating keygen context\n");
1694: ERR_print_errors(err);
1695: return NULL;
1696: }
1697: if (EVP_PKEY_keygen_init(gctx) <= 0) {
1698: BIO_puts(err, "Error initializing keygen context\n");
1699: ERR_print_errors(err);
1700: return NULL;
1701: }
1702: if ((*pkey_type == EVP_PKEY_RSA) && (keylen != -1)) {
1703: if (EVP_PKEY_CTX_set_rsa_keygen_bits(gctx, keylen) <= 0) {
1704: BIO_puts(err, "Error setting RSA keysize\n");
1705: ERR_print_errors(err);
1706: EVP_PKEY_CTX_free(gctx);
1707: return NULL;
1708: }
1709: }
1710:
1711: return gctx;
1712: }
1713:
1714: static int
1715: genpkey_cb(EVP_PKEY_CTX * ctx)
1716: {
1717: char c = '*';
1718: BIO *b = EVP_PKEY_CTX_get_app_data(ctx);
1719: int p;
1720: p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
1721: if (p == 0)
1722: c = '.';
1723: if (p == 1)
1724: c = '+';
1725: if (p == 2)
1726: c = '*';
1727: if (p == 3)
1728: c = '\n';
1729: BIO_write(b, &c, 1);
1730: (void) BIO_flush(b);
1731: return 1;
1732: }
1733:
1734: static int
1735: do_sign_init(BIO * err, EVP_MD_CTX * ctx, EVP_PKEY * pkey,
1736: const EVP_MD * md, STACK_OF(OPENSSL_STRING) * sigopts)
1737: {
1738: EVP_PKEY_CTX *pkctx = NULL;
1739: int i;
1740: EVP_MD_CTX_init(ctx);
1741: if (!EVP_DigestSignInit(ctx, &pkctx, md, NULL, pkey))
1742: return 0;
1743: for (i = 0; i < sk_OPENSSL_STRING_num(sigopts); i++) {
1744: char *sigopt = sk_OPENSSL_STRING_value(sigopts, i);
1745: if (pkey_ctrl_string(pkctx, sigopt) <= 0) {
1746: BIO_printf(err, "parameter error \"%s\"\n", sigopt);
1747: ERR_print_errors(bio_err);
1748: return 0;
1749: }
1750: }
1751: return 1;
1752: }
1753:
1754: int
1755: do_X509_sign(BIO * err, X509 * x, EVP_PKEY * pkey, const EVP_MD * md,
1756: STACK_OF(OPENSSL_STRING) * sigopts)
1757: {
1.22 tb 1758: EVP_MD_CTX *mctx;
1.1 jsing 1759: int rv;
1.22 tb 1760:
1761: if ((mctx = EVP_MD_CTX_new()) == NULL)
1762: return 0;
1763:
1764: rv = do_sign_init(err, mctx, pkey, md, sigopts);
1.1 jsing 1765: if (rv > 0)
1.22 tb 1766: rv = X509_sign_ctx(x, mctx);
1767:
1768: EVP_MD_CTX_free(mctx);
1769:
1770: return rv > 0;
1.1 jsing 1771: }
1772:
1773:
1774: int
1775: do_X509_REQ_sign(BIO * err, X509_REQ * x, EVP_PKEY * pkey, const EVP_MD * md,
1776: STACK_OF(OPENSSL_STRING) * sigopts)
1777: {
1.22 tb 1778: EVP_MD_CTX *mctx;
1.1 jsing 1779: int rv;
1.22 tb 1780:
1781: if ((mctx = EVP_MD_CTX_new()) == NULL)
1782: return 0;
1783:
1784: rv = do_sign_init(err, mctx, pkey, md, sigopts);
1.1 jsing 1785: if (rv > 0)
1.22 tb 1786: rv = X509_REQ_sign_ctx(x, mctx);
1787:
1788: EVP_MD_CTX_free(mctx);
1789:
1790: return rv > 0;
1.1 jsing 1791: }
1792:
1793:
1794:
1795: int
1796: do_X509_CRL_sign(BIO * err, X509_CRL * x, EVP_PKEY * pkey, const EVP_MD * md,
1797: STACK_OF(OPENSSL_STRING) * sigopts)
1798: {
1799: int rv;
1.22 tb 1800: EVP_MD_CTX *mctx;
1801:
1802: if ((mctx = EVP_MD_CTX_new()) == NULL)
1803: return 0;
1804:
1805: rv = do_sign_init(err, mctx, pkey, md, sigopts);
1.1 jsing 1806: if (rv > 0)
1.22 tb 1807: rv = X509_CRL_sign_ctx(x, mctx);
1808:
1809: EVP_MD_CTX_free(mctx);
1810:
1811: return rv > 0;
1.17 inoguchi 1812: }
1813:
1814: static unsigned long
1815: ext_name_hash(const OPENSSL_STRING *a)
1816: {
1817: return lh_strhash((const char *)a);
1818: }
1819:
1820: static int
1821: ext_name_cmp(const OPENSSL_STRING *a, const OPENSSL_STRING *b)
1822: {
1823: return strcmp((const char *)a, (const char *)b);
1824: }
1825:
1826: static void
1827: exts_cleanup(OPENSSL_STRING *x)
1828: {
1829: free((char *)x);
1830: }
1831:
1832: /*
1833: * Is the |kv| key already duplicated ? This is remarkably tricky to get right.
1834: * Return 0 if unique, -1 on runtime error; 1 if found or a syntax error.
1835: */
1836: static int
1837: duplicated(LHASH_OF(OPENSSL_STRING) *addexts, char *kv)
1838: {
1839: char *p;
1840: size_t off;
1841:
1842: /* Check syntax. */
1843: /* Skip leading whitespace, make a copy. */
1844: while (*kv && isspace(*kv))
1845: if (*++kv == '\0')
1846: return 1;
1847: if ((p = strchr(kv, '=')) == NULL)
1848: return 1;
1849: off = p - kv;
1850: if ((kv = strdup(kv)) == NULL)
1851: return -1;
1852:
1853: /* Skip trailing space before the equal sign. */
1854: for (p = kv + off; p > kv; --p)
1855: if (!isspace(p[-1]))
1856: break;
1857: if (p == kv) {
1858: free(kv);
1859: return 1;
1860: }
1861: *p = '\0';
1862:
1863: /* See if "key" is there by attempting to add it. */
1864: if ((p = (char *)lh_OPENSSL_STRING_insert(addexts, (OPENSSL_STRING*)kv))
1865: != NULL || lh_OPENSSL_STRING_error(addexts)) {
1866: free(p != NULL ? p : kv);
1867: return -1;
1868: }
1869:
1870: return 0;
1.1 jsing 1871: }