xref: /openbsd-src/usr.bin/openssl/ocsp.c (revision dcc2b9cff833ae1d7a629e83871041a1a80e8704)
1*dcc2b9cfStb /* $OpenBSD: ocsp.c,v 1.26 2024/08/31 18:39:25 tb Exp $ */
2dab3f910Sjsing /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3dab3f910Sjsing  * project 2000.
4dab3f910Sjsing  */
5dab3f910Sjsing /* ====================================================================
6dab3f910Sjsing  * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
7dab3f910Sjsing  *
8dab3f910Sjsing  * Redistribution and use in source and binary forms, with or without
9dab3f910Sjsing  * modification, are permitted provided that the following conditions
10dab3f910Sjsing  * are met:
11dab3f910Sjsing  *
12dab3f910Sjsing  * 1. Redistributions of source code must retain the above copyright
13dab3f910Sjsing  *    notice, this list of conditions and the following disclaimer.
14dab3f910Sjsing  *
15dab3f910Sjsing  * 2. Redistributions in binary form must reproduce the above copyright
16dab3f910Sjsing  *    notice, this list of conditions and the following disclaimer in
17dab3f910Sjsing  *    the documentation and/or other materials provided with the
18dab3f910Sjsing  *    distribution.
19dab3f910Sjsing  *
20dab3f910Sjsing  * 3. All advertising materials mentioning features or use of this
21dab3f910Sjsing  *    software must display the following acknowledgment:
22dab3f910Sjsing  *    "This product includes software developed by the OpenSSL Project
23dab3f910Sjsing  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24dab3f910Sjsing  *
25dab3f910Sjsing  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26dab3f910Sjsing  *    endorse or promote products derived from this software without
27dab3f910Sjsing  *    prior written permission. For written permission, please contact
28dab3f910Sjsing  *    licensing@OpenSSL.org.
29dab3f910Sjsing  *
30dab3f910Sjsing  * 5. Products derived from this software may not be called "OpenSSL"
31dab3f910Sjsing  *    nor may "OpenSSL" appear in their names without prior written
32dab3f910Sjsing  *    permission of the OpenSSL Project.
33dab3f910Sjsing  *
34dab3f910Sjsing  * 6. Redistributions of any form whatsoever must retain the following
35dab3f910Sjsing  *    acknowledgment:
36dab3f910Sjsing  *    "This product includes software developed by the OpenSSL Project
37dab3f910Sjsing  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38dab3f910Sjsing  *
39dab3f910Sjsing  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40dab3f910Sjsing  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41dab3f910Sjsing  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42dab3f910Sjsing  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43dab3f910Sjsing  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44dab3f910Sjsing  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45dab3f910Sjsing  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46dab3f910Sjsing  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47dab3f910Sjsing  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48dab3f910Sjsing  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49dab3f910Sjsing  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50dab3f910Sjsing  * OF THE POSSIBILITY OF SUCH DAMAGE.
51dab3f910Sjsing  * ====================================================================
52dab3f910Sjsing  *
53dab3f910Sjsing  * This product includes cryptographic software written by Eric Young
54dab3f910Sjsing  * (eay@cryptsoft.com).  This product includes software written by Tim
55dab3f910Sjsing  * Hudson (tjh@cryptsoft.com).
56dab3f910Sjsing  *
57dab3f910Sjsing  */
58dab3f910Sjsing #ifndef OPENSSL_NO_OCSP
59dab3f910Sjsing 
60230ab7bfSderaadt #include <sys/types.h>
61dab3f910Sjsing 
62dab3f910Sjsing #include <stdio.h>
63dab3f910Sjsing #include <stdlib.h>
64dab3f910Sjsing #include <limits.h>
65dab3f910Sjsing #include <string.h>
66230ab7bfSderaadt #include <poll.h>
67dab3f910Sjsing #include <time.h>
68dab3f910Sjsing 
69dab3f910Sjsing /* Needs to be included before the openssl headers! */
70dab3f910Sjsing #include "apps.h"
71dab3f910Sjsing 
72dab3f910Sjsing #include <openssl/bn.h>
7329c2232eStb #include <openssl/conf.h>
74dab3f910Sjsing #include <openssl/crypto.h>
75dab3f910Sjsing #include <openssl/err.h>
76dab3f910Sjsing #include <openssl/evp.h>
77dab3f910Sjsing #include <openssl/ssl.h>
78dab3f910Sjsing #include <openssl/x509v3.h>
79dab3f910Sjsing 
80dab3f910Sjsing /* Maximum leeway in validity period: default 5 minutes */
81dab3f910Sjsing #define MAX_VALIDITY_PERIOD	(5 * 60)
82dab3f910Sjsing 
83bc14ef1fSinoguchi static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert,
84bc14ef1fSinoguchi     const EVP_MD *cert_id_md, X509 *issuer, STACK_OF(OCSP_CERTID) *ids);
85bc14ef1fSinoguchi static int add_ocsp_serial(OCSP_REQUEST **req, char *serial,
86bc14ef1fSinoguchi     const EVP_MD *cert_id_md, X509 *issuer, STACK_OF(OCSP_CERTID) *ids);
87dab3f910Sjsing static int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req,
88bc14ef1fSinoguchi     STACK_OF(OPENSSL_STRING) *names, STACK_OF(OCSP_CERTID) *ids, long nsec,
89dab3f910Sjsing     long maxage);
90dab3f910Sjsing 
91bc14ef1fSinoguchi static int make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req,
92bc14ef1fSinoguchi     CA_DB *db, X509 *ca, X509 *rcert, EVP_PKEY *rkey, STACK_OF(X509) *rother,
93bc14ef1fSinoguchi     unsigned long flags, int nmin, int ndays);
94dab3f910Sjsing 
95dab3f910Sjsing static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser);
96dab3f910Sjsing static BIO *init_responder(char *port);
97bc14ef1fSinoguchi static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio,
98bc14ef1fSinoguchi     char *port);
99dab3f910Sjsing static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp);
100dab3f910Sjsing static OCSP_RESPONSE *query_responder(BIO *err, BIO *cbio, char *path,
1017b609544Stb     STACK_OF(CONF_VALUE) *headers, const char *host, OCSP_REQUEST *req,
1027b609544Stb     int req_timeout);
103dab3f910Sjsing 
10492c3ac0cSinoguchi static struct {
10592c3ac0cSinoguchi 	int accept_count;
10692c3ac0cSinoguchi 	int add_nonce;
10792c3ac0cSinoguchi 	char *CAfile;
10892c3ac0cSinoguchi 	char *CApath;
10992c3ac0cSinoguchi 	X509 *cert;
11092c3ac0cSinoguchi 	const EVP_MD *cert_id_md;
11192c3ac0cSinoguchi 	STACK_OF(CONF_VALUE) *headers;
11292c3ac0cSinoguchi 	char *host;
11392c3ac0cSinoguchi 	STACK_OF(OCSP_CERTID) *ids;
11492c3ac0cSinoguchi 	int ignore_err;
11592c3ac0cSinoguchi 	X509 *issuer;
11692c3ac0cSinoguchi 	char *keyfile;
11792c3ac0cSinoguchi 	long maxage;
11892c3ac0cSinoguchi 	int ndays;
11992c3ac0cSinoguchi 	int nmin;
12092c3ac0cSinoguchi 	int no_usage;
12192c3ac0cSinoguchi 	int noverify;
12292c3ac0cSinoguchi 	long nsec;
12392c3ac0cSinoguchi 	char *outfile;
12492c3ac0cSinoguchi 	char *path;
12592c3ac0cSinoguchi 	char *port;
12692c3ac0cSinoguchi 	char *rca_filename;
12792c3ac0cSinoguchi 	char *rcertfile;
12892c3ac0cSinoguchi 	OCSP_REQUEST *req;
12992c3ac0cSinoguchi 	int req_text;
13092c3ac0cSinoguchi 	int req_timeout;
13192c3ac0cSinoguchi 	char *reqin;
13292c3ac0cSinoguchi 	STACK_OF(OPENSSL_STRING) *reqnames;
13392c3ac0cSinoguchi 	char *reqout;
13492c3ac0cSinoguchi 	int resp_text;
13592c3ac0cSinoguchi 	char *respin;
13692c3ac0cSinoguchi 	char *respout;
13792c3ac0cSinoguchi 	unsigned long rflags;
13892c3ac0cSinoguchi 	char *ridx_filename;
13992c3ac0cSinoguchi 	char *rkeyfile;
14092c3ac0cSinoguchi 	char *rsignfile;
14192c3ac0cSinoguchi 	char *sign_certfile;
14292c3ac0cSinoguchi 	unsigned long sign_flags;
14392c3ac0cSinoguchi 	char *signfile;
14492c3ac0cSinoguchi 	int use_ssl;
14592c3ac0cSinoguchi 	char *verify_certfile;
14692c3ac0cSinoguchi 	unsigned long verify_flags;
147e7718adaStb } cfg;
14892c3ac0cSinoguchi 
14992c3ac0cSinoguchi static int
15092c3ac0cSinoguchi ocsp_opt_cert(char *arg)
15192c3ac0cSinoguchi {
152e7718adaStb 	X509_free(cfg.cert);
153e7718adaStb 	cfg.cert = load_cert(bio_err, arg, FORMAT_PEM, NULL,
15492c3ac0cSinoguchi 	    "certificate");
155e7718adaStb 	if (cfg.cert == NULL) {
156e7718adaStb 		cfg.no_usage = 1;
15792c3ac0cSinoguchi 		return (1);
15892c3ac0cSinoguchi 	}
159e7718adaStb 	if (cfg.cert_id_md == NULL)
160e7718adaStb 		cfg.cert_id_md = EVP_sha1();
161e7718adaStb 	if (!add_ocsp_cert(&cfg.req, cfg.cert,
162e7718adaStb 	    cfg.cert_id_md, cfg.issuer, cfg.ids)) {
163e7718adaStb 		cfg.no_usage = 1;
16492c3ac0cSinoguchi 		return (1);
16592c3ac0cSinoguchi 	}
166e7718adaStb 	if (!sk_OPENSSL_STRING_push(cfg.reqnames, arg)) {
167e7718adaStb 		cfg.no_usage = 1;
16892c3ac0cSinoguchi 		return (1);
16992c3ac0cSinoguchi 	}
17092c3ac0cSinoguchi 	return (0);
17192c3ac0cSinoguchi }
17292c3ac0cSinoguchi 
17392c3ac0cSinoguchi static int
17492c3ac0cSinoguchi ocsp_opt_cert_id_md(int argc, char **argv, int *argsused)
17592c3ac0cSinoguchi {
17692c3ac0cSinoguchi 	char *name = argv[0];
17792c3ac0cSinoguchi 
17892c3ac0cSinoguchi 	if (*name++ != '-')
17992c3ac0cSinoguchi 		return (1);
18092c3ac0cSinoguchi 
181e7718adaStb 	if ((cfg.cert_id_md = EVP_get_digestbyname(name)) == NULL)
18292c3ac0cSinoguchi 		return (1);
18392c3ac0cSinoguchi 
18492c3ac0cSinoguchi 	*argsused = 1;
18592c3ac0cSinoguchi 	return (0);
18692c3ac0cSinoguchi }
18792c3ac0cSinoguchi 
18892c3ac0cSinoguchi static int
18929c2232eStb x509v3_add_value(const char *name, const char *value,
190*dcc2b9cfStb     STACK_OF(CONF_VALUE) **out_extlist)
19129c2232eStb {
192*dcc2b9cfStb 	STACK_OF(CONF_VALUE) *extlist = NULL;
193*dcc2b9cfStb 	CONF_VALUE *conf_value = NULL;
194*dcc2b9cfStb 	int ret = 0;
19529c2232eStb 
196*dcc2b9cfStb 	if ((conf_value = calloc(1, sizeof(*conf_value))) == NULL) {
197*dcc2b9cfStb 		X509V3error(ERR_R_MALLOC_FAILURE);
19829c2232eStb 		goto err;
199*dcc2b9cfStb 	}
20029c2232eStb 	if (name != NULL) {
201*dcc2b9cfStb 		if ((conf_value->name = strdup(name)) == NULL) {
202*dcc2b9cfStb 			X509V3error(ERR_R_MALLOC_FAILURE);
20329c2232eStb 			goto err;
20429c2232eStb 		}
205*dcc2b9cfStb 	}
20629c2232eStb 	if (value != NULL) {
207*dcc2b9cfStb 		if ((conf_value->value = strdup(value)) == NULL) {
208*dcc2b9cfStb 			X509V3error(ERR_R_MALLOC_FAILURE);
209*dcc2b9cfStb 			goto err;
210*dcc2b9cfStb 		}
211*dcc2b9cfStb 	}
212*dcc2b9cfStb 
213*dcc2b9cfStb 	if ((extlist = *out_extlist) == NULL)
214*dcc2b9cfStb 		extlist = sk_CONF_VALUE_new_null();
215*dcc2b9cfStb 	if (extlist == NULL) {
216*dcc2b9cfStb 		X509V3error(ERR_R_MALLOC_FAILURE);
21729c2232eStb 		goto err;
21829c2232eStb 	}
21929c2232eStb 
220*dcc2b9cfStb 	if (!sk_CONF_VALUE_push(extlist, conf_value)) {
221*dcc2b9cfStb 		X509V3error(ERR_R_MALLOC_FAILURE);
22229c2232eStb 		goto err;
22329c2232eStb 	}
224*dcc2b9cfStb 	conf_value = NULL;
22529c2232eStb 
226*dcc2b9cfStb 	*out_extlist = extlist;
227*dcc2b9cfStb 	extlist = NULL;
22829c2232eStb 
229*dcc2b9cfStb 	ret = 1;
23029c2232eStb 
23129c2232eStb  err:
232*dcc2b9cfStb 	if (extlist != *out_extlist)
233*dcc2b9cfStb 		sk_CONF_VALUE_pop_free(extlist, X509V3_conf_free);
234*dcc2b9cfStb 	X509V3_conf_free(conf_value);
235*dcc2b9cfStb 
236*dcc2b9cfStb 	return ret;
23729c2232eStb }
23829c2232eStb 
23929c2232eStb static int
24092c3ac0cSinoguchi ocsp_opt_header(int argc, char **argv, int *argsused)
24192c3ac0cSinoguchi {
24292c3ac0cSinoguchi 	if (argc < 3 || argv[1] == NULL || argv[2] == NULL)
24392c3ac0cSinoguchi 		return (1);
24492c3ac0cSinoguchi 
24529c2232eStb 	if (!x509v3_add_value(argv[1], argv[2], &cfg.headers)) {
246e7718adaStb 		cfg.no_usage = 1;
24792c3ac0cSinoguchi 		return (1);
24892c3ac0cSinoguchi 	}
24992c3ac0cSinoguchi 
25092c3ac0cSinoguchi 	*argsused = 3;
25192c3ac0cSinoguchi 	return (0);
25292c3ac0cSinoguchi }
25392c3ac0cSinoguchi 
25492c3ac0cSinoguchi static int
25592c3ac0cSinoguchi ocsp_opt_host(char *arg)
25692c3ac0cSinoguchi {
257e7718adaStb 	if (cfg.use_ssl != -1)
25892c3ac0cSinoguchi 		return (1);
25992c3ac0cSinoguchi 
260e7718adaStb 	cfg.host = arg;
26192c3ac0cSinoguchi 	return (0);
26292c3ac0cSinoguchi }
26392c3ac0cSinoguchi 
26492c3ac0cSinoguchi static int
26592c3ac0cSinoguchi ocsp_opt_issuer(char *arg)
26692c3ac0cSinoguchi {
267e7718adaStb 	X509_free(cfg.issuer);
268e7718adaStb 	cfg.issuer = load_cert(bio_err, arg, FORMAT_PEM, NULL,
26992c3ac0cSinoguchi 	    "issuer certificate");
270e7718adaStb 	if (cfg.issuer == NULL) {
271e7718adaStb 		cfg.no_usage = 1;
27292c3ac0cSinoguchi 		return (1);
27392c3ac0cSinoguchi 	}
27492c3ac0cSinoguchi 	return (0);
27592c3ac0cSinoguchi }
27692c3ac0cSinoguchi 
27792c3ac0cSinoguchi static int
27892c3ac0cSinoguchi ocsp_opt_ndays(char *arg)
27992c3ac0cSinoguchi {
28092c3ac0cSinoguchi 	const char *errstr = NULL;
28192c3ac0cSinoguchi 
282e7718adaStb 	cfg.ndays = strtonum(arg, 0, INT_MAX, &errstr);
28392c3ac0cSinoguchi 	if (errstr != NULL) {
28492c3ac0cSinoguchi 		BIO_printf(bio_err, "Illegal update period %s: %s\n",
28592c3ac0cSinoguchi 		    arg, errstr);
28692c3ac0cSinoguchi 		return (1);
28792c3ac0cSinoguchi 	}
28892c3ac0cSinoguchi 	return (0);
28992c3ac0cSinoguchi }
29092c3ac0cSinoguchi 
29192c3ac0cSinoguchi static int
29292c3ac0cSinoguchi ocsp_opt_nmin(char *arg)
29392c3ac0cSinoguchi {
29492c3ac0cSinoguchi 	const char *errstr = NULL;
29592c3ac0cSinoguchi 
296e7718adaStb 	cfg.nmin = strtonum(arg, 0, INT_MAX, &errstr);
29792c3ac0cSinoguchi 	if (errstr != NULL) {
29892c3ac0cSinoguchi 		BIO_printf(bio_err, "Illegal update period %s: %s\n",
29992c3ac0cSinoguchi 		    arg, errstr);
30092c3ac0cSinoguchi 		return (1);
30192c3ac0cSinoguchi 	}
30292c3ac0cSinoguchi 
303e7718adaStb 	if (cfg.ndays != -1)
30492c3ac0cSinoguchi 		return (1);
30592c3ac0cSinoguchi 
306e7718adaStb 	cfg.ndays = 0;
30792c3ac0cSinoguchi 	return (0);
30892c3ac0cSinoguchi }
30992c3ac0cSinoguchi 
31092c3ac0cSinoguchi static int
31192c3ac0cSinoguchi ocsp_opt_nrequest(char *arg)
31292c3ac0cSinoguchi {
31392c3ac0cSinoguchi 	const char *errstr = NULL;
31492c3ac0cSinoguchi 
315e7718adaStb 	cfg.accept_count = strtonum(arg, 0, INT_MAX, &errstr);
31692c3ac0cSinoguchi 	if (errstr != NULL) {
31792c3ac0cSinoguchi 		BIO_printf(bio_err, "Illegal accept count %s: %s\n",
31892c3ac0cSinoguchi 		    arg, errstr);
31992c3ac0cSinoguchi 		return (1);
32092c3ac0cSinoguchi 	}
32192c3ac0cSinoguchi 	return (0);
32292c3ac0cSinoguchi }
32392c3ac0cSinoguchi 
32492c3ac0cSinoguchi static int
32592c3ac0cSinoguchi ocsp_opt_port(char *arg)
32692c3ac0cSinoguchi {
327e7718adaStb 	if (cfg.use_ssl != -1)
32892c3ac0cSinoguchi 		return (1);
32992c3ac0cSinoguchi 
330e7718adaStb 	cfg.port = arg;
33192c3ac0cSinoguchi 	return (0);
33292c3ac0cSinoguchi }
33392c3ac0cSinoguchi 
33492c3ac0cSinoguchi static int
33592c3ac0cSinoguchi ocsp_opt_serial(char *arg)
33692c3ac0cSinoguchi {
337e7718adaStb 	if (cfg.cert_id_md == NULL)
338e7718adaStb 		cfg.cert_id_md = EVP_sha1();
339e7718adaStb 	if (!add_ocsp_serial(&cfg.req, arg, cfg.cert_id_md,
340e7718adaStb 	    cfg.issuer, cfg.ids)) {
341e7718adaStb 		cfg.no_usage = 1;
34292c3ac0cSinoguchi 		return (1);
34392c3ac0cSinoguchi 	}
344e7718adaStb 	if (!sk_OPENSSL_STRING_push(cfg.reqnames, arg)) {
345e7718adaStb 		cfg.no_usage = 1;
34692c3ac0cSinoguchi 		return (1);
34792c3ac0cSinoguchi 	}
34892c3ac0cSinoguchi 	return (0);
34992c3ac0cSinoguchi }
35092c3ac0cSinoguchi 
35192c3ac0cSinoguchi static int
35292c3ac0cSinoguchi ocsp_opt_status_age(char *arg)
35392c3ac0cSinoguchi {
35492c3ac0cSinoguchi 	const char *errstr = NULL;
35592c3ac0cSinoguchi 
356e7718adaStb 	cfg.maxage = strtonum(arg, 0, LONG_MAX, &errstr);
35792c3ac0cSinoguchi 	if (errstr != NULL) {
35892c3ac0cSinoguchi 		BIO_printf(bio_err, "Illegal validity age %s: %s\n",
35992c3ac0cSinoguchi 		    arg, errstr);
36092c3ac0cSinoguchi 		return (1);
36192c3ac0cSinoguchi 	}
36292c3ac0cSinoguchi 	return (0);
36392c3ac0cSinoguchi }
36492c3ac0cSinoguchi 
36592c3ac0cSinoguchi static int
36692c3ac0cSinoguchi ocsp_opt_text(void)
36792c3ac0cSinoguchi {
368e7718adaStb 	cfg.req_text = 1;
369e7718adaStb 	cfg.resp_text = 1;
37092c3ac0cSinoguchi 	return (0);
37192c3ac0cSinoguchi }
37292c3ac0cSinoguchi 
37392c3ac0cSinoguchi static int
37492c3ac0cSinoguchi ocsp_opt_timeout(char *arg)
37592c3ac0cSinoguchi {
37692c3ac0cSinoguchi 	const char *errstr = NULL;
37792c3ac0cSinoguchi 
378e7718adaStb 	cfg.req_timeout = strtonum(arg, 0, INT_MAX, &errstr);
37992c3ac0cSinoguchi 	if (errstr != NULL) {
38092c3ac0cSinoguchi 		BIO_printf(bio_err, "Illegal timeout value %s: %s\n",
38192c3ac0cSinoguchi 		    arg, errstr);
38292c3ac0cSinoguchi 		return (1);
38392c3ac0cSinoguchi 	}
38492c3ac0cSinoguchi 	return (0);
38592c3ac0cSinoguchi }
38692c3ac0cSinoguchi 
38792c3ac0cSinoguchi static int
38892c3ac0cSinoguchi ocsp_opt_url(char *arg)
38992c3ac0cSinoguchi {
390e7718adaStb 	if (cfg.host == NULL && cfg.port == NULL &&
391e7718adaStb 	    cfg.path == NULL) {
392e7718adaStb 		if (!OCSP_parse_url(arg, &cfg.host, &cfg.port,
393e7718adaStb 		    &cfg.path, &cfg.use_ssl)) {
39492c3ac0cSinoguchi 			BIO_printf(bio_err, "Error parsing URL\n");
39592c3ac0cSinoguchi 			return (1);
39692c3ac0cSinoguchi 		}
39792c3ac0cSinoguchi 	}
39892c3ac0cSinoguchi 	return (0);
39992c3ac0cSinoguchi }
40092c3ac0cSinoguchi 
40192c3ac0cSinoguchi static int
40292c3ac0cSinoguchi ocsp_opt_vafile(char *arg)
40392c3ac0cSinoguchi {
404e7718adaStb 	cfg.verify_certfile = arg;
405e7718adaStb 	cfg.verify_flags |= OCSP_TRUSTOTHER;
40692c3ac0cSinoguchi 	return (0);
40792c3ac0cSinoguchi }
40892c3ac0cSinoguchi 
40992c3ac0cSinoguchi static int
41092c3ac0cSinoguchi ocsp_opt_validity_period(char *arg)
41192c3ac0cSinoguchi {
41292c3ac0cSinoguchi 	const char *errstr = NULL;
41392c3ac0cSinoguchi 
414e7718adaStb 	cfg.nsec = strtonum(arg, 0, LONG_MAX, &errstr);
41592c3ac0cSinoguchi 	if (errstr != NULL) {
41692c3ac0cSinoguchi 		BIO_printf(bio_err, "Illegal validity period %s: %s\n",
41792c3ac0cSinoguchi 		    arg, errstr);
41892c3ac0cSinoguchi 		return (1);
41992c3ac0cSinoguchi 	}
42092c3ac0cSinoguchi 	return (0);
42192c3ac0cSinoguchi }
42292c3ac0cSinoguchi 
42392c3ac0cSinoguchi static const struct option ocsp_options[] = {
42492c3ac0cSinoguchi 	{
42592c3ac0cSinoguchi 		.name = "CA",
42692c3ac0cSinoguchi 		.argname = "file",
42792c3ac0cSinoguchi 		.desc = "CA certificate corresponding to the revocation information",
42892c3ac0cSinoguchi 		.type = OPTION_ARG,
429e7718adaStb 		.opt.arg = &cfg.rca_filename,
43092c3ac0cSinoguchi 	},
43192c3ac0cSinoguchi 	{
43292c3ac0cSinoguchi 		.name = "CAfile",
43392c3ac0cSinoguchi 		.argname = "file",
43492c3ac0cSinoguchi 		.desc = "Trusted certificates file",
43592c3ac0cSinoguchi 		.type = OPTION_ARG,
436e7718adaStb 		.opt.arg = &cfg.CAfile,
43792c3ac0cSinoguchi 	},
43892c3ac0cSinoguchi 	{
43992c3ac0cSinoguchi 		.name = "CApath",
44092c3ac0cSinoguchi 		.argname = "directory",
44192c3ac0cSinoguchi 		.desc = "Trusted certificates directory",
44292c3ac0cSinoguchi 		.type = OPTION_ARG,
443e7718adaStb 		.opt.arg = &cfg.CApath,
44492c3ac0cSinoguchi 	},
44592c3ac0cSinoguchi 	{
44692c3ac0cSinoguchi 		.name = "cert",
44792c3ac0cSinoguchi 		.argname = "file",
44892c3ac0cSinoguchi 		.desc = "Certificate to check",
44992c3ac0cSinoguchi 		.type = OPTION_ARG_FUNC,
45092c3ac0cSinoguchi 		.opt.argfunc = ocsp_opt_cert,
45192c3ac0cSinoguchi 	},
45292c3ac0cSinoguchi 	{
45392c3ac0cSinoguchi 		.name = "header",
45492c3ac0cSinoguchi 		.argname = "name value",
45592c3ac0cSinoguchi 		.desc = "Add the header name with the value to the request",
45692c3ac0cSinoguchi 		.type = OPTION_ARGV_FUNC,
45792c3ac0cSinoguchi 		.opt.argvfunc = ocsp_opt_header,
45892c3ac0cSinoguchi 	},
45992c3ac0cSinoguchi 	{
46092c3ac0cSinoguchi 		.name = "host",
46192c3ac0cSinoguchi 		.argname = "hostname:port",
46292c3ac0cSinoguchi 		.desc = "Send OCSP request to host on port",
46392c3ac0cSinoguchi 		.type = OPTION_ARG_FUNC,
46492c3ac0cSinoguchi 		.opt.argfunc = ocsp_opt_host,
46592c3ac0cSinoguchi 	},
46692c3ac0cSinoguchi 	{
46792c3ac0cSinoguchi 		.name = "ignore_err",
46892c3ac0cSinoguchi 		.desc = "Ignore the invalid response",
46992c3ac0cSinoguchi 		.type = OPTION_FLAG,
470e7718adaStb 		.opt.flag = &cfg.ignore_err,
47192c3ac0cSinoguchi 	},
47292c3ac0cSinoguchi 	{
47392c3ac0cSinoguchi 		.name = "index",
47492c3ac0cSinoguchi 		.argname = "indexfile",
47592c3ac0cSinoguchi 		.desc = "Certificate status index file",
47692c3ac0cSinoguchi 		.type = OPTION_ARG,
477e7718adaStb 		.opt.arg = &cfg.ridx_filename,
47892c3ac0cSinoguchi 	},
47992c3ac0cSinoguchi 	{
48092c3ac0cSinoguchi 		.name = "issuer",
48192c3ac0cSinoguchi 		.argname = "file",
48292c3ac0cSinoguchi 		.desc = "Issuer certificate",
48392c3ac0cSinoguchi 		.type = OPTION_ARG_FUNC,
48492c3ac0cSinoguchi 		.opt.argfunc = ocsp_opt_issuer,
48592c3ac0cSinoguchi 	},
48692c3ac0cSinoguchi 	{
48792c3ac0cSinoguchi 		.name = "ndays",
48892c3ac0cSinoguchi 		.argname = "days",
48992c3ac0cSinoguchi 		.desc = "Number of days before next update",
49092c3ac0cSinoguchi 		.type = OPTION_ARG_FUNC,
49192c3ac0cSinoguchi 		.opt.argfunc = ocsp_opt_ndays,
49292c3ac0cSinoguchi 	},
49392c3ac0cSinoguchi 	{
49492c3ac0cSinoguchi 		.name = "nmin",
49592c3ac0cSinoguchi 		.argname = "minutes",
49692c3ac0cSinoguchi 		.desc = "Number of minutes before next update",
49792c3ac0cSinoguchi 		.type = OPTION_ARG_FUNC,
49892c3ac0cSinoguchi 		.opt.argfunc = ocsp_opt_nmin,
49992c3ac0cSinoguchi 	},
50092c3ac0cSinoguchi 	{
50192c3ac0cSinoguchi 		.name = "no_cert_checks",
50292c3ac0cSinoguchi 		.desc = "Don't do additional checks on signing certificate",
50392c3ac0cSinoguchi 		.type = OPTION_UL_VALUE_OR,
504e7718adaStb 		.opt.ulvalue = &cfg.verify_flags,
50592c3ac0cSinoguchi 		.ulvalue = OCSP_NOCHECKS,
50692c3ac0cSinoguchi 	},
50792c3ac0cSinoguchi 	{
50892c3ac0cSinoguchi 		.name = "no_cert_verify",
50992c3ac0cSinoguchi 		.desc = "Don't check signing certificate",
51092c3ac0cSinoguchi 		.type = OPTION_UL_VALUE_OR,
511e7718adaStb 		.opt.ulvalue = &cfg.verify_flags,
51292c3ac0cSinoguchi 		.ulvalue = OCSP_NOVERIFY,
51392c3ac0cSinoguchi 	},
51492c3ac0cSinoguchi 	{
51592c3ac0cSinoguchi 		.name = "no_certs",
51692c3ac0cSinoguchi 		.desc = "Don't include any certificates in signed request",
51792c3ac0cSinoguchi 		.type = OPTION_UL_VALUE_OR,
518e7718adaStb 		.opt.ulvalue = &cfg.sign_flags,
51992c3ac0cSinoguchi 		.ulvalue = OCSP_NOCERTS,
52092c3ac0cSinoguchi 	},
52192c3ac0cSinoguchi 	{
52292c3ac0cSinoguchi 		.name = "no_chain",
52392c3ac0cSinoguchi 		.desc = "Don't use certificates in the response",
52492c3ac0cSinoguchi 		.type = OPTION_UL_VALUE_OR,
525e7718adaStb 		.opt.ulvalue = &cfg.verify_flags,
52692c3ac0cSinoguchi 		.ulvalue = OCSP_NOCHAIN,
52792c3ac0cSinoguchi 	},
52892c3ac0cSinoguchi 	{
52992c3ac0cSinoguchi 		.name = "no_explicit",
53092c3ac0cSinoguchi 		.desc = "Don't check the explicit trust for OCSP signing",
53192c3ac0cSinoguchi 		.type = OPTION_UL_VALUE_OR,
532e7718adaStb 		.opt.ulvalue = &cfg.verify_flags,
53392c3ac0cSinoguchi 		.ulvalue = OCSP_NOEXPLICIT,
53492c3ac0cSinoguchi 	},
53592c3ac0cSinoguchi 	{
53692c3ac0cSinoguchi 		.name = "no_intern",
53792c3ac0cSinoguchi 		.desc = "Don't search certificates contained in response for signer",
53892c3ac0cSinoguchi 		.type = OPTION_UL_VALUE_OR,
539e7718adaStb 		.opt.ulvalue = &cfg.verify_flags,
54092c3ac0cSinoguchi 		.ulvalue = OCSP_NOINTERN,
54192c3ac0cSinoguchi 	},
54292c3ac0cSinoguchi 	{
54392c3ac0cSinoguchi 		.name = "no_nonce",
54492c3ac0cSinoguchi 		.desc = "Don't add OCSP nonce to request",
54592c3ac0cSinoguchi 		.type = OPTION_VALUE,
546e7718adaStb 		.opt.value = &cfg.add_nonce,
54792c3ac0cSinoguchi 		.value = 0,
54892c3ac0cSinoguchi 	},
54992c3ac0cSinoguchi 	{
55092c3ac0cSinoguchi 		.name = "no_signature_verify",
55192c3ac0cSinoguchi 		.desc = "Don't check signature on response",
55292c3ac0cSinoguchi 		.type = OPTION_UL_VALUE_OR,
553e7718adaStb 		.opt.ulvalue = &cfg.verify_flags,
55492c3ac0cSinoguchi 		.ulvalue = OCSP_NOSIGS,
55592c3ac0cSinoguchi 	},
55692c3ac0cSinoguchi 	{
55792c3ac0cSinoguchi 		.name = "nonce",
55892c3ac0cSinoguchi 		.desc = "Add OCSP nonce to request",
55992c3ac0cSinoguchi 		.type = OPTION_VALUE,
560e7718adaStb 		.opt.value = &cfg.add_nonce,
56192c3ac0cSinoguchi 		.value = 2,
56292c3ac0cSinoguchi 	},
56392c3ac0cSinoguchi 	{
56492c3ac0cSinoguchi 		.name = "noverify",
56592c3ac0cSinoguchi 		.desc = "Don't verify response at all",
56692c3ac0cSinoguchi 		.type = OPTION_FLAG,
567e7718adaStb 		.opt.flag = &cfg.noverify,
56892c3ac0cSinoguchi 	},
56992c3ac0cSinoguchi 	{
57092c3ac0cSinoguchi 		.name = "nrequest",
57192c3ac0cSinoguchi 		.argname = "number",
57292c3ac0cSinoguchi 		.desc = "Number of requests to accept (default unlimited)",
57392c3ac0cSinoguchi 		.type = OPTION_ARG_FUNC,
57492c3ac0cSinoguchi 		.opt.argfunc = ocsp_opt_nrequest,
57592c3ac0cSinoguchi 	},
57692c3ac0cSinoguchi 	{
57792c3ac0cSinoguchi 		.name = "out",
57892c3ac0cSinoguchi 		.argname = "file",
57992c3ac0cSinoguchi 		.desc = "Output filename",
58092c3ac0cSinoguchi 		.type = OPTION_ARG,
581e7718adaStb 		.opt.arg = &cfg.outfile,
58292c3ac0cSinoguchi 	},
58392c3ac0cSinoguchi 	{
58492c3ac0cSinoguchi 		.name = "path",
58592c3ac0cSinoguchi 		.argname = "path",
58692c3ac0cSinoguchi 		.desc = "Path to use in OCSP request",
58792c3ac0cSinoguchi 		.type = OPTION_ARG,
588e7718adaStb 		.opt.arg = &cfg.path,
58992c3ac0cSinoguchi 	},
59092c3ac0cSinoguchi 	{
59192c3ac0cSinoguchi 		.name = "port",
59292c3ac0cSinoguchi 		.argname = "portnum",
59392c3ac0cSinoguchi 		.desc = "Port to run responder on",
59492c3ac0cSinoguchi 		.type = OPTION_ARG_FUNC,
59592c3ac0cSinoguchi 		.opt.argfunc = ocsp_opt_port,
59692c3ac0cSinoguchi 	},
59792c3ac0cSinoguchi 	{
59892c3ac0cSinoguchi 		.name = "req_text",
59992c3ac0cSinoguchi 		.desc = "Print text form of request",
60092c3ac0cSinoguchi 		.type = OPTION_FLAG,
601e7718adaStb 		.opt.flag = &cfg.req_text,
60292c3ac0cSinoguchi 	},
60392c3ac0cSinoguchi 	{
60492c3ac0cSinoguchi 		.name = "reqin",
60592c3ac0cSinoguchi 		.argname = "file",
60692c3ac0cSinoguchi 		.desc = "Read DER encoded OCSP request from \"file\"",
60792c3ac0cSinoguchi 		.type = OPTION_ARG,
608e7718adaStb 		.opt.arg = &cfg.reqin,
60992c3ac0cSinoguchi 	},
61092c3ac0cSinoguchi 	{
61192c3ac0cSinoguchi 		.name = "reqout",
61292c3ac0cSinoguchi 		.argname = "file",
61392c3ac0cSinoguchi 		.desc = "Write DER encoded OCSP request to \"file\"",
61492c3ac0cSinoguchi 		.type = OPTION_ARG,
615e7718adaStb 		.opt.arg = &cfg.reqout,
61692c3ac0cSinoguchi 	},
61792c3ac0cSinoguchi 	{
61892c3ac0cSinoguchi 		.name = "resp_key_id",
61992c3ac0cSinoguchi 		.desc = "Identify response by signing certificate key ID",
62092c3ac0cSinoguchi 		.type = OPTION_UL_VALUE_OR,
621e7718adaStb 		.opt.ulvalue = &cfg.rflags,
62292c3ac0cSinoguchi 		.ulvalue = OCSP_RESPID_KEY,
62392c3ac0cSinoguchi 	},
62492c3ac0cSinoguchi 	{
62592c3ac0cSinoguchi 		.name = "resp_no_certs",
62692c3ac0cSinoguchi 		.desc = "Don't include any certificates in response",
62792c3ac0cSinoguchi 		.type = OPTION_UL_VALUE_OR,
628e7718adaStb 		.opt.ulvalue = &cfg.rflags,
62992c3ac0cSinoguchi 		.ulvalue = OCSP_NOCERTS,
63092c3ac0cSinoguchi 	},
63192c3ac0cSinoguchi 	{
63292c3ac0cSinoguchi 		.name = "resp_text",
63392c3ac0cSinoguchi 		.desc = "Print text form of response",
63492c3ac0cSinoguchi 		.type = OPTION_FLAG,
635e7718adaStb 		.opt.flag = &cfg.resp_text,
63692c3ac0cSinoguchi 	},
63792c3ac0cSinoguchi 	{
63892c3ac0cSinoguchi 		.name = "respin",
63992c3ac0cSinoguchi 		.argname = "file",
64092c3ac0cSinoguchi 		.desc = "Read DER encoded OCSP response from \"file\"",
64192c3ac0cSinoguchi 		.type = OPTION_ARG,
642e7718adaStb 		.opt.arg = &cfg.respin,
64392c3ac0cSinoguchi 	},
64492c3ac0cSinoguchi 	{
64592c3ac0cSinoguchi 		.name = "respout",
64692c3ac0cSinoguchi 		.argname = "file",
64792c3ac0cSinoguchi 		.desc = "Write DER encoded OCSP response to \"file\"",
64892c3ac0cSinoguchi 		.type = OPTION_ARG,
649e7718adaStb 		.opt.arg = &cfg.respout,
65092c3ac0cSinoguchi 	},
65192c3ac0cSinoguchi 	{
65292c3ac0cSinoguchi 		.name = "rkey",
65392c3ac0cSinoguchi 		.argname = "file",
65492c3ac0cSinoguchi 		.desc = "Responder key to sign responses with",
65592c3ac0cSinoguchi 		.type = OPTION_ARG,
656e7718adaStb 		.opt.arg = &cfg.rkeyfile,
65792c3ac0cSinoguchi 	},
65892c3ac0cSinoguchi 	{
65992c3ac0cSinoguchi 		.name = "rother",
66092c3ac0cSinoguchi 		.argname = "file",
66192c3ac0cSinoguchi 		.desc = "Other certificates to include in response",
66292c3ac0cSinoguchi 		.type = OPTION_ARG,
663e7718adaStb 		.opt.arg = &cfg.rcertfile,
66492c3ac0cSinoguchi 	},
66592c3ac0cSinoguchi 	{
66692c3ac0cSinoguchi 		.name = "rsigner",
66792c3ac0cSinoguchi 		.argname = "file",
66892c3ac0cSinoguchi 		.desc = "Responder certificate to sign responses with",
66992c3ac0cSinoguchi 		.type = OPTION_ARG,
670e7718adaStb 		.opt.arg = &cfg.rsignfile,
67192c3ac0cSinoguchi 	},
67292c3ac0cSinoguchi 	{
67392c3ac0cSinoguchi 		.name = "serial",
67492c3ac0cSinoguchi 		.argname = "num",
67592c3ac0cSinoguchi 		.desc = "Serial number to check",
67692c3ac0cSinoguchi 		.type = OPTION_ARG_FUNC,
67792c3ac0cSinoguchi 		.opt.argfunc = ocsp_opt_serial,
67892c3ac0cSinoguchi 	},
67992c3ac0cSinoguchi 	{
68092c3ac0cSinoguchi 		.name = "sign_other",
68192c3ac0cSinoguchi 		.argname = "file",
68292c3ac0cSinoguchi 		.desc = "Additional certificates to include in signed request",
68392c3ac0cSinoguchi 		.type = OPTION_ARG,
684e7718adaStb 		.opt.arg = &cfg.sign_certfile,
68592c3ac0cSinoguchi 	},
68692c3ac0cSinoguchi 	{
68792c3ac0cSinoguchi 		.name = "signer",
68892c3ac0cSinoguchi 		.argname = "file",
68992c3ac0cSinoguchi 		.desc = "Certificate to sign OCSP request with",
69092c3ac0cSinoguchi 		.type = OPTION_ARG,
691e7718adaStb 		.opt.arg = &cfg.signfile,
69292c3ac0cSinoguchi 	},
69392c3ac0cSinoguchi 	{
69492c3ac0cSinoguchi 		.name = "signkey",
69592c3ac0cSinoguchi 		.argname = "file",
69692c3ac0cSinoguchi 		.desc = "Private key to sign OCSP request with",
69792c3ac0cSinoguchi 		.type = OPTION_ARG,
698e7718adaStb 		.opt.arg = &cfg.keyfile,
69992c3ac0cSinoguchi 	},
70092c3ac0cSinoguchi 	{
70192c3ac0cSinoguchi 		.name = "status_age",
70292c3ac0cSinoguchi 		.argname = "age",
70392c3ac0cSinoguchi 		.desc = "Maximum status age in seconds",
70492c3ac0cSinoguchi 		.type = OPTION_ARG_FUNC,
70592c3ac0cSinoguchi 		.opt.argfunc = ocsp_opt_status_age,
70692c3ac0cSinoguchi 	},
70792c3ac0cSinoguchi 	{
70892c3ac0cSinoguchi 		.name = "text",
70992c3ac0cSinoguchi 		.desc = "Print text form of request and response",
71092c3ac0cSinoguchi 		.type = OPTION_FUNC,
71192c3ac0cSinoguchi 		.opt.func = ocsp_opt_text,
71292c3ac0cSinoguchi 	},
71392c3ac0cSinoguchi 	{
71492c3ac0cSinoguchi 		.name = "timeout",
71592c3ac0cSinoguchi 		.argname = "seconds",
71692c3ac0cSinoguchi 		.desc = "Connection timeout to the OCSP responder in seconds",
71792c3ac0cSinoguchi 		.type = OPTION_ARG_FUNC,
71892c3ac0cSinoguchi 		.opt.argfunc = ocsp_opt_timeout,
71992c3ac0cSinoguchi 	},
72092c3ac0cSinoguchi 	{
72192c3ac0cSinoguchi 		.name = "trust_other",
72292c3ac0cSinoguchi 		.desc = "Don't verify additional certificates",
72392c3ac0cSinoguchi 		.type = OPTION_UL_VALUE_OR,
724e7718adaStb 		.opt.ulvalue = &cfg.verify_flags,
72592c3ac0cSinoguchi 		.ulvalue = OCSP_TRUSTOTHER,
72692c3ac0cSinoguchi 	},
72792c3ac0cSinoguchi 	{
72892c3ac0cSinoguchi 		.name = "url",
72992c3ac0cSinoguchi 		.argname = "responder_url",
73092c3ac0cSinoguchi 		.desc = "OCSP responder URL",
73192c3ac0cSinoguchi 		.type = OPTION_ARG_FUNC,
73292c3ac0cSinoguchi 		.opt.argfunc = ocsp_opt_url,
73392c3ac0cSinoguchi 	},
73492c3ac0cSinoguchi 	{
73592c3ac0cSinoguchi 		.name = "VAfile",
73692c3ac0cSinoguchi 		.argname = "file",
73792c3ac0cSinoguchi 		.desc = "Explicitly trusted responder certificates",
73892c3ac0cSinoguchi 		.type = OPTION_ARG_FUNC,
73992c3ac0cSinoguchi 		.opt.argfunc = ocsp_opt_vafile,
74092c3ac0cSinoguchi 	},
74192c3ac0cSinoguchi 	{
74292c3ac0cSinoguchi 		.name = "validity_period",
74392c3ac0cSinoguchi 		.argname = "n",
74492c3ac0cSinoguchi 		.desc = "Maximum validity discrepancy in seconds",
74592c3ac0cSinoguchi 		.type = OPTION_ARG_FUNC,
74692c3ac0cSinoguchi 		.opt.argfunc = ocsp_opt_validity_period,
74792c3ac0cSinoguchi 	},
74892c3ac0cSinoguchi 	{
74992c3ac0cSinoguchi 		.name = "verify_other",
75092c3ac0cSinoguchi 		.argname = "file",
75192c3ac0cSinoguchi 		.desc = "Additional certificates to search for signer",
75292c3ac0cSinoguchi 		.type = OPTION_ARG,
753e7718adaStb 		.opt.arg = &cfg.verify_certfile,
75492c3ac0cSinoguchi 	},
75592c3ac0cSinoguchi 	{
75692c3ac0cSinoguchi 		.name = NULL,
75792c3ac0cSinoguchi 		.desc = "",
75892c3ac0cSinoguchi 		.type = OPTION_ARGV_FUNC,
75992c3ac0cSinoguchi 		.opt.argvfunc = ocsp_opt_cert_id_md,
76092c3ac0cSinoguchi 	},
76192c3ac0cSinoguchi 	{ NULL },
76292c3ac0cSinoguchi };
76392c3ac0cSinoguchi 
76492c3ac0cSinoguchi static void
76592c3ac0cSinoguchi ocsp_usage(void)
76692c3ac0cSinoguchi {
76792c3ac0cSinoguchi 	fprintf(stderr, "usage: ocsp "
76892c3ac0cSinoguchi 	    "[-CA file] [-CAfile file] [-CApath directory] [-cert file]\n"
76992c3ac0cSinoguchi 	    "    [-dgst alg] [-header name value] [-host hostname:port]\n"
77092c3ac0cSinoguchi 	    "    [-ignore_err] [-index indexfile] [-issuer file]\n"
77192c3ac0cSinoguchi 	    "    [-ndays days] [-nmin minutes] [-no_cert_checks]\n"
77292c3ac0cSinoguchi 	    "    [-no_cert_verify] [-no_certs] [-no_chain] [-no_explicit]\n"
77392c3ac0cSinoguchi 	    "    [-no_intern] [-no_nonce] [-no_signature_verify] [-nonce]\n"
77492c3ac0cSinoguchi 	    "    [-noverify] [-nrequest number] [-out file] [-path path]\n"
77592c3ac0cSinoguchi 	    "    [-port portnum] [-req_text] [-reqin file] [-reqout file]\n"
77692c3ac0cSinoguchi 	    "    [-resp_key_id] [-resp_no_certs] [-resp_text] [-respin file]\n"
77792c3ac0cSinoguchi 	    "    [-respout file] [-rkey file] [-rother file] [-rsigner file]\n"
77892c3ac0cSinoguchi 	    "    [-serial num] [-sign_other file] [-signer file]\n"
77992c3ac0cSinoguchi 	    "    [-signkey file] [-status_age age] [-text]\n"
78092c3ac0cSinoguchi 	    "    [-timeout seconds] [-trust_other] [-url responder_url]\n"
78192c3ac0cSinoguchi 	    "    [-VAfile file] [-validity_period nsec] [-verify_other file]\n");
78292c3ac0cSinoguchi 	fprintf(stderr, "\n");
78392c3ac0cSinoguchi 	options_usage(ocsp_options);
78492c3ac0cSinoguchi 	fprintf(stderr, "\n");
78592c3ac0cSinoguchi }
78692c3ac0cSinoguchi 
787dab3f910Sjsing int
788dab3f910Sjsing ocsp_main(int argc, char **argv)
789dab3f910Sjsing {
790dab3f910Sjsing 	OCSP_RESPONSE *resp = NULL;
791dab3f910Sjsing 	OCSP_BASICRESP *bs = NULL;
792dab3f910Sjsing 	X509 *signer = NULL, *rsigner = NULL;
793dab3f910Sjsing 	EVP_PKEY *key = NULL, *rkey = NULL;
794dab3f910Sjsing 	BIO *acbio = NULL, *cbio = NULL;
795dab3f910Sjsing 	BIO *derbio = NULL;
796dab3f910Sjsing 	BIO *out = NULL;
797dab3f910Sjsing 	X509_STORE *store = NULL;
798dab3f910Sjsing 	STACK_OF(X509) *sign_other = NULL, *verify_other = NULL, *rother = NULL;
799dab3f910Sjsing 	int ret = 1;
800dab3f910Sjsing 	int badarg = 0;
801dab3f910Sjsing 	int i;
802dab3f910Sjsing 	X509 *rca_cert = NULL;
803dab3f910Sjsing 	CA_DB *rdb = NULL;
804dab3f910Sjsing 
80551811eadSderaadt 	if (pledge("stdio cpath wpath rpath inet dns tty", NULL) == -1) {
8069bc487adSdoug 		perror("pledge");
807e370f0eeSdoug 		exit(1);
808e370f0eeSdoug 	}
8099bc487adSdoug 
810e7718adaStb 	memset(&cfg, 0, sizeof(cfg));
811e7718adaStb 	cfg.accept_count = -1;
812e7718adaStb 	cfg.add_nonce = 1;
813e7718adaStb 	if ((cfg.ids = sk_OCSP_CERTID_new_null()) == NULL)
814dab3f910Sjsing 		goto end;
815e7718adaStb 	cfg.maxage = -1;
816e7718adaStb 	cfg.ndays = -1;
817e7718adaStb 	cfg.nsec = MAX_VALIDITY_PERIOD;
818e7718adaStb 	cfg.req_timeout = -1;
819e7718adaStb 	if ((cfg.reqnames = sk_OPENSSL_STRING_new_null()) == NULL)
820dab3f910Sjsing 		goto end;
821e7718adaStb 	cfg.use_ssl = -1;
82292c3ac0cSinoguchi 
82392c3ac0cSinoguchi 	if (options_parse(argc, argv, ocsp_options, NULL, NULL) != 0) {
824e7718adaStb 		if (cfg.no_usage)
825dab3f910Sjsing 			goto end;
826dab3f910Sjsing 		else
827dab3f910Sjsing 			badarg = 1;
828dab3f910Sjsing 	}
829dab3f910Sjsing 
830dab3f910Sjsing 	/* Have we anything to do? */
831e7718adaStb 	if (!cfg.req && !cfg.reqin && !cfg.respin &&
832e7718adaStb 	    !(cfg.port && cfg.ridx_filename))
833dab3f910Sjsing 		badarg = 1;
834dab3f910Sjsing 
835dab3f910Sjsing 	if (badarg) {
83692c3ac0cSinoguchi 		ocsp_usage();
837dab3f910Sjsing 		goto end;
838dab3f910Sjsing 	}
839e7718adaStb 	if (cfg.outfile)
840e7718adaStb 		out = BIO_new_file(cfg.outfile, "w");
841dab3f910Sjsing 	else
842dab3f910Sjsing 		out = BIO_new_fp(stdout, BIO_NOCLOSE);
843dab3f910Sjsing 
844dab3f910Sjsing 	if (!out) {
845dab3f910Sjsing 		BIO_printf(bio_err, "Error opening output file\n");
846dab3f910Sjsing 		goto end;
847dab3f910Sjsing 	}
848e7718adaStb 	if (!cfg.req && (cfg.add_nonce != 2))
849e7718adaStb 		cfg.add_nonce = 0;
850dab3f910Sjsing 
851e7718adaStb 	if (!cfg.req && cfg.reqin) {
852e7718adaStb 		derbio = BIO_new_file(cfg.reqin, "rb");
853dab3f910Sjsing 		if (!derbio) {
854bc14ef1fSinoguchi 			BIO_printf(bio_err,
855bc14ef1fSinoguchi 			    "Error Opening OCSP request file\n");
856dab3f910Sjsing 			goto end;
857dab3f910Sjsing 		}
858e7718adaStb 		cfg.req = d2i_OCSP_REQUEST_bio(derbio, NULL);
859dab3f910Sjsing 		BIO_free(derbio);
860e7718adaStb 		if (!cfg.req) {
861dab3f910Sjsing 			BIO_printf(bio_err, "Error reading OCSP request\n");
862dab3f910Sjsing 			goto end;
863dab3f910Sjsing 		}
864dab3f910Sjsing 	}
865e7718adaStb 	if (!cfg.req && cfg.port) {
866e7718adaStb 		acbio = init_responder(cfg.port);
867dab3f910Sjsing 		if (!acbio)
868dab3f910Sjsing 			goto end;
869dab3f910Sjsing 	}
870e7718adaStb 	if (cfg.rsignfile && !rdb) {
871e7718adaStb 		if (!cfg.rkeyfile)
872e7718adaStb 			cfg.rkeyfile = cfg.rsignfile;
873e7718adaStb 		rsigner = load_cert(bio_err, cfg.rsignfile, FORMAT_PEM,
8745284dfeaSbcook 		    NULL, "responder certificate");
875dab3f910Sjsing 		if (!rsigner) {
876bc14ef1fSinoguchi 			BIO_printf(bio_err,
877bc14ef1fSinoguchi 			    "Error loading responder certificate\n");
878dab3f910Sjsing 			goto end;
879dab3f910Sjsing 		}
880e7718adaStb 		rca_cert = load_cert(bio_err, cfg.rca_filename,
881bc14ef1fSinoguchi 		    FORMAT_PEM, NULL, "CA certificate");
882e7718adaStb 		if (cfg.rcertfile) {
883e7718adaStb 			rother = load_certs(bio_err, cfg.rcertfile,
884bc14ef1fSinoguchi 			    FORMAT_PEM, NULL, "responder other certificates");
885dab3f910Sjsing 			if (!rother)
886dab3f910Sjsing 				goto end;
887dab3f910Sjsing 		}
888e7718adaStb 		rkey = load_key(bio_err, cfg.rkeyfile, FORMAT_PEM, 0,
889bc14ef1fSinoguchi 		    NULL, "responder private key");
890dab3f910Sjsing 		if (!rkey)
891dab3f910Sjsing 			goto end;
892dab3f910Sjsing 	}
893dab3f910Sjsing 	if (acbio)
894dab3f910Sjsing 		BIO_printf(bio_err, "Waiting for OCSP client connections...\n");
895dab3f910Sjsing 
896dab3f910Sjsing  redo_accept:
897dab3f910Sjsing 
898dab3f910Sjsing 	if (acbio) {
899e7718adaStb 		if (!do_responder(&cfg.req, &cbio, acbio,
900e7718adaStb 		    cfg.port))
901dab3f910Sjsing 			goto end;
902e7718adaStb 		if (!cfg.req) {
903bc14ef1fSinoguchi 			resp = OCSP_response_create(
904bc14ef1fSinoguchi 			    OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, NULL);
905dab3f910Sjsing 			send_ocsp_response(cbio, resp);
906dab3f910Sjsing 			goto done_resp;
907dab3f910Sjsing 		}
908dab3f910Sjsing 	}
909e7718adaStb 	if (!cfg.req &&
910e7718adaStb 	    (cfg.signfile || cfg.reqout || cfg.host ||
911e7718adaStb 	    cfg.add_nonce || cfg.ridx_filename)) {
912bc14ef1fSinoguchi 		BIO_printf(bio_err,
913bc14ef1fSinoguchi 		    "Need an OCSP request for this operation!\n");
914dab3f910Sjsing 		goto end;
915dab3f910Sjsing 	}
916e7718adaStb 	if (cfg.req && cfg.add_nonce)
917e7718adaStb 		OCSP_request_add1_nonce(cfg.req, NULL, -1);
918dab3f910Sjsing 
919e7718adaStb 	if (cfg.signfile) {
920e7718adaStb 		if (!cfg.keyfile)
921e7718adaStb 			cfg.keyfile = cfg.signfile;
922e7718adaStb 		signer = load_cert(bio_err, cfg.signfile, FORMAT_PEM,
9235284dfeaSbcook 		    NULL, "signer certificate");
924dab3f910Sjsing 		if (!signer) {
925bc14ef1fSinoguchi 			BIO_printf(bio_err,
926bc14ef1fSinoguchi 			    "Error loading signer certificate\n");
927dab3f910Sjsing 			goto end;
928dab3f910Sjsing 		}
929e7718adaStb 		if (cfg.sign_certfile) {
930bc14ef1fSinoguchi 			sign_other = load_certs(bio_err,
931e7718adaStb 			    cfg.sign_certfile, FORMAT_PEM, NULL,
932bc14ef1fSinoguchi 			    "signer certificates");
933dab3f910Sjsing 			if (!sign_other)
934dab3f910Sjsing 				goto end;
935dab3f910Sjsing 		}
936e7718adaStb 		key = load_key(bio_err, cfg.keyfile, FORMAT_PEM, 0,
937bc14ef1fSinoguchi 		    NULL, "signer private key");
938dab3f910Sjsing 		if (!key)
939dab3f910Sjsing 			goto end;
940dab3f910Sjsing 
941e7718adaStb 		if (!OCSP_request_sign(cfg.req, signer, key, NULL,
942e7718adaStb 		    sign_other, cfg.sign_flags)) {
943dab3f910Sjsing 			BIO_printf(bio_err, "Error signing OCSP request\n");
944dab3f910Sjsing 			goto end;
945dab3f910Sjsing 		}
946dab3f910Sjsing 	}
947e7718adaStb 	if (cfg.req_text && cfg.req)
948e7718adaStb 		OCSP_REQUEST_print(out, cfg.req, 0);
949dab3f910Sjsing 
950e7718adaStb 	if (cfg.reqout) {
951e7718adaStb 		derbio = BIO_new_file(cfg.reqout, "wb");
952dab3f910Sjsing 		if (!derbio) {
953bc14ef1fSinoguchi 			BIO_printf(bio_err, "Error opening file %s\n",
954e7718adaStb 			    cfg.reqout);
955dab3f910Sjsing 			goto end;
956dab3f910Sjsing 		}
957e7718adaStb 		i2d_OCSP_REQUEST_bio(derbio, cfg.req);
958dab3f910Sjsing 		BIO_free(derbio);
959dab3f910Sjsing 	}
960e7718adaStb 	if (cfg.ridx_filename && (!rkey || !rsigner || !rca_cert)) {
961bc14ef1fSinoguchi 		BIO_printf(bio_err,
962bc14ef1fSinoguchi 		    "Need a responder certificate, key and CA for this operation!\n");
963dab3f910Sjsing 		goto end;
964dab3f910Sjsing 	}
965e7718adaStb 	if (cfg.ridx_filename && !rdb) {
966e7718adaStb 		rdb = load_index(cfg.ridx_filename, NULL);
967dab3f910Sjsing 		if (!rdb)
968dab3f910Sjsing 			goto end;
969dab3f910Sjsing 		if (!index_index(rdb))
970dab3f910Sjsing 			goto end;
971dab3f910Sjsing 	}
972dab3f910Sjsing 	if (rdb) {
973e7718adaStb 		i = make_ocsp_response(&resp, cfg.req, rdb, rca_cert,
974e7718adaStb 		    rsigner, rkey, rother, cfg.rflags,
975e7718adaStb 		    cfg.nmin, cfg.ndays);
976dab3f910Sjsing 		if (cbio)
977dab3f910Sjsing 			send_ocsp_response(cbio, resp);
978e7718adaStb 	} else if (cfg.host) {
979e7718adaStb 		resp = process_responder(bio_err, cfg.req,
980e7718adaStb 		    cfg.host,
981e7718adaStb 		    cfg.path ? cfg.path : "/",
982e7718adaStb 		    cfg.port, cfg.use_ssl, cfg.headers,
983e7718adaStb 		    cfg.req_timeout);
984dab3f910Sjsing 		if (!resp)
985dab3f910Sjsing 			goto end;
986e7718adaStb 	} else if (cfg.respin) {
987e7718adaStb 		derbio = BIO_new_file(cfg.respin, "rb");
988dab3f910Sjsing 		if (!derbio) {
989bc14ef1fSinoguchi 			BIO_printf(bio_err,
990bc14ef1fSinoguchi 			    "Error Opening OCSP response file\n");
991dab3f910Sjsing 			goto end;
992dab3f910Sjsing 		}
993dab3f910Sjsing 		resp = d2i_OCSP_RESPONSE_bio(derbio, NULL);
994dab3f910Sjsing 		BIO_free(derbio);
995dab3f910Sjsing 		if (!resp) {
996dab3f910Sjsing 			BIO_printf(bio_err, "Error reading OCSP response\n");
997dab3f910Sjsing 			goto end;
998dab3f910Sjsing 		}
999dab3f910Sjsing 	} else {
1000dab3f910Sjsing 		ret = 0;
1001dab3f910Sjsing 		goto end;
1002dab3f910Sjsing 	}
1003dab3f910Sjsing 
1004dab3f910Sjsing  done_resp:
1005dab3f910Sjsing 
1006e7718adaStb 	if (cfg.respout) {
1007e7718adaStb 		derbio = BIO_new_file(cfg.respout, "wb");
1008dab3f910Sjsing 		if (!derbio) {
1009bc14ef1fSinoguchi 			BIO_printf(bio_err, "Error opening file %s\n",
1010e7718adaStb 			    cfg.respout);
1011dab3f910Sjsing 			goto end;
1012dab3f910Sjsing 		}
1013dab3f910Sjsing 		i2d_OCSP_RESPONSE_bio(derbio, resp);
1014dab3f910Sjsing 		BIO_free(derbio);
1015dab3f910Sjsing 	}
1016dab3f910Sjsing 	i = OCSP_response_status(resp);
1017dab3f910Sjsing 
1018dab3f910Sjsing 	if (i != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
1019c48dfb0cSbeck 		BIO_printf(bio_err, "Responder Error: %s (%d)\n",
1020dab3f910Sjsing 		    OCSP_response_status_str(i), i);
1021e7718adaStb 		if (cfg.ignore_err)
1022dab3f910Sjsing 			goto redo_accept;
1023c48dfb0cSbeck 		ret = 1;
1024dab3f910Sjsing 		goto end;
1025dab3f910Sjsing 	}
1026e7718adaStb 	if (cfg.resp_text)
1027dab3f910Sjsing 		OCSP_RESPONSE_print(out, resp, 0);
1028dab3f910Sjsing 
1029dab3f910Sjsing 	/* If running as responder don't verify our own response */
1030dab3f910Sjsing 	if (cbio) {
1031e7718adaStb 		if (cfg.accept_count > 0)
1032e7718adaStb 			cfg.accept_count--;
1033dab3f910Sjsing 		/* Redo if more connections needed */
1034e7718adaStb 		if (cfg.accept_count) {
1035dab3f910Sjsing 			BIO_free_all(cbio);
1036dab3f910Sjsing 			cbio = NULL;
1037e7718adaStb 			OCSP_REQUEST_free(cfg.req);
1038e7718adaStb 			cfg.req = NULL;
1039dab3f910Sjsing 			OCSP_RESPONSE_free(resp);
1040dab3f910Sjsing 			resp = NULL;
1041dab3f910Sjsing 			goto redo_accept;
1042dab3f910Sjsing 		}
1043dab3f910Sjsing 		goto end;
1044dab3f910Sjsing 	}
1045dab3f910Sjsing 	if (!store)
1046e7718adaStb 		store = setup_verify(bio_err, cfg.CAfile,
1047e7718adaStb 		    cfg.CApath);
1048dab3f910Sjsing 	if (!store)
1049dab3f910Sjsing 		goto end;
1050e7718adaStb 	if (cfg.verify_certfile) {
1051e7718adaStb 		verify_other = load_certs(bio_err, cfg.verify_certfile,
1052bc14ef1fSinoguchi 		    FORMAT_PEM, NULL, "validator certificate");
1053dab3f910Sjsing 		if (!verify_other)
1054dab3f910Sjsing 			goto end;
1055dab3f910Sjsing 	}
1056dab3f910Sjsing 	bs = OCSP_response_get1_basic(resp);
1057dab3f910Sjsing 
1058dab3f910Sjsing 	if (!bs) {
1059dab3f910Sjsing 		BIO_printf(bio_err, "Error parsing response\n");
1060dab3f910Sjsing 		goto end;
1061dab3f910Sjsing 	}
1062e7718adaStb 	if (!cfg.noverify) {
1063e7718adaStb 		if (cfg.req &&
1064e7718adaStb 		    ((i = OCSP_check_nonce(cfg.req, bs)) <= 0)) {
1065bc14ef1fSinoguchi 			if (i == -1) {
1066bc14ef1fSinoguchi 				BIO_printf(bio_err,
1067bc14ef1fSinoguchi 				    "WARNING: no nonce in response\n");
1068bc14ef1fSinoguchi 			} else {
1069dab3f910Sjsing 				BIO_printf(bio_err, "Nonce Verify error\n");
1070dab3f910Sjsing 				goto end;
1071dab3f910Sjsing 			}
1072dab3f910Sjsing 		}
1073bc14ef1fSinoguchi 		i = OCSP_basic_verify(bs, verify_other, store,
1074e7718adaStb 		    cfg.verify_flags);
1075dab3f910Sjsing 		if (i < 0)
1076dab3f910Sjsing 			i = OCSP_basic_verify(bs, NULL, store, 0);
1077dab3f910Sjsing 
1078dab3f910Sjsing 		if (i <= 0) {
1079dab3f910Sjsing 			BIO_printf(bio_err, "Response Verify Failure\n");
1080dab3f910Sjsing 			ERR_print_errors(bio_err);
1081bc14ef1fSinoguchi 		} else {
1082dab3f910Sjsing 			BIO_printf(bio_err, "Response verify OK\n");
1083dab3f910Sjsing 		}
1084bc14ef1fSinoguchi 	}
1085e7718adaStb 	if (!print_ocsp_summary(out, bs, cfg.req, cfg.reqnames,
1086e7718adaStb 	    cfg.ids, cfg.nsec, cfg.maxage))
1087dab3f910Sjsing 		goto end;
1088dab3f910Sjsing 
1089dab3f910Sjsing 	ret = 0;
1090dab3f910Sjsing 
1091dab3f910Sjsing  end:
1092dab3f910Sjsing 	ERR_print_errors(bio_err);
1093dab3f910Sjsing 	X509_free(signer);
1094dab3f910Sjsing 	X509_STORE_free(store);
1095dab3f910Sjsing 	EVP_PKEY_free(key);
1096dab3f910Sjsing 	EVP_PKEY_free(rkey);
1097e7718adaStb 	X509_free(cfg.issuer);
1098e7718adaStb 	X509_free(cfg.cert);
1099dab3f910Sjsing 	X509_free(rsigner);
1100dab3f910Sjsing 	X509_free(rca_cert);
1101dab3f910Sjsing 	free_index(rdb);
1102dab3f910Sjsing 	BIO_free_all(cbio);
1103dab3f910Sjsing 	BIO_free_all(acbio);
1104dab3f910Sjsing 	BIO_free(out);
1105e7718adaStb 	OCSP_REQUEST_free(cfg.req);
1106dab3f910Sjsing 	OCSP_RESPONSE_free(resp);
1107dab3f910Sjsing 	OCSP_BASICRESP_free(bs);
1108e7718adaStb 	sk_OPENSSL_STRING_free(cfg.reqnames);
1109e7718adaStb 	sk_OCSP_CERTID_free(cfg.ids);
1110dab3f910Sjsing 	sk_X509_pop_free(sign_other, X509_free);
1111dab3f910Sjsing 	sk_X509_pop_free(verify_other, X509_free);
1112e7718adaStb 	sk_CONF_VALUE_pop_free(cfg.headers, X509V3_conf_free);
1113dab3f910Sjsing 
1114e7718adaStb 	if (cfg.use_ssl != -1) {
1115e7718adaStb 		free(cfg.host);
1116e7718adaStb 		free(cfg.port);
1117e7718adaStb 		free(cfg.path);
1118dab3f910Sjsing 	}
1119dab3f910Sjsing 	return (ret);
1120dab3f910Sjsing }
1121dab3f910Sjsing 
1122dab3f910Sjsing static int
1123bc14ef1fSinoguchi add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, const EVP_MD *cert_id_md,
1124bc14ef1fSinoguchi     X509 *issuer, STACK_OF(OCSP_CERTID) *ids)
1125dab3f910Sjsing {
1126dab3f910Sjsing 	OCSP_CERTID *id;
1127bc14ef1fSinoguchi 
1128dab3f910Sjsing 	if (!issuer) {
1129dab3f910Sjsing 		BIO_printf(bio_err, "No issuer certificate specified\n");
1130dab3f910Sjsing 		return 0;
1131dab3f910Sjsing 	}
1132dab3f910Sjsing 	if (!*req)
1133dab3f910Sjsing 		*req = OCSP_REQUEST_new();
1134dab3f910Sjsing 	if (!*req)
1135dab3f910Sjsing 		goto err;
1136dab3f910Sjsing 	id = OCSP_cert_to_id(cert_id_md, cert, issuer);
1137dab3f910Sjsing 	if (!id || !sk_OCSP_CERTID_push(ids, id))
1138dab3f910Sjsing 		goto err;
1139dab3f910Sjsing 	if (!OCSP_request_add0_id(*req, id))
1140dab3f910Sjsing 		goto err;
1141dab3f910Sjsing 	return 1;
1142dab3f910Sjsing 
1143dab3f910Sjsing  err:
1144dab3f910Sjsing 	BIO_printf(bio_err, "Error Creating OCSP request\n");
1145dab3f910Sjsing 	return 0;
1146dab3f910Sjsing }
1147dab3f910Sjsing 
1148dab3f910Sjsing static int
1149bc14ef1fSinoguchi add_ocsp_serial(OCSP_REQUEST **req, char *serial, const EVP_MD *cert_id_md,
1150bc14ef1fSinoguchi     X509 *issuer, STACK_OF(OCSP_CERTID) *ids)
1151dab3f910Sjsing {
1152dab3f910Sjsing 	OCSP_CERTID *id;
1153dab3f910Sjsing 	X509_NAME *iname;
1154dab3f910Sjsing 	ASN1_BIT_STRING *ikey;
1155dab3f910Sjsing 	ASN1_INTEGER *sno;
1156bc14ef1fSinoguchi 
1157dab3f910Sjsing 	if (!issuer) {
1158dab3f910Sjsing 		BIO_printf(bio_err, "No issuer certificate specified\n");
1159dab3f910Sjsing 		return 0;
1160dab3f910Sjsing 	}
1161dab3f910Sjsing 	if (!*req)
1162dab3f910Sjsing 		*req = OCSP_REQUEST_new();
1163dab3f910Sjsing 	if (!*req)
1164dab3f910Sjsing 		goto err;
1165dab3f910Sjsing 	iname = X509_get_subject_name(issuer);
1166dab3f910Sjsing 	ikey = X509_get0_pubkey_bitstr(issuer);
1167dab3f910Sjsing 	sno = s2i_ASN1_INTEGER(NULL, serial);
1168dab3f910Sjsing 	if (!sno) {
1169bc14ef1fSinoguchi 		BIO_printf(bio_err, "Error converting serial number %s\n",
1170bc14ef1fSinoguchi 		    serial);
1171dab3f910Sjsing 		return 0;
1172dab3f910Sjsing 	}
1173dab3f910Sjsing 	id = OCSP_cert_id_new(cert_id_md, iname, ikey, sno);
1174dab3f910Sjsing 	ASN1_INTEGER_free(sno);
1175dab3f910Sjsing 	if (!id || !sk_OCSP_CERTID_push(ids, id))
1176dab3f910Sjsing 		goto err;
1177dab3f910Sjsing 	if (!OCSP_request_add0_id(*req, id))
1178dab3f910Sjsing 		goto err;
1179dab3f910Sjsing 	return 1;
1180dab3f910Sjsing 
1181dab3f910Sjsing  err:
1182dab3f910Sjsing 	BIO_printf(bio_err, "Error Creating OCSP request\n");
1183dab3f910Sjsing 	return 0;
1184dab3f910Sjsing }
1185dab3f910Sjsing 
1186dab3f910Sjsing static int
1187dab3f910Sjsing print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req,
1188bc14ef1fSinoguchi     STACK_OF(OPENSSL_STRING) *names, STACK_OF(OCSP_CERTID) *ids, long nsec,
1189dab3f910Sjsing     long maxage)
1190dab3f910Sjsing {
1191dab3f910Sjsing 	OCSP_CERTID *id;
1192dab3f910Sjsing 	char *name;
1193dab3f910Sjsing 	int i;
1194dab3f910Sjsing 	int status, reason;
1195dab3f910Sjsing 
1196dab3f910Sjsing 	ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
1197dab3f910Sjsing 
1198bc14ef1fSinoguchi 	if (!bs || !req || !sk_OPENSSL_STRING_num(names) ||
1199bc14ef1fSinoguchi 	    !sk_OCSP_CERTID_num(ids))
1200dab3f910Sjsing 		return 1;
1201dab3f910Sjsing 
1202dab3f910Sjsing 	for (i = 0; i < sk_OCSP_CERTID_num(ids); i++) {
1203dab3f910Sjsing 		id = sk_OCSP_CERTID_value(ids, i);
1204dab3f910Sjsing 		name = sk_OPENSSL_STRING_value(names, i);
1205dab3f910Sjsing 		BIO_printf(out, "%s: ", name);
1206dab3f910Sjsing 
1207dab3f910Sjsing 		if (!OCSP_resp_find_status(bs, id, &status, &reason,
1208dab3f910Sjsing 			&rev, &thisupd, &nextupd)) {
1209dab3f910Sjsing 			BIO_puts(out, "ERROR: No Status found.\n");
1210dab3f910Sjsing 			continue;
1211dab3f910Sjsing 		}
1212dab3f910Sjsing 		/*
1213dab3f910Sjsing 		 * Check validity: if invalid write to output BIO so we know
1214dab3f910Sjsing 		 * which response this refers to.
1215dab3f910Sjsing 		 */
1216dab3f910Sjsing 		if (!OCSP_check_validity(thisupd, nextupd, nsec, maxage)) {
1217dab3f910Sjsing 			BIO_puts(out, "WARNING: Status times invalid.\n");
1218dab3f910Sjsing 			ERR_print_errors(out);
1219dab3f910Sjsing 		}
1220dab3f910Sjsing 		BIO_printf(out, "%s\n", OCSP_cert_status_str(status));
1221dab3f910Sjsing 
1222dab3f910Sjsing 		BIO_puts(out, "\tThis Update: ");
1223dab3f910Sjsing 		ASN1_GENERALIZEDTIME_print(out, thisupd);
1224dab3f910Sjsing 		BIO_puts(out, "\n");
1225dab3f910Sjsing 
1226dab3f910Sjsing 		if (nextupd) {
1227dab3f910Sjsing 			BIO_puts(out, "\tNext Update: ");
1228dab3f910Sjsing 			ASN1_GENERALIZEDTIME_print(out, nextupd);
1229dab3f910Sjsing 			BIO_puts(out, "\n");
1230dab3f910Sjsing 		}
1231dab3f910Sjsing 		if (status != V_OCSP_CERTSTATUS_REVOKED)
1232dab3f910Sjsing 			continue;
1233dab3f910Sjsing 
1234dab3f910Sjsing 		if (reason != -1)
1235dab3f910Sjsing 			BIO_printf(out, "\tReason: %s\n",
1236dab3f910Sjsing 			    OCSP_crl_reason_str(reason));
1237dab3f910Sjsing 
1238dab3f910Sjsing 		BIO_puts(out, "\tRevocation Time: ");
1239dab3f910Sjsing 		ASN1_GENERALIZEDTIME_print(out, rev);
1240dab3f910Sjsing 		BIO_puts(out, "\n");
1241dab3f910Sjsing 	}
1242dab3f910Sjsing 
1243dab3f910Sjsing 	return 1;
1244dab3f910Sjsing }
1245dab3f910Sjsing 
1246dab3f910Sjsing 
1247dab3f910Sjsing static int
1248dab3f910Sjsing make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req, CA_DB *db,
1249bc14ef1fSinoguchi     X509 *ca, X509 *rcert, EVP_PKEY *rkey, STACK_OF(X509) *rother,
1250bc14ef1fSinoguchi     unsigned long flags, int nmin, int ndays)
1251dab3f910Sjsing {
1252dab3f910Sjsing 	ASN1_TIME *thisupd = NULL, *nextupd = NULL;
1253dab3f910Sjsing 	OCSP_CERTID *cid, *ca_id = NULL;
1254dab3f910Sjsing 	OCSP_BASICRESP *bs = NULL;
1255dab3f910Sjsing 	int i, id_count, ret = 1;
1256dab3f910Sjsing 
1257dab3f910Sjsing 	id_count = OCSP_request_onereq_count(req);
1258dab3f910Sjsing 
1259dab3f910Sjsing 	if (id_count <= 0) {
1260bc14ef1fSinoguchi 		*resp = OCSP_response_create(
1261bc14ef1fSinoguchi 		    OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, NULL);
1262dab3f910Sjsing 		goto end;
1263dab3f910Sjsing 	}
1264dab3f910Sjsing 	bs = OCSP_BASICRESP_new();
1265dab3f910Sjsing 	thisupd = X509_gmtime_adj(NULL, 0);
1266dab3f910Sjsing 	if (ndays != -1)
1267dab3f910Sjsing 		nextupd = X509_gmtime_adj(NULL, nmin * 60 + ndays * 3600 * 24);
1268dab3f910Sjsing 
1269dab3f910Sjsing 	/* Examine each certificate id in the request */
1270dab3f910Sjsing 	for (i = 0; i < id_count; i++) {
1271dab3f910Sjsing 		OCSP_ONEREQ *one;
1272dab3f910Sjsing 		ASN1_INTEGER *serial;
1273dab3f910Sjsing 		char **inf;
1274dab3f910Sjsing 		ASN1_OBJECT *cert_id_md_oid;
1275dab3f910Sjsing 		const EVP_MD *cert_id_md;
1276dab3f910Sjsing 		one = OCSP_request_onereq_get0(req, i);
1277dab3f910Sjsing 		cid = OCSP_onereq_get0_id(one);
1278dab3f910Sjsing 
1279dab3f910Sjsing 		OCSP_id_get0_info(NULL, &cert_id_md_oid, NULL, NULL, cid);
1280dab3f910Sjsing 
1281dab3f910Sjsing 		cert_id_md = EVP_get_digestbyobj(cert_id_md_oid);
1282dab3f910Sjsing 		if (!cert_id_md) {
1283bc14ef1fSinoguchi 			*resp = OCSP_response_create(
1284bc14ef1fSinoguchi 			    OCSP_RESPONSE_STATUS_INTERNALERROR, NULL);
1285dab3f910Sjsing 			goto end;
1286dab3f910Sjsing 		}
1287dab3f910Sjsing 		OCSP_CERTID_free(ca_id);
1288dab3f910Sjsing 		ca_id = OCSP_cert_to_id(cert_id_md, NULL, ca);
1289dab3f910Sjsing 
1290dab3f910Sjsing 		/* Is this request about our CA? */
1291dab3f910Sjsing 		if (OCSP_id_issuer_cmp(ca_id, cid)) {
1292dab3f910Sjsing 			OCSP_basic_add1_status(bs, cid,
1293bc14ef1fSinoguchi 			    V_OCSP_CERTSTATUS_UNKNOWN, 0, NULL,
1294dab3f910Sjsing 			    thisupd, nextupd);
1295dab3f910Sjsing 			continue;
1296dab3f910Sjsing 		}
1297dab3f910Sjsing 		OCSP_id_get0_info(NULL, NULL, NULL, &serial, cid);
1298dab3f910Sjsing 		inf = lookup_serial(db, serial);
1299bc14ef1fSinoguchi 		if (!inf) {
1300dab3f910Sjsing 			OCSP_basic_add1_status(bs, cid,
1301bc14ef1fSinoguchi 			    V_OCSP_CERTSTATUS_UNKNOWN, 0, NULL,
1302dab3f910Sjsing 			    thisupd, nextupd);
1303bc14ef1fSinoguchi 		} else if (inf[DB_type][0] == DB_TYPE_VAL) {
1304dab3f910Sjsing 			OCSP_basic_add1_status(bs, cid,
1305bc14ef1fSinoguchi 			    V_OCSP_CERTSTATUS_GOOD, 0, NULL,
1306dab3f910Sjsing 			    thisupd, nextupd);
1307bc14ef1fSinoguchi 		} else if (inf[DB_type][0] == DB_TYPE_REV) {
1308dab3f910Sjsing 			ASN1_OBJECT *inst = NULL;
1309dab3f910Sjsing 			ASN1_TIME *revtm = NULL;
1310dab3f910Sjsing 			ASN1_GENERALIZEDTIME *invtm = NULL;
1311dab3f910Sjsing 			OCSP_SINGLERESP *single;
1312dab3f910Sjsing 			int reason = -1;
1313bc14ef1fSinoguchi 
1314bc14ef1fSinoguchi 			unpack_revinfo(&revtm, &reason, &inst, &invtm,
1315bc14ef1fSinoguchi 			    inf[DB_rev_date]);
1316dab3f910Sjsing 			single = OCSP_basic_add1_status(bs, cid,
1317dab3f910Sjsing 			    V_OCSP_CERTSTATUS_REVOKED,
1318dab3f910Sjsing 			    reason, revtm,
1319dab3f910Sjsing 			    thisupd, nextupd);
1320dab3f910Sjsing 			if (invtm)
1321bc14ef1fSinoguchi 				OCSP_SINGLERESP_add1_ext_i2d(single,
1322bc14ef1fSinoguchi 				    NID_invalidity_date, invtm, 0, 0);
1323dab3f910Sjsing 			else if (inst)
1324bc14ef1fSinoguchi 				OCSP_SINGLERESP_add1_ext_i2d(single,
1325bc14ef1fSinoguchi 				    NID_hold_instruction_code, inst, 0, 0);
1326dab3f910Sjsing 			ASN1_OBJECT_free(inst);
1327dab3f910Sjsing 			ASN1_TIME_free(revtm);
1328dab3f910Sjsing 			ASN1_GENERALIZEDTIME_free(invtm);
1329dab3f910Sjsing 		}
1330dab3f910Sjsing 	}
1331dab3f910Sjsing 
1332dab3f910Sjsing 	OCSP_copy_nonce(bs, req);
1333dab3f910Sjsing 
1334dab3f910Sjsing 	OCSP_basic_sign(bs, rcert, rkey, NULL, rother, flags);
1335dab3f910Sjsing 
1336dab3f910Sjsing 	*resp = OCSP_response_create(OCSP_RESPONSE_STATUS_SUCCESSFUL, bs);
1337dab3f910Sjsing 
1338dab3f910Sjsing  end:
1339dab3f910Sjsing 	ASN1_TIME_free(thisupd);
1340dab3f910Sjsing 	ASN1_TIME_free(nextupd);
1341dab3f910Sjsing 	OCSP_CERTID_free(ca_id);
1342dab3f910Sjsing 	OCSP_BASICRESP_free(bs);
1343dab3f910Sjsing 	return ret;
1344dab3f910Sjsing }
1345dab3f910Sjsing 
1346dab3f910Sjsing static char **
1347dab3f910Sjsing lookup_serial(CA_DB *db, ASN1_INTEGER *ser)
1348dab3f910Sjsing {
1349dab3f910Sjsing 	int i;
1350dab3f910Sjsing 	BIGNUM *bn = NULL;
1351dab3f910Sjsing 	char *itmp, *row[DB_NUMBER], **rrow;
1352bc14ef1fSinoguchi 
1353dab3f910Sjsing 	for (i = 0; i < DB_NUMBER; i++)
1354dab3f910Sjsing 		row[i] = NULL;
1355dab3f910Sjsing 	bn = ASN1_INTEGER_to_BN(ser, NULL);
1356dab3f910Sjsing 	OPENSSL_assert(bn);	/* FIXME: should report an error at this
1357dab3f910Sjsing 				 * point and abort */
1358dab3f910Sjsing 	if (BN_is_zero(bn))
1359dab3f910Sjsing 		itmp = strdup("00");
1360dab3f910Sjsing 	else
1361dab3f910Sjsing 		itmp = BN_bn2hex(bn);
1362dab3f910Sjsing 	row[DB_serial] = itmp;
1363dab3f910Sjsing 	BN_free(bn);
1364dab3f910Sjsing 	rrow = TXT_DB_get_by_index(db->db, DB_serial, row);
1365dab3f910Sjsing 	free(itmp);
1366dab3f910Sjsing 	return rrow;
1367dab3f910Sjsing }
1368dab3f910Sjsing 
1369dab3f910Sjsing /* Quick and dirty OCSP server: read in and parse input request */
1370dab3f910Sjsing 
1371dab3f910Sjsing static BIO *
1372dab3f910Sjsing init_responder(char *port)
1373dab3f910Sjsing {
1374dab3f910Sjsing 	BIO *acbio = NULL, *bufbio = NULL;
1375bc14ef1fSinoguchi 
1376dab3f910Sjsing 	bufbio = BIO_new(BIO_f_buffer());
1377dab3f910Sjsing 	if (!bufbio)
1378dab3f910Sjsing 		goto err;
1379dab3f910Sjsing 	acbio = BIO_new_accept(port);
1380dab3f910Sjsing 	if (!acbio)
1381dab3f910Sjsing 		goto err;
138284decd30Sbeck 	BIO_set_bind_mode(acbio, BIO_BIND_REUSEADDR);
1383dab3f910Sjsing 	BIO_set_accept_bios(acbio, bufbio);
1384dab3f910Sjsing 	bufbio = NULL;
1385dab3f910Sjsing 
1386dab3f910Sjsing 	if (BIO_do_accept(acbio) <= 0) {
1387dab3f910Sjsing 		BIO_printf(bio_err, "Error setting up accept BIO\n");
1388dab3f910Sjsing 		ERR_print_errors(bio_err);
1389dab3f910Sjsing 		goto err;
1390dab3f910Sjsing 	}
1391dab3f910Sjsing 	return acbio;
1392dab3f910Sjsing 
1393dab3f910Sjsing  err:
1394dab3f910Sjsing 	BIO_free_all(acbio);
1395dab3f910Sjsing 	BIO_free(bufbio);
1396dab3f910Sjsing 	return NULL;
1397dab3f910Sjsing }
1398dab3f910Sjsing 
1399dab3f910Sjsing static int
1400dab3f910Sjsing do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, char *port)
1401dab3f910Sjsing {
1402dab3f910Sjsing 	int have_post = 0, len;
1403dab3f910Sjsing 	OCSP_REQUEST *req = NULL;
1404dab3f910Sjsing 	char inbuf[1024];
1405dab3f910Sjsing 	BIO *cbio = NULL;
1406dab3f910Sjsing 
1407dab3f910Sjsing 	if (BIO_do_accept(acbio) <= 0) {
1408dab3f910Sjsing 		BIO_printf(bio_err, "Error accepting connection\n");
1409dab3f910Sjsing 		ERR_print_errors(bio_err);
1410dab3f910Sjsing 		return 0;
1411dab3f910Sjsing 	}
1412dab3f910Sjsing 	cbio = BIO_pop(acbio);
1413dab3f910Sjsing 	*pcbio = cbio;
1414dab3f910Sjsing 
1415dab3f910Sjsing 	for (;;) {
1416dab3f910Sjsing 		len = BIO_gets(cbio, inbuf, sizeof inbuf);
1417dab3f910Sjsing 		if (len <= 0)
1418dab3f910Sjsing 			return 1;
1419dab3f910Sjsing 		/* Look for "POST" signalling start of query */
1420dab3f910Sjsing 		if (!have_post) {
1421dab3f910Sjsing 			if (strncmp(inbuf, "POST", 4)) {
1422dab3f910Sjsing 				BIO_printf(bio_err, "Invalid request\n");
1423dab3f910Sjsing 				return 1;
1424dab3f910Sjsing 			}
1425dab3f910Sjsing 			have_post = 1;
1426dab3f910Sjsing 		}
1427dab3f910Sjsing 		/* Look for end of headers */
1428dab3f910Sjsing 		if ((inbuf[0] == '\r') || (inbuf[0] == '\n'))
1429dab3f910Sjsing 			break;
1430dab3f910Sjsing 	}
1431dab3f910Sjsing 
1432dab3f910Sjsing 	/* Try to read OCSP request */
1433dab3f910Sjsing 
1434dab3f910Sjsing 	req = d2i_OCSP_REQUEST_bio(cbio, NULL);
1435dab3f910Sjsing 
1436dab3f910Sjsing 	if (!req) {
1437dab3f910Sjsing 		BIO_printf(bio_err, "Error parsing OCSP request\n");
1438dab3f910Sjsing 		ERR_print_errors(bio_err);
1439dab3f910Sjsing 	}
1440dab3f910Sjsing 	*preq = req;
1441dab3f910Sjsing 
1442dab3f910Sjsing 	return 1;
1443dab3f910Sjsing }
1444dab3f910Sjsing 
1445dab3f910Sjsing static int
1446dab3f910Sjsing send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp)
1447dab3f910Sjsing {
1448dab3f910Sjsing 	static const char http_resp[] =
1449dab3f910Sjsing 	"HTTP/1.0 200 OK\r\nContent-type: application/ocsp-response\r\n"
1450dab3f910Sjsing 	"Content-Length: %d\r\n\r\n";
1451bc14ef1fSinoguchi 
1452dab3f910Sjsing 	if (!cbio)
1453dab3f910Sjsing 		return 0;
1454dab3f910Sjsing 	BIO_printf(cbio, http_resp, i2d_OCSP_RESPONSE(resp, NULL));
1455dab3f910Sjsing 	i2d_OCSP_RESPONSE_bio(cbio, resp);
1456dab3f910Sjsing 	(void) BIO_flush(cbio);
1457dab3f910Sjsing 	return 1;
1458dab3f910Sjsing }
1459dab3f910Sjsing 
1460dab3f910Sjsing static OCSP_RESPONSE *
1461bc14ef1fSinoguchi query_responder(BIO *err, BIO *cbio, char *path, STACK_OF(CONF_VALUE) *headers,
14627b609544Stb     const char *host, OCSP_REQUEST *req, int req_timeout)
1463dab3f910Sjsing {
1464dab3f910Sjsing 	int fd;
1465dab3f910Sjsing 	int rv;
1466dab3f910Sjsing 	int i;
14677b609544Stb 	int have_host = 0;
1468dab3f910Sjsing 	OCSP_REQ_CTX *ctx = NULL;
1469dab3f910Sjsing 	OCSP_RESPONSE *rsp = NULL;
1470230ab7bfSderaadt 	struct pollfd pfd[1];
1471dab3f910Sjsing 
1472dab3f910Sjsing 	if (req_timeout != -1)
1473dab3f910Sjsing 		BIO_set_nbio(cbio, 1);
1474dab3f910Sjsing 
1475dab3f910Sjsing 	rv = BIO_do_connect(cbio);
1476dab3f910Sjsing 
1477dab3f910Sjsing 	if ((rv <= 0) && ((req_timeout == -1) || !BIO_should_retry(cbio))) {
1478dab3f910Sjsing 		BIO_puts(err, "Error connecting BIO\n");
1479dab3f910Sjsing 		return NULL;
1480dab3f910Sjsing 	}
1481e8302d26Sderaadt 	if (BIO_get_fd(cbio, &fd) < 0) {
1482dab3f910Sjsing 		BIO_puts(err, "Can't get connection fd\n");
1483dab3f910Sjsing 		goto err;
1484dab3f910Sjsing 	}
1485dab3f910Sjsing 	if (req_timeout != -1 && rv <= 0) {
1486230ab7bfSderaadt 		pfd[0].fd = fd;
1487230ab7bfSderaadt 		pfd[0].events = POLLOUT;
1488230ab7bfSderaadt 		rv = poll(pfd, 1, req_timeout * 1000);
1489dab3f910Sjsing 		if (rv == 0) {
1490dab3f910Sjsing 			BIO_puts(err, "Timeout on connect\n");
1491dab3f910Sjsing 			return NULL;
1492dab3f910Sjsing 		}
1493230ab7bfSderaadt 		if (rv == -1) {
1494230ab7bfSderaadt 			BIO_puts(err, "Poll error\n");
1495230ab7bfSderaadt 			return NULL;
1496230ab7bfSderaadt 		}
1497dab3f910Sjsing 	}
1498dab3f910Sjsing 	ctx = OCSP_sendreq_new(cbio, path, NULL, -1);
1499dab3f910Sjsing 	if (!ctx)
1500dab3f910Sjsing 		return NULL;
1501dab3f910Sjsing 
1502dab3f910Sjsing 	for (i = 0; i < sk_CONF_VALUE_num(headers); i++) {
1503dab3f910Sjsing 		CONF_VALUE *hdr = sk_CONF_VALUE_value(headers, i);
15047b609544Stb 		if (strcasecmp("host", hdr->name) == 0)
15057b609544Stb 			have_host = 1;
1506dab3f910Sjsing 		if (!OCSP_REQ_CTX_add1_header(ctx, hdr->name, hdr->value))
1507dab3f910Sjsing 			goto err;
1508dab3f910Sjsing 	}
1509dab3f910Sjsing 
15107b609544Stb 	if (!have_host) {
15117b609544Stb 		if (!OCSP_REQ_CTX_add1_header(ctx, "Host", host))
15127b609544Stb 			goto err;
15137b609544Stb 	}
15147b609544Stb 
1515dab3f910Sjsing 	if (!OCSP_REQ_CTX_set1_req(ctx, req))
1516dab3f910Sjsing 		goto err;
1517dab3f910Sjsing 
1518dab3f910Sjsing 	for (;;) {
1519dab3f910Sjsing 		rv = OCSP_sendreq_nbio(&rsp, ctx);
1520dab3f910Sjsing 		if (rv != -1)
1521dab3f910Sjsing 			break;
1522dab3f910Sjsing 		if (req_timeout == -1)
1523dab3f910Sjsing 			continue;
1524230ab7bfSderaadt 		pfd[0].fd = fd;
1525bc14ef1fSinoguchi 		if (BIO_should_read(cbio)) {
1526230ab7bfSderaadt 			pfd[0].events = POLLIN;
1527bc14ef1fSinoguchi 		} else if (BIO_should_write(cbio)) {
1528230ab7bfSderaadt 			pfd[0].events = POLLOUT;
1529bc14ef1fSinoguchi 		} else {
1530dab3f910Sjsing 			BIO_puts(err, "Unexpected retry condition\n");
1531dab3f910Sjsing 			goto err;
1532dab3f910Sjsing 		}
1533230ab7bfSderaadt 		rv = poll(pfd, 1, req_timeout * 1000);
1534dab3f910Sjsing 		if (rv == 0) {
1535dab3f910Sjsing 			BIO_puts(err, "Timeout on request\n");
1536dab3f910Sjsing 			break;
1537dab3f910Sjsing 		}
1538230ab7bfSderaadt 		if (rv == -1 || (pfd[0].revents & (POLLERR|POLLNVAL))) {
1539230ab7bfSderaadt 			BIO_puts(err, "Poll error\n");
1540dab3f910Sjsing 			break;
1541dab3f910Sjsing 		}
1542dab3f910Sjsing 	}
1543bc14ef1fSinoguchi 
1544dab3f910Sjsing  err:
1545dab3f910Sjsing 	OCSP_REQ_CTX_free(ctx);
1546dab3f910Sjsing 	return rsp;
1547dab3f910Sjsing }
1548dab3f910Sjsing 
1549dab3f910Sjsing OCSP_RESPONSE *
1550bc14ef1fSinoguchi process_responder(BIO *err, OCSP_REQUEST *req, char *host, char *path,
1551bc14ef1fSinoguchi     char *port, int use_ssl, STACK_OF(CONF_VALUE) *headers, int req_timeout)
1552dab3f910Sjsing {
1553dab3f910Sjsing 	BIO *cbio = NULL;
1554dab3f910Sjsing 	SSL_CTX *ctx = NULL;
1555dab3f910Sjsing 	OCSP_RESPONSE *resp = NULL;
1556bc14ef1fSinoguchi 
1557dab3f910Sjsing 	cbio = BIO_new_connect(host);
1558dab3f910Sjsing 	if (!cbio) {
1559dab3f910Sjsing 		BIO_printf(err, "Error creating connect BIO\n");
1560dab3f910Sjsing 		goto end;
1561dab3f910Sjsing 	}
1562dab3f910Sjsing 	if (port)
1563dab3f910Sjsing 		BIO_set_conn_port(cbio, port);
1564dab3f910Sjsing 	if (use_ssl == 1) {
1565dab3f910Sjsing 		BIO *sbio;
15665eedcc54Sinoguchi 		ctx = SSL_CTX_new(TLS_client_method());
1567dab3f910Sjsing 		if (ctx == NULL) {
1568dab3f910Sjsing 			BIO_printf(err, "Error creating SSL context.\n");
1569dab3f910Sjsing 			goto end;
1570dab3f910Sjsing 		}
1571dab3f910Sjsing 		SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
1572dab3f910Sjsing 		sbio = BIO_new_ssl(ctx, 1);
1573dab3f910Sjsing 		cbio = BIO_push(sbio, cbio);
1574dab3f910Sjsing 	}
15757b609544Stb 	resp = query_responder(err, cbio, path, headers, host, req, req_timeout);
1576dab3f910Sjsing 	if (!resp)
1577dab3f910Sjsing 		BIO_printf(bio_err, "Error querying OCSP responder\n");
1578bc14ef1fSinoguchi 
1579dab3f910Sjsing  end:
1580dab3f910Sjsing 	BIO_free_all(cbio);
1581dab3f910Sjsing 	SSL_CTX_free(ctx);
1582dab3f910Sjsing 	return resp;
1583dab3f910Sjsing }
1584dab3f910Sjsing #endif
1585