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