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