xref: /dflybsd-src/crypto/libressl/apps/openssl/ocsp.c (revision 961e30ea7dc61d1112b778ea4981eac68129fb86)
1*de0e0e4dSAntonio Huete Jimenez /* $OpenBSD: ocsp.c,v 1.21 2020/10/13 18:25:35 tb Exp $ */
2f5b1c8a1SJohn Marino /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3f5b1c8a1SJohn Marino  * project 2000.
4f5b1c8a1SJohn Marino  */
5f5b1c8a1SJohn Marino /* ====================================================================
6f5b1c8a1SJohn Marino  * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
7f5b1c8a1SJohn Marino  *
8f5b1c8a1SJohn Marino  * Redistribution and use in source and binary forms, with or without
9f5b1c8a1SJohn Marino  * modification, are permitted provided that the following conditions
10f5b1c8a1SJohn Marino  * are met:
11f5b1c8a1SJohn Marino  *
12f5b1c8a1SJohn Marino  * 1. Redistributions of source code must retain the above copyright
13f5b1c8a1SJohn Marino  *    notice, this list of conditions and the following disclaimer.
14f5b1c8a1SJohn Marino  *
15f5b1c8a1SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
16f5b1c8a1SJohn Marino  *    notice, this list of conditions and the following disclaimer in
17f5b1c8a1SJohn Marino  *    the documentation and/or other materials provided with the
18f5b1c8a1SJohn Marino  *    distribution.
19f5b1c8a1SJohn Marino  *
20f5b1c8a1SJohn Marino  * 3. All advertising materials mentioning features or use of this
21f5b1c8a1SJohn Marino  *    software must display the following acknowledgment:
22f5b1c8a1SJohn Marino  *    "This product includes software developed by the OpenSSL Project
23f5b1c8a1SJohn Marino  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24f5b1c8a1SJohn Marino  *
25f5b1c8a1SJohn Marino  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26f5b1c8a1SJohn Marino  *    endorse or promote products derived from this software without
27f5b1c8a1SJohn Marino  *    prior written permission. For written permission, please contact
28f5b1c8a1SJohn Marino  *    licensing@OpenSSL.org.
29f5b1c8a1SJohn Marino  *
30f5b1c8a1SJohn Marino  * 5. Products derived from this software may not be called "OpenSSL"
31f5b1c8a1SJohn Marino  *    nor may "OpenSSL" appear in their names without prior written
32f5b1c8a1SJohn Marino  *    permission of the OpenSSL Project.
33f5b1c8a1SJohn Marino  *
34f5b1c8a1SJohn Marino  * 6. Redistributions of any form whatsoever must retain the following
35f5b1c8a1SJohn Marino  *    acknowledgment:
36f5b1c8a1SJohn Marino  *    "This product includes software developed by the OpenSSL Project
37f5b1c8a1SJohn Marino  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38f5b1c8a1SJohn Marino  *
39f5b1c8a1SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40f5b1c8a1SJohn Marino  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41f5b1c8a1SJohn Marino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42f5b1c8a1SJohn Marino  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43f5b1c8a1SJohn Marino  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44f5b1c8a1SJohn Marino  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45f5b1c8a1SJohn Marino  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46f5b1c8a1SJohn Marino  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47f5b1c8a1SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48f5b1c8a1SJohn Marino  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49f5b1c8a1SJohn Marino  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50f5b1c8a1SJohn Marino  * OF THE POSSIBILITY OF SUCH DAMAGE.
51f5b1c8a1SJohn Marino  * ====================================================================
52f5b1c8a1SJohn Marino  *
53f5b1c8a1SJohn Marino  * This product includes cryptographic software written by Eric Young
54f5b1c8a1SJohn Marino  * (eay@cryptsoft.com).  This product includes software written by Tim
55f5b1c8a1SJohn Marino  * Hudson (tjh@cryptsoft.com).
56f5b1c8a1SJohn Marino  *
57f5b1c8a1SJohn Marino  */
58f5b1c8a1SJohn Marino #ifndef OPENSSL_NO_OCSP
59f5b1c8a1SJohn Marino 
60f5b1c8a1SJohn Marino #include <sys/types.h>
61f5b1c8a1SJohn Marino 
62f5b1c8a1SJohn Marino #include <stdio.h>
63f5b1c8a1SJohn Marino #include <stdlib.h>
64f5b1c8a1SJohn Marino #include <limits.h>
65f5b1c8a1SJohn Marino #include <string.h>
66f5b1c8a1SJohn Marino #include <poll.h>
67f5b1c8a1SJohn Marino #include <time.h>
68f5b1c8a1SJohn Marino 
69f5b1c8a1SJohn Marino /* Needs to be included before the openssl headers! */
70f5b1c8a1SJohn Marino #include "apps.h"
71f5b1c8a1SJohn Marino 
72f5b1c8a1SJohn Marino #include <openssl/bn.h>
73f5b1c8a1SJohn Marino #include <openssl/crypto.h>
74f5b1c8a1SJohn Marino #include <openssl/err.h>
75f5b1c8a1SJohn Marino #include <openssl/evp.h>
76f5b1c8a1SJohn Marino #include <openssl/ssl.h>
77f5b1c8a1SJohn Marino #include <openssl/x509v3.h>
78f5b1c8a1SJohn Marino 
79f5b1c8a1SJohn Marino /* Maximum leeway in validity period: default 5 minutes */
80f5b1c8a1SJohn Marino #define MAX_VALIDITY_PERIOD	(5 * 60)
81f5b1c8a1SJohn Marino 
828edacedfSDaniel Fojt static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert,
838edacedfSDaniel Fojt     const EVP_MD *cert_id_md, X509 *issuer, STACK_OF(OCSP_CERTID) *ids);
848edacedfSDaniel Fojt static int add_ocsp_serial(OCSP_REQUEST **req, char *serial,
858edacedfSDaniel Fojt     const EVP_MD *cert_id_md, X509 *issuer, STACK_OF(OCSP_CERTID) *ids);
86f5b1c8a1SJohn Marino static int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req,
878edacedfSDaniel Fojt     STACK_OF(OPENSSL_STRING) *names, STACK_OF(OCSP_CERTID) *ids, long nsec,
88f5b1c8a1SJohn Marino     long maxage);
89f5b1c8a1SJohn Marino 
908edacedfSDaniel Fojt static int make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req,
918edacedfSDaniel Fojt     CA_DB *db, X509 *ca, X509 *rcert, EVP_PKEY *rkey, STACK_OF(X509) *rother,
928edacedfSDaniel Fojt     unsigned long flags, int nmin, int ndays);
93f5b1c8a1SJohn Marino 
94f5b1c8a1SJohn Marino static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser);
95f5b1c8a1SJohn Marino static BIO *init_responder(char *port);
968edacedfSDaniel Fojt static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio,
978edacedfSDaniel Fojt     char *port);
98f5b1c8a1SJohn Marino static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp);
99f5b1c8a1SJohn Marino static OCSP_RESPONSE *query_responder(BIO *err, BIO *cbio, char *path,
100*de0e0e4dSAntonio Huete Jimenez     STACK_OF(CONF_VALUE) *headers, const char *host, OCSP_REQUEST *req,
101*de0e0e4dSAntonio Huete Jimenez     int req_timeout);
1028edacedfSDaniel Fojt 
1038edacedfSDaniel Fojt static struct {
1048edacedfSDaniel Fojt 	int accept_count;
1058edacedfSDaniel Fojt 	int add_nonce;
1068edacedfSDaniel Fojt 	char *CAfile;
1078edacedfSDaniel Fojt 	char *CApath;
1088edacedfSDaniel Fojt 	X509 *cert;
1098edacedfSDaniel Fojt 	const EVP_MD *cert_id_md;
1108edacedfSDaniel Fojt 	STACK_OF(CONF_VALUE) *headers;
1118edacedfSDaniel Fojt 	char *host;
1128edacedfSDaniel Fojt 	STACK_OF(OCSP_CERTID) *ids;
1138edacedfSDaniel Fojt 	int ignore_err;
1148edacedfSDaniel Fojt 	X509 *issuer;
1158edacedfSDaniel Fojt 	char *keyfile;
1168edacedfSDaniel Fojt 	long maxage;
1178edacedfSDaniel Fojt 	int ndays;
1188edacedfSDaniel Fojt 	int nmin;
1198edacedfSDaniel Fojt 	int no_usage;
1208edacedfSDaniel Fojt 	int noverify;
1218edacedfSDaniel Fojt 	long nsec;
1228edacedfSDaniel Fojt 	char *outfile;
1238edacedfSDaniel Fojt 	char *path;
1248edacedfSDaniel Fojt 	char *port;
1258edacedfSDaniel Fojt 	char *rca_filename;
1268edacedfSDaniel Fojt 	char *rcertfile;
1278edacedfSDaniel Fojt 	OCSP_REQUEST *req;
1288edacedfSDaniel Fojt 	int req_text;
1298edacedfSDaniel Fojt 	int req_timeout;
1308edacedfSDaniel Fojt 	char *reqin;
1318edacedfSDaniel Fojt 	STACK_OF(OPENSSL_STRING) *reqnames;
1328edacedfSDaniel Fojt 	char *reqout;
1338edacedfSDaniel Fojt 	int resp_text;
1348edacedfSDaniel Fojt 	char *respin;
1358edacedfSDaniel Fojt 	char *respout;
1368edacedfSDaniel Fojt 	unsigned long rflags;
1378edacedfSDaniel Fojt 	char *ridx_filename;
1388edacedfSDaniel Fojt 	char *rkeyfile;
1398edacedfSDaniel Fojt 	char *rsignfile;
1408edacedfSDaniel Fojt 	char *sign_certfile;
1418edacedfSDaniel Fojt 	unsigned long sign_flags;
1428edacedfSDaniel Fojt 	char *signfile;
1438edacedfSDaniel Fojt 	int use_ssl;
1448edacedfSDaniel Fojt 	char *verify_certfile;
1458edacedfSDaniel Fojt 	unsigned long verify_flags;
1468edacedfSDaniel Fojt } ocsp_config;
1478edacedfSDaniel Fojt 
1488edacedfSDaniel Fojt static int
ocsp_opt_cert(char * arg)1498edacedfSDaniel Fojt ocsp_opt_cert(char *arg)
1508edacedfSDaniel Fojt {
1518edacedfSDaniel Fojt 	X509_free(ocsp_config.cert);
1528edacedfSDaniel Fojt 	ocsp_config.cert = load_cert(bio_err, arg, FORMAT_PEM, NULL,
1538edacedfSDaniel Fojt 	    "certificate");
1548edacedfSDaniel Fojt 	if (ocsp_config.cert == NULL) {
1558edacedfSDaniel Fojt 		ocsp_config.no_usage = 1;
1568edacedfSDaniel Fojt 		return (1);
1578edacedfSDaniel Fojt 	}
1588edacedfSDaniel Fojt 	if (ocsp_config.cert_id_md == NULL)
1598edacedfSDaniel Fojt 		ocsp_config.cert_id_md = EVP_sha1();
1608edacedfSDaniel Fojt 	if (!add_ocsp_cert(&ocsp_config.req, ocsp_config.cert,
1618edacedfSDaniel Fojt 	    ocsp_config.cert_id_md, ocsp_config.issuer, ocsp_config.ids)) {
1628edacedfSDaniel Fojt 		ocsp_config.no_usage = 1;
1638edacedfSDaniel Fojt 		return (1);
1648edacedfSDaniel Fojt 	}
1658edacedfSDaniel Fojt 	if (!sk_OPENSSL_STRING_push(ocsp_config.reqnames, arg)) {
1668edacedfSDaniel Fojt 		ocsp_config.no_usage = 1;
1678edacedfSDaniel Fojt 		return (1);
1688edacedfSDaniel Fojt 	}
1698edacedfSDaniel Fojt 	return (0);
1708edacedfSDaniel Fojt }
1718edacedfSDaniel Fojt 
1728edacedfSDaniel Fojt static int
ocsp_opt_cert_id_md(int argc,char ** argv,int * argsused)1738edacedfSDaniel Fojt ocsp_opt_cert_id_md(int argc, char **argv, int *argsused)
1748edacedfSDaniel Fojt {
1758edacedfSDaniel Fojt 	char *name = argv[0];
1768edacedfSDaniel Fojt 
1778edacedfSDaniel Fojt 	if (*name++ != '-')
1788edacedfSDaniel Fojt 		return (1);
1798edacedfSDaniel Fojt 
1808edacedfSDaniel Fojt 	if ((ocsp_config.cert_id_md = EVP_get_digestbyname(name)) == NULL)
1818edacedfSDaniel Fojt 		return (1);
1828edacedfSDaniel Fojt 
1838edacedfSDaniel Fojt 	*argsused = 1;
1848edacedfSDaniel Fojt 	return (0);
1858edacedfSDaniel Fojt }
1868edacedfSDaniel Fojt 
1878edacedfSDaniel Fojt static int
ocsp_opt_header(int argc,char ** argv,int * argsused)1888edacedfSDaniel Fojt ocsp_opt_header(int argc, char **argv, int *argsused)
1898edacedfSDaniel Fojt {
1908edacedfSDaniel Fojt 	if (argc < 3 || argv[1] == NULL || argv[2] == NULL)
1918edacedfSDaniel Fojt 		return (1);
1928edacedfSDaniel Fojt 
1938edacedfSDaniel Fojt 	if (!X509V3_add_value(argv[1], argv[2], &ocsp_config.headers)) {
1948edacedfSDaniel Fojt 		ocsp_config.no_usage = 1;
1958edacedfSDaniel Fojt 		return (1);
1968edacedfSDaniel Fojt 	}
1978edacedfSDaniel Fojt 
1988edacedfSDaniel Fojt 	*argsused = 3;
1998edacedfSDaniel Fojt 	return (0);
2008edacedfSDaniel Fojt }
2018edacedfSDaniel Fojt 
2028edacedfSDaniel Fojt static int
ocsp_opt_host(char * arg)2038edacedfSDaniel Fojt ocsp_opt_host(char *arg)
2048edacedfSDaniel Fojt {
2058edacedfSDaniel Fojt 	if (ocsp_config.use_ssl != -1)
2068edacedfSDaniel Fojt 		return (1);
2078edacedfSDaniel Fojt 
2088edacedfSDaniel Fojt 	ocsp_config.host = arg;
2098edacedfSDaniel Fojt 	return (0);
2108edacedfSDaniel Fojt }
2118edacedfSDaniel Fojt 
2128edacedfSDaniel Fojt static int
ocsp_opt_issuer(char * arg)2138edacedfSDaniel Fojt ocsp_opt_issuer(char *arg)
2148edacedfSDaniel Fojt {
2158edacedfSDaniel Fojt 	X509_free(ocsp_config.issuer);
2168edacedfSDaniel Fojt 	ocsp_config.issuer = load_cert(bio_err, arg, FORMAT_PEM, NULL,
2178edacedfSDaniel Fojt 	    "issuer certificate");
2188edacedfSDaniel Fojt 	if (ocsp_config.issuer == NULL) {
2198edacedfSDaniel Fojt 		ocsp_config.no_usage = 1;
2208edacedfSDaniel Fojt 		return (1);
2218edacedfSDaniel Fojt 	}
2228edacedfSDaniel Fojt 	return (0);
2238edacedfSDaniel Fojt }
2248edacedfSDaniel Fojt 
2258edacedfSDaniel Fojt static int
ocsp_opt_ndays(char * arg)2268edacedfSDaniel Fojt ocsp_opt_ndays(char *arg)
2278edacedfSDaniel Fojt {
2288edacedfSDaniel Fojt 	const char *errstr = NULL;
2298edacedfSDaniel Fojt 
2308edacedfSDaniel Fojt 	ocsp_config.ndays = strtonum(arg, 0, INT_MAX, &errstr);
2318edacedfSDaniel Fojt 	if (errstr != NULL) {
2328edacedfSDaniel Fojt 		BIO_printf(bio_err, "Illegal update period %s: %s\n",
2338edacedfSDaniel Fojt 		    arg, errstr);
2348edacedfSDaniel Fojt 		return (1);
2358edacedfSDaniel Fojt 	}
2368edacedfSDaniel Fojt 	return (0);
2378edacedfSDaniel Fojt }
2388edacedfSDaniel Fojt 
2398edacedfSDaniel Fojt static int
ocsp_opt_nmin(char * arg)2408edacedfSDaniel Fojt ocsp_opt_nmin(char *arg)
2418edacedfSDaniel Fojt {
2428edacedfSDaniel Fojt 	const char *errstr = NULL;
2438edacedfSDaniel Fojt 
2448edacedfSDaniel Fojt 	ocsp_config.nmin = strtonum(arg, 0, INT_MAX, &errstr);
2458edacedfSDaniel Fojt 	if (errstr != NULL) {
2468edacedfSDaniel Fojt 		BIO_printf(bio_err, "Illegal update period %s: %s\n",
2478edacedfSDaniel Fojt 		    arg, errstr);
2488edacedfSDaniel Fojt 		return (1);
2498edacedfSDaniel Fojt 	}
2508edacedfSDaniel Fojt 
2518edacedfSDaniel Fojt 	if (ocsp_config.ndays != -1)
2528edacedfSDaniel Fojt 		return (1);
2538edacedfSDaniel Fojt 
2548edacedfSDaniel Fojt 	ocsp_config.ndays = 0;
2558edacedfSDaniel Fojt 	return (0);
2568edacedfSDaniel Fojt }
2578edacedfSDaniel Fojt 
2588edacedfSDaniel Fojt static int
ocsp_opt_nrequest(char * arg)2598edacedfSDaniel Fojt ocsp_opt_nrequest(char *arg)
2608edacedfSDaniel Fojt {
2618edacedfSDaniel Fojt 	const char *errstr = NULL;
2628edacedfSDaniel Fojt 
2638edacedfSDaniel Fojt 	ocsp_config.accept_count = strtonum(arg, 0, INT_MAX, &errstr);
2648edacedfSDaniel Fojt 	if (errstr != NULL) {
2658edacedfSDaniel Fojt 		BIO_printf(bio_err, "Illegal accept count %s: %s\n",
2668edacedfSDaniel Fojt 		    arg, errstr);
2678edacedfSDaniel Fojt 		return (1);
2688edacedfSDaniel Fojt 	}
2698edacedfSDaniel Fojt 	return (0);
2708edacedfSDaniel Fojt }
2718edacedfSDaniel Fojt 
2728edacedfSDaniel Fojt static int
ocsp_opt_port(char * arg)2738edacedfSDaniel Fojt ocsp_opt_port(char *arg)
2748edacedfSDaniel Fojt {
2758edacedfSDaniel Fojt 	if (ocsp_config.use_ssl != -1)
2768edacedfSDaniel Fojt 		return (1);
2778edacedfSDaniel Fojt 
2788edacedfSDaniel Fojt 	ocsp_config.port = arg;
2798edacedfSDaniel Fojt 	return (0);
2808edacedfSDaniel Fojt }
2818edacedfSDaniel Fojt 
2828edacedfSDaniel Fojt static int
ocsp_opt_serial(char * arg)2838edacedfSDaniel Fojt ocsp_opt_serial(char *arg)
2848edacedfSDaniel Fojt {
2858edacedfSDaniel Fojt 	if (ocsp_config.cert_id_md == NULL)
2868edacedfSDaniel Fojt 		ocsp_config.cert_id_md = EVP_sha1();
2878edacedfSDaniel Fojt 	if (!add_ocsp_serial(&ocsp_config.req, arg, ocsp_config.cert_id_md,
2888edacedfSDaniel Fojt 	    ocsp_config.issuer, ocsp_config.ids)) {
2898edacedfSDaniel Fojt 		ocsp_config.no_usage = 1;
2908edacedfSDaniel Fojt 		return (1);
2918edacedfSDaniel Fojt 	}
2928edacedfSDaniel Fojt 	if (!sk_OPENSSL_STRING_push(ocsp_config.reqnames, arg)) {
2938edacedfSDaniel Fojt 		ocsp_config.no_usage = 1;
2948edacedfSDaniel Fojt 		return (1);
2958edacedfSDaniel Fojt 	}
2968edacedfSDaniel Fojt 	return (0);
2978edacedfSDaniel Fojt }
2988edacedfSDaniel Fojt 
2998edacedfSDaniel Fojt static int
ocsp_opt_status_age(char * arg)3008edacedfSDaniel Fojt ocsp_opt_status_age(char *arg)
3018edacedfSDaniel Fojt {
3028edacedfSDaniel Fojt 	const char *errstr = NULL;
3038edacedfSDaniel Fojt 
3048edacedfSDaniel Fojt 	ocsp_config.maxage = strtonum(arg, 0, LONG_MAX, &errstr);
3058edacedfSDaniel Fojt 	if (errstr != NULL) {
3068edacedfSDaniel Fojt 		BIO_printf(bio_err, "Illegal validity age %s: %s\n",
3078edacedfSDaniel Fojt 		    arg, errstr);
3088edacedfSDaniel Fojt 		return (1);
3098edacedfSDaniel Fojt 	}
3108edacedfSDaniel Fojt 	return (0);
3118edacedfSDaniel Fojt }
3128edacedfSDaniel Fojt 
3138edacedfSDaniel Fojt static int
ocsp_opt_text(void)3148edacedfSDaniel Fojt ocsp_opt_text(void)
3158edacedfSDaniel Fojt {
3168edacedfSDaniel Fojt 	ocsp_config.req_text = 1;
3178edacedfSDaniel Fojt 	ocsp_config.resp_text = 1;
3188edacedfSDaniel Fojt 	return (0);
3198edacedfSDaniel Fojt }
3208edacedfSDaniel Fojt 
3218edacedfSDaniel Fojt static int
ocsp_opt_timeout(char * arg)3228edacedfSDaniel Fojt ocsp_opt_timeout(char *arg)
3238edacedfSDaniel Fojt {
3248edacedfSDaniel Fojt 	const char *errstr = NULL;
3258edacedfSDaniel Fojt 
3268edacedfSDaniel Fojt 	ocsp_config.req_timeout = strtonum(arg, 0, INT_MAX, &errstr);
3278edacedfSDaniel Fojt 	if (errstr != NULL) {
3288edacedfSDaniel Fojt 		BIO_printf(bio_err, "Illegal timeout value %s: %s\n",
3298edacedfSDaniel Fojt 		    arg, errstr);
3308edacedfSDaniel Fojt 		return (1);
3318edacedfSDaniel Fojt 	}
3328edacedfSDaniel Fojt 	return (0);
3338edacedfSDaniel Fojt }
3348edacedfSDaniel Fojt 
3358edacedfSDaniel Fojt static int
ocsp_opt_url(char * arg)3368edacedfSDaniel Fojt ocsp_opt_url(char *arg)
3378edacedfSDaniel Fojt {
3388edacedfSDaniel Fojt 	if (ocsp_config.host == NULL && ocsp_config.port == NULL &&
3398edacedfSDaniel Fojt 	    ocsp_config.path == NULL) {
3408edacedfSDaniel Fojt 		if (!OCSP_parse_url(arg, &ocsp_config.host, &ocsp_config.port,
3418edacedfSDaniel Fojt 		    &ocsp_config.path, &ocsp_config.use_ssl)) {
3428edacedfSDaniel Fojt 			BIO_printf(bio_err, "Error parsing URL\n");
3438edacedfSDaniel Fojt 			return (1);
3448edacedfSDaniel Fojt 		}
3458edacedfSDaniel Fojt 	}
3468edacedfSDaniel Fojt 	return (0);
3478edacedfSDaniel Fojt }
3488edacedfSDaniel Fojt 
3498edacedfSDaniel Fojt static int
ocsp_opt_vafile(char * arg)3508edacedfSDaniel Fojt ocsp_opt_vafile(char *arg)
3518edacedfSDaniel Fojt {
3528edacedfSDaniel Fojt 	ocsp_config.verify_certfile = arg;
3538edacedfSDaniel Fojt 	ocsp_config.verify_flags |= OCSP_TRUSTOTHER;
3548edacedfSDaniel Fojt 	return (0);
3558edacedfSDaniel Fojt }
3568edacedfSDaniel Fojt 
3578edacedfSDaniel Fojt static int
ocsp_opt_validity_period(char * arg)3588edacedfSDaniel Fojt ocsp_opt_validity_period(char *arg)
3598edacedfSDaniel Fojt {
3608edacedfSDaniel Fojt 	const char *errstr = NULL;
3618edacedfSDaniel Fojt 
3628edacedfSDaniel Fojt 	ocsp_config.nsec = strtonum(arg, 0, LONG_MAX, &errstr);
3638edacedfSDaniel Fojt 	if (errstr != NULL) {
3648edacedfSDaniel Fojt 		BIO_printf(bio_err, "Illegal validity period %s: %s\n",
3658edacedfSDaniel Fojt 		    arg, errstr);
3668edacedfSDaniel Fojt 		return (1);
3678edacedfSDaniel Fojt 	}
3688edacedfSDaniel Fojt 	return (0);
3698edacedfSDaniel Fojt }
3708edacedfSDaniel Fojt 
3718edacedfSDaniel Fojt static const struct option ocsp_options[] = {
3728edacedfSDaniel Fojt 	{
3738edacedfSDaniel Fojt 		.name = "CA",
3748edacedfSDaniel Fojt 		.argname = "file",
3758edacedfSDaniel Fojt 		.desc = "CA certificate corresponding to the revocation information",
3768edacedfSDaniel Fojt 		.type = OPTION_ARG,
3778edacedfSDaniel Fojt 		.opt.arg = &ocsp_config.rca_filename,
3788edacedfSDaniel Fojt 	},
3798edacedfSDaniel Fojt 	{
3808edacedfSDaniel Fojt 		.name = "CAfile",
3818edacedfSDaniel Fojt 		.argname = "file",
3828edacedfSDaniel Fojt 		.desc = "Trusted certificates file",
3838edacedfSDaniel Fojt 		.type = OPTION_ARG,
3848edacedfSDaniel Fojt 		.opt.arg = &ocsp_config.CAfile,
3858edacedfSDaniel Fojt 	},
3868edacedfSDaniel Fojt 	{
3878edacedfSDaniel Fojt 		.name = "CApath",
3888edacedfSDaniel Fojt 		.argname = "directory",
3898edacedfSDaniel Fojt 		.desc = "Trusted certificates directory",
3908edacedfSDaniel Fojt 		.type = OPTION_ARG,
3918edacedfSDaniel Fojt 		.opt.arg = &ocsp_config.CApath,
3928edacedfSDaniel Fojt 	},
3938edacedfSDaniel Fojt 	{
3948edacedfSDaniel Fojt 		.name = "cert",
3958edacedfSDaniel Fojt 		.argname = "file",
3968edacedfSDaniel Fojt 		.desc = "Certificate to check",
3978edacedfSDaniel Fojt 		.type = OPTION_ARG_FUNC,
3988edacedfSDaniel Fojt 		.opt.argfunc = ocsp_opt_cert,
3998edacedfSDaniel Fojt 	},
4008edacedfSDaniel Fojt 	{
4018edacedfSDaniel Fojt 		.name = "header",
4028edacedfSDaniel Fojt 		.argname = "name value",
4038edacedfSDaniel Fojt 		.desc = "Add the header name with the value to the request",
4048edacedfSDaniel Fojt 		.type = OPTION_ARGV_FUNC,
4058edacedfSDaniel Fojt 		.opt.argvfunc = ocsp_opt_header,
4068edacedfSDaniel Fojt 	},
4078edacedfSDaniel Fojt 	{
4088edacedfSDaniel Fojt 		.name = "host",
4098edacedfSDaniel Fojt 		.argname = "hostname:port",
4108edacedfSDaniel Fojt 		.desc = "Send OCSP request to host on port",
4118edacedfSDaniel Fojt 		.type = OPTION_ARG_FUNC,
4128edacedfSDaniel Fojt 		.opt.argfunc = ocsp_opt_host,
4138edacedfSDaniel Fojt 	},
4148edacedfSDaniel Fojt 	{
4158edacedfSDaniel Fojt 		.name = "ignore_err",
4168edacedfSDaniel Fojt 		.desc = "Ignore the invalid response",
4178edacedfSDaniel Fojt 		.type = OPTION_FLAG,
4188edacedfSDaniel Fojt 		.opt.flag = &ocsp_config.ignore_err,
4198edacedfSDaniel Fojt 	},
4208edacedfSDaniel Fojt 	{
4218edacedfSDaniel Fojt 		.name = "index",
4228edacedfSDaniel Fojt 		.argname = "indexfile",
4238edacedfSDaniel Fojt 		.desc = "Certificate status index file",
4248edacedfSDaniel Fojt 		.type = OPTION_ARG,
4258edacedfSDaniel Fojt 		.opt.arg = &ocsp_config.ridx_filename,
4268edacedfSDaniel Fojt 	},
4278edacedfSDaniel Fojt 	{
4288edacedfSDaniel Fojt 		.name = "issuer",
4298edacedfSDaniel Fojt 		.argname = "file",
4308edacedfSDaniel Fojt 		.desc = "Issuer certificate",
4318edacedfSDaniel Fojt 		.type = OPTION_ARG_FUNC,
4328edacedfSDaniel Fojt 		.opt.argfunc = ocsp_opt_issuer,
4338edacedfSDaniel Fojt 	},
4348edacedfSDaniel Fojt 	{
4358edacedfSDaniel Fojt 		.name = "ndays",
4368edacedfSDaniel Fojt 		.argname = "days",
4378edacedfSDaniel Fojt 		.desc = "Number of days before next update",
4388edacedfSDaniel Fojt 		.type = OPTION_ARG_FUNC,
4398edacedfSDaniel Fojt 		.opt.argfunc = ocsp_opt_ndays,
4408edacedfSDaniel Fojt 	},
4418edacedfSDaniel Fojt 	{
4428edacedfSDaniel Fojt 		.name = "nmin",
4438edacedfSDaniel Fojt 		.argname = "minutes",
4448edacedfSDaniel Fojt 		.desc = "Number of minutes before next update",
4458edacedfSDaniel Fojt 		.type = OPTION_ARG_FUNC,
4468edacedfSDaniel Fojt 		.opt.argfunc = ocsp_opt_nmin,
4478edacedfSDaniel Fojt 	},
4488edacedfSDaniel Fojt 	{
4498edacedfSDaniel Fojt 		.name = "no_cert_checks",
4508edacedfSDaniel Fojt 		.desc = "Don't do additional checks on signing certificate",
4518edacedfSDaniel Fojt 		.type = OPTION_UL_VALUE_OR,
4528edacedfSDaniel Fojt 		.opt.ulvalue = &ocsp_config.verify_flags,
4538edacedfSDaniel Fojt 		.ulvalue = OCSP_NOCHECKS,
4548edacedfSDaniel Fojt 	},
4558edacedfSDaniel Fojt 	{
4568edacedfSDaniel Fojt 		.name = "no_cert_verify",
4578edacedfSDaniel Fojt 		.desc = "Don't check signing certificate",
4588edacedfSDaniel Fojt 		.type = OPTION_UL_VALUE_OR,
4598edacedfSDaniel Fojt 		.opt.ulvalue = &ocsp_config.verify_flags,
4608edacedfSDaniel Fojt 		.ulvalue = OCSP_NOVERIFY,
4618edacedfSDaniel Fojt 	},
4628edacedfSDaniel Fojt 	{
4638edacedfSDaniel Fojt 		.name = "no_certs",
4648edacedfSDaniel Fojt 		.desc = "Don't include any certificates in signed request",
4658edacedfSDaniel Fojt 		.type = OPTION_UL_VALUE_OR,
4668edacedfSDaniel Fojt 		.opt.ulvalue = &ocsp_config.sign_flags,
4678edacedfSDaniel Fojt 		.ulvalue = OCSP_NOCERTS,
4688edacedfSDaniel Fojt 	},
4698edacedfSDaniel Fojt 	{
4708edacedfSDaniel Fojt 		.name = "no_chain",
4718edacedfSDaniel Fojt 		.desc = "Don't use certificates in the response",
4728edacedfSDaniel Fojt 		.type = OPTION_UL_VALUE_OR,
4738edacedfSDaniel Fojt 		.opt.ulvalue = &ocsp_config.verify_flags,
4748edacedfSDaniel Fojt 		.ulvalue = OCSP_NOCHAIN,
4758edacedfSDaniel Fojt 	},
4768edacedfSDaniel Fojt 	{
4778edacedfSDaniel Fojt 		.name = "no_explicit",
4788edacedfSDaniel Fojt 		.desc = "Don't check the explicit trust for OCSP signing",
4798edacedfSDaniel Fojt 		.type = OPTION_UL_VALUE_OR,
4808edacedfSDaniel Fojt 		.opt.ulvalue = &ocsp_config.verify_flags,
4818edacedfSDaniel Fojt 		.ulvalue = OCSP_NOEXPLICIT,
4828edacedfSDaniel Fojt 	},
4838edacedfSDaniel Fojt 	{
4848edacedfSDaniel Fojt 		.name = "no_intern",
4858edacedfSDaniel Fojt 		.desc = "Don't search certificates contained in response for signer",
4868edacedfSDaniel Fojt 		.type = OPTION_UL_VALUE_OR,
4878edacedfSDaniel Fojt 		.opt.ulvalue = &ocsp_config.verify_flags,
4888edacedfSDaniel Fojt 		.ulvalue = OCSP_NOINTERN,
4898edacedfSDaniel Fojt 	},
4908edacedfSDaniel Fojt 	{
4918edacedfSDaniel Fojt 		.name = "no_nonce",
4928edacedfSDaniel Fojt 		.desc = "Don't add OCSP nonce to request",
4938edacedfSDaniel Fojt 		.type = OPTION_VALUE,
4948edacedfSDaniel Fojt 		.opt.value = &ocsp_config.add_nonce,
4958edacedfSDaniel Fojt 		.value = 0,
4968edacedfSDaniel Fojt 	},
4978edacedfSDaniel Fojt 	{
4988edacedfSDaniel Fojt 		.name = "no_signature_verify",
4998edacedfSDaniel Fojt 		.desc = "Don't check signature on response",
5008edacedfSDaniel Fojt 		.type = OPTION_UL_VALUE_OR,
5018edacedfSDaniel Fojt 		.opt.ulvalue = &ocsp_config.verify_flags,
5028edacedfSDaniel Fojt 		.ulvalue = OCSP_NOSIGS,
5038edacedfSDaniel Fojt 	},
5048edacedfSDaniel Fojt 	{
5058edacedfSDaniel Fojt 		.name = "nonce",
5068edacedfSDaniel Fojt 		.desc = "Add OCSP nonce to request",
5078edacedfSDaniel Fojt 		.type = OPTION_VALUE,
5088edacedfSDaniel Fojt 		.opt.value = &ocsp_config.add_nonce,
5098edacedfSDaniel Fojt 		.value = 2,
5108edacedfSDaniel Fojt 	},
5118edacedfSDaniel Fojt 	{
5128edacedfSDaniel Fojt 		.name = "noverify",
5138edacedfSDaniel Fojt 		.desc = "Don't verify response at all",
5148edacedfSDaniel Fojt 		.type = OPTION_FLAG,
5158edacedfSDaniel Fojt 		.opt.flag = &ocsp_config.noverify,
5168edacedfSDaniel Fojt 	},
5178edacedfSDaniel Fojt 	{
5188edacedfSDaniel Fojt 		.name = "nrequest",
5198edacedfSDaniel Fojt 		.argname = "number",
5208edacedfSDaniel Fojt 		.desc = "Number of requests to accept (default unlimited)",
5218edacedfSDaniel Fojt 		.type = OPTION_ARG_FUNC,
5228edacedfSDaniel Fojt 		.opt.argfunc = ocsp_opt_nrequest,
5238edacedfSDaniel Fojt 	},
5248edacedfSDaniel Fojt 	{
5258edacedfSDaniel Fojt 		.name = "out",
5268edacedfSDaniel Fojt 		.argname = "file",
5278edacedfSDaniel Fojt 		.desc = "Output filename",
5288edacedfSDaniel Fojt 		.type = OPTION_ARG,
5298edacedfSDaniel Fojt 		.opt.arg = &ocsp_config.outfile,
5308edacedfSDaniel Fojt 	},
5318edacedfSDaniel Fojt 	{
5328edacedfSDaniel Fojt 		.name = "path",
5338edacedfSDaniel Fojt 		.argname = "path",
5348edacedfSDaniel Fojt 		.desc = "Path to use in OCSP request",
5358edacedfSDaniel Fojt 		.type = OPTION_ARG,
5368edacedfSDaniel Fojt 		.opt.arg = &ocsp_config.path,
5378edacedfSDaniel Fojt 	},
5388edacedfSDaniel Fojt 	{
5398edacedfSDaniel Fojt 		.name = "port",
5408edacedfSDaniel Fojt 		.argname = "portnum",
5418edacedfSDaniel Fojt 		.desc = "Port to run responder on",
5428edacedfSDaniel Fojt 		.type = OPTION_ARG_FUNC,
5438edacedfSDaniel Fojt 		.opt.argfunc = ocsp_opt_port,
5448edacedfSDaniel Fojt 	},
5458edacedfSDaniel Fojt 	{
5468edacedfSDaniel Fojt 		.name = "req_text",
5478edacedfSDaniel Fojt 		.desc = "Print text form of request",
5488edacedfSDaniel Fojt 		.type = OPTION_FLAG,
5498edacedfSDaniel Fojt 		.opt.flag = &ocsp_config.req_text,
5508edacedfSDaniel Fojt 	},
5518edacedfSDaniel Fojt 	{
5528edacedfSDaniel Fojt 		.name = "reqin",
5538edacedfSDaniel Fojt 		.argname = "file",
5548edacedfSDaniel Fojt 		.desc = "Read DER encoded OCSP request from \"file\"",
5558edacedfSDaniel Fojt 		.type = OPTION_ARG,
5568edacedfSDaniel Fojt 		.opt.arg = &ocsp_config.reqin,
5578edacedfSDaniel Fojt 	},
5588edacedfSDaniel Fojt 	{
5598edacedfSDaniel Fojt 		.name = "reqout",
5608edacedfSDaniel Fojt 		.argname = "file",
5618edacedfSDaniel Fojt 		.desc = "Write DER encoded OCSP request to \"file\"",
5628edacedfSDaniel Fojt 		.type = OPTION_ARG,
5638edacedfSDaniel Fojt 		.opt.arg = &ocsp_config.reqout,
5648edacedfSDaniel Fojt 	},
5658edacedfSDaniel Fojt 	{
5668edacedfSDaniel Fojt 		.name = "resp_key_id",
5678edacedfSDaniel Fojt 		.desc = "Identify response by signing certificate key ID",
5688edacedfSDaniel Fojt 		.type = OPTION_UL_VALUE_OR,
5698edacedfSDaniel Fojt 		.opt.ulvalue = &ocsp_config.rflags,
5708edacedfSDaniel Fojt 		.ulvalue = OCSP_RESPID_KEY,
5718edacedfSDaniel Fojt 	},
5728edacedfSDaniel Fojt 	{
5738edacedfSDaniel Fojt 		.name = "resp_no_certs",
5748edacedfSDaniel Fojt 		.desc = "Don't include any certificates in response",
5758edacedfSDaniel Fojt 		.type = OPTION_UL_VALUE_OR,
5768edacedfSDaniel Fojt 		.opt.ulvalue = &ocsp_config.rflags,
5778edacedfSDaniel Fojt 		.ulvalue = OCSP_NOCERTS,
5788edacedfSDaniel Fojt 	},
5798edacedfSDaniel Fojt 	{
5808edacedfSDaniel Fojt 		.name = "resp_text",
5818edacedfSDaniel Fojt 		.desc = "Print text form of response",
5828edacedfSDaniel Fojt 		.type = OPTION_FLAG,
5838edacedfSDaniel Fojt 		.opt.flag = &ocsp_config.resp_text,
5848edacedfSDaniel Fojt 	},
5858edacedfSDaniel Fojt 	{
5868edacedfSDaniel Fojt 		.name = "respin",
5878edacedfSDaniel Fojt 		.argname = "file",
5888edacedfSDaniel Fojt 		.desc = "Read DER encoded OCSP response from \"file\"",
5898edacedfSDaniel Fojt 		.type = OPTION_ARG,
5908edacedfSDaniel Fojt 		.opt.arg = &ocsp_config.respin,
5918edacedfSDaniel Fojt 	},
5928edacedfSDaniel Fojt 	{
5938edacedfSDaniel Fojt 		.name = "respout",
5948edacedfSDaniel Fojt 		.argname = "file",
5958edacedfSDaniel Fojt 		.desc = "Write DER encoded OCSP response to \"file\"",
5968edacedfSDaniel Fojt 		.type = OPTION_ARG,
5978edacedfSDaniel Fojt 		.opt.arg = &ocsp_config.respout,
5988edacedfSDaniel Fojt 	},
5998edacedfSDaniel Fojt 	{
6008edacedfSDaniel Fojt 		.name = "rkey",
6018edacedfSDaniel Fojt 		.argname = "file",
6028edacedfSDaniel Fojt 		.desc = "Responder key to sign responses with",
6038edacedfSDaniel Fojt 		.type = OPTION_ARG,
6048edacedfSDaniel Fojt 		.opt.arg = &ocsp_config.rkeyfile,
6058edacedfSDaniel Fojt 	},
6068edacedfSDaniel Fojt 	{
6078edacedfSDaniel Fojt 		.name = "rother",
6088edacedfSDaniel Fojt 		.argname = "file",
6098edacedfSDaniel Fojt 		.desc = "Other certificates to include in response",
6108edacedfSDaniel Fojt 		.type = OPTION_ARG,
6118edacedfSDaniel Fojt 		.opt.arg = &ocsp_config.rcertfile,
6128edacedfSDaniel Fojt 	},
6138edacedfSDaniel Fojt 	{
6148edacedfSDaniel Fojt 		.name = "rsigner",
6158edacedfSDaniel Fojt 		.argname = "file",
6168edacedfSDaniel Fojt 		.desc = "Responder certificate to sign responses with",
6178edacedfSDaniel Fojt 		.type = OPTION_ARG,
6188edacedfSDaniel Fojt 		.opt.arg = &ocsp_config.rsignfile,
6198edacedfSDaniel Fojt 	},
6208edacedfSDaniel Fojt 	{
6218edacedfSDaniel Fojt 		.name = "serial",
6228edacedfSDaniel Fojt 		.argname = "num",
6238edacedfSDaniel Fojt 		.desc = "Serial number to check",
6248edacedfSDaniel Fojt 		.type = OPTION_ARG_FUNC,
6258edacedfSDaniel Fojt 		.opt.argfunc = ocsp_opt_serial,
6268edacedfSDaniel Fojt 	},
6278edacedfSDaniel Fojt 	{
6288edacedfSDaniel Fojt 		.name = "sign_other",
6298edacedfSDaniel Fojt 		.argname = "file",
6308edacedfSDaniel Fojt 		.desc = "Additional certificates to include in signed request",
6318edacedfSDaniel Fojt 		.type = OPTION_ARG,
6328edacedfSDaniel Fojt 		.opt.arg = &ocsp_config.sign_certfile,
6338edacedfSDaniel Fojt 	},
6348edacedfSDaniel Fojt 	{
6358edacedfSDaniel Fojt 		.name = "signer",
6368edacedfSDaniel Fojt 		.argname = "file",
6378edacedfSDaniel Fojt 		.desc = "Certificate to sign OCSP request with",
6388edacedfSDaniel Fojt 		.type = OPTION_ARG,
6398edacedfSDaniel Fojt 		.opt.arg = &ocsp_config.signfile,
6408edacedfSDaniel Fojt 	},
6418edacedfSDaniel Fojt 	{
6428edacedfSDaniel Fojt 		.name = "signkey",
6438edacedfSDaniel Fojt 		.argname = "file",
6448edacedfSDaniel Fojt 		.desc = "Private key to sign OCSP request with",
6458edacedfSDaniel Fojt 		.type = OPTION_ARG,
6468edacedfSDaniel Fojt 		.opt.arg = &ocsp_config.keyfile,
6478edacedfSDaniel Fojt 	},
6488edacedfSDaniel Fojt 	{
6498edacedfSDaniel Fojt 		.name = "status_age",
6508edacedfSDaniel Fojt 		.argname = "age",
6518edacedfSDaniel Fojt 		.desc = "Maximum status age in seconds",
6528edacedfSDaniel Fojt 		.type = OPTION_ARG_FUNC,
6538edacedfSDaniel Fojt 		.opt.argfunc = ocsp_opt_status_age,
6548edacedfSDaniel Fojt 	},
6558edacedfSDaniel Fojt 	{
6568edacedfSDaniel Fojt 		.name = "text",
6578edacedfSDaniel Fojt 		.desc = "Print text form of request and response",
6588edacedfSDaniel Fojt 		.type = OPTION_FUNC,
6598edacedfSDaniel Fojt 		.opt.func = ocsp_opt_text,
6608edacedfSDaniel Fojt 	},
6618edacedfSDaniel Fojt 	{
6628edacedfSDaniel Fojt 		.name = "timeout",
6638edacedfSDaniel Fojt 		.argname = "seconds",
6648edacedfSDaniel Fojt 		.desc = "Connection timeout to the OCSP responder in seconds",
6658edacedfSDaniel Fojt 		.type = OPTION_ARG_FUNC,
6668edacedfSDaniel Fojt 		.opt.argfunc = ocsp_opt_timeout,
6678edacedfSDaniel Fojt 	},
6688edacedfSDaniel Fojt 	{
6698edacedfSDaniel Fojt 		.name = "trust_other",
6708edacedfSDaniel Fojt 		.desc = "Don't verify additional certificates",
6718edacedfSDaniel Fojt 		.type = OPTION_UL_VALUE_OR,
6728edacedfSDaniel Fojt 		.opt.ulvalue = &ocsp_config.verify_flags,
6738edacedfSDaniel Fojt 		.ulvalue = OCSP_TRUSTOTHER,
6748edacedfSDaniel Fojt 	},
6758edacedfSDaniel Fojt 	{
6768edacedfSDaniel Fojt 		.name = "url",
6778edacedfSDaniel Fojt 		.argname = "responder_url",
6788edacedfSDaniel Fojt 		.desc = "OCSP responder URL",
6798edacedfSDaniel Fojt 		.type = OPTION_ARG_FUNC,
6808edacedfSDaniel Fojt 		.opt.argfunc = ocsp_opt_url,
6818edacedfSDaniel Fojt 	},
6828edacedfSDaniel Fojt 	{
6838edacedfSDaniel Fojt 		.name = "VAfile",
6848edacedfSDaniel Fojt 		.argname = "file",
6858edacedfSDaniel Fojt 		.desc = "Explicitly trusted responder certificates",
6868edacedfSDaniel Fojt 		.type = OPTION_ARG_FUNC,
6878edacedfSDaniel Fojt 		.opt.argfunc = ocsp_opt_vafile,
6888edacedfSDaniel Fojt 	},
6898edacedfSDaniel Fojt 	{
6908edacedfSDaniel Fojt 		.name = "validity_period",
6918edacedfSDaniel Fojt 		.argname = "n",
6928edacedfSDaniel Fojt 		.desc = "Maximum validity discrepancy in seconds",
6938edacedfSDaniel Fojt 		.type = OPTION_ARG_FUNC,
6948edacedfSDaniel Fojt 		.opt.argfunc = ocsp_opt_validity_period,
6958edacedfSDaniel Fojt 	},
6968edacedfSDaniel Fojt 	{
6978edacedfSDaniel Fojt 		.name = "verify_other",
6988edacedfSDaniel Fojt 		.argname = "file",
6998edacedfSDaniel Fojt 		.desc = "Additional certificates to search for signer",
7008edacedfSDaniel Fojt 		.type = OPTION_ARG,
7018edacedfSDaniel Fojt 		.opt.arg = &ocsp_config.verify_certfile,
7028edacedfSDaniel Fojt 	},
7038edacedfSDaniel Fojt 	{
7048edacedfSDaniel Fojt 		.name = NULL,
7058edacedfSDaniel Fojt 		.desc = "",
7068edacedfSDaniel Fojt 		.type = OPTION_ARGV_FUNC,
7078edacedfSDaniel Fojt 		.opt.argvfunc = ocsp_opt_cert_id_md,
7088edacedfSDaniel Fojt 	},
7098edacedfSDaniel Fojt 	{ NULL },
7108edacedfSDaniel Fojt };
7118edacedfSDaniel Fojt 
7128edacedfSDaniel Fojt static void
ocsp_usage(void)7138edacedfSDaniel Fojt ocsp_usage(void)
7148edacedfSDaniel Fojt {
7158edacedfSDaniel Fojt 	fprintf(stderr, "usage: ocsp "
7168edacedfSDaniel Fojt 	    "[-CA file] [-CAfile file] [-CApath directory] [-cert file]\n"
7178edacedfSDaniel Fojt 	    "    [-dgst alg] [-header name value] [-host hostname:port]\n"
7188edacedfSDaniel Fojt 	    "    [-ignore_err] [-index indexfile] [-issuer file]\n"
7198edacedfSDaniel Fojt 	    "    [-ndays days] [-nmin minutes] [-no_cert_checks]\n"
7208edacedfSDaniel Fojt 	    "    [-no_cert_verify] [-no_certs] [-no_chain] [-no_explicit]\n"
7218edacedfSDaniel Fojt 	    "    [-no_intern] [-no_nonce] [-no_signature_verify] [-nonce]\n"
7228edacedfSDaniel Fojt 	    "    [-noverify] [-nrequest number] [-out file] [-path path]\n"
7238edacedfSDaniel Fojt 	    "    [-port portnum] [-req_text] [-reqin file] [-reqout file]\n"
7248edacedfSDaniel Fojt 	    "    [-resp_key_id] [-resp_no_certs] [-resp_text] [-respin file]\n"
7258edacedfSDaniel Fojt 	    "    [-respout file] [-rkey file] [-rother file] [-rsigner file]\n"
7268edacedfSDaniel Fojt 	    "    [-serial num] [-sign_other file] [-signer file]\n"
7278edacedfSDaniel Fojt 	    "    [-signkey file] [-status_age age] [-text]\n"
7288edacedfSDaniel Fojt 	    "    [-timeout seconds] [-trust_other] [-url responder_url]\n"
7298edacedfSDaniel Fojt 	    "    [-VAfile file] [-validity_period nsec] [-verify_other file]\n");
7308edacedfSDaniel Fojt 	fprintf(stderr, "\n");
7318edacedfSDaniel Fojt 	options_usage(ocsp_options);
7328edacedfSDaniel Fojt 	fprintf(stderr, "\n");
7338edacedfSDaniel Fojt }
734f5b1c8a1SJohn Marino 
735f5b1c8a1SJohn Marino int
ocsp_main(int argc,char ** argv)736f5b1c8a1SJohn Marino ocsp_main(int argc, char **argv)
737f5b1c8a1SJohn Marino {
738f5b1c8a1SJohn Marino 	OCSP_RESPONSE *resp = NULL;
739f5b1c8a1SJohn Marino 	OCSP_BASICRESP *bs = NULL;
740f5b1c8a1SJohn Marino 	X509 *signer = NULL, *rsigner = NULL;
741f5b1c8a1SJohn Marino 	EVP_PKEY *key = NULL, *rkey = NULL;
742f5b1c8a1SJohn Marino 	BIO *acbio = NULL, *cbio = NULL;
743f5b1c8a1SJohn Marino 	BIO *derbio = NULL;
744f5b1c8a1SJohn Marino 	BIO *out = NULL;
745f5b1c8a1SJohn Marino 	X509_STORE *store = NULL;
746f5b1c8a1SJohn Marino 	STACK_OF(X509) *sign_other = NULL, *verify_other = NULL, *rother = NULL;
747f5b1c8a1SJohn Marino 	int ret = 1;
748f5b1c8a1SJohn Marino 	int badarg = 0;
749f5b1c8a1SJohn Marino 	int i;
750f5b1c8a1SJohn Marino 	X509 *rca_cert = NULL;
751f5b1c8a1SJohn Marino 	CA_DB *rdb = NULL;
752f5b1c8a1SJohn Marino 
753f5b1c8a1SJohn Marino 	if (single_execution) {
75472c33676SMaxim Ag 		if (pledge("stdio cpath wpath rpath inet dns tty", NULL) == -1) {
755f5b1c8a1SJohn Marino 			perror("pledge");
756f5b1c8a1SJohn Marino 			exit(1);
757f5b1c8a1SJohn Marino 		}
758f5b1c8a1SJohn Marino 	}
759f5b1c8a1SJohn Marino 
7608edacedfSDaniel Fojt 	memset(&ocsp_config, 0, sizeof(ocsp_config));
7618edacedfSDaniel Fojt 	ocsp_config.accept_count = -1;
7628edacedfSDaniel Fojt 	ocsp_config.add_nonce = 1;
7638edacedfSDaniel Fojt 	if ((ocsp_config.ids = sk_OCSP_CERTID_new_null()) == NULL)
764f5b1c8a1SJohn Marino 		goto end;
7658edacedfSDaniel Fojt 	ocsp_config.maxage = -1;
7668edacedfSDaniel Fojt 	ocsp_config.ndays = -1;
7678edacedfSDaniel Fojt 	ocsp_config.nsec = MAX_VALIDITY_PERIOD;
7688edacedfSDaniel Fojt 	ocsp_config.req_timeout = -1;
7698edacedfSDaniel Fojt 	if ((ocsp_config.reqnames = sk_OPENSSL_STRING_new_null()) == NULL)
770f5b1c8a1SJohn Marino 		goto end;
7718edacedfSDaniel Fojt 	ocsp_config.use_ssl = -1;
7728edacedfSDaniel Fojt 
7738edacedfSDaniel Fojt 	if (options_parse(argc, argv, ocsp_options, NULL, NULL) != 0) {
7748edacedfSDaniel Fojt 		if (ocsp_config.no_usage)
775f5b1c8a1SJohn Marino 			goto end;
776f5b1c8a1SJohn Marino 		else
777f5b1c8a1SJohn Marino 			badarg = 1;
778f5b1c8a1SJohn Marino 	}
779f5b1c8a1SJohn Marino 
780f5b1c8a1SJohn Marino 	/* Have we anything to do? */
7818edacedfSDaniel Fojt 	if (!ocsp_config.req && !ocsp_config.reqin && !ocsp_config.respin &&
7828edacedfSDaniel Fojt 	    !(ocsp_config.port && ocsp_config.ridx_filename))
783f5b1c8a1SJohn Marino 		badarg = 1;
784f5b1c8a1SJohn Marino 
785f5b1c8a1SJohn Marino 	if (badarg) {
7868edacedfSDaniel Fojt 		ocsp_usage();
787f5b1c8a1SJohn Marino 		goto end;
788f5b1c8a1SJohn Marino 	}
7898edacedfSDaniel Fojt 	if (ocsp_config.outfile)
7908edacedfSDaniel Fojt 		out = BIO_new_file(ocsp_config.outfile, "w");
791f5b1c8a1SJohn Marino 	else
792f5b1c8a1SJohn Marino 		out = BIO_new_fp(stdout, BIO_NOCLOSE);
793f5b1c8a1SJohn Marino 
794f5b1c8a1SJohn Marino 	if (!out) {
795f5b1c8a1SJohn Marino 		BIO_printf(bio_err, "Error opening output file\n");
796f5b1c8a1SJohn Marino 		goto end;
797f5b1c8a1SJohn Marino 	}
7988edacedfSDaniel Fojt 	if (!ocsp_config.req && (ocsp_config.add_nonce != 2))
7998edacedfSDaniel Fojt 		ocsp_config.add_nonce = 0;
800f5b1c8a1SJohn Marino 
8018edacedfSDaniel Fojt 	if (!ocsp_config.req && ocsp_config.reqin) {
8028edacedfSDaniel Fojt 		derbio = BIO_new_file(ocsp_config.reqin, "rb");
803f5b1c8a1SJohn Marino 		if (!derbio) {
8048edacedfSDaniel Fojt 			BIO_printf(bio_err,
8058edacedfSDaniel Fojt 			    "Error Opening OCSP request file\n");
806f5b1c8a1SJohn Marino 			goto end;
807f5b1c8a1SJohn Marino 		}
8088edacedfSDaniel Fojt 		ocsp_config.req = d2i_OCSP_REQUEST_bio(derbio, NULL);
809f5b1c8a1SJohn Marino 		BIO_free(derbio);
8108edacedfSDaniel Fojt 		if (!ocsp_config.req) {
811f5b1c8a1SJohn Marino 			BIO_printf(bio_err, "Error reading OCSP request\n");
812f5b1c8a1SJohn Marino 			goto end;
813f5b1c8a1SJohn Marino 		}
814f5b1c8a1SJohn Marino 	}
8158edacedfSDaniel Fojt 	if (!ocsp_config.req && ocsp_config.port) {
8168edacedfSDaniel Fojt 		acbio = init_responder(ocsp_config.port);
817f5b1c8a1SJohn Marino 		if (!acbio)
818f5b1c8a1SJohn Marino 			goto end;
819f5b1c8a1SJohn Marino 	}
8208edacedfSDaniel Fojt 	if (ocsp_config.rsignfile && !rdb) {
8218edacedfSDaniel Fojt 		if (!ocsp_config.rkeyfile)
8228edacedfSDaniel Fojt 			ocsp_config.rkeyfile = ocsp_config.rsignfile;
8238edacedfSDaniel Fojt 		rsigner = load_cert(bio_err, ocsp_config.rsignfile, FORMAT_PEM,
824f5b1c8a1SJohn Marino 		    NULL, "responder certificate");
825f5b1c8a1SJohn Marino 		if (!rsigner) {
8268edacedfSDaniel Fojt 			BIO_printf(bio_err,
8278edacedfSDaniel Fojt 			    "Error loading responder certificate\n");
828f5b1c8a1SJohn Marino 			goto end;
829f5b1c8a1SJohn Marino 		}
8308edacedfSDaniel Fojt 		rca_cert = load_cert(bio_err, ocsp_config.rca_filename,
8318edacedfSDaniel Fojt 		    FORMAT_PEM, NULL, "CA certificate");
8328edacedfSDaniel Fojt 		if (ocsp_config.rcertfile) {
8338edacedfSDaniel Fojt 			rother = load_certs(bio_err, ocsp_config.rcertfile,
8348edacedfSDaniel Fojt 			    FORMAT_PEM, NULL, "responder other certificates");
835f5b1c8a1SJohn Marino 			if (!rother)
836f5b1c8a1SJohn Marino 				goto end;
837f5b1c8a1SJohn Marino 		}
8388edacedfSDaniel Fojt 		rkey = load_key(bio_err, ocsp_config.rkeyfile, FORMAT_PEM, 0,
8398edacedfSDaniel Fojt 		    NULL, "responder private key");
840f5b1c8a1SJohn Marino 		if (!rkey)
841f5b1c8a1SJohn Marino 			goto end;
842f5b1c8a1SJohn Marino 	}
843f5b1c8a1SJohn Marino 	if (acbio)
844f5b1c8a1SJohn Marino 		BIO_printf(bio_err, "Waiting for OCSP client connections...\n");
845f5b1c8a1SJohn Marino 
846f5b1c8a1SJohn Marino  redo_accept:
847f5b1c8a1SJohn Marino 
848f5b1c8a1SJohn Marino 	if (acbio) {
8498edacedfSDaniel Fojt 		if (!do_responder(&ocsp_config.req, &cbio, acbio,
8508edacedfSDaniel Fojt 		    ocsp_config.port))
851f5b1c8a1SJohn Marino 			goto end;
8528edacedfSDaniel Fojt 		if (!ocsp_config.req) {
8538edacedfSDaniel Fojt 			resp = OCSP_response_create(
8548edacedfSDaniel Fojt 			    OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, NULL);
855f5b1c8a1SJohn Marino 			send_ocsp_response(cbio, resp);
856f5b1c8a1SJohn Marino 			goto done_resp;
857f5b1c8a1SJohn Marino 		}
858f5b1c8a1SJohn Marino 	}
8598edacedfSDaniel Fojt 	if (!ocsp_config.req &&
8608edacedfSDaniel Fojt 	    (ocsp_config.signfile || ocsp_config.reqout || ocsp_config.host ||
8618edacedfSDaniel Fojt 	    ocsp_config.add_nonce || ocsp_config.ridx_filename)) {
8628edacedfSDaniel Fojt 		BIO_printf(bio_err,
8638edacedfSDaniel Fojt 		    "Need an OCSP request for this operation!\n");
864f5b1c8a1SJohn Marino 		goto end;
865f5b1c8a1SJohn Marino 	}
8668edacedfSDaniel Fojt 	if (ocsp_config.req && ocsp_config.add_nonce)
8678edacedfSDaniel Fojt 		OCSP_request_add1_nonce(ocsp_config.req, NULL, -1);
868f5b1c8a1SJohn Marino 
8698edacedfSDaniel Fojt 	if (ocsp_config.signfile) {
8708edacedfSDaniel Fojt 		if (!ocsp_config.keyfile)
8718edacedfSDaniel Fojt 			ocsp_config.keyfile = ocsp_config.signfile;
8728edacedfSDaniel Fojt 		signer = load_cert(bio_err, ocsp_config.signfile, FORMAT_PEM,
873f5b1c8a1SJohn Marino 		    NULL, "signer certificate");
874f5b1c8a1SJohn Marino 		if (!signer) {
8758edacedfSDaniel Fojt 			BIO_printf(bio_err,
8768edacedfSDaniel Fojt 			    "Error loading signer certificate\n");
877f5b1c8a1SJohn Marino 			goto end;
878f5b1c8a1SJohn Marino 		}
8798edacedfSDaniel Fojt 		if (ocsp_config.sign_certfile) {
8808edacedfSDaniel Fojt 			sign_other = load_certs(bio_err,
8818edacedfSDaniel Fojt 			    ocsp_config.sign_certfile, FORMAT_PEM, NULL,
8828edacedfSDaniel Fojt 			    "signer certificates");
883f5b1c8a1SJohn Marino 			if (!sign_other)
884f5b1c8a1SJohn Marino 				goto end;
885f5b1c8a1SJohn Marino 		}
8868edacedfSDaniel Fojt 		key = load_key(bio_err, ocsp_config.keyfile, FORMAT_PEM, 0,
8878edacedfSDaniel Fojt 		    NULL, "signer private key");
888f5b1c8a1SJohn Marino 		if (!key)
889f5b1c8a1SJohn Marino 			goto end;
890f5b1c8a1SJohn Marino 
8918edacedfSDaniel Fojt 		if (!OCSP_request_sign(ocsp_config.req, signer, key, NULL,
8928edacedfSDaniel Fojt 		    sign_other, ocsp_config.sign_flags)) {
893f5b1c8a1SJohn Marino 			BIO_printf(bio_err, "Error signing OCSP request\n");
894f5b1c8a1SJohn Marino 			goto end;
895f5b1c8a1SJohn Marino 		}
896f5b1c8a1SJohn Marino 	}
8978edacedfSDaniel Fojt 	if (ocsp_config.req_text && ocsp_config.req)
8988edacedfSDaniel Fojt 		OCSP_REQUEST_print(out, ocsp_config.req, 0);
899f5b1c8a1SJohn Marino 
9008edacedfSDaniel Fojt 	if (ocsp_config.reqout) {
9018edacedfSDaniel Fojt 		derbio = BIO_new_file(ocsp_config.reqout, "wb");
902f5b1c8a1SJohn Marino 		if (!derbio) {
9038edacedfSDaniel Fojt 			BIO_printf(bio_err, "Error opening file %s\n",
9048edacedfSDaniel Fojt 			    ocsp_config.reqout);
905f5b1c8a1SJohn Marino 			goto end;
906f5b1c8a1SJohn Marino 		}
9078edacedfSDaniel Fojt 		i2d_OCSP_REQUEST_bio(derbio, ocsp_config.req);
908f5b1c8a1SJohn Marino 		BIO_free(derbio);
909f5b1c8a1SJohn Marino 	}
9108edacedfSDaniel Fojt 	if (ocsp_config.ridx_filename && (!rkey || !rsigner || !rca_cert)) {
9118edacedfSDaniel Fojt 		BIO_printf(bio_err,
9128edacedfSDaniel Fojt 		    "Need a responder certificate, key and CA for this operation!\n");
913f5b1c8a1SJohn Marino 		goto end;
914f5b1c8a1SJohn Marino 	}
9158edacedfSDaniel Fojt 	if (ocsp_config.ridx_filename && !rdb) {
9168edacedfSDaniel Fojt 		rdb = load_index(ocsp_config.ridx_filename, NULL);
917f5b1c8a1SJohn Marino 		if (!rdb)
918f5b1c8a1SJohn Marino 			goto end;
919f5b1c8a1SJohn Marino 		if (!index_index(rdb))
920f5b1c8a1SJohn Marino 			goto end;
921f5b1c8a1SJohn Marino 	}
922f5b1c8a1SJohn Marino 	if (rdb) {
9238edacedfSDaniel Fojt 		i = make_ocsp_response(&resp, ocsp_config.req, rdb, rca_cert,
9248edacedfSDaniel Fojt 		    rsigner, rkey, rother, ocsp_config.rflags,
9258edacedfSDaniel Fojt 		    ocsp_config.nmin, ocsp_config.ndays);
926f5b1c8a1SJohn Marino 		if (cbio)
927f5b1c8a1SJohn Marino 			send_ocsp_response(cbio, resp);
9288edacedfSDaniel Fojt 	} else if (ocsp_config.host) {
9298edacedfSDaniel Fojt 		resp = process_responder(bio_err, ocsp_config.req,
9308edacedfSDaniel Fojt 		    ocsp_config.host,
9318edacedfSDaniel Fojt 		    ocsp_config.path ? ocsp_config.path : "/",
9328edacedfSDaniel Fojt 		    ocsp_config.port, ocsp_config.use_ssl, ocsp_config.headers,
9338edacedfSDaniel Fojt 		    ocsp_config.req_timeout);
934f5b1c8a1SJohn Marino 		if (!resp)
935f5b1c8a1SJohn Marino 			goto end;
9368edacedfSDaniel Fojt 	} else if (ocsp_config.respin) {
9378edacedfSDaniel Fojt 		derbio = BIO_new_file(ocsp_config.respin, "rb");
938f5b1c8a1SJohn Marino 		if (!derbio) {
9398edacedfSDaniel Fojt 			BIO_printf(bio_err,
9408edacedfSDaniel Fojt 			    "Error Opening OCSP response file\n");
941f5b1c8a1SJohn Marino 			goto end;
942f5b1c8a1SJohn Marino 		}
943f5b1c8a1SJohn Marino 		resp = d2i_OCSP_RESPONSE_bio(derbio, NULL);
944f5b1c8a1SJohn Marino 		BIO_free(derbio);
945f5b1c8a1SJohn Marino 		if (!resp) {
946f5b1c8a1SJohn Marino 			BIO_printf(bio_err, "Error reading OCSP response\n");
947f5b1c8a1SJohn Marino 			goto end;
948f5b1c8a1SJohn Marino 		}
949f5b1c8a1SJohn Marino 	} else {
950f5b1c8a1SJohn Marino 		ret = 0;
951f5b1c8a1SJohn Marino 		goto end;
952f5b1c8a1SJohn Marino 	}
953f5b1c8a1SJohn Marino 
954f5b1c8a1SJohn Marino  done_resp:
955f5b1c8a1SJohn Marino 
9568edacedfSDaniel Fojt 	if (ocsp_config.respout) {
9578edacedfSDaniel Fojt 		derbio = BIO_new_file(ocsp_config.respout, "wb");
958f5b1c8a1SJohn Marino 		if (!derbio) {
9598edacedfSDaniel Fojt 			BIO_printf(bio_err, "Error opening file %s\n",
9608edacedfSDaniel Fojt 			    ocsp_config.respout);
961f5b1c8a1SJohn Marino 			goto end;
962f5b1c8a1SJohn Marino 		}
963f5b1c8a1SJohn Marino 		i2d_OCSP_RESPONSE_bio(derbio, resp);
964f5b1c8a1SJohn Marino 		BIO_free(derbio);
965f5b1c8a1SJohn Marino 	}
966f5b1c8a1SJohn Marino 	i = OCSP_response_status(resp);
967f5b1c8a1SJohn Marino 
968f5b1c8a1SJohn Marino 	if (i != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
96972c33676SMaxim Ag 		BIO_printf(bio_err, "Responder Error: %s (%d)\n",
970f5b1c8a1SJohn Marino 		    OCSP_response_status_str(i), i);
9718edacedfSDaniel Fojt 		if (ocsp_config.ignore_err)
972f5b1c8a1SJohn Marino 			goto redo_accept;
97372c33676SMaxim Ag 		ret = 1;
974f5b1c8a1SJohn Marino 		goto end;
975f5b1c8a1SJohn Marino 	}
9768edacedfSDaniel Fojt 	if (ocsp_config.resp_text)
977f5b1c8a1SJohn Marino 		OCSP_RESPONSE_print(out, resp, 0);
978f5b1c8a1SJohn Marino 
979f5b1c8a1SJohn Marino 	/* If running as responder don't verify our own response */
980f5b1c8a1SJohn Marino 	if (cbio) {
9818edacedfSDaniel Fojt 		if (ocsp_config.accept_count > 0)
9828edacedfSDaniel Fojt 			ocsp_config.accept_count--;
983f5b1c8a1SJohn Marino 		/* Redo if more connections needed */
9848edacedfSDaniel Fojt 		if (ocsp_config.accept_count) {
985f5b1c8a1SJohn Marino 			BIO_free_all(cbio);
986f5b1c8a1SJohn Marino 			cbio = NULL;
9878edacedfSDaniel Fojt 			OCSP_REQUEST_free(ocsp_config.req);
9888edacedfSDaniel Fojt 			ocsp_config.req = NULL;
989f5b1c8a1SJohn Marino 			OCSP_RESPONSE_free(resp);
990f5b1c8a1SJohn Marino 			resp = NULL;
991f5b1c8a1SJohn Marino 			goto redo_accept;
992f5b1c8a1SJohn Marino 		}
993f5b1c8a1SJohn Marino 		goto end;
994f5b1c8a1SJohn Marino 	}
995f5b1c8a1SJohn Marino 	if (!store)
9968edacedfSDaniel Fojt 		store = setup_verify(bio_err, ocsp_config.CAfile,
9978edacedfSDaniel Fojt 		    ocsp_config.CApath);
998f5b1c8a1SJohn Marino 	if (!store)
999f5b1c8a1SJohn Marino 		goto end;
10008edacedfSDaniel Fojt 	if (ocsp_config.verify_certfile) {
10018edacedfSDaniel Fojt 		verify_other = load_certs(bio_err, ocsp_config.verify_certfile,
10028edacedfSDaniel Fojt 		    FORMAT_PEM, NULL, "validator certificate");
1003f5b1c8a1SJohn Marino 		if (!verify_other)
1004f5b1c8a1SJohn Marino 			goto end;
1005f5b1c8a1SJohn Marino 	}
1006f5b1c8a1SJohn Marino 	bs = OCSP_response_get1_basic(resp);
1007f5b1c8a1SJohn Marino 
1008f5b1c8a1SJohn Marino 	if (!bs) {
1009f5b1c8a1SJohn Marino 		BIO_printf(bio_err, "Error parsing response\n");
1010f5b1c8a1SJohn Marino 		goto end;
1011f5b1c8a1SJohn Marino 	}
10128edacedfSDaniel Fojt 	if (!ocsp_config.noverify) {
10138edacedfSDaniel Fojt 		if (ocsp_config.req &&
10148edacedfSDaniel Fojt 		    ((i = OCSP_check_nonce(ocsp_config.req, bs)) <= 0)) {
10158edacedfSDaniel Fojt 			if (i == -1) {
10168edacedfSDaniel Fojt 				BIO_printf(bio_err,
10178edacedfSDaniel Fojt 				    "WARNING: no nonce in response\n");
10188edacedfSDaniel Fojt 			} else {
1019f5b1c8a1SJohn Marino 				BIO_printf(bio_err, "Nonce Verify error\n");
1020f5b1c8a1SJohn Marino 				goto end;
1021f5b1c8a1SJohn Marino 			}
1022f5b1c8a1SJohn Marino 		}
10238edacedfSDaniel Fojt 		i = OCSP_basic_verify(bs, verify_other, store,
10248edacedfSDaniel Fojt 		    ocsp_config.verify_flags);
1025f5b1c8a1SJohn Marino 		if (i < 0)
1026f5b1c8a1SJohn Marino 			i = OCSP_basic_verify(bs, NULL, store, 0);
1027f5b1c8a1SJohn Marino 
1028f5b1c8a1SJohn Marino 		if (i <= 0) {
1029f5b1c8a1SJohn Marino 			BIO_printf(bio_err, "Response Verify Failure\n");
1030f5b1c8a1SJohn Marino 			ERR_print_errors(bio_err);
10318edacedfSDaniel Fojt 		} else {
1032f5b1c8a1SJohn Marino 			BIO_printf(bio_err, "Response verify OK\n");
1033f5b1c8a1SJohn Marino 		}
10348edacedfSDaniel Fojt 	}
10358edacedfSDaniel Fojt 	if (!print_ocsp_summary(out, bs, ocsp_config.req, ocsp_config.reqnames,
10368edacedfSDaniel Fojt 	    ocsp_config.ids, ocsp_config.nsec, ocsp_config.maxage))
1037f5b1c8a1SJohn Marino 		goto end;
1038f5b1c8a1SJohn Marino 
1039f5b1c8a1SJohn Marino 	ret = 0;
1040f5b1c8a1SJohn Marino 
1041f5b1c8a1SJohn Marino  end:
1042f5b1c8a1SJohn Marino 	ERR_print_errors(bio_err);
1043f5b1c8a1SJohn Marino 	X509_free(signer);
1044f5b1c8a1SJohn Marino 	X509_STORE_free(store);
1045f5b1c8a1SJohn Marino 	EVP_PKEY_free(key);
1046f5b1c8a1SJohn Marino 	EVP_PKEY_free(rkey);
10478edacedfSDaniel Fojt 	X509_free(ocsp_config.issuer);
10488edacedfSDaniel Fojt 	X509_free(ocsp_config.cert);
1049f5b1c8a1SJohn Marino 	X509_free(rsigner);
1050f5b1c8a1SJohn Marino 	X509_free(rca_cert);
1051f5b1c8a1SJohn Marino 	free_index(rdb);
1052f5b1c8a1SJohn Marino 	BIO_free_all(cbio);
1053f5b1c8a1SJohn Marino 	BIO_free_all(acbio);
1054f5b1c8a1SJohn Marino 	BIO_free(out);
10558edacedfSDaniel Fojt 	OCSP_REQUEST_free(ocsp_config.req);
1056f5b1c8a1SJohn Marino 	OCSP_RESPONSE_free(resp);
1057f5b1c8a1SJohn Marino 	OCSP_BASICRESP_free(bs);
10588edacedfSDaniel Fojt 	sk_OPENSSL_STRING_free(ocsp_config.reqnames);
10598edacedfSDaniel Fojt 	sk_OCSP_CERTID_free(ocsp_config.ids);
1060f5b1c8a1SJohn Marino 	sk_X509_pop_free(sign_other, X509_free);
1061f5b1c8a1SJohn Marino 	sk_X509_pop_free(verify_other, X509_free);
10628edacedfSDaniel Fojt 	sk_CONF_VALUE_pop_free(ocsp_config.headers, X509V3_conf_free);
1063f5b1c8a1SJohn Marino 
10648edacedfSDaniel Fojt 	if (ocsp_config.use_ssl != -1) {
10658edacedfSDaniel Fojt 		free(ocsp_config.host);
10668edacedfSDaniel Fojt 		free(ocsp_config.port);
10678edacedfSDaniel Fojt 		free(ocsp_config.path);
1068f5b1c8a1SJohn Marino 	}
1069f5b1c8a1SJohn Marino 	return (ret);
1070f5b1c8a1SJohn Marino }
1071f5b1c8a1SJohn Marino 
1072f5b1c8a1SJohn Marino static int
add_ocsp_cert(OCSP_REQUEST ** req,X509 * cert,const EVP_MD * cert_id_md,X509 * issuer,STACK_OF (OCSP_CERTID)* ids)10738edacedfSDaniel Fojt add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, const EVP_MD *cert_id_md,
10748edacedfSDaniel Fojt     X509 *issuer, STACK_OF(OCSP_CERTID) *ids)
1075f5b1c8a1SJohn Marino {
1076f5b1c8a1SJohn Marino 	OCSP_CERTID *id;
10778edacedfSDaniel Fojt 
1078f5b1c8a1SJohn Marino 	if (!issuer) {
1079f5b1c8a1SJohn Marino 		BIO_printf(bio_err, "No issuer certificate specified\n");
1080f5b1c8a1SJohn Marino 		return 0;
1081f5b1c8a1SJohn Marino 	}
1082f5b1c8a1SJohn Marino 	if (!*req)
1083f5b1c8a1SJohn Marino 		*req = OCSP_REQUEST_new();
1084f5b1c8a1SJohn Marino 	if (!*req)
1085f5b1c8a1SJohn Marino 		goto err;
1086f5b1c8a1SJohn Marino 	id = OCSP_cert_to_id(cert_id_md, cert, issuer);
1087f5b1c8a1SJohn Marino 	if (!id || !sk_OCSP_CERTID_push(ids, id))
1088f5b1c8a1SJohn Marino 		goto err;
1089f5b1c8a1SJohn Marino 	if (!OCSP_request_add0_id(*req, id))
1090f5b1c8a1SJohn Marino 		goto err;
1091f5b1c8a1SJohn Marino 	return 1;
1092f5b1c8a1SJohn Marino 
1093f5b1c8a1SJohn Marino  err:
1094f5b1c8a1SJohn Marino 	BIO_printf(bio_err, "Error Creating OCSP request\n");
1095f5b1c8a1SJohn Marino 	return 0;
1096f5b1c8a1SJohn Marino }
1097f5b1c8a1SJohn Marino 
1098f5b1c8a1SJohn Marino static int
add_ocsp_serial(OCSP_REQUEST ** req,char * serial,const EVP_MD * cert_id_md,X509 * issuer,STACK_OF (OCSP_CERTID)* ids)10998edacedfSDaniel Fojt add_ocsp_serial(OCSP_REQUEST **req, char *serial, const EVP_MD *cert_id_md,
11008edacedfSDaniel Fojt     X509 *issuer, STACK_OF(OCSP_CERTID) *ids)
1101f5b1c8a1SJohn Marino {
1102f5b1c8a1SJohn Marino 	OCSP_CERTID *id;
1103f5b1c8a1SJohn Marino 	X509_NAME *iname;
1104f5b1c8a1SJohn Marino 	ASN1_BIT_STRING *ikey;
1105f5b1c8a1SJohn Marino 	ASN1_INTEGER *sno;
11068edacedfSDaniel Fojt 
1107f5b1c8a1SJohn Marino 	if (!issuer) {
1108f5b1c8a1SJohn Marino 		BIO_printf(bio_err, "No issuer certificate specified\n");
1109f5b1c8a1SJohn Marino 		return 0;
1110f5b1c8a1SJohn Marino 	}
1111f5b1c8a1SJohn Marino 	if (!*req)
1112f5b1c8a1SJohn Marino 		*req = OCSP_REQUEST_new();
1113f5b1c8a1SJohn Marino 	if (!*req)
1114f5b1c8a1SJohn Marino 		goto err;
1115f5b1c8a1SJohn Marino 	iname = X509_get_subject_name(issuer);
1116f5b1c8a1SJohn Marino 	ikey = X509_get0_pubkey_bitstr(issuer);
1117f5b1c8a1SJohn Marino 	sno = s2i_ASN1_INTEGER(NULL, serial);
1118f5b1c8a1SJohn Marino 	if (!sno) {
11198edacedfSDaniel Fojt 		BIO_printf(bio_err, "Error converting serial number %s\n",
11208edacedfSDaniel Fojt 		    serial);
1121f5b1c8a1SJohn Marino 		return 0;
1122f5b1c8a1SJohn Marino 	}
1123f5b1c8a1SJohn Marino 	id = OCSP_cert_id_new(cert_id_md, iname, ikey, sno);
1124f5b1c8a1SJohn Marino 	ASN1_INTEGER_free(sno);
1125f5b1c8a1SJohn Marino 	if (!id || !sk_OCSP_CERTID_push(ids, id))
1126f5b1c8a1SJohn Marino 		goto err;
1127f5b1c8a1SJohn Marino 	if (!OCSP_request_add0_id(*req, id))
1128f5b1c8a1SJohn Marino 		goto err;
1129f5b1c8a1SJohn Marino 	return 1;
1130f5b1c8a1SJohn Marino 
1131f5b1c8a1SJohn Marino  err:
1132f5b1c8a1SJohn Marino 	BIO_printf(bio_err, "Error Creating OCSP request\n");
1133f5b1c8a1SJohn Marino 	return 0;
1134f5b1c8a1SJohn Marino }
1135f5b1c8a1SJohn Marino 
1136f5b1c8a1SJohn Marino static int
print_ocsp_summary(BIO * out,OCSP_BASICRESP * bs,OCSP_REQUEST * req,STACK_OF (OPENSSL_STRING)* names,STACK_OF (OCSP_CERTID)* ids,long nsec,long maxage)1137f5b1c8a1SJohn Marino print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req,
11388edacedfSDaniel Fojt     STACK_OF(OPENSSL_STRING) *names, STACK_OF(OCSP_CERTID) *ids, long nsec,
1139f5b1c8a1SJohn Marino     long maxage)
1140f5b1c8a1SJohn Marino {
1141f5b1c8a1SJohn Marino 	OCSP_CERTID *id;
1142f5b1c8a1SJohn Marino 	char *name;
1143f5b1c8a1SJohn Marino 	int i;
1144f5b1c8a1SJohn Marino 	int status, reason;
1145f5b1c8a1SJohn Marino 
1146f5b1c8a1SJohn Marino 	ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
1147f5b1c8a1SJohn Marino 
11488edacedfSDaniel Fojt 	if (!bs || !req || !sk_OPENSSL_STRING_num(names) ||
11498edacedfSDaniel Fojt 	    !sk_OCSP_CERTID_num(ids))
1150f5b1c8a1SJohn Marino 		return 1;
1151f5b1c8a1SJohn Marino 
1152f5b1c8a1SJohn Marino 	for (i = 0; i < sk_OCSP_CERTID_num(ids); i++) {
1153f5b1c8a1SJohn Marino 		id = sk_OCSP_CERTID_value(ids, i);
1154f5b1c8a1SJohn Marino 		name = sk_OPENSSL_STRING_value(names, i);
1155f5b1c8a1SJohn Marino 		BIO_printf(out, "%s: ", name);
1156f5b1c8a1SJohn Marino 
1157f5b1c8a1SJohn Marino 		if (!OCSP_resp_find_status(bs, id, &status, &reason,
1158f5b1c8a1SJohn Marino 			&rev, &thisupd, &nextupd)) {
1159f5b1c8a1SJohn Marino 			BIO_puts(out, "ERROR: No Status found.\n");
1160f5b1c8a1SJohn Marino 			continue;
1161f5b1c8a1SJohn Marino 		}
1162f5b1c8a1SJohn Marino 		/*
1163f5b1c8a1SJohn Marino 		 * Check validity: if invalid write to output BIO so we know
1164f5b1c8a1SJohn Marino 		 * which response this refers to.
1165f5b1c8a1SJohn Marino 		 */
1166f5b1c8a1SJohn Marino 		if (!OCSP_check_validity(thisupd, nextupd, nsec, maxage)) {
1167f5b1c8a1SJohn Marino 			BIO_puts(out, "WARNING: Status times invalid.\n");
1168f5b1c8a1SJohn Marino 			ERR_print_errors(out);
1169f5b1c8a1SJohn Marino 		}
1170f5b1c8a1SJohn Marino 		BIO_printf(out, "%s\n", OCSP_cert_status_str(status));
1171f5b1c8a1SJohn Marino 
1172f5b1c8a1SJohn Marino 		BIO_puts(out, "\tThis Update: ");
1173f5b1c8a1SJohn Marino 		ASN1_GENERALIZEDTIME_print(out, thisupd);
1174f5b1c8a1SJohn Marino 		BIO_puts(out, "\n");
1175f5b1c8a1SJohn Marino 
1176f5b1c8a1SJohn Marino 		if (nextupd) {
1177f5b1c8a1SJohn Marino 			BIO_puts(out, "\tNext Update: ");
1178f5b1c8a1SJohn Marino 			ASN1_GENERALIZEDTIME_print(out, nextupd);
1179f5b1c8a1SJohn Marino 			BIO_puts(out, "\n");
1180f5b1c8a1SJohn Marino 		}
1181f5b1c8a1SJohn Marino 		if (status != V_OCSP_CERTSTATUS_REVOKED)
1182f5b1c8a1SJohn Marino 			continue;
1183f5b1c8a1SJohn Marino 
1184f5b1c8a1SJohn Marino 		if (reason != -1)
1185f5b1c8a1SJohn Marino 			BIO_printf(out, "\tReason: %s\n",
1186f5b1c8a1SJohn Marino 			    OCSP_crl_reason_str(reason));
1187f5b1c8a1SJohn Marino 
1188f5b1c8a1SJohn Marino 		BIO_puts(out, "\tRevocation Time: ");
1189f5b1c8a1SJohn Marino 		ASN1_GENERALIZEDTIME_print(out, rev);
1190f5b1c8a1SJohn Marino 		BIO_puts(out, "\n");
1191f5b1c8a1SJohn Marino 	}
1192f5b1c8a1SJohn Marino 
1193f5b1c8a1SJohn Marino 	return 1;
1194f5b1c8a1SJohn Marino }
1195f5b1c8a1SJohn Marino 
1196f5b1c8a1SJohn Marino 
1197f5b1c8a1SJohn Marino static int
make_ocsp_response(OCSP_RESPONSE ** resp,OCSP_REQUEST * req,CA_DB * db,X509 * ca,X509 * rcert,EVP_PKEY * rkey,STACK_OF (X509)* rother,unsigned long flags,int nmin,int ndays)1198f5b1c8a1SJohn Marino make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req, CA_DB *db,
11998edacedfSDaniel Fojt     X509 *ca, X509 *rcert, EVP_PKEY *rkey, STACK_OF(X509) *rother,
12008edacedfSDaniel Fojt     unsigned long flags, int nmin, int ndays)
1201f5b1c8a1SJohn Marino {
1202f5b1c8a1SJohn Marino 	ASN1_TIME *thisupd = NULL, *nextupd = NULL;
1203f5b1c8a1SJohn Marino 	OCSP_CERTID *cid, *ca_id = NULL;
1204f5b1c8a1SJohn Marino 	OCSP_BASICRESP *bs = NULL;
1205f5b1c8a1SJohn Marino 	int i, id_count, ret = 1;
1206f5b1c8a1SJohn Marino 
1207f5b1c8a1SJohn Marino 	id_count = OCSP_request_onereq_count(req);
1208f5b1c8a1SJohn Marino 
1209f5b1c8a1SJohn Marino 	if (id_count <= 0) {
12108edacedfSDaniel Fojt 		*resp = OCSP_response_create(
12118edacedfSDaniel Fojt 		    OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, NULL);
1212f5b1c8a1SJohn Marino 		goto end;
1213f5b1c8a1SJohn Marino 	}
1214f5b1c8a1SJohn Marino 	bs = OCSP_BASICRESP_new();
1215f5b1c8a1SJohn Marino 	thisupd = X509_gmtime_adj(NULL, 0);
1216f5b1c8a1SJohn Marino 	if (ndays != -1)
1217f5b1c8a1SJohn Marino 		nextupd = X509_gmtime_adj(NULL, nmin * 60 + ndays * 3600 * 24);
1218f5b1c8a1SJohn Marino 
1219f5b1c8a1SJohn Marino 	/* Examine each certificate id in the request */
1220f5b1c8a1SJohn Marino 	for (i = 0; i < id_count; i++) {
1221f5b1c8a1SJohn Marino 		OCSP_ONEREQ *one;
1222f5b1c8a1SJohn Marino 		ASN1_INTEGER *serial;
1223f5b1c8a1SJohn Marino 		char **inf;
1224f5b1c8a1SJohn Marino 		ASN1_OBJECT *cert_id_md_oid;
1225f5b1c8a1SJohn Marino 		const EVP_MD *cert_id_md;
1226f5b1c8a1SJohn Marino 		one = OCSP_request_onereq_get0(req, i);
1227f5b1c8a1SJohn Marino 		cid = OCSP_onereq_get0_id(one);
1228f5b1c8a1SJohn Marino 
1229f5b1c8a1SJohn Marino 		OCSP_id_get0_info(NULL, &cert_id_md_oid, NULL, NULL, cid);
1230f5b1c8a1SJohn Marino 
1231f5b1c8a1SJohn Marino 		cert_id_md = EVP_get_digestbyobj(cert_id_md_oid);
1232f5b1c8a1SJohn Marino 		if (!cert_id_md) {
12338edacedfSDaniel Fojt 			*resp = OCSP_response_create(
12348edacedfSDaniel Fojt 			    OCSP_RESPONSE_STATUS_INTERNALERROR, NULL);
1235f5b1c8a1SJohn Marino 			goto end;
1236f5b1c8a1SJohn Marino 		}
1237f5b1c8a1SJohn Marino 		OCSP_CERTID_free(ca_id);
1238f5b1c8a1SJohn Marino 		ca_id = OCSP_cert_to_id(cert_id_md, NULL, ca);
1239f5b1c8a1SJohn Marino 
1240f5b1c8a1SJohn Marino 		/* Is this request about our CA? */
1241f5b1c8a1SJohn Marino 		if (OCSP_id_issuer_cmp(ca_id, cid)) {
1242f5b1c8a1SJohn Marino 			OCSP_basic_add1_status(bs, cid,
12438edacedfSDaniel Fojt 			    V_OCSP_CERTSTATUS_UNKNOWN, 0, NULL,
1244f5b1c8a1SJohn Marino 			    thisupd, nextupd);
1245f5b1c8a1SJohn Marino 			continue;
1246f5b1c8a1SJohn Marino 		}
1247f5b1c8a1SJohn Marino 		OCSP_id_get0_info(NULL, NULL, NULL, &serial, cid);
1248f5b1c8a1SJohn Marino 		inf = lookup_serial(db, serial);
12498edacedfSDaniel Fojt 		if (!inf) {
1250f5b1c8a1SJohn Marino 			OCSP_basic_add1_status(bs, cid,
12518edacedfSDaniel Fojt 			    V_OCSP_CERTSTATUS_UNKNOWN, 0, NULL,
1252f5b1c8a1SJohn Marino 			    thisupd, nextupd);
12538edacedfSDaniel Fojt 		} else if (inf[DB_type][0] == DB_TYPE_VAL) {
1254f5b1c8a1SJohn Marino 			OCSP_basic_add1_status(bs, cid,
12558edacedfSDaniel Fojt 			    V_OCSP_CERTSTATUS_GOOD, 0, NULL,
1256f5b1c8a1SJohn Marino 			    thisupd, nextupd);
12578edacedfSDaniel Fojt 		} else if (inf[DB_type][0] == DB_TYPE_REV) {
1258f5b1c8a1SJohn Marino 			ASN1_OBJECT *inst = NULL;
1259f5b1c8a1SJohn Marino 			ASN1_TIME *revtm = NULL;
1260f5b1c8a1SJohn Marino 			ASN1_GENERALIZEDTIME *invtm = NULL;
1261f5b1c8a1SJohn Marino 			OCSP_SINGLERESP *single;
1262f5b1c8a1SJohn Marino 			int reason = -1;
12638edacedfSDaniel Fojt 
12648edacedfSDaniel Fojt 			unpack_revinfo(&revtm, &reason, &inst, &invtm,
12658edacedfSDaniel Fojt 			    inf[DB_rev_date]);
1266f5b1c8a1SJohn Marino 			single = OCSP_basic_add1_status(bs, cid,
1267f5b1c8a1SJohn Marino 			    V_OCSP_CERTSTATUS_REVOKED,
1268f5b1c8a1SJohn Marino 			    reason, revtm,
1269f5b1c8a1SJohn Marino 			    thisupd, nextupd);
1270f5b1c8a1SJohn Marino 			if (invtm)
12718edacedfSDaniel Fojt 				OCSP_SINGLERESP_add1_ext_i2d(single,
12728edacedfSDaniel Fojt 				    NID_invalidity_date, invtm, 0, 0);
1273f5b1c8a1SJohn Marino 			else if (inst)
12748edacedfSDaniel Fojt 				OCSP_SINGLERESP_add1_ext_i2d(single,
12758edacedfSDaniel Fojt 				    NID_hold_instruction_code, inst, 0, 0);
1276f5b1c8a1SJohn Marino 			ASN1_OBJECT_free(inst);
1277f5b1c8a1SJohn Marino 			ASN1_TIME_free(revtm);
1278f5b1c8a1SJohn Marino 			ASN1_GENERALIZEDTIME_free(invtm);
1279f5b1c8a1SJohn Marino 		}
1280f5b1c8a1SJohn Marino 	}
1281f5b1c8a1SJohn Marino 
1282f5b1c8a1SJohn Marino 	OCSP_copy_nonce(bs, req);
1283f5b1c8a1SJohn Marino 
1284f5b1c8a1SJohn Marino 	OCSP_basic_sign(bs, rcert, rkey, NULL, rother, flags);
1285f5b1c8a1SJohn Marino 
1286f5b1c8a1SJohn Marino 	*resp = OCSP_response_create(OCSP_RESPONSE_STATUS_SUCCESSFUL, bs);
1287f5b1c8a1SJohn Marino 
1288f5b1c8a1SJohn Marino  end:
1289f5b1c8a1SJohn Marino 	ASN1_TIME_free(thisupd);
1290f5b1c8a1SJohn Marino 	ASN1_TIME_free(nextupd);
1291f5b1c8a1SJohn Marino 	OCSP_CERTID_free(ca_id);
1292f5b1c8a1SJohn Marino 	OCSP_BASICRESP_free(bs);
1293f5b1c8a1SJohn Marino 	return ret;
1294f5b1c8a1SJohn Marino }
1295f5b1c8a1SJohn Marino 
1296f5b1c8a1SJohn Marino static char **
lookup_serial(CA_DB * db,ASN1_INTEGER * ser)1297f5b1c8a1SJohn Marino lookup_serial(CA_DB *db, ASN1_INTEGER *ser)
1298f5b1c8a1SJohn Marino {
1299f5b1c8a1SJohn Marino 	int i;
1300f5b1c8a1SJohn Marino 	BIGNUM *bn = NULL;
1301f5b1c8a1SJohn Marino 	char *itmp, *row[DB_NUMBER], **rrow;
13028edacedfSDaniel Fojt 
1303f5b1c8a1SJohn Marino 	for (i = 0; i < DB_NUMBER; i++)
1304f5b1c8a1SJohn Marino 		row[i] = NULL;
1305f5b1c8a1SJohn Marino 	bn = ASN1_INTEGER_to_BN(ser, NULL);
1306f5b1c8a1SJohn Marino 	OPENSSL_assert(bn);	/* FIXME: should report an error at this
1307f5b1c8a1SJohn Marino 				 * point and abort */
1308f5b1c8a1SJohn Marino 	if (BN_is_zero(bn))
1309f5b1c8a1SJohn Marino 		itmp = strdup("00");
1310f5b1c8a1SJohn Marino 	else
1311f5b1c8a1SJohn Marino 		itmp = BN_bn2hex(bn);
1312f5b1c8a1SJohn Marino 	row[DB_serial] = itmp;
1313f5b1c8a1SJohn Marino 	BN_free(bn);
1314f5b1c8a1SJohn Marino 	rrow = TXT_DB_get_by_index(db->db, DB_serial, row);
1315f5b1c8a1SJohn Marino 	free(itmp);
1316f5b1c8a1SJohn Marino 	return rrow;
1317f5b1c8a1SJohn Marino }
1318f5b1c8a1SJohn Marino 
1319f5b1c8a1SJohn Marino /* Quick and dirty OCSP server: read in and parse input request */
1320f5b1c8a1SJohn Marino 
1321f5b1c8a1SJohn Marino static BIO *
init_responder(char * port)1322f5b1c8a1SJohn Marino init_responder(char *port)
1323f5b1c8a1SJohn Marino {
1324f5b1c8a1SJohn Marino 	BIO *acbio = NULL, *bufbio = NULL;
13258edacedfSDaniel Fojt 
1326f5b1c8a1SJohn Marino 	bufbio = BIO_new(BIO_f_buffer());
1327f5b1c8a1SJohn Marino 	if (!bufbio)
1328f5b1c8a1SJohn Marino 		goto err;
1329f5b1c8a1SJohn Marino 	acbio = BIO_new_accept(port);
1330f5b1c8a1SJohn Marino 	if (!acbio)
1331f5b1c8a1SJohn Marino 		goto err;
1332*de0e0e4dSAntonio Huete Jimenez 	BIO_set_bind_mode(acbio, BIO_BIND_REUSEADDR);
1333f5b1c8a1SJohn Marino 	BIO_set_accept_bios(acbio, bufbio);
1334f5b1c8a1SJohn Marino 	bufbio = NULL;
1335f5b1c8a1SJohn Marino 
1336f5b1c8a1SJohn Marino 	if (BIO_do_accept(acbio) <= 0) {
1337f5b1c8a1SJohn Marino 		BIO_printf(bio_err, "Error setting up accept BIO\n");
1338f5b1c8a1SJohn Marino 		ERR_print_errors(bio_err);
1339f5b1c8a1SJohn Marino 		goto err;
1340f5b1c8a1SJohn Marino 	}
1341f5b1c8a1SJohn Marino 	return acbio;
1342f5b1c8a1SJohn Marino 
1343f5b1c8a1SJohn Marino  err:
1344f5b1c8a1SJohn Marino 	BIO_free_all(acbio);
1345f5b1c8a1SJohn Marino 	BIO_free(bufbio);
1346f5b1c8a1SJohn Marino 	return NULL;
1347f5b1c8a1SJohn Marino }
1348f5b1c8a1SJohn Marino 
1349f5b1c8a1SJohn Marino static int
do_responder(OCSP_REQUEST ** preq,BIO ** pcbio,BIO * acbio,char * port)1350f5b1c8a1SJohn Marino do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, char *port)
1351f5b1c8a1SJohn Marino {
1352f5b1c8a1SJohn Marino 	int have_post = 0, len;
1353f5b1c8a1SJohn Marino 	OCSP_REQUEST *req = NULL;
1354f5b1c8a1SJohn Marino 	char inbuf[1024];
1355f5b1c8a1SJohn Marino 	BIO *cbio = NULL;
1356f5b1c8a1SJohn Marino 
1357f5b1c8a1SJohn Marino 	if (BIO_do_accept(acbio) <= 0) {
1358f5b1c8a1SJohn Marino 		BIO_printf(bio_err, "Error accepting connection\n");
1359f5b1c8a1SJohn Marino 		ERR_print_errors(bio_err);
1360f5b1c8a1SJohn Marino 		return 0;
1361f5b1c8a1SJohn Marino 	}
1362f5b1c8a1SJohn Marino 	cbio = BIO_pop(acbio);
1363f5b1c8a1SJohn Marino 	*pcbio = cbio;
1364f5b1c8a1SJohn Marino 
1365f5b1c8a1SJohn Marino 	for (;;) {
1366f5b1c8a1SJohn Marino 		len = BIO_gets(cbio, inbuf, sizeof inbuf);
1367f5b1c8a1SJohn Marino 		if (len <= 0)
1368f5b1c8a1SJohn Marino 			return 1;
1369f5b1c8a1SJohn Marino 		/* Look for "POST" signalling start of query */
1370f5b1c8a1SJohn Marino 		if (!have_post) {
1371f5b1c8a1SJohn Marino 			if (strncmp(inbuf, "POST", 4)) {
1372f5b1c8a1SJohn Marino 				BIO_printf(bio_err, "Invalid request\n");
1373f5b1c8a1SJohn Marino 				return 1;
1374f5b1c8a1SJohn Marino 			}
1375f5b1c8a1SJohn Marino 			have_post = 1;
1376f5b1c8a1SJohn Marino 		}
1377f5b1c8a1SJohn Marino 		/* Look for end of headers */
1378f5b1c8a1SJohn Marino 		if ((inbuf[0] == '\r') || (inbuf[0] == '\n'))
1379f5b1c8a1SJohn Marino 			break;
1380f5b1c8a1SJohn Marino 	}
1381f5b1c8a1SJohn Marino 
1382f5b1c8a1SJohn Marino 	/* Try to read OCSP request */
1383f5b1c8a1SJohn Marino 
1384f5b1c8a1SJohn Marino 	req = d2i_OCSP_REQUEST_bio(cbio, NULL);
1385f5b1c8a1SJohn Marino 
1386f5b1c8a1SJohn Marino 	if (!req) {
1387f5b1c8a1SJohn Marino 		BIO_printf(bio_err, "Error parsing OCSP request\n");
1388f5b1c8a1SJohn Marino 		ERR_print_errors(bio_err);
1389f5b1c8a1SJohn Marino 	}
1390f5b1c8a1SJohn Marino 	*preq = req;
1391f5b1c8a1SJohn Marino 
1392f5b1c8a1SJohn Marino 	return 1;
1393f5b1c8a1SJohn Marino }
1394f5b1c8a1SJohn Marino 
1395f5b1c8a1SJohn Marino static int
send_ocsp_response(BIO * cbio,OCSP_RESPONSE * resp)1396f5b1c8a1SJohn Marino send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp)
1397f5b1c8a1SJohn Marino {
1398f5b1c8a1SJohn Marino 	static const char http_resp[] =
1399f5b1c8a1SJohn Marino 	"HTTP/1.0 200 OK\r\nContent-type: application/ocsp-response\r\n"
1400f5b1c8a1SJohn Marino 	"Content-Length: %d\r\n\r\n";
14018edacedfSDaniel Fojt 
1402f5b1c8a1SJohn Marino 	if (!cbio)
1403f5b1c8a1SJohn Marino 		return 0;
1404f5b1c8a1SJohn Marino 	BIO_printf(cbio, http_resp, i2d_OCSP_RESPONSE(resp, NULL));
1405f5b1c8a1SJohn Marino 	i2d_OCSP_RESPONSE_bio(cbio, resp);
1406f5b1c8a1SJohn Marino 	(void) BIO_flush(cbio);
1407f5b1c8a1SJohn Marino 	return 1;
1408f5b1c8a1SJohn Marino }
1409f5b1c8a1SJohn Marino 
1410f5b1c8a1SJohn Marino static OCSP_RESPONSE *
query_responder(BIO * err,BIO * cbio,char * path,STACK_OF (CONF_VALUE)* headers,const char * host,OCSP_REQUEST * req,int req_timeout)14118edacedfSDaniel Fojt query_responder(BIO *err, BIO *cbio, char *path, STACK_OF(CONF_VALUE) *headers,
1412*de0e0e4dSAntonio Huete Jimenez     const char *host, OCSP_REQUEST *req, int req_timeout)
1413f5b1c8a1SJohn Marino {
1414f5b1c8a1SJohn Marino 	int fd;
1415f5b1c8a1SJohn Marino 	int rv;
1416f5b1c8a1SJohn Marino 	int i;
1417*de0e0e4dSAntonio Huete Jimenez 	int have_host = 0;
1418f5b1c8a1SJohn Marino 	OCSP_REQ_CTX *ctx = NULL;
1419f5b1c8a1SJohn Marino 	OCSP_RESPONSE *rsp = NULL;
1420f5b1c8a1SJohn Marino 	struct pollfd pfd[1];
1421f5b1c8a1SJohn Marino 
1422f5b1c8a1SJohn Marino 	if (req_timeout != -1)
1423f5b1c8a1SJohn Marino 		BIO_set_nbio(cbio, 1);
1424f5b1c8a1SJohn Marino 
1425f5b1c8a1SJohn Marino 	rv = BIO_do_connect(cbio);
1426f5b1c8a1SJohn Marino 
1427f5b1c8a1SJohn Marino 	if ((rv <= 0) && ((req_timeout == -1) || !BIO_should_retry(cbio))) {
1428f5b1c8a1SJohn Marino 		BIO_puts(err, "Error connecting BIO\n");
1429f5b1c8a1SJohn Marino 		return NULL;
1430f5b1c8a1SJohn Marino 	}
1431f5b1c8a1SJohn Marino 	if (BIO_get_fd(cbio, &fd) < 0) {
1432f5b1c8a1SJohn Marino 		BIO_puts(err, "Can't get connection fd\n");
1433f5b1c8a1SJohn Marino 		goto err;
1434f5b1c8a1SJohn Marino 	}
1435f5b1c8a1SJohn Marino 	if (req_timeout != -1 && rv <= 0) {
1436f5b1c8a1SJohn Marino 		pfd[0].fd = fd;
1437f5b1c8a1SJohn Marino 		pfd[0].events = POLLOUT;
1438f5b1c8a1SJohn Marino 		rv = poll(pfd, 1, req_timeout * 1000);
1439f5b1c8a1SJohn Marino 		if (rv == 0) {
1440f5b1c8a1SJohn Marino 			BIO_puts(err, "Timeout on connect\n");
1441f5b1c8a1SJohn Marino 			return NULL;
1442f5b1c8a1SJohn Marino 		}
1443f5b1c8a1SJohn Marino 		if (rv == -1) {
1444f5b1c8a1SJohn Marino 			BIO_puts(err, "Poll error\n");
1445f5b1c8a1SJohn Marino 			return NULL;
1446f5b1c8a1SJohn Marino 		}
1447f5b1c8a1SJohn Marino 	}
1448f5b1c8a1SJohn Marino 	ctx = OCSP_sendreq_new(cbio, path, NULL, -1);
1449f5b1c8a1SJohn Marino 	if (!ctx)
1450f5b1c8a1SJohn Marino 		return NULL;
1451f5b1c8a1SJohn Marino 
1452f5b1c8a1SJohn Marino 	for (i = 0; i < sk_CONF_VALUE_num(headers); i++) {
1453f5b1c8a1SJohn Marino 		CONF_VALUE *hdr = sk_CONF_VALUE_value(headers, i);
1454*de0e0e4dSAntonio Huete Jimenez 		if (strcasecmp("host", hdr->name) == 0)
1455*de0e0e4dSAntonio Huete Jimenez 			have_host = 1;
1456f5b1c8a1SJohn Marino 		if (!OCSP_REQ_CTX_add1_header(ctx, hdr->name, hdr->value))
1457f5b1c8a1SJohn Marino 			goto err;
1458f5b1c8a1SJohn Marino 	}
1459f5b1c8a1SJohn Marino 
1460*de0e0e4dSAntonio Huete Jimenez 	if (!have_host) {
1461*de0e0e4dSAntonio Huete Jimenez 		if (!OCSP_REQ_CTX_add1_header(ctx, "Host", host))
1462*de0e0e4dSAntonio Huete Jimenez 			goto err;
1463*de0e0e4dSAntonio Huete Jimenez 	}
1464*de0e0e4dSAntonio Huete Jimenez 
1465f5b1c8a1SJohn Marino 	if (!OCSP_REQ_CTX_set1_req(ctx, req))
1466f5b1c8a1SJohn Marino 		goto err;
1467f5b1c8a1SJohn Marino 
1468f5b1c8a1SJohn Marino 	for (;;) {
1469f5b1c8a1SJohn Marino 		rv = OCSP_sendreq_nbio(&rsp, ctx);
1470f5b1c8a1SJohn Marino 		if (rv != -1)
1471f5b1c8a1SJohn Marino 			break;
1472f5b1c8a1SJohn Marino 		if (req_timeout == -1)
1473f5b1c8a1SJohn Marino 			continue;
1474f5b1c8a1SJohn Marino 		pfd[0].fd = fd;
14758edacedfSDaniel Fojt 		if (BIO_should_read(cbio)) {
1476f5b1c8a1SJohn Marino 			pfd[0].events = POLLIN;
14778edacedfSDaniel Fojt 		} else if (BIO_should_write(cbio)) {
1478f5b1c8a1SJohn Marino 			pfd[0].events = POLLOUT;
14798edacedfSDaniel Fojt 		} else {
1480f5b1c8a1SJohn Marino 			BIO_puts(err, "Unexpected retry condition\n");
1481f5b1c8a1SJohn Marino 			goto err;
1482f5b1c8a1SJohn Marino 		}
1483f5b1c8a1SJohn Marino 		rv = poll(pfd, 1, req_timeout * 1000);
1484f5b1c8a1SJohn Marino 		if (rv == 0) {
1485f5b1c8a1SJohn Marino 			BIO_puts(err, "Timeout on request\n");
1486f5b1c8a1SJohn Marino 			break;
1487f5b1c8a1SJohn Marino 		}
1488f5b1c8a1SJohn Marino 		if (rv == -1 || (pfd[0].revents & (POLLERR|POLLNVAL))) {
1489f5b1c8a1SJohn Marino 			BIO_puts(err, "Poll error\n");
1490f5b1c8a1SJohn Marino 			break;
1491f5b1c8a1SJohn Marino 		}
1492f5b1c8a1SJohn Marino 	}
14938edacedfSDaniel Fojt 
1494f5b1c8a1SJohn Marino  err:
1495f5b1c8a1SJohn Marino 	OCSP_REQ_CTX_free(ctx);
1496f5b1c8a1SJohn Marino 	return rsp;
1497f5b1c8a1SJohn Marino }
1498f5b1c8a1SJohn Marino 
1499f5b1c8a1SJohn Marino OCSP_RESPONSE *
process_responder(BIO * err,OCSP_REQUEST * req,char * host,char * path,char * port,int use_ssl,STACK_OF (CONF_VALUE)* headers,int req_timeout)15008edacedfSDaniel Fojt process_responder(BIO *err, OCSP_REQUEST *req, char *host, char *path,
15018edacedfSDaniel Fojt     char *port, int use_ssl, STACK_OF(CONF_VALUE) *headers, int req_timeout)
1502f5b1c8a1SJohn Marino {
1503f5b1c8a1SJohn Marino 	BIO *cbio = NULL;
1504f5b1c8a1SJohn Marino 	SSL_CTX *ctx = NULL;
1505f5b1c8a1SJohn Marino 	OCSP_RESPONSE *resp = NULL;
15068edacedfSDaniel Fojt 
1507f5b1c8a1SJohn Marino 	cbio = BIO_new_connect(host);
1508f5b1c8a1SJohn Marino 	if (!cbio) {
1509f5b1c8a1SJohn Marino 		BIO_printf(err, "Error creating connect BIO\n");
1510f5b1c8a1SJohn Marino 		goto end;
1511f5b1c8a1SJohn Marino 	}
1512f5b1c8a1SJohn Marino 	if (port)
1513f5b1c8a1SJohn Marino 		BIO_set_conn_port(cbio, port);
1514f5b1c8a1SJohn Marino 	if (use_ssl == 1) {
1515f5b1c8a1SJohn Marino 		BIO *sbio;
15168edacedfSDaniel Fojt 		ctx = SSL_CTX_new(TLS_client_method());
1517f5b1c8a1SJohn Marino 		if (ctx == NULL) {
1518f5b1c8a1SJohn Marino 			BIO_printf(err, "Error creating SSL context.\n");
1519f5b1c8a1SJohn Marino 			goto end;
1520f5b1c8a1SJohn Marino 		}
1521f5b1c8a1SJohn Marino 		SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
1522f5b1c8a1SJohn Marino 		sbio = BIO_new_ssl(ctx, 1);
1523f5b1c8a1SJohn Marino 		cbio = BIO_push(sbio, cbio);
1524f5b1c8a1SJohn Marino 	}
1525*de0e0e4dSAntonio Huete Jimenez 	resp = query_responder(err, cbio, path, headers, host, req, req_timeout);
1526f5b1c8a1SJohn Marino 	if (!resp)
1527f5b1c8a1SJohn Marino 		BIO_printf(bio_err, "Error querying OCSP responder\n");
15288edacedfSDaniel Fojt 
1529f5b1c8a1SJohn Marino  end:
1530f5b1c8a1SJohn Marino 	BIO_free_all(cbio);
1531f5b1c8a1SJohn Marino 	SSL_CTX_free(ctx);
1532f5b1c8a1SJohn Marino 	return resp;
1533f5b1c8a1SJohn Marino }
1534f5b1c8a1SJohn Marino #endif
1535