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