xref: /freebsd/crypto/openssl/apps/ocsp.c (revision e71b70530d95c4f34d8bdbd78d1242df1ba4a945)
16f9291ceSJung-uk Kim /*
2*e71b7053SJung-uk Kim  * Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved.
3*e71b7053SJung-uk Kim  *
4*e71b7053SJung-uk Kim  * Licensed under the OpenSSL license (the "License").  You may not use
5*e71b7053SJung-uk Kim  * this file except in compliance with the License.  You can obtain a copy
6*e71b7053SJung-uk Kim  * in the file LICENSE in the source distribution or at
7*e71b7053SJung-uk Kim  * https://www.openssl.org/source/license.html
85c87c606SMark Murray  */
91f13597dSJung-uk Kim 
10*e71b7053SJung-uk Kim #include <openssl/opensslconf.h>
11*e71b7053SJung-uk Kim 
12*e71b7053SJung-uk Kim #ifdef OPENSSL_NO_OCSP
13*e71b7053SJung-uk Kim NON_EMPTY_TRANSLATION_UNIT
14*e71b7053SJung-uk Kim #else
151f13597dSJung-uk Kim # ifdef OPENSSL_SYS_VMS
161f13597dSJung-uk Kim #  define _XOPEN_SOURCE_EXTENDED/* So fd_set and friends get properly defined
176f9291ceSJung-uk Kim                                  * on OpenVMS */
181f13597dSJung-uk Kim # endif
191f13597dSJung-uk Kim 
205c87c606SMark Murray # include <stdio.h>
21db522d3aSSimon L. B. Nielsen # include <stdlib.h>
225c87c606SMark Murray # include <string.h>
231f13597dSJung-uk Kim # include <time.h>
24*e71b7053SJung-uk Kim # include <ctype.h>
25*e71b7053SJung-uk Kim 
26*e71b7053SJung-uk Kim /* Needs to be included before the openssl headers */
27*e71b7053SJung-uk Kim # include "apps.h"
28*e71b7053SJung-uk Kim # include "progs.h"
29*e71b7053SJung-uk Kim # include "internal/sockets.h"
30db522d3aSSimon L. B. Nielsen # include <openssl/e_os2.h>
311f13597dSJung-uk Kim # include <openssl/crypto.h>
32db522d3aSSimon L. B. Nielsen # include <openssl/err.h>
331f13597dSJung-uk Kim # include <openssl/ssl.h>
341f13597dSJung-uk Kim # include <openssl/evp.h>
351f13597dSJung-uk Kim # include <openssl/bn.h>
361f13597dSJung-uk Kim # include <openssl/x509v3.h>
37*e71b7053SJung-uk Kim # include <openssl/rand.h>
381f13597dSJung-uk Kim 
39*e71b7053SJung-uk Kim # if defined(OPENSSL_SYS_UNIX) && !defined(OPENSSL_NO_SOCK) \
40*e71b7053SJung-uk Kim      && !defined(OPENSSL_NO_POSIX_IO)
41*e71b7053SJung-uk Kim #  define OCSP_DAEMON
42*e71b7053SJung-uk Kim #  include <sys/types.h>
43*e71b7053SJung-uk Kim #  include <sys/wait.h>
44*e71b7053SJung-uk Kim #  include <syslog.h>
45*e71b7053SJung-uk Kim #  include <signal.h>
46*e71b7053SJung-uk Kim #  define MAXERRLEN 1000 /* limit error text sent to syslog to 1000 bytes */
471f13597dSJung-uk Kim # else
48*e71b7053SJung-uk Kim #  undef LOG_INFO
49*e71b7053SJung-uk Kim #  undef LOG_WARNING
50*e71b7053SJung-uk Kim #  undef LOG_ERR
51*e71b7053SJung-uk Kim #  define LOG_INFO      0
52*e71b7053SJung-uk Kim #  define LOG_WARNING   1
53*e71b7053SJung-uk Kim #  define LOG_ERR       2
541f13597dSJung-uk Kim # endif
555c87c606SMark Murray 
565c87c606SMark Murray /* Maximum leeway in validity period: default 5 minutes */
575c87c606SMark Murray # define MAX_VALIDITY_PERIOD    (5 * 60)
585c87c606SMark Murray 
596f9291ceSJung-uk Kim static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert,
606f9291ceSJung-uk Kim                          const EVP_MD *cert_id_md, X509 *issuer,
615c87c606SMark Murray                          STACK_OF(OCSP_CERTID) *ids);
626f9291ceSJung-uk Kim static int add_ocsp_serial(OCSP_REQUEST **req, char *serial,
636f9291ceSJung-uk Kim                            const EVP_MD *cert_id_md, X509 *issuer,
645c87c606SMark Murray                            STACK_OF(OCSP_CERTID) *ids);
65*e71b7053SJung-uk Kim static void print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req,
661f13597dSJung-uk Kim                               STACK_OF(OPENSSL_STRING) *names,
671f13597dSJung-uk Kim                               STACK_OF(OCSP_CERTID) *ids, long nsec,
681f13597dSJung-uk Kim                               long maxage);
69*e71b7053SJung-uk Kim static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req,
70*e71b7053SJung-uk Kim                               CA_DB *db, STACK_OF(X509) *ca, X509 *rcert,
717bded2dbSJung-uk Kim                               EVP_PKEY *rkey, const EVP_MD *md,
72*e71b7053SJung-uk Kim                               STACK_OF(OPENSSL_STRING) *sigopts,
737bded2dbSJung-uk Kim                               STACK_OF(X509) *rother, unsigned long flags,
747bded2dbSJung-uk Kim                               int nmin, int ndays, int badsig);
755c87c606SMark Murray 
76ced566fdSJacques Vidrine static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser);
777bded2dbSJung-uk Kim static BIO *init_responder(const char *port);
78*e71b7053SJung-uk Kim static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, int timeout);
795c87c606SMark Murray static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp);
80*e71b7053SJung-uk Kim static void log_message(int level, const char *fmt, ...);
81*e71b7053SJung-uk Kim static char *prog;
82*e71b7053SJung-uk Kim static int multi = 0;
83*e71b7053SJung-uk Kim 
84*e71b7053SJung-uk Kim # ifdef OCSP_DAEMON
85*e71b7053SJung-uk Kim static int acfd = (int) INVALID_SOCKET;
86*e71b7053SJung-uk Kim static int index_changed(CA_DB *);
87*e71b7053SJung-uk Kim static void spawn_loop(void);
88*e71b7053SJung-uk Kim static int print_syslog(const char *str, size_t len, void *levPtr);
89*e71b7053SJung-uk Kim static void sock_timeout(int signum);
90*e71b7053SJung-uk Kim # endif
91*e71b7053SJung-uk Kim 
92*e71b7053SJung-uk Kim # ifndef OPENSSL_NO_SOCK
93*e71b7053SJung-uk Kim static OCSP_RESPONSE *query_responder(BIO *cbio, const char *host,
94*e71b7053SJung-uk Kim                                       const char *path,
957bded2dbSJung-uk Kim                                       const STACK_OF(CONF_VALUE) *headers,
96db522d3aSSimon L. B. Nielsen                                       OCSP_REQUEST *req, int req_timeout);
97*e71b7053SJung-uk Kim # endif
985c87c606SMark Murray 
99*e71b7053SJung-uk Kim typedef enum OPTION_choice {
100*e71b7053SJung-uk Kim     OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
101*e71b7053SJung-uk Kim     OPT_OUTFILE, OPT_TIMEOUT, OPT_URL, OPT_HOST, OPT_PORT,
102*e71b7053SJung-uk Kim     OPT_IGNORE_ERR, OPT_NOVERIFY, OPT_NONCE, OPT_NO_NONCE,
103*e71b7053SJung-uk Kim     OPT_RESP_NO_CERTS, OPT_RESP_KEY_ID, OPT_NO_CERTS,
104*e71b7053SJung-uk Kim     OPT_NO_SIGNATURE_VERIFY, OPT_NO_CERT_VERIFY, OPT_NO_CHAIN,
105*e71b7053SJung-uk Kim     OPT_NO_CERT_CHECKS, OPT_NO_EXPLICIT, OPT_TRUST_OTHER,
106*e71b7053SJung-uk Kim     OPT_NO_INTERN, OPT_BADSIG, OPT_TEXT, OPT_REQ_TEXT, OPT_RESP_TEXT,
107*e71b7053SJung-uk Kim     OPT_REQIN, OPT_RESPIN, OPT_SIGNER, OPT_VAFILE, OPT_SIGN_OTHER,
108*e71b7053SJung-uk Kim     OPT_VERIFY_OTHER, OPT_CAFILE, OPT_CAPATH, OPT_NOCAFILE, OPT_NOCAPATH,
109*e71b7053SJung-uk Kim     OPT_VALIDITY_PERIOD, OPT_STATUS_AGE, OPT_SIGNKEY, OPT_REQOUT,
110*e71b7053SJung-uk Kim     OPT_RESPOUT, OPT_PATH, OPT_ISSUER, OPT_CERT, OPT_SERIAL,
111*e71b7053SJung-uk Kim     OPT_INDEX, OPT_CA, OPT_NMIN, OPT_REQUEST, OPT_NDAYS, OPT_RSIGNER,
112*e71b7053SJung-uk Kim     OPT_RKEY, OPT_ROTHER, OPT_RMD, OPT_RSIGOPT, OPT_HEADER,
113*e71b7053SJung-uk Kim     OPT_V_ENUM,
114*e71b7053SJung-uk Kim     OPT_MD,
115*e71b7053SJung-uk Kim     OPT_MULTI
116*e71b7053SJung-uk Kim } OPTION_CHOICE;
1175c87c606SMark Murray 
118*e71b7053SJung-uk Kim const OPTIONS ocsp_options[] = {
119*e71b7053SJung-uk Kim     {"help", OPT_HELP, '-', "Display this summary"},
120*e71b7053SJung-uk Kim     {"out", OPT_OUTFILE, '>', "Output filename"},
121*e71b7053SJung-uk Kim     {"timeout", OPT_TIMEOUT, 'p',
122*e71b7053SJung-uk Kim      "Connection timeout (in seconds) to the OCSP responder"},
123*e71b7053SJung-uk Kim     {"url", OPT_URL, 's', "Responder URL"},
124*e71b7053SJung-uk Kim     {"host", OPT_HOST, 's', "TCP/IP hostname:port to connect to"},
125*e71b7053SJung-uk Kim     {"port", OPT_PORT, 'p', "Port to run responder on"},
126*e71b7053SJung-uk Kim     {"ignore_err", OPT_IGNORE_ERR, '-',
127*e71b7053SJung-uk Kim      "Ignore error on OCSP request or response and continue running"},
128*e71b7053SJung-uk Kim     {"noverify", OPT_NOVERIFY, '-', "Don't verify response at all"},
129*e71b7053SJung-uk Kim     {"nonce", OPT_NONCE, '-', "Add OCSP nonce to request"},
130*e71b7053SJung-uk Kim     {"no_nonce", OPT_NO_NONCE, '-', "Don't add OCSP nonce to request"},
131*e71b7053SJung-uk Kim     {"resp_no_certs", OPT_RESP_NO_CERTS, '-',
132*e71b7053SJung-uk Kim      "Don't include any certificates in response"},
133*e71b7053SJung-uk Kim     {"resp_key_id", OPT_RESP_KEY_ID, '-',
134*e71b7053SJung-uk Kim      "Identify response by signing certificate key ID"},
135*e71b7053SJung-uk Kim # ifdef OCSP_DAEMON
136*e71b7053SJung-uk Kim     {"multi", OPT_MULTI, 'p', "run multiple responder processes"},
137*e71b7053SJung-uk Kim # endif
138*e71b7053SJung-uk Kim     {"no_certs", OPT_NO_CERTS, '-',
139*e71b7053SJung-uk Kim      "Don't include any certificates in signed request"},
140*e71b7053SJung-uk Kim     {"no_signature_verify", OPT_NO_SIGNATURE_VERIFY, '-',
141*e71b7053SJung-uk Kim      "Don't check signature on response"},
142*e71b7053SJung-uk Kim     {"no_cert_verify", OPT_NO_CERT_VERIFY, '-',
143*e71b7053SJung-uk Kim      "Don't check signing certificate"},
144*e71b7053SJung-uk Kim     {"no_chain", OPT_NO_CHAIN, '-', "Don't chain verify response"},
145*e71b7053SJung-uk Kim     {"no_cert_checks", OPT_NO_CERT_CHECKS, '-',
146*e71b7053SJung-uk Kim      "Don't do additional checks on signing certificate"},
147*e71b7053SJung-uk Kim     {"no_explicit", OPT_NO_EXPLICIT, '-',
148*e71b7053SJung-uk Kim      "Do not explicitly check the chain, just verify the root"},
149*e71b7053SJung-uk Kim     {"trust_other", OPT_TRUST_OTHER, '-',
150*e71b7053SJung-uk Kim      "Don't verify additional certificates"},
151*e71b7053SJung-uk Kim     {"no_intern", OPT_NO_INTERN, '-',
152*e71b7053SJung-uk Kim      "Don't search certificates contained in response for signer"},
153*e71b7053SJung-uk Kim     {"badsig", OPT_BADSIG, '-',
154*e71b7053SJung-uk Kim         "Corrupt last byte of loaded OSCP response signature (for test)"},
155*e71b7053SJung-uk Kim     {"text", OPT_TEXT, '-', "Print text form of request and response"},
156*e71b7053SJung-uk Kim     {"req_text", OPT_REQ_TEXT, '-', "Print text form of request"},
157*e71b7053SJung-uk Kim     {"resp_text", OPT_RESP_TEXT, '-', "Print text form of response"},
158*e71b7053SJung-uk Kim     {"reqin", OPT_REQIN, 's', "File with the DER-encoded request"},
159*e71b7053SJung-uk Kim     {"respin", OPT_RESPIN, 's', "File with the DER-encoded response"},
160*e71b7053SJung-uk Kim     {"signer", OPT_SIGNER, '<', "Certificate to sign OCSP request with"},
161*e71b7053SJung-uk Kim     {"VAfile", OPT_VAFILE, '<', "Validator certificates file"},
162*e71b7053SJung-uk Kim     {"sign_other", OPT_SIGN_OTHER, '<',
163*e71b7053SJung-uk Kim      "Additional certificates to include in signed request"},
164*e71b7053SJung-uk Kim     {"verify_other", OPT_VERIFY_OTHER, '<',
165*e71b7053SJung-uk Kim      "Additional certificates to search for signer"},
166*e71b7053SJung-uk Kim     {"CAfile", OPT_CAFILE, '<', "Trusted certificates file"},
167*e71b7053SJung-uk Kim     {"CApath", OPT_CAPATH, '<', "Trusted certificates directory"},
168*e71b7053SJung-uk Kim     {"no-CAfile", OPT_NOCAFILE, '-',
169*e71b7053SJung-uk Kim      "Do not load the default certificates file"},
170*e71b7053SJung-uk Kim     {"no-CApath", OPT_NOCAPATH, '-',
171*e71b7053SJung-uk Kim      "Do not load certificates from the default certificates directory"},
172*e71b7053SJung-uk Kim     {"validity_period", OPT_VALIDITY_PERIOD, 'u',
173*e71b7053SJung-uk Kim      "Maximum validity discrepancy in seconds"},
174*e71b7053SJung-uk Kim     {"status_age", OPT_STATUS_AGE, 'p', "Maximum status age in seconds"},
175*e71b7053SJung-uk Kim     {"signkey", OPT_SIGNKEY, 's', "Private key to sign OCSP request with"},
176*e71b7053SJung-uk Kim     {"reqout", OPT_REQOUT, 's', "Output file for the DER-encoded request"},
177*e71b7053SJung-uk Kim     {"respout", OPT_RESPOUT, 's', "Output file for the DER-encoded response"},
178*e71b7053SJung-uk Kim     {"path", OPT_PATH, 's', "Path to use in OCSP request"},
179*e71b7053SJung-uk Kim     {"issuer", OPT_ISSUER, '<', "Issuer certificate"},
180*e71b7053SJung-uk Kim     {"cert", OPT_CERT, '<', "Certificate to check"},
181*e71b7053SJung-uk Kim     {"serial", OPT_SERIAL, 's', "Serial number to check"},
182*e71b7053SJung-uk Kim     {"index", OPT_INDEX, '<', "Certificate status index file"},
183*e71b7053SJung-uk Kim     {"CA", OPT_CA, '<', "CA certificate"},
184*e71b7053SJung-uk Kim     {"nmin", OPT_NMIN, 'p', "Number of minutes before next update"},
185*e71b7053SJung-uk Kim     {"nrequest", OPT_REQUEST, 'p',
186*e71b7053SJung-uk Kim      "Number of requests to accept (default unlimited)"},
187*e71b7053SJung-uk Kim     {"ndays", OPT_NDAYS, 'p', "Number of days before next update"},
188*e71b7053SJung-uk Kim     {"rsigner", OPT_RSIGNER, '<',
189*e71b7053SJung-uk Kim      "Responder certificate to sign responses with"},
190*e71b7053SJung-uk Kim     {"rkey", OPT_RKEY, '<', "Responder key to sign responses with"},
191*e71b7053SJung-uk Kim     {"rother", OPT_ROTHER, '<', "Other certificates to include in response"},
192*e71b7053SJung-uk Kim     {"rmd", OPT_RMD, 's', "Digest Algorithm to use in signature of OCSP response"},
193*e71b7053SJung-uk Kim     {"rsigopt", OPT_RSIGOPT, 's', "OCSP response signature parameter in n:v form"},
194*e71b7053SJung-uk Kim     {"header", OPT_HEADER, 's', "key=value header to add"},
195*e71b7053SJung-uk Kim     {"", OPT_MD, '-', "Any supported digest algorithm (sha1,sha256, ... )"},
196*e71b7053SJung-uk Kim     OPT_V_OPTIONS,
197*e71b7053SJung-uk Kim     {NULL}
198*e71b7053SJung-uk Kim };
1995c87c606SMark Murray 
200*e71b7053SJung-uk Kim int ocsp_main(int argc, char **argv)
2015c87c606SMark Murray {
202*e71b7053SJung-uk Kim     BIO *acbio = NULL, *cbio = NULL, *derbio = NULL, *out = NULL;
203*e71b7053SJung-uk Kim     const EVP_MD *cert_id_md = NULL, *rsign_md = NULL;
204*e71b7053SJung-uk Kim     STACK_OF(OPENSSL_STRING) *rsign_sigopts = NULL;
205*e71b7053SJung-uk Kim     int trailing_md = 0;
206*e71b7053SJung-uk Kim     CA_DB *rdb = NULL;
207*e71b7053SJung-uk Kim     EVP_PKEY *key = NULL, *rkey = NULL;
208*e71b7053SJung-uk Kim     OCSP_BASICRESP *bs = NULL;
2095c87c606SMark Murray     OCSP_REQUEST *req = NULL;
2105c87c606SMark Murray     OCSP_RESPONSE *resp = NULL;
211*e71b7053SJung-uk Kim     STACK_OF(CONF_VALUE) *headers = NULL;
212*e71b7053SJung-uk Kim     STACK_OF(OCSP_CERTID) *ids = NULL;
213*e71b7053SJung-uk Kim     STACK_OF(OPENSSL_STRING) *reqnames = NULL;
214*e71b7053SJung-uk Kim     STACK_OF(X509) *sign_other = NULL, *verify_other = NULL, *rother = NULL;
215*e71b7053SJung-uk Kim     STACK_OF(X509) *issuers = NULL;
2165c87c606SMark Murray     X509 *issuer = NULL, *cert = NULL;
217*e71b7053SJung-uk Kim     STACK_OF(X509) *rca_cert = NULL;
2185c87c606SMark Murray     X509 *signer = NULL, *rsigner = NULL;
2195c87c606SMark Murray     X509_STORE *store = NULL;
2207bded2dbSJung-uk Kim     X509_VERIFY_PARAM *vpm = NULL;
221*e71b7053SJung-uk Kim     const char *CAfile = NULL, *CApath = NULL;
222*e71b7053SJung-uk Kim     char *header, *value;
223*e71b7053SJung-uk Kim     char *host = NULL, *port = NULL, *path = "/", *outfile = NULL;
224*e71b7053SJung-uk Kim     char *rca_filename = NULL, *reqin = NULL, *respin = NULL;
225*e71b7053SJung-uk Kim     char *reqout = NULL, *respout = NULL, *ridx_filename = NULL;
226*e71b7053SJung-uk Kim     char *rsignfile = NULL, *rkeyfile = NULL;
2275c87c606SMark Murray     char *sign_certfile = NULL, *verify_certfile = NULL, *rcertfile = NULL;
228*e71b7053SJung-uk Kim     char *signfile = NULL, *keyfile = NULL;
229*e71b7053SJung-uk Kim     char *thost = NULL, *tport = NULL, *tpath = NULL;
230*e71b7053SJung-uk Kim     int noCAfile = 0, noCApath = 0;
231*e71b7053SJung-uk Kim     int accept_count = -1, add_nonce = 1, noverify = 0, use_ssl = -1;
232*e71b7053SJung-uk Kim     int vpmtouched = 0, badsig = 0, i, ignore_err = 0, nmin = 0, ndays = -1;
233*e71b7053SJung-uk Kim     int req_text = 0, resp_text = 0, ret = 1;
234*e71b7053SJung-uk Kim     int req_timeout = -1;
235*e71b7053SJung-uk Kim     long nsec = MAX_VALIDITY_PERIOD, maxage = -1;
2365c87c606SMark Murray     unsigned long sign_flags = 0, verify_flags = 0, rflags = 0;
237*e71b7053SJung-uk Kim     OPTION_CHOICE o;
2385c87c606SMark Murray 
2391f13597dSJung-uk Kim     reqnames = sk_OPENSSL_STRING_new_null();
240*e71b7053SJung-uk Kim     if (reqnames == NULL)
241*e71b7053SJung-uk Kim         goto end;
2425c87c606SMark Murray     ids = sk_OCSP_CERTID_new_null();
243*e71b7053SJung-uk Kim     if (ids == NULL)
244*e71b7053SJung-uk Kim         goto end;
245*e71b7053SJung-uk Kim     if ((vpm = X509_VERIFY_PARAM_new()) == NULL)
246*e71b7053SJung-uk Kim         return 1;
247*e71b7053SJung-uk Kim 
248*e71b7053SJung-uk Kim     prog = opt_init(argc, argv, ocsp_options);
249*e71b7053SJung-uk Kim     while ((o = opt_next()) != OPT_EOF) {
250*e71b7053SJung-uk Kim         switch (o) {
251*e71b7053SJung-uk Kim         case OPT_EOF:
252*e71b7053SJung-uk Kim         case OPT_ERR:
253*e71b7053SJung-uk Kim  opthelp:
254*e71b7053SJung-uk Kim             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
255*e71b7053SJung-uk Kim             goto end;
256*e71b7053SJung-uk Kim         case OPT_HELP:
257*e71b7053SJung-uk Kim             ret = 0;
258*e71b7053SJung-uk Kim             opt_help(ocsp_options);
259*e71b7053SJung-uk Kim             goto end;
260*e71b7053SJung-uk Kim         case OPT_OUTFILE:
261*e71b7053SJung-uk Kim             outfile = opt_arg();
262*e71b7053SJung-uk Kim             break;
263*e71b7053SJung-uk Kim         case OPT_TIMEOUT:
264*e71b7053SJung-uk Kim #ifndef OPENSSL_NO_SOCK
265*e71b7053SJung-uk Kim             req_timeout = atoi(opt_arg());
266*e71b7053SJung-uk Kim #endif
267*e71b7053SJung-uk Kim             break;
268*e71b7053SJung-uk Kim         case OPT_URL:
26994ad176cSJung-uk Kim             OPENSSL_free(thost);
27094ad176cSJung-uk Kim             OPENSSL_free(tport);
27194ad176cSJung-uk Kim             OPENSSL_free(tpath);
2727bded2dbSJung-uk Kim             thost = tport = tpath = NULL;
273*e71b7053SJung-uk Kim             if (!OCSP_parse_url(opt_arg(), &host, &port, &path, &use_ssl)) {
274*e71b7053SJung-uk Kim                 BIO_printf(bio_err, "%s Error parsing URL\n", prog);
275*e71b7053SJung-uk Kim                 goto end;
2765c87c606SMark Murray             }
27794ad176cSJung-uk Kim             thost = host;
27894ad176cSJung-uk Kim             tport = port;
27994ad176cSJung-uk Kim             tpath = path;
280*e71b7053SJung-uk Kim             break;
281*e71b7053SJung-uk Kim         case OPT_HOST:
282*e71b7053SJung-uk Kim             host = opt_arg();
283*e71b7053SJung-uk Kim             break;
284*e71b7053SJung-uk Kim         case OPT_PORT:
285*e71b7053SJung-uk Kim             port = opt_arg();
286*e71b7053SJung-uk Kim             break;
287*e71b7053SJung-uk Kim         case OPT_IGNORE_ERR:
28850ef0093SJacques Vidrine             ignore_err = 1;
289*e71b7053SJung-uk Kim             break;
290*e71b7053SJung-uk Kim         case OPT_NOVERIFY:
2915c87c606SMark Murray             noverify = 1;
292*e71b7053SJung-uk Kim             break;
293*e71b7053SJung-uk Kim         case OPT_NONCE:
2945c87c606SMark Murray             add_nonce = 2;
295*e71b7053SJung-uk Kim             break;
296*e71b7053SJung-uk Kim         case OPT_NO_NONCE:
2975c87c606SMark Murray             add_nonce = 0;
298*e71b7053SJung-uk Kim             break;
299*e71b7053SJung-uk Kim         case OPT_RESP_NO_CERTS:
3005c87c606SMark Murray             rflags |= OCSP_NOCERTS;
301*e71b7053SJung-uk Kim             break;
302*e71b7053SJung-uk Kim         case OPT_RESP_KEY_ID:
3035c87c606SMark Murray             rflags |= OCSP_RESPID_KEY;
304*e71b7053SJung-uk Kim             break;
305*e71b7053SJung-uk Kim         case OPT_NO_CERTS:
3065c87c606SMark Murray             sign_flags |= OCSP_NOCERTS;
307*e71b7053SJung-uk Kim             break;
308*e71b7053SJung-uk Kim         case OPT_NO_SIGNATURE_VERIFY:
3095c87c606SMark Murray             verify_flags |= OCSP_NOSIGS;
310*e71b7053SJung-uk Kim             break;
311*e71b7053SJung-uk Kim         case OPT_NO_CERT_VERIFY:
3125c87c606SMark Murray             verify_flags |= OCSP_NOVERIFY;
313*e71b7053SJung-uk Kim             break;
314*e71b7053SJung-uk Kim         case OPT_NO_CHAIN:
3155c87c606SMark Murray             verify_flags |= OCSP_NOCHAIN;
316*e71b7053SJung-uk Kim             break;
317*e71b7053SJung-uk Kim         case OPT_NO_CERT_CHECKS:
3185c87c606SMark Murray             verify_flags |= OCSP_NOCHECKS;
319*e71b7053SJung-uk Kim             break;
320*e71b7053SJung-uk Kim         case OPT_NO_EXPLICIT:
3215c87c606SMark Murray             verify_flags |= OCSP_NOEXPLICIT;
322*e71b7053SJung-uk Kim             break;
323*e71b7053SJung-uk Kim         case OPT_TRUST_OTHER:
3245c87c606SMark Murray             verify_flags |= OCSP_TRUSTOTHER;
325*e71b7053SJung-uk Kim             break;
326*e71b7053SJung-uk Kim         case OPT_NO_INTERN:
3275c87c606SMark Murray             verify_flags |= OCSP_NOINTERN;
328*e71b7053SJung-uk Kim             break;
329*e71b7053SJung-uk Kim         case OPT_BADSIG:
3307bded2dbSJung-uk Kim             badsig = 1;
331*e71b7053SJung-uk Kim             break;
332*e71b7053SJung-uk Kim         case OPT_TEXT:
333*e71b7053SJung-uk Kim             req_text = resp_text = 1;
334*e71b7053SJung-uk Kim             break;
335*e71b7053SJung-uk Kim         case OPT_REQ_TEXT:
3365c87c606SMark Murray             req_text = 1;
337*e71b7053SJung-uk Kim             break;
338*e71b7053SJung-uk Kim         case OPT_RESP_TEXT:
3395c87c606SMark Murray             resp_text = 1;
340*e71b7053SJung-uk Kim             break;
341*e71b7053SJung-uk Kim         case OPT_REQIN:
342*e71b7053SJung-uk Kim             reqin = opt_arg();
343*e71b7053SJung-uk Kim             break;
344*e71b7053SJung-uk Kim         case OPT_RESPIN:
345*e71b7053SJung-uk Kim             respin = opt_arg();
346*e71b7053SJung-uk Kim             break;
347*e71b7053SJung-uk Kim         case OPT_SIGNER:
348*e71b7053SJung-uk Kim             signfile = opt_arg();
349*e71b7053SJung-uk Kim             break;
350*e71b7053SJung-uk Kim         case OPT_VAFILE:
351*e71b7053SJung-uk Kim             verify_certfile = opt_arg();
3525c87c606SMark Murray             verify_flags |= OCSP_TRUSTOTHER;
353*e71b7053SJung-uk Kim             break;
354*e71b7053SJung-uk Kim         case OPT_SIGN_OTHER:
355*e71b7053SJung-uk Kim             sign_certfile = opt_arg();
356*e71b7053SJung-uk Kim             break;
357*e71b7053SJung-uk Kim         case OPT_VERIFY_OTHER:
358*e71b7053SJung-uk Kim             verify_certfile = opt_arg();
359*e71b7053SJung-uk Kim             break;
360*e71b7053SJung-uk Kim         case OPT_CAFILE:
361*e71b7053SJung-uk Kim             CAfile = opt_arg();
362*e71b7053SJung-uk Kim             break;
363*e71b7053SJung-uk Kim         case OPT_CAPATH:
364*e71b7053SJung-uk Kim             CApath = opt_arg();
365*e71b7053SJung-uk Kim             break;
366*e71b7053SJung-uk Kim         case OPT_NOCAFILE:
367*e71b7053SJung-uk Kim             noCAfile = 1;
368*e71b7053SJung-uk Kim             break;
369*e71b7053SJung-uk Kim         case OPT_NOCAPATH:
370*e71b7053SJung-uk Kim             noCApath = 1;
371*e71b7053SJung-uk Kim             break;
372*e71b7053SJung-uk Kim         case OPT_V_CASES:
373*e71b7053SJung-uk Kim             if (!opt_verify(o, vpm))
3747bded2dbSJung-uk Kim                 goto end;
375*e71b7053SJung-uk Kim             vpmtouched++;
376*e71b7053SJung-uk Kim             break;
377*e71b7053SJung-uk Kim         case OPT_VALIDITY_PERIOD:
378*e71b7053SJung-uk Kim             opt_long(opt_arg(), &nsec);
379*e71b7053SJung-uk Kim             break;
380*e71b7053SJung-uk Kim         case OPT_STATUS_AGE:
381*e71b7053SJung-uk Kim             opt_long(opt_arg(), &maxage);
382*e71b7053SJung-uk Kim             break;
383*e71b7053SJung-uk Kim         case OPT_SIGNKEY:
384*e71b7053SJung-uk Kim             keyfile = opt_arg();
385*e71b7053SJung-uk Kim             break;
386*e71b7053SJung-uk Kim         case OPT_REQOUT:
387*e71b7053SJung-uk Kim             reqout = opt_arg();
388*e71b7053SJung-uk Kim             break;
389*e71b7053SJung-uk Kim         case OPT_RESPOUT:
390*e71b7053SJung-uk Kim             respout = opt_arg();
391*e71b7053SJung-uk Kim             break;
392*e71b7053SJung-uk Kim         case OPT_PATH:
393*e71b7053SJung-uk Kim             path = opt_arg();
394*e71b7053SJung-uk Kim             break;
395*e71b7053SJung-uk Kim         case OPT_ISSUER:
396*e71b7053SJung-uk Kim             issuer = load_cert(opt_arg(), FORMAT_PEM, "issuer certificate");
397*e71b7053SJung-uk Kim             if (issuer == NULL)
3986f9291ceSJung-uk Kim                 goto end;
399*e71b7053SJung-uk Kim             if (issuers == NULL) {
400*e71b7053SJung-uk Kim                 if ((issuers = sk_X509_new_null()) == NULL)
401*e71b7053SJung-uk Kim                     goto end;
402*e71b7053SJung-uk Kim             }
403*e71b7053SJung-uk Kim             sk_X509_push(issuers, issuer);
404*e71b7053SJung-uk Kim             break;
405*e71b7053SJung-uk Kim         case OPT_CERT:
4065c87c606SMark Murray             X509_free(cert);
407*e71b7053SJung-uk Kim             cert = load_cert(opt_arg(), FORMAT_PEM, "certificate");
408*e71b7053SJung-uk Kim             if (cert == NULL)
4096f9291ceSJung-uk Kim                 goto end;
410*e71b7053SJung-uk Kim             if (cert_id_md == NULL)
4116f9291ceSJung-uk Kim                 cert_id_md = EVP_sha1();
4121f13597dSJung-uk Kim             if (!add_ocsp_cert(&req, cert, cert_id_md, issuer, ids))
4135c87c606SMark Murray                 goto end;
414*e71b7053SJung-uk Kim             if (!sk_OPENSSL_STRING_push(reqnames, opt_arg()))
4155c87c606SMark Murray                 goto end;
416*e71b7053SJung-uk Kim             trailing_md = 0;
417*e71b7053SJung-uk Kim             break;
418*e71b7053SJung-uk Kim         case OPT_SERIAL:
419*e71b7053SJung-uk Kim             if (cert_id_md == NULL)
4206f9291ceSJung-uk Kim                 cert_id_md = EVP_sha1();
421*e71b7053SJung-uk Kim             if (!add_ocsp_serial(&req, opt_arg(), cert_id_md, issuer, ids))
4225c87c606SMark Murray                 goto end;
423*e71b7053SJung-uk Kim             if (!sk_OPENSSL_STRING_push(reqnames, opt_arg()))
4245c87c606SMark Murray                 goto end;
425*e71b7053SJung-uk Kim             trailing_md = 0;
426*e71b7053SJung-uk Kim             break;
427*e71b7053SJung-uk Kim         case OPT_INDEX:
428*e71b7053SJung-uk Kim             ridx_filename = opt_arg();
429*e71b7053SJung-uk Kim             break;
430*e71b7053SJung-uk Kim         case OPT_CA:
431*e71b7053SJung-uk Kim             rca_filename = opt_arg();
432*e71b7053SJung-uk Kim             break;
433*e71b7053SJung-uk Kim         case OPT_NMIN:
434*e71b7053SJung-uk Kim             opt_int(opt_arg(), &nmin);
4355c87c606SMark Murray             if (ndays == -1)
4365c87c606SMark Murray                 ndays = 0;
437*e71b7053SJung-uk Kim             break;
438*e71b7053SJung-uk Kim         case OPT_REQUEST:
439*e71b7053SJung-uk Kim             opt_int(opt_arg(), &accept_count);
440*e71b7053SJung-uk Kim             break;
441*e71b7053SJung-uk Kim         case OPT_NDAYS:
442*e71b7053SJung-uk Kim             ndays = atoi(opt_arg());
443*e71b7053SJung-uk Kim             break;
444*e71b7053SJung-uk Kim         case OPT_RSIGNER:
445*e71b7053SJung-uk Kim             rsignfile = opt_arg();
446*e71b7053SJung-uk Kim             break;
447*e71b7053SJung-uk Kim         case OPT_RKEY:
448*e71b7053SJung-uk Kim             rkeyfile = opt_arg();
449*e71b7053SJung-uk Kim             break;
450*e71b7053SJung-uk Kim         case OPT_ROTHER:
451*e71b7053SJung-uk Kim             rcertfile = opt_arg();
452*e71b7053SJung-uk Kim             break;
453*e71b7053SJung-uk Kim         case OPT_RMD:   /* Response MessageDigest */
454*e71b7053SJung-uk Kim             if (!opt_md(opt_arg(), &rsign_md))
455*e71b7053SJung-uk Kim                 goto end;
456*e71b7053SJung-uk Kim             break;
457*e71b7053SJung-uk Kim         case OPT_RSIGOPT:
458*e71b7053SJung-uk Kim             if (rsign_sigopts == NULL)
459*e71b7053SJung-uk Kim                 rsign_sigopts = sk_OPENSSL_STRING_new_null();
460*e71b7053SJung-uk Kim             if (rsign_sigopts == NULL || !sk_OPENSSL_STRING_push(rsign_sigopts, opt_arg()))
461*e71b7053SJung-uk Kim                 goto end;
462*e71b7053SJung-uk Kim             break;
463*e71b7053SJung-uk Kim         case OPT_HEADER:
464*e71b7053SJung-uk Kim             header = opt_arg();
465*e71b7053SJung-uk Kim             value = strchr(header, '=');
466*e71b7053SJung-uk Kim             if (value == NULL) {
467*e71b7053SJung-uk Kim                 BIO_printf(bio_err, "Missing = in header key=value\n");
468*e71b7053SJung-uk Kim                 goto opthelp;
4695c87c606SMark Murray             }
470*e71b7053SJung-uk Kim             *value++ = '\0';
471*e71b7053SJung-uk Kim             if (!X509V3_add_value(header, value, &headers))
472*e71b7053SJung-uk Kim                 goto end;
473*e71b7053SJung-uk Kim             break;
474*e71b7053SJung-uk Kim         case OPT_MD:
475*e71b7053SJung-uk Kim             if (trailing_md) {
476*e71b7053SJung-uk Kim                 BIO_printf(bio_err,
477*e71b7053SJung-uk Kim                            "%s: Digest must be before -cert or -serial\n",
478*e71b7053SJung-uk Kim                            prog);
479*e71b7053SJung-uk Kim                 goto opthelp;
4805c87c606SMark Murray             }
481*e71b7053SJung-uk Kim             if (!opt_md(opt_unknown(), &cert_id_md))
482*e71b7053SJung-uk Kim                 goto opthelp;
483*e71b7053SJung-uk Kim             trailing_md = 1;
484*e71b7053SJung-uk Kim             break;
485*e71b7053SJung-uk Kim         case OPT_MULTI:
486*e71b7053SJung-uk Kim # ifdef OCSP_DAEMON
487*e71b7053SJung-uk Kim             multi = atoi(opt_arg());
488*e71b7053SJung-uk Kim # endif
489*e71b7053SJung-uk Kim             break;
4901f13597dSJung-uk Kim         }
4915c87c606SMark Murray     }
492*e71b7053SJung-uk Kim     if (trailing_md) {
493*e71b7053SJung-uk Kim         BIO_printf(bio_err, "%s: Digest must be before -cert or -serial\n",
494*e71b7053SJung-uk Kim                    prog);
495*e71b7053SJung-uk Kim         goto opthelp;
496*e71b7053SJung-uk Kim     }
497*e71b7053SJung-uk Kim     argc = opt_num_rest();
498*e71b7053SJung-uk Kim     if (argc != 0)
499*e71b7053SJung-uk Kim         goto opthelp;
5005c87c606SMark Murray 
5015c87c606SMark Murray     /* Have we anything to do? */
502*e71b7053SJung-uk Kim     if (req == NULL && reqin == NULL
503*e71b7053SJung-uk Kim         && respin == NULL && !(port != NULL && ridx_filename != NULL))
504*e71b7053SJung-uk Kim         goto opthelp;
5055c87c606SMark Murray 
506*e71b7053SJung-uk Kim     out = bio_open_default(outfile, 'w', FORMAT_TEXT);
507*e71b7053SJung-uk Kim     if (out == NULL)
5085c87c606SMark Murray         goto end;
5095c87c606SMark Murray 
510*e71b7053SJung-uk Kim     if (req == NULL && (add_nonce != 2))
5116f9291ceSJung-uk Kim         add_nonce = 0;
5125c87c606SMark Murray 
513*e71b7053SJung-uk Kim     if (req == NULL && reqin != NULL) {
514*e71b7053SJung-uk Kim         derbio = bio_open_default(reqin, 'r', FORMAT_ASN1);
515*e71b7053SJung-uk Kim         if (derbio == NULL)
5165c87c606SMark Murray             goto end;
5175c87c606SMark Murray         req = d2i_OCSP_REQUEST_bio(derbio, NULL);
5185c87c606SMark Murray         BIO_free(derbio);
519*e71b7053SJung-uk Kim         if (req == NULL) {
5205c87c606SMark Murray             BIO_printf(bio_err, "Error reading OCSP request\n");
5215c87c606SMark Murray             goto end;
5225c87c606SMark Murray         }
5235c87c606SMark Murray     }
5245c87c606SMark Murray 
525*e71b7053SJung-uk Kim     if (req == NULL && port != NULL) {
5265c87c606SMark Murray         acbio = init_responder(port);
527*e71b7053SJung-uk Kim         if (acbio == NULL)
5285c87c606SMark Murray             goto end;
5295c87c606SMark Murray     }
5305c87c606SMark Murray 
531*e71b7053SJung-uk Kim     if (rsignfile != NULL) {
532*e71b7053SJung-uk Kim         if (rkeyfile == NULL)
5336f9291ceSJung-uk Kim             rkeyfile = rsignfile;
534*e71b7053SJung-uk Kim         rsigner = load_cert(rsignfile, FORMAT_PEM, "responder certificate");
535*e71b7053SJung-uk Kim         if (rsigner == NULL) {
5365c87c606SMark Murray             BIO_printf(bio_err, "Error loading responder certificate\n");
5375c87c606SMark Murray             goto end;
5385c87c606SMark Murray         }
539*e71b7053SJung-uk Kim         if (!load_certs(rca_filename, &rca_cert, FORMAT_PEM,
540*e71b7053SJung-uk Kim                         NULL, "CA certificate"))
541*e71b7053SJung-uk Kim             goto end;
542*e71b7053SJung-uk Kim         if (rcertfile != NULL) {
543*e71b7053SJung-uk Kim             if (!load_certs(rcertfile, &rother, FORMAT_PEM, NULL,
544*e71b7053SJung-uk Kim                             "responder other certificates"))
5456f9291ceSJung-uk Kim                 goto end;
5465c87c606SMark Murray         }
547*e71b7053SJung-uk Kim         rkey = load_key(rkeyfile, FORMAT_PEM, 0, NULL, NULL,
5485c87c606SMark Murray                         "responder private key");
549*e71b7053SJung-uk Kim         if (rkey == NULL)
5505c87c606SMark Murray             goto end;
5515c87c606SMark Murray     }
552*e71b7053SJung-uk Kim 
553*e71b7053SJung-uk Kim     if (ridx_filename != NULL
554*e71b7053SJung-uk Kim         && (rkey == NULL || rsigner == NULL || rca_cert == NULL)) {
555*e71b7053SJung-uk Kim         BIO_printf(bio_err,
556*e71b7053SJung-uk Kim                    "Responder mode requires certificate, key, and CA.\n");
557*e71b7053SJung-uk Kim         goto end;
558*e71b7053SJung-uk Kim     }
559*e71b7053SJung-uk Kim 
560*e71b7053SJung-uk Kim     if (ridx_filename != NULL) {
561*e71b7053SJung-uk Kim         rdb = load_index(ridx_filename, NULL);
562*e71b7053SJung-uk Kim         if (rdb == NULL || index_index(rdb) <= 0) {
563*e71b7053SJung-uk Kim             ret = 1;
564*e71b7053SJung-uk Kim             goto end;
565*e71b7053SJung-uk Kim         }
566*e71b7053SJung-uk Kim     }
567*e71b7053SJung-uk Kim 
568*e71b7053SJung-uk Kim # ifdef OCSP_DAEMON
569*e71b7053SJung-uk Kim     if (multi && acbio != NULL)
570*e71b7053SJung-uk Kim         spawn_loop();
571*e71b7053SJung-uk Kim     if (acbio != NULL && req_timeout > 0)
572*e71b7053SJung-uk Kim         signal(SIGALRM, sock_timeout);
573*e71b7053SJung-uk Kim #endif
574*e71b7053SJung-uk Kim 
575*e71b7053SJung-uk Kim     if (acbio != NULL)
576*e71b7053SJung-uk Kim         log_message(LOG_INFO, "waiting for OCSP client connections...");
5775c87c606SMark Murray 
5785c87c606SMark Murray redo_accept:
5795c87c606SMark Murray 
580*e71b7053SJung-uk Kim     if (acbio != NULL) {
581*e71b7053SJung-uk Kim # ifdef OCSP_DAEMON
582*e71b7053SJung-uk Kim         if (index_changed(rdb)) {
583*e71b7053SJung-uk Kim             CA_DB *newrdb = load_index(ridx_filename, NULL);
584*e71b7053SJung-uk Kim 
585*e71b7053SJung-uk Kim             if (newrdb != NULL && index_index(newrdb) > 0) {
586*e71b7053SJung-uk Kim                 free_index(rdb);
587*e71b7053SJung-uk Kim                 rdb = newrdb;
588*e71b7053SJung-uk Kim             } else {
589*e71b7053SJung-uk Kim                 free_index(newrdb);
590*e71b7053SJung-uk Kim                 log_message(LOG_ERR, "error reloading updated index: %s",
591*e71b7053SJung-uk Kim                             ridx_filename);
592*e71b7053SJung-uk Kim             }
593*e71b7053SJung-uk Kim         }
594*e71b7053SJung-uk Kim # endif
595*e71b7053SJung-uk Kim 
596*e71b7053SJung-uk Kim         req = NULL;
597*e71b7053SJung-uk Kim         if (!do_responder(&req, &cbio, acbio, req_timeout))
598*e71b7053SJung-uk Kim             goto redo_accept;
599*e71b7053SJung-uk Kim 
600*e71b7053SJung-uk Kim         if (req == NULL) {
6016f9291ceSJung-uk Kim             resp =
6026f9291ceSJung-uk Kim                 OCSP_response_create(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST,
6036f9291ceSJung-uk Kim                                      NULL);
6045c87c606SMark Murray             send_ocsp_response(cbio, resp);
6055c87c606SMark Murray             goto done_resp;
6065c87c606SMark Murray         }
6075c87c606SMark Murray     }
6085c87c606SMark Murray 
609*e71b7053SJung-uk Kim     if (req == NULL
610*e71b7053SJung-uk Kim         && (signfile != NULL || reqout != NULL
611*e71b7053SJung-uk Kim             || host != NULL || add_nonce || ridx_filename != NULL)) {
6125c87c606SMark Murray         BIO_printf(bio_err, "Need an OCSP request for this operation!\n");
6135c87c606SMark Murray         goto end;
6145c87c606SMark Murray     }
6155c87c606SMark Murray 
616*e71b7053SJung-uk Kim     if (req != NULL && add_nonce)
6176f9291ceSJung-uk Kim         OCSP_request_add1_nonce(req, NULL, -1);
6185c87c606SMark Murray 
619*e71b7053SJung-uk Kim     if (signfile != NULL) {
620*e71b7053SJung-uk Kim         if (keyfile == NULL)
6216f9291ceSJung-uk Kim             keyfile = signfile;
622*e71b7053SJung-uk Kim         signer = load_cert(signfile, FORMAT_PEM, "signer certificate");
623*e71b7053SJung-uk Kim         if (signer == NULL) {
6245c87c606SMark Murray             BIO_printf(bio_err, "Error loading signer certificate\n");
6255c87c606SMark Murray             goto end;
6265c87c606SMark Murray         }
627*e71b7053SJung-uk Kim         if (sign_certfile != NULL) {
628*e71b7053SJung-uk Kim             if (!load_certs(sign_certfile, &sign_other, FORMAT_PEM, NULL,
629*e71b7053SJung-uk Kim                             "signer certificates"))
6306f9291ceSJung-uk Kim                 goto end;
6315c87c606SMark Murray         }
632*e71b7053SJung-uk Kim         key = load_key(keyfile, FORMAT_PEM, 0, NULL, NULL,
6335c87c606SMark Murray                        "signer private key");
634*e71b7053SJung-uk Kim         if (key == NULL)
6355c87c606SMark Murray             goto end;
6361f13597dSJung-uk Kim 
6376f9291ceSJung-uk Kim         if (!OCSP_request_sign
6386f9291ceSJung-uk Kim             (req, signer, key, NULL, sign_other, sign_flags)) {
6395c87c606SMark Murray             BIO_printf(bio_err, "Error signing OCSP request\n");
6405c87c606SMark Murray             goto end;
6415c87c606SMark Murray         }
6425c87c606SMark Murray     }
6435c87c606SMark Murray 
644*e71b7053SJung-uk Kim     if (req_text && req != NULL)
6456f9291ceSJung-uk Kim         OCSP_REQUEST_print(out, req, 0);
6465c87c606SMark Murray 
647*e71b7053SJung-uk Kim     if (reqout != NULL) {
648*e71b7053SJung-uk Kim         derbio = bio_open_default(reqout, 'w', FORMAT_ASN1);
649*e71b7053SJung-uk Kim         if (derbio == NULL)
6505c87c606SMark Murray             goto end;
6515c87c606SMark Murray         i2d_OCSP_REQUEST_bio(derbio, req);
6525c87c606SMark Murray         BIO_free(derbio);
6535c87c606SMark Murray     }
6545c87c606SMark Murray 
655*e71b7053SJung-uk Kim     if (rdb != NULL) {
656*e71b7053SJung-uk Kim         make_ocsp_response(bio_err, &resp, req, rdb, rca_cert, rsigner, rkey,
657*e71b7053SJung-uk Kim                                rsign_md, rsign_sigopts, rother, rflags, nmin, ndays, badsig);
658*e71b7053SJung-uk Kim         if (cbio != NULL)
6595c87c606SMark Murray             send_ocsp_response(cbio, resp);
660*e71b7053SJung-uk Kim     } else if (host != NULL) {
661fceca8a3SJacques Vidrine # ifndef OPENSSL_NO_SOCK
662*e71b7053SJung-uk Kim         resp = process_responder(req, host, path,
6631f13597dSJung-uk Kim                                  port, use_ssl, headers, req_timeout);
664*e71b7053SJung-uk Kim         if (resp == NULL)
665db522d3aSSimon L. B. Nielsen             goto end;
666fceca8a3SJacques Vidrine # else
6676f9291ceSJung-uk Kim         BIO_printf(bio_err,
6686f9291ceSJung-uk Kim                    "Error creating connect BIO - sockets not supported.\n");
669fceca8a3SJacques Vidrine         goto end;
670fceca8a3SJacques Vidrine # endif
671*e71b7053SJung-uk Kim     } else if (respin != NULL) {
672*e71b7053SJung-uk Kim         derbio = bio_open_default(respin, 'r', FORMAT_ASN1);
673*e71b7053SJung-uk Kim         if (derbio == NULL)
6745c87c606SMark Murray             goto end;
6755c87c606SMark Murray         resp = d2i_OCSP_RESPONSE_bio(derbio, NULL);
6765c87c606SMark Murray         BIO_free(derbio);
677*e71b7053SJung-uk Kim         if (resp == NULL) {
6785c87c606SMark Murray             BIO_printf(bio_err, "Error reading OCSP response\n");
6795c87c606SMark Murray             goto end;
6805c87c606SMark Murray         }
6816f9291ceSJung-uk Kim     } else {
6825c87c606SMark Murray         ret = 0;
6835c87c606SMark Murray         goto end;
6845c87c606SMark Murray     }
6855c87c606SMark Murray 
6865c87c606SMark Murray  done_resp:
6875c87c606SMark Murray 
688*e71b7053SJung-uk Kim     if (respout != NULL) {
689*e71b7053SJung-uk Kim         derbio = bio_open_default(respout, 'w', FORMAT_ASN1);
690*e71b7053SJung-uk Kim         if (derbio == NULL)
6915c87c606SMark Murray             goto end;
6925c87c606SMark Murray         i2d_OCSP_RESPONSE_bio(derbio, resp);
6935c87c606SMark Murray         BIO_free(derbio);
6945c87c606SMark Murray     }
6955c87c606SMark Murray 
6965c87c606SMark Murray     i = OCSP_response_status(resp);
6976f9291ceSJung-uk Kim     if (i != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
6983b4e3dcbSSimon L. B. Nielsen         BIO_printf(out, "Responder Error: %s (%d)\n",
6995c87c606SMark Murray                    OCSP_response_status_str(i), i);
700*e71b7053SJung-uk Kim         if (!ignore_err)
7015c87c606SMark Murray                 goto end;
7025c87c606SMark Murray     }
7035c87c606SMark Murray 
7046f9291ceSJung-uk Kim     if (resp_text)
7056f9291ceSJung-uk Kim         OCSP_RESPONSE_print(out, resp, 0);
7065c87c606SMark Murray 
7075c87c606SMark Murray     /* If running as responder don't verify our own response */
708*e71b7053SJung-uk Kim     if (cbio != NULL) {
709*e71b7053SJung-uk Kim         /* If not unlimited, see if we took all we should. */
710*e71b7053SJung-uk Kim         if (accept_count != -1 && --accept_count <= 0) {
711*e71b7053SJung-uk Kim             ret = 0;
712*e71b7053SJung-uk Kim             goto end;
713*e71b7053SJung-uk Kim         }
7145c87c606SMark Murray         BIO_free_all(cbio);
7155c87c606SMark Murray         cbio = NULL;
7165c87c606SMark Murray         OCSP_REQUEST_free(req);
7175c87c606SMark Murray         req = NULL;
7185c87c606SMark Murray         OCSP_RESPONSE_free(resp);
7195c87c606SMark Murray         resp = NULL;
7205c87c606SMark Murray         goto redo_accept;
7215c87c606SMark Murray     }
722*e71b7053SJung-uk Kim     if (ridx_filename != NULL) {
7237bded2dbSJung-uk Kim         ret = 0;
7245c87c606SMark Murray         goto end;
7255c87c606SMark Murray     }
7265c87c606SMark Murray 
727*e71b7053SJung-uk Kim     if (store == NULL) {
728*e71b7053SJung-uk Kim         store = setup_verify(CAfile, CApath, noCAfile, noCApath);
7295c87c606SMark Murray         if (!store)
7305c87c606SMark Murray             goto end;
731*e71b7053SJung-uk Kim     }
732*e71b7053SJung-uk Kim     if (vpmtouched)
7337bded2dbSJung-uk Kim         X509_STORE_set1_param(store, vpm);
734*e71b7053SJung-uk Kim     if (verify_certfile != NULL) {
735*e71b7053SJung-uk Kim         if (!load_certs(verify_certfile, &verify_other, FORMAT_PEM, NULL,
736*e71b7053SJung-uk Kim                         "validator certificate"))
7376f9291ceSJung-uk Kim             goto end;
7385c87c606SMark Murray     }
7395c87c606SMark Murray 
7405c87c606SMark Murray     bs = OCSP_response_get1_basic(resp);
741*e71b7053SJung-uk Kim     if (bs == NULL) {
7425c87c606SMark Murray         BIO_printf(bio_err, "Error parsing response\n");
7435c87c606SMark Murray         goto end;
7445c87c606SMark Murray     }
7455c87c606SMark Murray 
7467bded2dbSJung-uk Kim     ret = 0;
7477bded2dbSJung-uk Kim 
7486f9291ceSJung-uk Kim     if (!noverify) {
749*e71b7053SJung-uk Kim         if (req != NULL && ((i = OCSP_check_nonce(req, bs)) <= 0)) {
7505c87c606SMark Murray             if (i == -1)
7515c87c606SMark Murray                 BIO_printf(bio_err, "WARNING: no nonce in response\n");
7526f9291ceSJung-uk Kim             else {
7535c87c606SMark Murray                 BIO_printf(bio_err, "Nonce Verify error\n");
7547bded2dbSJung-uk Kim                 ret = 1;
7555c87c606SMark Murray                 goto end;
7565c87c606SMark Murray             }
7575c87c606SMark Murray         }
7585c87c606SMark Murray 
7595c87c606SMark Murray         i = OCSP_basic_verify(bs, verify_other, store, verify_flags);
760*e71b7053SJung-uk Kim         if (i <= 0 && issuers) {
761*e71b7053SJung-uk Kim             i = OCSP_basic_verify(bs, issuers, store, OCSP_TRUSTOTHER);
762*e71b7053SJung-uk Kim             if (i > 0)
763*e71b7053SJung-uk Kim                 ERR_clear_error();
764*e71b7053SJung-uk Kim         }
7656f9291ceSJung-uk Kim         if (i <= 0) {
7663b4e3dcbSSimon L. B. Nielsen             BIO_printf(bio_err, "Response Verify Failure\n");
7675c87c606SMark Murray             ERR_print_errors(bio_err);
7687bded2dbSJung-uk Kim             ret = 1;
769*e71b7053SJung-uk Kim         } else {
7705c87c606SMark Murray             BIO_printf(bio_err, "Response verify OK\n");
771*e71b7053SJung-uk Kim         }
7725c87c606SMark Murray     }
7735c87c606SMark Murray 
774*e71b7053SJung-uk Kim     print_ocsp_summary(out, bs, req, reqnames, ids, nsec, maxage);
7755c87c606SMark Murray 
7765c87c606SMark Murray  end:
7775c87c606SMark Murray     ERR_print_errors(bio_err);
7785c87c606SMark Murray     X509_free(signer);
7795c87c606SMark Murray     X509_STORE_free(store);
7807bded2dbSJung-uk Kim     X509_VERIFY_PARAM_free(vpm);
781*e71b7053SJung-uk Kim     sk_OPENSSL_STRING_free(rsign_sigopts);
7825c87c606SMark Murray     EVP_PKEY_free(key);
7835c87c606SMark Murray     EVP_PKEY_free(rkey);
7845c87c606SMark Murray     X509_free(cert);
785*e71b7053SJung-uk Kim     sk_X509_pop_free(issuers, X509_free);
7865c87c606SMark Murray     X509_free(rsigner);
787*e71b7053SJung-uk Kim     sk_X509_pop_free(rca_cert, X509_free);
788ced566fdSJacques Vidrine     free_index(rdb);
7895c87c606SMark Murray     BIO_free_all(cbio);
7905c87c606SMark Murray     BIO_free_all(acbio);
791*e71b7053SJung-uk Kim     BIO_free_all(out);
7925c87c606SMark Murray     OCSP_REQUEST_free(req);
7935c87c606SMark Murray     OCSP_RESPONSE_free(resp);
7945c87c606SMark Murray     OCSP_BASICRESP_free(bs);
7951f13597dSJung-uk Kim     sk_OPENSSL_STRING_free(reqnames);
7965c87c606SMark Murray     sk_OCSP_CERTID_free(ids);
7975c87c606SMark Murray     sk_X509_pop_free(sign_other, X509_free);
7985c87c606SMark Murray     sk_X509_pop_free(verify_other, X509_free);
7991f13597dSJung-uk Kim     sk_CONF_VALUE_pop_free(headers, X509V3_conf_free);
80094ad176cSJung-uk Kim     OPENSSL_free(thost);
80194ad176cSJung-uk Kim     OPENSSL_free(tport);
80294ad176cSJung-uk Kim     OPENSSL_free(tpath);
8035c87c606SMark Murray 
804*e71b7053SJung-uk Kim     return ret;
8055c87c606SMark Murray }
8065c87c606SMark Murray 
807*e71b7053SJung-uk Kim static void
808*e71b7053SJung-uk Kim log_message(int level, const char *fmt, ...)
809*e71b7053SJung-uk Kim {
810*e71b7053SJung-uk Kim     va_list ap;
811*e71b7053SJung-uk Kim 
812*e71b7053SJung-uk Kim     va_start(ap, fmt);
813*e71b7053SJung-uk Kim # ifdef OCSP_DAEMON
814*e71b7053SJung-uk Kim     if (multi) {
815*e71b7053SJung-uk Kim         char buf[1024];
816*e71b7053SJung-uk Kim         if (vsnprintf(buf, sizeof(buf), fmt, ap) > 0) {
817*e71b7053SJung-uk Kim             syslog(level, "%s", buf);
818*e71b7053SJung-uk Kim         }
819*e71b7053SJung-uk Kim         if (level >= LOG_ERR)
820*e71b7053SJung-uk Kim             ERR_print_errors_cb(print_syslog, &level);
821*e71b7053SJung-uk Kim     }
822*e71b7053SJung-uk Kim # endif
823*e71b7053SJung-uk Kim     if (!multi) {
824*e71b7053SJung-uk Kim         BIO_printf(bio_err, "%s: ", prog);
825*e71b7053SJung-uk Kim         BIO_vprintf(bio_err, fmt, ap);
826*e71b7053SJung-uk Kim         BIO_printf(bio_err, "\n");
827*e71b7053SJung-uk Kim     }
828*e71b7053SJung-uk Kim     va_end(ap);
829*e71b7053SJung-uk Kim }
830*e71b7053SJung-uk Kim 
831*e71b7053SJung-uk Kim # ifdef OCSP_DAEMON
832*e71b7053SJung-uk Kim 
833*e71b7053SJung-uk Kim static int print_syslog(const char *str, size_t len, void *levPtr)
834*e71b7053SJung-uk Kim {
835*e71b7053SJung-uk Kim     int level = *(int *)levPtr;
836*e71b7053SJung-uk Kim     int ilen = (len > MAXERRLEN) ? MAXERRLEN : len;
837*e71b7053SJung-uk Kim 
838*e71b7053SJung-uk Kim     syslog(level, "%.*s", ilen, str);
839*e71b7053SJung-uk Kim 
840*e71b7053SJung-uk Kim     return ilen;
841*e71b7053SJung-uk Kim }
842*e71b7053SJung-uk Kim 
843*e71b7053SJung-uk Kim static int index_changed(CA_DB *rdb)
844*e71b7053SJung-uk Kim {
845*e71b7053SJung-uk Kim     struct stat sb;
846*e71b7053SJung-uk Kim 
847*e71b7053SJung-uk Kim     if (rdb != NULL && stat(rdb->dbfname, &sb) != -1) {
848*e71b7053SJung-uk Kim         if (rdb->dbst.st_mtime != sb.st_mtime
849*e71b7053SJung-uk Kim             || rdb->dbst.st_ctime != sb.st_ctime
850*e71b7053SJung-uk Kim             || rdb->dbst.st_ino != sb.st_ino
851*e71b7053SJung-uk Kim             || rdb->dbst.st_dev != sb.st_dev) {
852*e71b7053SJung-uk Kim             syslog(LOG_INFO, "index file changed, reloading");
853*e71b7053SJung-uk Kim             return 1;
854*e71b7053SJung-uk Kim         }
855*e71b7053SJung-uk Kim     }
856*e71b7053SJung-uk Kim     return 0;
857*e71b7053SJung-uk Kim }
858*e71b7053SJung-uk Kim 
859*e71b7053SJung-uk Kim static void killall(int ret, pid_t *kidpids)
860*e71b7053SJung-uk Kim {
861*e71b7053SJung-uk Kim     int i;
862*e71b7053SJung-uk Kim 
863*e71b7053SJung-uk Kim     for (i = 0; i < multi; ++i)
864*e71b7053SJung-uk Kim         if (kidpids[i] != 0)
865*e71b7053SJung-uk Kim             (void)kill(kidpids[i], SIGTERM);
866*e71b7053SJung-uk Kim     sleep(1);
867*e71b7053SJung-uk Kim     exit(ret);
868*e71b7053SJung-uk Kim }
869*e71b7053SJung-uk Kim 
870*e71b7053SJung-uk Kim static int termsig = 0;
871*e71b7053SJung-uk Kim 
872*e71b7053SJung-uk Kim static void noteterm (int sig)
873*e71b7053SJung-uk Kim {
874*e71b7053SJung-uk Kim     termsig = sig;
875*e71b7053SJung-uk Kim }
876*e71b7053SJung-uk Kim 
877*e71b7053SJung-uk Kim /*
878*e71b7053SJung-uk Kim  * Loop spawning up to `multi` child processes, only child processes return
879*e71b7053SJung-uk Kim  * from this function.  The parent process loops until receiving a termination
880*e71b7053SJung-uk Kim  * signal, kills extant children and exits without returning.
881*e71b7053SJung-uk Kim  */
882*e71b7053SJung-uk Kim static void spawn_loop(void)
883*e71b7053SJung-uk Kim {
884*e71b7053SJung-uk Kim     pid_t *kidpids = NULL;
885*e71b7053SJung-uk Kim     int status;
886*e71b7053SJung-uk Kim     int procs = 0;
887*e71b7053SJung-uk Kim     int i;
888*e71b7053SJung-uk Kim 
889*e71b7053SJung-uk Kim     openlog(prog, LOG_PID, LOG_DAEMON);
890*e71b7053SJung-uk Kim 
891*e71b7053SJung-uk Kim     if (setpgid(0, 0)) {
892*e71b7053SJung-uk Kim         syslog(LOG_ERR, "fatal: error detaching from parent process group: %s",
893*e71b7053SJung-uk Kim                strerror(errno));
894*e71b7053SJung-uk Kim         exit(1);
895*e71b7053SJung-uk Kim     }
896*e71b7053SJung-uk Kim     kidpids = app_malloc(multi * sizeof(*kidpids), "child PID array");
897*e71b7053SJung-uk Kim     for (i = 0; i < multi; ++i)
898*e71b7053SJung-uk Kim         kidpids[i] = 0;
899*e71b7053SJung-uk Kim 
900*e71b7053SJung-uk Kim     signal(SIGINT, noteterm);
901*e71b7053SJung-uk Kim     signal(SIGTERM, noteterm);
902*e71b7053SJung-uk Kim 
903*e71b7053SJung-uk Kim     while (termsig == 0) {
904*e71b7053SJung-uk Kim         pid_t fpid;
905*e71b7053SJung-uk Kim 
906*e71b7053SJung-uk Kim         /*
907*e71b7053SJung-uk Kim          * Wait for a child to replace when we're at the limit.
908*e71b7053SJung-uk Kim          * Slow down if a child exited abnormally or waitpid() < 0
909*e71b7053SJung-uk Kim          */
910*e71b7053SJung-uk Kim         while (termsig == 0 && procs >= multi) {
911*e71b7053SJung-uk Kim             if ((fpid = waitpid(-1, &status, 0)) > 0) {
912*e71b7053SJung-uk Kim                 for (i = 0; i < procs; ++i) {
913*e71b7053SJung-uk Kim                     if (kidpids[i] == fpid) {
914*e71b7053SJung-uk Kim                         kidpids[i] = 0;
915*e71b7053SJung-uk Kim                         --procs;
916*e71b7053SJung-uk Kim                         break;
917*e71b7053SJung-uk Kim                     }
918*e71b7053SJung-uk Kim                 }
919*e71b7053SJung-uk Kim                 if (i >= multi) {
920*e71b7053SJung-uk Kim                     syslog(LOG_ERR, "fatal: internal error: "
921*e71b7053SJung-uk Kim                            "no matching child slot for pid: %ld",
922*e71b7053SJung-uk Kim                            (long) fpid);
923*e71b7053SJung-uk Kim                     killall(1, kidpids);
924*e71b7053SJung-uk Kim                 }
925*e71b7053SJung-uk Kim                 if (status != 0) {
926*e71b7053SJung-uk Kim                     if (WIFEXITED(status))
927*e71b7053SJung-uk Kim                         syslog(LOG_WARNING, "child process: %ld, exit status: %d",
928*e71b7053SJung-uk Kim                                (long)fpid, WEXITSTATUS(status));
929*e71b7053SJung-uk Kim                     else if (WIFSIGNALED(status))
930*e71b7053SJung-uk Kim                         syslog(LOG_WARNING, "child process: %ld, term signal %d%s",
931*e71b7053SJung-uk Kim                                (long)fpid, WTERMSIG(status),
932*e71b7053SJung-uk Kim #ifdef WCOREDUMP
933*e71b7053SJung-uk Kim                                WCOREDUMP(status) ? " (core dumped)" :
934*e71b7053SJung-uk Kim #endif
935*e71b7053SJung-uk Kim                                "");
936*e71b7053SJung-uk Kim                     sleep(1);
937*e71b7053SJung-uk Kim                 }
938*e71b7053SJung-uk Kim                 break;
939*e71b7053SJung-uk Kim             } else if (errno != EINTR) {
940*e71b7053SJung-uk Kim                 syslog(LOG_ERR, "fatal: waitpid(): %s", strerror(errno));
941*e71b7053SJung-uk Kim                 killall(1, kidpids);
942*e71b7053SJung-uk Kim             }
943*e71b7053SJung-uk Kim         }
944*e71b7053SJung-uk Kim         if (termsig)
945*e71b7053SJung-uk Kim             break;
946*e71b7053SJung-uk Kim 
947*e71b7053SJung-uk Kim         switch(fpid = fork()) {
948*e71b7053SJung-uk Kim         case -1:            /* error */
949*e71b7053SJung-uk Kim             /* System critically low on memory, pause and try again later */
950*e71b7053SJung-uk Kim             sleep(30);
951*e71b7053SJung-uk Kim             break;
952*e71b7053SJung-uk Kim         case 0:             /* child */
953*e71b7053SJung-uk Kim             signal(SIGINT, SIG_DFL);
954*e71b7053SJung-uk Kim             signal(SIGTERM, SIG_DFL);
955*e71b7053SJung-uk Kim             if (termsig)
956*e71b7053SJung-uk Kim                 _exit(0);
957*e71b7053SJung-uk Kim             if (RAND_poll() <= 0) {
958*e71b7053SJung-uk Kim                 syslog(LOG_ERR, "fatal: RAND_poll() failed");
959*e71b7053SJung-uk Kim                 _exit(1);
960*e71b7053SJung-uk Kim             }
961*e71b7053SJung-uk Kim             return;
962*e71b7053SJung-uk Kim         default:            /* parent */
963*e71b7053SJung-uk Kim             for (i = 0; i < multi; ++i) {
964*e71b7053SJung-uk Kim                 if (kidpids[i] == 0) {
965*e71b7053SJung-uk Kim                     kidpids[i] = fpid;
966*e71b7053SJung-uk Kim                     procs++;
967*e71b7053SJung-uk Kim                     break;
968*e71b7053SJung-uk Kim                 }
969*e71b7053SJung-uk Kim             }
970*e71b7053SJung-uk Kim             if (i >= multi) {
971*e71b7053SJung-uk Kim                 syslog(LOG_ERR, "fatal: internal error: no free child slots");
972*e71b7053SJung-uk Kim                 killall(1, kidpids);
973*e71b7053SJung-uk Kim             }
974*e71b7053SJung-uk Kim             break;
975*e71b7053SJung-uk Kim         }
976*e71b7053SJung-uk Kim     }
977*e71b7053SJung-uk Kim 
978*e71b7053SJung-uk Kim     /* The loop above can only break on termsig */
979*e71b7053SJung-uk Kim     syslog(LOG_INFO, "terminating on signal: %d", termsig);
980*e71b7053SJung-uk Kim     killall(0, kidpids);
981*e71b7053SJung-uk Kim }
982*e71b7053SJung-uk Kim # endif
983*e71b7053SJung-uk Kim 
9846f9291ceSJung-uk Kim static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert,
9856f9291ceSJung-uk Kim                          const EVP_MD *cert_id_md, X509 *issuer,
9865c87c606SMark Murray                          STACK_OF(OCSP_CERTID) *ids)
9875c87c606SMark Murray {
9885c87c606SMark Murray     OCSP_CERTID *id;
989*e71b7053SJung-uk Kim 
990*e71b7053SJung-uk Kim     if (issuer == NULL) {
9915c87c606SMark Murray         BIO_printf(bio_err, "No issuer certificate specified\n");
9925c87c606SMark Murray         return 0;
9935c87c606SMark Murray     }
994*e71b7053SJung-uk Kim     if (*req == NULL)
9956f9291ceSJung-uk Kim         *req = OCSP_REQUEST_new();
996*e71b7053SJung-uk Kim     if (*req == NULL)
9976f9291ceSJung-uk Kim         goto err;
9981f13597dSJung-uk Kim     id = OCSP_cert_to_id(cert_id_md, cert, issuer);
999*e71b7053SJung-uk Kim     if (id == NULL || !sk_OCSP_CERTID_push(ids, id))
10006f9291ceSJung-uk Kim         goto err;
10016f9291ceSJung-uk Kim     if (!OCSP_request_add0_id(*req, id))
10026f9291ceSJung-uk Kim         goto err;
10035c87c606SMark Murray     return 1;
10045c87c606SMark Murray 
10055c87c606SMark Murray  err:
10065c87c606SMark Murray     BIO_printf(bio_err, "Error Creating OCSP request\n");
10075c87c606SMark Murray     return 0;
10085c87c606SMark Murray }
10095c87c606SMark Murray 
10106f9291ceSJung-uk Kim static int add_ocsp_serial(OCSP_REQUEST **req, char *serial,
10116f9291ceSJung-uk Kim                            const EVP_MD *cert_id_md, X509 *issuer,
10125c87c606SMark Murray                            STACK_OF(OCSP_CERTID) *ids)
10135c87c606SMark Murray {
10145c87c606SMark Murray     OCSP_CERTID *id;
10155c87c606SMark Murray     X509_NAME *iname;
10165c87c606SMark Murray     ASN1_BIT_STRING *ikey;
10175c87c606SMark Murray     ASN1_INTEGER *sno;
1018*e71b7053SJung-uk Kim 
1019*e71b7053SJung-uk Kim     if (issuer == NULL) {
10205c87c606SMark Murray         BIO_printf(bio_err, "No issuer certificate specified\n");
10215c87c606SMark Murray         return 0;
10225c87c606SMark Murray     }
1023*e71b7053SJung-uk Kim     if (*req == NULL)
10246f9291ceSJung-uk Kim         *req = OCSP_REQUEST_new();
1025*e71b7053SJung-uk Kim     if (*req == NULL)
10266f9291ceSJung-uk Kim         goto err;
10275c87c606SMark Murray     iname = X509_get_subject_name(issuer);
10285c87c606SMark Murray     ikey = X509_get0_pubkey_bitstr(issuer);
10295c87c606SMark Murray     sno = s2i_ASN1_INTEGER(NULL, serial);
1030*e71b7053SJung-uk Kim     if (sno == NULL) {
10315c87c606SMark Murray         BIO_printf(bio_err, "Error converting serial number %s\n", serial);
10325c87c606SMark Murray         return 0;
10335c87c606SMark Murray     }
10341f13597dSJung-uk Kim     id = OCSP_cert_id_new(cert_id_md, iname, ikey, sno);
10355c87c606SMark Murray     ASN1_INTEGER_free(sno);
1036*e71b7053SJung-uk Kim     if (id == NULL || !sk_OCSP_CERTID_push(ids, id))
10376f9291ceSJung-uk Kim         goto err;
10386f9291ceSJung-uk Kim     if (!OCSP_request_add0_id(*req, id))
10396f9291ceSJung-uk Kim         goto err;
10405c87c606SMark Murray     return 1;
10415c87c606SMark Murray 
10425c87c606SMark Murray  err:
10435c87c606SMark Murray     BIO_printf(bio_err, "Error Creating OCSP request\n");
10445c87c606SMark Murray     return 0;
10455c87c606SMark Murray }
10465c87c606SMark Murray 
1047*e71b7053SJung-uk Kim static void print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req,
10481f13597dSJung-uk Kim                               STACK_OF(OPENSSL_STRING) *names,
10491f13597dSJung-uk Kim                               STACK_OF(OCSP_CERTID) *ids, long nsec,
10501f13597dSJung-uk Kim                               long maxage)
10515c87c606SMark Murray {
10525c87c606SMark Murray     OCSP_CERTID *id;
1053*e71b7053SJung-uk Kim     const char *name;
1054*e71b7053SJung-uk Kim     int i, status, reason;
10555c87c606SMark Murray     ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
10565c87c606SMark Murray 
1057*e71b7053SJung-uk Kim     if (bs == NULL || req == NULL || !sk_OPENSSL_STRING_num(names)
10586f9291ceSJung-uk Kim         || !sk_OCSP_CERTID_num(ids))
1059*e71b7053SJung-uk Kim         return;
10605c87c606SMark Murray 
10616f9291ceSJung-uk Kim     for (i = 0; i < sk_OCSP_CERTID_num(ids); i++) {
10625c87c606SMark Murray         id = sk_OCSP_CERTID_value(ids, i);
10631f13597dSJung-uk Kim         name = sk_OPENSSL_STRING_value(names, i);
10645c87c606SMark Murray         BIO_printf(out, "%s: ", name);
10655c87c606SMark Murray 
10665c87c606SMark Murray         if (!OCSP_resp_find_status(bs, id, &status, &reason,
10676f9291ceSJung-uk Kim                                    &rev, &thisupd, &nextupd)) {
10685c87c606SMark Murray             BIO_puts(out, "ERROR: No Status found.\n");
10695c87c606SMark Murray             continue;
10705c87c606SMark Murray         }
10715c87c606SMark Murray 
10726f9291ceSJung-uk Kim         /*
10736f9291ceSJung-uk Kim          * Check validity: if invalid write to output BIO so we know which
10746f9291ceSJung-uk Kim          * response this refers to.
10755c87c606SMark Murray          */
10766f9291ceSJung-uk Kim         if (!OCSP_check_validity(thisupd, nextupd, nsec, maxage)) {
10775c87c606SMark Murray             BIO_puts(out, "WARNING: Status times invalid.\n");
10785c87c606SMark Murray             ERR_print_errors(out);
10795c87c606SMark Murray         }
10805c87c606SMark Murray         BIO_printf(out, "%s\n", OCSP_cert_status_str(status));
10815c87c606SMark Murray 
10825c87c606SMark Murray         BIO_puts(out, "\tThis Update: ");
10835c87c606SMark Murray         ASN1_GENERALIZEDTIME_print(out, thisupd);
10845c87c606SMark Murray         BIO_puts(out, "\n");
10855c87c606SMark Murray 
10866f9291ceSJung-uk Kim         if (nextupd) {
10875c87c606SMark Murray             BIO_puts(out, "\tNext Update: ");
10885c87c606SMark Murray             ASN1_GENERALIZEDTIME_print(out, nextupd);
10895c87c606SMark Murray             BIO_puts(out, "\n");
10905c87c606SMark Murray         }
10915c87c606SMark Murray 
10925c87c606SMark Murray         if (status != V_OCSP_CERTSTATUS_REVOKED)
10935c87c606SMark Murray             continue;
10945c87c606SMark Murray 
10955c87c606SMark Murray         if (reason != -1)
10966f9291ceSJung-uk Kim             BIO_printf(out, "\tReason: %s\n", OCSP_crl_reason_str(reason));
10975c87c606SMark Murray 
10985c87c606SMark Murray         BIO_puts(out, "\tRevocation Time: ");
10995c87c606SMark Murray         ASN1_GENERALIZEDTIME_print(out, rev);
11005c87c606SMark Murray         BIO_puts(out, "\n");
11015c87c606SMark Murray     }
11025c87c606SMark Murray }
11035c87c606SMark Murray 
1104*e71b7053SJung-uk Kim static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req,
1105*e71b7053SJung-uk Kim                               CA_DB *db, STACK_OF(X509) *ca, X509 *rcert,
11067bded2dbSJung-uk Kim                               EVP_PKEY *rkey, const EVP_MD *rmd,
1107*e71b7053SJung-uk Kim                               STACK_OF(OPENSSL_STRING) *sigopts,
11087bded2dbSJung-uk Kim                               STACK_OF(X509) *rother, unsigned long flags,
11097bded2dbSJung-uk Kim                               int nmin, int ndays, int badsig)
11105c87c606SMark Murray {
11115c87c606SMark Murray     ASN1_TIME *thisupd = NULL, *nextupd = NULL;
1112*e71b7053SJung-uk Kim     OCSP_CERTID *cid;
11135c87c606SMark Murray     OCSP_BASICRESP *bs = NULL;
1114*e71b7053SJung-uk Kim     int i, id_count;
1115*e71b7053SJung-uk Kim     EVP_MD_CTX *mctx = NULL;
1116*e71b7053SJung-uk Kim     EVP_PKEY_CTX *pkctx = NULL;
11175c87c606SMark Murray 
11185c87c606SMark Murray     id_count = OCSP_request_onereq_count(req);
11195c87c606SMark Murray 
11206f9291ceSJung-uk Kim     if (id_count <= 0) {
11216f9291ceSJung-uk Kim         *resp =
11226f9291ceSJung-uk Kim             OCSP_response_create(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, NULL);
11235c87c606SMark Murray         goto end;
11245c87c606SMark Murray     }
11255c87c606SMark Murray 
11265c87c606SMark Murray     bs = OCSP_BASICRESP_new();
11275c87c606SMark Murray     thisupd = X509_gmtime_adj(NULL, 0);
11285c87c606SMark Murray     if (ndays != -1)
11298180e704SJung-uk Kim         nextupd = X509_time_adj_ex(NULL, ndays, nmin * 60, NULL);
11305c87c606SMark Murray 
11315c87c606SMark Murray     /* Examine each certificate id in the request */
11326f9291ceSJung-uk Kim     for (i = 0; i < id_count; i++) {
11335c87c606SMark Murray         OCSP_ONEREQ *one;
11345c87c606SMark Murray         ASN1_INTEGER *serial;
11355c87c606SMark Murray         char **inf;
1136*e71b7053SJung-uk Kim         int jj;
1137*e71b7053SJung-uk Kim         int found = 0;
11381f13597dSJung-uk Kim         ASN1_OBJECT *cert_id_md_oid;
11391f13597dSJung-uk Kim         const EVP_MD *cert_id_md;
11405c87c606SMark Murray         one = OCSP_request_onereq_get0(req, i);
11415c87c606SMark Murray         cid = OCSP_onereq_get0_id(one);
11421f13597dSJung-uk Kim 
11431f13597dSJung-uk Kim         OCSP_id_get0_info(NULL, &cert_id_md_oid, NULL, NULL, cid);
11441f13597dSJung-uk Kim 
11451f13597dSJung-uk Kim         cert_id_md = EVP_get_digestbyobj(cert_id_md_oid);
1146*e71b7053SJung-uk Kim         if (cert_id_md == NULL) {
11471f13597dSJung-uk Kim             *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_INTERNALERROR,
11481f13597dSJung-uk Kim                                          NULL);
11491f13597dSJung-uk Kim             goto end;
11501f13597dSJung-uk Kim         }
1151*e71b7053SJung-uk Kim         for (jj = 0; jj < sk_X509_num(ca) && !found; jj++) {
1152*e71b7053SJung-uk Kim             X509 *ca_cert = sk_X509_value(ca, jj);
1153*e71b7053SJung-uk Kim             OCSP_CERTID *ca_id = OCSP_cert_to_id(cert_id_md, NULL, ca_cert);
11541f13597dSJung-uk Kim 
1155*e71b7053SJung-uk Kim             if (OCSP_id_issuer_cmp(ca_id, cid) == 0)
1156*e71b7053SJung-uk Kim                 found = 1;
1157*e71b7053SJung-uk Kim 
1158*e71b7053SJung-uk Kim             OCSP_CERTID_free(ca_id);
1159*e71b7053SJung-uk Kim         }
1160*e71b7053SJung-uk Kim 
1161*e71b7053SJung-uk Kim         if (!found) {
11625c87c606SMark Murray             OCSP_basic_add1_status(bs, cid,
11635c87c606SMark Murray                                    V_OCSP_CERTSTATUS_UNKNOWN,
11646f9291ceSJung-uk Kim                                    0, NULL, thisupd, nextupd);
11655c87c606SMark Murray             continue;
11665c87c606SMark Murray         }
11675c87c606SMark Murray         OCSP_id_get0_info(NULL, NULL, NULL, &serial, cid);
11685c87c606SMark Murray         inf = lookup_serial(db, serial);
1169*e71b7053SJung-uk Kim         if (inf == NULL) {
11705c87c606SMark Murray             OCSP_basic_add1_status(bs, cid,
11715c87c606SMark Murray                                    V_OCSP_CERTSTATUS_UNKNOWN,
11726f9291ceSJung-uk Kim                                    0, NULL, thisupd, nextupd);
1173*e71b7053SJung-uk Kim         } else if (inf[DB_type][0] == DB_TYPE_VAL) {
11745c87c606SMark Murray             OCSP_basic_add1_status(bs, cid,
11755c87c606SMark Murray                                    V_OCSP_CERTSTATUS_GOOD,
11766f9291ceSJung-uk Kim                                    0, NULL, thisupd, nextupd);
1177*e71b7053SJung-uk Kim         } else if (inf[DB_type][0] == DB_TYPE_REV) {
11785c87c606SMark Murray             ASN1_OBJECT *inst = NULL;
11795c87c606SMark Murray             ASN1_TIME *revtm = NULL;
11805c87c606SMark Murray             ASN1_GENERALIZEDTIME *invtm = NULL;
11815c87c606SMark Murray             OCSP_SINGLERESP *single;
11825c87c606SMark Murray             int reason = -1;
11835c87c606SMark Murray             unpack_revinfo(&revtm, &reason, &inst, &invtm, inf[DB_rev_date]);
11845c87c606SMark Murray             single = OCSP_basic_add1_status(bs, cid,
11855c87c606SMark Murray                                             V_OCSP_CERTSTATUS_REVOKED,
11866f9291ceSJung-uk Kim                                             reason, revtm, thisupd, nextupd);
1187*e71b7053SJung-uk Kim             if (invtm != NULL)
11886f9291ceSJung-uk Kim                 OCSP_SINGLERESP_add1_ext_i2d(single, NID_invalidity_date,
11896f9291ceSJung-uk Kim                                              invtm, 0, 0);
1190*e71b7053SJung-uk Kim             else if (inst != NULL)
11916f9291ceSJung-uk Kim                 OCSP_SINGLERESP_add1_ext_i2d(single,
11926f9291ceSJung-uk Kim                                              NID_hold_instruction_code, inst,
11936f9291ceSJung-uk Kim                                              0, 0);
11945c87c606SMark Murray             ASN1_OBJECT_free(inst);
11955c87c606SMark Murray             ASN1_TIME_free(revtm);
11965c87c606SMark Murray             ASN1_GENERALIZEDTIME_free(invtm);
11975c87c606SMark Murray         }
11985c87c606SMark Murray     }
11995c87c606SMark Murray 
12005c87c606SMark Murray     OCSP_copy_nonce(bs, req);
12015c87c606SMark Murray 
1202*e71b7053SJung-uk Kim     mctx = EVP_MD_CTX_new();
1203*e71b7053SJung-uk Kim     if ( mctx == NULL || !EVP_DigestSignInit(mctx, &pkctx, rmd, NULL, rkey)) {
1204*e71b7053SJung-uk Kim         *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_INTERNALERROR, NULL);
1205*e71b7053SJung-uk Kim         goto end;
1206*e71b7053SJung-uk Kim     }
1207*e71b7053SJung-uk Kim     for (i = 0; i < sk_OPENSSL_STRING_num(sigopts); i++) {
1208*e71b7053SJung-uk Kim         char *sigopt = sk_OPENSSL_STRING_value(sigopts, i);
12097bded2dbSJung-uk Kim 
1210*e71b7053SJung-uk Kim         if (pkey_ctrl_string(pkctx, sigopt) <= 0) {
1211*e71b7053SJung-uk Kim             BIO_printf(err, "parameter error \"%s\"\n", sigopt);
1212*e71b7053SJung-uk Kim             ERR_print_errors(bio_err);
1213*e71b7053SJung-uk Kim             *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_INTERNALERROR,
1214*e71b7053SJung-uk Kim                                          NULL);
1215*e71b7053SJung-uk Kim             goto end;
1216*e71b7053SJung-uk Kim         }
1217*e71b7053SJung-uk Kim     }
1218*e71b7053SJung-uk Kim     OCSP_basic_sign_ctx(bs, rcert, mctx, rother, flags);
1219*e71b7053SJung-uk Kim 
1220*e71b7053SJung-uk Kim     if (badsig) {
1221*e71b7053SJung-uk Kim         const ASN1_OCTET_STRING *sig = OCSP_resp_get0_signature(bs);
1222*e71b7053SJung-uk Kim         corrupt_signature(sig);
1223*e71b7053SJung-uk Kim     }
12245c87c606SMark Murray 
12255c87c606SMark Murray     *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_SUCCESSFUL, bs);
12265c87c606SMark Murray 
12275c87c606SMark Murray  end:
1228*e71b7053SJung-uk Kim     EVP_MD_CTX_free(mctx);
12295c87c606SMark Murray     ASN1_TIME_free(thisupd);
12305c87c606SMark Murray     ASN1_TIME_free(nextupd);
12315c87c606SMark Murray     OCSP_BASICRESP_free(bs);
12325c87c606SMark Murray }
12335c87c606SMark Murray 
1234ced566fdSJacques Vidrine static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser)
12355c87c606SMark Murray {
12365c87c606SMark Murray     int i;
12375c87c606SMark Murray     BIGNUM *bn = NULL;
12385c87c606SMark Murray     char *itmp, *row[DB_NUMBER], **rrow;
12396f9291ceSJung-uk Kim     for (i = 0; i < DB_NUMBER; i++)
12406f9291ceSJung-uk Kim         row[i] = NULL;
12415c87c606SMark Murray     bn = ASN1_INTEGER_to_BN(ser, NULL);
12426f9291ceSJung-uk Kim     OPENSSL_assert(bn);         /* FIXME: should report an error at this
12436f9291ceSJung-uk Kim                                  * point and abort */
12445c87c606SMark Murray     if (BN_is_zero(bn))
1245*e71b7053SJung-uk Kim         itmp = OPENSSL_strdup("00");
12465c87c606SMark Murray     else
12475c87c606SMark Murray         itmp = BN_bn2hex(bn);
12485c87c606SMark Murray     row[DB_serial] = itmp;
12495c87c606SMark Murray     BN_free(bn);
1250ced566fdSJacques Vidrine     rrow = TXT_DB_get_by_index(db->db, DB_serial, row);
12515c87c606SMark Murray     OPENSSL_free(itmp);
12525c87c606SMark Murray     return rrow;
12535c87c606SMark Murray }
12545c87c606SMark Murray 
12555c87c606SMark Murray /* Quick and dirty OCSP server: read in and parse input request */
12565c87c606SMark Murray 
12577bded2dbSJung-uk Kim static BIO *init_responder(const char *port)
12585c87c606SMark Murray {
1259*e71b7053SJung-uk Kim # ifdef OPENSSL_NO_SOCK
12606f9291ceSJung-uk Kim     BIO_printf(bio_err,
12616f9291ceSJung-uk Kim                "Error setting up accept BIO - sockets not supported.\n");
1262*e71b7053SJung-uk Kim     return NULL;
1263*e71b7053SJung-uk Kim # else
1264*e71b7053SJung-uk Kim     BIO *acbio = NULL, *bufbio = NULL;
1265*e71b7053SJung-uk Kim 
1266*e71b7053SJung-uk Kim     bufbio = BIO_new(BIO_f_buffer());
1267*e71b7053SJung-uk Kim     if (bufbio == NULL)
12685c87c606SMark Murray         goto err;
1269*e71b7053SJung-uk Kim     acbio = BIO_new(BIO_s_accept());
1270*e71b7053SJung-uk Kim     if (acbio == NULL
1271*e71b7053SJung-uk Kim         || BIO_set_bind_mode(acbio, BIO_BIND_REUSEADDR) < 0
1272*e71b7053SJung-uk Kim         || BIO_set_accept_port(acbio, port) < 0) {
1273*e71b7053SJung-uk Kim         log_message(LOG_ERR, "Error setting up accept BIO");
1274*e71b7053SJung-uk Kim         goto err;
1275*e71b7053SJung-uk Kim     }
1276*e71b7053SJung-uk Kim 
12775c87c606SMark Murray     BIO_set_accept_bios(acbio, bufbio);
12785c87c606SMark Murray     bufbio = NULL;
12796f9291ceSJung-uk Kim     if (BIO_do_accept(acbio) <= 0) {
1280*e71b7053SJung-uk Kim         log_message(LOG_ERR, "Error starting accept");
12815c87c606SMark Murray         goto err;
12825c87c606SMark Murray     }
12835c87c606SMark Murray 
12845c87c606SMark Murray     return acbio;
12855c87c606SMark Murray 
12865c87c606SMark Murray  err:
12875c87c606SMark Murray     BIO_free_all(acbio);
12885c87c606SMark Murray     BIO_free(bufbio);
12895c87c606SMark Murray     return NULL;
1290*e71b7053SJung-uk Kim # endif
12915c87c606SMark Murray }
12925c87c606SMark Murray 
1293*e71b7053SJung-uk Kim # ifndef OPENSSL_NO_SOCK
1294*e71b7053SJung-uk Kim /*
1295*e71b7053SJung-uk Kim  * Decode %xx URL-decoding in-place. Ignores mal-formed sequences.
1296*e71b7053SJung-uk Kim  */
1297*e71b7053SJung-uk Kim static int urldecode(char *p)
1298*e71b7053SJung-uk Kim {
1299*e71b7053SJung-uk Kim     unsigned char *out = (unsigned char *)p;
1300*e71b7053SJung-uk Kim     unsigned char *save = out;
1301*e71b7053SJung-uk Kim 
1302*e71b7053SJung-uk Kim     for (; *p; p++) {
1303*e71b7053SJung-uk Kim         if (*p != '%')
1304*e71b7053SJung-uk Kim             *out++ = *p;
1305*e71b7053SJung-uk Kim         else if (isxdigit(_UC(p[1])) && isxdigit(_UC(p[2]))) {
1306*e71b7053SJung-uk Kim             /* Don't check, can't fail because of ixdigit() call. */
1307*e71b7053SJung-uk Kim             *out++ = (OPENSSL_hexchar2int(p[1]) << 4)
1308*e71b7053SJung-uk Kim                    | OPENSSL_hexchar2int(p[2]);
1309*e71b7053SJung-uk Kim             p += 2;
1310*e71b7053SJung-uk Kim         }
1311*e71b7053SJung-uk Kim         else
1312*e71b7053SJung-uk Kim             return -1;
1313*e71b7053SJung-uk Kim     }
1314*e71b7053SJung-uk Kim     *out = '\0';
1315*e71b7053SJung-uk Kim     return (int)(out - save);
1316*e71b7053SJung-uk Kim }
1317*e71b7053SJung-uk Kim # endif
1318*e71b7053SJung-uk Kim 
1319*e71b7053SJung-uk Kim # ifdef OCSP_DAEMON
1320*e71b7053SJung-uk Kim static void sock_timeout(int signum)
1321*e71b7053SJung-uk Kim {
1322*e71b7053SJung-uk Kim     if (acfd != (int)INVALID_SOCKET)
1323*e71b7053SJung-uk Kim         (void)shutdown(acfd, SHUT_RD);
1324*e71b7053SJung-uk Kim }
1325*e71b7053SJung-uk Kim # endif
1326*e71b7053SJung-uk Kim 
13276f9291ceSJung-uk Kim static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio,
1328*e71b7053SJung-uk Kim                         int timeout)
13295c87c606SMark Murray {
1330*e71b7053SJung-uk Kim # ifdef OPENSSL_NO_SOCK
13315c87c606SMark Murray     return 0;
1332*e71b7053SJung-uk Kim # else
1333*e71b7053SJung-uk Kim     int len;
1334*e71b7053SJung-uk Kim     OCSP_REQUEST *req = NULL;
1335*e71b7053SJung-uk Kim     char inbuf[2048], reqbuf[2048];
1336*e71b7053SJung-uk Kim     char *p, *q;
1337*e71b7053SJung-uk Kim     BIO *cbio = NULL, *getbio = NULL, *b64 = NULL;
1338*e71b7053SJung-uk Kim     const char *client;
1339*e71b7053SJung-uk Kim 
1340*e71b7053SJung-uk Kim     *preq = NULL;
1341*e71b7053SJung-uk Kim 
1342*e71b7053SJung-uk Kim     /* Connection loss before accept() is routine, ignore silently */
1343*e71b7053SJung-uk Kim     if (BIO_do_accept(acbio) <= 0)
1344*e71b7053SJung-uk Kim         return 0;
13455c87c606SMark Murray 
13465c87c606SMark Murray     cbio = BIO_pop(acbio);
13475c87c606SMark Murray     *pcbio = cbio;
1348*e71b7053SJung-uk Kim     client = BIO_get_peer_name(cbio);
13495c87c606SMark Murray 
1350*e71b7053SJung-uk Kim #  ifdef OCSP_DAEMON
1351*e71b7053SJung-uk Kim     if (timeout > 0) {
1352*e71b7053SJung-uk Kim         (void) BIO_get_fd(cbio, &acfd);
1353*e71b7053SJung-uk Kim         alarm(timeout);
1354*e71b7053SJung-uk Kim     }
1355*e71b7053SJung-uk Kim #  endif
1356*e71b7053SJung-uk Kim 
1357*e71b7053SJung-uk Kim     /* Read the request line. */
1358*e71b7053SJung-uk Kim     len = BIO_gets(cbio, reqbuf, sizeof(reqbuf));
1359*e71b7053SJung-uk Kim     if (len <= 0)
1360*e71b7053SJung-uk Kim         goto out;
1361*e71b7053SJung-uk Kim 
1362*e71b7053SJung-uk Kim     if (strncmp(reqbuf, "GET ", 4) == 0) {
1363*e71b7053SJung-uk Kim         /* Expecting GET {sp} /URL {sp} HTTP/1.x */
1364*e71b7053SJung-uk Kim         for (p = reqbuf + 4; *p == ' '; ++p)
1365*e71b7053SJung-uk Kim             continue;
1366*e71b7053SJung-uk Kim         if (*p != '/') {
1367*e71b7053SJung-uk Kim             log_message(LOG_INFO, "Invalid request -- bad URL: %s", client);
1368*e71b7053SJung-uk Kim             goto out;
1369*e71b7053SJung-uk Kim         }
1370*e71b7053SJung-uk Kim         p++;
1371*e71b7053SJung-uk Kim 
1372*e71b7053SJung-uk Kim         /* Splice off the HTTP version identifier. */
1373*e71b7053SJung-uk Kim         for (q = p; *q; q++)
1374*e71b7053SJung-uk Kim             if (*q == ' ')
1375*e71b7053SJung-uk Kim                 break;
1376*e71b7053SJung-uk Kim         if (strncmp(q, " HTTP/1.", 8) != 0) {
1377*e71b7053SJung-uk Kim             log_message(LOG_INFO,
1378*e71b7053SJung-uk Kim                         "Invalid request -- bad HTTP version: %s", client);
1379*e71b7053SJung-uk Kim             goto out;
1380*e71b7053SJung-uk Kim         }
1381*e71b7053SJung-uk Kim         *q = '\0';
1382*e71b7053SJung-uk Kim 
1383*e71b7053SJung-uk Kim         /*
1384*e71b7053SJung-uk Kim          * Skip "GET / HTTP..." requests often used by load-balancers
1385*e71b7053SJung-uk Kim          */
1386*e71b7053SJung-uk Kim         if (p[1] == '\0')
1387*e71b7053SJung-uk Kim             goto out;
1388*e71b7053SJung-uk Kim 
1389*e71b7053SJung-uk Kim         len = urldecode(p);
1390*e71b7053SJung-uk Kim         if (len <= 0) {
1391*e71b7053SJung-uk Kim             log_message(LOG_INFO,
1392*e71b7053SJung-uk Kim                         "Invalid request -- bad URL encoding: %s", client);
1393*e71b7053SJung-uk Kim             goto out;
1394*e71b7053SJung-uk Kim         }
1395*e71b7053SJung-uk Kim         if ((getbio = BIO_new_mem_buf(p, len)) == NULL
1396*e71b7053SJung-uk Kim             || (b64 = BIO_new(BIO_f_base64())) == NULL) {
1397*e71b7053SJung-uk Kim             log_message(LOG_ERR, "Could not allocate base64 bio: %s", client);
1398*e71b7053SJung-uk Kim             goto out;
1399*e71b7053SJung-uk Kim         }
1400*e71b7053SJung-uk Kim         BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
1401*e71b7053SJung-uk Kim         getbio = BIO_push(b64, getbio);
1402*e71b7053SJung-uk Kim     } else if (strncmp(reqbuf, "POST ", 5) != 0) {
1403*e71b7053SJung-uk Kim         log_message(LOG_INFO, "Invalid request -- bad HTTP verb: %s", client);
1404*e71b7053SJung-uk Kim         goto out;
1405*e71b7053SJung-uk Kim     }
1406*e71b7053SJung-uk Kim 
1407*e71b7053SJung-uk Kim     /* Read and skip past the headers. */
14086f9291ceSJung-uk Kim     for (;;) {
1409dee36b4fSJung-uk Kim         len = BIO_gets(cbio, inbuf, sizeof(inbuf));
14105c87c606SMark Murray         if (len <= 0)
1411*e71b7053SJung-uk Kim             goto out;
14125c87c606SMark Murray         if ((inbuf[0] == '\r') || (inbuf[0] == '\n'))
14135c87c606SMark Murray             break;
14145c87c606SMark Murray     }
14155c87c606SMark Murray 
1416*e71b7053SJung-uk Kim #  ifdef OCSP_DAEMON
1417*e71b7053SJung-uk Kim     /* Clear alarm before we close the client socket */
1418*e71b7053SJung-uk Kim     alarm(0);
1419*e71b7053SJung-uk Kim     timeout = 0;
1420*e71b7053SJung-uk Kim #  endif
1421*e71b7053SJung-uk Kim 
14225c87c606SMark Murray     /* Try to read OCSP request */
1423*e71b7053SJung-uk Kim     if (getbio != NULL) {
1424*e71b7053SJung-uk Kim         req = d2i_OCSP_REQUEST_bio(getbio, NULL);
1425*e71b7053SJung-uk Kim         BIO_free_all(getbio);
1426*e71b7053SJung-uk Kim     } else {
14275c87c606SMark Murray         req = d2i_OCSP_REQUEST_bio(cbio, NULL);
14285c87c606SMark Murray     }
14295c87c606SMark Murray 
1430*e71b7053SJung-uk Kim     if (req == NULL)
1431*e71b7053SJung-uk Kim         log_message(LOG_ERR, "Error parsing OCSP request");
1432*e71b7053SJung-uk Kim 
14335c87c606SMark Murray     *preq = req;
14345c87c606SMark Murray 
1435*e71b7053SJung-uk Kim out:
1436*e71b7053SJung-uk Kim #  ifdef OCSP_DAEMON
1437*e71b7053SJung-uk Kim     if (timeout > 0)
1438*e71b7053SJung-uk Kim         alarm(0);
1439*e71b7053SJung-uk Kim     acfd = (int)INVALID_SOCKET;
1440*e71b7053SJung-uk Kim #  endif
14415c87c606SMark Murray     return 1;
1442*e71b7053SJung-uk Kim # endif
14435c87c606SMark Murray }
14445c87c606SMark Murray 
14455c87c606SMark Murray static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp)
14465c87c606SMark Murray {
14475c87c606SMark Murray     char http_resp[] =
14485c87c606SMark Murray         "HTTP/1.0 200 OK\r\nContent-type: application/ocsp-response\r\n"
14495c87c606SMark Murray         "Content-Length: %d\r\n\r\n";
1450*e71b7053SJung-uk Kim     if (cbio == NULL)
14515c87c606SMark Murray         return 0;
14525c87c606SMark Murray     BIO_printf(cbio, http_resp, i2d_OCSP_RESPONSE(resp, NULL));
14535c87c606SMark Murray     i2d_OCSP_RESPONSE_bio(cbio, resp);
1454db522d3aSSimon L. B. Nielsen     (void)BIO_flush(cbio);
14555c87c606SMark Murray     return 1;
14565c87c606SMark Murray }
14575c87c606SMark Murray 
1458*e71b7053SJung-uk Kim # ifndef OPENSSL_NO_SOCK
1459*e71b7053SJung-uk Kim static OCSP_RESPONSE *query_responder(BIO *cbio, const char *host,
1460*e71b7053SJung-uk Kim                                       const char *path,
14617bded2dbSJung-uk Kim                                       const STACK_OF(CONF_VALUE) *headers,
1462db522d3aSSimon L. B. Nielsen                                       OCSP_REQUEST *req, int req_timeout)
1463db522d3aSSimon L. B. Nielsen {
1464db522d3aSSimon L. B. Nielsen     int fd;
1465db522d3aSSimon L. B. Nielsen     int rv;
14661f13597dSJung-uk Kim     int i;
1467*e71b7053SJung-uk Kim     int add_host = 1;
1468db522d3aSSimon L. B. Nielsen     OCSP_REQ_CTX *ctx = NULL;
1469db522d3aSSimon L. B. Nielsen     OCSP_RESPONSE *rsp = NULL;
1470db522d3aSSimon L. B. Nielsen     fd_set confds;
1471db522d3aSSimon L. B. Nielsen     struct timeval tv;
1472db522d3aSSimon L. B. Nielsen 
1473db522d3aSSimon L. B. Nielsen     if (req_timeout != -1)
1474db522d3aSSimon L. B. Nielsen         BIO_set_nbio(cbio, 1);
1475db522d3aSSimon L. B. Nielsen 
1476db522d3aSSimon L. B. Nielsen     rv = BIO_do_connect(cbio);
1477db522d3aSSimon L. B. Nielsen 
14786f9291ceSJung-uk Kim     if ((rv <= 0) && ((req_timeout == -1) || !BIO_should_retry(cbio))) {
1479*e71b7053SJung-uk Kim         BIO_puts(bio_err, "Error connecting BIO\n");
1480db522d3aSSimon L. B. Nielsen         return NULL;
1481db522d3aSSimon L. B. Nielsen     }
1482db522d3aSSimon L. B. Nielsen 
148380815a77SJung-uk Kim     if (BIO_get_fd(cbio, &fd) < 0) {
148480815a77SJung-uk Kim         BIO_puts(bio_err, "Can't get connection fd\n");
1485db522d3aSSimon L. B. Nielsen         goto err;
1486db522d3aSSimon L. B. Nielsen     }
1487db522d3aSSimon L. B. Nielsen 
14886f9291ceSJung-uk Kim     if (req_timeout != -1 && rv <= 0) {
1489db522d3aSSimon L. B. Nielsen         FD_ZERO(&confds);
1490db522d3aSSimon L. B. Nielsen         openssl_fdset(fd, &confds);
1491db522d3aSSimon L. B. Nielsen         tv.tv_usec = 0;
1492db522d3aSSimon L. B. Nielsen         tv.tv_sec = req_timeout;
1493db522d3aSSimon L. B. Nielsen         rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv);
14946f9291ceSJung-uk Kim         if (rv == 0) {
1495*e71b7053SJung-uk Kim             BIO_puts(bio_err, "Timeout on connect\n");
1496db522d3aSSimon L. B. Nielsen             return NULL;
1497db522d3aSSimon L. B. Nielsen         }
1498db522d3aSSimon L. B. Nielsen     }
1499db522d3aSSimon L. B. Nielsen 
15001f13597dSJung-uk Kim     ctx = OCSP_sendreq_new(cbio, path, NULL, -1);
1501*e71b7053SJung-uk Kim     if (ctx == NULL)
1502db522d3aSSimon L. B. Nielsen         return NULL;
1503db522d3aSSimon L. B. Nielsen 
15046f9291ceSJung-uk Kim     for (i = 0; i < sk_CONF_VALUE_num(headers); i++) {
15051f13597dSJung-uk Kim         CONF_VALUE *hdr = sk_CONF_VALUE_value(headers, i);
1506*e71b7053SJung-uk Kim         if (add_host == 1 && strcasecmp("host", hdr->name) == 0)
1507*e71b7053SJung-uk Kim             add_host = 0;
15081f13597dSJung-uk Kim         if (!OCSP_REQ_CTX_add1_header(ctx, hdr->name, hdr->value))
15091f13597dSJung-uk Kim             goto err;
15101f13597dSJung-uk Kim     }
15111f13597dSJung-uk Kim 
1512*e71b7053SJung-uk Kim     if (add_host == 1 && OCSP_REQ_CTX_add1_header(ctx, "Host", host) == 0)
1513*e71b7053SJung-uk Kim         goto err;
1514*e71b7053SJung-uk Kim 
15151f13597dSJung-uk Kim     if (!OCSP_REQ_CTX_set1_req(ctx, req))
15161f13597dSJung-uk Kim         goto err;
15171f13597dSJung-uk Kim 
15186f9291ceSJung-uk Kim     for (;;) {
1519db522d3aSSimon L. B. Nielsen         rv = OCSP_sendreq_nbio(&rsp, ctx);
1520db522d3aSSimon L. B. Nielsen         if (rv != -1)
1521db522d3aSSimon L. B. Nielsen             break;
15221f13597dSJung-uk Kim         if (req_timeout == -1)
15231f13597dSJung-uk Kim             continue;
1524db522d3aSSimon L. B. Nielsen         FD_ZERO(&confds);
1525db522d3aSSimon L. B. Nielsen         openssl_fdset(fd, &confds);
1526db522d3aSSimon L. B. Nielsen         tv.tv_usec = 0;
1527db522d3aSSimon L. B. Nielsen         tv.tv_sec = req_timeout;
1528*e71b7053SJung-uk Kim         if (BIO_should_read(cbio)) {
1529db522d3aSSimon L. B. Nielsen             rv = select(fd + 1, (void *)&confds, NULL, NULL, &tv);
1530*e71b7053SJung-uk Kim         } else if (BIO_should_write(cbio)) {
1531db522d3aSSimon L. B. Nielsen             rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv);
1532*e71b7053SJung-uk Kim         } else {
1533*e71b7053SJung-uk Kim             BIO_puts(bio_err, "Unexpected retry condition\n");
1534db522d3aSSimon L. B. Nielsen             goto err;
1535db522d3aSSimon L. B. Nielsen         }
15366f9291ceSJung-uk Kim         if (rv == 0) {
1537*e71b7053SJung-uk Kim             BIO_puts(bio_err, "Timeout on request\n");
1538db522d3aSSimon L. B. Nielsen             break;
1539db522d3aSSimon L. B. Nielsen         }
15406f9291ceSJung-uk Kim         if (rv == -1) {
1541*e71b7053SJung-uk Kim             BIO_puts(bio_err, "Select error\n");
1542db522d3aSSimon L. B. Nielsen             break;
1543db522d3aSSimon L. B. Nielsen         }
1544db522d3aSSimon L. B. Nielsen 
1545db522d3aSSimon L. B. Nielsen     }
1546db522d3aSSimon L. B. Nielsen  err:
1547db522d3aSSimon L. B. Nielsen     OCSP_REQ_CTX_free(ctx);
1548db522d3aSSimon L. B. Nielsen 
1549db522d3aSSimon L. B. Nielsen     return rsp;
1550db522d3aSSimon L. B. Nielsen }
1551db522d3aSSimon L. B. Nielsen 
1552*e71b7053SJung-uk Kim OCSP_RESPONSE *process_responder(OCSP_REQUEST *req,
15537bded2dbSJung-uk Kim                                  const char *host, const char *path,
15547bded2dbSJung-uk Kim                                  const char *port, int use_ssl,
1555*e71b7053SJung-uk Kim                                  STACK_OF(CONF_VALUE) *headers,
1556db522d3aSSimon L. B. Nielsen                                  int req_timeout)
1557db522d3aSSimon L. B. Nielsen {
1558db522d3aSSimon L. B. Nielsen     BIO *cbio = NULL;
1559db522d3aSSimon L. B. Nielsen     SSL_CTX *ctx = NULL;
1560db522d3aSSimon L. B. Nielsen     OCSP_RESPONSE *resp = NULL;
1561*e71b7053SJung-uk Kim 
1562db522d3aSSimon L. B. Nielsen     cbio = BIO_new_connect(host);
1563*e71b7053SJung-uk Kim     if (cbio == NULL) {
1564*e71b7053SJung-uk Kim         BIO_printf(bio_err, "Error creating connect BIO\n");
1565db522d3aSSimon L. B. Nielsen         goto end;
1566db522d3aSSimon L. B. Nielsen     }
1567*e71b7053SJung-uk Kim     if (port != NULL)
15686f9291ceSJung-uk Kim         BIO_set_conn_port(cbio, port);
15696f9291ceSJung-uk Kim     if (use_ssl == 1) {
1570db522d3aSSimon L. B. Nielsen         BIO *sbio;
1571*e71b7053SJung-uk Kim         ctx = SSL_CTX_new(TLS_client_method());
15726f9291ceSJung-uk Kim         if (ctx == NULL) {
1573*e71b7053SJung-uk Kim             BIO_printf(bio_err, "Error creating SSL context.\n");
1574db522d3aSSimon L. B. Nielsen             goto end;
1575db522d3aSSimon L. B. Nielsen         }
1576db522d3aSSimon L. B. Nielsen         SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
1577db522d3aSSimon L. B. Nielsen         sbio = BIO_new_ssl(ctx, 1);
1578db522d3aSSimon L. B. Nielsen         cbio = BIO_push(sbio, cbio);
1579db522d3aSSimon L. B. Nielsen     }
1580*e71b7053SJung-uk Kim 
1581*e71b7053SJung-uk Kim     resp = query_responder(cbio, host, path, headers, req, req_timeout);
1582*e71b7053SJung-uk Kim     if (resp == NULL)
1583a93cbc2bSJung-uk Kim         BIO_printf(bio_err, "Error querying OCSP responder\n");
1584db522d3aSSimon L. B. Nielsen  end:
1585db522d3aSSimon L. B. Nielsen     BIO_free_all(cbio);
15861f13597dSJung-uk Kim     SSL_CTX_free(ctx);
1587db522d3aSSimon L. B. Nielsen     return resp;
1588db522d3aSSimon L. B. Nielsen }
1589*e71b7053SJung-uk Kim # endif
1590db522d3aSSimon L. B. Nielsen 
1591fceca8a3SJacques Vidrine #endif
1592