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