Annotation of src/usr.bin/openssl/ca.c, Revision 1.58
1.58 ! tb 1: /* $OpenBSD: ca.c,v 1.57 2023/11/13 12:43:08 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: /* The PPKI stuff has been donated by Jeff Barber <jeffb@issl.atl.hp.com> */
60:
61: #include <sys/types.h>
62:
63: #include <ctype.h>
64: #include <stdio.h>
65: #include <stdlib.h>
66: #include <limits.h>
67: #include <string.h>
68: #include <unistd.h>
69:
70: #include "apps.h"
71:
72: #include <openssl/bio.h>
73: #include <openssl/bn.h>
74: #include <openssl/conf.h>
75: #include <openssl/err.h>
76: #include <openssl/evp.h>
77: #include <openssl/objects.h>
78: #include <openssl/ocsp.h>
79: #include <openssl/pem.h>
80: #include <openssl/txt_db.h>
81: #include <openssl/x509.h>
82: #include <openssl/x509v3.h>
83:
84: #define BASE_SECTION "ca"
85:
86: #define ENV_DEFAULT_CA "default_ca"
87:
88: #define STRING_MASK "string_mask"
89: #define UTF8_IN "utf8"
90:
91: #define ENV_NEW_CERTS_DIR "new_certs_dir"
92: #define ENV_CERTIFICATE "certificate"
93: #define ENV_SERIAL "serial"
94: #define ENV_CRLNUMBER "crlnumber"
95: #define ENV_PRIVATE_KEY "private_key"
96: #define ENV_DEFAULT_DAYS "default_days"
97: #define ENV_DEFAULT_STARTDATE "default_startdate"
98: #define ENV_DEFAULT_ENDDATE "default_enddate"
99: #define ENV_DEFAULT_CRL_DAYS "default_crl_days"
100: #define ENV_DEFAULT_CRL_HOURS "default_crl_hours"
101: #define ENV_DEFAULT_MD "default_md"
102: #define ENV_DEFAULT_EMAIL_DN "email_in_dn"
103: #define ENV_PRESERVE "preserve"
104: #define ENV_POLICY "policy"
105: #define ENV_EXTENSIONS "x509_extensions"
106: #define ENV_CRLEXT "crl_extensions"
107: #define ENV_MSIE_HACK "msie_hack"
108: #define ENV_NAMEOPT "name_opt"
109: #define ENV_CERTOPT "cert_opt"
110: #define ENV_EXTCOPY "copy_extensions"
111: #define ENV_UNIQUE_SUBJECT "unique_subject"
112:
113: #define ENV_DATABASE "database"
114:
115: /* Additional revocation information types */
116:
117: #define REV_NONE 0 /* No addditional information */
118: #define REV_CRL_REASON 1 /* Value is CRL reason code */
119: #define REV_HOLD 2 /* Value is hold instruction */
120: #define REV_KEY_COMPROMISE 3 /* Value is cert key compromise time */
121: #define REV_CA_COMPROMISE 4 /* Value is CA key compromise time */
122:
123: static void lookup_fail(const char *name, const char *tag);
1.31 inoguchi 124: static int certify(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
125: const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts,
126: STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, char *subj,
1.1 jsing 127: unsigned long chtype, int multirdn, int email_dn, char *startdate,
1.31 inoguchi 128: char *enddate, long days, int batch, char *ext_sect, CONF *conf,
1.1 jsing 129: int verbose, unsigned long certopt, unsigned long nameopt,
130: int default_op, int ext_copy, int selfsign);
1.31 inoguchi 131: static int certify_cert(X509 **xret, char *infile, EVP_PKEY *pkey,
132: X509 *x509, const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts,
133: STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, char *subj,
1.1 jsing 134: unsigned long chtype, int multirdn, int email_dn, char *startdate,
1.31 inoguchi 135: char *enddate, long days, int batch, char *ext_sect, CONF *conf,
1.1 jsing 136: int verbose, unsigned long certopt, unsigned long nameopt, int default_op,
1.12 bcook 137: int ext_copy);
1.31 inoguchi 138: static int certify_spkac(X509 **xret, char *infile, EVP_PKEY *pkey,
139: X509 *x509, const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts,
140: STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, char *subj,
1.1 jsing 141: unsigned long chtype, int multirdn, int email_dn, char *startdate,
1.31 inoguchi 142: char *enddate, long days, char *ext_sect, CONF *conf, int verbose,
1.1 jsing 143: unsigned long certopt, unsigned long nameopt, int default_op, int ext_copy);
1.36 inoguchi 144: static int write_new_certificate(BIO *bp, X509 *x, int output_der,
1.1 jsing 145: int notext);
1.31 inoguchi 146: static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509,
147: const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts,
148: STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, char *subj,
1.1 jsing 149: unsigned long chtype, int multirdn, int email_dn, char *startdate,
1.31 inoguchi 150: char *enddate, long days, int batch, int verbose, X509_REQ *req,
151: char *ext_sect, CONF *conf, unsigned long certopt, unsigned long nameopt,
1.1 jsing 152: int default_op, int ext_copy, int selfsign);
1.31 inoguchi 153: static int do_revoke(X509 *x509, CA_DB *db, int ext, char *extval);
154: static int get_certificate_status(const char *serial, CA_DB *db);
155: static int do_updatedb(CA_DB *db);
1.1 jsing 156: static int check_time_format(const char *str);
1.31 inoguchi 157: static char *bin2hex(unsigned char *, size_t);
1.1 jsing 158: char *make_revocation_str(int rev_type, char *rev_arg);
1.31 inoguchi 159: int make_revoked(X509_REVOKED *rev, const char *str);
160: int old_entry_print(BIO *bp, ASN1_OBJECT *obj, ASN1_STRING *str);
1.29 inoguchi 161:
1.1 jsing 162: static CONF *conf = NULL;
163: static CONF *extconf = NULL;
164:
1.29 inoguchi 165: static struct {
166: int batch;
167: char *certfile;
168: unsigned long chtype;
169: char *configfile;
1.30 inoguchi 170: int create_serial;
1.29 inoguchi 171: char *crl_ext;
172: long crldays;
173: long crlhours;
174: long crlsec;
175: long days;
176: int dorevoke;
177: int doupdatedb;
178: int email_dn;
179: char *enddate;
180: char *extensions;
181: char *extfile;
182: int gencrl;
183: char *infile;
184: char **infiles;
185: int infiles_num;
186: char *key;
187: char *keyfile;
188: int keyform;
189: char *md;
190: int multirdn;
191: int msie_hack;
192: int notext;
193: char *outdir;
194: char *outfile;
195: char *passargin;
196: char *policy;
197: int preserve;
198: int req;
199: char *rev_arg;
200: int rev_type;
1.30 inoguchi 201: char *serial_status;
1.29 inoguchi 202: char *section;
203: int selfsign;
1.31 inoguchi 204: STACK_OF(OPENSSL_STRING) *sigopts;
1.29 inoguchi 205: char *spkac_file;
206: char *ss_cert_file;
207: char *startdate;
208: char *subj;
209: int verbose;
1.55 tb 210: } cfg;
1.29 inoguchi 211:
212: static int
213: ca_opt_chtype_utf8(void)
214: {
1.55 tb 215: cfg.chtype = MBSTRING_UTF8;
1.29 inoguchi 216: return (0);
217: }
218:
219: static int
220: ca_opt_crl_ca_compromise(char *arg)
221: {
1.55 tb 222: cfg.rev_arg = arg;
223: cfg.rev_type = REV_CA_COMPROMISE;
1.29 inoguchi 224: return (0);
225: }
226:
227: static int
228: ca_opt_crl_compromise(char *arg)
229: {
1.55 tb 230: cfg.rev_arg = arg;
231: cfg.rev_type = REV_KEY_COMPROMISE;
1.29 inoguchi 232: return (0);
233: }
234:
235: static int
236: ca_opt_crl_hold(char *arg)
237: {
1.55 tb 238: cfg.rev_arg = arg;
239: cfg.rev_type = REV_HOLD;
1.29 inoguchi 240: return (0);
241: }
242:
243: static int
244: ca_opt_crl_reason(char *arg)
245: {
1.55 tb 246: cfg.rev_arg = arg;
247: cfg.rev_type = REV_CRL_REASON;
1.29 inoguchi 248: return (0);
249: }
1.1 jsing 250:
1.29 inoguchi 251: static int
252: ca_opt_in(char *arg)
253: {
1.55 tb 254: cfg.infile = arg;
255: cfg.req = 1;
1.29 inoguchi 256: return (0);
257: }
258:
259: static int
260: ca_opt_infiles(int argc, char **argv, int *argsused)
261: {
1.55 tb 262: cfg.infiles_num = argc - 1;
263: if (cfg.infiles_num < 1)
1.29 inoguchi 264: return (1);
1.55 tb 265: cfg.infiles = argv + 1;
266: cfg.req = 1;
1.29 inoguchi 267: *argsused = argc;
268: return (0);
269: }
270:
271: static int
272: ca_opt_revoke(char *arg)
273: {
1.55 tb 274: cfg.infile = arg;
275: cfg.dorevoke = 1;
1.29 inoguchi 276: return (0);
277: }
278:
279: static int
280: ca_opt_sigopt(char *arg)
281: {
1.55 tb 282: if (cfg.sigopts == NULL)
283: cfg.sigopts = sk_OPENSSL_STRING_new_null();
284: if (cfg.sigopts == NULL)
1.29 inoguchi 285: return (1);
1.55 tb 286: if (!sk_OPENSSL_STRING_push(cfg.sigopts, arg))
1.29 inoguchi 287: return (1);
288: return (0);
289: }
290:
291: static int
292: ca_opt_spkac(char *arg)
293: {
1.55 tb 294: cfg.spkac_file = arg;
295: cfg.req = 1;
1.29 inoguchi 296: return (0);
297: }
298:
299: static int
300: ca_opt_ss_cert(char *arg)
301: {
1.55 tb 302: cfg.ss_cert_file = arg;
303: cfg.req = 1;
1.29 inoguchi 304: return (0);
305: }
306:
307: static const struct option ca_options[] = {
308: {
309: .name = "batch",
310: .desc = "Operate in batch mode",
311: .type = OPTION_FLAG,
1.55 tb 312: .opt.flag = &cfg.batch,
1.29 inoguchi 313: },
314: {
315: .name = "cert",
316: .argname = "file",
317: .desc = "File containing the CA certificate",
318: .type = OPTION_ARG,
1.55 tb 319: .opt.arg = &cfg.certfile,
1.29 inoguchi 320: },
321: {
322: .name = "config",
323: .argname = "file",
324: .desc = "Specify an alternative configuration file",
325: .type = OPTION_ARG,
1.55 tb 326: .opt.arg = &cfg.configfile,
1.29 inoguchi 327: },
328: {
329: .name = "create_serial",
330: .desc = "If reading serial fails, create a new random serial",
331: .type = OPTION_FLAG,
1.55 tb 332: .opt.flag = &cfg.create_serial,
1.29 inoguchi 333: },
334: {
335: .name = "crl_CA_compromise",
336: .argname = "time",
337: .desc = "Set the compromise time and the revocation reason to\n"
338: "CACompromise",
339: .type = OPTION_ARG_FUNC,
340: .opt.argfunc = ca_opt_crl_ca_compromise,
341: },
342: {
343: .name = "crl_compromise",
344: .argname = "time",
345: .desc = "Set the compromise time and the revocation reason to\n"
346: "keyCompromise",
347: .type = OPTION_ARG_FUNC,
348: .opt.argfunc = ca_opt_crl_compromise,
349: },
350: {
351: .name = "crl_hold",
352: .argname = "instruction",
353: .desc = "Set the hold instruction and the revocation reason to\n"
354: "certificateHold",
355: .type = OPTION_ARG_FUNC,
356: .opt.argfunc = ca_opt_crl_hold,
357: },
358: {
359: .name = "crl_reason",
360: .argname = "reason",
361: .desc = "Revocation reason",
362: .type = OPTION_ARG_FUNC,
363: .opt.argfunc = ca_opt_crl_reason,
364: },
365: {
366: .name = "crldays",
367: .argname = "days",
368: .desc = "Number of days before the next CRL is due",
369: .type = OPTION_ARG_LONG,
1.55 tb 370: .opt.lvalue = &cfg.crldays,
1.29 inoguchi 371: },
372: {
373: .name = "crlexts",
374: .argname = "section",
375: .desc = "CRL extension section (override value in config file)",
376: .type = OPTION_ARG,
1.55 tb 377: .opt.arg = &cfg.crl_ext,
1.29 inoguchi 378: },
379: {
380: .name = "crlhours",
381: .argname = "hours",
382: .desc = "Number of hours before the next CRL is due",
383: .type = OPTION_ARG_LONG,
1.55 tb 384: .opt.lvalue = &cfg.crlhours,
1.29 inoguchi 385: },
386: {
387: .name = "crlsec",
388: .argname = "seconds",
389: .desc = "Number of seconds before the next CRL is due",
390: .type = OPTION_ARG_LONG,
1.55 tb 391: .opt.lvalue = &cfg.crlsec,
1.29 inoguchi 392: },
393: {
394: .name = "days",
395: .argname = "arg",
396: .desc = "Number of days to certify the certificate for",
397: .type = OPTION_ARG_LONG,
1.55 tb 398: .opt.lvalue = &cfg.days,
1.29 inoguchi 399: },
400: {
401: .name = "enddate",
402: .argname = "YYMMDDHHMMSSZ",
403: .desc = "Certificate validity notAfter (overrides -days)",
404: .type = OPTION_ARG,
1.55 tb 405: .opt.arg = &cfg.enddate,
1.29 inoguchi 406: },
407: {
408: .name = "extensions",
409: .argname = "section",
410: .desc = "Extension section (override value in config file)",
411: .type = OPTION_ARG,
1.55 tb 412: .opt.arg = &cfg.extensions,
1.29 inoguchi 413: },
414: {
415: .name = "extfile",
416: .argname = "file",
417: .desc = "Configuration file with X509v3 extentions to add",
418: .type = OPTION_ARG,
1.55 tb 419: .opt.arg = &cfg.extfile,
1.29 inoguchi 420: },
421: {
422: .name = "gencrl",
423: .desc = "Generate a new CRL",
424: .type = OPTION_FLAG,
1.55 tb 425: .opt.flag = &cfg.gencrl,
1.29 inoguchi 426: },
427: {
428: .name = "in",
429: .argname = "file",
430: .desc = "Input file containing a single certificate request",
431: .type = OPTION_ARG_FUNC,
432: .opt.argfunc = ca_opt_in,
433: },
434: {
435: .name = "infiles",
436: .argname = "...",
437: .desc = "The last argument, certificate requests to process",
438: .type = OPTION_ARGV_FUNC,
439: .opt.argvfunc = ca_opt_infiles,
440: },
441: {
442: .name = "key",
443: .argname = "password",
444: .desc = "Key to decode the private key if it is encrypted",
445: .type = OPTION_ARG,
1.55 tb 446: .opt.arg = &cfg.key,
1.29 inoguchi 447: },
448: {
449: .name = "keyfile",
450: .argname = "file",
451: .desc = "Private key file",
452: .type = OPTION_ARG,
1.55 tb 453: .opt.arg = &cfg.keyfile,
1.29 inoguchi 454: },
455: {
456: .name = "keyform",
457: .argname = "fmt",
458: .desc = "Private key file format (DER or PEM (default))",
459: .type = OPTION_ARG_FORMAT,
1.55 tb 460: .opt.value = &cfg.keyform,
1.29 inoguchi 461: },
462: {
463: .name = "md",
464: .argname = "alg",
465: .desc = "Message digest to use",
466: .type = OPTION_ARG,
1.55 tb 467: .opt.arg = &cfg.md,
1.29 inoguchi 468: },
469: {
470: .name = "msie_hack",
471: .type = OPTION_FLAG,
1.55 tb 472: .opt.flag = &cfg.msie_hack,
1.29 inoguchi 473: },
474: {
475: .name = "multivalue-rdn",
476: .desc = "Enable support for multivalued RDNs",
477: .type = OPTION_FLAG,
1.55 tb 478: .opt.flag = &cfg.multirdn,
1.29 inoguchi 479: },
480: {
481: .name = "name",
482: .argname = "section",
483: .desc = "Specifies the configuration file section to use",
484: .type = OPTION_ARG,
1.55 tb 485: .opt.arg = &cfg.section,
1.29 inoguchi 486: },
487: {
488: .name = "noemailDN",
489: .desc = "Do not add the EMAIL field to the DN",
490: .type = OPTION_VALUE,
1.55 tb 491: .opt.value = &cfg.email_dn,
1.29 inoguchi 492: .value = 0,
493: },
494: {
495: .name = "notext",
496: .desc = "Do not print the generated certificate",
497: .type = OPTION_FLAG,
1.55 tb 498: .opt.flag = &cfg.notext,
1.29 inoguchi 499: },
500: {
501: .name = "out",
502: .argname = "file",
503: .desc = "Output file (default stdout)",
504: .type = OPTION_ARG,
1.55 tb 505: .opt.arg = &cfg.outfile,
1.29 inoguchi 506: },
507: {
508: .name = "outdir",
509: .argname = "directory",
510: .desc = " Directory to output certificates to",
511: .type = OPTION_ARG,
1.55 tb 512: .opt.arg = &cfg.outdir,
1.29 inoguchi 513: },
514: {
515: .name = "passin",
516: .argname = "src",
517: .desc = "Private key input password source",
518: .type = OPTION_ARG,
1.55 tb 519: .opt.arg = &cfg.passargin,
1.29 inoguchi 520: },
521: {
522: .name = "policy",
523: .argname = "name",
524: .desc = "The CA 'policy' to support",
525: .type = OPTION_ARG,
1.55 tb 526: .opt.arg = &cfg.policy,
1.29 inoguchi 527: },
528: {
529: .name = "preserveDN",
530: .desc = "Do not re-order the DN",
531: .type = OPTION_FLAG,
1.55 tb 532: .opt.flag = &cfg.preserve,
1.29 inoguchi 533: },
534: {
535: .name = "revoke",
536: .argname = "file",
537: .desc = "Revoke a certificate (given in file)",
538: .type = OPTION_ARG_FUNC,
539: .opt.argfunc = ca_opt_revoke,
540: },
541: {
542: .name = "selfsign",
543: .desc = "Sign a certificate using the key associated with it",
544: .type = OPTION_FLAG,
1.55 tb 545: .opt.flag = &cfg.selfsign,
1.29 inoguchi 546: },
547: {
548: .name = "sigopt",
549: .argname = "nm:v",
550: .desc = "Signature parameter in nm:v form",
551: .type = OPTION_ARG_FUNC,
552: .opt.argfunc = ca_opt_sigopt,
553: },
554: {
555: .name = "spkac",
556: .argname = "file",
557: .desc = "File contains DN and signed public key and challenge",
558: .type = OPTION_ARG_FUNC,
559: .opt.argfunc = ca_opt_spkac,
560: },
561: {
562: .name = "ss_cert",
563: .argname = "file",
564: .desc = "File contains a self signed certificate to sign",
565: .type = OPTION_ARG_FUNC,
566: .opt.argfunc = ca_opt_ss_cert,
567: },
568: {
569: .name = "startdate",
570: .argname = "YYMMDDHHMMSSZ",
571: .desc = "Certificate validity notBefore",
572: .type = OPTION_ARG,
1.55 tb 573: .opt.arg = &cfg.startdate,
1.29 inoguchi 574: },
575: {
576: .name = "status",
577: .argname = "serial",
578: .desc = "Shows certificate status given the serial number",
579: .type = OPTION_ARG,
1.55 tb 580: .opt.arg = &cfg.serial_status,
1.29 inoguchi 581: },
582: {
583: .name = "subj",
584: .argname = "arg",
585: .desc = "Use arg instead of request's subject",
586: .type = OPTION_ARG,
1.55 tb 587: .opt.arg = &cfg.subj,
1.29 inoguchi 588: },
589: {
590: .name = "updatedb",
591: .desc = "Updates db for expired certificates",
592: .type = OPTION_FLAG,
1.55 tb 593: .opt.flag = &cfg.doupdatedb,
1.29 inoguchi 594: },
595: {
596: .name = "utf8",
597: .desc = "Input characters are in UTF-8 (default ASCII)",
598: .type = OPTION_FUNC,
599: .opt.func = ca_opt_chtype_utf8,
600: },
601: {
602: .name = "verbose",
603: .desc = "Verbose output during processing",
604: .type = OPTION_FLAG,
1.55 tb 605: .opt.flag = &cfg.verbose,
1.29 inoguchi 606: },
607: { NULL },
608: };
1.1 jsing 609:
1.29 inoguchi 610: static void
611: ca_usage(void)
612: {
613: fprintf(stderr,
614: "usage: ca [-batch] [-cert file] [-config file] [-create_serial]\n"
615: " [-crl_CA_compromise time] [-crl_compromise time]\n"
616: " [-crl_hold instruction] [-crl_reason reason] [-crldays days]\n"
617: " [-crlexts section] [-crlhours hours] [-crlsec seconds]\n"
618: " [-days arg] [-enddate date] [-extensions section]\n"
619: " [-extfile file] [-gencrl] [-in file] [-infiles]\n"
620: " [-key password] [-keyfile file] [-keyform pem | der]\n"
621: " [-md alg] [-multivalue-rdn] [-name section]\n"
622: " [-noemailDN] [-notext] [-out file] [-outdir directory]\n"
623: " [-passin arg] [-policy name] [-preserveDN] [-revoke file]\n"
624: " [-selfsign] [-sigopt nm:v] [-spkac file] [-ss_cert file]\n"
625: " [-startdate date] [-status serial] [-subj arg] [-updatedb]\n"
626: " [-utf8] [-verbose]\n\n");
627: options_usage(ca_options);
628: fprintf(stderr, "\n");
629: }
630:
1.1 jsing 631: int
632: ca_main(int argc, char **argv)
633: {
634: int free_key = 0;
635: int total = 0;
636: int total_done = 0;
637: long errorline = -1;
638: EVP_PKEY *pkey = NULL;
639: int output_der = 0;
640: char *serialfile = NULL;
641: char *crlnumberfile = NULL;
642: char *tmp_email_dn = NULL;
643: BIGNUM *serial = NULL;
644: BIGNUM *crlnumber = NULL;
645: unsigned long nameopt = 0, certopt = 0;
646: int default_op = 1;
647: int ext_copy = EXT_COPY_NONE;
648: X509 *x509 = NULL, *x509p = NULL;
649: X509 *x = NULL;
650: BIO *in = NULL, *out = NULL, *Sout = NULL, *Cout = NULL;
651: char *dbfile = NULL;
652: CA_DB *db = NULL;
653: X509_CRL *crl = NULL;
654: X509_REVOKED *r = NULL;
1.39 inoguchi 655: ASN1_TIME *tmptm = NULL;
1.30 inoguchi 656: ASN1_INTEGER *tmpserial;
1.1 jsing 657: char *f;
658: const char *p;
1.31 inoguchi 659: char *const *pp;
1.1 jsing 660: int i, j;
661: const EVP_MD *dgst = NULL;
1.31 inoguchi 662: STACK_OF(CONF_VALUE) *attribs = NULL;
663: STACK_OF(X509) *cert_sk = NULL;
1.1 jsing 664: char *tofree = NULL;
665: DB_ATTR db_attr;
1.56 tb 666: int default_nid, rv;
667: int ret = 1;
1.17 doug 668:
1.54 joshua 669: if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
670: perror("pledge");
671: exit(1);
1.17 doug 672: }
1.1 jsing 673:
1.55 tb 674: memset(&cfg, 0, sizeof(cfg));
675: cfg.email_dn = 1;
676: cfg.keyform = FORMAT_PEM;
677: cfg.chtype = MBSTRING_ASC;
678: cfg.rev_type = REV_NONE;
1.29 inoguchi 679:
1.1 jsing 680: conf = NULL;
681:
1.29 inoguchi 682: if (options_parse(argc, argv, ca_options, NULL, NULL) != 0) {
683: ca_usage();
1.1 jsing 684: goto err;
685: }
686:
687: /*****************************************************************/
688: tofree = NULL;
1.55 tb 689: if (cfg.configfile == NULL)
690: cfg.configfile = getenv("OPENSSL_CONF");
691: if (cfg.configfile == NULL) {
1.1 jsing 692: if ((tofree = make_config_name()) == NULL) {
693: BIO_printf(bio_err, "error making config file name\n");
694: goto err;
695: }
1.55 tb 696: cfg.configfile = tofree;
1.1 jsing 697: }
1.33 inoguchi 698: BIO_printf(bio_err, "Using configuration from %s\n",
1.55 tb 699: cfg.configfile);
1.1 jsing 700: conf = NCONF_new(NULL);
1.55 tb 701: if (NCONF_load(conf, cfg.configfile, &errorline) <= 0) {
1.1 jsing 702: if (errorline <= 0)
703: BIO_printf(bio_err,
704: "error loading the config file '%s'\n",
1.55 tb 705: cfg.configfile);
1.1 jsing 706: else
707: BIO_printf(bio_err,
708: "error on line %ld of config file '%s'\n",
1.55 tb 709: errorline, cfg.configfile);
1.1 jsing 710: goto err;
711: }
712: free(tofree);
713: tofree = NULL;
714:
715: /* Lets get the config section we are using */
1.55 tb 716: if (cfg.section == NULL) {
717: cfg.section = NCONF_get_string(conf, BASE_SECTION,
1.33 inoguchi 718: ENV_DEFAULT_CA);
1.55 tb 719: if (cfg.section == NULL) {
1.1 jsing 720: lookup_fail(BASE_SECTION, ENV_DEFAULT_CA);
721: goto err;
722: }
723: }
724: if (conf != NULL) {
725: p = NCONF_get_string(conf, NULL, "oid_file");
726: if (p == NULL)
727: ERR_clear_error();
728: if (p != NULL) {
729: BIO *oid_bio;
730:
731: oid_bio = BIO_new_file(p, "r");
732: if (oid_bio == NULL) {
733: /*
734: BIO_printf(bio_err,
735: "problems opening %s for extra oid's\n", p);
736: ERR_print_errors(bio_err);
737: */
738: ERR_clear_error();
739: } else {
740: OBJ_create_objects(oid_bio);
741: BIO_free(oid_bio);
742: }
743: }
744: if (!add_oid_section(bio_err, conf)) {
745: ERR_print_errors(bio_err);
746: goto err;
747: }
748: }
1.55 tb 749: f = NCONF_get_string(conf, cfg.section, STRING_MASK);
1.32 inoguchi 750: if (f == NULL)
1.1 jsing 751: ERR_clear_error();
752:
1.32 inoguchi 753: if (f != NULL && !ASN1_STRING_set_default_mask_asc(f)) {
1.1 jsing 754: BIO_printf(bio_err,
755: "Invalid global string mask setting %s\n", f);
756: goto err;
757: }
1.55 tb 758: if (cfg.chtype != MBSTRING_UTF8) {
759: f = NCONF_get_string(conf, cfg.section, UTF8_IN);
1.32 inoguchi 760: if (f == NULL)
1.1 jsing 761: ERR_clear_error();
1.35 inoguchi 762: else if (strcmp(f, "yes") == 0)
1.55 tb 763: cfg.chtype = MBSTRING_UTF8;
1.1 jsing 764: }
765: db_attr.unique_subject = 1;
1.55 tb 766: p = NCONF_get_string(conf, cfg.section, ENV_UNIQUE_SUBJECT);
1.32 inoguchi 767: if (p != NULL) {
1.1 jsing 768: db_attr.unique_subject = parse_yesno(p, 1);
769: } else
770: ERR_clear_error();
771:
772: in = BIO_new(BIO_s_file());
773: out = BIO_new(BIO_s_file());
774: Sout = BIO_new(BIO_s_file());
775: Cout = BIO_new(BIO_s_file());
776: if ((in == NULL) || (out == NULL) || (Sout == NULL) || (Cout == NULL)) {
777: ERR_print_errors(bio_err);
778: goto err;
779: }
780: /*****************************************************************/
781: /* report status of cert with serial number given on command line */
1.55 tb 782: if (cfg.serial_status) {
783: if ((dbfile = NCONF_get_string(conf, cfg.section,
1.1 jsing 784: ENV_DATABASE)) == NULL) {
1.55 tb 785: lookup_fail(cfg.section, ENV_DATABASE);
1.1 jsing 786: goto err;
787: }
788: db = load_index(dbfile, &db_attr);
789: if (db == NULL)
790: goto err;
791:
792: if (!index_index(db))
793: goto err;
794:
1.55 tb 795: if (get_certificate_status(cfg.serial_status, db) != 1)
1.1 jsing 796: BIO_printf(bio_err, "Error verifying serial %s!\n",
1.55 tb 797: cfg.serial_status);
1.1 jsing 798: goto err;
799: }
800: /*****************************************************************/
801: /* we definitely need a private key, so let's get it */
802:
1.55 tb 803: if ((cfg.keyfile == NULL) &&
804: ((cfg.keyfile = NCONF_get_string(conf, cfg.section,
1.33 inoguchi 805: ENV_PRIVATE_KEY)) == NULL)) {
1.55 tb 806: lookup_fail(cfg.section, ENV_PRIVATE_KEY);
1.1 jsing 807: goto err;
808: }
1.55 tb 809: if (cfg.key == NULL) {
1.1 jsing 810: free_key = 1;
1.55 tb 811: if (!app_passwd(bio_err, cfg.passargin, NULL,
812: &cfg.key, NULL)) {
1.1 jsing 813: BIO_printf(bio_err, "Error getting password\n");
814: goto err;
815: }
816: }
1.55 tb 817: pkey = load_key(bio_err, cfg.keyfile, cfg.keyform, 0,
818: cfg.key, "CA private key");
819: if (cfg.key != NULL)
820: explicit_bzero(cfg.key, strlen(cfg.key));
1.1 jsing 821: if (pkey == NULL) {
822: /* load_key() has already printed an appropriate message */
823: goto err;
824: }
825: /*****************************************************************/
826: /* we need a certificate */
1.55 tb 827: if (!cfg.selfsign || cfg.spkac_file != NULL ||
828: cfg.ss_cert_file != NULL || cfg.gencrl) {
829: if ((cfg.certfile == NULL) &&
830: ((cfg.certfile = NCONF_get_string(conf,
831: cfg.section, ENV_CERTIFICATE)) == NULL)) {
832: lookup_fail(cfg.section, ENV_CERTIFICATE);
1.1 jsing 833: goto err;
834: }
1.55 tb 835: x509 = load_cert(bio_err, cfg.certfile, FORMAT_PEM, NULL,
1.1 jsing 836: "CA certificate");
837: if (x509 == NULL)
838: goto err;
839:
840: if (!X509_check_private_key(x509, pkey)) {
841: BIO_printf(bio_err,
842: "CA certificate and CA private key do not match\n");
843: goto err;
844: }
845: }
1.55 tb 846: if (!cfg.selfsign)
1.1 jsing 847: x509p = x509;
848:
849: f = NCONF_get_string(conf, BASE_SECTION, ENV_PRESERVE);
850: if (f == NULL)
851: ERR_clear_error();
852: if ((f != NULL) && ((*f == 'y') || (*f == 'Y')))
1.55 tb 853: cfg.preserve = 1;
1.1 jsing 854: f = NCONF_get_string(conf, BASE_SECTION, ENV_MSIE_HACK);
855: if (f == NULL)
856: ERR_clear_error();
857: if ((f != NULL) && ((*f == 'y') || (*f == 'Y')))
1.55 tb 858: cfg.msie_hack = 1;
1.1 jsing 859:
1.55 tb 860: f = NCONF_get_string(conf, cfg.section, ENV_NAMEOPT);
1.1 jsing 861:
1.34 inoguchi 862: if (f != NULL) {
1.1 jsing 863: if (!set_name_ex(&nameopt, f)) {
864: BIO_printf(bio_err,
865: "Invalid name options: \"%s\"\n", f);
866: goto err;
867: }
868: default_op = 0;
869: } else
870: ERR_clear_error();
871:
1.55 tb 872: f = NCONF_get_string(conf, cfg.section, ENV_CERTOPT);
1.1 jsing 873:
1.32 inoguchi 874: if (f != NULL) {
1.1 jsing 875: if (!set_cert_ex(&certopt, f)) {
876: BIO_printf(bio_err,
877: "Invalid certificate options: \"%s\"\n", f);
878: goto err;
879: }
880: default_op = 0;
881: } else
882: ERR_clear_error();
883:
1.55 tb 884: f = NCONF_get_string(conf, cfg.section, ENV_EXTCOPY);
1.1 jsing 885:
1.32 inoguchi 886: if (f != NULL) {
1.1 jsing 887: if (!set_ext_copy(&ext_copy, f)) {
888: BIO_printf(bio_err,
889: "Invalid extension copy option: \"%s\"\n", f);
890: goto err;
891: }
892: } else
893: ERR_clear_error();
894:
895: /*****************************************************************/
896: /* lookup where to write new certificates */
1.55 tb 897: if (cfg.outdir == NULL && cfg.req) {
898: if ((cfg.outdir = NCONF_get_string(conf,
899: cfg.section, ENV_NEW_CERTS_DIR)) == NULL) {
1.22 deraadt 900: BIO_printf(bio_err, "output directory %s not defined\n",
901: ENV_NEW_CERTS_DIR);
1.1 jsing 902: goto err;
903: }
904: }
905: /*****************************************************************/
906: /* we need to load the database file */
1.55 tb 907: if ((dbfile = NCONF_get_string(conf, cfg.section,
1.33 inoguchi 908: ENV_DATABASE)) == NULL) {
1.55 tb 909: lookup_fail(cfg.section, ENV_DATABASE);
1.1 jsing 910: goto err;
911: }
912: db = load_index(dbfile, &db_attr);
913: if (db == NULL)
914: goto err;
915:
916: /* Lets check some fields */
917: for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
918: pp = sk_OPENSSL_PSTRING_value(db->db->data, i);
919: if ((pp[DB_type][0] != DB_TYPE_REV) &&
920: (pp[DB_rev_date][0] != '\0')) {
1.33 inoguchi 921: BIO_printf(bio_err,
922: "entry %d: not revoked yet, but has a revocation date\n",
923: i + 1);
1.1 jsing 924: goto err;
925: }
926: if ((pp[DB_type][0] == DB_TYPE_REV) &&
927: !make_revoked(NULL, pp[DB_rev_date])) {
928: BIO_printf(bio_err, " in entry %d\n", i + 1);
929: goto err;
930: }
931: if (!check_time_format((char *) pp[DB_exp_date])) {
932: BIO_printf(bio_err, "entry %d: invalid expiry date\n",
933: i + 1);
934: goto err;
935: }
936: p = pp[DB_serial];
937: j = strlen(p);
938: if (*p == '-') {
939: p++;
940: j--;
941: }
942: if ((j & 1) || (j < 2)) {
943: BIO_printf(bio_err,
944: "entry %d: bad serial number length (%d)\n",
945: i + 1, j);
946: goto err;
947: }
948: while (*p) {
949: if (!(((*p >= '0') && (*p <= '9')) ||
950: ((*p >= 'A') && (*p <= 'F')) ||
951: ((*p >= 'a') && (*p <= 'f')))) {
1.33 inoguchi 952: BIO_printf(bio_err,
953: "entry %d: bad serial number characters, char pos %ld, char is '%c'\n",
954: i + 1, (long) (p - pp[DB_serial]), *p);
1.1 jsing 955: goto err;
956: }
957: p++;
958: }
959: }
1.55 tb 960: if (cfg.verbose) {
1.33 inoguchi 961: BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT);
1.1 jsing 962: TXT_DB_write(out, db->db);
963: BIO_printf(bio_err, "%d entries loaded from the database\n",
964: sk_OPENSSL_PSTRING_num(db->db->data));
965: BIO_printf(bio_err, "generating index\n");
966: }
967: if (!index_index(db))
968: goto err;
969:
970: /*****************************************************************/
971: /* Update the db file for expired certificates */
1.55 tb 972: if (cfg.doupdatedb) {
973: if (cfg.verbose)
1.1 jsing 974: BIO_printf(bio_err, "Updating %s ...\n", dbfile);
975:
976: i = do_updatedb(db);
977: if (i == -1) {
978: BIO_printf(bio_err, "Malloc failure\n");
979: goto err;
980: } else if (i == 0) {
1.55 tb 981: if (cfg.verbose)
1.1 jsing 982: BIO_printf(bio_err,
983: "No entries found to mark expired\n");
984: } else {
985: if (!save_index(dbfile, "new", db))
986: goto err;
987:
988: if (!rotate_index(dbfile, "new", "old"))
989: goto err;
990:
1.55 tb 991: if (cfg.verbose)
1.1 jsing 992: BIO_printf(bio_err,
993: "Done. %d entries marked as expired\n", i);
994: }
995: }
996: /*****************************************************************/
997: /* Read extentions config file */
1.55 tb 998: if (cfg.extfile != NULL) {
1.1 jsing 999: extconf = NCONF_new(NULL);
1.55 tb 1000: if (NCONF_load(extconf, cfg.extfile, &errorline) <= 0) {
1.1 jsing 1001: if (errorline <= 0)
1002: BIO_printf(bio_err,
1003: "ERROR: loading the config file '%s'\n",
1.55 tb 1004: cfg.extfile);
1.1 jsing 1005: else
1006: BIO_printf(bio_err,
1007: "ERROR: on line %ld of config file '%s'\n",
1.55 tb 1008: errorline, cfg.extfile);
1.1 jsing 1009: ret = 1;
1010: goto err;
1011: }
1.55 tb 1012: if (cfg.verbose)
1.1 jsing 1013: BIO_printf(bio_err,
1014: "Successfully loaded extensions file %s\n",
1.55 tb 1015: cfg.extfile);
1.1 jsing 1016:
1017: /* We can have sections in the ext file */
1.55 tb 1018: if (cfg.extensions == NULL &&
1019: (cfg.extensions = NCONF_get_string(extconf, "default",
1.33 inoguchi 1020: "extensions")) == NULL)
1.55 tb 1021: cfg.extensions = "default";
1.1 jsing 1022: }
1023: /*****************************************************************/
1.55 tb 1024: if (cfg.req || cfg.gencrl) {
1025: if (cfg.outfile != NULL) {
1026: if (BIO_write_filename(Sout, cfg.outfile) <= 0) {
1027: perror(cfg.outfile);
1.1 jsing 1028: goto err;
1029: }
1030: } else {
1031: BIO_set_fp(Sout, stdout, BIO_NOCLOSE | BIO_FP_TEXT);
1032: }
1033: }
1.56 tb 1034:
1035: rv = EVP_PKEY_get_default_digest_nid(pkey, &default_nid);
1036: if (rv == 2 && default_nid == NID_undef) {
1037: /* The digest is required to be EVP_md_null() (EdDSA). */
1038: dgst = EVP_md_null();
1039: } else {
1040: /* Ignore rv unless we need a valid default_nid. */
1041: if (cfg.md == NULL)
1042: cfg.md = NCONF_get_string(conf, cfg.section,
1043: ENV_DEFAULT_MD);
1044: if (cfg.md == NULL) {
1045: lookup_fail(cfg.section, ENV_DEFAULT_MD);
1.1 jsing 1046: goto err;
1047: }
1.56 tb 1048: if (strcmp(cfg.md, "default") == 0) {
1049: if (rv <= 0) {
1050: BIO_puts(bio_err, "no default digest\n");
1051: goto err;
1052: }
1053: cfg.md = (char *)OBJ_nid2sn(default_nid);
1054: }
1.55 tb 1055: if (cfg.md == NULL)
1.36 inoguchi 1056: goto err;
1.56 tb 1057: if ((dgst = EVP_get_digestbyname(cfg.md)) == NULL) {
1058: BIO_printf(bio_err, "%s is an unsupported "
1059: "message digest type\n", cfg.md);
1060: goto err;
1061: }
1.1 jsing 1062: }
1.55 tb 1063: if (cfg.req) {
1064: if ((cfg.email_dn == 1) &&
1065: ((tmp_email_dn = NCONF_get_string(conf, cfg.section,
1.33 inoguchi 1066: ENV_DEFAULT_EMAIL_DN)) != NULL)) {
1.1 jsing 1067: if (strcmp(tmp_email_dn, "no") == 0)
1.55 tb 1068: cfg.email_dn = 0;
1.1 jsing 1069: }
1.55 tb 1070: if (cfg.verbose)
1.1 jsing 1071: BIO_printf(bio_err, "message digest is %s\n",
1.52 tb 1072: OBJ_nid2ln(EVP_MD_type(dgst)));
1.55 tb 1073: if ((cfg.policy == NULL) &&
1074: ((cfg.policy = NCONF_get_string(conf,
1075: cfg.section, ENV_POLICY)) == NULL)) {
1076: lookup_fail(cfg.section, ENV_POLICY);
1.1 jsing 1077: goto err;
1078: }
1.55 tb 1079: if (cfg.verbose)
1080: BIO_printf(bio_err, "policy is %s\n", cfg.policy);
1.1 jsing 1081:
1.55 tb 1082: if ((serialfile = NCONF_get_string(conf, cfg.section,
1.1 jsing 1083: ENV_SERIAL)) == NULL) {
1.55 tb 1084: lookup_fail(cfg.section, ENV_SERIAL);
1.1 jsing 1085: goto err;
1086: }
1.32 inoguchi 1087: if (extconf == NULL) {
1.1 jsing 1088: /*
1089: * no '-extfile' option, so we look for extensions in
1090: * the main configuration file
1091: */
1.55 tb 1092: if (cfg.extensions == NULL) {
1093: cfg.extensions = NCONF_get_string(conf,
1094: cfg.section, ENV_EXTENSIONS);
1095: if (cfg.extensions == NULL)
1.1 jsing 1096: ERR_clear_error();
1097: }
1.55 tb 1098: if (cfg.extensions != NULL) {
1.1 jsing 1099: /* Check syntax of file */
1100: X509V3_CTX ctx;
1101: X509V3_set_ctx_test(&ctx);
1102: X509V3_set_nconf(&ctx, conf);
1103: if (!X509V3_EXT_add_nconf(conf, &ctx,
1.55 tb 1104: cfg.extensions, NULL)) {
1.1 jsing 1105: BIO_printf(bio_err,
1106: "Error Loading extension section %s\n",
1.55 tb 1107: cfg.extensions);
1.1 jsing 1108: ret = 1;
1109: goto err;
1110: }
1111: }
1112: }
1.55 tb 1113: if (cfg.startdate == NULL) {
1114: cfg.startdate = NCONF_get_string(conf,
1115: cfg.section, ENV_DEFAULT_STARTDATE);
1116: if (cfg.startdate == NULL)
1.1 jsing 1117: ERR_clear_error();
1118: }
1.55 tb 1119: if (cfg.startdate == NULL)
1120: cfg.startdate = "today";
1.1 jsing 1121:
1.55 tb 1122: if (cfg.enddate == NULL) {
1123: cfg.enddate = NCONF_get_string(conf,
1124: cfg.section, ENV_DEFAULT_ENDDATE);
1125: if (cfg.enddate == NULL)
1.1 jsing 1126: ERR_clear_error();
1127: }
1.55 tb 1128: if (cfg.days == 0 && cfg.enddate == NULL) {
1129: if (!NCONF_get_number(conf, cfg.section,
1130: ENV_DEFAULT_DAYS, &cfg.days))
1131: cfg.days = 0;
1.1 jsing 1132: }
1.55 tb 1133: if (cfg.enddate == NULL && cfg.days == 0) {
1.1 jsing 1134: BIO_printf(bio_err,
1135: "cannot lookup how many days to certify for\n");
1136: goto err;
1137: }
1.55 tb 1138: if ((serial = load_serial(serialfile, cfg.create_serial,
1.33 inoguchi 1139: NULL)) == NULL) {
1.1 jsing 1140: BIO_printf(bio_err,
1141: "error while loading serial number\n");
1142: goto err;
1143: }
1.55 tb 1144: if (cfg.verbose) {
1.1 jsing 1145: if (BN_is_zero(serial))
1146: BIO_printf(bio_err,
1147: "next serial number is 00\n");
1148: else {
1149: if ((f = BN_bn2hex(serial)) == NULL)
1150: goto err;
1151: BIO_printf(bio_err,
1152: "next serial number is %s\n", f);
1153: free(f);
1154: }
1155: }
1.55 tb 1156: if ((attribs = NCONF_get_section(conf, cfg.policy)) ==
1.33 inoguchi 1157: NULL) {
1158: BIO_printf(bio_err, "unable to find 'section' for %s\n",
1.55 tb 1159: cfg.policy);
1.1 jsing 1160: goto err;
1161: }
1162: if ((cert_sk = sk_X509_new_null()) == NULL) {
1163: BIO_printf(bio_err, "Memory allocation failure\n");
1164: goto err;
1165: }
1.55 tb 1166: if (cfg.spkac_file != NULL) {
1.1 jsing 1167: total++;
1.55 tb 1168: j = certify_spkac(&x, cfg.spkac_file, pkey, x509,
1169: dgst, cfg.sigopts, attribs, db, serial,
1170: cfg.subj, cfg.chtype,
1171: cfg.multirdn, cfg.email_dn,
1172: cfg.startdate, cfg.enddate,
1173: cfg.days, cfg.extensions, conf,
1174: cfg.verbose, certopt, nameopt, default_op,
1.33 inoguchi 1175: ext_copy);
1.1 jsing 1176: if (j < 0)
1177: goto err;
1178: if (j > 0) {
1179: total_done++;
1180: BIO_printf(bio_err, "\n");
1181: if (!BN_add_word(serial, 1))
1182: goto err;
1183: if (!sk_X509_push(cert_sk, x)) {
1184: BIO_printf(bio_err,
1185: "Memory allocation failure\n");
1186: goto err;
1187: }
1.55 tb 1188: if (cfg.outfile != NULL) {
1.1 jsing 1189: output_der = 1;
1.55 tb 1190: cfg.batch = 1;
1.1 jsing 1191: }
1192: }
1193: }
1.55 tb 1194: if (cfg.ss_cert_file != NULL) {
1.1 jsing 1195: total++;
1.55 tb 1196: j = certify_cert(&x, cfg.ss_cert_file, pkey, x509,
1197: dgst, cfg.sigopts, attribs, db, serial,
1198: cfg.subj, cfg.chtype,
1199: cfg.multirdn, cfg.email_dn,
1200: cfg.startdate, cfg.enddate,
1201: cfg.days, cfg.batch,
1202: cfg.extensions, conf, cfg.verbose,
1.33 inoguchi 1203: certopt, nameopt, default_op, ext_copy);
1.1 jsing 1204: if (j < 0)
1205: goto err;
1206: if (j > 0) {
1207: total_done++;
1208: BIO_printf(bio_err, "\n");
1209: if (!BN_add_word(serial, 1))
1210: goto err;
1211: if (!sk_X509_push(cert_sk, x)) {
1212: BIO_printf(bio_err,
1213: "Memory allocation failure\n");
1214: goto err;
1215: }
1216: }
1217: }
1.55 tb 1218: if (cfg.infile != NULL) {
1.1 jsing 1219: total++;
1.55 tb 1220: j = certify(&x, cfg.infile, pkey, x509p, dgst,
1221: cfg.sigopts, attribs, db, serial,
1222: cfg.subj, cfg.chtype,
1223: cfg.multirdn, cfg.email_dn,
1224: cfg.startdate, cfg.enddate,
1225: cfg.days, cfg.batch,
1226: cfg.extensions, conf, cfg.verbose,
1.33 inoguchi 1227: certopt, nameopt, default_op, ext_copy,
1.55 tb 1228: cfg.selfsign);
1.1 jsing 1229: if (j < 0)
1230: goto err;
1231: if (j > 0) {
1232: total_done++;
1233: BIO_printf(bio_err, "\n");
1234: if (!BN_add_word(serial, 1))
1235: goto err;
1236: if (!sk_X509_push(cert_sk, x)) {
1237: BIO_printf(bio_err,
1238: "Memory allocation failure\n");
1239: goto err;
1240: }
1241: }
1242: }
1.55 tb 1243: for (i = 0; i < cfg.infiles_num; i++) {
1.1 jsing 1244: total++;
1.55 tb 1245: j = certify(&x, cfg.infiles[i], pkey, x509p, dgst,
1246: cfg.sigopts, attribs, db, serial,
1247: cfg.subj, cfg.chtype,
1248: cfg.multirdn, cfg.email_dn,
1249: cfg.startdate, cfg.enddate,
1250: cfg.days, cfg.batch,
1251: cfg.extensions, conf, cfg.verbose,
1.33 inoguchi 1252: certopt, nameopt, default_op, ext_copy,
1.55 tb 1253: cfg.selfsign);
1.1 jsing 1254: if (j < 0)
1255: goto err;
1256: if (j > 0) {
1257: total_done++;
1258: BIO_printf(bio_err, "\n");
1259: if (!BN_add_word(serial, 1))
1260: goto err;
1261: if (!sk_X509_push(cert_sk, x)) {
1262: BIO_printf(bio_err,
1263: "Memory allocation failure\n");
1264: goto err;
1265: }
1266: }
1267: }
1268: /*
1269: * we have a stack of newly certified certificates and a data
1270: * base and serial number that need updating
1271: */
1272:
1273: if (sk_X509_num(cert_sk) > 0) {
1.55 tb 1274: if (!cfg.batch) {
1.21 deraadt 1275: char answer[10];
1276:
1.33 inoguchi 1277: BIO_printf(bio_err,
1278: "\n%d out of %d certificate requests certified, commit? [y/n]",
1279: total_done, total);
1.1 jsing 1280: (void) BIO_flush(bio_err);
1.33 inoguchi 1281: if (fgets(answer, sizeof answer - 1, stdin) ==
1282: NULL) {
1283: BIO_printf(bio_err,
1284: "CERTIFICATION CANCELED: I/O error\n");
1.1 jsing 1285: ret = 0;
1286: goto err;
1287: }
1.21 deraadt 1288: if ((answer[0] != 'y') && (answer[0] != 'Y')) {
1.33 inoguchi 1289: BIO_printf(bio_err,
1290: "CERTIFICATION CANCELED\n");
1.1 jsing 1291: ret = 0;
1292: goto err;
1293: }
1294: }
1.33 inoguchi 1295: BIO_printf(bio_err,
1296: "Write out database with %d new entries\n",
1297: sk_X509_num(cert_sk));
1.1 jsing 1298:
1299: if (!save_serial(serialfile, "new", serial, NULL))
1300: goto err;
1301:
1302: if (!save_index(dbfile, "new", db))
1303: goto err;
1304: }
1.55 tb 1305: if (cfg.verbose)
1.1 jsing 1306: BIO_printf(bio_err, "writing new certificates\n");
1307: for (i = 0; i < sk_X509_num(cert_sk); i++) {
1.46 inoguchi 1308: ASN1_INTEGER *serialNumber;
1.1 jsing 1309: int k;
1.3 doug 1310: char *serialstr;
1.1 jsing 1311: unsigned char *data;
1.21 deraadt 1312: char pempath[PATH_MAX];
1.1 jsing 1313:
1314: x = sk_X509_value(cert_sk, i);
1315:
1.46 inoguchi 1316: serialNumber = X509_get_serialNumber(x);
1317: j = ASN1_STRING_length(serialNumber);
1318: data = ASN1_STRING_data(serialNumber);
1319:
1.1 jsing 1320: if (j > 0)
1.3 doug 1321: serialstr = bin2hex(data, j);
1.1 jsing 1322: else
1.3 doug 1323: serialstr = strdup("00");
1.32 inoguchi 1324: if (serialstr != NULL) {
1.21 deraadt 1325: k = snprintf(pempath, sizeof(pempath),
1.55 tb 1326: "%s/%s.pem", cfg.outdir, serialstr);
1.3 doug 1327: free(serialstr);
1.27 deraadt 1328: if (k < 0 || k >= sizeof(pempath)) {
1.1 jsing 1329: BIO_printf(bio_err,
1330: "certificate file name too long\n");
1331: goto err;
1332: }
1333: } else {
1334: BIO_printf(bio_err,
1335: "memory allocation failed\n");
1336: goto err;
1337: }
1.55 tb 1338: if (cfg.verbose)
1.21 deraadt 1339: BIO_printf(bio_err, "writing %s\n", pempath);
1.1 jsing 1340:
1.21 deraadt 1341: if (BIO_write_filename(Cout, pempath) <= 0) {
1342: perror(pempath);
1.1 jsing 1343: goto err;
1344: }
1.36 inoguchi 1345: if (!write_new_certificate(Cout, x, 0,
1.55 tb 1346: cfg.notext))
1.36 inoguchi 1347: goto err;
1348: if (!write_new_certificate(Sout, x, output_der,
1.55 tb 1349: cfg.notext))
1.36 inoguchi 1350: goto err;
1.1 jsing 1351: }
1352:
1353: if (sk_X509_num(cert_sk)) {
1354: /* Rename the database and the serial file */
1355: if (!rotate_serial(serialfile, "new", "old"))
1356: goto err;
1357:
1358: if (!rotate_index(dbfile, "new", "old"))
1359: goto err;
1360:
1361: BIO_printf(bio_err, "Data Base Updated\n");
1362: }
1363: }
1364: /*****************************************************************/
1.55 tb 1365: if (cfg.gencrl) {
1.1 jsing 1366: int crl_v2 = 0;
1.55 tb 1367: if (cfg.crl_ext == NULL) {
1368: cfg.crl_ext = NCONF_get_string(conf,
1369: cfg.section, ENV_CRLEXT);
1370: if (cfg.crl_ext == NULL)
1.1 jsing 1371: ERR_clear_error();
1372: }
1.55 tb 1373: if (cfg.crl_ext != NULL) {
1.1 jsing 1374: /* Check syntax of file */
1375: X509V3_CTX ctx;
1376: X509V3_set_ctx_test(&ctx);
1377: X509V3_set_nconf(&ctx, conf);
1.55 tb 1378: if (!X509V3_EXT_add_nconf(conf, &ctx, cfg.crl_ext,
1.33 inoguchi 1379: NULL)) {
1.1 jsing 1380: BIO_printf(bio_err,
1381: "Error Loading CRL extension section %s\n",
1.55 tb 1382: cfg.crl_ext);
1.1 jsing 1383: ret = 1;
1384: goto err;
1385: }
1386: }
1.55 tb 1387: if ((crlnumberfile = NCONF_get_string(conf, cfg.section,
1.1 jsing 1388: ENV_CRLNUMBER)) != NULL)
1389: if ((crlnumber = load_serial(crlnumberfile, 0,
1390: NULL)) == NULL) {
1391: BIO_printf(bio_err,
1392: "error while loading CRL number\n");
1393: goto err;
1394: }
1.55 tb 1395: if (!cfg.crldays && !cfg.crlhours &&
1396: !cfg.crlsec) {
1397: if (!NCONF_get_number(conf, cfg.section,
1398: ENV_DEFAULT_CRL_DAYS, &cfg.crldays))
1399: cfg.crldays = 0;
1400: if (!NCONF_get_number(conf, cfg.section,
1401: ENV_DEFAULT_CRL_HOURS, &cfg.crlhours))
1402: cfg.crlhours = 0;
1.1 jsing 1403: ERR_clear_error();
1404: }
1.55 tb 1405: if ((cfg.crldays == 0) && (cfg.crlhours == 0) &&
1406: (cfg.crlsec == 0)) {
1.33 inoguchi 1407: BIO_printf(bio_err,
1408: "cannot lookup how long until the next CRL is issued\n");
1.1 jsing 1409: goto err;
1410: }
1.55 tb 1411: if (cfg.verbose)
1.1 jsing 1412: BIO_printf(bio_err, "making CRL\n");
1413: if ((crl = X509_CRL_new()) == NULL)
1414: goto err;
1415: if (!X509_CRL_set_issuer_name(crl, X509_get_subject_name(x509)))
1416: goto err;
1417:
1.39 inoguchi 1418: if ((tmptm = X509_gmtime_adj(NULL, 0)) == NULL)
1.1 jsing 1419: goto err;
1.39 inoguchi 1420: if (!X509_CRL_set_lastUpdate(crl, tmptm))
1.36 inoguchi 1421: goto err;
1.55 tb 1422: if (X509_time_adj_ex(tmptm, cfg.crldays,
1423: cfg.crlhours * 60 * 60 + cfg.crlsec, NULL) ==
1.33 inoguchi 1424: NULL) {
1.1 jsing 1425: BIO_puts(bio_err, "error setting CRL nextUpdate\n");
1.36 inoguchi 1426: goto err;
1427: }
1.39 inoguchi 1428: if (!X509_CRL_set_nextUpdate(crl, tmptm))
1.1 jsing 1429: goto err;
1430: ASN1_TIME_free(tmptm);
1.39 inoguchi 1431: tmptm = NULL;
1.1 jsing 1432:
1433: for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
1434: pp = sk_OPENSSL_PSTRING_value(db->db->data, i);
1435: if (pp[DB_type][0] == DB_TYPE_REV) {
1436: if ((r = X509_REVOKED_new()) == NULL)
1437: goto err;
1438: j = make_revoked(r, pp[DB_rev_date]);
1439: if (!j)
1440: goto err;
1441: if (j == 2)
1442: crl_v2 = 1;
1443: if (!BN_hex2bn(&serial, pp[DB_serial]))
1444: goto err;
1.30 inoguchi 1445: tmpserial = BN_to_ASN1_INTEGER(serial, NULL);
1.1 jsing 1446: BN_free(serial);
1447: serial = NULL;
1.32 inoguchi 1448: if (tmpserial == NULL)
1.1 jsing 1449: goto err;
1.36 inoguchi 1450: if (!X509_REVOKED_set_serialNumber(r, tmpserial)) {
1451: ASN1_INTEGER_free(tmpserial);
1452: goto err;
1453: }
1.30 inoguchi 1454: ASN1_INTEGER_free(tmpserial);
1.36 inoguchi 1455: if (!X509_CRL_add0_revoked(crl, r))
1456: goto err;
1.37 inoguchi 1457: r = NULL;
1.1 jsing 1458: }
1459: }
1460:
1461: /*
1462: * sort the data so it will be written in serial number order
1463: */
1464: X509_CRL_sort(crl);
1465:
1466: /* we now have a CRL */
1.55 tb 1467: if (cfg.verbose)
1.1 jsing 1468: BIO_printf(bio_err, "signing CRL\n");
1469:
1470: /* Add any extensions asked for */
1471:
1.55 tb 1472: if (cfg.crl_ext != NULL || crlnumberfile != NULL) {
1.1 jsing 1473: X509V3_CTX crlctx;
1474: X509V3_set_ctx(&crlctx, x509, NULL, NULL, crl, 0);
1475: X509V3_set_nconf(&crlctx, conf);
1476:
1.55 tb 1477: if (cfg.crl_ext != NULL)
1.1 jsing 1478: if (!X509V3_EXT_CRL_add_nconf(conf, &crlctx,
1.55 tb 1479: cfg.crl_ext, crl))
1.1 jsing 1480: goto err;
1481: if (crlnumberfile != NULL) {
1.30 inoguchi 1482: tmpserial = BN_to_ASN1_INTEGER(crlnumber, NULL);
1.32 inoguchi 1483: if (tmpserial == NULL)
1.1 jsing 1484: goto err;
1.36 inoguchi 1485: if (!X509_CRL_add1_ext_i2d(crl, NID_crl_number,
1486: tmpserial, 0, 0)) {
1487: ASN1_INTEGER_free(tmpserial);
1488: goto err;
1489: }
1.30 inoguchi 1490: ASN1_INTEGER_free(tmpserial);
1.1 jsing 1491: crl_v2 = 1;
1492: if (!BN_add_word(crlnumber, 1))
1493: goto err;
1494: }
1495: }
1.55 tb 1496: if (cfg.crl_ext != NULL || crl_v2) {
1.1 jsing 1497: if (!X509_CRL_set_version(crl, 1))
1498: goto err; /* version 2 CRL */
1499: }
1500: if (crlnumberfile != NULL) /* we have a CRL number that
1501: * need updating */
1502: if (!save_serial(crlnumberfile, "new", crlnumber, NULL))
1503: goto err;
1504:
1.42 inoguchi 1505: BN_free(crlnumber);
1506: crlnumber = NULL;
1507:
1.33 inoguchi 1508: if (!do_X509_CRL_sign(bio_err, crl, pkey, dgst,
1.55 tb 1509: cfg.sigopts))
1.1 jsing 1510: goto err;
1511:
1.36 inoguchi 1512: if (!PEM_write_bio_X509_CRL(Sout, crl))
1513: goto err;
1.1 jsing 1514:
1515: if (crlnumberfile != NULL) /* Rename the crlnumber file */
1516: if (!rotate_serial(crlnumberfile, "new", "old"))
1517: goto err;
1518:
1519: }
1520: /*****************************************************************/
1.55 tb 1521: if (cfg.dorevoke) {
1522: if (cfg.infile == NULL) {
1.1 jsing 1523: BIO_printf(bio_err, "no input files\n");
1524: goto err;
1525: } else {
1526: X509 *revcert;
1.55 tb 1527: revcert = load_cert(bio_err, cfg.infile,
1528: FORMAT_PEM, NULL, cfg.infile);
1.1 jsing 1529: if (revcert == NULL)
1530: goto err;
1.55 tb 1531: j = do_revoke(revcert, db, cfg.rev_type,
1532: cfg.rev_arg);
1.1 jsing 1533: if (j <= 0)
1534: goto err;
1535: X509_free(revcert);
1536:
1537: if (!save_index(dbfile, "new", db))
1538: goto err;
1539:
1540: if (!rotate_index(dbfile, "new", "old"))
1541: goto err;
1542:
1543: BIO_printf(bio_err, "Data Base Updated\n");
1544: }
1545: }
1546: /*****************************************************************/
1547: ret = 0;
1548:
1.26 jsing 1549: err:
1.1 jsing 1550: free(tofree);
1551:
1552: BIO_free_all(Cout);
1553: BIO_free_all(Sout);
1554: BIO_free_all(out);
1555: BIO_free_all(in);
1556:
1.42 inoguchi 1557: sk_X509_pop_free(cert_sk, X509_free);
1.1 jsing 1558:
1559: if (ret)
1560: ERR_print_errors(bio_err);
1.42 inoguchi 1561: if (free_key)
1.55 tb 1562: free(cfg.key);
1.1 jsing 1563: BN_free(serial);
1564: BN_free(crlnumber);
1565: free_index(db);
1.55 tb 1566: sk_OPENSSL_STRING_free(cfg.sigopts);
1.1 jsing 1567: EVP_PKEY_free(pkey);
1.42 inoguchi 1568: X509_free(x509);
1.1 jsing 1569: X509_CRL_free(crl);
1.37 inoguchi 1570: X509_REVOKED_free(r);
1.39 inoguchi 1571: ASN1_TIME_free(tmptm);
1.1 jsing 1572: NCONF_free(conf);
1573: NCONF_free(extconf);
1574: OBJ_cleanup();
1575:
1576: return (ret);
1577: }
1578:
1579: static void
1580: lookup_fail(const char *name, const char *tag)
1581: {
1582: BIO_printf(bio_err, "variable lookup failed for %s::%s\n", name, tag);
1583: }
1584:
1585: static int
1.31 inoguchi 1586: certify(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
1587: const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts,
1588: STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, char *subj,
1.1 jsing 1589: unsigned long chtype, int multirdn, int email_dn, char *startdate,
1.31 inoguchi 1590: char *enddate, long days, int batch, char *ext_sect, CONF *lconf,
1.1 jsing 1591: int verbose, unsigned long certopt, unsigned long nameopt, int default_op,
1592: int ext_copy, int selfsign)
1593: {
1594: X509_REQ *req = NULL;
1595: BIO *in = NULL;
1596: EVP_PKEY *pktmp = NULL;
1597: int ok = -1, i;
1598:
1599: in = BIO_new(BIO_s_file());
1600:
1601: if (BIO_read_filename(in, infile) <= 0) {
1602: perror(infile);
1603: goto err;
1604: }
1605: if ((req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL)) == NULL) {
1606: BIO_printf(bio_err, "Error reading certificate request in %s\n",
1607: infile);
1608: goto err;
1609: }
1.36 inoguchi 1610: if (verbose) {
1611: if (!X509_REQ_print(bio_err, req))
1612: goto err;
1613: }
1.1 jsing 1614:
1615: BIO_printf(bio_err, "Check that the request matches the signature\n");
1616:
1617: if (selfsign && !X509_REQ_check_private_key(req, pkey)) {
1618: BIO_printf(bio_err,
1619: "Certificate request and CA private key do not match\n");
1620: ok = 0;
1621: goto err;
1622: }
1.53 tb 1623: if ((pktmp = X509_REQ_get0_pubkey(req)) == NULL) {
1.1 jsing 1624: BIO_printf(bio_err, "error unpacking public key\n");
1625: goto err;
1626: }
1627: i = X509_REQ_verify(req, pktmp);
1628: if (i < 0) {
1629: ok = 0;
1630: BIO_printf(bio_err, "Signature verification problems....\n");
1631: goto err;
1632: }
1633: if (i == 0) {
1634: ok = 0;
1635: BIO_printf(bio_err,
1636: "Signature did not match the certificate request\n");
1637: goto err;
1638: } else
1639: BIO_printf(bio_err, "Signature ok\n");
1640:
1641: ok = do_body(xret, pkey, x509, dgst, sigopts, policy, db, serial,
1642: subj, chtype, multirdn, email_dn, startdate, enddate, days, batch,
1643: verbose, req, ext_sect, lconf, certopt, nameopt, default_op,
1644: ext_copy, selfsign);
1645:
1.26 jsing 1646: err:
1.42 inoguchi 1647: X509_REQ_free(req);
1648: BIO_free(in);
1649:
1.1 jsing 1650: return (ok);
1651: }
1652:
1653: static int
1.31 inoguchi 1654: certify_cert(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
1655: const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts,
1656: STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, char *subj,
1.1 jsing 1657: unsigned long chtype, int multirdn, int email_dn, char *startdate,
1.31 inoguchi 1658: char *enddate, long days, int batch, char *ext_sect, CONF *lconf,
1.1 jsing 1659: int verbose, unsigned long certopt, unsigned long nameopt, int default_op,
1.12 bcook 1660: int ext_copy)
1.1 jsing 1661: {
1662: X509 *req = NULL;
1663: X509_REQ *rreq = NULL;
1664: EVP_PKEY *pktmp = NULL;
1665: int ok = -1, i;
1666:
1.12 bcook 1667: if ((req = load_cert(bio_err, infile, FORMAT_PEM, NULL,
1.1 jsing 1668: infile)) == NULL)
1669: goto err;
1.36 inoguchi 1670: if (verbose) {
1671: if (!X509_print(bio_err, req))
1672: goto err;
1673: }
1.1 jsing 1674:
1675: BIO_printf(bio_err, "Check that the request matches the signature\n");
1676:
1.53 tb 1677: if ((pktmp = X509_get0_pubkey(req)) == NULL) {
1.1 jsing 1678: BIO_printf(bio_err, "error unpacking public key\n");
1679: goto err;
1680: }
1681: i = X509_verify(req, pktmp);
1682: if (i < 0) {
1683: ok = 0;
1684: BIO_printf(bio_err, "Signature verification problems....\n");
1685: goto err;
1686: }
1687: if (i == 0) {
1688: ok = 0;
1689: BIO_printf(bio_err,
1690: "Signature did not match the certificate\n");
1691: goto err;
1692: } else
1693: BIO_printf(bio_err, "Signature ok\n");
1694:
1695: if ((rreq = X509_to_X509_REQ(req, NULL, EVP_md5())) == NULL)
1696: goto err;
1697:
1698: ok = do_body(xret, pkey, x509, dgst, sigopts, policy, db, serial,
1699: subj, chtype, multirdn, email_dn, startdate, enddate, days, batch,
1700: verbose, rreq, ext_sect, lconf, certopt, nameopt, default_op,
1701: ext_copy, 0);
1702:
1.26 jsing 1703: err:
1.42 inoguchi 1704: X509_REQ_free(rreq);
1705: X509_free(req);
1706:
1.1 jsing 1707: return (ok);
1708: }
1709:
1710: static int
1.31 inoguchi 1711: do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
1712: STACK_OF(OPENSSL_STRING) *sigopts, STACK_OF(CONF_VALUE) *policy,
1713: CA_DB *db, BIGNUM *serial, char *subj, unsigned long chtype, int multirdn,
1.1 jsing 1714: int email_dn, char *startdate, char *enddate, long days, int batch,
1.31 inoguchi 1715: int verbose, X509_REQ *req, char *ext_sect, CONF *lconf,
1.1 jsing 1716: unsigned long certopt, unsigned long nameopt, int default_op,
1717: int ext_copy, int selfsign)
1718: {
1.33 inoguchi 1719: X509_NAME *name = NULL, *CAname = NULL;
1720: X509_NAME *subject = NULL, *dn_subject = NULL;
1.49 inoguchi 1721: ASN1_UTCTIME *tm;
1.1 jsing 1722: ASN1_STRING *str, *str2;
1723: ASN1_OBJECT *obj;
1724: X509 *ret = NULL;
1725: X509_NAME_ENTRY *ne;
1726: X509_NAME_ENTRY *tne, *push;
1727: EVP_PKEY *pktmp;
1728: int ok = -1, i, j, last, nid;
1729: const char *p;
1730: CONF_VALUE *cv;
1731: OPENSSL_STRING row[DB_NUMBER];
1732: OPENSSL_STRING *irow = NULL;
1733: OPENSSL_STRING *rrow = NULL;
1.47 inoguchi 1734: const STACK_OF(X509_EXTENSION) *exts;
1.1 jsing 1735:
1.43 inoguchi 1736: *xret = NULL;
1737:
1.1 jsing 1738: for (i = 0; i < DB_NUMBER; i++)
1739: row[i] = NULL;
1740:
1.32 inoguchi 1741: if (subj != NULL) {
1.1 jsing 1742: X509_NAME *n = parse_name(subj, chtype, multirdn);
1743:
1.32 inoguchi 1744: if (n == NULL) {
1.1 jsing 1745: ERR_print_errors(bio_err);
1746: goto err;
1747: }
1.36 inoguchi 1748: if (!X509_REQ_set_subject_name(req, n)) {
1749: X509_NAME_free(n);
1750: goto err;
1751: }
1.1 jsing 1752: X509_NAME_free(n);
1753: }
1754: if (default_op)
1755: BIO_printf(bio_err,
1756: "The Subject's Distinguished Name is as follows\n");
1757:
1758: name = X509_REQ_get_subject_name(req);
1759: for (i = 0; i < X509_NAME_entry_count(name); i++) {
1760: ne = X509_NAME_get_entry(name, i);
1.36 inoguchi 1761: if (ne == NULL)
1762: goto err;
1.1 jsing 1763: str = X509_NAME_ENTRY_get_data(ne);
1.36 inoguchi 1764: if (str == NULL)
1765: goto err;
1.1 jsing 1766: obj = X509_NAME_ENTRY_get_object(ne);
1.36 inoguchi 1767: if (obj == NULL)
1768: goto err;
1.1 jsing 1769:
1.55 tb 1770: if (cfg.msie_hack) {
1.1 jsing 1771: /* assume all type should be strings */
1.51 tb 1772: nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(ne));
1.36 inoguchi 1773: if (nid == NID_undef)
1774: goto err;
1.1 jsing 1775:
1776: if (str->type == V_ASN1_UNIVERSALSTRING)
1777: ASN1_UNIVERSALSTRING_to_string(str);
1778:
1779: if ((str->type == V_ASN1_IA5STRING) &&
1780: (nid != NID_pkcs9_emailAddress))
1781: str->type = V_ASN1_T61STRING;
1782:
1783: if ((nid == NID_pkcs9_emailAddress) &&
1784: (str->type == V_ASN1_PRINTABLESTRING))
1785: str->type = V_ASN1_IA5STRING;
1786: }
1787: /* If no EMAIL is wanted in the subject */
1788: if ((OBJ_obj2nid(obj) == NID_pkcs9_emailAddress) && (!email_dn))
1789: continue;
1790:
1791: /* check some things */
1792: if ((OBJ_obj2nid(obj) == NID_pkcs9_emailAddress) &&
1793: (str->type != V_ASN1_IA5STRING)) {
1.33 inoguchi 1794: BIO_printf(bio_err,
1795: "\nemailAddress type needs to be of type IA5STRING\n");
1.1 jsing 1796: goto err;
1797: }
1798: if ((str->type != V_ASN1_BMPSTRING) &&
1799: (str->type != V_ASN1_UTF8STRING)) {
1800: j = ASN1_PRINTABLE_type(str->data, str->length);
1801: if (((j == V_ASN1_T61STRING) &&
1802: (str->type != V_ASN1_T61STRING)) ||
1803: ((j == V_ASN1_IA5STRING) &&
1804: (str->type == V_ASN1_PRINTABLESTRING))) {
1.33 inoguchi 1805: BIO_printf(bio_err,
1806: "\nThe string contains characters that are illegal for the ASN.1 type\n");
1.1 jsing 1807: goto err;
1808: }
1809: }
1810: if (default_op)
1811: old_entry_print(bio_err, obj, str);
1812: }
1813:
1814: /* Ok, now we check the 'policy' stuff. */
1815: if ((subject = X509_NAME_new()) == NULL) {
1816: BIO_printf(bio_err, "Memory allocation failure\n");
1817: goto err;
1818: }
1819: /* take a copy of the issuer name before we mess with it. */
1820: if (selfsign)
1821: CAname = X509_NAME_dup(name);
1822: else
1.46 inoguchi 1823: CAname = X509_NAME_dup(X509_get_subject_name(x509));
1.1 jsing 1824: if (CAname == NULL)
1825: goto err;
1826: str = str2 = NULL;
1827:
1828: for (i = 0; i < sk_CONF_VALUE_num(policy); i++) {
1829: cv = sk_CONF_VALUE_value(policy, i); /* get the object id */
1830: if ((j = OBJ_txt2nid(cv->name)) == NID_undef) {
1.33 inoguchi 1831: BIO_printf(bio_err,
1832: "%s:unknown object type in 'policy' configuration\n",
1833: cv->name);
1.1 jsing 1834: goto err;
1835: }
1836: obj = OBJ_nid2obj(j);
1.36 inoguchi 1837: if (obj == NULL)
1838: goto err;
1.1 jsing 1839:
1840: last = -1;
1841: for (;;) {
1842: /* lookup the object in the supplied name list */
1843: j = X509_NAME_get_index_by_OBJ(name, obj, last);
1844: if (j < 0) {
1845: if (last != -1)
1846: break;
1847: tne = NULL;
1848: } else {
1849: tne = X509_NAME_get_entry(name, j);
1.36 inoguchi 1850: if (tne == NULL)
1851: goto err;
1.1 jsing 1852: }
1853: last = j;
1854:
1855: /* depending on the 'policy', decide what to do. */
1856: push = NULL;
1857: if (strcmp(cv->value, "optional") == 0) {
1858: if (tne != NULL)
1859: push = tne;
1860: } else if (strcmp(cv->value, "supplied") == 0) {
1861: if (tne == NULL) {
1.33 inoguchi 1862: BIO_printf(bio_err,
1863: "The %s field needed to be supplied and was missing\n",
1864: cv->name);
1.1 jsing 1865: goto err;
1866: } else
1867: push = tne;
1868: } else if (strcmp(cv->value, "match") == 0) {
1869: int last2;
1870:
1871: if (tne == NULL) {
1.33 inoguchi 1872: BIO_printf(bio_err,
1873: "The mandatory %s field was missing\n",
1874: cv->name);
1.1 jsing 1875: goto err;
1876: }
1877: last2 = -1;
1878:
1.35 inoguchi 1879: again2:
1.33 inoguchi 1880: j = X509_NAME_get_index_by_OBJ(CAname, obj,
1881: last2);
1.1 jsing 1882: if ((j < 0) && (last2 == -1)) {
1.33 inoguchi 1883: BIO_printf(bio_err,
1884: "The %s field does not exist in the CA certificate,\nthe 'policy' is misconfigured\n",
1885: cv->name);
1.1 jsing 1886: goto err;
1887: }
1888: if (j >= 0) {
1889: push = X509_NAME_get_entry(CAname, j);
1.36 inoguchi 1890: if (push == NULL)
1891: goto err;
1.1 jsing 1892: str = X509_NAME_ENTRY_get_data(tne);
1.36 inoguchi 1893: if (str == NULL)
1894: goto err;
1.1 jsing 1895: str2 = X509_NAME_ENTRY_get_data(push);
1.36 inoguchi 1896: if (str2 == NULL)
1897: goto err;
1.1 jsing 1898: last2 = j;
1899: if (ASN1_STRING_cmp(str, str2) != 0)
1900: goto again2;
1901: }
1902: if (j < 0) {
1.33 inoguchi 1903: BIO_printf(bio_err,
1904: "The %s field needed to be the same in the\nCA certificate (%s) and the request (%s)\n",
1905: cv->name, ((str2 == NULL) ?
1906: "NULL" : (char *) str2->data),
1907: ((str == NULL) ?
1908: "NULL" : (char *) str->data));
1.1 jsing 1909: goto err;
1910: }
1911: } else {
1.33 inoguchi 1912: BIO_printf(bio_err,
1913: "%s:invalid type in 'policy' configuration\n",
1914: cv->value);
1.1 jsing 1915: goto err;
1916: }
1917:
1918: if (push != NULL) {
1919: if (!X509_NAME_add_entry(subject, push,
1920: -1, 0)) {
1.42 inoguchi 1921: X509_NAME_ENTRY_free(push);
1.1 jsing 1922: BIO_printf(bio_err,
1923: "Memory allocation failure\n");
1924: goto err;
1925: }
1926: }
1927: if (j < 0)
1928: break;
1929: }
1930: }
1931:
1.55 tb 1932: if (cfg.preserve) {
1.1 jsing 1933: X509_NAME_free(subject);
1934: /* subject=X509_NAME_dup(X509_REQ_get_subject_name(req)); */
1935: subject = X509_NAME_dup(name);
1936: if (subject == NULL)
1937: goto err;
1938: }
1939:
1940: /* We are now totally happy, lets make and sign the certificate */
1941: if (verbose)
1.33 inoguchi 1942: BIO_printf(bio_err,
1943: "Everything appears to be ok, creating and signing the certificate\n");
1.1 jsing 1944:
1945: if ((ret = X509_new()) == NULL)
1946: goto err;
1947:
1948: #ifdef X509_V3
1949: /* Make it an X509 v3 certificate. */
1950: if (!X509_set_version(ret, 2))
1951: goto err;
1952: #endif
1.46 inoguchi 1953: if (X509_get_serialNumber(ret) == NULL)
1.13 beck 1954: goto err;
1.46 inoguchi 1955: if (BN_to_ASN1_INTEGER(serial, X509_get_serialNumber(ret)) == NULL)
1.1 jsing 1956: goto err;
1957: if (selfsign) {
1958: if (!X509_set_issuer_name(ret, subject))
1959: goto err;
1960: } else {
1961: if (!X509_set_issuer_name(ret, X509_get_subject_name(x509)))
1962: goto err;
1963: }
1964:
1.36 inoguchi 1965: if (strcmp(startdate, "today") == 0) {
1966: if (X509_gmtime_adj(X509_get_notBefore(ret), 0) == NULL)
1967: goto err;
1.57 tb 1968: } else if (!ASN1_TIME_set_string_X509(X509_get_notBefore(ret), startdate)) {
1.38 inoguchi 1969: BIO_printf(bio_err, "Invalid start date %s\n", startdate);
1.24 beck 1970: goto err;
1971: }
1.1 jsing 1972:
1.36 inoguchi 1973: if (enddate == NULL) {
1974: if (X509_time_adj_ex(X509_get_notAfter(ret), days, 0,
1975: NULL) == NULL)
1976: goto err;
1.57 tb 1977: } else if (!ASN1_TIME_set_string_X509(X509_get_notAfter(ret), enddate)) {
1.38 inoguchi 1978: BIO_printf(bio_err, "Invalid end date %s\n", enddate);
1.24 beck 1979: goto err;
1980: }
1.1 jsing 1981:
1982: if (!X509_set_subject_name(ret, subject))
1983: goto err;
1984:
1.53 tb 1985: if ((pktmp = X509_REQ_get0_pubkey(req)) == NULL)
1.36 inoguchi 1986: goto err;
1987:
1.53 tb 1988: if (!X509_set_pubkey(ret, pktmp))
1.1 jsing 1989: goto err;
1990:
1991: /* Lets add the extensions, if there are any */
1.32 inoguchi 1992: if (ext_sect != NULL) {
1.1 jsing 1993: X509V3_CTX ctx;
1.36 inoguchi 1994:
1.1 jsing 1995: /* Initialize the context structure */
1996: if (selfsign)
1997: X509V3_set_ctx(&ctx, ret, ret, req, NULL, 0);
1998: else
1999: X509V3_set_ctx(&ctx, x509, ret, req, NULL, 0);
2000:
1.32 inoguchi 2001: if (extconf != NULL) {
1.1 jsing 2002: if (verbose)
2003: BIO_printf(bio_err,
2004: "Extra configuration file found\n");
2005:
2006: /* Use the extconf configuration db LHASH */
2007: X509V3_set_nconf(&ctx, extconf);
2008:
2009: /* Test the structure (needed?) */
2010: /* X509V3_set_ctx_test(&ctx); */
2011:
2012: /* Adds exts contained in the configuration file */
2013: if (!X509V3_EXT_add_nconf(extconf, &ctx,
2014: ext_sect, ret)) {
2015: BIO_printf(bio_err,
2016: "ERROR: adding extensions in section %s\n",
2017: ext_sect);
2018: ERR_print_errors(bio_err);
2019: goto err;
2020: }
2021: if (verbose)
1.33 inoguchi 2022: BIO_printf(bio_err,
2023: "Successfully added extensions from file.\n");
1.32 inoguchi 2024: } else if (ext_sect != NULL) {
1.1 jsing 2025: /* We found extensions to be set from config file */
2026: X509V3_set_nconf(&ctx, lconf);
2027:
2028: if (!X509V3_EXT_add_nconf(lconf, &ctx, ext_sect, ret)) {
2029: BIO_printf(bio_err,
2030: "ERROR: adding extensions in section %s\n",
2031: ext_sect);
2032: ERR_print_errors(bio_err);
2033: goto err;
2034: }
2035: if (verbose)
1.33 inoguchi 2036: BIO_printf(bio_err,
2037: "Successfully added extensions from config\n");
1.1 jsing 2038: }
2039: }
1.47 inoguchi 2040:
1.1 jsing 2041: /* Copy extensions from request (if any) */
2042: if (!copy_extensions(ret, req, ext_copy)) {
2043: BIO_printf(bio_err, "ERROR: adding extensions from request\n");
2044: ERR_print_errors(bio_err);
2045: goto err;
1.47 inoguchi 2046: }
2047:
2048: exts = X509_get0_extensions(ret);
2049: if (exts != NULL && sk_X509_EXTENSION_num(exts) > 0) {
2050: /* Make it an X509 v3 certificate. */
2051: if (!X509_set_version(ret, 2))
2052: goto err;
1.1 jsing 2053: }
1.44 inoguchi 2054:
2055: if (verbose)
2056: BIO_printf(bio_err,
2057: "The subject name appears to be ok, checking data base for clashes\n");
2058:
2059: /* Build the correct Subject if no email is wanted in the subject */
2060: if (!email_dn) {
2061: X509_NAME_ENTRY *tmpne;
2062: /*
2063: * Its best to dup the subject DN and then delete any email
2064: * addresses because this retains its structure.
2065: */
2066: if ((dn_subject = X509_NAME_dup(subject)) == NULL) {
2067: BIO_printf(bio_err, "Memory allocation failure\n");
2068: goto err;
2069: }
2070: while ((i = X509_NAME_get_index_by_NID(dn_subject,
2071: NID_pkcs9_emailAddress, -1)) >= 0) {
2072: tmpne = X509_NAME_get_entry(dn_subject, i);
2073: if (tmpne == NULL)
2074: goto err;
2075: if (X509_NAME_delete_entry(dn_subject, i) == NULL) {
2076: X509_NAME_ENTRY_free(tmpne);
2077: goto err;
2078: }
2079: X509_NAME_ENTRY_free(tmpne);
2080: }
2081:
1.1 jsing 2082: if (!X509_set_subject_name(ret, dn_subject))
2083: goto err;
1.44 inoguchi 2084:
2085: X509_NAME_free(dn_subject);
2086: dn_subject = NULL;
1.1 jsing 2087: }
1.44 inoguchi 2088:
2089: row[DB_name] = X509_NAME_oneline(X509_get_subject_name(ret), NULL, 0);
2090: if (row[DB_name] == NULL) {
2091: BIO_printf(bio_err, "Memory allocation failure\n");
2092: goto err;
2093: }
2094:
2095: if (BN_is_zero(serial))
2096: row[DB_serial] = strdup("00");
2097: else
2098: row[DB_serial] = BN_bn2hex(serial);
2099: if (row[DB_serial] == NULL) {
2100: BIO_printf(bio_err, "Memory allocation failure\n");
2101: goto err;
2102: }
1.48 inoguchi 2103:
2104: if (row[DB_name][0] == '\0') {
2105: /*
2106: * An empty subject! We'll use the serial number instead. If
2107: * unique_subject is in use then we don't want different
2108: * entries with empty subjects matching each other.
2109: */
2110: free(row[DB_name]);
2111: row[DB_name] = strdup(row[DB_serial]);
2112: if (row[DB_name] == NULL) {
2113: BIO_printf(bio_err, "Memory allocation failure\n");
2114: goto err;
2115: }
2116: }
2117:
1.44 inoguchi 2118: if (db->attributes.unique_subject) {
2119: OPENSSL_STRING *crow = row;
2120:
2121: rrow = TXT_DB_get_by_index(db->db, DB_name, crow);
2122: if (rrow != NULL) {
2123: BIO_printf(bio_err,
2124: "ERROR:There is already a certificate for %s\n",
2125: row[DB_name]);
2126: }
2127: }
2128: if (rrow == NULL) {
2129: rrow = TXT_DB_get_by_index(db->db, DB_serial, row);
2130: if (rrow != NULL) {
2131: BIO_printf(bio_err,
2132: "ERROR:Serial number %s has already been issued,\n",
2133: row[DB_serial]);
2134: BIO_printf(bio_err,
2135: " check the database/serial_file for corruption\n");
2136: }
2137: }
2138: if (rrow != NULL) {
2139: BIO_printf(bio_err,
2140: "The matching entry has the following details\n");
1.45 inoguchi 2141: if (rrow[DB_type][0] == DB_TYPE_EXP)
1.44 inoguchi 2142: p = "Expired";
1.45 inoguchi 2143: else if (rrow[DB_type][0] == DB_TYPE_REV)
1.44 inoguchi 2144: p = "Revoked";
1.45 inoguchi 2145: else if (rrow[DB_type][0] == DB_TYPE_VAL)
1.44 inoguchi 2146: p = "Valid";
2147: else
2148: p = "\ninvalid type, Data base error\n";
2149: BIO_printf(bio_err, "Type :%s\n", p);
1.45 inoguchi 2150: if (rrow[DB_type][0] == DB_TYPE_REV) {
1.44 inoguchi 2151: p = rrow[DB_exp_date];
2152: if (p == NULL)
2153: p = "undef";
2154: BIO_printf(bio_err, "Was revoked on:%s\n", p);
2155: }
2156: p = rrow[DB_exp_date];
2157: if (p == NULL)
2158: p = "undef";
2159: BIO_printf(bio_err, "Expires on :%s\n", p);
2160: p = rrow[DB_serial];
2161: if (p == NULL)
2162: p = "undef";
2163: BIO_printf(bio_err, "Serial Number :%s\n", p);
2164: p = rrow[DB_file];
2165: if (p == NULL)
2166: p = "undef";
2167: BIO_printf(bio_err, "File name :%s\n", p);
2168: p = rrow[DB_name];
2169: if (p == NULL)
2170: p = "undef";
2171: BIO_printf(bio_err, "Subject Name :%s\n", p);
2172: ok = -1; /* This is now a 'bad' error. */
2173: goto err;
2174: }
2175:
1.1 jsing 2176: if (!default_op) {
2177: BIO_printf(bio_err, "Certificate Details:\n");
2178: /*
2179: * Never print signature details because signature not
2180: * present
2181: */
2182: certopt |= X509_FLAG_NO_SIGDUMP | X509_FLAG_NO_SIGNAME;
1.36 inoguchi 2183: if (!X509_print_ex(bio_err, ret, nameopt, certopt))
2184: goto err;
1.1 jsing 2185: }
2186: BIO_printf(bio_err, "Certificate is to be certified until ");
2187: ASN1_TIME_print(bio_err, X509_get_notAfter(ret));
2188: if (days)
2189: BIO_printf(bio_err, " (%ld days)", days);
2190: BIO_printf(bio_err, "\n");
2191:
2192: if (!batch) {
1.21 deraadt 2193: char answer[25];
1.1 jsing 2194:
2195: BIO_printf(bio_err, "Sign the certificate? [y/n]:");
2196: (void) BIO_flush(bio_err);
1.21 deraadt 2197: if (!fgets(answer, sizeof(answer) - 1, stdin)) {
1.1 jsing 2198: BIO_printf(bio_err,
2199: "CERTIFICATE WILL NOT BE CERTIFIED: I/O error\n");
2200: ok = 0;
2201: goto err;
2202: }
1.21 deraadt 2203: if (!((answer[0] == 'y') || (answer[0] == 'Y'))) {
1.1 jsing 2204: BIO_printf(bio_err,
2205: "CERTIFICATE WILL NOT BE CERTIFIED\n");
2206: ok = 0;
2207: goto err;
2208: }
2209: }
1.36 inoguchi 2210:
1.53 tb 2211: if ((pktmp = X509_get0_pubkey(ret)) == NULL)
1.36 inoguchi 2212: goto err;
2213:
1.1 jsing 2214: if (EVP_PKEY_missing_parameters(pktmp) &&
1.36 inoguchi 2215: !EVP_PKEY_missing_parameters(pkey)) {
2216: if (!EVP_PKEY_copy_parameters(pktmp, pkey)) {
2217: goto err;
2218: }
2219: }
1.1 jsing 2220:
2221: if (!do_X509_sign(bio_err, ret, pkey, dgst, sigopts))
2222: goto err;
2223:
2224: /* We now just add it to the database */
2225: row[DB_type] = malloc(2);
2226:
1.41 inoguchi 2227: if ((tm = X509_get_notAfter(ret)) == NULL)
2228: goto err;
1.40 inoguchi 2229: row[DB_exp_date] = strndup(tm->data, tm->length);
1.16 bcook 2230: if (row[DB_type] == NULL || row[DB_exp_date] == NULL) {
1.13 beck 2231: BIO_printf(bio_err, "Memory allocation failure\n");
2232: goto err;
2233: }
2234:
1.1 jsing 2235: row[DB_rev_date] = NULL;
2236:
2237: /* row[DB_serial] done already */
2238: row[DB_file] = malloc(8);
2239:
1.13 beck 2240: if ((row[DB_type] == NULL) || (row[DB_file] == NULL) ||
2241: (row[DB_name] == NULL)) {
1.1 jsing 2242: BIO_printf(bio_err, "Memory allocation failure\n");
2243: goto err;
2244: }
2245: (void) strlcpy(row[DB_file], "unknown", 8);
1.45 inoguchi 2246: row[DB_type][0] = DB_TYPE_VAL;
1.1 jsing 2247: row[DB_type][1] = '\0';
2248:
2249: if ((irow = reallocarray(NULL, DB_NUMBER + 1, sizeof(char *))) ==
2250: NULL) {
2251: BIO_printf(bio_err, "Memory allocation failure\n");
2252: goto err;
2253: }
2254: for (i = 0; i < DB_NUMBER; i++) {
2255: irow[i] = row[i];
2256: row[i] = NULL;
2257: }
2258: irow[DB_NUMBER] = NULL;
2259:
2260: if (!TXT_DB_insert(db->db, irow)) {
2261: BIO_printf(bio_err, "failed to update database\n");
2262: BIO_printf(bio_err, "TXT_DB error number %ld\n", db->db->error);
2263: goto err;
2264: }
1.43 inoguchi 2265:
2266: *xret = ret;
2267: ret = NULL;
1.1 jsing 2268: ok = 1;
1.43 inoguchi 2269:
1.26 jsing 2270: err:
1.1 jsing 2271: for (i = 0; i < DB_NUMBER; i++)
2272: free(row[i]);
2273:
1.42 inoguchi 2274: X509_NAME_free(CAname);
2275: X509_NAME_free(subject);
1.44 inoguchi 2276: X509_NAME_free(dn_subject);
1.43 inoguchi 2277: X509_free(ret);
1.42 inoguchi 2278:
1.1 jsing 2279: return (ok);
2280: }
2281:
1.36 inoguchi 2282: static int
1.31 inoguchi 2283: write_new_certificate(BIO *bp, X509 *x, int output_der, int notext)
1.1 jsing 2284: {
2285: if (output_der) {
1.36 inoguchi 2286: if (!i2d_X509_bio(bp, x))
2287: return (0);
1.1 jsing 2288: }
1.36 inoguchi 2289: if (!notext) {
2290: if (!X509_print(bp, x))
2291: return (0);
2292: }
2293:
2294: return PEM_write_bio_X509(bp, x);
1.1 jsing 2295: }
2296:
2297: static int
1.31 inoguchi 2298: certify_spkac(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
2299: const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts,
2300: STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, char *subj,
1.1 jsing 2301: unsigned long chtype, int multirdn, int email_dn, char *startdate,
1.31 inoguchi 2302: char *enddate, long days, char *ext_sect, CONF *lconf, int verbose,
1.1 jsing 2303: unsigned long certopt, unsigned long nameopt, int default_op, int ext_copy)
2304: {
1.31 inoguchi 2305: STACK_OF(CONF_VALUE) *sk = NULL;
2306: LHASH_OF(CONF_VALUE) *parms = NULL;
1.1 jsing 2307: X509_REQ *req = NULL;
2308: CONF_VALUE *cv = NULL;
2309: NETSCAPE_SPKI *spki = NULL;
2310: char *type, *buf;
2311: EVP_PKEY *pktmp = NULL;
2312: X509_NAME *n = NULL;
2313: int ok = -1, i, j;
2314: long errline;
2315: int nid;
2316:
2317: /*
2318: * Load input file into a hash table. (This is just an easy
2319: * way to read and parse the file, then put it into a convenient
2320: * STACK format).
2321: */
2322: parms = CONF_load(NULL, infile, &errline);
2323: if (parms == NULL) {
2324: BIO_printf(bio_err, "error on line %ld of %s\n",
2325: errline, infile);
2326: ERR_print_errors(bio_err);
2327: goto err;
2328: }
2329: sk = CONF_get_section(parms, "default");
2330: if (sk_CONF_VALUE_num(sk) == 0) {
2331: BIO_printf(bio_err, "no name/value pairs found in %s\n",
2332: infile);
2333: CONF_free(parms);
2334: goto err;
2335: }
2336: /*
2337: * Now create a dummy X509 request structure. We don't actually
2338: * have an X509 request, but we have many of the components
2339: * (a public key, various DN components). The idea is that we
2340: * put these components into the right X509 request structure
2341: * and we can use the same code as if you had a real X509 request.
2342: */
2343: req = X509_REQ_new();
2344: if (req == NULL) {
2345: ERR_print_errors(bio_err);
2346: goto err;
2347: }
2348: /*
2349: * Build up the subject name set.
2350: */
1.51 tb 2351: n = X509_REQ_get_subject_name(req);
1.1 jsing 2352:
2353: for (i = 0;; i++) {
2354: if (sk_CONF_VALUE_num(sk) <= i)
2355: break;
2356:
2357: cv = sk_CONF_VALUE_value(sk, i);
2358: type = cv->name;
2359: /*
2360: * Skip past any leading X. X: X, etc to allow for multiple
2361: * instances
2362: */
2363: for (buf = cv->name; *buf; buf++) {
2364: if ((*buf == ':') || (*buf == ',') || (*buf == '.')) {
2365: buf++;
2366: if (*buf)
2367: type = buf;
2368: break;
2369: }
2370: }
2371:
2372: buf = cv->value;
2373: if ((nid = OBJ_txt2nid(type)) == NID_undef) {
2374: if (strcmp(type, "SPKAC") == 0) {
2375: spki = NETSCAPE_SPKI_b64_decode(cv->value, -1);
2376: if (spki == NULL) {
1.33 inoguchi 2377: BIO_printf(bio_err,
2378: "unable to load Netscape SPKAC structure\n");
1.1 jsing 2379: ERR_print_errors(bio_err);
2380: goto err;
2381: }
2382: }
2383: continue;
2384: }
2385: if (!X509_NAME_add_entry_by_NID(n, nid, chtype,
2386: (unsigned char *)buf, -1, -1, 0))
2387: goto err;
2388: }
2389: if (spki == NULL) {
2390: BIO_printf(bio_err,
2391: "Netscape SPKAC structure not found in %s\n", infile);
2392: goto err;
2393: }
2394: /*
2395: * Now extract the key from the SPKI structure.
2396: */
2397:
2398: BIO_printf(bio_err,
2399: "Check that the SPKAC request matches the signature\n");
2400:
2401: if ((pktmp = NETSCAPE_SPKI_get_pubkey(spki)) == NULL) {
2402: BIO_printf(bio_err, "error unpacking SPKAC public key\n");
2403: goto err;
2404: }
2405: j = NETSCAPE_SPKI_verify(spki, pktmp);
2406: if (j <= 0) {
2407: BIO_printf(bio_err,
2408: "signature verification failed on SPKAC public key\n");
2409: goto err;
2410: }
2411: BIO_printf(bio_err, "Signature ok\n");
2412:
1.36 inoguchi 2413: if (!X509_REQ_set_pubkey(req, pktmp)) {
2414: EVP_PKEY_free(pktmp);
2415: goto err;
2416: }
1.1 jsing 2417: EVP_PKEY_free(pktmp);
2418: ok = do_body(xret, pkey, x509, dgst, sigopts, policy, db, serial,
2419: subj, chtype, multirdn, email_dn, startdate, enddate, days, 1,
2420: verbose, req, ext_sect, lconf, certopt, nameopt, default_op,
2421: ext_copy, 0);
2422:
1.26 jsing 2423: err:
1.42 inoguchi 2424: X509_REQ_free(req);
2425: CONF_free(parms);
2426: NETSCAPE_SPKI_free(spki);
1.1 jsing 2427:
2428: return (ok);
2429: }
2430:
2431: static int
2432: check_time_format(const char *str)
2433: {
2434: return ASN1_TIME_set_string(NULL, str);
2435: }
2436:
2437: static int
1.31 inoguchi 2438: do_revoke(X509 *x509, CA_DB *db, int type, char *value)
1.1 jsing 2439: {
2440: ASN1_UTCTIME *tm = NULL;
2441: char *row[DB_NUMBER], **rrow, **irow;
2442: char *rev_str = NULL;
2443: BIGNUM *bn = NULL;
2444: int ok = -1, i;
2445:
2446: for (i = 0; i < DB_NUMBER; i++)
2447: row[i] = NULL;
2448: row[DB_name] = X509_NAME_oneline(X509_get_subject_name(x509), NULL, 0);
2449: bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(x509), NULL);
1.32 inoguchi 2450: if (bn == NULL)
1.1 jsing 2451: goto err;
2452: if (BN_is_zero(bn))
2453: row[DB_serial] = strdup("00");
2454: else
2455: row[DB_serial] = BN_bn2hex(bn);
2456: BN_free(bn);
1.48 inoguchi 2457:
2458: if (row[DB_name] != NULL && row[DB_name][0] == '\0') {
2459: /*
2460: * Entries with empty Subjects actually use the serial number
2461: * instead
2462: */
2463: free(row[DB_name]);
2464: row[DB_name] = strdup(row[DB_serial]);
2465: if (row[DB_name] == NULL) {
2466: BIO_printf(bio_err, "Memory allocation failure\n");
2467: goto err;
2468: }
2469: }
2470:
1.1 jsing 2471: if ((row[DB_name] == NULL) || (row[DB_serial] == NULL)) {
2472: BIO_printf(bio_err, "Memory allocation failure\n");
2473: goto err;
2474: }
2475: /*
2476: * We have to lookup by serial number because name lookup skips
2477: * revoked certs
2478: */
2479: rrow = TXT_DB_get_by_index(db->db, DB_serial, row);
2480: if (rrow == NULL) {
2481: BIO_printf(bio_err,
2482: "Adding Entry with serial number %s to DB for %s\n",
2483: row[DB_serial], row[DB_name]);
2484:
2485: /* We now just add it to the database */
2486: row[DB_type] = malloc(2);
2487:
1.41 inoguchi 2488: if ((tm = X509_get_notAfter(x509)) == NULL)
2489: goto err;
1.40 inoguchi 2490: row[DB_exp_date] = strndup(tm->data, tm->length);
1.16 bcook 2491: if (row[DB_type] == NULL || row[DB_exp_date] == NULL) {
1.13 beck 2492: BIO_printf(bio_err, "Memory allocation failure\n");
2493: goto err;
2494: }
1.1 jsing 2495:
2496: row[DB_rev_date] = NULL;
2497:
2498: /* row[DB_serial] done already */
2499: row[DB_file] = malloc(8);
2500:
2501: /* row[DB_name] done already */
2502:
1.13 beck 2503: if ((row[DB_type] == NULL) || (row[DB_file] == NULL)) {
1.1 jsing 2504: BIO_printf(bio_err, "Memory allocation failure\n");
2505: goto err;
2506: }
2507: (void) strlcpy(row[DB_file], "unknown", 8);
1.45 inoguchi 2508: row[DB_type][0] = DB_TYPE_VAL;
1.1 jsing 2509: row[DB_type][1] = '\0';
2510:
2511: if ((irow = reallocarray(NULL, sizeof(char *),
2512: (DB_NUMBER + 1))) == NULL) {
2513: BIO_printf(bio_err, "Memory allocation failure\n");
2514: goto err;
2515: }
2516: for (i = 0; i < DB_NUMBER; i++) {
2517: irow[i] = row[i];
2518: row[i] = NULL;
2519: }
2520: irow[DB_NUMBER] = NULL;
2521:
2522: if (!TXT_DB_insert(db->db, irow)) {
2523: BIO_printf(bio_err, "failed to update database\n");
2524: BIO_printf(bio_err, "TXT_DB error number %ld\n",
2525: db->db->error);
2526: goto err;
2527: }
2528: /* Revoke Certificate */
2529: ok = do_revoke(x509, db, type, value);
2530:
2531: goto err;
2532:
2533: } else if (index_name_cmp_noconst(row, rrow)) {
2534: BIO_printf(bio_err, "ERROR:name does not match %s\n",
2535: row[DB_name]);
2536: goto err;
1.45 inoguchi 2537: } else if (rrow[DB_type][0] == DB_TYPE_REV) {
1.1 jsing 2538: BIO_printf(bio_err, "ERROR:Already revoked, serial number %s\n",
2539: row[DB_serial]);
2540: goto err;
2541: } else {
2542: BIO_printf(bio_err, "Revoking Certificate %s.\n",
2543: rrow[DB_serial]);
2544: rev_str = make_revocation_str(type, value);
1.32 inoguchi 2545: if (rev_str == NULL) {
1.1 jsing 2546: BIO_printf(bio_err, "Error in revocation arguments\n");
2547: goto err;
2548: }
1.45 inoguchi 2549: rrow[DB_type][0] = DB_TYPE_REV;
1.1 jsing 2550: rrow[DB_type][1] = '\0';
2551: rrow[DB_rev_date] = rev_str;
2552: }
2553: ok = 1;
2554:
1.26 jsing 2555: err:
1.1 jsing 2556: for (i = 0; i < DB_NUMBER; i++)
2557: free(row[i]);
2558:
2559: return (ok);
2560: }
2561:
2562: static int
1.31 inoguchi 2563: get_certificate_status(const char *serial, CA_DB *db)
1.1 jsing 2564: {
2565: char *row[DB_NUMBER], **rrow;
2566: int ok = -1, i;
2567:
2568: /* Free Resources */
2569: for (i = 0; i < DB_NUMBER; i++)
2570: row[i] = NULL;
2571:
2572: /* Malloc needed char spaces */
2573: row[DB_serial] = malloc(strlen(serial) + 2);
2574: if (row[DB_serial] == NULL) {
2575: BIO_printf(bio_err, "Malloc failure\n");
2576: goto err;
2577: }
2578: if (strlen(serial) % 2) {
2579: row[DB_serial][0] = '0';
2580:
2581: /* Copy String from serial to row[DB_serial] */
2582: memcpy(row[DB_serial] + 1, serial, strlen(serial));
2583: row[DB_serial][strlen(serial) + 1] = '\0';
2584: } else {
2585: /* Copy String from serial to row[DB_serial] */
2586: memcpy(row[DB_serial], serial, strlen(serial));
2587: row[DB_serial][strlen(serial)] = '\0';
2588: }
2589:
2590: /* Make it Upper Case */
2591: for (i = 0; row[DB_serial][i] != '\0'; i++)
2592: row[DB_serial][i] = toupper((unsigned char) row[DB_serial][i]);
2593:
2594:
2595: ok = 1;
2596:
2597: /* Search for the certificate */
2598: rrow = TXT_DB_get_by_index(db->db, DB_serial, row);
2599: if (rrow == NULL) {
2600: BIO_printf(bio_err, "Serial %s not present in db.\n",
2601: row[DB_serial]);
2602: ok = -1;
2603: goto err;
1.45 inoguchi 2604: } else if (rrow[DB_type][0] == DB_TYPE_VAL) {
1.1 jsing 2605: BIO_printf(bio_err, "%s=Valid (%c)\n",
2606: row[DB_serial], rrow[DB_type][0]);
2607: goto err;
1.45 inoguchi 2608: } else if (rrow[DB_type][0] == DB_TYPE_REV) {
1.1 jsing 2609: BIO_printf(bio_err, "%s=Revoked (%c)\n",
2610: row[DB_serial], rrow[DB_type][0]);
2611: goto err;
1.45 inoguchi 2612: } else if (rrow[DB_type][0] == DB_TYPE_EXP) {
1.1 jsing 2613: BIO_printf(bio_err, "%s=Expired (%c)\n",
2614: row[DB_serial], rrow[DB_type][0]);
2615: goto err;
1.45 inoguchi 2616: } else if (rrow[DB_type][0] == DB_TYPE_SUSP) {
1.1 jsing 2617: BIO_printf(bio_err, "%s=Suspended (%c)\n",
2618: row[DB_serial], rrow[DB_type][0]);
2619: goto err;
2620: } else {
2621: BIO_printf(bio_err, "%s=Unknown (%c).\n",
2622: row[DB_serial], rrow[DB_type][0]);
2623: ok = -1;
2624: }
2625:
1.26 jsing 2626: err:
1.1 jsing 2627: for (i = 0; i < DB_NUMBER; i++)
2628: free(row[i]);
2629:
2630: return (ok);
2631: }
2632:
2633: static int
1.31 inoguchi 2634: do_updatedb(CA_DB *db)
1.1 jsing 2635: {
2636: ASN1_UTCTIME *a_tm = NULL;
2637: int i, cnt = 0;
2638: int db_y2k, a_y2k; /* flags = 1 if y >= 2000 */
1.36 inoguchi 2639: char **rrow, *a_tm_s = NULL;
1.1 jsing 2640:
2641: a_tm = ASN1_UTCTIME_new();
1.36 inoguchi 2642: if (a_tm == NULL) {
2643: cnt = -1;
2644: goto err;
2645: }
1.1 jsing 2646:
2647: /* get actual time and make a string */
2648: a_tm = X509_gmtime_adj(a_tm, 0);
1.36 inoguchi 2649: if (a_tm == NULL) {
2650: cnt = -1;
2651: goto err;
2652: }
1.40 inoguchi 2653: a_tm_s = strndup(a_tm->data, a_tm->length);
1.1 jsing 2654: if (a_tm_s == NULL) {
2655: cnt = -1;
2656: goto err;
2657: }
2658:
2659: if (strncmp(a_tm_s, "49", 2) <= 0)
2660: a_y2k = 1;
2661: else
2662: a_y2k = 0;
2663:
2664: for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
2665: rrow = sk_OPENSSL_PSTRING_value(db->db->data, i);
2666:
1.45 inoguchi 2667: if (rrow[DB_type][0] == DB_TYPE_VAL) {
1.1 jsing 2668: /* ignore entries that are not valid */
2669: if (strncmp(rrow[DB_exp_date], "49", 2) <= 0)
2670: db_y2k = 1;
2671: else
2672: db_y2k = 0;
2673:
2674: if (db_y2k == a_y2k) {
2675: /* all on the same y2k side */
2676: if (strcmp(rrow[DB_exp_date], a_tm_s) <= 0) {
1.45 inoguchi 2677: rrow[DB_type][0] = DB_TYPE_EXP;
1.1 jsing 2678: rrow[DB_type][1] = '\0';
2679: cnt++;
2680:
2681: BIO_printf(bio_err, "%s=Expired\n",
2682: rrow[DB_serial]);
2683: }
2684: } else if (db_y2k < a_y2k) {
1.45 inoguchi 2685: rrow[DB_type][0] = DB_TYPE_EXP;
1.1 jsing 2686: rrow[DB_type][1] = '\0';
2687: cnt++;
2688:
2689: BIO_printf(bio_err, "%s=Expired\n",
2690: rrow[DB_serial]);
2691: }
2692: }
2693: }
2694:
1.26 jsing 2695: err:
1.1 jsing 2696: ASN1_UTCTIME_free(a_tm);
2697: free(a_tm_s);
2698:
2699: return (cnt);
2700: }
2701:
2702: static const char *crl_reasons[] = {
2703: /* CRL reason strings */
2704: "unspecified",
2705: "keyCompromise",
2706: "CACompromise",
2707: "affiliationChanged",
2708: "superseded",
2709: "cessationOfOperation",
2710: "certificateHold",
2711: "removeFromCRL",
2712: /* Additional pseudo reasons */
2713: "holdInstruction",
2714: "keyTime",
2715: "CAkeyTime"
2716: };
2717:
2718: #define NUM_REASONS (sizeof(crl_reasons) / sizeof(char *))
2719:
2720: /* Given revocation information convert to a DB string.
2721: * The format of the string is:
2722: * revtime[,reason,extra]. Where 'revtime' is the
2723: * revocation time (the current time). 'reason' is the
2724: * optional CRL reason and 'extra' is any additional
2725: * argument
2726: */
2727:
2728: char *
2729: make_revocation_str(int rev_type, char *rev_arg)
2730: {
2731: char *other = NULL, *str;
2732: const char *reason = NULL;
2733: ASN1_OBJECT *otmp;
2734: ASN1_UTCTIME *revtm = NULL;
2735: int i;
2736: switch (rev_type) {
2737: case REV_NONE:
2738: break;
2739:
2740: case REV_CRL_REASON:
2741: for (i = 0; i < 8; i++) {
1.35 inoguchi 2742: if (strcasecmp(rev_arg, crl_reasons[i]) == 0) {
1.1 jsing 2743: reason = crl_reasons[i];
2744: break;
2745: }
2746: }
2747: if (reason == NULL) {
2748: BIO_printf(bio_err, "Unknown CRL reason %s\n", rev_arg);
2749: return NULL;
2750: }
2751: break;
2752:
2753: case REV_HOLD:
2754: /* Argument is an OID */
2755: otmp = OBJ_txt2obj(rev_arg, 0);
2756: ASN1_OBJECT_free(otmp);
2757:
2758: if (otmp == NULL) {
2759: BIO_printf(bio_err,
2760: "Invalid object identifier %s\n", rev_arg);
2761: return NULL;
2762: }
2763: reason = "holdInstruction";
2764: other = rev_arg;
2765: break;
2766:
2767: case REV_KEY_COMPROMISE:
2768: case REV_CA_COMPROMISE:
2769: /* Argument is the key compromise time */
2770: if (!ASN1_GENERALIZEDTIME_set_string(NULL, rev_arg)) {
2771: BIO_printf(bio_err,
2772: "Invalid time format %s. Need YYYYMMDDHHMMSSZ\n",
2773: rev_arg);
2774: return NULL;
2775: }
2776: other = rev_arg;
2777: if (rev_type == REV_KEY_COMPROMISE)
2778: reason = "keyTime";
2779: else
2780: reason = "CAkeyTime";
2781:
2782: break;
2783: }
2784:
2785: revtm = X509_gmtime_adj(NULL, 0);
1.36 inoguchi 2786: if (revtm == NULL)
2787: return NULL;
2788:
1.1 jsing 2789: if (asprintf(&str, "%s%s%s%s%s", revtm->data,
2790: reason ? "," : "", reason ? reason : "",
2791: other ? "," : "", other ? other : "") == -1)
2792: str = NULL;
1.36 inoguchi 2793:
1.1 jsing 2794: ASN1_UTCTIME_free(revtm);
1.36 inoguchi 2795:
1.1 jsing 2796: return str;
2797: }
2798:
2799: /* Convert revocation field to X509_REVOKED entry
2800: * return code:
2801: * 0 error
2802: * 1 OK
2803: * 2 OK and some extensions added (i.e. V2 CRL)
2804: */
2805:
2806: int
1.31 inoguchi 2807: make_revoked(X509_REVOKED *rev, const char *str)
1.1 jsing 2808: {
2809: char *tmp = NULL;
2810: int reason_code = -1;
2811: int i, ret = 0;
2812: ASN1_OBJECT *hold = NULL;
2813: ASN1_GENERALIZEDTIME *comp_time = NULL;
2814: ASN1_ENUMERATED *rtmp = NULL;
2815:
2816: ASN1_TIME *revDate = NULL;
2817:
2818: i = unpack_revinfo(&revDate, &reason_code, &hold, &comp_time, str);
2819:
2820: if (i == 0)
2821: goto err;
2822:
1.32 inoguchi 2823: if (rev != NULL && !X509_REVOKED_set_revocationDate(rev, revDate))
1.1 jsing 2824: goto err;
2825:
1.32 inoguchi 2826: if (rev != NULL && (reason_code != OCSP_REVOKED_STATUS_NOSTATUS)) {
1.1 jsing 2827: rtmp = ASN1_ENUMERATED_new();
1.32 inoguchi 2828: if (rtmp == NULL || !ASN1_ENUMERATED_set(rtmp, reason_code))
1.1 jsing 2829: goto err;
2830: if (!X509_REVOKED_add1_ext_i2d(rev, NID_crl_reason, rtmp, 0, 0))
2831: goto err;
2832: }
1.32 inoguchi 2833: if (rev != NULL && comp_time != NULL) {
1.1 jsing 2834: if (!X509_REVOKED_add1_ext_i2d(rev, NID_invalidity_date,
2835: comp_time, 0, 0))
2836: goto err;
2837: }
1.32 inoguchi 2838: if (rev != NULL && hold != NULL) {
1.1 jsing 2839: if (!X509_REVOKED_add1_ext_i2d(rev, NID_hold_instruction_code,
2840: hold, 0, 0))
2841: goto err;
2842: }
2843: if (reason_code != OCSP_REVOKED_STATUS_NOSTATUS)
2844: ret = 2;
2845: else
2846: ret = 1;
2847:
1.26 jsing 2848: err:
1.1 jsing 2849: free(tmp);
2850:
2851: ASN1_OBJECT_free(hold);
2852: ASN1_GENERALIZEDTIME_free(comp_time);
2853: ASN1_ENUMERATED_free(rtmp);
2854: ASN1_TIME_free(revDate);
2855:
2856: return ret;
2857: }
2858:
2859: int
1.31 inoguchi 2860: old_entry_print(BIO *bp, ASN1_OBJECT *obj, ASN1_STRING *str)
1.1 jsing 2861: {
2862: char buf[25], *pbuf, *p;
2863: int j;
2864:
2865: j = i2a_ASN1_OBJECT(bp, obj);
2866: pbuf = buf;
2867: for (j = 22 - j; j > 0; j--)
2868: *(pbuf++) = ' ';
2869: *(pbuf++) = ':';
2870: *(pbuf++) = '\0';
2871: BIO_puts(bp, buf);
2872:
2873: if (str->type == V_ASN1_PRINTABLESTRING)
2874: BIO_printf(bp, "PRINTABLE:'");
2875: else if (str->type == V_ASN1_T61STRING)
2876: BIO_printf(bp, "T61STRING:'");
2877: else if (str->type == V_ASN1_IA5STRING)
2878: BIO_printf(bp, "IA5STRING:'");
2879: else if (str->type == V_ASN1_UNIVERSALSTRING)
2880: BIO_printf(bp, "UNIVERSALSTRING:'");
2881: else
2882: BIO_printf(bp, "ASN.1 %2d:'", str->type);
2883:
2884: p = (char *) str->data;
2885: for (j = str->length; j > 0; j--) {
2886: if ((*p >= ' ') && (*p <= '~'))
2887: BIO_printf(bp, "%c", *p);
2888: else if (*p & 0x80)
2889: BIO_printf(bp, "\\0x%02X", *p);
2890: else if ((unsigned char) *p == 0xf7)
2891: BIO_printf(bp, "^?");
2892: else
2893: BIO_printf(bp, "^%c", *p + '@');
2894: p++;
2895: }
2896: BIO_printf(bp, "'\n");
2897: return 1;
2898: }
2899:
2900: int
1.31 inoguchi 2901: unpack_revinfo(ASN1_TIME **prevtm, int *preason, ASN1_OBJECT **phold,
2902: ASN1_GENERALIZEDTIME **pinvtm, const char *str)
1.1 jsing 2903: {
2904: char *tmp = NULL;
2905: char *rtime_str, *reason_str = NULL, *arg_str = NULL, *p;
2906: int reason_code = -1;
2907: int ret = 0;
2908: unsigned int i;
2909: ASN1_OBJECT *hold = NULL;
2910: ASN1_GENERALIZEDTIME *comp_time = NULL;
2911:
2912: if ((tmp = strdup(str)) == NULL) {
2913: BIO_printf(bio_err, "malloc failed\n");
2914: goto err;
2915: }
2916: p = strchr(tmp, ',');
2917: rtime_str = tmp;
2918:
1.32 inoguchi 2919: if (p != NULL) {
1.1 jsing 2920: *p = '\0';
2921: p++;
2922: reason_str = p;
2923: p = strchr(p, ',');
1.32 inoguchi 2924: if (p != NULL) {
1.1 jsing 2925: *p = '\0';
2926: arg_str = p + 1;
2927: }
2928: }
1.32 inoguchi 2929: if (prevtm != NULL) {
1.1 jsing 2930: *prevtm = ASN1_UTCTIME_new();
2931: if (!ASN1_UTCTIME_set_string(*prevtm, rtime_str)) {
2932: BIO_printf(bio_err, "invalid revocation date %s\n",
2933: rtime_str);
2934: goto err;
2935: }
2936: }
1.32 inoguchi 2937: if (reason_str != NULL) {
1.1 jsing 2938: for (i = 0; i < NUM_REASONS; i++) {
1.35 inoguchi 2939: if (strcasecmp(reason_str, crl_reasons[i]) == 0) {
1.1 jsing 2940: reason_code = i;
2941: break;
2942: }
2943: }
2944: if (reason_code == OCSP_REVOKED_STATUS_NOSTATUS) {
2945: BIO_printf(bio_err, "invalid reason code %s\n",
2946: reason_str);
2947: goto err;
2948: }
2949: if (reason_code == 7)
2950: reason_code = OCSP_REVOKED_STATUS_REMOVEFROMCRL;
2951: else if (reason_code == 8) { /* Hold instruction */
1.32 inoguchi 2952: if (arg_str == NULL) {
1.1 jsing 2953: BIO_printf(bio_err,
2954: "missing hold instruction\n");
2955: goto err;
2956: }
2957: reason_code = OCSP_REVOKED_STATUS_CERTIFICATEHOLD;
2958: hold = OBJ_txt2obj(arg_str, 0);
2959:
1.32 inoguchi 2960: if (hold == NULL) {
1.1 jsing 2961: BIO_printf(bio_err,
2962: "invalid object identifier %s\n", arg_str);
2963: goto err;
2964: }
1.32 inoguchi 2965: if (phold != NULL)
1.1 jsing 2966: *phold = hold;
2967: } else if ((reason_code == 9) || (reason_code == 10)) {
1.32 inoguchi 2968: if (arg_str == NULL) {
1.1 jsing 2969: BIO_printf(bio_err,
2970: "missing compromised time\n");
2971: goto err;
2972: }
2973: comp_time = ASN1_GENERALIZEDTIME_new();
2974: if (!ASN1_GENERALIZEDTIME_set_string(comp_time,
2975: arg_str)) {
2976: BIO_printf(bio_err,
2977: "invalid compromised time %s\n", arg_str);
2978: goto err;
2979: }
2980: if (reason_code == 9)
2981: reason_code = OCSP_REVOKED_STATUS_KEYCOMPROMISE;
2982: else
2983: reason_code = OCSP_REVOKED_STATUS_CACOMPROMISE;
2984: }
2985: }
1.32 inoguchi 2986: if (preason != NULL)
1.1 jsing 2987: *preason = reason_code;
1.32 inoguchi 2988: if (pinvtm != NULL)
1.1 jsing 2989: *pinvtm = comp_time;
2990: else
2991: ASN1_GENERALIZEDTIME_free(comp_time);
2992:
2993: ret = 1;
2994:
1.26 jsing 2995: err:
1.1 jsing 2996: free(tmp);
2997:
1.32 inoguchi 2998: if (phold == NULL)
1.1 jsing 2999: ASN1_OBJECT_free(hold);
1.32 inoguchi 3000: if (pinvtm == NULL)
1.1 jsing 3001: ASN1_GENERALIZEDTIME_free(comp_time);
3002:
3003: return ret;
3004: }
3005:
3006: static char *
1.31 inoguchi 3007: bin2hex(unsigned char *data, size_t len)
1.1 jsing 3008: {
3009: char *ret = NULL;
3010: char hex[] = "0123456789ABCDEF";
3011: int i;
3012:
1.32 inoguchi 3013: if ((ret = malloc(len * 2 + 1)) != NULL) {
1.1 jsing 3014: for (i = 0; i < len; i++) {
3015: ret[i * 2 + 0] = hex[data[i] >> 4];
3016: ret[i * 2 + 1] = hex[data[i] & 0x0F];
3017: }
3018: ret[len * 2] = '\0';
3019: }
3020: return ret;
3021: }