xref: /openbsd-src/usr.bin/openssl/ca.c (revision 77fb829e28a4fec2a4425ebefffdd6a01266b315)
1*77fb829eStb /* $OpenBSD: ca.c,v 1.60 2024/07/08 05:56:17 tb Exp $ */
2dab3f910Sjsing /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3dab3f910Sjsing  * All rights reserved.
4dab3f910Sjsing  *
5dab3f910Sjsing  * This package is an SSL implementation written
6dab3f910Sjsing  * by Eric Young (eay@cryptsoft.com).
7dab3f910Sjsing  * The implementation was written so as to conform with Netscapes SSL.
8dab3f910Sjsing  *
9dab3f910Sjsing  * This library is free for commercial and non-commercial use as long as
10dab3f910Sjsing  * the following conditions are aheared to.  The following conditions
11dab3f910Sjsing  * apply to all code found in this distribution, be it the RC4, RSA,
12dab3f910Sjsing  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13dab3f910Sjsing  * included with this distribution is covered by the same copyright terms
14dab3f910Sjsing  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15dab3f910Sjsing  *
16dab3f910Sjsing  * Copyright remains Eric Young's, and as such any Copyright notices in
17dab3f910Sjsing  * the code are not to be removed.
18dab3f910Sjsing  * If this package is used in a product, Eric Young should be given attribution
19dab3f910Sjsing  * as the author of the parts of the library used.
20dab3f910Sjsing  * This can be in the form of a textual message at program startup or
21dab3f910Sjsing  * in documentation (online or textual) provided with the package.
22dab3f910Sjsing  *
23dab3f910Sjsing  * Redistribution and use in source and binary forms, with or without
24dab3f910Sjsing  * modification, are permitted provided that the following conditions
25dab3f910Sjsing  * are met:
26dab3f910Sjsing  * 1. Redistributions of source code must retain the copyright
27dab3f910Sjsing  *    notice, this list of conditions and the following disclaimer.
28dab3f910Sjsing  * 2. Redistributions in binary form must reproduce the above copyright
29dab3f910Sjsing  *    notice, this list of conditions and the following disclaimer in the
30dab3f910Sjsing  *    documentation and/or other materials provided with the distribution.
31dab3f910Sjsing  * 3. All advertising materials mentioning features or use of this software
32dab3f910Sjsing  *    must display the following acknowledgement:
33dab3f910Sjsing  *    "This product includes cryptographic software written by
34dab3f910Sjsing  *     Eric Young (eay@cryptsoft.com)"
35dab3f910Sjsing  *    The word 'cryptographic' can be left out if the rouines from the library
36dab3f910Sjsing  *    being used are not cryptographic related :-).
37dab3f910Sjsing  * 4. If you include any Windows specific code (or a derivative thereof) from
38dab3f910Sjsing  *    the apps directory (application code) you must include an acknowledgement:
39dab3f910Sjsing  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40dab3f910Sjsing  *
41dab3f910Sjsing  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42dab3f910Sjsing  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43dab3f910Sjsing  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44dab3f910Sjsing  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45dab3f910Sjsing  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46dab3f910Sjsing  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47dab3f910Sjsing  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48dab3f910Sjsing  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49dab3f910Sjsing  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50dab3f910Sjsing  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51dab3f910Sjsing  * SUCH DAMAGE.
52dab3f910Sjsing  *
53dab3f910Sjsing  * The licence and distribution terms for any publically available version or
54dab3f910Sjsing  * derivative of this code cannot be changed.  i.e. this code cannot simply be
55dab3f910Sjsing  * copied and put under another distribution licence
56dab3f910Sjsing  * [including the GNU Public Licence.]
57dab3f910Sjsing  */
58dab3f910Sjsing 
59dab3f910Sjsing /* The PPKI stuff has been donated by Jeff Barber <jeffb@issl.atl.hp.com> */
60dab3f910Sjsing 
61dab3f910Sjsing #include <sys/types.h>
62dab3f910Sjsing 
63dab3f910Sjsing #include <ctype.h>
64dab3f910Sjsing #include <stdio.h>
65dab3f910Sjsing #include <stdlib.h>
66dab3f910Sjsing #include <limits.h>
67dab3f910Sjsing #include <string.h>
68dab3f910Sjsing #include <unistd.h>
69dab3f910Sjsing 
70dab3f910Sjsing #include "apps.h"
71dab3f910Sjsing 
72dab3f910Sjsing #include <openssl/bio.h>
73dab3f910Sjsing #include <openssl/bn.h>
74dab3f910Sjsing #include <openssl/conf.h>
75dab3f910Sjsing #include <openssl/err.h>
76dab3f910Sjsing #include <openssl/evp.h>
77dab3f910Sjsing #include <openssl/objects.h>
78dab3f910Sjsing #include <openssl/ocsp.h>
79dab3f910Sjsing #include <openssl/pem.h>
80dab3f910Sjsing #include <openssl/txt_db.h>
81dab3f910Sjsing #include <openssl/x509.h>
82dab3f910Sjsing #include <openssl/x509v3.h>
83dab3f910Sjsing 
84dab3f910Sjsing #define BASE_SECTION		"ca"
85dab3f910Sjsing 
86dab3f910Sjsing #define ENV_DEFAULT_CA		"default_ca"
87dab3f910Sjsing 
88dab3f910Sjsing #define STRING_MASK		"string_mask"
89dab3f910Sjsing #define UTF8_IN			"utf8"
90dab3f910Sjsing 
91dab3f910Sjsing #define ENV_NEW_CERTS_DIR	"new_certs_dir"
92dab3f910Sjsing #define ENV_CERTIFICATE 	"certificate"
93dab3f910Sjsing #define ENV_SERIAL		"serial"
94dab3f910Sjsing #define ENV_CRLNUMBER		"crlnumber"
95dab3f910Sjsing #define ENV_PRIVATE_KEY		"private_key"
96dab3f910Sjsing #define ENV_DEFAULT_DAYS 	"default_days"
97dab3f910Sjsing #define ENV_DEFAULT_STARTDATE 	"default_startdate"
98dab3f910Sjsing #define ENV_DEFAULT_ENDDATE 	"default_enddate"
99dab3f910Sjsing #define ENV_DEFAULT_CRL_DAYS 	"default_crl_days"
100dab3f910Sjsing #define ENV_DEFAULT_CRL_HOURS 	"default_crl_hours"
101dab3f910Sjsing #define ENV_DEFAULT_MD		"default_md"
102dab3f910Sjsing #define ENV_DEFAULT_EMAIL_DN	"email_in_dn"
103dab3f910Sjsing #define ENV_PRESERVE		"preserve"
104dab3f910Sjsing #define ENV_POLICY      	"policy"
105dab3f910Sjsing #define ENV_EXTENSIONS      	"x509_extensions"
106dab3f910Sjsing #define ENV_CRLEXT      	"crl_extensions"
107dab3f910Sjsing #define ENV_MSIE_HACK		"msie_hack"
108dab3f910Sjsing #define ENV_NAMEOPT		"name_opt"
109dab3f910Sjsing #define ENV_CERTOPT		"cert_opt"
110dab3f910Sjsing #define ENV_EXTCOPY		"copy_extensions"
111dab3f910Sjsing #define ENV_UNIQUE_SUBJECT	"unique_subject"
112dab3f910Sjsing 
113dab3f910Sjsing #define ENV_DATABASE		"database"
114dab3f910Sjsing 
115dab3f910Sjsing /* Additional revocation information types */
116dab3f910Sjsing 
117dab3f910Sjsing #define REV_NONE		0	/* No addditional information */
118dab3f910Sjsing #define REV_CRL_REASON		1	/* Value is CRL reason code */
119dab3f910Sjsing #define REV_HOLD		2	/* Value is hold instruction */
120dab3f910Sjsing #define REV_KEY_COMPROMISE	3	/* Value is cert key compromise time */
121dab3f910Sjsing #define REV_CA_COMPROMISE	4	/* Value is CA key compromise time */
122dab3f910Sjsing 
123dab3f910Sjsing static void lookup_fail(const char *name, const char *tag);
124dab3f910Sjsing static int certify(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
125dab3f910Sjsing     const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts,
126dab3f910Sjsing     STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, char *subj,
127dab3f910Sjsing     unsigned long chtype, int multirdn, int email_dn, char *startdate,
128dab3f910Sjsing     char *enddate, long days, int batch, char *ext_sect, CONF *conf,
129dab3f910Sjsing     int verbose, unsigned long certopt, unsigned long nameopt,
130dab3f910Sjsing     int default_op, int ext_copy, int selfsign);
131dab3f910Sjsing static int certify_cert(X509 **xret, char *infile, EVP_PKEY *pkey,
132dab3f910Sjsing     X509 *x509, const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts,
133dab3f910Sjsing     STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, char *subj,
134dab3f910Sjsing     unsigned long chtype, int multirdn, int email_dn, char *startdate,
135dab3f910Sjsing     char *enddate, long days, int batch, char *ext_sect, CONF *conf,
136dab3f910Sjsing     int verbose, unsigned long certopt, unsigned long nameopt, int default_op,
1375284dfeaSbcook     int ext_copy);
13854292de2Sinoguchi static int write_new_certificate(BIO *bp, X509 *x, int output_der,
139dab3f910Sjsing     int notext);
140dab3f910Sjsing static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509,
141dab3f910Sjsing     const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts,
142dab3f910Sjsing     STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, char *subj,
143dab3f910Sjsing     unsigned long chtype, int multirdn, int email_dn, char *startdate,
144dab3f910Sjsing     char *enddate, long days, int batch, int verbose, X509_REQ *req,
145dab3f910Sjsing     char *ext_sect, CONF *conf, unsigned long certopt, unsigned long nameopt,
146dab3f910Sjsing     int default_op, int ext_copy, int selfsign);
147dab3f910Sjsing static int do_revoke(X509 *x509, CA_DB *db, int ext, char *extval);
148c80f2811Sinoguchi static int get_certificate_status(const char *serial, CA_DB *db);
149dab3f910Sjsing static int do_updatedb(CA_DB *db);
150dab3f910Sjsing static int check_time_format(const char *str);
151dab3f910Sjsing static char *bin2hex(unsigned char *, size_t);
152dab3f910Sjsing char *make_revocation_str(int rev_type, char *rev_arg);
153dab3f910Sjsing int make_revoked(X509_REVOKED *rev, const char *str);
154dab3f910Sjsing int old_entry_print(BIO *bp, ASN1_OBJECT *obj, ASN1_STRING *str);
15563a81de5Sinoguchi 
156dab3f910Sjsing static CONF *conf = NULL;
157dab3f910Sjsing static CONF *extconf = NULL;
158dab3f910Sjsing 
15963a81de5Sinoguchi static struct {
16063a81de5Sinoguchi 	int batch;
16163a81de5Sinoguchi 	char *certfile;
16263a81de5Sinoguchi 	unsigned long chtype;
16363a81de5Sinoguchi 	char *configfile;
164c80f2811Sinoguchi 	int create_serial;
16563a81de5Sinoguchi 	char *crl_ext;
16663a81de5Sinoguchi 	long crldays;
16763a81de5Sinoguchi 	long crlhours;
16863a81de5Sinoguchi 	long crlsec;
16963a81de5Sinoguchi 	long days;
17063a81de5Sinoguchi 	int dorevoke;
17163a81de5Sinoguchi 	int doupdatedb;
17263a81de5Sinoguchi 	int email_dn;
17363a81de5Sinoguchi 	char *enddate;
17463a81de5Sinoguchi 	char *extensions;
17563a81de5Sinoguchi 	char *extfile;
17663a81de5Sinoguchi 	int gencrl;
17763a81de5Sinoguchi 	char *infile;
17863a81de5Sinoguchi 	char **infiles;
17963a81de5Sinoguchi 	int infiles_num;
18063a81de5Sinoguchi 	char *key;
18163a81de5Sinoguchi 	char *keyfile;
18263a81de5Sinoguchi 	int keyform;
18363a81de5Sinoguchi 	char *md;
18463a81de5Sinoguchi 	int multirdn;
18563a81de5Sinoguchi 	int msie_hack;
18663a81de5Sinoguchi 	int notext;
18763a81de5Sinoguchi 	char *outdir;
18863a81de5Sinoguchi 	char *outfile;
18963a81de5Sinoguchi 	char *passargin;
19063a81de5Sinoguchi 	char *policy;
19163a81de5Sinoguchi 	int preserve;
19263a81de5Sinoguchi 	int req;
19363a81de5Sinoguchi 	char *rev_arg;
19463a81de5Sinoguchi 	int rev_type;
195c80f2811Sinoguchi 	char *serial_status;
19663a81de5Sinoguchi 	char *section;
19763a81de5Sinoguchi 	int selfsign;
19863a81de5Sinoguchi 	STACK_OF(OPENSSL_STRING) *sigopts;
19963a81de5Sinoguchi 	char *ss_cert_file;
20063a81de5Sinoguchi 	char *startdate;
20163a81de5Sinoguchi 	char *subj;
20263a81de5Sinoguchi 	int verbose;
203e7718adaStb } cfg;
204dab3f910Sjsing 
20563a81de5Sinoguchi static int
ca_opt_chtype_utf8(void)20663a81de5Sinoguchi ca_opt_chtype_utf8(void)
20763a81de5Sinoguchi {
208e7718adaStb 	cfg.chtype = MBSTRING_UTF8;
20963a81de5Sinoguchi 	return (0);
21063a81de5Sinoguchi }
21163a81de5Sinoguchi 
21263a81de5Sinoguchi static int
ca_opt_crl_ca_compromise(char * arg)21363a81de5Sinoguchi ca_opt_crl_ca_compromise(char *arg)
21463a81de5Sinoguchi {
215e7718adaStb 	cfg.rev_arg = arg;
216e7718adaStb 	cfg.rev_type = REV_CA_COMPROMISE;
21763a81de5Sinoguchi 	return (0);
21863a81de5Sinoguchi }
21963a81de5Sinoguchi 
22063a81de5Sinoguchi static int
ca_opt_crl_compromise(char * arg)22163a81de5Sinoguchi ca_opt_crl_compromise(char *arg)
22263a81de5Sinoguchi {
223e7718adaStb 	cfg.rev_arg = arg;
224e7718adaStb 	cfg.rev_type = REV_KEY_COMPROMISE;
22563a81de5Sinoguchi 	return (0);
22663a81de5Sinoguchi }
22763a81de5Sinoguchi 
22863a81de5Sinoguchi static int
ca_opt_crl_hold(char * arg)22963a81de5Sinoguchi ca_opt_crl_hold(char *arg)
23063a81de5Sinoguchi {
231e7718adaStb 	cfg.rev_arg = arg;
232e7718adaStb 	cfg.rev_type = REV_HOLD;
23363a81de5Sinoguchi 	return (0);
23463a81de5Sinoguchi }
23563a81de5Sinoguchi 
23663a81de5Sinoguchi static int
ca_opt_crl_reason(char * arg)23763a81de5Sinoguchi ca_opt_crl_reason(char *arg)
23863a81de5Sinoguchi {
239e7718adaStb 	cfg.rev_arg = arg;
240e7718adaStb 	cfg.rev_type = REV_CRL_REASON;
24163a81de5Sinoguchi 	return (0);
24263a81de5Sinoguchi }
24363a81de5Sinoguchi 
24463a81de5Sinoguchi static int
ca_opt_in(char * arg)24563a81de5Sinoguchi ca_opt_in(char *arg)
24663a81de5Sinoguchi {
247e7718adaStb 	cfg.infile = arg;
248e7718adaStb 	cfg.req = 1;
24963a81de5Sinoguchi 	return (0);
25063a81de5Sinoguchi }
25163a81de5Sinoguchi 
25263a81de5Sinoguchi static int
ca_opt_infiles(int argc,char ** argv,int * argsused)25363a81de5Sinoguchi ca_opt_infiles(int argc, char **argv, int *argsused)
25463a81de5Sinoguchi {
255e7718adaStb 	cfg.infiles_num = argc - 1;
256e7718adaStb 	if (cfg.infiles_num < 1)
25763a81de5Sinoguchi 		return (1);
258e7718adaStb 	cfg.infiles = argv + 1;
259e7718adaStb 	cfg.req = 1;
26063a81de5Sinoguchi 	*argsused = argc;
26163a81de5Sinoguchi 	return (0);
26263a81de5Sinoguchi }
26363a81de5Sinoguchi 
26463a81de5Sinoguchi static int
ca_opt_revoke(char * arg)26563a81de5Sinoguchi ca_opt_revoke(char *arg)
26663a81de5Sinoguchi {
267e7718adaStb 	cfg.infile = arg;
268e7718adaStb 	cfg.dorevoke = 1;
26963a81de5Sinoguchi 	return (0);
27063a81de5Sinoguchi }
27163a81de5Sinoguchi 
27263a81de5Sinoguchi static int
ca_opt_sigopt(char * arg)27363a81de5Sinoguchi ca_opt_sigopt(char *arg)
27463a81de5Sinoguchi {
275e7718adaStb 	if (cfg.sigopts == NULL)
276e7718adaStb 		cfg.sigopts = sk_OPENSSL_STRING_new_null();
277e7718adaStb 	if (cfg.sigopts == NULL)
27863a81de5Sinoguchi 		return (1);
279e7718adaStb 	if (!sk_OPENSSL_STRING_push(cfg.sigopts, arg))
28063a81de5Sinoguchi 		return (1);
28163a81de5Sinoguchi 	return (0);
28263a81de5Sinoguchi }
28363a81de5Sinoguchi 
28463a81de5Sinoguchi static int
ca_opt_ss_cert(char * arg)28563a81de5Sinoguchi ca_opt_ss_cert(char *arg)
28663a81de5Sinoguchi {
287e7718adaStb 	cfg.ss_cert_file = arg;
288e7718adaStb 	cfg.req = 1;
28963a81de5Sinoguchi 	return (0);
29063a81de5Sinoguchi }
29163a81de5Sinoguchi 
29263a81de5Sinoguchi static const struct option ca_options[] = {
29363a81de5Sinoguchi 	{
29463a81de5Sinoguchi 		.name = "batch",
29563a81de5Sinoguchi 		.desc = "Operate in batch mode",
29663a81de5Sinoguchi 		.type = OPTION_FLAG,
297e7718adaStb 		.opt.flag = &cfg.batch,
29863a81de5Sinoguchi 	},
29963a81de5Sinoguchi 	{
30063a81de5Sinoguchi 		.name = "cert",
30163a81de5Sinoguchi 		.argname = "file",
30263a81de5Sinoguchi 		.desc = "File containing the CA certificate",
30363a81de5Sinoguchi 		.type = OPTION_ARG,
304e7718adaStb 		.opt.arg = &cfg.certfile,
30563a81de5Sinoguchi 	},
30663a81de5Sinoguchi 	{
30763a81de5Sinoguchi 		.name = "config",
30863a81de5Sinoguchi 		.argname = "file",
30963a81de5Sinoguchi 		.desc = "Specify an alternative configuration file",
31063a81de5Sinoguchi 		.type = OPTION_ARG,
311e7718adaStb 		.opt.arg = &cfg.configfile,
31263a81de5Sinoguchi 	},
31363a81de5Sinoguchi 	{
31463a81de5Sinoguchi 		.name = "create_serial",
31563a81de5Sinoguchi 		.desc = "If reading serial fails, create a new random serial",
31663a81de5Sinoguchi 		.type = OPTION_FLAG,
317e7718adaStb 		.opt.flag = &cfg.create_serial,
31863a81de5Sinoguchi 	},
31963a81de5Sinoguchi 	{
32063a81de5Sinoguchi 		.name = "crl_CA_compromise",
32163a81de5Sinoguchi 		.argname = "time",
32263a81de5Sinoguchi 		.desc = "Set the compromise time and the revocation reason to\n"
32363a81de5Sinoguchi 		    "CACompromise",
32463a81de5Sinoguchi 		.type = OPTION_ARG_FUNC,
32563a81de5Sinoguchi 		.opt.argfunc = ca_opt_crl_ca_compromise,
32663a81de5Sinoguchi 	},
32763a81de5Sinoguchi 	{
32863a81de5Sinoguchi 		.name = "crl_compromise",
32963a81de5Sinoguchi 		.argname = "time",
33063a81de5Sinoguchi 		.desc = "Set the compromise time and the revocation reason to\n"
33163a81de5Sinoguchi 		    "keyCompromise",
33263a81de5Sinoguchi 		.type = OPTION_ARG_FUNC,
33363a81de5Sinoguchi 		.opt.argfunc = ca_opt_crl_compromise,
33463a81de5Sinoguchi 	},
33563a81de5Sinoguchi 	{
33663a81de5Sinoguchi 		.name = "crl_hold",
33763a81de5Sinoguchi 		.argname = "instruction",
33863a81de5Sinoguchi 		.desc = "Set the hold instruction and the revocation reason to\n"
33963a81de5Sinoguchi 		    "certificateHold",
34063a81de5Sinoguchi 		.type = OPTION_ARG_FUNC,
34163a81de5Sinoguchi 		.opt.argfunc = ca_opt_crl_hold,
34263a81de5Sinoguchi 	},
34363a81de5Sinoguchi 	{
34463a81de5Sinoguchi 		.name = "crl_reason",
34563a81de5Sinoguchi 		.argname = "reason",
34663a81de5Sinoguchi 		.desc = "Revocation reason",
34763a81de5Sinoguchi 		.type = OPTION_ARG_FUNC,
34863a81de5Sinoguchi 		.opt.argfunc = ca_opt_crl_reason,
34963a81de5Sinoguchi 	},
35063a81de5Sinoguchi 	{
35163a81de5Sinoguchi 		.name = "crldays",
35263a81de5Sinoguchi 		.argname = "days",
35363a81de5Sinoguchi 		.desc = "Number of days before the next CRL is due",
35463a81de5Sinoguchi 		.type = OPTION_ARG_LONG,
355e7718adaStb 		.opt.lvalue = &cfg.crldays,
35663a81de5Sinoguchi 	},
35763a81de5Sinoguchi 	{
35863a81de5Sinoguchi 		.name = "crlexts",
35963a81de5Sinoguchi 		.argname = "section",
36063a81de5Sinoguchi 		.desc = "CRL extension section (override value in config file)",
36163a81de5Sinoguchi 		.type = OPTION_ARG,
362e7718adaStb 		.opt.arg = &cfg.crl_ext,
36363a81de5Sinoguchi 	},
36463a81de5Sinoguchi 	{
36563a81de5Sinoguchi 		.name = "crlhours",
36663a81de5Sinoguchi 		.argname = "hours",
36763a81de5Sinoguchi 		.desc = "Number of hours before the next CRL is due",
36863a81de5Sinoguchi 		.type = OPTION_ARG_LONG,
369e7718adaStb 		.opt.lvalue = &cfg.crlhours,
37063a81de5Sinoguchi 	},
37163a81de5Sinoguchi 	{
37263a81de5Sinoguchi 		.name = "crlsec",
37363a81de5Sinoguchi 		.argname = "seconds",
37463a81de5Sinoguchi 		.desc = "Number of seconds before the next CRL is due",
37563a81de5Sinoguchi 		.type = OPTION_ARG_LONG,
376e7718adaStb 		.opt.lvalue = &cfg.crlsec,
37763a81de5Sinoguchi 	},
37863a81de5Sinoguchi 	{
37963a81de5Sinoguchi 		.name = "days",
38063a81de5Sinoguchi 		.argname = "arg",
38163a81de5Sinoguchi 		.desc = "Number of days to certify the certificate for",
38263a81de5Sinoguchi 		.type = OPTION_ARG_LONG,
383e7718adaStb 		.opt.lvalue = &cfg.days,
38463a81de5Sinoguchi 	},
38563a81de5Sinoguchi 	{
38663a81de5Sinoguchi 		.name = "enddate",
38763a81de5Sinoguchi 		.argname = "YYMMDDHHMMSSZ",
38863a81de5Sinoguchi 		.desc = "Certificate validity notAfter (overrides -days)",
38963a81de5Sinoguchi 		.type = OPTION_ARG,
390e7718adaStb 		.opt.arg = &cfg.enddate,
39163a81de5Sinoguchi 	},
39263a81de5Sinoguchi 	{
39363a81de5Sinoguchi 		.name = "extensions",
39463a81de5Sinoguchi 		.argname = "section",
39563a81de5Sinoguchi 		.desc = "Extension section (override value in config file)",
39663a81de5Sinoguchi 		.type = OPTION_ARG,
397e7718adaStb 		.opt.arg = &cfg.extensions,
39863a81de5Sinoguchi 	},
39963a81de5Sinoguchi 	{
40063a81de5Sinoguchi 		.name = "extfile",
40163a81de5Sinoguchi 		.argname = "file",
40263a81de5Sinoguchi 		.desc = "Configuration file with X509v3 extentions to add",
40363a81de5Sinoguchi 		.type = OPTION_ARG,
404e7718adaStb 		.opt.arg = &cfg.extfile,
40563a81de5Sinoguchi 	},
40663a81de5Sinoguchi 	{
40763a81de5Sinoguchi 		.name = "gencrl",
40863a81de5Sinoguchi 		.desc = "Generate a new CRL",
40963a81de5Sinoguchi 		.type = OPTION_FLAG,
410e7718adaStb 		.opt.flag = &cfg.gencrl,
41163a81de5Sinoguchi 	},
41263a81de5Sinoguchi 	{
41363a81de5Sinoguchi 		.name = "in",
41463a81de5Sinoguchi 		.argname = "file",
41563a81de5Sinoguchi 		.desc = "Input file containing a single certificate request",
41663a81de5Sinoguchi 		.type = OPTION_ARG_FUNC,
41763a81de5Sinoguchi 		.opt.argfunc = ca_opt_in,
41863a81de5Sinoguchi 	},
41963a81de5Sinoguchi 	{
42063a81de5Sinoguchi 		.name = "infiles",
42163a81de5Sinoguchi 		.argname = "...",
42263a81de5Sinoguchi 		.desc = "The last argument, certificate requests to process",
42363a81de5Sinoguchi 		.type = OPTION_ARGV_FUNC,
42463a81de5Sinoguchi 		.opt.argvfunc = ca_opt_infiles,
42563a81de5Sinoguchi 	},
42663a81de5Sinoguchi 	{
42763a81de5Sinoguchi 		.name = "key",
42863a81de5Sinoguchi 		.argname = "password",
42963a81de5Sinoguchi 		.desc = "Key to decode the private key if it is encrypted",
43063a81de5Sinoguchi 		.type = OPTION_ARG,
431e7718adaStb 		.opt.arg = &cfg.key,
43263a81de5Sinoguchi 	},
43363a81de5Sinoguchi 	{
43463a81de5Sinoguchi 		.name = "keyfile",
43563a81de5Sinoguchi 		.argname = "file",
43663a81de5Sinoguchi 		.desc = "Private key file",
43763a81de5Sinoguchi 		.type = OPTION_ARG,
438e7718adaStb 		.opt.arg = &cfg.keyfile,
43963a81de5Sinoguchi 	},
44063a81de5Sinoguchi 	{
44163a81de5Sinoguchi 		.name = "keyform",
44263a81de5Sinoguchi 		.argname = "fmt",
44363a81de5Sinoguchi 		.desc = "Private key file format (DER or PEM (default))",
44463a81de5Sinoguchi 		.type = OPTION_ARG_FORMAT,
445e7718adaStb 		.opt.value = &cfg.keyform,
44663a81de5Sinoguchi 	},
44763a81de5Sinoguchi 	{
44863a81de5Sinoguchi 		.name = "md",
44963a81de5Sinoguchi 		.argname = "alg",
45063a81de5Sinoguchi 		.desc = "Message digest to use",
45163a81de5Sinoguchi 		.type = OPTION_ARG,
452e7718adaStb 		.opt.arg = &cfg.md,
45363a81de5Sinoguchi 	},
45463a81de5Sinoguchi 	{
45563a81de5Sinoguchi 		.name = "msie_hack",
45663a81de5Sinoguchi 		.type = OPTION_FLAG,
457e7718adaStb 		.opt.flag = &cfg.msie_hack,
45863a81de5Sinoguchi 	},
45963a81de5Sinoguchi 	{
46063a81de5Sinoguchi 		.name = "multivalue-rdn",
46163a81de5Sinoguchi 		.desc = "Enable support for multivalued RDNs",
46263a81de5Sinoguchi 		.type = OPTION_FLAG,
463e7718adaStb 		.opt.flag = &cfg.multirdn,
46463a81de5Sinoguchi 	},
46563a81de5Sinoguchi 	{
46663a81de5Sinoguchi 		.name = "name",
46763a81de5Sinoguchi 		.argname = "section",
46863a81de5Sinoguchi 		.desc = "Specifies the configuration file section to use",
46963a81de5Sinoguchi 		.type = OPTION_ARG,
470e7718adaStb 		.opt.arg = &cfg.section,
47163a81de5Sinoguchi 	},
47263a81de5Sinoguchi 	{
47363a81de5Sinoguchi 		.name = "noemailDN",
47463a81de5Sinoguchi 		.desc = "Do not add the EMAIL field to the DN",
47563a81de5Sinoguchi 		.type = OPTION_VALUE,
476e7718adaStb 		.opt.value = &cfg.email_dn,
47763a81de5Sinoguchi 		.value = 0,
47863a81de5Sinoguchi 	},
47963a81de5Sinoguchi 	{
48063a81de5Sinoguchi 		.name = "notext",
48163a81de5Sinoguchi 		.desc = "Do not print the generated certificate",
48263a81de5Sinoguchi 		.type = OPTION_FLAG,
483e7718adaStb 		.opt.flag = &cfg.notext,
48463a81de5Sinoguchi 	},
48563a81de5Sinoguchi 	{
48663a81de5Sinoguchi 		.name = "out",
48763a81de5Sinoguchi 		.argname = "file",
48863a81de5Sinoguchi 		.desc = "Output file (default stdout)",
48963a81de5Sinoguchi 		.type = OPTION_ARG,
490e7718adaStb 		.opt.arg = &cfg.outfile,
49163a81de5Sinoguchi 	},
49263a81de5Sinoguchi 	{
49363a81de5Sinoguchi 		.name = "outdir",
49463a81de5Sinoguchi 		.argname = "directory",
49563a81de5Sinoguchi 		.desc = " Directory to output certificates to",
49663a81de5Sinoguchi 		.type = OPTION_ARG,
497e7718adaStb 		.opt.arg = &cfg.outdir,
49863a81de5Sinoguchi 	},
49963a81de5Sinoguchi 	{
50063a81de5Sinoguchi 		.name = "passin",
50163a81de5Sinoguchi 		.argname = "src",
50263a81de5Sinoguchi 		.desc = "Private key input password source",
50363a81de5Sinoguchi 		.type = OPTION_ARG,
504e7718adaStb 		.opt.arg = &cfg.passargin,
50563a81de5Sinoguchi 	},
50663a81de5Sinoguchi 	{
50763a81de5Sinoguchi 		.name = "policy",
50863a81de5Sinoguchi 		.argname = "name",
50963a81de5Sinoguchi 		.desc = "The CA 'policy' to support",
51063a81de5Sinoguchi 		.type = OPTION_ARG,
511e7718adaStb 		.opt.arg = &cfg.policy,
51263a81de5Sinoguchi 	},
51363a81de5Sinoguchi 	{
51463a81de5Sinoguchi 		.name = "preserveDN",
51563a81de5Sinoguchi 		.desc = "Do not re-order the DN",
51663a81de5Sinoguchi 		.type = OPTION_FLAG,
517e7718adaStb 		.opt.flag = &cfg.preserve,
51863a81de5Sinoguchi 	},
51963a81de5Sinoguchi 	{
52063a81de5Sinoguchi 		.name = "revoke",
52163a81de5Sinoguchi 		.argname = "file",
52263a81de5Sinoguchi 		.desc = "Revoke a certificate (given in file)",
52363a81de5Sinoguchi 		.type = OPTION_ARG_FUNC,
52463a81de5Sinoguchi 		.opt.argfunc = ca_opt_revoke,
52563a81de5Sinoguchi 	},
52663a81de5Sinoguchi 	{
52763a81de5Sinoguchi 		.name = "selfsign",
52863a81de5Sinoguchi 		.desc = "Sign a certificate using the key associated with it",
52963a81de5Sinoguchi 		.type = OPTION_FLAG,
530e7718adaStb 		.opt.flag = &cfg.selfsign,
53163a81de5Sinoguchi 	},
53263a81de5Sinoguchi 	{
53363a81de5Sinoguchi 		.name = "sigopt",
53463a81de5Sinoguchi 		.argname = "nm:v",
53563a81de5Sinoguchi 		.desc = "Signature parameter in nm:v form",
53663a81de5Sinoguchi 		.type = OPTION_ARG_FUNC,
53763a81de5Sinoguchi 		.opt.argfunc = ca_opt_sigopt,
53863a81de5Sinoguchi 	},
53963a81de5Sinoguchi 	{
54063a81de5Sinoguchi 		.name = "ss_cert",
54163a81de5Sinoguchi 		.argname = "file",
54263a81de5Sinoguchi 		.desc = "File contains a self signed certificate to sign",
54363a81de5Sinoguchi 		.type = OPTION_ARG_FUNC,
54463a81de5Sinoguchi 		.opt.argfunc = ca_opt_ss_cert,
54563a81de5Sinoguchi 	},
54663a81de5Sinoguchi 	{
54763a81de5Sinoguchi 		.name = "startdate",
54863a81de5Sinoguchi 		.argname = "YYMMDDHHMMSSZ",
54963a81de5Sinoguchi 		.desc = "Certificate validity notBefore",
55063a81de5Sinoguchi 		.type = OPTION_ARG,
551e7718adaStb 		.opt.arg = &cfg.startdate,
55263a81de5Sinoguchi 	},
55363a81de5Sinoguchi 	{
55463a81de5Sinoguchi 		.name = "status",
55563a81de5Sinoguchi 		.argname = "serial",
55663a81de5Sinoguchi 		.desc = "Shows certificate status given the serial number",
55763a81de5Sinoguchi 		.type = OPTION_ARG,
558e7718adaStb 		.opt.arg = &cfg.serial_status,
55963a81de5Sinoguchi 	},
56063a81de5Sinoguchi 	{
56163a81de5Sinoguchi 		.name = "subj",
56263a81de5Sinoguchi 		.argname = "arg",
56363a81de5Sinoguchi 		.desc = "Use arg instead of request's subject",
56463a81de5Sinoguchi 		.type = OPTION_ARG,
565e7718adaStb 		.opt.arg = &cfg.subj,
56663a81de5Sinoguchi 	},
56763a81de5Sinoguchi 	{
56863a81de5Sinoguchi 		.name = "updatedb",
56963a81de5Sinoguchi 		.desc = "Updates db for expired certificates",
57063a81de5Sinoguchi 		.type = OPTION_FLAG,
571e7718adaStb 		.opt.flag = &cfg.doupdatedb,
57263a81de5Sinoguchi 	},
57363a81de5Sinoguchi 	{
57463a81de5Sinoguchi 		.name = "utf8",
57563a81de5Sinoguchi 		.desc = "Input characters are in UTF-8 (default ASCII)",
57663a81de5Sinoguchi 		.type = OPTION_FUNC,
57763a81de5Sinoguchi 		.opt.func = ca_opt_chtype_utf8,
57863a81de5Sinoguchi 	},
57963a81de5Sinoguchi 	{
58063a81de5Sinoguchi 		.name = "verbose",
58163a81de5Sinoguchi 		.desc = "Verbose output during processing",
58263a81de5Sinoguchi 		.type = OPTION_FLAG,
583e7718adaStb 		.opt.flag = &cfg.verbose,
58463a81de5Sinoguchi 	},
58563a81de5Sinoguchi 	{ NULL },
58663a81de5Sinoguchi };
587dab3f910Sjsing 
58863a81de5Sinoguchi static void
ca_usage(void)58963a81de5Sinoguchi ca_usage(void)
59063a81de5Sinoguchi {
59163a81de5Sinoguchi 	fprintf(stderr,
59263a81de5Sinoguchi 	    "usage: ca  [-batch] [-cert file] [-config file] [-create_serial]\n"
59363a81de5Sinoguchi 	    "    [-crl_CA_compromise time] [-crl_compromise time]\n"
59463a81de5Sinoguchi 	    "    [-crl_hold instruction] [-crl_reason reason] [-crldays days]\n"
59563a81de5Sinoguchi 	    "    [-crlexts section] [-crlhours hours] [-crlsec seconds]\n"
59663a81de5Sinoguchi 	    "    [-days arg] [-enddate date] [-extensions section]\n"
59763a81de5Sinoguchi 	    "    [-extfile file] [-gencrl] [-in file] [-infiles]\n"
59863a81de5Sinoguchi 	    "    [-key password] [-keyfile file] [-keyform pem | der]\n"
59963a81de5Sinoguchi 	    "    [-md alg] [-multivalue-rdn] [-name section]\n"
60063a81de5Sinoguchi 	    "    [-noemailDN] [-notext] [-out file] [-outdir directory]\n"
60163a81de5Sinoguchi 	    "    [-passin arg] [-policy name] [-preserveDN] [-revoke file]\n"
602*77fb829eStb 	    "    [-selfsign] [-sigopt nm:v] [-ss_cert file]\n"
60363a81de5Sinoguchi 	    "    [-startdate date] [-status serial] [-subj arg] [-updatedb]\n"
60463a81de5Sinoguchi 	    "    [-utf8] [-verbose]\n\n");
60563a81de5Sinoguchi 	options_usage(ca_options);
60663a81de5Sinoguchi 	fprintf(stderr, "\n");
60763a81de5Sinoguchi }
60863a81de5Sinoguchi 
609dab3f910Sjsing int
ca_main(int argc,char ** argv)610dab3f910Sjsing ca_main(int argc, char **argv)
611dab3f910Sjsing {
612dab3f910Sjsing 	int free_key = 0;
613dab3f910Sjsing 	int total = 0;
614dab3f910Sjsing 	int total_done = 0;
615dab3f910Sjsing 	long errorline = -1;
616dab3f910Sjsing 	EVP_PKEY *pkey = NULL;
617dab3f910Sjsing 	int output_der = 0;
618dab3f910Sjsing 	char *serialfile = NULL;
619dab3f910Sjsing 	char *crlnumberfile = NULL;
620dab3f910Sjsing 	char *tmp_email_dn = NULL;
621dab3f910Sjsing 	BIGNUM *serial = NULL;
622dab3f910Sjsing 	BIGNUM *crlnumber = NULL;
623dab3f910Sjsing 	unsigned long nameopt = 0, certopt = 0;
624dab3f910Sjsing 	int default_op = 1;
625dab3f910Sjsing 	int ext_copy = EXT_COPY_NONE;
626dab3f910Sjsing 	X509 *x509 = NULL, *x509p = NULL;
627dab3f910Sjsing 	X509 *x = NULL;
628dab3f910Sjsing 	BIO *in = NULL, *out = NULL, *Sout = NULL, *Cout = NULL;
629dab3f910Sjsing 	char *dbfile = NULL;
630dab3f910Sjsing 	CA_DB *db = NULL;
631dab3f910Sjsing 	X509_CRL *crl = NULL;
632dab3f910Sjsing 	X509_REVOKED *r = NULL;
6332c098a5bSinoguchi 	ASN1_TIME *tmptm = NULL;
634c80f2811Sinoguchi 	ASN1_INTEGER *tmpserial;
635dab3f910Sjsing 	char *f;
636dab3f910Sjsing 	const char *p;
637dab3f910Sjsing 	char *const *pp;
638dab3f910Sjsing 	int i, j;
639dab3f910Sjsing 	const EVP_MD *dgst = NULL;
640dab3f910Sjsing 	STACK_OF(CONF_VALUE) *attribs = NULL;
641dab3f910Sjsing 	STACK_OF(X509) *cert_sk = NULL;
642dab3f910Sjsing 	char *tofree = NULL;
643dab3f910Sjsing 	DB_ATTR db_attr;
644df970faaStb 	int default_nid, rv;
645df970faaStb 	int ret = 1;
646dab3f910Sjsing 
64751811eadSderaadt 	if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
6489bc487adSdoug 		perror("pledge");
649e370f0eeSdoug 		exit(1);
650e370f0eeSdoug 	}
6519bc487adSdoug 
652e7718adaStb 	memset(&cfg, 0, sizeof(cfg));
653e7718adaStb 	cfg.email_dn = 1;
654e7718adaStb 	cfg.keyform = FORMAT_PEM;
655e7718adaStb 	cfg.chtype = MBSTRING_ASC;
656e7718adaStb 	cfg.rev_type = REV_NONE;
65763a81de5Sinoguchi 
658dab3f910Sjsing 	conf = NULL;
659dab3f910Sjsing 
66063a81de5Sinoguchi 	if (options_parse(argc, argv, ca_options, NULL, NULL) != 0) {
66163a81de5Sinoguchi 		ca_usage();
662dab3f910Sjsing 		goto err;
663dab3f910Sjsing 	}
664dab3f910Sjsing 
665dab3f910Sjsing 	/*****************************************************************/
666dab3f910Sjsing 	tofree = NULL;
667e7718adaStb 	if (cfg.configfile == NULL)
668e7718adaStb 		cfg.configfile = getenv("OPENSSL_CONF");
669e7718adaStb 	if (cfg.configfile == NULL) {
670dab3f910Sjsing 		if ((tofree = make_config_name()) == NULL) {
671dab3f910Sjsing 			BIO_printf(bio_err, "error making config file name\n");
672dab3f910Sjsing 			goto err;
673dab3f910Sjsing 		}
674e7718adaStb 		cfg.configfile = tofree;
675dab3f910Sjsing 	}
67616f009d4Sinoguchi 	BIO_printf(bio_err, "Using configuration from %s\n",
677e7718adaStb 	    cfg.configfile);
678dab3f910Sjsing 	conf = NCONF_new(NULL);
679e7718adaStb 	if (NCONF_load(conf, cfg.configfile, &errorline) <= 0) {
680dab3f910Sjsing 		if (errorline <= 0)
681dab3f910Sjsing 			BIO_printf(bio_err,
682dab3f910Sjsing 			    "error loading the config file '%s'\n",
683e7718adaStb 			    cfg.configfile);
684dab3f910Sjsing 		else
685dab3f910Sjsing 			BIO_printf(bio_err,
686dab3f910Sjsing 			    "error on line %ld of config file '%s'\n",
687e7718adaStb 			    errorline, cfg.configfile);
688dab3f910Sjsing 		goto err;
689dab3f910Sjsing 	}
690dab3f910Sjsing 	free(tofree);
691dab3f910Sjsing 	tofree = NULL;
692dab3f910Sjsing 
693dab3f910Sjsing 	/* Lets get the config section we are using */
694e7718adaStb 	if (cfg.section == NULL) {
695e7718adaStb 		cfg.section = NCONF_get_string(conf, BASE_SECTION,
69616f009d4Sinoguchi 		    ENV_DEFAULT_CA);
697e7718adaStb 		if (cfg.section == NULL) {
698dab3f910Sjsing 			lookup_fail(BASE_SECTION, ENV_DEFAULT_CA);
699dab3f910Sjsing 			goto err;
700dab3f910Sjsing 		}
701dab3f910Sjsing 	}
702dab3f910Sjsing 	if (conf != NULL) {
703dab3f910Sjsing 		p = NCONF_get_string(conf, NULL, "oid_file");
704dab3f910Sjsing 		if (p == NULL)
705dab3f910Sjsing 			ERR_clear_error();
706dab3f910Sjsing 		if (p != NULL) {
707dab3f910Sjsing 			BIO *oid_bio;
708dab3f910Sjsing 
709dab3f910Sjsing 			oid_bio = BIO_new_file(p, "r");
710dab3f910Sjsing 			if (oid_bio == NULL) {
711dab3f910Sjsing 				/*
712dab3f910Sjsing 				BIO_printf(bio_err,
713dab3f910Sjsing 				    "problems opening %s for extra oid's\n", p);
714dab3f910Sjsing 				ERR_print_errors(bio_err);
715dab3f910Sjsing 				*/
716dab3f910Sjsing 				ERR_clear_error();
717dab3f910Sjsing 			} else {
718dab3f910Sjsing 				OBJ_create_objects(oid_bio);
719dab3f910Sjsing 				BIO_free(oid_bio);
720dab3f910Sjsing 			}
721dab3f910Sjsing 		}
722dab3f910Sjsing 		if (!add_oid_section(bio_err, conf)) {
723dab3f910Sjsing 			ERR_print_errors(bio_err);
724dab3f910Sjsing 			goto err;
725dab3f910Sjsing 		}
726dab3f910Sjsing 	}
727e7718adaStb 	f = NCONF_get_string(conf, cfg.section, STRING_MASK);
728eb28c9b3Sinoguchi 	if (f == NULL)
729dab3f910Sjsing 		ERR_clear_error();
730dab3f910Sjsing 
731eb28c9b3Sinoguchi 	if (f != NULL && !ASN1_STRING_set_default_mask_asc(f)) {
732dab3f910Sjsing 		BIO_printf(bio_err,
733dab3f910Sjsing 		    "Invalid global string mask setting %s\n", f);
734dab3f910Sjsing 		goto err;
735dab3f910Sjsing 	}
736e7718adaStb 	if (cfg.chtype != MBSTRING_UTF8) {
737e7718adaStb 		f = NCONF_get_string(conf, cfg.section, UTF8_IN);
738eb28c9b3Sinoguchi 		if (f == NULL)
739dab3f910Sjsing 			ERR_clear_error();
7409da5b6dbSinoguchi 		else if (strcmp(f, "yes") == 0)
741e7718adaStb 			cfg.chtype = MBSTRING_UTF8;
742dab3f910Sjsing 	}
743dab3f910Sjsing 	db_attr.unique_subject = 1;
744e7718adaStb 	p = NCONF_get_string(conf, cfg.section, ENV_UNIQUE_SUBJECT);
745eb28c9b3Sinoguchi 	if (p != NULL) {
746dab3f910Sjsing 		db_attr.unique_subject = parse_yesno(p, 1);
747dab3f910Sjsing 	} else
748dab3f910Sjsing 		ERR_clear_error();
749dab3f910Sjsing 
750dab3f910Sjsing 	in = BIO_new(BIO_s_file());
751dab3f910Sjsing 	out = BIO_new(BIO_s_file());
752dab3f910Sjsing 	Sout = BIO_new(BIO_s_file());
753dab3f910Sjsing 	Cout = BIO_new(BIO_s_file());
754dab3f910Sjsing 	if ((in == NULL) || (out == NULL) || (Sout == NULL) || (Cout == NULL)) {
755dab3f910Sjsing 		ERR_print_errors(bio_err);
756dab3f910Sjsing 		goto err;
757dab3f910Sjsing 	}
758dab3f910Sjsing 	/*****************************************************************/
759dab3f910Sjsing 	/* report status of cert with serial number given on command line */
760e7718adaStb 	if (cfg.serial_status) {
761e7718adaStb 		if ((dbfile = NCONF_get_string(conf, cfg.section,
762dab3f910Sjsing 		    ENV_DATABASE)) == NULL) {
763e7718adaStb 			lookup_fail(cfg.section, ENV_DATABASE);
764dab3f910Sjsing 			goto err;
765dab3f910Sjsing 		}
766dab3f910Sjsing 		db = load_index(dbfile, &db_attr);
767dab3f910Sjsing 		if (db == NULL)
768dab3f910Sjsing 			goto err;
769dab3f910Sjsing 
770dab3f910Sjsing 		if (!index_index(db))
771dab3f910Sjsing 			goto err;
772dab3f910Sjsing 
773e7718adaStb 		if (get_certificate_status(cfg.serial_status, db) != 1)
774dab3f910Sjsing 			BIO_printf(bio_err, "Error verifying serial %s!\n",
775e7718adaStb 			    cfg.serial_status);
776dab3f910Sjsing 		goto err;
777dab3f910Sjsing 	}
778dab3f910Sjsing 	/*****************************************************************/
779dab3f910Sjsing 	/* we definitely need a private key, so let's get it */
780dab3f910Sjsing 
781e7718adaStb 	if ((cfg.keyfile == NULL) &&
782e7718adaStb 	    ((cfg.keyfile = NCONF_get_string(conf, cfg.section,
78316f009d4Sinoguchi 	    ENV_PRIVATE_KEY)) == NULL)) {
784e7718adaStb 		lookup_fail(cfg.section, ENV_PRIVATE_KEY);
785dab3f910Sjsing 		goto err;
786dab3f910Sjsing 	}
787e7718adaStb 	if (cfg.key == NULL) {
788dab3f910Sjsing 		free_key = 1;
789e7718adaStb 		if (!app_passwd(bio_err, cfg.passargin, NULL,
790e7718adaStb 		    &cfg.key, NULL)) {
791dab3f910Sjsing 			BIO_printf(bio_err, "Error getting password\n");
792dab3f910Sjsing 			goto err;
793dab3f910Sjsing 		}
794dab3f910Sjsing 	}
795e7718adaStb 	pkey = load_key(bio_err, cfg.keyfile, cfg.keyform, 0,
796e7718adaStb 	    cfg.key, "CA private key");
797e7718adaStb 	if (cfg.key != NULL)
798e7718adaStb 		explicit_bzero(cfg.key, strlen(cfg.key));
799dab3f910Sjsing 	if (pkey == NULL) {
800dab3f910Sjsing 		/* load_key() has already printed an appropriate message */
801dab3f910Sjsing 		goto err;
802dab3f910Sjsing 	}
803dab3f910Sjsing 	/*****************************************************************/
804dab3f910Sjsing 	/* we need a certificate */
805*77fb829eStb 	if (!cfg.selfsign || cfg.ss_cert_file != NULL || cfg.gencrl) {
806e7718adaStb 		if ((cfg.certfile == NULL) &&
807e7718adaStb 		    ((cfg.certfile = NCONF_get_string(conf,
808e7718adaStb 		    cfg.section, ENV_CERTIFICATE)) == NULL)) {
809e7718adaStb 			lookup_fail(cfg.section, ENV_CERTIFICATE);
810dab3f910Sjsing 			goto err;
811dab3f910Sjsing 		}
812e7718adaStb 		x509 = load_cert(bio_err, cfg.certfile, FORMAT_PEM, NULL,
813dab3f910Sjsing 		    "CA certificate");
814dab3f910Sjsing 		if (x509 == NULL)
815dab3f910Sjsing 			goto err;
816dab3f910Sjsing 
817dab3f910Sjsing 		if (!X509_check_private_key(x509, pkey)) {
818dab3f910Sjsing 			BIO_printf(bio_err,
819dab3f910Sjsing 			    "CA certificate and CA private key do not match\n");
820dab3f910Sjsing 			goto err;
821dab3f910Sjsing 		}
822dab3f910Sjsing 	}
823e7718adaStb 	if (!cfg.selfsign)
824dab3f910Sjsing 		x509p = x509;
825dab3f910Sjsing 
826dab3f910Sjsing 	f = NCONF_get_string(conf, BASE_SECTION, ENV_PRESERVE);
827dab3f910Sjsing 	if (f == NULL)
828dab3f910Sjsing 		ERR_clear_error();
829dab3f910Sjsing 	if ((f != NULL) && ((*f == 'y') || (*f == 'Y')))
830e7718adaStb 		cfg.preserve = 1;
831dab3f910Sjsing 	f = NCONF_get_string(conf, BASE_SECTION, ENV_MSIE_HACK);
832dab3f910Sjsing 	if (f == NULL)
833dab3f910Sjsing 		ERR_clear_error();
834dab3f910Sjsing 	if ((f != NULL) && ((*f == 'y') || (*f == 'Y')))
835e7718adaStb 		cfg.msie_hack = 1;
836dab3f910Sjsing 
837e7718adaStb 	f = NCONF_get_string(conf, cfg.section, ENV_NAMEOPT);
838dab3f910Sjsing 
839e9918fb5Sinoguchi 	if (f != NULL) {
840dab3f910Sjsing 		if (!set_name_ex(&nameopt, f)) {
841dab3f910Sjsing 			BIO_printf(bio_err,
842dab3f910Sjsing 			    "Invalid name options: \"%s\"\n", f);
843dab3f910Sjsing 			goto err;
844dab3f910Sjsing 		}
845dab3f910Sjsing 		default_op = 0;
846dab3f910Sjsing 	} else
847dab3f910Sjsing 		ERR_clear_error();
848dab3f910Sjsing 
849e7718adaStb 	f = NCONF_get_string(conf, cfg.section, ENV_CERTOPT);
850dab3f910Sjsing 
851eb28c9b3Sinoguchi 	if (f != NULL) {
852dab3f910Sjsing 		if (!set_cert_ex(&certopt, f)) {
853dab3f910Sjsing 			BIO_printf(bio_err,
854dab3f910Sjsing 			    "Invalid certificate options: \"%s\"\n", f);
855dab3f910Sjsing 			goto err;
856dab3f910Sjsing 		}
857dab3f910Sjsing 		default_op = 0;
858dab3f910Sjsing 	} else
859dab3f910Sjsing 		ERR_clear_error();
860dab3f910Sjsing 
861e7718adaStb 	f = NCONF_get_string(conf, cfg.section, ENV_EXTCOPY);
862dab3f910Sjsing 
863eb28c9b3Sinoguchi 	if (f != NULL) {
864dab3f910Sjsing 		if (!set_ext_copy(&ext_copy, f)) {
865dab3f910Sjsing 			BIO_printf(bio_err,
866dab3f910Sjsing 			    "Invalid extension copy option: \"%s\"\n", f);
867dab3f910Sjsing 			goto err;
868dab3f910Sjsing 		}
869dab3f910Sjsing 	} else
870dab3f910Sjsing 		ERR_clear_error();
871dab3f910Sjsing 
872dab3f910Sjsing 	/*****************************************************************/
873dab3f910Sjsing 	/* lookup where to write new certificates */
874e7718adaStb 	if (cfg.outdir == NULL && cfg.req) {
875e7718adaStb 		if ((cfg.outdir = NCONF_get_string(conf,
876e7718adaStb 		    cfg.section, ENV_NEW_CERTS_DIR)) == NULL) {
877d8741cfaSderaadt 			BIO_printf(bio_err, "output directory %s not defined\n",
878d8741cfaSderaadt 			    ENV_NEW_CERTS_DIR);
879dab3f910Sjsing 			goto err;
880dab3f910Sjsing 		}
881dab3f910Sjsing 	}
882dab3f910Sjsing 	/*****************************************************************/
883dab3f910Sjsing 	/* we need to load the database file */
884e7718adaStb 	if ((dbfile = NCONF_get_string(conf, cfg.section,
88516f009d4Sinoguchi 	    ENV_DATABASE)) == NULL) {
886e7718adaStb 		lookup_fail(cfg.section, ENV_DATABASE);
887dab3f910Sjsing 		goto err;
888dab3f910Sjsing 	}
889dab3f910Sjsing 	db = load_index(dbfile, &db_attr);
890dab3f910Sjsing 	if (db == NULL)
891dab3f910Sjsing 		goto err;
892dab3f910Sjsing 
893dab3f910Sjsing 	/* Lets check some fields */
894dab3f910Sjsing 	for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
895dab3f910Sjsing 		pp = sk_OPENSSL_PSTRING_value(db->db->data, i);
896dab3f910Sjsing 		if ((pp[DB_type][0] != DB_TYPE_REV) &&
897dab3f910Sjsing 		    (pp[DB_rev_date][0] != '\0')) {
89816f009d4Sinoguchi 			BIO_printf(bio_err,
89916f009d4Sinoguchi 			    "entry %d: not revoked yet, but has a revocation date\n",
90016f009d4Sinoguchi 			    i + 1);
901dab3f910Sjsing 			goto err;
902dab3f910Sjsing 		}
903dab3f910Sjsing 		if ((pp[DB_type][0] == DB_TYPE_REV) &&
904dab3f910Sjsing 		    !make_revoked(NULL, pp[DB_rev_date])) {
905dab3f910Sjsing 			BIO_printf(bio_err, " in entry %d\n", i + 1);
906dab3f910Sjsing 			goto err;
907dab3f910Sjsing 		}
908dab3f910Sjsing 		if (!check_time_format((char *) pp[DB_exp_date])) {
909dab3f910Sjsing 			BIO_printf(bio_err, "entry %d: invalid expiry date\n",
910dab3f910Sjsing 			    i + 1);
911dab3f910Sjsing 			goto err;
912dab3f910Sjsing 		}
913dab3f910Sjsing 		p = pp[DB_serial];
914dab3f910Sjsing 		j = strlen(p);
915dab3f910Sjsing 		if (*p == '-') {
916dab3f910Sjsing 			p++;
917dab3f910Sjsing 			j--;
918dab3f910Sjsing 		}
919dab3f910Sjsing 		if ((j & 1) || (j < 2)) {
920dab3f910Sjsing 			BIO_printf(bio_err,
921dab3f910Sjsing 			    "entry %d: bad serial number length (%d)\n",
922dab3f910Sjsing 			    i + 1, j);
923dab3f910Sjsing 			goto err;
924dab3f910Sjsing 		}
925dab3f910Sjsing 		while (*p) {
926dab3f910Sjsing 			if (!(((*p >= '0') && (*p <= '9')) ||
927dab3f910Sjsing 			    ((*p >= 'A') && (*p <= 'F')) ||
928dab3f910Sjsing 			    ((*p >= 'a') && (*p <= 'f')))) {
92916f009d4Sinoguchi 				BIO_printf(bio_err,
93016f009d4Sinoguchi 				    "entry %d: bad serial number characters, char pos %ld, char is '%c'\n",
93116f009d4Sinoguchi 				    i + 1, (long) (p - pp[DB_serial]), *p);
932dab3f910Sjsing 				goto err;
933dab3f910Sjsing 			}
934dab3f910Sjsing 			p++;
935dab3f910Sjsing 		}
936dab3f910Sjsing 	}
937e7718adaStb 	if (cfg.verbose) {
93816f009d4Sinoguchi 		BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT);
939dab3f910Sjsing 		TXT_DB_write(out, db->db);
940dab3f910Sjsing 		BIO_printf(bio_err, "%d entries loaded from the database\n",
941dab3f910Sjsing 		    sk_OPENSSL_PSTRING_num(db->db->data));
942dab3f910Sjsing 		BIO_printf(bio_err, "generating index\n");
943dab3f910Sjsing 	}
944dab3f910Sjsing 	if (!index_index(db))
945dab3f910Sjsing 		goto err;
946dab3f910Sjsing 
947dab3f910Sjsing 	/*****************************************************************/
948dab3f910Sjsing 	/* Update the db file for expired certificates */
949e7718adaStb 	if (cfg.doupdatedb) {
950e7718adaStb 		if (cfg.verbose)
951dab3f910Sjsing 			BIO_printf(bio_err, "Updating %s ...\n", dbfile);
952dab3f910Sjsing 
953dab3f910Sjsing 		i = do_updatedb(db);
954dab3f910Sjsing 		if (i == -1) {
955dab3f910Sjsing 			BIO_printf(bio_err, "Malloc failure\n");
956dab3f910Sjsing 			goto err;
957dab3f910Sjsing 		} else if (i == 0) {
958e7718adaStb 			if (cfg.verbose)
959dab3f910Sjsing 				BIO_printf(bio_err,
960dab3f910Sjsing 				    "No entries found to mark expired\n");
961dab3f910Sjsing 		} else {
962dab3f910Sjsing 			if (!save_index(dbfile, "new", db))
963dab3f910Sjsing 				goto err;
964dab3f910Sjsing 
965dab3f910Sjsing 			if (!rotate_index(dbfile, "new", "old"))
966dab3f910Sjsing 				goto err;
967dab3f910Sjsing 
968e7718adaStb 			if (cfg.verbose)
969dab3f910Sjsing 				BIO_printf(bio_err,
970dab3f910Sjsing 				    "Done. %d entries marked as expired\n", i);
971dab3f910Sjsing 		}
972dab3f910Sjsing 	}
973dab3f910Sjsing 	/*****************************************************************/
974dab3f910Sjsing 	/* Read extentions config file                                   */
975e7718adaStb 	if (cfg.extfile != NULL) {
976dab3f910Sjsing 		extconf = NCONF_new(NULL);
977e7718adaStb 		if (NCONF_load(extconf, cfg.extfile, &errorline) <= 0) {
978dab3f910Sjsing 			if (errorline <= 0)
979dab3f910Sjsing 				BIO_printf(bio_err,
980dab3f910Sjsing 				    "ERROR: loading the config file '%s'\n",
981e7718adaStb 				    cfg.extfile);
982dab3f910Sjsing 			else
983dab3f910Sjsing 				BIO_printf(bio_err,
984dab3f910Sjsing 				    "ERROR: on line %ld of config file '%s'\n",
985e7718adaStb 				    errorline, cfg.extfile);
986dab3f910Sjsing 			ret = 1;
987dab3f910Sjsing 			goto err;
988dab3f910Sjsing 		}
989e7718adaStb 		if (cfg.verbose)
990dab3f910Sjsing 			BIO_printf(bio_err,
991dab3f910Sjsing 			    "Successfully loaded extensions file %s\n",
992e7718adaStb 			    cfg.extfile);
993dab3f910Sjsing 
994dab3f910Sjsing 		/* We can have sections in the ext file */
995e7718adaStb 		if (cfg.extensions == NULL &&
996e7718adaStb 		    (cfg.extensions = NCONF_get_string(extconf, "default",
99716f009d4Sinoguchi 		    "extensions")) == NULL)
998e7718adaStb 			cfg.extensions = "default";
999dab3f910Sjsing 	}
1000dab3f910Sjsing 	/*****************************************************************/
1001e7718adaStb 	if (cfg.req || cfg.gencrl) {
1002e7718adaStb 		if (cfg.outfile != NULL) {
1003e7718adaStb 			if (BIO_write_filename(Sout, cfg.outfile) <= 0) {
1004e7718adaStb 				perror(cfg.outfile);
1005dab3f910Sjsing 				goto err;
1006dab3f910Sjsing 			}
1007dab3f910Sjsing 		} else {
1008dab3f910Sjsing 			BIO_set_fp(Sout, stdout, BIO_NOCLOSE | BIO_FP_TEXT);
1009dab3f910Sjsing 		}
1010dab3f910Sjsing 	}
1011df970faaStb 
1012df970faaStb 	rv = EVP_PKEY_get_default_digest_nid(pkey, &default_nid);
1013df970faaStb 	if (rv == 2 && default_nid == NID_undef) {
1014df970faaStb 		/* The digest is required to be EVP_md_null() (EdDSA). */
1015df970faaStb 		dgst = EVP_md_null();
1016df970faaStb 	} else {
1017df970faaStb 		/* Ignore rv unless we need a valid default_nid. */
1018df970faaStb 		if (cfg.md == NULL)
1019df970faaStb 			cfg.md = NCONF_get_string(conf, cfg.section,
1020df970faaStb 			    ENV_DEFAULT_MD);
1021df970faaStb 		if (cfg.md == NULL) {
1022e7718adaStb 			lookup_fail(cfg.section, ENV_DEFAULT_MD);
1023dab3f910Sjsing 			goto err;
1024dab3f910Sjsing 		}
1025e7718adaStb 		if (strcmp(cfg.md, "default") == 0) {
1026df970faaStb 			if (rv <= 0) {
1027dab3f910Sjsing 				BIO_puts(bio_err, "no default digest\n");
1028dab3f910Sjsing 				goto err;
1029dab3f910Sjsing 			}
1030df970faaStb 			cfg.md = (char *)OBJ_nid2sn(default_nid);
1031df970faaStb 		}
1032e7718adaStb 		if (cfg.md == NULL)
103354292de2Sinoguchi 			goto err;
1034e7718adaStb 		if ((dgst = EVP_get_digestbyname(cfg.md)) == NULL) {
1035df970faaStb 			BIO_printf(bio_err, "%s is an unsupported "
1036df970faaStb 			    "message digest type\n", cfg.md);
1037dab3f910Sjsing 			goto err;
1038dab3f910Sjsing 		}
1039df970faaStb 	}
1040e7718adaStb 	if (cfg.req) {
1041e7718adaStb 		if ((cfg.email_dn == 1) &&
1042e7718adaStb 		    ((tmp_email_dn = NCONF_get_string(conf, cfg.section,
104316f009d4Sinoguchi 		    ENV_DEFAULT_EMAIL_DN)) != NULL)) {
1044dab3f910Sjsing 			if (strcmp(tmp_email_dn, "no") == 0)
1045e7718adaStb 				cfg.email_dn = 0;
1046dab3f910Sjsing 		}
1047e7718adaStb 		if (cfg.verbose)
1048dab3f910Sjsing 			BIO_printf(bio_err, "message digest is %s\n",
1049f43c9d0bStb 			    OBJ_nid2ln(EVP_MD_type(dgst)));
1050e7718adaStb 		if ((cfg.policy == NULL) &&
1051e7718adaStb 		    ((cfg.policy = NCONF_get_string(conf,
1052e7718adaStb 		    cfg.section, ENV_POLICY)) == NULL)) {
1053e7718adaStb 			lookup_fail(cfg.section, ENV_POLICY);
1054dab3f910Sjsing 			goto err;
1055dab3f910Sjsing 		}
1056e7718adaStb 		if (cfg.verbose)
1057e7718adaStb 			BIO_printf(bio_err, "policy is %s\n", cfg.policy);
1058dab3f910Sjsing 
1059e7718adaStb 		if ((serialfile = NCONF_get_string(conf, cfg.section,
1060dab3f910Sjsing 		    ENV_SERIAL)) == NULL) {
1061e7718adaStb 			lookup_fail(cfg.section, ENV_SERIAL);
1062dab3f910Sjsing 			goto err;
1063dab3f910Sjsing 		}
1064eb28c9b3Sinoguchi 		if (extconf == NULL) {
1065dab3f910Sjsing 			/*
1066dab3f910Sjsing 			 * no '-extfile' option, so we look for extensions in
1067dab3f910Sjsing 			 * the main configuration file
1068dab3f910Sjsing 			 */
1069e7718adaStb 			if (cfg.extensions == NULL) {
1070e7718adaStb 				cfg.extensions = NCONF_get_string(conf,
1071e7718adaStb 				    cfg.section, ENV_EXTENSIONS);
1072e7718adaStb 				if (cfg.extensions == NULL)
1073dab3f910Sjsing 					ERR_clear_error();
1074dab3f910Sjsing 			}
1075e7718adaStb 			if (cfg.extensions != NULL) {
1076dab3f910Sjsing 				/* Check syntax of file */
1077dab3f910Sjsing 				X509V3_CTX ctx;
1078dab3f910Sjsing 				X509V3_set_ctx_test(&ctx);
1079dab3f910Sjsing 				X509V3_set_nconf(&ctx, conf);
1080dab3f910Sjsing 				if (!X509V3_EXT_add_nconf(conf, &ctx,
1081e7718adaStb 				    cfg.extensions, NULL)) {
1082dab3f910Sjsing 					BIO_printf(bio_err,
1083dab3f910Sjsing 					    "Error Loading extension section %s\n",
1084e7718adaStb 					    cfg.extensions);
1085dab3f910Sjsing 					ret = 1;
1086dab3f910Sjsing 					goto err;
1087dab3f910Sjsing 				}
1088dab3f910Sjsing 			}
1089dab3f910Sjsing 		}
1090e7718adaStb 		if (cfg.startdate == NULL) {
1091e7718adaStb 			cfg.startdate = NCONF_get_string(conf,
1092e7718adaStb 			    cfg.section, ENV_DEFAULT_STARTDATE);
1093e7718adaStb 			if (cfg.startdate == NULL)
1094dab3f910Sjsing 				ERR_clear_error();
1095dab3f910Sjsing 		}
1096e7718adaStb 		if (cfg.startdate == NULL)
1097e7718adaStb 			cfg.startdate = "today";
1098dab3f910Sjsing 
1099e7718adaStb 		if (cfg.enddate == NULL) {
1100e7718adaStb 			cfg.enddate = NCONF_get_string(conf,
1101e7718adaStb 			    cfg.section, ENV_DEFAULT_ENDDATE);
1102e7718adaStb 			if (cfg.enddate == NULL)
1103dab3f910Sjsing 				ERR_clear_error();
1104dab3f910Sjsing 		}
1105e7718adaStb 		if (cfg.days == 0 && cfg.enddate == NULL) {
1106e7718adaStb 			if (!NCONF_get_number(conf, cfg.section,
1107e7718adaStb 				ENV_DEFAULT_DAYS, &cfg.days))
1108e7718adaStb 				cfg.days = 0;
1109dab3f910Sjsing 		}
1110e7718adaStb 		if (cfg.enddate == NULL && cfg.days == 0) {
1111dab3f910Sjsing 			BIO_printf(bio_err,
1112dab3f910Sjsing 			    "cannot lookup how many days to certify for\n");
1113dab3f910Sjsing 			goto err;
1114dab3f910Sjsing 		}
1115e7718adaStb 		if ((serial = load_serial(serialfile, cfg.create_serial,
111616f009d4Sinoguchi 		    NULL)) == NULL) {
1117dab3f910Sjsing 			BIO_printf(bio_err,
1118dab3f910Sjsing 			    "error while loading serial number\n");
1119dab3f910Sjsing 			goto err;
1120dab3f910Sjsing 		}
1121e7718adaStb 		if (cfg.verbose) {
1122dab3f910Sjsing 			if (BN_is_zero(serial))
1123dab3f910Sjsing 				BIO_printf(bio_err,
1124dab3f910Sjsing 				    "next serial number is 00\n");
1125dab3f910Sjsing 			else {
1126dab3f910Sjsing 				if ((f = BN_bn2hex(serial)) == NULL)
1127dab3f910Sjsing 					goto err;
1128dab3f910Sjsing 				BIO_printf(bio_err,
1129dab3f910Sjsing 				    "next serial number is %s\n", f);
1130dab3f910Sjsing 				free(f);
1131dab3f910Sjsing 			}
1132dab3f910Sjsing 		}
1133e7718adaStb 		if ((attribs = NCONF_get_section(conf, cfg.policy)) ==
113416f009d4Sinoguchi 		    NULL) {
113516f009d4Sinoguchi 			BIO_printf(bio_err, "unable to find 'section' for %s\n",
1136e7718adaStb 			    cfg.policy);
1137dab3f910Sjsing 			goto err;
1138dab3f910Sjsing 		}
1139dab3f910Sjsing 		if ((cert_sk = sk_X509_new_null()) == NULL) {
1140dab3f910Sjsing 			BIO_printf(bio_err, "Memory allocation failure\n");
1141dab3f910Sjsing 			goto err;
1142dab3f910Sjsing 		}
1143e7718adaStb 		if (cfg.ss_cert_file != NULL) {
1144dab3f910Sjsing 			total++;
1145e7718adaStb 			j = certify_cert(&x, cfg.ss_cert_file, pkey, x509,
1146e7718adaStb 			    dgst, cfg.sigopts, attribs, db, serial,
1147e7718adaStb 			    cfg.subj, cfg.chtype,
1148e7718adaStb 			    cfg.multirdn, cfg.email_dn,
1149e7718adaStb 			    cfg.startdate, cfg.enddate,
1150e7718adaStb 			    cfg.days, cfg.batch,
1151e7718adaStb 			    cfg.extensions, conf, cfg.verbose,
115216f009d4Sinoguchi 			    certopt, nameopt, default_op, ext_copy);
1153dab3f910Sjsing 			if (j < 0)
1154dab3f910Sjsing 				goto err;
1155dab3f910Sjsing 			if (j > 0) {
1156dab3f910Sjsing 				total_done++;
1157dab3f910Sjsing 				BIO_printf(bio_err, "\n");
1158dab3f910Sjsing 				if (!BN_add_word(serial, 1))
1159dab3f910Sjsing 					goto err;
1160dab3f910Sjsing 				if (!sk_X509_push(cert_sk, x)) {
1161dab3f910Sjsing 					BIO_printf(bio_err,
1162dab3f910Sjsing 					    "Memory allocation failure\n");
1163dab3f910Sjsing 					goto err;
1164dab3f910Sjsing 				}
1165dab3f910Sjsing 			}
1166dab3f910Sjsing 		}
1167e7718adaStb 		if (cfg.infile != NULL) {
1168dab3f910Sjsing 			total++;
1169e7718adaStb 			j = certify(&x, cfg.infile, pkey, x509p, dgst,
1170e7718adaStb 			    cfg.sigopts, attribs, db, serial,
1171e7718adaStb 			    cfg.subj, cfg.chtype,
1172e7718adaStb 			    cfg.multirdn, cfg.email_dn,
1173e7718adaStb 			    cfg.startdate, cfg.enddate,
1174e7718adaStb 			    cfg.days, cfg.batch,
1175e7718adaStb 			    cfg.extensions, conf, cfg.verbose,
117616f009d4Sinoguchi 			    certopt, nameopt, default_op, ext_copy,
1177e7718adaStb 			    cfg.selfsign);
1178dab3f910Sjsing 			if (j < 0)
1179dab3f910Sjsing 				goto err;
1180dab3f910Sjsing 			if (j > 0) {
1181dab3f910Sjsing 				total_done++;
1182dab3f910Sjsing 				BIO_printf(bio_err, "\n");
1183dab3f910Sjsing 				if (!BN_add_word(serial, 1))
1184dab3f910Sjsing 					goto err;
1185dab3f910Sjsing 				if (!sk_X509_push(cert_sk, x)) {
1186dab3f910Sjsing 					BIO_printf(bio_err,
1187dab3f910Sjsing 					    "Memory allocation failure\n");
1188dab3f910Sjsing 					goto err;
1189dab3f910Sjsing 				}
1190dab3f910Sjsing 			}
1191dab3f910Sjsing 		}
1192e7718adaStb 		for (i = 0; i < cfg.infiles_num; i++) {
1193dab3f910Sjsing 			total++;
1194e7718adaStb 			j = certify(&x, cfg.infiles[i], pkey, x509p, dgst,
1195e7718adaStb 			    cfg.sigopts, attribs, db, serial,
1196e7718adaStb 			    cfg.subj, cfg.chtype,
1197e7718adaStb 			    cfg.multirdn, cfg.email_dn,
1198e7718adaStb 			    cfg.startdate, cfg.enddate,
1199e7718adaStb 			    cfg.days, cfg.batch,
1200e7718adaStb 			    cfg.extensions, conf, cfg.verbose,
120116f009d4Sinoguchi 			    certopt, nameopt, default_op, ext_copy,
1202e7718adaStb 			    cfg.selfsign);
1203dab3f910Sjsing 			if (j < 0)
1204dab3f910Sjsing 				goto err;
1205dab3f910Sjsing 			if (j > 0) {
1206dab3f910Sjsing 				total_done++;
1207dab3f910Sjsing 				BIO_printf(bio_err, "\n");
1208dab3f910Sjsing 				if (!BN_add_word(serial, 1))
1209dab3f910Sjsing 					goto err;
1210dab3f910Sjsing 				if (!sk_X509_push(cert_sk, x)) {
1211dab3f910Sjsing 					BIO_printf(bio_err,
1212dab3f910Sjsing 					    "Memory allocation failure\n");
1213dab3f910Sjsing 					goto err;
1214dab3f910Sjsing 				}
1215dab3f910Sjsing 			}
1216dab3f910Sjsing 		}
1217dab3f910Sjsing 		/*
1218dab3f910Sjsing 		 * we have a stack of newly certified certificates and a data
1219dab3f910Sjsing 		 * base and serial number that need updating
1220dab3f910Sjsing 		 */
1221dab3f910Sjsing 
1222dab3f910Sjsing 		if (sk_X509_num(cert_sk) > 0) {
1223e7718adaStb 			if (!cfg.batch) {
1224b707c6faSderaadt 				char answer[10];
1225b707c6faSderaadt 
122616f009d4Sinoguchi 				BIO_printf(bio_err,
122716f009d4Sinoguchi 				    "\n%d out of %d certificate requests certified, commit? [y/n]",
122816f009d4Sinoguchi 				    total_done, total);
1229dab3f910Sjsing 				(void) BIO_flush(bio_err);
123016f009d4Sinoguchi 				if (fgets(answer, sizeof answer - 1, stdin) ==
123116f009d4Sinoguchi 				    NULL) {
123216f009d4Sinoguchi 					BIO_printf(bio_err,
123316f009d4Sinoguchi 					    "CERTIFICATION CANCELED: I/O error\n");
1234dab3f910Sjsing 					ret = 0;
1235dab3f910Sjsing 					goto err;
1236dab3f910Sjsing 				}
1237b707c6faSderaadt 				if ((answer[0] != 'y') && (answer[0] != 'Y')) {
123816f009d4Sinoguchi 					BIO_printf(bio_err,
123916f009d4Sinoguchi 					    "CERTIFICATION CANCELED\n");
1240dab3f910Sjsing 					ret = 0;
1241dab3f910Sjsing 					goto err;
1242dab3f910Sjsing 				}
1243dab3f910Sjsing 			}
124416f009d4Sinoguchi 			BIO_printf(bio_err,
124516f009d4Sinoguchi 			    "Write out database with %d new entries\n",
124616f009d4Sinoguchi 			    sk_X509_num(cert_sk));
1247dab3f910Sjsing 
1248dab3f910Sjsing 			if (!save_serial(serialfile, "new", serial, NULL))
1249dab3f910Sjsing 				goto err;
1250dab3f910Sjsing 
1251dab3f910Sjsing 			if (!save_index(dbfile, "new", db))
1252dab3f910Sjsing 				goto err;
1253dab3f910Sjsing 		}
1254e7718adaStb 		if (cfg.verbose)
1255dab3f910Sjsing 			BIO_printf(bio_err, "writing new certificates\n");
1256dab3f910Sjsing 		for (i = 0; i < sk_X509_num(cert_sk); i++) {
125735ccf6b5Sinoguchi 			ASN1_INTEGER *serialNumber;
1258dab3f910Sjsing 			int k;
1259695cbeafSdoug 			char *serialstr;
1260dab3f910Sjsing 			unsigned char *data;
1261b707c6faSderaadt 			char pempath[PATH_MAX];
1262dab3f910Sjsing 
1263dab3f910Sjsing 			x = sk_X509_value(cert_sk, i);
1264dab3f910Sjsing 
126535ccf6b5Sinoguchi 			serialNumber = X509_get_serialNumber(x);
126635ccf6b5Sinoguchi 			j = ASN1_STRING_length(serialNumber);
126735ccf6b5Sinoguchi 			data = ASN1_STRING_data(serialNumber);
126835ccf6b5Sinoguchi 
1269dab3f910Sjsing 			if (j > 0)
1270695cbeafSdoug 				serialstr = bin2hex(data, j);
1271dab3f910Sjsing 			else
1272695cbeafSdoug 				serialstr = strdup("00");
1273eb28c9b3Sinoguchi 			if (serialstr != NULL) {
1274b707c6faSderaadt 				k = snprintf(pempath, sizeof(pempath),
1275e7718adaStb 				    "%s/%s.pem", cfg.outdir, serialstr);
1276695cbeafSdoug 				free(serialstr);
1277515e489cSderaadt 				if (k < 0 || k >= sizeof(pempath)) {
1278dab3f910Sjsing 					BIO_printf(bio_err,
1279dab3f910Sjsing 					    "certificate file name too long\n");
1280dab3f910Sjsing 					goto err;
1281dab3f910Sjsing 				}
1282dab3f910Sjsing 			} else {
1283dab3f910Sjsing 				BIO_printf(bio_err,
1284dab3f910Sjsing 				    "memory allocation failed\n");
1285dab3f910Sjsing 				goto err;
1286dab3f910Sjsing 			}
1287e7718adaStb 			if (cfg.verbose)
1288b707c6faSderaadt 				BIO_printf(bio_err, "writing %s\n", pempath);
1289dab3f910Sjsing 
1290b707c6faSderaadt 			if (BIO_write_filename(Cout, pempath) <= 0) {
1291b707c6faSderaadt 				perror(pempath);
1292dab3f910Sjsing 				goto err;
1293dab3f910Sjsing 			}
129454292de2Sinoguchi 			if (!write_new_certificate(Cout, x, 0,
1295e7718adaStb 			    cfg.notext))
129654292de2Sinoguchi 				goto err;
129754292de2Sinoguchi 			if (!write_new_certificate(Sout, x, output_der,
1298e7718adaStb 			    cfg.notext))
129954292de2Sinoguchi 				goto err;
1300dab3f910Sjsing 		}
1301dab3f910Sjsing 
1302dab3f910Sjsing 		if (sk_X509_num(cert_sk)) {
1303dab3f910Sjsing 			/* Rename the database and the serial file */
1304dab3f910Sjsing 			if (!rotate_serial(serialfile, "new", "old"))
1305dab3f910Sjsing 				goto err;
1306dab3f910Sjsing 
1307dab3f910Sjsing 			if (!rotate_index(dbfile, "new", "old"))
1308dab3f910Sjsing 				goto err;
1309dab3f910Sjsing 
1310dab3f910Sjsing 			BIO_printf(bio_err, "Data Base Updated\n");
1311dab3f910Sjsing 		}
1312dab3f910Sjsing 	}
1313dab3f910Sjsing 	/*****************************************************************/
1314e7718adaStb 	if (cfg.gencrl) {
1315dab3f910Sjsing 		int crl_v2 = 0;
1316e7718adaStb 		if (cfg.crl_ext == NULL) {
1317e7718adaStb 			cfg.crl_ext = NCONF_get_string(conf,
1318e7718adaStb 			    cfg.section, ENV_CRLEXT);
1319e7718adaStb 			if (cfg.crl_ext == NULL)
1320dab3f910Sjsing 				ERR_clear_error();
1321dab3f910Sjsing 		}
1322e7718adaStb 		if (cfg.crl_ext != NULL) {
1323dab3f910Sjsing 			/* Check syntax of file */
1324dab3f910Sjsing 			X509V3_CTX ctx;
1325dab3f910Sjsing 			X509V3_set_ctx_test(&ctx);
1326dab3f910Sjsing 			X509V3_set_nconf(&ctx, conf);
1327e7718adaStb 			if (!X509V3_EXT_add_nconf(conf, &ctx, cfg.crl_ext,
132816f009d4Sinoguchi 			    NULL)) {
1329dab3f910Sjsing 				BIO_printf(bio_err,
1330dab3f910Sjsing 				    "Error Loading CRL extension section %s\n",
1331e7718adaStb 				    cfg.crl_ext);
1332dab3f910Sjsing 				ret = 1;
1333dab3f910Sjsing 				goto err;
1334dab3f910Sjsing 			}
1335dab3f910Sjsing 		}
1336e7718adaStb 		if ((crlnumberfile = NCONF_get_string(conf, cfg.section,
1337dab3f910Sjsing 		    ENV_CRLNUMBER)) != NULL)
1338dab3f910Sjsing 			if ((crlnumber = load_serial(crlnumberfile, 0,
1339dab3f910Sjsing 			    NULL)) == NULL) {
1340dab3f910Sjsing 				BIO_printf(bio_err,
1341dab3f910Sjsing 				    "error while loading CRL number\n");
1342dab3f910Sjsing 				goto err;
1343dab3f910Sjsing 			}
1344e7718adaStb 		if (!cfg.crldays && !cfg.crlhours &&
1345e7718adaStb 		    !cfg.crlsec) {
1346e7718adaStb 			if (!NCONF_get_number(conf, cfg.section,
1347e7718adaStb 			    ENV_DEFAULT_CRL_DAYS, &cfg.crldays))
1348e7718adaStb 				cfg.crldays = 0;
1349e7718adaStb 			if (!NCONF_get_number(conf, cfg.section,
1350e7718adaStb 			    ENV_DEFAULT_CRL_HOURS, &cfg.crlhours))
1351e7718adaStb 				cfg.crlhours = 0;
1352dab3f910Sjsing 			ERR_clear_error();
1353dab3f910Sjsing 		}
1354e7718adaStb 		if ((cfg.crldays == 0) && (cfg.crlhours == 0) &&
1355e7718adaStb 		    (cfg.crlsec == 0)) {
135616f009d4Sinoguchi 			BIO_printf(bio_err,
135716f009d4Sinoguchi 			    "cannot lookup how long until the next CRL is issued\n");
1358dab3f910Sjsing 			goto err;
1359dab3f910Sjsing 		}
1360e7718adaStb 		if (cfg.verbose)
1361dab3f910Sjsing 			BIO_printf(bio_err, "making CRL\n");
1362dab3f910Sjsing 		if ((crl = X509_CRL_new()) == NULL)
1363dab3f910Sjsing 			goto err;
1364dab3f910Sjsing 		if (!X509_CRL_set_issuer_name(crl, X509_get_subject_name(x509)))
1365dab3f910Sjsing 			goto err;
1366dab3f910Sjsing 
13672c098a5bSinoguchi 		if ((tmptm = X509_gmtime_adj(NULL, 0)) == NULL)
1368dab3f910Sjsing 			goto err;
13692c098a5bSinoguchi 		if (!X509_CRL_set_lastUpdate(crl, tmptm))
137054292de2Sinoguchi 			goto err;
1371e7718adaStb 		if (X509_time_adj_ex(tmptm, cfg.crldays,
1372e7718adaStb 		    cfg.crlhours * 60 * 60 + cfg.crlsec, NULL) ==
137316f009d4Sinoguchi 		    NULL) {
1374dab3f910Sjsing 			BIO_puts(bio_err, "error setting CRL nextUpdate\n");
1375dab3f910Sjsing 			goto err;
1376dab3f910Sjsing 		}
13772c098a5bSinoguchi 		if (!X509_CRL_set_nextUpdate(crl, tmptm))
137854292de2Sinoguchi 			goto err;
1379dab3f910Sjsing 		ASN1_TIME_free(tmptm);
13802c098a5bSinoguchi 		tmptm = NULL;
1381dab3f910Sjsing 
1382dab3f910Sjsing 		for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
1383dab3f910Sjsing 			pp = sk_OPENSSL_PSTRING_value(db->db->data, i);
1384dab3f910Sjsing 			if (pp[DB_type][0] == DB_TYPE_REV) {
1385dab3f910Sjsing 				if ((r = X509_REVOKED_new()) == NULL)
1386dab3f910Sjsing 					goto err;
1387dab3f910Sjsing 				j = make_revoked(r, pp[DB_rev_date]);
1388dab3f910Sjsing 				if (!j)
1389dab3f910Sjsing 					goto err;
1390dab3f910Sjsing 				if (j == 2)
1391dab3f910Sjsing 					crl_v2 = 1;
1392dab3f910Sjsing 				if (!BN_hex2bn(&serial, pp[DB_serial]))
1393dab3f910Sjsing 					goto err;
1394c80f2811Sinoguchi 				tmpserial = BN_to_ASN1_INTEGER(serial, NULL);
1395dab3f910Sjsing 				BN_free(serial);
1396dab3f910Sjsing 				serial = NULL;
1397eb28c9b3Sinoguchi 				if (tmpserial == NULL)
1398dab3f910Sjsing 					goto err;
139954292de2Sinoguchi 				if (!X509_REVOKED_set_serialNumber(r, tmpserial)) {
1400c80f2811Sinoguchi 					ASN1_INTEGER_free(tmpserial);
140154292de2Sinoguchi 					goto err;
140254292de2Sinoguchi 				}
140354292de2Sinoguchi 				ASN1_INTEGER_free(tmpserial);
140454292de2Sinoguchi 				if (!X509_CRL_add0_revoked(crl, r))
140554292de2Sinoguchi 					goto err;
14068346d41bSinoguchi 				r = NULL;
1407dab3f910Sjsing 			}
1408dab3f910Sjsing 		}
1409dab3f910Sjsing 
1410dab3f910Sjsing 		/*
1411dab3f910Sjsing 		 * sort the data so it will be written in serial number order
1412dab3f910Sjsing 		 */
1413dab3f910Sjsing 		X509_CRL_sort(crl);
1414dab3f910Sjsing 
1415dab3f910Sjsing 		/* we now have a CRL */
1416e7718adaStb 		if (cfg.verbose)
1417dab3f910Sjsing 			BIO_printf(bio_err, "signing CRL\n");
1418dab3f910Sjsing 
1419dab3f910Sjsing 		/* Add any extensions asked for */
1420dab3f910Sjsing 
1421e7718adaStb 		if (cfg.crl_ext != NULL || crlnumberfile != NULL) {
1422dab3f910Sjsing 			X509V3_CTX crlctx;
1423dab3f910Sjsing 			X509V3_set_ctx(&crlctx, x509, NULL, NULL, crl, 0);
1424dab3f910Sjsing 			X509V3_set_nconf(&crlctx, conf);
1425dab3f910Sjsing 
1426e7718adaStb 			if (cfg.crl_ext != NULL)
1427dab3f910Sjsing 				if (!X509V3_EXT_CRL_add_nconf(conf, &crlctx,
1428e7718adaStb 				    cfg.crl_ext, crl))
1429dab3f910Sjsing 					goto err;
1430dab3f910Sjsing 			if (crlnumberfile != NULL) {
1431c80f2811Sinoguchi 				tmpserial = BN_to_ASN1_INTEGER(crlnumber, NULL);
1432eb28c9b3Sinoguchi 				if (tmpserial == NULL)
1433dab3f910Sjsing 					goto err;
143454292de2Sinoguchi 				if (!X509_CRL_add1_ext_i2d(crl, NID_crl_number,
143554292de2Sinoguchi 				    tmpserial, 0, 0)) {
143654292de2Sinoguchi 					ASN1_INTEGER_free(tmpserial);
143754292de2Sinoguchi 					goto err;
143854292de2Sinoguchi 				}
1439c80f2811Sinoguchi 				ASN1_INTEGER_free(tmpserial);
1440dab3f910Sjsing 				crl_v2 = 1;
1441dab3f910Sjsing 				if (!BN_add_word(crlnumber, 1))
1442dab3f910Sjsing 					goto err;
1443dab3f910Sjsing 			}
1444dab3f910Sjsing 		}
1445e7718adaStb 		if (cfg.crl_ext != NULL || crl_v2) {
1446dab3f910Sjsing 			if (!X509_CRL_set_version(crl, 1))
1447dab3f910Sjsing 				goto err;	/* version 2 CRL */
1448dab3f910Sjsing 		}
1449dab3f910Sjsing 		if (crlnumberfile != NULL)	/* we have a CRL number that
1450dab3f910Sjsing 						 * need updating */
1451dab3f910Sjsing 			if (!save_serial(crlnumberfile, "new", crlnumber, NULL))
1452dab3f910Sjsing 				goto err;
1453dab3f910Sjsing 
1454dab3f910Sjsing 		BN_free(crlnumber);
1455dab3f910Sjsing 		crlnumber = NULL;
145660dbdbd9Sinoguchi 
145716f009d4Sinoguchi 		if (!do_X509_CRL_sign(bio_err, crl, pkey, dgst,
1458e7718adaStb 		    cfg.sigopts))
1459dab3f910Sjsing 			goto err;
1460dab3f910Sjsing 
146154292de2Sinoguchi 		if (!PEM_write_bio_X509_CRL(Sout, crl))
146254292de2Sinoguchi 			goto err;
1463dab3f910Sjsing 
1464dab3f910Sjsing 		if (crlnumberfile != NULL)	/* Rename the crlnumber file */
1465dab3f910Sjsing 			if (!rotate_serial(crlnumberfile, "new", "old"))
1466dab3f910Sjsing 				goto err;
1467dab3f910Sjsing 
1468dab3f910Sjsing 	}
1469dab3f910Sjsing 	/*****************************************************************/
1470e7718adaStb 	if (cfg.dorevoke) {
1471e7718adaStb 		if (cfg.infile == NULL) {
1472dab3f910Sjsing 			BIO_printf(bio_err, "no input files\n");
1473dab3f910Sjsing 			goto err;
1474dab3f910Sjsing 		} else {
1475dab3f910Sjsing 			X509 *revcert;
1476e7718adaStb 			revcert = load_cert(bio_err, cfg.infile,
1477e7718adaStb 			    FORMAT_PEM, NULL, cfg.infile);
1478dab3f910Sjsing 			if (revcert == NULL)
1479dab3f910Sjsing 				goto err;
1480e7718adaStb 			j = do_revoke(revcert, db, cfg.rev_type,
1481e7718adaStb 			    cfg.rev_arg);
1482dab3f910Sjsing 			if (j <= 0)
1483dab3f910Sjsing 				goto err;
1484dab3f910Sjsing 			X509_free(revcert);
1485dab3f910Sjsing 
1486dab3f910Sjsing 			if (!save_index(dbfile, "new", db))
1487dab3f910Sjsing 				goto err;
1488dab3f910Sjsing 
1489dab3f910Sjsing 			if (!rotate_index(dbfile, "new", "old"))
1490dab3f910Sjsing 				goto err;
1491dab3f910Sjsing 
1492dab3f910Sjsing 			BIO_printf(bio_err, "Data Base Updated\n");
1493dab3f910Sjsing 		}
1494dab3f910Sjsing 	}
1495dab3f910Sjsing 	/*****************************************************************/
1496dab3f910Sjsing 	ret = 0;
1497dab3f910Sjsing 
1498dab3f910Sjsing  err:
1499dab3f910Sjsing 	free(tofree);
1500dab3f910Sjsing 
1501dab3f910Sjsing 	BIO_free_all(Cout);
1502dab3f910Sjsing 	BIO_free_all(Sout);
1503dab3f910Sjsing 	BIO_free_all(out);
1504dab3f910Sjsing 	BIO_free_all(in);
1505dab3f910Sjsing 
1506dab3f910Sjsing 	sk_X509_pop_free(cert_sk, X509_free);
1507dab3f910Sjsing 
1508dab3f910Sjsing 	if (ret)
1509dab3f910Sjsing 		ERR_print_errors(bio_err);
151060dbdbd9Sinoguchi 	if (free_key)
1511e7718adaStb 		free(cfg.key);
1512dab3f910Sjsing 	BN_free(serial);
1513dab3f910Sjsing 	BN_free(crlnumber);
1514dab3f910Sjsing 	free_index(db);
1515e7718adaStb 	sk_OPENSSL_STRING_free(cfg.sigopts);
1516dab3f910Sjsing 	EVP_PKEY_free(pkey);
1517dab3f910Sjsing 	X509_free(x509);
1518dab3f910Sjsing 	X509_CRL_free(crl);
15198346d41bSinoguchi 	X509_REVOKED_free(r);
15202c098a5bSinoguchi 	ASN1_TIME_free(tmptm);
1521dab3f910Sjsing 	NCONF_free(conf);
1522dab3f910Sjsing 	NCONF_free(extconf);
1523dab3f910Sjsing 	OBJ_cleanup();
1524dab3f910Sjsing 
1525dab3f910Sjsing 	return (ret);
1526dab3f910Sjsing }
1527dab3f910Sjsing 
1528dab3f910Sjsing static void
lookup_fail(const char * name,const char * tag)1529dab3f910Sjsing lookup_fail(const char *name, const char *tag)
1530dab3f910Sjsing {
1531dab3f910Sjsing 	BIO_printf(bio_err, "variable lookup failed for %s::%s\n", name, tag);
1532dab3f910Sjsing }
1533dab3f910Sjsing 
1534dab3f910Sjsing static int
certify(X509 ** xret,char * infile,EVP_PKEY * pkey,X509 * x509,const EVP_MD * dgst,STACK_OF (OPENSSL_STRING)* sigopts,STACK_OF (CONF_VALUE)* policy,CA_DB * db,BIGNUM * serial,char * subj,unsigned long chtype,int multirdn,int email_dn,char * startdate,char * enddate,long days,int batch,char * ext_sect,CONF * lconf,int verbose,unsigned long certopt,unsigned long nameopt,int default_op,int ext_copy,int selfsign)1535dab3f910Sjsing certify(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
1536dab3f910Sjsing     const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts,
1537dab3f910Sjsing     STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, char *subj,
1538dab3f910Sjsing     unsigned long chtype, int multirdn, int email_dn, char *startdate,
1539dab3f910Sjsing     char *enddate, long days, int batch, char *ext_sect, CONF *lconf,
1540dab3f910Sjsing     int verbose, unsigned long certopt, unsigned long nameopt, int default_op,
1541dab3f910Sjsing     int ext_copy, int selfsign)
1542dab3f910Sjsing {
1543dab3f910Sjsing 	X509_REQ *req = NULL;
1544dab3f910Sjsing 	BIO *in = NULL;
1545dab3f910Sjsing 	EVP_PKEY *pktmp = NULL;
1546dab3f910Sjsing 	int ok = -1, i;
1547dab3f910Sjsing 
1548dab3f910Sjsing 	in = BIO_new(BIO_s_file());
1549dab3f910Sjsing 
1550dab3f910Sjsing 	if (BIO_read_filename(in, infile) <= 0) {
1551dab3f910Sjsing 		perror(infile);
1552dab3f910Sjsing 		goto err;
1553dab3f910Sjsing 	}
1554dab3f910Sjsing 	if ((req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL)) == NULL) {
1555dab3f910Sjsing 		BIO_printf(bio_err, "Error reading certificate request in %s\n",
1556dab3f910Sjsing 		    infile);
1557dab3f910Sjsing 		goto err;
1558dab3f910Sjsing 	}
155954292de2Sinoguchi 	if (verbose) {
156054292de2Sinoguchi 		if (!X509_REQ_print(bio_err, req))
156154292de2Sinoguchi 			goto err;
156254292de2Sinoguchi 	}
1563dab3f910Sjsing 
1564dab3f910Sjsing 	BIO_printf(bio_err, "Check that the request matches the signature\n");
1565dab3f910Sjsing 
1566dab3f910Sjsing 	if (selfsign && !X509_REQ_check_private_key(req, pkey)) {
1567dab3f910Sjsing 		BIO_printf(bio_err,
1568dab3f910Sjsing 		    "Certificate request and CA private key do not match\n");
1569dab3f910Sjsing 		ok = 0;
1570dab3f910Sjsing 		goto err;
1571dab3f910Sjsing 	}
157284dd6e9aStb 	if ((pktmp = X509_REQ_get0_pubkey(req)) == NULL) {
1573dab3f910Sjsing 		BIO_printf(bio_err, "error unpacking public key\n");
1574dab3f910Sjsing 		goto err;
1575dab3f910Sjsing 	}
1576dab3f910Sjsing 	i = X509_REQ_verify(req, pktmp);
1577dab3f910Sjsing 	if (i < 0) {
1578dab3f910Sjsing 		ok = 0;
1579dab3f910Sjsing 		BIO_printf(bio_err, "Signature verification problems....\n");
1580dab3f910Sjsing 		goto err;
1581dab3f910Sjsing 	}
1582dab3f910Sjsing 	if (i == 0) {
1583dab3f910Sjsing 		ok = 0;
1584dab3f910Sjsing 		BIO_printf(bio_err,
1585dab3f910Sjsing 		    "Signature did not match the certificate request\n");
1586dab3f910Sjsing 		goto err;
1587dab3f910Sjsing 	} else
1588dab3f910Sjsing 		BIO_printf(bio_err, "Signature ok\n");
1589dab3f910Sjsing 
1590dab3f910Sjsing 	ok = do_body(xret, pkey, x509, dgst, sigopts, policy, db, serial,
1591dab3f910Sjsing 	    subj, chtype, multirdn, email_dn, startdate, enddate, days, batch,
1592dab3f910Sjsing 	    verbose, req, ext_sect, lconf, certopt, nameopt, default_op,
1593dab3f910Sjsing 	    ext_copy, selfsign);
1594dab3f910Sjsing 
1595dab3f910Sjsing  err:
1596dab3f910Sjsing 	X509_REQ_free(req);
1597dab3f910Sjsing 	BIO_free(in);
159860dbdbd9Sinoguchi 
1599dab3f910Sjsing 	return (ok);
1600dab3f910Sjsing }
1601dab3f910Sjsing 
1602dab3f910Sjsing static int
certify_cert(X509 ** xret,char * infile,EVP_PKEY * pkey,X509 * x509,const EVP_MD * dgst,STACK_OF (OPENSSL_STRING)* sigopts,STACK_OF (CONF_VALUE)* policy,CA_DB * db,BIGNUM * serial,char * subj,unsigned long chtype,int multirdn,int email_dn,char * startdate,char * enddate,long days,int batch,char * ext_sect,CONF * lconf,int verbose,unsigned long certopt,unsigned long nameopt,int default_op,int ext_copy)1603dab3f910Sjsing certify_cert(X509 **xret, char *infile, EVP_PKEY *pkey, X509 *x509,
1604dab3f910Sjsing     const EVP_MD *dgst, STACK_OF(OPENSSL_STRING) *sigopts,
1605dab3f910Sjsing     STACK_OF(CONF_VALUE) *policy, CA_DB *db, BIGNUM *serial, char *subj,
1606dab3f910Sjsing     unsigned long chtype, int multirdn, int email_dn, char *startdate,
1607dab3f910Sjsing     char *enddate, long days, int batch, char *ext_sect, CONF *lconf,
1608dab3f910Sjsing     int verbose, unsigned long certopt, unsigned long nameopt, int default_op,
16095284dfeaSbcook     int ext_copy)
1610dab3f910Sjsing {
1611dab3f910Sjsing 	X509 *req = NULL;
1612dab3f910Sjsing 	X509_REQ *rreq = NULL;
1613dab3f910Sjsing 	EVP_PKEY *pktmp = NULL;
1614dab3f910Sjsing 	int ok = -1, i;
1615dab3f910Sjsing 
16165284dfeaSbcook 	if ((req = load_cert(bio_err, infile, FORMAT_PEM, NULL,
1617dab3f910Sjsing 	    infile)) == NULL)
1618dab3f910Sjsing 		goto err;
161954292de2Sinoguchi 	if (verbose) {
162054292de2Sinoguchi 		if (!X509_print(bio_err, req))
162154292de2Sinoguchi 			goto err;
162254292de2Sinoguchi 	}
1623dab3f910Sjsing 
1624dab3f910Sjsing 	BIO_printf(bio_err, "Check that the request matches the signature\n");
1625dab3f910Sjsing 
162684dd6e9aStb 	if ((pktmp = X509_get0_pubkey(req)) == NULL) {
1627dab3f910Sjsing 		BIO_printf(bio_err, "error unpacking public key\n");
1628dab3f910Sjsing 		goto err;
1629dab3f910Sjsing 	}
1630dab3f910Sjsing 	i = X509_verify(req, pktmp);
1631dab3f910Sjsing 	if (i < 0) {
1632dab3f910Sjsing 		ok = 0;
1633dab3f910Sjsing 		BIO_printf(bio_err, "Signature verification problems....\n");
1634dab3f910Sjsing 		goto err;
1635dab3f910Sjsing 	}
1636dab3f910Sjsing 	if (i == 0) {
1637dab3f910Sjsing 		ok = 0;
1638dab3f910Sjsing 		BIO_printf(bio_err,
1639dab3f910Sjsing 		    "Signature did not match the certificate\n");
1640dab3f910Sjsing 		goto err;
1641dab3f910Sjsing 	} else
1642dab3f910Sjsing 		BIO_printf(bio_err, "Signature ok\n");
1643dab3f910Sjsing 
1644dab3f910Sjsing 	if ((rreq = X509_to_X509_REQ(req, NULL, EVP_md5())) == NULL)
1645dab3f910Sjsing 		goto err;
1646dab3f910Sjsing 
1647dab3f910Sjsing 	ok = do_body(xret, pkey, x509, dgst, sigopts, policy, db, serial,
1648dab3f910Sjsing 	    subj, chtype, multirdn, email_dn, startdate, enddate, days, batch,
1649dab3f910Sjsing 	    verbose, rreq, ext_sect, lconf, certopt, nameopt, default_op,
1650dab3f910Sjsing 	    ext_copy, 0);
1651dab3f910Sjsing 
1652dab3f910Sjsing  err:
1653dab3f910Sjsing 	X509_REQ_free(rreq);
1654dab3f910Sjsing 	X509_free(req);
165560dbdbd9Sinoguchi 
1656dab3f910Sjsing 	return (ok);
1657dab3f910Sjsing }
1658dab3f910Sjsing 
1659dab3f910Sjsing static int
do_body(X509 ** xret,EVP_PKEY * pkey,X509 * x509,const EVP_MD * dgst,STACK_OF (OPENSSL_STRING)* sigopts,STACK_OF (CONF_VALUE)* policy,CA_DB * db,BIGNUM * serial,char * subj,unsigned long chtype,int multirdn,int email_dn,char * startdate,char * enddate,long days,int batch,int verbose,X509_REQ * req,char * ext_sect,CONF * lconf,unsigned long certopt,unsigned long nameopt,int default_op,int ext_copy,int selfsign)1660dab3f910Sjsing do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
1661dab3f910Sjsing     STACK_OF(OPENSSL_STRING) *sigopts, STACK_OF(CONF_VALUE) *policy,
1662dab3f910Sjsing     CA_DB *db, BIGNUM *serial, char *subj, unsigned long chtype, int multirdn,
1663dab3f910Sjsing     int email_dn, char *startdate, char *enddate, long days, int batch,
1664dab3f910Sjsing     int verbose, X509_REQ *req, char *ext_sect, CONF *lconf,
1665dab3f910Sjsing     unsigned long certopt, unsigned long nameopt, int default_op,
1666dab3f910Sjsing     int ext_copy, int selfsign)
1667dab3f910Sjsing {
166816f009d4Sinoguchi 	X509_NAME *name = NULL, *CAname = NULL;
166916f009d4Sinoguchi 	X509_NAME *subject = NULL, *dn_subject = NULL;
16708e354cfdSinoguchi 	ASN1_UTCTIME *tm;
1671dab3f910Sjsing 	ASN1_STRING *str, *str2;
1672dab3f910Sjsing 	ASN1_OBJECT *obj;
1673dab3f910Sjsing 	X509 *ret = NULL;
1674dab3f910Sjsing 	X509_NAME_ENTRY *ne;
1675dab3f910Sjsing 	X509_NAME_ENTRY *tne, *push;
1676dab3f910Sjsing 	EVP_PKEY *pktmp;
1677dab3f910Sjsing 	int ok = -1, i, j, last, nid;
1678dab3f910Sjsing 	const char *p;
1679dab3f910Sjsing 	CONF_VALUE *cv;
1680dab3f910Sjsing 	OPENSSL_STRING row[DB_NUMBER];
1681dab3f910Sjsing 	OPENSSL_STRING *irow = NULL;
1682dab3f910Sjsing 	OPENSSL_STRING *rrow = NULL;
1683f2fc6f86Sinoguchi 	const STACK_OF(X509_EXTENSION) *exts;
1684dab3f910Sjsing 
1685b7d83ebfSinoguchi 	*xret = NULL;
1686b7d83ebfSinoguchi 
1687dab3f910Sjsing 	for (i = 0; i < DB_NUMBER; i++)
1688dab3f910Sjsing 		row[i] = NULL;
1689dab3f910Sjsing 
1690eb28c9b3Sinoguchi 	if (subj != NULL) {
1691dab3f910Sjsing 		X509_NAME *n = parse_name(subj, chtype, multirdn);
1692dab3f910Sjsing 
1693eb28c9b3Sinoguchi 		if (n == NULL) {
1694dab3f910Sjsing 			ERR_print_errors(bio_err);
1695dab3f910Sjsing 			goto err;
1696dab3f910Sjsing 		}
169754292de2Sinoguchi 		if (!X509_REQ_set_subject_name(req, n)) {
169854292de2Sinoguchi 			X509_NAME_free(n);
169954292de2Sinoguchi 			goto err;
170054292de2Sinoguchi 		}
1701dab3f910Sjsing 		X509_NAME_free(n);
1702dab3f910Sjsing 	}
1703dab3f910Sjsing 	if (default_op)
1704dab3f910Sjsing 		BIO_printf(bio_err,
1705dab3f910Sjsing 		    "The Subject's Distinguished Name is as follows\n");
1706dab3f910Sjsing 
1707dab3f910Sjsing 	name = X509_REQ_get_subject_name(req);
1708dab3f910Sjsing 	for (i = 0; i < X509_NAME_entry_count(name); i++) {
1709dab3f910Sjsing 		ne = X509_NAME_get_entry(name, i);
171054292de2Sinoguchi 		if (ne == NULL)
171154292de2Sinoguchi 			goto err;
1712dab3f910Sjsing 		str = X509_NAME_ENTRY_get_data(ne);
171354292de2Sinoguchi 		if (str == NULL)
171454292de2Sinoguchi 			goto err;
1715dab3f910Sjsing 		obj = X509_NAME_ENTRY_get_object(ne);
171654292de2Sinoguchi 		if (obj == NULL)
171754292de2Sinoguchi 			goto err;
1718dab3f910Sjsing 
1719e7718adaStb 		if (cfg.msie_hack) {
1720dab3f910Sjsing 			/* assume all type should be strings */
1721ac5c5185Stb 			nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(ne));
172254292de2Sinoguchi 			if (nid == NID_undef)
172354292de2Sinoguchi 				goto err;
1724dab3f910Sjsing 
1725dab3f910Sjsing 			if (str->type == V_ASN1_UNIVERSALSTRING)
1726dab3f910Sjsing 				ASN1_UNIVERSALSTRING_to_string(str);
1727dab3f910Sjsing 
1728dab3f910Sjsing 			if ((str->type == V_ASN1_IA5STRING) &&
1729dab3f910Sjsing 			    (nid != NID_pkcs9_emailAddress))
1730dab3f910Sjsing 				str->type = V_ASN1_T61STRING;
1731dab3f910Sjsing 
1732dab3f910Sjsing 			if ((nid == NID_pkcs9_emailAddress) &&
1733dab3f910Sjsing 			    (str->type == V_ASN1_PRINTABLESTRING))
1734dab3f910Sjsing 				str->type = V_ASN1_IA5STRING;
1735dab3f910Sjsing 		}
1736dab3f910Sjsing 		/* If no EMAIL is wanted in the subject */
1737dab3f910Sjsing 		if ((OBJ_obj2nid(obj) == NID_pkcs9_emailAddress) && (!email_dn))
1738dab3f910Sjsing 			continue;
1739dab3f910Sjsing 
1740dab3f910Sjsing 		/* check some things */
1741dab3f910Sjsing 		if ((OBJ_obj2nid(obj) == NID_pkcs9_emailAddress) &&
1742dab3f910Sjsing 		    (str->type != V_ASN1_IA5STRING)) {
174316f009d4Sinoguchi 			BIO_printf(bio_err,
174416f009d4Sinoguchi 			    "\nemailAddress type needs to be of type IA5STRING\n");
1745dab3f910Sjsing 			goto err;
1746dab3f910Sjsing 		}
1747dab3f910Sjsing 		if ((str->type != V_ASN1_BMPSTRING) &&
1748dab3f910Sjsing 		    (str->type != V_ASN1_UTF8STRING)) {
1749dab3f910Sjsing 			j = ASN1_PRINTABLE_type(str->data, str->length);
1750dab3f910Sjsing 			if (((j == V_ASN1_T61STRING) &&
1751dab3f910Sjsing 			    (str->type != V_ASN1_T61STRING)) ||
1752dab3f910Sjsing 			    ((j == V_ASN1_IA5STRING) &&
1753dab3f910Sjsing 			    (str->type == V_ASN1_PRINTABLESTRING))) {
175416f009d4Sinoguchi 				BIO_printf(bio_err,
175516f009d4Sinoguchi 				    "\nThe string contains characters that are illegal for the ASN.1 type\n");
1756dab3f910Sjsing 				goto err;
1757dab3f910Sjsing 			}
1758dab3f910Sjsing 		}
1759dab3f910Sjsing 		if (default_op)
1760dab3f910Sjsing 			old_entry_print(bio_err, obj, str);
1761dab3f910Sjsing 	}
1762dab3f910Sjsing 
1763dab3f910Sjsing 	/* Ok, now we check the 'policy' stuff. */
1764dab3f910Sjsing 	if ((subject = X509_NAME_new()) == NULL) {
1765dab3f910Sjsing 		BIO_printf(bio_err, "Memory allocation failure\n");
1766dab3f910Sjsing 		goto err;
1767dab3f910Sjsing 	}
1768dab3f910Sjsing 	/* take a copy of the issuer name before we mess with it. */
1769dab3f910Sjsing 	if (selfsign)
1770dab3f910Sjsing 		CAname = X509_NAME_dup(name);
1771dab3f910Sjsing 	else
177235ccf6b5Sinoguchi 		CAname = X509_NAME_dup(X509_get_subject_name(x509));
1773dab3f910Sjsing 	if (CAname == NULL)
1774dab3f910Sjsing 		goto err;
1775dab3f910Sjsing 	str = str2 = NULL;
1776dab3f910Sjsing 
1777dab3f910Sjsing 	for (i = 0; i < sk_CONF_VALUE_num(policy); i++) {
1778dab3f910Sjsing 		cv = sk_CONF_VALUE_value(policy, i);	/* get the object id */
1779dab3f910Sjsing 		if ((j = OBJ_txt2nid(cv->name)) == NID_undef) {
178016f009d4Sinoguchi 			BIO_printf(bio_err,
178116f009d4Sinoguchi 			    "%s:unknown object type in 'policy' configuration\n",
178216f009d4Sinoguchi 			    cv->name);
1783dab3f910Sjsing 			goto err;
1784dab3f910Sjsing 		}
1785dab3f910Sjsing 		obj = OBJ_nid2obj(j);
178654292de2Sinoguchi 		if (obj == NULL)
178754292de2Sinoguchi 			goto err;
1788dab3f910Sjsing 
1789dab3f910Sjsing 		last = -1;
1790dab3f910Sjsing 		for (;;) {
1791dab3f910Sjsing 			/* lookup the object in the supplied name list */
1792dab3f910Sjsing 			j = X509_NAME_get_index_by_OBJ(name, obj, last);
1793dab3f910Sjsing 			if (j < 0) {
1794dab3f910Sjsing 				if (last != -1)
1795dab3f910Sjsing 					break;
1796dab3f910Sjsing 				tne = NULL;
1797dab3f910Sjsing 			} else {
1798dab3f910Sjsing 				tne = X509_NAME_get_entry(name, j);
179954292de2Sinoguchi 				if (tne == NULL)
180054292de2Sinoguchi 					goto err;
1801dab3f910Sjsing 			}
1802dab3f910Sjsing 			last = j;
1803dab3f910Sjsing 
1804dab3f910Sjsing 			/* depending on the 'policy', decide what to do. */
1805dab3f910Sjsing 			push = NULL;
1806dab3f910Sjsing 			if (strcmp(cv->value, "optional") == 0) {
1807dab3f910Sjsing 				if (tne != NULL)
1808dab3f910Sjsing 					push = tne;
1809dab3f910Sjsing 			} else if (strcmp(cv->value, "supplied") == 0) {
1810dab3f910Sjsing 				if (tne == NULL) {
181116f009d4Sinoguchi 					BIO_printf(bio_err,
181216f009d4Sinoguchi 					    "The %s field needed to be supplied and was missing\n",
181316f009d4Sinoguchi 					    cv->name);
1814dab3f910Sjsing 					goto err;
1815dab3f910Sjsing 				} else
1816dab3f910Sjsing 					push = tne;
1817dab3f910Sjsing 			} else if (strcmp(cv->value, "match") == 0) {
1818dab3f910Sjsing 				int last2;
1819dab3f910Sjsing 
1820dab3f910Sjsing 				if (tne == NULL) {
182116f009d4Sinoguchi 					BIO_printf(bio_err,
182216f009d4Sinoguchi 					    "The mandatory %s field was missing\n",
182316f009d4Sinoguchi 					    cv->name);
1824dab3f910Sjsing 					goto err;
1825dab3f910Sjsing 				}
1826dab3f910Sjsing 				last2 = -1;
1827dab3f910Sjsing 
1828dab3f910Sjsing  again2:
182916f009d4Sinoguchi 				j = X509_NAME_get_index_by_OBJ(CAname, obj,
183016f009d4Sinoguchi 				    last2);
1831dab3f910Sjsing 				if ((j < 0) && (last2 == -1)) {
183216f009d4Sinoguchi 					BIO_printf(bio_err,
183316f009d4Sinoguchi 					    "The %s field does not exist in the CA certificate,\nthe 'policy' is misconfigured\n",
183416f009d4Sinoguchi 					    cv->name);
1835dab3f910Sjsing 					goto err;
1836dab3f910Sjsing 				}
1837dab3f910Sjsing 				if (j >= 0) {
1838dab3f910Sjsing 					push = X509_NAME_get_entry(CAname, j);
183954292de2Sinoguchi 					if (push == NULL)
184054292de2Sinoguchi 						goto err;
1841dab3f910Sjsing 					str = X509_NAME_ENTRY_get_data(tne);
184254292de2Sinoguchi 					if (str == NULL)
184354292de2Sinoguchi 						goto err;
1844dab3f910Sjsing 					str2 = X509_NAME_ENTRY_get_data(push);
184554292de2Sinoguchi 					if (str2 == NULL)
184654292de2Sinoguchi 						goto err;
1847dab3f910Sjsing 					last2 = j;
1848dab3f910Sjsing 					if (ASN1_STRING_cmp(str, str2) != 0)
1849dab3f910Sjsing 						goto again2;
1850dab3f910Sjsing 				}
1851dab3f910Sjsing 				if (j < 0) {
185216f009d4Sinoguchi 					BIO_printf(bio_err,
185316f009d4Sinoguchi 					    "The %s field needed to be the same in the\nCA certificate (%s) and the request (%s)\n",
185416f009d4Sinoguchi 					    cv->name, ((str2 == NULL) ?
185516f009d4Sinoguchi 					    "NULL" : (char *) str2->data),
185616f009d4Sinoguchi 					    ((str == NULL) ?
185716f009d4Sinoguchi 					    "NULL" : (char *) str->data));
1858dab3f910Sjsing 					goto err;
1859dab3f910Sjsing 				}
1860dab3f910Sjsing 			} else {
186116f009d4Sinoguchi 				BIO_printf(bio_err,
186216f009d4Sinoguchi 				    "%s:invalid type in 'policy' configuration\n",
186316f009d4Sinoguchi 				    cv->value);
1864dab3f910Sjsing 				goto err;
1865dab3f910Sjsing 			}
1866dab3f910Sjsing 
1867dab3f910Sjsing 			if (push != NULL) {
1868dab3f910Sjsing 				if (!X509_NAME_add_entry(subject, push,
1869dab3f910Sjsing 				    -1, 0)) {
1870dab3f910Sjsing 					X509_NAME_ENTRY_free(push);
1871dab3f910Sjsing 					BIO_printf(bio_err,
1872dab3f910Sjsing 					    "Memory allocation failure\n");
1873dab3f910Sjsing 					goto err;
1874dab3f910Sjsing 				}
1875dab3f910Sjsing 			}
1876dab3f910Sjsing 			if (j < 0)
1877dab3f910Sjsing 				break;
1878dab3f910Sjsing 		}
1879dab3f910Sjsing 	}
1880dab3f910Sjsing 
1881e7718adaStb 	if (cfg.preserve) {
1882dab3f910Sjsing 		X509_NAME_free(subject);
1883dab3f910Sjsing 		/* subject=X509_NAME_dup(X509_REQ_get_subject_name(req)); */
1884dab3f910Sjsing 		subject = X509_NAME_dup(name);
1885dab3f910Sjsing 		if (subject == NULL)
1886dab3f910Sjsing 			goto err;
1887dab3f910Sjsing 	}
1888dab3f910Sjsing 
1889dab3f910Sjsing 	/* We are now totally happy, lets make and sign the certificate */
1890dab3f910Sjsing 	if (verbose)
189116f009d4Sinoguchi 		BIO_printf(bio_err,
189216f009d4Sinoguchi 		    "Everything appears to be ok, creating and signing the certificate\n");
1893dab3f910Sjsing 
1894dab3f910Sjsing 	if ((ret = X509_new()) == NULL)
1895dab3f910Sjsing 		goto err;
1896dab3f910Sjsing 
1897dab3f910Sjsing #ifdef X509_V3
1898dab3f910Sjsing 	/* Make it an X509 v3 certificate. */
1899dab3f910Sjsing 	if (!X509_set_version(ret, 2))
1900dab3f910Sjsing 		goto err;
1901dab3f910Sjsing #endif
190235ccf6b5Sinoguchi 	if (X509_get_serialNumber(ret) == NULL)
19032036efe8Sbeck 		goto err;
190435ccf6b5Sinoguchi 	if (BN_to_ASN1_INTEGER(serial, X509_get_serialNumber(ret)) == NULL)
1905dab3f910Sjsing 		goto err;
1906dab3f910Sjsing 	if (selfsign) {
1907dab3f910Sjsing 		if (!X509_set_issuer_name(ret, subject))
1908dab3f910Sjsing 			goto err;
1909dab3f910Sjsing 	} else {
1910dab3f910Sjsing 		if (!X509_set_issuer_name(ret, X509_get_subject_name(x509)))
1911dab3f910Sjsing 			goto err;
1912dab3f910Sjsing 	}
1913dab3f910Sjsing 
191454292de2Sinoguchi 	if (strcmp(startdate, "today") == 0) {
191554292de2Sinoguchi 		if (X509_gmtime_adj(X509_get_notBefore(ret), 0) == NULL)
191654292de2Sinoguchi 			goto err;
19173feee4c5Stb 	} else if (!ASN1_TIME_set_string_X509(X509_get_notBefore(ret), startdate)) {
19186c329af6Sinoguchi 		BIO_printf(bio_err, "Invalid start date %s\n", startdate);
1919747c3cedSbeck 		goto err;
1920747c3cedSbeck 	}
1921dab3f910Sjsing 
192254292de2Sinoguchi 	if (enddate == NULL) {
192354292de2Sinoguchi 		if (X509_time_adj_ex(X509_get_notAfter(ret), days, 0,
192454292de2Sinoguchi 		    NULL) == NULL)
192554292de2Sinoguchi 			goto err;
19263feee4c5Stb 	} else if (!ASN1_TIME_set_string_X509(X509_get_notAfter(ret), enddate)) {
19276c329af6Sinoguchi 		BIO_printf(bio_err, "Invalid end date %s\n", enddate);
1928747c3cedSbeck 		goto err;
1929747c3cedSbeck 	}
1930dab3f910Sjsing 
1931dab3f910Sjsing 	if (!X509_set_subject_name(ret, subject))
1932dab3f910Sjsing 		goto err;
1933dab3f910Sjsing 
193484dd6e9aStb 	if ((pktmp = X509_REQ_get0_pubkey(req)) == NULL)
193554292de2Sinoguchi 		goto err;
193654292de2Sinoguchi 
193784dd6e9aStb 	if (!X509_set_pubkey(ret, pktmp))
1938dab3f910Sjsing 		goto err;
1939dab3f910Sjsing 
1940dab3f910Sjsing 	/* Lets add the extensions, if there are any */
1941eb28c9b3Sinoguchi 	if (ext_sect != NULL) {
1942dab3f910Sjsing 		X509V3_CTX ctx;
194354292de2Sinoguchi 
1944dab3f910Sjsing 		/* Initialize the context structure */
1945dab3f910Sjsing 		if (selfsign)
1946dab3f910Sjsing 			X509V3_set_ctx(&ctx, ret, ret, req, NULL, 0);
1947dab3f910Sjsing 		else
1948dab3f910Sjsing 			X509V3_set_ctx(&ctx, x509, ret, req, NULL, 0);
1949dab3f910Sjsing 
1950eb28c9b3Sinoguchi 		if (extconf != NULL) {
1951dab3f910Sjsing 			if (verbose)
1952dab3f910Sjsing 				BIO_printf(bio_err,
1953dab3f910Sjsing 				    "Extra configuration file found\n");
1954dab3f910Sjsing 
1955dab3f910Sjsing 			/* Use the extconf configuration db LHASH */
1956dab3f910Sjsing 			X509V3_set_nconf(&ctx, extconf);
1957dab3f910Sjsing 
1958dab3f910Sjsing 			/* Test the structure (needed?) */
1959dab3f910Sjsing 			/* X509V3_set_ctx_test(&ctx); */
1960dab3f910Sjsing 
1961dab3f910Sjsing 			/* Adds exts contained in the configuration file */
1962dab3f910Sjsing 			if (!X509V3_EXT_add_nconf(extconf, &ctx,
1963dab3f910Sjsing 			    ext_sect, ret)) {
1964dab3f910Sjsing 				BIO_printf(bio_err,
1965dab3f910Sjsing 				    "ERROR: adding extensions in section %s\n",
1966dab3f910Sjsing 				    ext_sect);
1967dab3f910Sjsing 				ERR_print_errors(bio_err);
1968dab3f910Sjsing 				goto err;
1969dab3f910Sjsing 			}
1970dab3f910Sjsing 			if (verbose)
197116f009d4Sinoguchi 				BIO_printf(bio_err,
197216f009d4Sinoguchi 				    "Successfully added extensions from file.\n");
1973eb28c9b3Sinoguchi 		} else if (ext_sect != NULL) {
1974dab3f910Sjsing 			/* We found extensions to be set from config file */
1975dab3f910Sjsing 			X509V3_set_nconf(&ctx, lconf);
1976dab3f910Sjsing 
1977dab3f910Sjsing 			if (!X509V3_EXT_add_nconf(lconf, &ctx, ext_sect, ret)) {
1978dab3f910Sjsing 				BIO_printf(bio_err,
1979dab3f910Sjsing 				    "ERROR: adding extensions in section %s\n",
1980dab3f910Sjsing 				    ext_sect);
1981dab3f910Sjsing 				ERR_print_errors(bio_err);
1982dab3f910Sjsing 				goto err;
1983dab3f910Sjsing 			}
1984dab3f910Sjsing 			if (verbose)
198516f009d4Sinoguchi 				BIO_printf(bio_err,
198616f009d4Sinoguchi 				    "Successfully added extensions from config\n");
1987dab3f910Sjsing 		}
1988dab3f910Sjsing 	}
1989dab3f910Sjsing 
1990f2fc6f86Sinoguchi 	/* Copy extensions from request (if any) */
1991dab3f910Sjsing 	if (!copy_extensions(ret, req, ext_copy)) {
1992dab3f910Sjsing 		BIO_printf(bio_err, "ERROR: adding extensions from request\n");
1993dab3f910Sjsing 		ERR_print_errors(bio_err);
1994dab3f910Sjsing 		goto err;
1995dab3f910Sjsing 	}
19963f1ba6adSinoguchi 
1997f2fc6f86Sinoguchi 	exts = X509_get0_extensions(ret);
1998f2fc6f86Sinoguchi 	if (exts != NULL && sk_X509_EXTENSION_num(exts) > 0) {
1999f2fc6f86Sinoguchi 		/* Make it an X509 v3 certificate. */
2000f2fc6f86Sinoguchi 		if (!X509_set_version(ret, 2))
2001f2fc6f86Sinoguchi 			goto err;
2002f2fc6f86Sinoguchi 	}
2003f2fc6f86Sinoguchi 
20043f1ba6adSinoguchi 	if (verbose)
20053f1ba6adSinoguchi 		BIO_printf(bio_err,
20063f1ba6adSinoguchi 		    "The subject name appears to be ok, checking data base for clashes\n");
20073f1ba6adSinoguchi 
20083f1ba6adSinoguchi 	/* Build the correct Subject if no email is wanted in the subject */
20093f1ba6adSinoguchi 	if (!email_dn) {
20103f1ba6adSinoguchi 		X509_NAME_ENTRY *tmpne;
20113f1ba6adSinoguchi 		/*
20123f1ba6adSinoguchi 		 * Its best to dup the subject DN and then delete any email
20133f1ba6adSinoguchi 		 * addresses because this retains its structure.
20143f1ba6adSinoguchi 		 */
20153f1ba6adSinoguchi 		if ((dn_subject = X509_NAME_dup(subject)) == NULL) {
20163f1ba6adSinoguchi 			BIO_printf(bio_err, "Memory allocation failure\n");
2017dab3f910Sjsing 			goto err;
2018dab3f910Sjsing 		}
20193f1ba6adSinoguchi 		while ((i = X509_NAME_get_index_by_NID(dn_subject,
20203f1ba6adSinoguchi 		    NID_pkcs9_emailAddress, -1)) >= 0) {
20213f1ba6adSinoguchi 			tmpne = X509_NAME_get_entry(dn_subject, i);
20223f1ba6adSinoguchi 			if (tmpne == NULL)
20233f1ba6adSinoguchi 				goto err;
20243f1ba6adSinoguchi 			if (X509_NAME_delete_entry(dn_subject, i) == NULL) {
20253f1ba6adSinoguchi 				X509_NAME_ENTRY_free(tmpne);
20263f1ba6adSinoguchi 				goto err;
20273f1ba6adSinoguchi 			}
20283f1ba6adSinoguchi 			X509_NAME_ENTRY_free(tmpne);
20293f1ba6adSinoguchi 		}
20303f1ba6adSinoguchi 
20313f1ba6adSinoguchi 		if (!X509_set_subject_name(ret, dn_subject))
20323f1ba6adSinoguchi 			goto err;
20333f1ba6adSinoguchi 
20343f1ba6adSinoguchi 		X509_NAME_free(dn_subject);
20353f1ba6adSinoguchi 		dn_subject = NULL;
20363f1ba6adSinoguchi 	}
20373f1ba6adSinoguchi 
20383f1ba6adSinoguchi 	row[DB_name] = X509_NAME_oneline(X509_get_subject_name(ret), NULL, 0);
20393f1ba6adSinoguchi 	if (row[DB_name] == NULL) {
20403f1ba6adSinoguchi 		BIO_printf(bio_err, "Memory allocation failure\n");
20413f1ba6adSinoguchi 		goto err;
20423f1ba6adSinoguchi 	}
20433f1ba6adSinoguchi 
20443f1ba6adSinoguchi 	if (BN_is_zero(serial))
20453f1ba6adSinoguchi 		row[DB_serial] = strdup("00");
20463f1ba6adSinoguchi 	else
20473f1ba6adSinoguchi 		row[DB_serial] = BN_bn2hex(serial);
20483f1ba6adSinoguchi 	if (row[DB_serial] == NULL) {
20493f1ba6adSinoguchi 		BIO_printf(bio_err, "Memory allocation failure\n");
20503f1ba6adSinoguchi 		goto err;
20513f1ba6adSinoguchi 	}
205200f68246Sinoguchi 
205300f68246Sinoguchi 	if (row[DB_name][0] == '\0') {
205400f68246Sinoguchi 		/*
205500f68246Sinoguchi 		 * An empty subject! We'll use the serial number instead. If
205600f68246Sinoguchi 		 * unique_subject is in use then we don't want different
205700f68246Sinoguchi 		 * entries with empty subjects matching each other.
205800f68246Sinoguchi 		 */
205900f68246Sinoguchi 		free(row[DB_name]);
206000f68246Sinoguchi 		row[DB_name] = strdup(row[DB_serial]);
206100f68246Sinoguchi 		if (row[DB_name] == NULL) {
206200f68246Sinoguchi 			BIO_printf(bio_err, "Memory allocation failure\n");
206300f68246Sinoguchi 			goto err;
206400f68246Sinoguchi 		}
206500f68246Sinoguchi 	}
206600f68246Sinoguchi 
20673f1ba6adSinoguchi 	if (db->attributes.unique_subject) {
20683f1ba6adSinoguchi 		OPENSSL_STRING *crow = row;
20693f1ba6adSinoguchi 
20703f1ba6adSinoguchi 		rrow = TXT_DB_get_by_index(db->db, DB_name, crow);
20713f1ba6adSinoguchi 		if (rrow != NULL) {
20723f1ba6adSinoguchi 			BIO_printf(bio_err,
20733f1ba6adSinoguchi 			    "ERROR:There is already a certificate for %s\n",
20743f1ba6adSinoguchi 			    row[DB_name]);
20753f1ba6adSinoguchi 		}
20763f1ba6adSinoguchi 	}
20773f1ba6adSinoguchi 	if (rrow == NULL) {
20783f1ba6adSinoguchi 		rrow = TXT_DB_get_by_index(db->db, DB_serial, row);
20793f1ba6adSinoguchi 		if (rrow != NULL) {
20803f1ba6adSinoguchi 			BIO_printf(bio_err,
20813f1ba6adSinoguchi 			    "ERROR:Serial number %s has already been issued,\n",
20823f1ba6adSinoguchi 			    row[DB_serial]);
20833f1ba6adSinoguchi 			BIO_printf(bio_err,
20843f1ba6adSinoguchi 			    "      check the database/serial_file for corruption\n");
20853f1ba6adSinoguchi 		}
20863f1ba6adSinoguchi 	}
20873f1ba6adSinoguchi 	if (rrow != NULL) {
20883f1ba6adSinoguchi 		BIO_printf(bio_err,
20893f1ba6adSinoguchi 		    "The matching entry has the following details\n");
2090e7b5565eSinoguchi 		if (rrow[DB_type][0] == DB_TYPE_EXP)
20913f1ba6adSinoguchi 			p = "Expired";
2092e7b5565eSinoguchi 		else if (rrow[DB_type][0] == DB_TYPE_REV)
20933f1ba6adSinoguchi 			p = "Revoked";
2094e7b5565eSinoguchi 		else if (rrow[DB_type][0] == DB_TYPE_VAL)
20953f1ba6adSinoguchi 			p = "Valid";
20963f1ba6adSinoguchi 		else
20973f1ba6adSinoguchi 			p = "\ninvalid type, Data base error\n";
20983f1ba6adSinoguchi 		BIO_printf(bio_err, "Type	  :%s\n", p);
2099e7b5565eSinoguchi 		if (rrow[DB_type][0] == DB_TYPE_REV) {
21003f1ba6adSinoguchi 			p = rrow[DB_exp_date];
21013f1ba6adSinoguchi 			if (p == NULL)
21023f1ba6adSinoguchi 				p = "undef";
21033f1ba6adSinoguchi 			BIO_printf(bio_err, "Was revoked on:%s\n", p);
21043f1ba6adSinoguchi 		}
21053f1ba6adSinoguchi 		p = rrow[DB_exp_date];
21063f1ba6adSinoguchi 		if (p == NULL)
21073f1ba6adSinoguchi 			p = "undef";
21083f1ba6adSinoguchi 		BIO_printf(bio_err, "Expires on    :%s\n", p);
21093f1ba6adSinoguchi 		p = rrow[DB_serial];
21103f1ba6adSinoguchi 		if (p == NULL)
21113f1ba6adSinoguchi 			p = "undef";
21123f1ba6adSinoguchi 		BIO_printf(bio_err, "Serial Number :%s\n", p);
21133f1ba6adSinoguchi 		p = rrow[DB_file];
21143f1ba6adSinoguchi 		if (p == NULL)
21153f1ba6adSinoguchi 			p = "undef";
21163f1ba6adSinoguchi 		BIO_printf(bio_err, "File name     :%s\n", p);
21173f1ba6adSinoguchi 		p = rrow[DB_name];
21183f1ba6adSinoguchi 		if (p == NULL)
21193f1ba6adSinoguchi 			p = "undef";
21203f1ba6adSinoguchi 		BIO_printf(bio_err, "Subject Name  :%s\n", p);
21213f1ba6adSinoguchi 		ok = -1;	/* This is now a 'bad' error. */
21223f1ba6adSinoguchi 		goto err;
21233f1ba6adSinoguchi 	}
21243f1ba6adSinoguchi 
2125dab3f910Sjsing 	if (!default_op) {
2126dab3f910Sjsing 		BIO_printf(bio_err, "Certificate Details:\n");
2127dab3f910Sjsing 		/*
2128dab3f910Sjsing 		 * Never print signature details because signature not
2129dab3f910Sjsing 		 * present
2130dab3f910Sjsing 		 */
2131dab3f910Sjsing 		certopt |= X509_FLAG_NO_SIGDUMP | X509_FLAG_NO_SIGNAME;
213254292de2Sinoguchi 		if (!X509_print_ex(bio_err, ret, nameopt, certopt))
213354292de2Sinoguchi 			goto err;
2134dab3f910Sjsing 	}
2135dab3f910Sjsing 	BIO_printf(bio_err, "Certificate is to be certified until ");
2136dab3f910Sjsing 	ASN1_TIME_print(bio_err, X509_get_notAfter(ret));
2137dab3f910Sjsing 	if (days)
2138dab3f910Sjsing 		BIO_printf(bio_err, " (%ld days)", days);
2139dab3f910Sjsing 	BIO_printf(bio_err, "\n");
2140dab3f910Sjsing 
2141dab3f910Sjsing 	if (!batch) {
2142b707c6faSderaadt 		char answer[25];
2143dab3f910Sjsing 
2144dab3f910Sjsing 		BIO_printf(bio_err, "Sign the certificate? [y/n]:");
2145dab3f910Sjsing 		(void) BIO_flush(bio_err);
2146b707c6faSderaadt 		if (!fgets(answer, sizeof(answer) - 1, stdin)) {
2147dab3f910Sjsing 			BIO_printf(bio_err,
2148dab3f910Sjsing 			    "CERTIFICATE WILL NOT BE CERTIFIED: I/O error\n");
2149dab3f910Sjsing 			ok = 0;
2150dab3f910Sjsing 			goto err;
2151dab3f910Sjsing 		}
2152b707c6faSderaadt 		if (!((answer[0] == 'y') || (answer[0] == 'Y'))) {
2153dab3f910Sjsing 			BIO_printf(bio_err,
2154dab3f910Sjsing 			    "CERTIFICATE WILL NOT BE CERTIFIED\n");
2155dab3f910Sjsing 			ok = 0;
2156dab3f910Sjsing 			goto err;
2157dab3f910Sjsing 		}
2158dab3f910Sjsing 	}
215954292de2Sinoguchi 
216084dd6e9aStb 	if ((pktmp = X509_get0_pubkey(ret)) == NULL)
216154292de2Sinoguchi 		goto err;
216254292de2Sinoguchi 
2163dab3f910Sjsing 	if (EVP_PKEY_missing_parameters(pktmp) &&
216454292de2Sinoguchi 	    !EVP_PKEY_missing_parameters(pkey)) {
216554292de2Sinoguchi 		if (!EVP_PKEY_copy_parameters(pktmp, pkey)) {
216654292de2Sinoguchi 			goto err;
216754292de2Sinoguchi 		}
216854292de2Sinoguchi 	}
2169dab3f910Sjsing 
2170dab3f910Sjsing 	if (!do_X509_sign(bio_err, ret, pkey, dgst, sigopts))
2171dab3f910Sjsing 		goto err;
2172dab3f910Sjsing 
2173dab3f910Sjsing 	/* We now just add it to the database */
2174dab3f910Sjsing 	row[DB_type] = malloc(2);
2175dab3f910Sjsing 
2176f7e03064Sinoguchi 	if ((tm = X509_get_notAfter(ret)) == NULL)
2177f7e03064Sinoguchi 		goto err;
217830e8f6f5Sinoguchi 	row[DB_exp_date] = strndup(tm->data, tm->length);
2179db3c928cSbcook 	if (row[DB_type] == NULL || row[DB_exp_date] == NULL) {
21802036efe8Sbeck 		BIO_printf(bio_err, "Memory allocation failure\n");
21812036efe8Sbeck 		goto err;
21822036efe8Sbeck 	}
21832036efe8Sbeck 
2184dab3f910Sjsing 	row[DB_rev_date] = NULL;
2185dab3f910Sjsing 
2186dab3f910Sjsing 	/* row[DB_serial] done already */
2187dab3f910Sjsing 	row[DB_file] = malloc(8);
2188dab3f910Sjsing 
21892036efe8Sbeck 	if ((row[DB_type] == NULL) || (row[DB_file] == NULL) ||
21902036efe8Sbeck 	    (row[DB_name] == NULL)) {
2191dab3f910Sjsing 		BIO_printf(bio_err, "Memory allocation failure\n");
2192dab3f910Sjsing 		goto err;
2193dab3f910Sjsing 	}
2194dab3f910Sjsing 	(void) strlcpy(row[DB_file], "unknown", 8);
2195e7b5565eSinoguchi 	row[DB_type][0] = DB_TYPE_VAL;
2196dab3f910Sjsing 	row[DB_type][1] = '\0';
2197dab3f910Sjsing 
2198dab3f910Sjsing 	if ((irow = reallocarray(NULL, DB_NUMBER + 1, sizeof(char *))) ==
2199dab3f910Sjsing 	    NULL) {
2200dab3f910Sjsing 		BIO_printf(bio_err, "Memory allocation failure\n");
2201dab3f910Sjsing 		goto err;
2202dab3f910Sjsing 	}
2203dab3f910Sjsing 	for (i = 0; i < DB_NUMBER; i++) {
2204dab3f910Sjsing 		irow[i] = row[i];
2205dab3f910Sjsing 		row[i] = NULL;
2206dab3f910Sjsing 	}
2207dab3f910Sjsing 	irow[DB_NUMBER] = NULL;
2208dab3f910Sjsing 
2209dab3f910Sjsing 	if (!TXT_DB_insert(db->db, irow)) {
2210dab3f910Sjsing 		BIO_printf(bio_err, "failed to update database\n");
2211dab3f910Sjsing 		BIO_printf(bio_err, "TXT_DB error number %ld\n", db->db->error);
2212dab3f910Sjsing 		goto err;
2213dab3f910Sjsing 	}
2214b7d83ebfSinoguchi 
2215b7d83ebfSinoguchi 	*xret = ret;
2216b7d83ebfSinoguchi 	ret = NULL;
2217dab3f910Sjsing 	ok = 1;
2218b7d83ebfSinoguchi 
2219dab3f910Sjsing  err:
2220dab3f910Sjsing 	for (i = 0; i < DB_NUMBER; i++)
2221dab3f910Sjsing 		free(row[i]);
2222dab3f910Sjsing 
2223dab3f910Sjsing 	X509_NAME_free(CAname);
2224dab3f910Sjsing 	X509_NAME_free(subject);
2225dab3f910Sjsing 	X509_NAME_free(dn_subject);
2226dab3f910Sjsing 	X509_free(ret);
222760dbdbd9Sinoguchi 
2228dab3f910Sjsing 	return (ok);
2229dab3f910Sjsing }
2230dab3f910Sjsing 
223154292de2Sinoguchi static int
write_new_certificate(BIO * bp,X509 * x,int output_der,int notext)2232dab3f910Sjsing write_new_certificate(BIO *bp, X509 *x, int output_der, int notext)
2233dab3f910Sjsing {
2234dab3f910Sjsing 	if (output_der) {
223554292de2Sinoguchi 		if (!i2d_X509_bio(bp, x))
223654292de2Sinoguchi 			return (0);
2237dab3f910Sjsing 	}
223854292de2Sinoguchi 	if (!notext) {
223954292de2Sinoguchi 		if (!X509_print(bp, x))
224054292de2Sinoguchi 			return (0);
224154292de2Sinoguchi 	}
224254292de2Sinoguchi 
224354292de2Sinoguchi 	return PEM_write_bio_X509(bp, x);
2244dab3f910Sjsing }
2245dab3f910Sjsing 
2246dab3f910Sjsing static int
check_time_format(const char * str)2247dab3f910Sjsing check_time_format(const char *str)
2248dab3f910Sjsing {
2249dab3f910Sjsing 	return ASN1_TIME_set_string(NULL, str);
2250dab3f910Sjsing }
2251dab3f910Sjsing 
2252dab3f910Sjsing static int
do_revoke(X509 * x509,CA_DB * db,int type,char * value)2253dab3f910Sjsing do_revoke(X509 *x509, CA_DB *db, int type, char *value)
2254dab3f910Sjsing {
2255dab3f910Sjsing 	ASN1_UTCTIME *tm = NULL;
2256dab3f910Sjsing 	char *row[DB_NUMBER], **rrow, **irow;
2257dab3f910Sjsing 	char *rev_str = NULL;
2258dab3f910Sjsing 	BIGNUM *bn = NULL;
2259dab3f910Sjsing 	int ok = -1, i;
2260dab3f910Sjsing 
2261dab3f910Sjsing 	for (i = 0; i < DB_NUMBER; i++)
2262dab3f910Sjsing 		row[i] = NULL;
2263dab3f910Sjsing 	row[DB_name] = X509_NAME_oneline(X509_get_subject_name(x509), NULL, 0);
2264dab3f910Sjsing 	bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(x509), NULL);
2265eb28c9b3Sinoguchi 	if (bn == NULL)
2266dab3f910Sjsing 		goto err;
2267dab3f910Sjsing 	if (BN_is_zero(bn))
2268dab3f910Sjsing 		row[DB_serial] = strdup("00");
2269dab3f910Sjsing 	else
2270dab3f910Sjsing 		row[DB_serial] = BN_bn2hex(bn);
2271dab3f910Sjsing 	BN_free(bn);
227200f68246Sinoguchi 
227300f68246Sinoguchi 	if (row[DB_name] != NULL && row[DB_name][0] == '\0') {
227400f68246Sinoguchi 		/*
227500f68246Sinoguchi 		 * Entries with empty Subjects actually use the serial number
227600f68246Sinoguchi 		 * instead
227700f68246Sinoguchi 		 */
227800f68246Sinoguchi 		free(row[DB_name]);
227900f68246Sinoguchi 		row[DB_name] = strdup(row[DB_serial]);
228000f68246Sinoguchi 		if (row[DB_name] == NULL) {
228100f68246Sinoguchi 			BIO_printf(bio_err, "Memory allocation failure\n");
228200f68246Sinoguchi 			goto err;
228300f68246Sinoguchi 		}
228400f68246Sinoguchi 	}
228500f68246Sinoguchi 
2286dab3f910Sjsing 	if ((row[DB_name] == NULL) || (row[DB_serial] == NULL)) {
2287dab3f910Sjsing 		BIO_printf(bio_err, "Memory allocation failure\n");
2288dab3f910Sjsing 		goto err;
2289dab3f910Sjsing 	}
2290dab3f910Sjsing 	/*
2291dab3f910Sjsing 	 * We have to lookup by serial number because name lookup skips
2292dab3f910Sjsing 	 * revoked certs
2293dab3f910Sjsing 	 */
2294dab3f910Sjsing 	rrow = TXT_DB_get_by_index(db->db, DB_serial, row);
2295dab3f910Sjsing 	if (rrow == NULL) {
2296dab3f910Sjsing 		BIO_printf(bio_err,
2297dab3f910Sjsing 		    "Adding Entry with serial number %s to DB for %s\n",
2298dab3f910Sjsing 		    row[DB_serial], row[DB_name]);
2299dab3f910Sjsing 
2300dab3f910Sjsing 		/* We now just add it to the database */
2301dab3f910Sjsing 		row[DB_type] = malloc(2);
2302dab3f910Sjsing 
2303f7e03064Sinoguchi 		if ((tm = X509_get_notAfter(x509)) == NULL)
2304f7e03064Sinoguchi 			goto err;
230530e8f6f5Sinoguchi 		row[DB_exp_date] = strndup(tm->data, tm->length);
2306db3c928cSbcook 		if (row[DB_type] == NULL || row[DB_exp_date] == NULL) {
23072036efe8Sbeck 			BIO_printf(bio_err, "Memory allocation failure\n");
23082036efe8Sbeck 			goto err;
23092036efe8Sbeck 		}
2310dab3f910Sjsing 
2311dab3f910Sjsing 		row[DB_rev_date] = NULL;
2312dab3f910Sjsing 
2313dab3f910Sjsing 		/* row[DB_serial] done already */
2314dab3f910Sjsing 		row[DB_file] = malloc(8);
2315dab3f910Sjsing 
2316dab3f910Sjsing 		/* row[DB_name] done already */
2317dab3f910Sjsing 
23182036efe8Sbeck 		if ((row[DB_type] == NULL) || (row[DB_file] == NULL)) {
2319dab3f910Sjsing 			BIO_printf(bio_err, "Memory allocation failure\n");
2320dab3f910Sjsing 			goto err;
2321dab3f910Sjsing 		}
2322dab3f910Sjsing 		(void) strlcpy(row[DB_file], "unknown", 8);
2323e7b5565eSinoguchi 		row[DB_type][0] = DB_TYPE_VAL;
2324dab3f910Sjsing 		row[DB_type][1] = '\0';
2325dab3f910Sjsing 
2326dab3f910Sjsing 		if ((irow = reallocarray(NULL, sizeof(char *),
2327dab3f910Sjsing 		    (DB_NUMBER + 1))) == NULL) {
2328dab3f910Sjsing 			BIO_printf(bio_err, "Memory allocation failure\n");
2329dab3f910Sjsing 			goto err;
2330dab3f910Sjsing 		}
2331dab3f910Sjsing 		for (i = 0; i < DB_NUMBER; i++) {
2332dab3f910Sjsing 			irow[i] = row[i];
2333dab3f910Sjsing 			row[i] = NULL;
2334dab3f910Sjsing 		}
2335dab3f910Sjsing 		irow[DB_NUMBER] = NULL;
2336dab3f910Sjsing 
2337dab3f910Sjsing 		if (!TXT_DB_insert(db->db, irow)) {
2338dab3f910Sjsing 			BIO_printf(bio_err, "failed to update database\n");
2339dab3f910Sjsing 			BIO_printf(bio_err, "TXT_DB error number %ld\n",
2340dab3f910Sjsing 			    db->db->error);
2341dab3f910Sjsing 			goto err;
2342dab3f910Sjsing 		}
2343dab3f910Sjsing 		/* Revoke Certificate */
2344dab3f910Sjsing 		ok = do_revoke(x509, db, type, value);
2345dab3f910Sjsing 
2346dab3f910Sjsing 		goto err;
2347dab3f910Sjsing 
2348dab3f910Sjsing 	} else if (index_name_cmp_noconst(row, rrow)) {
2349dab3f910Sjsing 		BIO_printf(bio_err, "ERROR:name does not match %s\n",
2350dab3f910Sjsing 		    row[DB_name]);
2351dab3f910Sjsing 		goto err;
2352e7b5565eSinoguchi 	} else if (rrow[DB_type][0] == DB_TYPE_REV) {
2353dab3f910Sjsing 		BIO_printf(bio_err, "ERROR:Already revoked, serial number %s\n",
2354dab3f910Sjsing 		    row[DB_serial]);
2355dab3f910Sjsing 		goto err;
2356dab3f910Sjsing 	} else {
2357dab3f910Sjsing 		BIO_printf(bio_err, "Revoking Certificate %s.\n",
2358dab3f910Sjsing 		    rrow[DB_serial]);
2359dab3f910Sjsing 		rev_str = make_revocation_str(type, value);
2360eb28c9b3Sinoguchi 		if (rev_str == NULL) {
2361dab3f910Sjsing 			BIO_printf(bio_err, "Error in revocation arguments\n");
2362dab3f910Sjsing 			goto err;
2363dab3f910Sjsing 		}
2364e7b5565eSinoguchi 		rrow[DB_type][0] = DB_TYPE_REV;
2365dab3f910Sjsing 		rrow[DB_type][1] = '\0';
2366dab3f910Sjsing 		rrow[DB_rev_date] = rev_str;
2367dab3f910Sjsing 	}
2368dab3f910Sjsing 	ok = 1;
2369dab3f910Sjsing 
2370dab3f910Sjsing  err:
2371dab3f910Sjsing 	for (i = 0; i < DB_NUMBER; i++)
2372dab3f910Sjsing 		free(row[i]);
2373dab3f910Sjsing 
2374dab3f910Sjsing 	return (ok);
2375dab3f910Sjsing }
2376dab3f910Sjsing 
2377dab3f910Sjsing static int
get_certificate_status(const char * serial,CA_DB * db)2378dab3f910Sjsing get_certificate_status(const char *serial, CA_DB *db)
2379dab3f910Sjsing {
2380dab3f910Sjsing 	char *row[DB_NUMBER], **rrow;
2381dab3f910Sjsing 	int ok = -1, i;
2382dab3f910Sjsing 
2383dab3f910Sjsing 	/* Free Resources */
2384dab3f910Sjsing 	for (i = 0; i < DB_NUMBER; i++)
2385dab3f910Sjsing 		row[i] = NULL;
2386dab3f910Sjsing 
2387dab3f910Sjsing 	/* Malloc needed char spaces */
2388dab3f910Sjsing 	row[DB_serial] = malloc(strlen(serial) + 2);
2389dab3f910Sjsing 	if (row[DB_serial] == NULL) {
2390dab3f910Sjsing 		BIO_printf(bio_err, "Malloc failure\n");
2391dab3f910Sjsing 		goto err;
2392dab3f910Sjsing 	}
2393dab3f910Sjsing 	if (strlen(serial) % 2) {
2394dab3f910Sjsing 		row[DB_serial][0] = '0';
2395dab3f910Sjsing 
2396dab3f910Sjsing 		/* Copy String from serial to row[DB_serial] */
2397dab3f910Sjsing 		memcpy(row[DB_serial] + 1, serial, strlen(serial));
2398dab3f910Sjsing 		row[DB_serial][strlen(serial) + 1] = '\0';
2399dab3f910Sjsing 	} else {
2400dab3f910Sjsing 		/* Copy String from serial to row[DB_serial] */
2401dab3f910Sjsing 		memcpy(row[DB_serial], serial, strlen(serial));
2402dab3f910Sjsing 		row[DB_serial][strlen(serial)] = '\0';
2403dab3f910Sjsing 	}
2404dab3f910Sjsing 
2405dab3f910Sjsing 	/* Make it Upper Case */
2406dab3f910Sjsing 	for (i = 0; row[DB_serial][i] != '\0'; i++)
2407dab3f910Sjsing 		row[DB_serial][i] = toupper((unsigned char) row[DB_serial][i]);
2408dab3f910Sjsing 
2409dab3f910Sjsing 
2410dab3f910Sjsing 	ok = 1;
2411dab3f910Sjsing 
2412dab3f910Sjsing 	/* Search for the certificate */
2413dab3f910Sjsing 	rrow = TXT_DB_get_by_index(db->db, DB_serial, row);
2414dab3f910Sjsing 	if (rrow == NULL) {
2415dab3f910Sjsing 		BIO_printf(bio_err, "Serial %s not present in db.\n",
2416dab3f910Sjsing 		    row[DB_serial]);
2417dab3f910Sjsing 		ok = -1;
2418dab3f910Sjsing 		goto err;
2419e7b5565eSinoguchi 	} else if (rrow[DB_type][0] == DB_TYPE_VAL) {
2420dab3f910Sjsing 		BIO_printf(bio_err, "%s=Valid (%c)\n",
2421dab3f910Sjsing 		    row[DB_serial], rrow[DB_type][0]);
2422dab3f910Sjsing 		goto err;
2423e7b5565eSinoguchi 	} else if (rrow[DB_type][0] == DB_TYPE_REV) {
2424dab3f910Sjsing 		BIO_printf(bio_err, "%s=Revoked (%c)\n",
2425dab3f910Sjsing 		    row[DB_serial], rrow[DB_type][0]);
2426dab3f910Sjsing 		goto err;
2427e7b5565eSinoguchi 	} else if (rrow[DB_type][0] == DB_TYPE_EXP) {
2428dab3f910Sjsing 		BIO_printf(bio_err, "%s=Expired (%c)\n",
2429dab3f910Sjsing 		    row[DB_serial], rrow[DB_type][0]);
2430dab3f910Sjsing 		goto err;
2431e7b5565eSinoguchi 	} else if (rrow[DB_type][0] == DB_TYPE_SUSP) {
2432dab3f910Sjsing 		BIO_printf(bio_err, "%s=Suspended (%c)\n",
2433dab3f910Sjsing 		    row[DB_serial], rrow[DB_type][0]);
2434dab3f910Sjsing 		goto err;
2435dab3f910Sjsing 	} else {
2436dab3f910Sjsing 		BIO_printf(bio_err, "%s=Unknown (%c).\n",
2437dab3f910Sjsing 		    row[DB_serial], rrow[DB_type][0]);
2438dab3f910Sjsing 		ok = -1;
2439dab3f910Sjsing 	}
2440dab3f910Sjsing 
2441dab3f910Sjsing  err:
2442dab3f910Sjsing 	for (i = 0; i < DB_NUMBER; i++)
2443dab3f910Sjsing 		free(row[i]);
2444dab3f910Sjsing 
2445dab3f910Sjsing 	return (ok);
2446dab3f910Sjsing }
2447dab3f910Sjsing 
2448dab3f910Sjsing static int
do_updatedb(CA_DB * db)2449dab3f910Sjsing do_updatedb(CA_DB *db)
2450dab3f910Sjsing {
2451dab3f910Sjsing 	ASN1_UTCTIME *a_tm = NULL;
2452dab3f910Sjsing 	int i, cnt = 0;
2453dab3f910Sjsing 	int db_y2k, a_y2k;	/* flags = 1 if y >= 2000 */
245454292de2Sinoguchi 	char **rrow, *a_tm_s = NULL;
2455dab3f910Sjsing 
2456dab3f910Sjsing 	a_tm = ASN1_UTCTIME_new();
245754292de2Sinoguchi 	if (a_tm == NULL) {
245854292de2Sinoguchi 		cnt = -1;
245954292de2Sinoguchi 		goto err;
246054292de2Sinoguchi 	}
2461dab3f910Sjsing 
2462dab3f910Sjsing 	/* get actual time and make a string */
2463dab3f910Sjsing 	a_tm = X509_gmtime_adj(a_tm, 0);
246454292de2Sinoguchi 	if (a_tm == NULL) {
246554292de2Sinoguchi 		cnt = -1;
246654292de2Sinoguchi 		goto err;
246754292de2Sinoguchi 	}
246830e8f6f5Sinoguchi 	a_tm_s = strndup(a_tm->data, a_tm->length);
2469dab3f910Sjsing 	if (a_tm_s == NULL) {
2470dab3f910Sjsing 		cnt = -1;
2471dab3f910Sjsing 		goto err;
2472dab3f910Sjsing 	}
2473dab3f910Sjsing 
2474dab3f910Sjsing 	if (strncmp(a_tm_s, "49", 2) <= 0)
2475dab3f910Sjsing 		a_y2k = 1;
2476dab3f910Sjsing 	else
2477dab3f910Sjsing 		a_y2k = 0;
2478dab3f910Sjsing 
2479dab3f910Sjsing 	for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) {
2480dab3f910Sjsing 		rrow = sk_OPENSSL_PSTRING_value(db->db->data, i);
2481dab3f910Sjsing 
2482e7b5565eSinoguchi 		if (rrow[DB_type][0] == DB_TYPE_VAL) {
2483dab3f910Sjsing 			/* ignore entries that are not valid */
2484dab3f910Sjsing 			if (strncmp(rrow[DB_exp_date], "49", 2) <= 0)
2485dab3f910Sjsing 				db_y2k = 1;
2486dab3f910Sjsing 			else
2487dab3f910Sjsing 				db_y2k = 0;
2488dab3f910Sjsing 
2489dab3f910Sjsing 			if (db_y2k == a_y2k) {
2490dab3f910Sjsing 				/* all on the same y2k side */
2491dab3f910Sjsing 				if (strcmp(rrow[DB_exp_date], a_tm_s) <= 0) {
2492e7b5565eSinoguchi 					rrow[DB_type][0] = DB_TYPE_EXP;
2493dab3f910Sjsing 					rrow[DB_type][1] = '\0';
2494dab3f910Sjsing 					cnt++;
2495dab3f910Sjsing 
2496dab3f910Sjsing 					BIO_printf(bio_err, "%s=Expired\n",
2497dab3f910Sjsing 					    rrow[DB_serial]);
2498dab3f910Sjsing 				}
2499dab3f910Sjsing 			} else if (db_y2k < a_y2k) {
2500e7b5565eSinoguchi 				rrow[DB_type][0] = DB_TYPE_EXP;
2501dab3f910Sjsing 				rrow[DB_type][1] = '\0';
2502dab3f910Sjsing 				cnt++;
2503dab3f910Sjsing 
2504dab3f910Sjsing 				BIO_printf(bio_err, "%s=Expired\n",
2505dab3f910Sjsing 				    rrow[DB_serial]);
2506dab3f910Sjsing 			}
2507dab3f910Sjsing 		}
2508dab3f910Sjsing 	}
2509dab3f910Sjsing 
2510dab3f910Sjsing  err:
2511dab3f910Sjsing 	ASN1_UTCTIME_free(a_tm);
2512dab3f910Sjsing 	free(a_tm_s);
2513dab3f910Sjsing 
2514dab3f910Sjsing 	return (cnt);
2515dab3f910Sjsing }
2516dab3f910Sjsing 
2517dab3f910Sjsing static const char *crl_reasons[] = {
2518dab3f910Sjsing 	/* CRL reason strings */
2519dab3f910Sjsing 	"unspecified",
2520dab3f910Sjsing 	"keyCompromise",
2521dab3f910Sjsing 	"CACompromise",
2522dab3f910Sjsing 	"affiliationChanged",
2523dab3f910Sjsing 	"superseded",
2524dab3f910Sjsing 	"cessationOfOperation",
2525dab3f910Sjsing 	"certificateHold",
2526dab3f910Sjsing 	"removeFromCRL",
2527dab3f910Sjsing 	/* Additional pseudo reasons */
2528dab3f910Sjsing 	"holdInstruction",
2529dab3f910Sjsing 	"keyTime",
2530dab3f910Sjsing 	"CAkeyTime"
2531dab3f910Sjsing };
2532dab3f910Sjsing 
2533dab3f910Sjsing #define NUM_REASONS (sizeof(crl_reasons) / sizeof(char *))
2534dab3f910Sjsing 
2535dab3f910Sjsing /* Given revocation information convert to a DB string.
2536dab3f910Sjsing  * The format of the string is:
2537dab3f910Sjsing  * revtime[,reason,extra]. Where 'revtime' is the
2538dab3f910Sjsing  * revocation time (the current time). 'reason' is the
2539dab3f910Sjsing  * optional CRL reason and 'extra' is any additional
2540dab3f910Sjsing  * argument
2541dab3f910Sjsing  */
2542dab3f910Sjsing 
2543dab3f910Sjsing char *
make_revocation_str(int rev_type,char * rev_arg)2544dab3f910Sjsing make_revocation_str(int rev_type, char *rev_arg)
2545dab3f910Sjsing {
2546dab3f910Sjsing 	char *other = NULL, *str;
2547dab3f910Sjsing 	const char *reason = NULL;
2548dab3f910Sjsing 	ASN1_OBJECT *otmp;
2549dab3f910Sjsing 	ASN1_UTCTIME *revtm = NULL;
2550dab3f910Sjsing 	int i;
2551dab3f910Sjsing 	switch (rev_type) {
2552dab3f910Sjsing 	case REV_NONE:
2553dab3f910Sjsing 		break;
2554dab3f910Sjsing 
2555dab3f910Sjsing 	case REV_CRL_REASON:
2556dab3f910Sjsing 		for (i = 0; i < 8; i++) {
25579da5b6dbSinoguchi 			if (strcasecmp(rev_arg, crl_reasons[i]) == 0) {
2558dab3f910Sjsing 				reason = crl_reasons[i];
2559dab3f910Sjsing 				break;
2560dab3f910Sjsing 			}
2561dab3f910Sjsing 		}
2562dab3f910Sjsing 		if (reason == NULL) {
2563dab3f910Sjsing 			BIO_printf(bio_err, "Unknown CRL reason %s\n", rev_arg);
2564dab3f910Sjsing 			return NULL;
2565dab3f910Sjsing 		}
2566dab3f910Sjsing 		break;
2567dab3f910Sjsing 
2568dab3f910Sjsing 	case REV_HOLD:
2569dab3f910Sjsing 		/* Argument is an OID */
2570dab3f910Sjsing 		otmp = OBJ_txt2obj(rev_arg, 0);
2571dab3f910Sjsing 		ASN1_OBJECT_free(otmp);
2572dab3f910Sjsing 
2573dab3f910Sjsing 		if (otmp == NULL) {
2574dab3f910Sjsing 			BIO_printf(bio_err,
2575dab3f910Sjsing 			    "Invalid object identifier %s\n", rev_arg);
2576dab3f910Sjsing 			return NULL;
2577dab3f910Sjsing 		}
2578dab3f910Sjsing 		reason = "holdInstruction";
2579dab3f910Sjsing 		other = rev_arg;
2580dab3f910Sjsing 		break;
2581dab3f910Sjsing 
2582dab3f910Sjsing 	case REV_KEY_COMPROMISE:
2583dab3f910Sjsing 	case REV_CA_COMPROMISE:
2584dab3f910Sjsing 		/* Argument is the key compromise time  */
2585dab3f910Sjsing 		if (!ASN1_GENERALIZEDTIME_set_string(NULL, rev_arg)) {
2586dab3f910Sjsing 			BIO_printf(bio_err,
2587dab3f910Sjsing 			    "Invalid time format %s. Need YYYYMMDDHHMMSSZ\n",
2588dab3f910Sjsing 			    rev_arg);
2589dab3f910Sjsing 			return NULL;
2590dab3f910Sjsing 		}
2591dab3f910Sjsing 		other = rev_arg;
2592dab3f910Sjsing 		if (rev_type == REV_KEY_COMPROMISE)
2593dab3f910Sjsing 			reason = "keyTime";
2594dab3f910Sjsing 		else
2595dab3f910Sjsing 			reason = "CAkeyTime";
2596dab3f910Sjsing 
2597dab3f910Sjsing 		break;
2598dab3f910Sjsing 	}
2599dab3f910Sjsing 
2600dab3f910Sjsing 	revtm = X509_gmtime_adj(NULL, 0);
260154292de2Sinoguchi 	if (revtm == NULL)
260254292de2Sinoguchi 		return NULL;
260354292de2Sinoguchi 
2604dab3f910Sjsing 	if (asprintf(&str, "%s%s%s%s%s", revtm->data,
2605dab3f910Sjsing 	    reason ? "," : "", reason ? reason : "",
2606dab3f910Sjsing 	    other ? "," : "", other ? other : "") == -1)
2607dab3f910Sjsing 		str = NULL;
260854292de2Sinoguchi 
2609dab3f910Sjsing 	ASN1_UTCTIME_free(revtm);
261054292de2Sinoguchi 
2611dab3f910Sjsing 	return str;
2612dab3f910Sjsing }
2613dab3f910Sjsing 
2614dab3f910Sjsing /* Convert revocation field to X509_REVOKED entry
2615dab3f910Sjsing  * return code:
2616dab3f910Sjsing  * 0 error
2617dab3f910Sjsing  * 1 OK
2618dab3f910Sjsing  * 2 OK and some extensions added (i.e. V2 CRL)
2619dab3f910Sjsing  */
2620dab3f910Sjsing 
2621dab3f910Sjsing int
make_revoked(X509_REVOKED * rev,const char * str)2622dab3f910Sjsing make_revoked(X509_REVOKED *rev, const char *str)
2623dab3f910Sjsing {
2624dab3f910Sjsing 	char *tmp = NULL;
2625dab3f910Sjsing 	int reason_code = -1;
2626dab3f910Sjsing 	int i, ret = 0;
2627dab3f910Sjsing 	ASN1_OBJECT *hold = NULL;
2628dab3f910Sjsing 	ASN1_GENERALIZEDTIME *comp_time = NULL;
2629dab3f910Sjsing 	ASN1_ENUMERATED *rtmp = NULL;
2630dab3f910Sjsing 
2631dab3f910Sjsing 	ASN1_TIME *revDate = NULL;
2632dab3f910Sjsing 
2633dab3f910Sjsing 	i = unpack_revinfo(&revDate, &reason_code, &hold, &comp_time, str);
2634dab3f910Sjsing 
2635dab3f910Sjsing 	if (i == 0)
2636dab3f910Sjsing 		goto err;
2637dab3f910Sjsing 
2638eb28c9b3Sinoguchi 	if (rev != NULL && !X509_REVOKED_set_revocationDate(rev, revDate))
2639dab3f910Sjsing 		goto err;
2640dab3f910Sjsing 
2641eb28c9b3Sinoguchi 	if (rev != NULL && (reason_code != OCSP_REVOKED_STATUS_NOSTATUS)) {
2642dab3f910Sjsing 		rtmp = ASN1_ENUMERATED_new();
2643eb28c9b3Sinoguchi 		if (rtmp == NULL || !ASN1_ENUMERATED_set(rtmp, reason_code))
2644dab3f910Sjsing 			goto err;
2645dab3f910Sjsing 		if (!X509_REVOKED_add1_ext_i2d(rev, NID_crl_reason, rtmp, 0, 0))
2646dab3f910Sjsing 			goto err;
2647dab3f910Sjsing 	}
2648eb28c9b3Sinoguchi 	if (rev != NULL && comp_time != NULL) {
2649dab3f910Sjsing 		if (!X509_REVOKED_add1_ext_i2d(rev, NID_invalidity_date,
2650dab3f910Sjsing 		    comp_time, 0, 0))
2651dab3f910Sjsing 			goto err;
2652dab3f910Sjsing 	}
2653eb28c9b3Sinoguchi 	if (rev != NULL && hold != NULL) {
2654dab3f910Sjsing 		if (!X509_REVOKED_add1_ext_i2d(rev, NID_hold_instruction_code,
2655dab3f910Sjsing 		    hold, 0, 0))
2656dab3f910Sjsing 			goto err;
2657dab3f910Sjsing 	}
2658dab3f910Sjsing 	if (reason_code != OCSP_REVOKED_STATUS_NOSTATUS)
2659dab3f910Sjsing 		ret = 2;
2660dab3f910Sjsing 	else
2661dab3f910Sjsing 		ret = 1;
2662dab3f910Sjsing 
2663dab3f910Sjsing  err:
2664dab3f910Sjsing 	free(tmp);
2665dab3f910Sjsing 
2666dab3f910Sjsing 	ASN1_OBJECT_free(hold);
2667dab3f910Sjsing 	ASN1_GENERALIZEDTIME_free(comp_time);
2668dab3f910Sjsing 	ASN1_ENUMERATED_free(rtmp);
2669dab3f910Sjsing 	ASN1_TIME_free(revDate);
2670dab3f910Sjsing 
2671dab3f910Sjsing 	return ret;
2672dab3f910Sjsing }
2673dab3f910Sjsing 
2674dab3f910Sjsing int
old_entry_print(BIO * bp,ASN1_OBJECT * obj,ASN1_STRING * str)2675dab3f910Sjsing old_entry_print(BIO *bp, ASN1_OBJECT *obj, ASN1_STRING *str)
2676dab3f910Sjsing {
2677dab3f910Sjsing 	char buf[25], *pbuf, *p;
2678dab3f910Sjsing 	int j;
2679dab3f910Sjsing 
2680dab3f910Sjsing 	j = i2a_ASN1_OBJECT(bp, obj);
2681dab3f910Sjsing 	pbuf = buf;
2682dab3f910Sjsing 	for (j = 22 - j; j > 0; j--)
2683dab3f910Sjsing 		*(pbuf++) = ' ';
2684dab3f910Sjsing 	*(pbuf++) = ':';
2685dab3f910Sjsing 	*(pbuf++) = '\0';
2686dab3f910Sjsing 	BIO_puts(bp, buf);
2687dab3f910Sjsing 
2688dab3f910Sjsing 	if (str->type == V_ASN1_PRINTABLESTRING)
2689dab3f910Sjsing 		BIO_printf(bp, "PRINTABLE:'");
2690dab3f910Sjsing 	else if (str->type == V_ASN1_T61STRING)
2691dab3f910Sjsing 		BIO_printf(bp, "T61STRING:'");
2692dab3f910Sjsing 	else if (str->type == V_ASN1_IA5STRING)
2693dab3f910Sjsing 		BIO_printf(bp, "IA5STRING:'");
2694dab3f910Sjsing 	else if (str->type == V_ASN1_UNIVERSALSTRING)
2695dab3f910Sjsing 		BIO_printf(bp, "UNIVERSALSTRING:'");
2696dab3f910Sjsing 	else
2697dab3f910Sjsing 		BIO_printf(bp, "ASN.1 %2d:'", str->type);
2698dab3f910Sjsing 
2699dab3f910Sjsing 	p = (char *) str->data;
2700dab3f910Sjsing 	for (j = str->length; j > 0; j--) {
2701dab3f910Sjsing 		if ((*p >= ' ') && (*p <= '~'))
2702dab3f910Sjsing 			BIO_printf(bp, "%c", *p);
2703dab3f910Sjsing 		else if (*p & 0x80)
2704dab3f910Sjsing 			BIO_printf(bp, "\\0x%02X", *p);
2705dab3f910Sjsing 		else if ((unsigned char) *p == 0xf7)
2706dab3f910Sjsing 			BIO_printf(bp, "^?");
2707dab3f910Sjsing 		else
2708dab3f910Sjsing 			BIO_printf(bp, "^%c", *p + '@');
2709dab3f910Sjsing 		p++;
2710dab3f910Sjsing 	}
2711dab3f910Sjsing 	BIO_printf(bp, "'\n");
2712dab3f910Sjsing 	return 1;
2713dab3f910Sjsing }
2714dab3f910Sjsing 
2715dab3f910Sjsing int
unpack_revinfo(ASN1_TIME ** prevtm,int * preason,ASN1_OBJECT ** phold,ASN1_GENERALIZEDTIME ** pinvtm,const char * str)2716dab3f910Sjsing unpack_revinfo(ASN1_TIME **prevtm, int *preason, ASN1_OBJECT **phold,
2717dab3f910Sjsing     ASN1_GENERALIZEDTIME **pinvtm, const char *str)
2718dab3f910Sjsing {
2719dab3f910Sjsing 	char *tmp = NULL;
2720dab3f910Sjsing 	char *rtime_str, *reason_str = NULL, *arg_str = NULL, *p;
2721dab3f910Sjsing 	int reason_code = -1;
2722dab3f910Sjsing 	int ret = 0;
2723dab3f910Sjsing 	unsigned int i;
2724dab3f910Sjsing 	ASN1_OBJECT *hold = NULL;
2725dab3f910Sjsing 	ASN1_GENERALIZEDTIME *comp_time = NULL;
2726dab3f910Sjsing 
2727dab3f910Sjsing 	if ((tmp = strdup(str)) == NULL) {
2728dab3f910Sjsing 		BIO_printf(bio_err, "malloc failed\n");
2729dab3f910Sjsing 		goto err;
2730dab3f910Sjsing 	}
2731dab3f910Sjsing 	p = strchr(tmp, ',');
2732dab3f910Sjsing 	rtime_str = tmp;
2733dab3f910Sjsing 
2734eb28c9b3Sinoguchi 	if (p != NULL) {
2735dab3f910Sjsing 		*p = '\0';
2736dab3f910Sjsing 		p++;
2737dab3f910Sjsing 		reason_str = p;
2738dab3f910Sjsing 		p = strchr(p, ',');
2739eb28c9b3Sinoguchi 		if (p != NULL) {
2740dab3f910Sjsing 			*p = '\0';
2741dab3f910Sjsing 			arg_str = p + 1;
2742dab3f910Sjsing 		}
2743dab3f910Sjsing 	}
2744eb28c9b3Sinoguchi 	if (prevtm != NULL) {
2745dab3f910Sjsing 		*prevtm = ASN1_UTCTIME_new();
2746dab3f910Sjsing 		if (!ASN1_UTCTIME_set_string(*prevtm, rtime_str)) {
2747dab3f910Sjsing 			BIO_printf(bio_err, "invalid revocation date %s\n",
2748dab3f910Sjsing 			    rtime_str);
2749dab3f910Sjsing 			goto err;
2750dab3f910Sjsing 		}
2751dab3f910Sjsing 	}
2752eb28c9b3Sinoguchi 	if (reason_str != NULL) {
2753dab3f910Sjsing 		for (i = 0; i < NUM_REASONS; i++) {
27549da5b6dbSinoguchi 			if (strcasecmp(reason_str, crl_reasons[i]) == 0) {
2755dab3f910Sjsing 				reason_code = i;
2756dab3f910Sjsing 				break;
2757dab3f910Sjsing 			}
2758dab3f910Sjsing 		}
2759dab3f910Sjsing 		if (reason_code == OCSP_REVOKED_STATUS_NOSTATUS) {
2760dab3f910Sjsing 			BIO_printf(bio_err, "invalid reason code %s\n",
2761dab3f910Sjsing 			    reason_str);
2762dab3f910Sjsing 			goto err;
2763dab3f910Sjsing 		}
2764dab3f910Sjsing 		if (reason_code == 7)
2765dab3f910Sjsing 			reason_code = OCSP_REVOKED_STATUS_REMOVEFROMCRL;
2766dab3f910Sjsing 		else if (reason_code == 8) {	/* Hold instruction */
2767eb28c9b3Sinoguchi 			if (arg_str == NULL) {
2768dab3f910Sjsing 				BIO_printf(bio_err,
2769dab3f910Sjsing 				    "missing hold instruction\n");
2770dab3f910Sjsing 				goto err;
2771dab3f910Sjsing 			}
2772dab3f910Sjsing 			reason_code = OCSP_REVOKED_STATUS_CERTIFICATEHOLD;
2773dab3f910Sjsing 			hold = OBJ_txt2obj(arg_str, 0);
2774dab3f910Sjsing 
2775eb28c9b3Sinoguchi 			if (hold == NULL) {
2776dab3f910Sjsing 				BIO_printf(bio_err,
2777dab3f910Sjsing 				    "invalid object identifier %s\n", arg_str);
2778dab3f910Sjsing 				goto err;
2779dab3f910Sjsing 			}
2780eb28c9b3Sinoguchi 			if (phold != NULL)
2781dab3f910Sjsing 				*phold = hold;
2782dab3f910Sjsing 		} else if ((reason_code == 9) || (reason_code == 10)) {
2783eb28c9b3Sinoguchi 			if (arg_str == NULL) {
2784dab3f910Sjsing 				BIO_printf(bio_err,
2785dab3f910Sjsing 				    "missing compromised time\n");
2786dab3f910Sjsing 				goto err;
2787dab3f910Sjsing 			}
2788dab3f910Sjsing 			comp_time = ASN1_GENERALIZEDTIME_new();
2789dab3f910Sjsing 			if (!ASN1_GENERALIZEDTIME_set_string(comp_time,
2790dab3f910Sjsing 			    arg_str)) {
2791dab3f910Sjsing 				BIO_printf(bio_err,
2792dab3f910Sjsing 				    "invalid compromised time %s\n", arg_str);
2793dab3f910Sjsing 				goto err;
2794dab3f910Sjsing 			}
2795dab3f910Sjsing 			if (reason_code == 9)
2796dab3f910Sjsing 				reason_code = OCSP_REVOKED_STATUS_KEYCOMPROMISE;
2797dab3f910Sjsing 			else
2798dab3f910Sjsing 				reason_code = OCSP_REVOKED_STATUS_CACOMPROMISE;
2799dab3f910Sjsing 		}
2800dab3f910Sjsing 	}
2801eb28c9b3Sinoguchi 	if (preason != NULL)
2802dab3f910Sjsing 		*preason = reason_code;
2803eb28c9b3Sinoguchi 	if (pinvtm != NULL)
2804dab3f910Sjsing 		*pinvtm = comp_time;
2805dab3f910Sjsing 	else
2806dab3f910Sjsing 		ASN1_GENERALIZEDTIME_free(comp_time);
2807dab3f910Sjsing 
2808dab3f910Sjsing 	ret = 1;
2809dab3f910Sjsing 
2810dab3f910Sjsing  err:
2811dab3f910Sjsing 	free(tmp);
2812dab3f910Sjsing 
2813eb28c9b3Sinoguchi 	if (phold == NULL)
2814dab3f910Sjsing 		ASN1_OBJECT_free(hold);
2815eb28c9b3Sinoguchi 	if (pinvtm == NULL)
2816dab3f910Sjsing 		ASN1_GENERALIZEDTIME_free(comp_time);
2817dab3f910Sjsing 
2818dab3f910Sjsing 	return ret;
2819dab3f910Sjsing }
2820dab3f910Sjsing 
2821dab3f910Sjsing static char *
bin2hex(unsigned char * data,size_t len)2822dab3f910Sjsing bin2hex(unsigned char *data, size_t len)
2823dab3f910Sjsing {
2824dab3f910Sjsing 	char *ret = NULL;
2825dab3f910Sjsing 	char hex[] = "0123456789ABCDEF";
2826dab3f910Sjsing 	int i;
2827dab3f910Sjsing 
2828eb28c9b3Sinoguchi 	if ((ret = malloc(len * 2 + 1)) != NULL) {
2829dab3f910Sjsing 		for (i = 0; i < len; i++) {
2830dab3f910Sjsing 			ret[i * 2 + 0] = hex[data[i] >> 4];
2831dab3f910Sjsing 			ret[i * 2 + 1] = hex[data[i] & 0x0F];
2832dab3f910Sjsing 		}
2833dab3f910Sjsing 		ret[len * 2] = '\0';
2834dab3f910Sjsing 	}
2835dab3f910Sjsing 	return ret;
2836dab3f910Sjsing }
2837