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