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