1109998Smarkm/* ocsp.c */
2194206Ssimon/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3109998Smarkm * project 2000.
4109998Smarkm */
5109998Smarkm/* ====================================================================
6109998Smarkm * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
7109998Smarkm *
8109998Smarkm * Redistribution and use in source and binary forms, with or without
9109998Smarkm * modification, are permitted provided that the following conditions
10109998Smarkm * are met:
11109998Smarkm *
12109998Smarkm * 1. Redistributions of source code must retain the above copyright
13109998Smarkm *    notice, this list of conditions and the following disclaimer.
14109998Smarkm *
15109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright
16109998Smarkm *    notice, this list of conditions and the following disclaimer in
17109998Smarkm *    the documentation and/or other materials provided with the
18109998Smarkm *    distribution.
19109998Smarkm *
20109998Smarkm * 3. All advertising materials mentioning features or use of this
21109998Smarkm *    software must display the following acknowledgment:
22109998Smarkm *    "This product includes software developed by the OpenSSL Project
23109998Smarkm *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24109998Smarkm *
25109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26109998Smarkm *    endorse or promote products derived from this software without
27109998Smarkm *    prior written permission. For written permission, please contact
28109998Smarkm *    licensing@OpenSSL.org.
29109998Smarkm *
30109998Smarkm * 5. Products derived from this software may not be called "OpenSSL"
31109998Smarkm *    nor may "OpenSSL" appear in their names without prior written
32109998Smarkm *    permission of the OpenSSL Project.
33109998Smarkm *
34109998Smarkm * 6. Redistributions of any form whatsoever must retain the following
35109998Smarkm *    acknowledgment:
36109998Smarkm *    "This product includes software developed by the OpenSSL Project
37109998Smarkm *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38109998Smarkm *
39109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42109998Smarkm * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE.
51109998Smarkm * ====================================================================
52109998Smarkm *
53109998Smarkm * This product includes cryptographic software written by Eric Young
54109998Smarkm * (eay@cryptsoft.com).  This product includes software written by Tim
55109998Smarkm * Hudson (tjh@cryptsoft.com).
56109998Smarkm *
57109998Smarkm */
58111147Snectar#ifndef OPENSSL_NO_OCSP
59238405Sjkim
60238405Sjkim#ifdef OPENSSL_SYS_VMS
61238405Sjkim#define _XOPEN_SOURCE_EXTENDED	/* So fd_set and friends get properly defined
62238405Sjkim				   on OpenVMS */
63238405Sjkim#endif
64238405Sjkim
65194206Ssimon#define USE_SOCKETS
66238405Sjkim
67109998Smarkm#include <stdio.h>
68194206Ssimon#include <stdlib.h>
69109998Smarkm#include <string.h>
70238405Sjkim#include <time.h>
71194206Ssimon#include "apps.h" /* needs to be included before the openssl headers! */
72194206Ssimon#include <openssl/e_os2.h>
73238405Sjkim#include <openssl/crypto.h>
74238405Sjkim#include <openssl/err.h>
75194206Ssimon#include <openssl/ssl.h>
76238405Sjkim#include <openssl/evp.h>
77238405Sjkim#include <openssl/bn.h>
78238405Sjkim#include <openssl/x509v3.h>
79109998Smarkm
80238405Sjkim#if defined(NETWARE_CLIB)
81238405Sjkim#  ifdef NETWARE_BSDSOCK
82238405Sjkim#    include <sys/socket.h>
83238405Sjkim#    include <sys/bsdskt.h>
84238405Sjkim#  else
85238405Sjkim#    include <novsock2.h>
86238405Sjkim#  endif
87238405Sjkim#elif defined(NETWARE_LIBC)
88238405Sjkim#  ifdef NETWARE_BSDSOCK
89238405Sjkim#    include <sys/select.h>
90238405Sjkim#  else
91238405Sjkim#    include <novsock2.h>
92238405Sjkim#  endif
93238405Sjkim#endif
94238405Sjkim
95109998Smarkm/* Maximum leeway in validity period: default 5 minutes */
96109998Smarkm#define MAX_VALIDITY_PERIOD	(5 * 60)
97109998Smarkm
98238405Sjkimstatic int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, const EVP_MD *cert_id_md, X509 *issuer,
99109998Smarkm				STACK_OF(OCSP_CERTID) *ids);
100238405Sjkimstatic int add_ocsp_serial(OCSP_REQUEST **req, char *serial, const EVP_MD * cert_id_md, X509 *issuer,
101109998Smarkm				STACK_OF(OCSP_CERTID) *ids);
102109998Smarkmstatic int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req,
103238405Sjkim			      STACK_OF(OPENSSL_STRING) *names,
104238405Sjkim			      STACK_OF(OCSP_CERTID) *ids, long nsec,
105238405Sjkim			      long maxage);
106109998Smarkm
107127128Snectarstatic int make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req, CA_DB *db,
108109998Smarkm			X509 *ca, X509 *rcert, EVP_PKEY *rkey,
109109998Smarkm			STACK_OF(X509) *rother, unsigned long flags,
110109998Smarkm			int nmin, int ndays);
111109998Smarkm
112127128Snectarstatic char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser);
113109998Smarkmstatic BIO *init_responder(char *port);
114109998Smarkmstatic int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, char *port);
115109998Smarkmstatic int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp);
116194206Ssimonstatic OCSP_RESPONSE *query_responder(BIO *err, BIO *cbio, char *path,
117238405Sjkim				STACK_OF(CONF_VALUE) *headers,
118194206Ssimon				OCSP_REQUEST *req, int req_timeout);
119109998Smarkm
120109998Smarkm#undef PROG
121109998Smarkm#define PROG ocsp_main
122109998Smarkm
123109998Smarkmint MAIN(int, char **);
124109998Smarkm
125109998Smarkmint MAIN(int argc, char **argv)
126109998Smarkm	{
127109998Smarkm	ENGINE *e = NULL;
128109998Smarkm	char **args;
129109998Smarkm	char *host = NULL, *port = NULL, *path = "/";
130279264Sdelphij	char *thost = NULL, *tport = NULL, *tpath = NULL;
131109998Smarkm	char *reqin = NULL, *respin = NULL;
132109998Smarkm	char *reqout = NULL, *respout = NULL;
133109998Smarkm	char *signfile = NULL, *keyfile = NULL;
134109998Smarkm	char *rsignfile = NULL, *rkeyfile = NULL;
135109998Smarkm	char *outfile = NULL;
136109998Smarkm	int add_nonce = 1, noverify = 0, use_ssl = -1;
137238405Sjkim	STACK_OF(CONF_VALUE) *headers = NULL;
138109998Smarkm	OCSP_REQUEST *req = NULL;
139109998Smarkm	OCSP_RESPONSE *resp = NULL;
140109998Smarkm	OCSP_BASICRESP *bs = NULL;
141109998Smarkm	X509 *issuer = NULL, *cert = NULL;
142109998Smarkm	X509 *signer = NULL, *rsigner = NULL;
143109998Smarkm	EVP_PKEY *key = NULL, *rkey = NULL;
144109998Smarkm	BIO *acbio = NULL, *cbio = NULL;
145109998Smarkm	BIO *derbio = NULL;
146109998Smarkm	BIO *out = NULL;
147194206Ssimon	int req_timeout = -1;
148109998Smarkm	int req_text = 0, resp_text = 0;
149109998Smarkm	long nsec = MAX_VALIDITY_PERIOD, maxage = -1;
150109998Smarkm	char *CAfile = NULL, *CApath = NULL;
151109998Smarkm	X509_STORE *store = NULL;
152109998Smarkm	STACK_OF(X509) *sign_other = NULL, *verify_other = NULL, *rother = NULL;
153109998Smarkm	char *sign_certfile = NULL, *verify_certfile = NULL, *rcertfile = NULL;
154109998Smarkm	unsigned long sign_flags = 0, verify_flags = 0, rflags = 0;
155109998Smarkm	int ret = 1;
156109998Smarkm	int accept_count = -1;
157109998Smarkm	int badarg = 0;
158109998Smarkm	int i;
159120631Snectar	int ignore_err = 0;
160238405Sjkim	STACK_OF(OPENSSL_STRING) *reqnames = NULL;
161109998Smarkm	STACK_OF(OCSP_CERTID) *ids = NULL;
162109998Smarkm
163109998Smarkm	X509 *rca_cert = NULL;
164109998Smarkm	char *ridx_filename = NULL;
165109998Smarkm	char *rca_filename = NULL;
166127128Snectar	CA_DB *rdb = NULL;
167109998Smarkm	int nmin = 0, ndays = -1;
168238405Sjkim	const EVP_MD *cert_id_md = NULL;
169109998Smarkm
170109998Smarkm	if (bio_err == NULL) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
171109998Smarkm
172109998Smarkm	if (!load_config(bio_err, NULL))
173109998Smarkm		goto end;
174109998Smarkm	SSL_load_error_strings();
175167612Ssimon	OpenSSL_add_ssl_algorithms();
176109998Smarkm	args = argv + 1;
177238405Sjkim	reqnames = sk_OPENSSL_STRING_new_null();
178109998Smarkm	ids = sk_OCSP_CERTID_new_null();
179109998Smarkm	while (!badarg && *args && *args[0] == '-')
180109998Smarkm		{
181109998Smarkm		if (!strcmp(*args, "-out"))
182109998Smarkm			{
183109998Smarkm			if (args[1])
184109998Smarkm				{
185109998Smarkm				args++;
186109998Smarkm				outfile = *args;
187109998Smarkm				}
188109998Smarkm			else badarg = 1;
189109998Smarkm			}
190194206Ssimon		else if (!strcmp(*args, "-timeout"))
191194206Ssimon			{
192194206Ssimon			if (args[1])
193194206Ssimon				{
194194206Ssimon				args++;
195194206Ssimon				req_timeout = atol(*args);
196194206Ssimon				if (req_timeout < 0)
197194206Ssimon					{
198194206Ssimon					BIO_printf(bio_err,
199194206Ssimon						"Illegal timeout value %s\n",
200194206Ssimon						*args);
201194206Ssimon					badarg = 1;
202194206Ssimon					}
203194206Ssimon				}
204194206Ssimon			else badarg = 1;
205194206Ssimon			}
206109998Smarkm		else if (!strcmp(*args, "-url"))
207109998Smarkm			{
208279264Sdelphij			if (thost)
209279264Sdelphij				OPENSSL_free(thost);
210279264Sdelphij			if (tport)
211279264Sdelphij				OPENSSL_free(tport);
212279264Sdelphij			if (tpath)
213279264Sdelphij				OPENSSL_free(tpath);
214109998Smarkm			if (args[1])
215109998Smarkm				{
216109998Smarkm				args++;
217109998Smarkm				if (!OCSP_parse_url(*args, &host, &port, &path, &use_ssl))
218109998Smarkm					{
219109998Smarkm					BIO_printf(bio_err, "Error parsing URL\n");
220109998Smarkm					badarg = 1;
221109998Smarkm					}
222279264Sdelphij				thost = host;
223279264Sdelphij				tport = port;
224279264Sdelphij				tpath = path;
225109998Smarkm				}
226109998Smarkm			else badarg = 1;
227109998Smarkm			}
228109998Smarkm		else if (!strcmp(*args, "-host"))
229109998Smarkm			{
230109998Smarkm			if (args[1])
231109998Smarkm				{
232109998Smarkm				args++;
233109998Smarkm				host = *args;
234109998Smarkm				}
235109998Smarkm			else badarg = 1;
236109998Smarkm			}
237109998Smarkm		else if (!strcmp(*args, "-port"))
238109998Smarkm			{
239109998Smarkm			if (args[1])
240109998Smarkm				{
241109998Smarkm				args++;
242109998Smarkm				port = *args;
243109998Smarkm				}
244109998Smarkm			else badarg = 1;
245109998Smarkm			}
246238405Sjkim		else if (!strcmp(*args, "-header"))
247238405Sjkim			{
248238405Sjkim			if (args[1] && args[2])
249238405Sjkim				{
250238405Sjkim				if (!X509V3_add_value(args[1], args[2], &headers))
251238405Sjkim					goto end;
252238405Sjkim				args += 2;
253238405Sjkim				}
254238405Sjkim			else badarg = 1;
255238405Sjkim			}
256120631Snectar		else if (!strcmp(*args, "-ignore_err"))
257120631Snectar			ignore_err = 1;
258109998Smarkm		else if (!strcmp(*args, "-noverify"))
259109998Smarkm			noverify = 1;
260109998Smarkm		else if (!strcmp(*args, "-nonce"))
261109998Smarkm			add_nonce = 2;
262109998Smarkm		else if (!strcmp(*args, "-no_nonce"))
263109998Smarkm			add_nonce = 0;
264109998Smarkm		else if (!strcmp(*args, "-resp_no_certs"))
265109998Smarkm			rflags |= OCSP_NOCERTS;
266109998Smarkm		else if (!strcmp(*args, "-resp_key_id"))
267109998Smarkm			rflags |= OCSP_RESPID_KEY;
268109998Smarkm		else if (!strcmp(*args, "-no_certs"))
269109998Smarkm			sign_flags |= OCSP_NOCERTS;
270109998Smarkm		else if (!strcmp(*args, "-no_signature_verify"))
271109998Smarkm			verify_flags |= OCSP_NOSIGS;
272109998Smarkm		else if (!strcmp(*args, "-no_cert_verify"))
273109998Smarkm			verify_flags |= OCSP_NOVERIFY;
274109998Smarkm		else if (!strcmp(*args, "-no_chain"))
275109998Smarkm			verify_flags |= OCSP_NOCHAIN;
276109998Smarkm		else if (!strcmp(*args, "-no_cert_checks"))
277109998Smarkm			verify_flags |= OCSP_NOCHECKS;
278109998Smarkm		else if (!strcmp(*args, "-no_explicit"))
279109998Smarkm			verify_flags |= OCSP_NOEXPLICIT;
280109998Smarkm		else if (!strcmp(*args, "-trust_other"))
281109998Smarkm			verify_flags |= OCSP_TRUSTOTHER;
282109998Smarkm		else if (!strcmp(*args, "-no_intern"))
283109998Smarkm			verify_flags |= OCSP_NOINTERN;
284109998Smarkm		else if (!strcmp(*args, "-text"))
285109998Smarkm			{
286109998Smarkm			req_text = 1;
287109998Smarkm			resp_text = 1;
288109998Smarkm			}
289109998Smarkm		else if (!strcmp(*args, "-req_text"))
290109998Smarkm			req_text = 1;
291109998Smarkm		else if (!strcmp(*args, "-resp_text"))
292109998Smarkm			resp_text = 1;
293109998Smarkm		else if (!strcmp(*args, "-reqin"))
294109998Smarkm			{
295109998Smarkm			if (args[1])
296109998Smarkm				{
297109998Smarkm				args++;
298109998Smarkm				reqin = *args;
299109998Smarkm				}
300109998Smarkm			else badarg = 1;
301109998Smarkm			}
302109998Smarkm		else if (!strcmp(*args, "-respin"))
303109998Smarkm			{
304109998Smarkm			if (args[1])
305109998Smarkm				{
306109998Smarkm				args++;
307109998Smarkm				respin = *args;
308109998Smarkm				}
309109998Smarkm			else badarg = 1;
310109998Smarkm			}
311109998Smarkm		else if (!strcmp(*args, "-signer"))
312109998Smarkm			{
313109998Smarkm			if (args[1])
314109998Smarkm				{
315109998Smarkm				args++;
316109998Smarkm				signfile = *args;
317109998Smarkm				}
318109998Smarkm			else badarg = 1;
319109998Smarkm			}
320109998Smarkm		else if (!strcmp (*args, "-VAfile"))
321109998Smarkm			{
322109998Smarkm			if (args[1])
323109998Smarkm				{
324109998Smarkm				args++;
325109998Smarkm				verify_certfile = *args;
326109998Smarkm				verify_flags |= OCSP_TRUSTOTHER;
327109998Smarkm				}
328109998Smarkm			else badarg = 1;
329109998Smarkm			}
330109998Smarkm		else if (!strcmp(*args, "-sign_other"))
331109998Smarkm			{
332109998Smarkm			if (args[1])
333109998Smarkm				{
334109998Smarkm				args++;
335109998Smarkm				sign_certfile = *args;
336109998Smarkm				}
337109998Smarkm			else badarg = 1;
338109998Smarkm			}
339109998Smarkm		else if (!strcmp(*args, "-verify_other"))
340109998Smarkm			{
341109998Smarkm			if (args[1])
342109998Smarkm				{
343109998Smarkm				args++;
344109998Smarkm				verify_certfile = *args;
345109998Smarkm				}
346109998Smarkm			else badarg = 1;
347109998Smarkm			}
348109998Smarkm		else if (!strcmp (*args, "-CAfile"))
349109998Smarkm			{
350109998Smarkm			if (args[1])
351109998Smarkm				{
352109998Smarkm				args++;
353109998Smarkm				CAfile = *args;
354109998Smarkm				}
355109998Smarkm			else badarg = 1;
356109998Smarkm			}
357109998Smarkm		else if (!strcmp (*args, "-CApath"))
358109998Smarkm			{
359109998Smarkm			if (args[1])
360109998Smarkm				{
361109998Smarkm				args++;
362109998Smarkm				CApath = *args;
363109998Smarkm				}
364109998Smarkm			else badarg = 1;
365109998Smarkm			}
366109998Smarkm		else if (!strcmp (*args, "-validity_period"))
367109998Smarkm			{
368109998Smarkm			if (args[1])
369109998Smarkm				{
370109998Smarkm				args++;
371109998Smarkm				nsec = atol(*args);
372109998Smarkm				if (nsec < 0)
373109998Smarkm					{
374109998Smarkm					BIO_printf(bio_err,
375109998Smarkm						"Illegal validity period %s\n",
376109998Smarkm						*args);
377109998Smarkm					badarg = 1;
378109998Smarkm					}
379109998Smarkm				}
380109998Smarkm			else badarg = 1;
381109998Smarkm			}
382109998Smarkm		else if (!strcmp (*args, "-status_age"))
383109998Smarkm			{
384109998Smarkm			if (args[1])
385109998Smarkm				{
386109998Smarkm				args++;
387109998Smarkm				maxage = atol(*args);
388109998Smarkm				if (maxage < 0)
389109998Smarkm					{
390109998Smarkm					BIO_printf(bio_err,
391109998Smarkm						"Illegal validity age %s\n",
392109998Smarkm						*args);
393109998Smarkm					badarg = 1;
394109998Smarkm					}
395109998Smarkm				}
396109998Smarkm			else badarg = 1;
397109998Smarkm			}
398109998Smarkm		 else if (!strcmp(*args, "-signkey"))
399109998Smarkm			{
400109998Smarkm			if (args[1])
401109998Smarkm				{
402109998Smarkm				args++;
403109998Smarkm				keyfile = *args;
404109998Smarkm				}
405109998Smarkm			else badarg = 1;
406109998Smarkm			}
407109998Smarkm		else if (!strcmp(*args, "-reqout"))
408109998Smarkm			{
409109998Smarkm			if (args[1])
410109998Smarkm				{
411109998Smarkm				args++;
412109998Smarkm				reqout = *args;
413109998Smarkm				}
414109998Smarkm			else badarg = 1;
415109998Smarkm			}
416109998Smarkm		else if (!strcmp(*args, "-respout"))
417109998Smarkm			{
418109998Smarkm			if (args[1])
419109998Smarkm				{
420109998Smarkm				args++;
421109998Smarkm				respout = *args;
422109998Smarkm				}
423109998Smarkm			else badarg = 1;
424109998Smarkm			}
425109998Smarkm		 else if (!strcmp(*args, "-path"))
426109998Smarkm			{
427109998Smarkm			if (args[1])
428109998Smarkm				{
429109998Smarkm				args++;
430109998Smarkm				path = *args;
431109998Smarkm				}
432109998Smarkm			else badarg = 1;
433109998Smarkm			}
434109998Smarkm		else if (!strcmp(*args, "-issuer"))
435109998Smarkm			{
436109998Smarkm			if (args[1])
437109998Smarkm				{
438109998Smarkm				args++;
439109998Smarkm				X509_free(issuer);
440109998Smarkm				issuer = load_cert(bio_err, *args, FORMAT_PEM,
441109998Smarkm					NULL, e, "issuer certificate");
442109998Smarkm				if(!issuer) goto end;
443109998Smarkm				}
444109998Smarkm			else badarg = 1;
445109998Smarkm			}
446109998Smarkm		else if (!strcmp (*args, "-cert"))
447109998Smarkm			{
448109998Smarkm			if (args[1])
449109998Smarkm				{
450109998Smarkm				args++;
451109998Smarkm				X509_free(cert);
452109998Smarkm				cert = load_cert(bio_err, *args, FORMAT_PEM,
453109998Smarkm					NULL, e, "certificate");
454109998Smarkm				if(!cert) goto end;
455238405Sjkim				if (!cert_id_md) cert_id_md = EVP_sha1();
456238405Sjkim				if(!add_ocsp_cert(&req, cert, cert_id_md, issuer, ids))
457109998Smarkm					goto end;
458238405Sjkim				if(!sk_OPENSSL_STRING_push(reqnames, *args))
459109998Smarkm					goto end;
460109998Smarkm				}
461109998Smarkm			else badarg = 1;
462109998Smarkm			}
463109998Smarkm		else if (!strcmp(*args, "-serial"))
464109998Smarkm			{
465109998Smarkm			if (args[1])
466109998Smarkm				{
467109998Smarkm				args++;
468238405Sjkim				if (!cert_id_md) cert_id_md = EVP_sha1();
469238405Sjkim				if(!add_ocsp_serial(&req, *args, cert_id_md, issuer, ids))
470109998Smarkm					goto end;
471238405Sjkim				if(!sk_OPENSSL_STRING_push(reqnames, *args))
472109998Smarkm					goto end;
473109998Smarkm				}
474109998Smarkm			else badarg = 1;
475109998Smarkm			}
476109998Smarkm		else if (!strcmp(*args, "-index"))
477109998Smarkm			{
478109998Smarkm			if (args[1])
479109998Smarkm				{
480109998Smarkm				args++;
481109998Smarkm				ridx_filename = *args;
482109998Smarkm				}
483109998Smarkm			else badarg = 1;
484109998Smarkm			}
485109998Smarkm		else if (!strcmp(*args, "-CA"))
486109998Smarkm			{
487109998Smarkm			if (args[1])
488109998Smarkm				{
489109998Smarkm				args++;
490109998Smarkm				rca_filename = *args;
491109998Smarkm				}
492109998Smarkm			else badarg = 1;
493109998Smarkm			}
494109998Smarkm		else if (!strcmp (*args, "-nmin"))
495109998Smarkm			{
496109998Smarkm			if (args[1])
497109998Smarkm				{
498109998Smarkm				args++;
499109998Smarkm				nmin = atol(*args);
500109998Smarkm				if (nmin < 0)
501109998Smarkm					{
502109998Smarkm					BIO_printf(bio_err,
503109998Smarkm						"Illegal update period %s\n",
504109998Smarkm						*args);
505109998Smarkm					badarg = 1;
506109998Smarkm					}
507109998Smarkm				}
508109998Smarkm				if (ndays == -1)
509109998Smarkm					ndays = 0;
510109998Smarkm			else badarg = 1;
511109998Smarkm			}
512109998Smarkm		else if (!strcmp (*args, "-nrequest"))
513109998Smarkm			{
514109998Smarkm			if (args[1])
515109998Smarkm				{
516109998Smarkm				args++;
517109998Smarkm				accept_count = atol(*args);
518109998Smarkm				if (accept_count < 0)
519109998Smarkm					{
520109998Smarkm					BIO_printf(bio_err,
521109998Smarkm						"Illegal accept count %s\n",
522109998Smarkm						*args);
523109998Smarkm					badarg = 1;
524109998Smarkm					}
525109998Smarkm				}
526109998Smarkm			else badarg = 1;
527109998Smarkm			}
528109998Smarkm		else if (!strcmp (*args, "-ndays"))
529109998Smarkm			{
530109998Smarkm			if (args[1])
531109998Smarkm				{
532109998Smarkm				args++;
533109998Smarkm				ndays = atol(*args);
534109998Smarkm				if (ndays < 0)
535109998Smarkm					{
536109998Smarkm					BIO_printf(bio_err,
537109998Smarkm						"Illegal update period %s\n",
538109998Smarkm						*args);
539109998Smarkm					badarg = 1;
540109998Smarkm					}
541109998Smarkm				}
542109998Smarkm			else badarg = 1;
543109998Smarkm			}
544109998Smarkm		else if (!strcmp(*args, "-rsigner"))
545109998Smarkm			{
546109998Smarkm			if (args[1])
547109998Smarkm				{
548109998Smarkm				args++;
549109998Smarkm				rsignfile = *args;
550109998Smarkm				}
551109998Smarkm			else badarg = 1;
552109998Smarkm			}
553109998Smarkm		else if (!strcmp(*args, "-rkey"))
554109998Smarkm			{
555109998Smarkm			if (args[1])
556109998Smarkm				{
557109998Smarkm				args++;
558109998Smarkm				rkeyfile = *args;
559109998Smarkm				}
560109998Smarkm			else badarg = 1;
561109998Smarkm			}
562109998Smarkm		else if (!strcmp(*args, "-rother"))
563109998Smarkm			{
564109998Smarkm			if (args[1])
565109998Smarkm				{
566109998Smarkm				args++;
567109998Smarkm				rcertfile = *args;
568109998Smarkm				}
569109998Smarkm			else badarg = 1;
570109998Smarkm			}
571238405Sjkim		else if ((cert_id_md = EVP_get_digestbyname((*args)+1))==NULL)
572238405Sjkim			{
573238405Sjkim			badarg = 1;
574238405Sjkim			}
575109998Smarkm		args++;
576109998Smarkm		}
577109998Smarkm
578109998Smarkm	/* Have we anything to do? */
579109998Smarkm	if (!req && !reqin && !respin && !(port && ridx_filename)) badarg = 1;
580109998Smarkm
581109998Smarkm	if (badarg)
582109998Smarkm		{
583109998Smarkm		BIO_printf (bio_err, "OCSP utility\n");
584109998Smarkm		BIO_printf (bio_err, "Usage ocsp [options]\n");
585109998Smarkm		BIO_printf (bio_err, "where options are\n");
586279264Sdelphij		BIO_printf (bio_err, "-out file            output filename\n");
587279264Sdelphij		BIO_printf (bio_err, "-issuer file         issuer certificate\n");
588279264Sdelphij		BIO_printf (bio_err, "-cert file           certificate to check\n");
589279264Sdelphij		BIO_printf (bio_err, "-serial n            serial number to check\n");
590279264Sdelphij		BIO_printf (bio_err, "-signer file         certificate to sign OCSP request with\n");
591279264Sdelphij		BIO_printf (bio_err, "-signkey file        private key to sign OCSP request with\n");
592279264Sdelphij		BIO_printf (bio_err, "-sign_other file     additional certificates to include in signed request\n");
593279264Sdelphij		BIO_printf (bio_err, "-no_certs            don't include any certificates in signed request\n");
594279264Sdelphij		BIO_printf (bio_err, "-req_text            print text form of request\n");
595279264Sdelphij		BIO_printf (bio_err, "-resp_text           print text form of response\n");
596279264Sdelphij		BIO_printf (bio_err, "-text                print text form of request and response\n");
597279264Sdelphij		BIO_printf (bio_err, "-reqout file         write DER encoded OCSP request to \"file\"\n");
598279264Sdelphij		BIO_printf (bio_err, "-respout file        write DER encoded OCSP reponse to \"file\"\n");
599279264Sdelphij		BIO_printf (bio_err, "-reqin file          read DER encoded OCSP request from \"file\"\n");
600279264Sdelphij		BIO_printf (bio_err, "-respin file         read DER encoded OCSP reponse from \"file\"\n");
601279264Sdelphij		BIO_printf (bio_err, "-nonce               add OCSP nonce to request\n");
602279264Sdelphij		BIO_printf (bio_err, "-no_nonce            don't add OCSP nonce to request\n");
603279264Sdelphij		BIO_printf (bio_err, "-url URL             OCSP responder URL\n");
604279264Sdelphij		BIO_printf (bio_err, "-host host:n         send OCSP request to host on port n\n");
605279264Sdelphij		BIO_printf (bio_err, "-path                path to use in OCSP request\n");
606279264Sdelphij		BIO_printf (bio_err, "-CApath dir          trusted certificates directory\n");
607279264Sdelphij		BIO_printf (bio_err, "-CAfile file         trusted certificates file\n");
608279264Sdelphij		BIO_printf (bio_err, "-VAfile file         validator certificates file\n");
609279264Sdelphij		BIO_printf (bio_err, "-validity_period n   maximum validity discrepancy in seconds\n");
610279264Sdelphij		BIO_printf (bio_err, "-status_age n        maximum status age in seconds\n");
611279264Sdelphij		BIO_printf (bio_err, "-noverify            don't verify response at all\n");
612279264Sdelphij		BIO_printf (bio_err, "-verify_other file   additional certificates to search for signer\n");
613279264Sdelphij		BIO_printf (bio_err, "-trust_other         don't verify additional certificates\n");
614279264Sdelphij		BIO_printf (bio_err, "-no_intern           don't search certificates contained in response for signer\n");
615120631Snectar		BIO_printf (bio_err, "-no_signature_verify don't check signature on response\n");
616279264Sdelphij		BIO_printf (bio_err, "-no_cert_verify      don't check signing certificate\n");
617279264Sdelphij		BIO_printf (bio_err, "-no_chain            don't chain verify response\n");
618279264Sdelphij		BIO_printf (bio_err, "-no_cert_checks      don't do additional checks on signing certificate\n");
619279264Sdelphij		BIO_printf (bio_err, "-port num            port to run responder on\n");
620279264Sdelphij		BIO_printf (bio_err, "-index file          certificate status index file\n");
621279264Sdelphij		BIO_printf (bio_err, "-CA file             CA certificate\n");
622279264Sdelphij		BIO_printf (bio_err, "-rsigner file        responder certificate to sign responses with\n");
623279264Sdelphij		BIO_printf (bio_err, "-rkey file           responder key to sign responses with\n");
624279264Sdelphij		BIO_printf (bio_err, "-rother file         other certificates to include in response\n");
625279264Sdelphij		BIO_printf (bio_err, "-resp_no_certs       don't include any certificates in response\n");
626279264Sdelphij		BIO_printf (bio_err, "-nmin n              number of minutes before next update\n");
627279264Sdelphij		BIO_printf (bio_err, "-ndays n             number of days before next update\n");
628279264Sdelphij		BIO_printf (bio_err, "-resp_key_id         identify reponse by signing certificate key ID\n");
629279264Sdelphij		BIO_printf (bio_err, "-nrequest n          number of requests to accept (default unlimited)\n");
630279264Sdelphij		BIO_printf (bio_err, "-<dgst alg>          use specified digest in the request\n");
631279264Sdelphij		BIO_printf (bio_err, "-timeout n           timeout connection to OCSP responder after n seconds\n");
632109998Smarkm		goto end;
633109998Smarkm		}
634109998Smarkm
635109998Smarkm	if(outfile) out = BIO_new_file(outfile, "w");
636109998Smarkm	else out = BIO_new_fp(stdout, BIO_NOCLOSE);
637109998Smarkm
638109998Smarkm	if(!out)
639109998Smarkm		{
640109998Smarkm		BIO_printf(bio_err, "Error opening output file\n");
641109998Smarkm		goto end;
642109998Smarkm		}
643109998Smarkm
644109998Smarkm	if (!req && (add_nonce != 2)) add_nonce = 0;
645109998Smarkm
646109998Smarkm	if (!req && reqin)
647109998Smarkm		{
648109998Smarkm		derbio = BIO_new_file(reqin, "rb");
649109998Smarkm		if (!derbio)
650109998Smarkm			{
651109998Smarkm			BIO_printf(bio_err, "Error Opening OCSP request file\n");
652109998Smarkm			goto end;
653109998Smarkm			}
654109998Smarkm		req = d2i_OCSP_REQUEST_bio(derbio, NULL);
655109998Smarkm		BIO_free(derbio);
656109998Smarkm		if(!req)
657109998Smarkm			{
658109998Smarkm			BIO_printf(bio_err, "Error reading OCSP request\n");
659109998Smarkm			goto end;
660109998Smarkm			}
661109998Smarkm		}
662109998Smarkm
663109998Smarkm	if (!req && port)
664109998Smarkm		{
665109998Smarkm		acbio = init_responder(port);
666109998Smarkm		if (!acbio)
667109998Smarkm			goto end;
668109998Smarkm		}
669109998Smarkm
670109998Smarkm	if (rsignfile && !rdb)
671109998Smarkm		{
672109998Smarkm		if (!rkeyfile) rkeyfile = rsignfile;
673109998Smarkm		rsigner = load_cert(bio_err, rsignfile, FORMAT_PEM,
674109998Smarkm			NULL, e, "responder certificate");
675109998Smarkm		if (!rsigner)
676109998Smarkm			{
677109998Smarkm			BIO_printf(bio_err, "Error loading responder certificate\n");
678109998Smarkm			goto end;
679109998Smarkm			}
680109998Smarkm		rca_cert = load_cert(bio_err, rca_filename, FORMAT_PEM,
681109998Smarkm			NULL, e, "CA certificate");
682109998Smarkm		if (rcertfile)
683109998Smarkm			{
684109998Smarkm			rother = load_certs(bio_err, rcertfile, FORMAT_PEM,
685109998Smarkm				NULL, e, "responder other certificates");
686109998Smarkm			if (!rother) goto end;
687109998Smarkm			}
688109998Smarkm		rkey = load_key(bio_err, rkeyfile, FORMAT_PEM, 0, NULL, NULL,
689109998Smarkm			"responder private key");
690109998Smarkm		if (!rkey)
691109998Smarkm			goto end;
692109998Smarkm		}
693109998Smarkm	if(acbio)
694109998Smarkm		BIO_printf(bio_err, "Waiting for OCSP client connections...\n");
695109998Smarkm
696109998Smarkm	redo_accept:
697109998Smarkm
698109998Smarkm	if (acbio)
699109998Smarkm		{
700109998Smarkm		if (!do_responder(&req, &cbio, acbio, port))
701109998Smarkm			goto end;
702109998Smarkm		if (!req)
703109998Smarkm			{
704109998Smarkm			resp = OCSP_response_create(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, NULL);
705109998Smarkm			send_ocsp_response(cbio, resp);
706109998Smarkm			goto done_resp;
707109998Smarkm			}
708109998Smarkm		}
709109998Smarkm
710109998Smarkm	if (!req && (signfile || reqout || host || add_nonce || ridx_filename))
711109998Smarkm		{
712109998Smarkm		BIO_printf(bio_err, "Need an OCSP request for this operation!\n");
713109998Smarkm		goto end;
714109998Smarkm		}
715109998Smarkm
716109998Smarkm	if (req && add_nonce) OCSP_request_add1_nonce(req, NULL, -1);
717109998Smarkm
718109998Smarkm	if (signfile)
719109998Smarkm		{
720109998Smarkm		if (!keyfile) keyfile = signfile;
721109998Smarkm		signer = load_cert(bio_err, signfile, FORMAT_PEM,
722109998Smarkm			NULL, e, "signer certificate");
723109998Smarkm		if (!signer)
724109998Smarkm			{
725109998Smarkm			BIO_printf(bio_err, "Error loading signer certificate\n");
726109998Smarkm			goto end;
727109998Smarkm			}
728109998Smarkm		if (sign_certfile)
729109998Smarkm			{
730109998Smarkm			sign_other = load_certs(bio_err, sign_certfile, FORMAT_PEM,
731109998Smarkm				NULL, e, "signer certificates");
732109998Smarkm			if (!sign_other) goto end;
733109998Smarkm			}
734109998Smarkm		key = load_key(bio_err, keyfile, FORMAT_PEM, 0, NULL, NULL,
735109998Smarkm			"signer private key");
736109998Smarkm		if (!key)
737109998Smarkm			goto end;
738238405Sjkim
739238405Sjkim		if (!OCSP_request_sign(req, signer, key, NULL, sign_other, sign_flags))
740109998Smarkm			{
741109998Smarkm			BIO_printf(bio_err, "Error signing OCSP request\n");
742109998Smarkm			goto end;
743109998Smarkm			}
744109998Smarkm		}
745109998Smarkm
746109998Smarkm	if (req_text && req) OCSP_REQUEST_print(out, req, 0);
747109998Smarkm
748109998Smarkm	if (reqout)
749109998Smarkm		{
750109998Smarkm		derbio = BIO_new_file(reqout, "wb");
751109998Smarkm		if(!derbio)
752109998Smarkm			{
753109998Smarkm			BIO_printf(bio_err, "Error opening file %s\n", reqout);
754109998Smarkm			goto end;
755109998Smarkm			}
756109998Smarkm		i2d_OCSP_REQUEST_bio(derbio, req);
757109998Smarkm		BIO_free(derbio);
758109998Smarkm		}
759109998Smarkm
760109998Smarkm	if (ridx_filename && (!rkey || !rsigner || !rca_cert))
761109998Smarkm		{
762109998Smarkm		BIO_printf(bio_err, "Need a responder certificate, key and CA for this operation!\n");
763109998Smarkm		goto end;
764109998Smarkm		}
765109998Smarkm
766109998Smarkm	if (ridx_filename && !rdb)
767109998Smarkm		{
768127128Snectar		rdb = load_index(ridx_filename, NULL);
769127128Snectar		if (!rdb) goto end;
770127128Snectar		if (!index_index(rdb)) goto end;
771109998Smarkm		}
772109998Smarkm
773109998Smarkm	if (rdb)
774109998Smarkm		{
775109998Smarkm		i = make_ocsp_response(&resp, req, rdb, rca_cert, rsigner, rkey, rother, rflags, nmin, ndays);
776109998Smarkm		if (cbio)
777109998Smarkm			send_ocsp_response(cbio, resp);
778109998Smarkm		}
779109998Smarkm	else if (host)
780109998Smarkm		{
781111147Snectar#ifndef OPENSSL_NO_SOCK
782194206Ssimon		resp = process_responder(bio_err, req, host, path,
783238405Sjkim					port, use_ssl, headers, req_timeout);
784194206Ssimon		if (!resp)
785194206Ssimon			goto end;
786111147Snectar#else
787111147Snectar		BIO_printf(bio_err, "Error creating connect BIO - sockets not supported.\n");
788111147Snectar		goto end;
789111147Snectar#endif
790109998Smarkm		}
791109998Smarkm	else if (respin)
792109998Smarkm		{
793109998Smarkm		derbio = BIO_new_file(respin, "rb");
794109998Smarkm		if (!derbio)
795109998Smarkm			{
796109998Smarkm			BIO_printf(bio_err, "Error Opening OCSP response file\n");
797109998Smarkm			goto end;
798109998Smarkm			}
799109998Smarkm		resp = d2i_OCSP_RESPONSE_bio(derbio, NULL);
800109998Smarkm		BIO_free(derbio);
801109998Smarkm		if(!resp)
802109998Smarkm			{
803109998Smarkm			BIO_printf(bio_err, "Error reading OCSP response\n");
804109998Smarkm			goto end;
805109998Smarkm			}
806109998Smarkm
807109998Smarkm		}
808109998Smarkm	else
809109998Smarkm		{
810109998Smarkm		ret = 0;
811109998Smarkm		goto end;
812109998Smarkm		}
813109998Smarkm
814109998Smarkm	done_resp:
815109998Smarkm
816109998Smarkm	if (respout)
817109998Smarkm		{
818109998Smarkm		derbio = BIO_new_file(respout, "wb");
819109998Smarkm		if(!derbio)
820109998Smarkm			{
821109998Smarkm			BIO_printf(bio_err, "Error opening file %s\n", respout);
822109998Smarkm			goto end;
823109998Smarkm			}
824109998Smarkm		i2d_OCSP_RESPONSE_bio(derbio, resp);
825109998Smarkm		BIO_free(derbio);
826109998Smarkm		}
827109998Smarkm
828109998Smarkm	i = OCSP_response_status(resp);
829109998Smarkm
830109998Smarkm	if (i != OCSP_RESPONSE_STATUS_SUCCESSFUL)
831109998Smarkm		{
832160814Ssimon		BIO_printf(out, "Responder Error: %s (%d)\n",
833109998Smarkm				OCSP_response_status_str(i), i);
834120631Snectar		if (ignore_err)
835120631Snectar			goto redo_accept;
836109998Smarkm		ret = 0;
837109998Smarkm		goto end;
838109998Smarkm		}
839109998Smarkm
840109998Smarkm	if (resp_text) OCSP_RESPONSE_print(out, resp, 0);
841109998Smarkm
842109998Smarkm	/* If running as responder don't verify our own response */
843109998Smarkm	if (cbio)
844109998Smarkm		{
845109998Smarkm		if (accept_count > 0)
846109998Smarkm			accept_count--;
847109998Smarkm		/* Redo if more connections needed */
848109998Smarkm		if (accept_count)
849109998Smarkm			{
850109998Smarkm			BIO_free_all(cbio);
851109998Smarkm			cbio = NULL;
852109998Smarkm			OCSP_REQUEST_free(req);
853109998Smarkm			req = NULL;
854109998Smarkm			OCSP_RESPONSE_free(resp);
855109998Smarkm			resp = NULL;
856109998Smarkm			goto redo_accept;
857109998Smarkm			}
858109998Smarkm		goto end;
859109998Smarkm		}
860109998Smarkm
861109998Smarkm	if (!store)
862109998Smarkm		store = setup_verify(bio_err, CAfile, CApath);
863109998Smarkm	if (!store)
864109998Smarkm		goto end;
865109998Smarkm	if (verify_certfile)
866109998Smarkm		{
867109998Smarkm		verify_other = load_certs(bio_err, verify_certfile, FORMAT_PEM,
868109998Smarkm			NULL, e, "validator certificate");
869109998Smarkm		if (!verify_other) goto end;
870109998Smarkm		}
871109998Smarkm
872109998Smarkm	bs = OCSP_response_get1_basic(resp);
873109998Smarkm
874109998Smarkm	if (!bs)
875109998Smarkm		{
876109998Smarkm		BIO_printf(bio_err, "Error parsing response\n");
877109998Smarkm		goto end;
878109998Smarkm		}
879109998Smarkm
880109998Smarkm	if (!noverify)
881109998Smarkm		{
882109998Smarkm		if (req && ((i = OCSP_check_nonce(req, bs)) <= 0))
883109998Smarkm			{
884109998Smarkm			if (i == -1)
885109998Smarkm				BIO_printf(bio_err, "WARNING: no nonce in response\n");
886109998Smarkm			else
887109998Smarkm				{
888109998Smarkm				BIO_printf(bio_err, "Nonce Verify error\n");
889109998Smarkm				goto end;
890109998Smarkm				}
891109998Smarkm			}
892109998Smarkm
893109998Smarkm		i = OCSP_basic_verify(bs, verify_other, store, verify_flags);
894109998Smarkm                if (i < 0) i = OCSP_basic_verify(bs, NULL, store, 0);
895109998Smarkm
896109998Smarkm		if(i <= 0)
897109998Smarkm			{
898160814Ssimon			BIO_printf(bio_err, "Response Verify Failure\n");
899109998Smarkm			ERR_print_errors(bio_err);
900109998Smarkm			}
901109998Smarkm		else
902109998Smarkm			BIO_printf(bio_err, "Response verify OK\n");
903109998Smarkm
904109998Smarkm		}
905109998Smarkm
906109998Smarkm	if (!print_ocsp_summary(out, bs, req, reqnames, ids, nsec, maxage))
907109998Smarkm		goto end;
908109998Smarkm
909109998Smarkm	ret = 0;
910109998Smarkm
911109998Smarkmend:
912109998Smarkm	ERR_print_errors(bio_err);
913109998Smarkm	X509_free(signer);
914109998Smarkm	X509_STORE_free(store);
915109998Smarkm	EVP_PKEY_free(key);
916109998Smarkm	EVP_PKEY_free(rkey);
917109998Smarkm	X509_free(issuer);
918109998Smarkm	X509_free(cert);
919109998Smarkm	X509_free(rsigner);
920109998Smarkm	X509_free(rca_cert);
921127128Snectar	free_index(rdb);
922109998Smarkm	BIO_free_all(cbio);
923109998Smarkm	BIO_free_all(acbio);
924109998Smarkm	BIO_free(out);
925109998Smarkm	OCSP_REQUEST_free(req);
926109998Smarkm	OCSP_RESPONSE_free(resp);
927109998Smarkm	OCSP_BASICRESP_free(bs);
928238405Sjkim	sk_OPENSSL_STRING_free(reqnames);
929109998Smarkm	sk_OCSP_CERTID_free(ids);
930109998Smarkm	sk_X509_pop_free(sign_other, X509_free);
931109998Smarkm	sk_X509_pop_free(verify_other, X509_free);
932238405Sjkim	sk_CONF_VALUE_pop_free(headers, X509V3_conf_free);
933109998Smarkm
934279264Sdelphij	if (thost)
935279264Sdelphij		OPENSSL_free(thost);
936279264Sdelphij	if (tport)
937279264Sdelphij		OPENSSL_free(tport);
938279264Sdelphij	if (tpath)
939279264Sdelphij		OPENSSL_free(tpath);
940109998Smarkm
941109998Smarkm	OPENSSL_EXIT(ret);
942109998Smarkm}
943109998Smarkm
944238405Sjkimstatic int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, const EVP_MD *cert_id_md,X509 *issuer,
945109998Smarkm				STACK_OF(OCSP_CERTID) *ids)
946109998Smarkm	{
947109998Smarkm	OCSP_CERTID *id;
948109998Smarkm	if(!issuer)
949109998Smarkm		{
950109998Smarkm		BIO_printf(bio_err, "No issuer certificate specified\n");
951109998Smarkm		return 0;
952109998Smarkm		}
953109998Smarkm	if(!*req) *req = OCSP_REQUEST_new();
954109998Smarkm	if(!*req) goto err;
955238405Sjkim	id = OCSP_cert_to_id(cert_id_md, cert, issuer);
956109998Smarkm	if(!id || !sk_OCSP_CERTID_push(ids, id)) goto err;
957109998Smarkm	if(!OCSP_request_add0_id(*req, id)) goto err;
958109998Smarkm	return 1;
959109998Smarkm
960109998Smarkm	err:
961109998Smarkm	BIO_printf(bio_err, "Error Creating OCSP request\n");
962109998Smarkm	return 0;
963109998Smarkm	}
964109998Smarkm
965238405Sjkimstatic int add_ocsp_serial(OCSP_REQUEST **req, char *serial,const EVP_MD *cert_id_md, X509 *issuer,
966109998Smarkm				STACK_OF(OCSP_CERTID) *ids)
967109998Smarkm	{
968109998Smarkm	OCSP_CERTID *id;
969109998Smarkm	X509_NAME *iname;
970109998Smarkm	ASN1_BIT_STRING *ikey;
971109998Smarkm	ASN1_INTEGER *sno;
972109998Smarkm	if(!issuer)
973109998Smarkm		{
974109998Smarkm		BIO_printf(bio_err, "No issuer certificate specified\n");
975109998Smarkm		return 0;
976109998Smarkm		}
977109998Smarkm	if(!*req) *req = OCSP_REQUEST_new();
978109998Smarkm	if(!*req) goto err;
979109998Smarkm	iname = X509_get_subject_name(issuer);
980109998Smarkm	ikey = X509_get0_pubkey_bitstr(issuer);
981109998Smarkm	sno = s2i_ASN1_INTEGER(NULL, serial);
982109998Smarkm	if(!sno)
983109998Smarkm		{
984109998Smarkm		BIO_printf(bio_err, "Error converting serial number %s\n", serial);
985109998Smarkm		return 0;
986109998Smarkm		}
987238405Sjkim	id = OCSP_cert_id_new(cert_id_md, iname, ikey, sno);
988109998Smarkm	ASN1_INTEGER_free(sno);
989109998Smarkm	if(!id || !sk_OCSP_CERTID_push(ids, id)) goto err;
990109998Smarkm	if(!OCSP_request_add0_id(*req, id)) goto err;
991109998Smarkm	return 1;
992109998Smarkm
993109998Smarkm	err:
994109998Smarkm	BIO_printf(bio_err, "Error Creating OCSP request\n");
995109998Smarkm	return 0;
996109998Smarkm	}
997109998Smarkm
998109998Smarkmstatic int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req,
999238405Sjkim			      STACK_OF(OPENSSL_STRING) *names,
1000238405Sjkim			      STACK_OF(OCSP_CERTID) *ids, long nsec,
1001238405Sjkim			      long maxage)
1002109998Smarkm	{
1003109998Smarkm	OCSP_CERTID *id;
1004109998Smarkm	char *name;
1005109998Smarkm	int i;
1006109998Smarkm
1007109998Smarkm	int status, reason;
1008109998Smarkm
1009109998Smarkm	ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
1010109998Smarkm
1011238405Sjkim	if (!bs || !req || !sk_OPENSSL_STRING_num(names) || !sk_OCSP_CERTID_num(ids))
1012109998Smarkm		return 1;
1013109998Smarkm
1014109998Smarkm	for (i = 0; i < sk_OCSP_CERTID_num(ids); i++)
1015109998Smarkm		{
1016109998Smarkm		id = sk_OCSP_CERTID_value(ids, i);
1017238405Sjkim		name = sk_OPENSSL_STRING_value(names, i);
1018109998Smarkm		BIO_printf(out, "%s: ", name);
1019109998Smarkm
1020109998Smarkm		if(!OCSP_resp_find_status(bs, id, &status, &reason,
1021109998Smarkm					&rev, &thisupd, &nextupd))
1022109998Smarkm			{
1023109998Smarkm			BIO_puts(out, "ERROR: No Status found.\n");
1024109998Smarkm			continue;
1025109998Smarkm			}
1026109998Smarkm
1027109998Smarkm		/* Check validity: if invalid write to output BIO so we
1028109998Smarkm		 * know which response this refers to.
1029109998Smarkm		 */
1030109998Smarkm		if (!OCSP_check_validity(thisupd, nextupd, nsec, maxage))
1031109998Smarkm			{
1032109998Smarkm			BIO_puts(out, "WARNING: Status times invalid.\n");
1033109998Smarkm			ERR_print_errors(out);
1034109998Smarkm			}
1035109998Smarkm		BIO_printf(out, "%s\n", OCSP_cert_status_str(status));
1036109998Smarkm
1037109998Smarkm		BIO_puts(out, "\tThis Update: ");
1038109998Smarkm		ASN1_GENERALIZEDTIME_print(out, thisupd);
1039109998Smarkm		BIO_puts(out, "\n");
1040109998Smarkm
1041109998Smarkm		if(nextupd)
1042109998Smarkm			{
1043109998Smarkm			BIO_puts(out, "\tNext Update: ");
1044109998Smarkm			ASN1_GENERALIZEDTIME_print(out, nextupd);
1045109998Smarkm			BIO_puts(out, "\n");
1046109998Smarkm			}
1047109998Smarkm
1048109998Smarkm		if (status != V_OCSP_CERTSTATUS_REVOKED)
1049109998Smarkm			continue;
1050109998Smarkm
1051109998Smarkm		if (reason != -1)
1052109998Smarkm			BIO_printf(out, "\tReason: %s\n",
1053109998Smarkm				OCSP_crl_reason_str(reason));
1054109998Smarkm
1055109998Smarkm		BIO_puts(out, "\tRevocation Time: ");
1056109998Smarkm		ASN1_GENERALIZEDTIME_print(out, rev);
1057109998Smarkm		BIO_puts(out, "\n");
1058109998Smarkm		}
1059109998Smarkm
1060109998Smarkm	return 1;
1061109998Smarkm	}
1062109998Smarkm
1063109998Smarkm
1064127128Snectarstatic int make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req, CA_DB *db,
1065109998Smarkm			X509 *ca, X509 *rcert, EVP_PKEY *rkey,
1066109998Smarkm			STACK_OF(X509) *rother, unsigned long flags,
1067109998Smarkm			int nmin, int ndays)
1068109998Smarkm	{
1069109998Smarkm	ASN1_TIME *thisupd = NULL, *nextupd = NULL;
1070109998Smarkm	OCSP_CERTID *cid, *ca_id = NULL;
1071109998Smarkm	OCSP_BASICRESP *bs = NULL;
1072109998Smarkm	int i, id_count, ret = 1;
1073109998Smarkm
1074109998Smarkm	id_count = OCSP_request_onereq_count(req);
1075109998Smarkm
1076109998Smarkm	if (id_count <= 0)
1077109998Smarkm		{
1078109998Smarkm		*resp = OCSP_response_create(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, NULL);
1079109998Smarkm		goto end;
1080109998Smarkm		}
1081109998Smarkm
1082109998Smarkm
1083109998Smarkm	bs = OCSP_BASICRESP_new();
1084109998Smarkm	thisupd = X509_gmtime_adj(NULL, 0);
1085109998Smarkm	if (ndays != -1)
1086109998Smarkm		nextupd = X509_gmtime_adj(NULL, nmin * 60 + ndays * 3600 * 24 );
1087109998Smarkm
1088109998Smarkm	/* Examine each certificate id in the request */
1089109998Smarkm	for (i = 0; i < id_count; i++)
1090109998Smarkm		{
1091109998Smarkm		OCSP_ONEREQ *one;
1092109998Smarkm		ASN1_INTEGER *serial;
1093109998Smarkm		char **inf;
1094238405Sjkim		ASN1_OBJECT *cert_id_md_oid;
1095238405Sjkim		const EVP_MD *cert_id_md;
1096109998Smarkm		one = OCSP_request_onereq_get0(req, i);
1097109998Smarkm		cid = OCSP_onereq_get0_id(one);
1098238405Sjkim
1099238405Sjkim		OCSP_id_get0_info(NULL,&cert_id_md_oid, NULL,NULL, cid);
1100238405Sjkim
1101238405Sjkim		cert_id_md = EVP_get_digestbyobj(cert_id_md_oid);
1102238405Sjkim		if (! cert_id_md)
1103238405Sjkim			{
1104238405Sjkim			*resp = OCSP_response_create(OCSP_RESPONSE_STATUS_INTERNALERROR,
1105238405Sjkim				NULL);
1106238405Sjkim				goto end;
1107238405Sjkim			}
1108238405Sjkim		if (ca_id) OCSP_CERTID_free(ca_id);
1109238405Sjkim		ca_id = OCSP_cert_to_id(cert_id_md, NULL, ca);
1110238405Sjkim
1111109998Smarkm		/* Is this request about our CA? */
1112109998Smarkm		if (OCSP_id_issuer_cmp(ca_id, cid))
1113109998Smarkm			{
1114109998Smarkm			OCSP_basic_add1_status(bs, cid,
1115109998Smarkm						V_OCSP_CERTSTATUS_UNKNOWN,
1116109998Smarkm						0, NULL,
1117109998Smarkm						thisupd, nextupd);
1118109998Smarkm			continue;
1119109998Smarkm			}
1120109998Smarkm		OCSP_id_get0_info(NULL, NULL, NULL, &serial, cid);
1121109998Smarkm		inf = lookup_serial(db, serial);
1122109998Smarkm		if (!inf)
1123109998Smarkm			OCSP_basic_add1_status(bs, cid,
1124109998Smarkm						V_OCSP_CERTSTATUS_UNKNOWN,
1125109998Smarkm						0, NULL,
1126109998Smarkm						thisupd, nextupd);
1127109998Smarkm		else if (inf[DB_type][0] == DB_TYPE_VAL)
1128109998Smarkm			OCSP_basic_add1_status(bs, cid,
1129109998Smarkm						V_OCSP_CERTSTATUS_GOOD,
1130109998Smarkm						0, NULL,
1131109998Smarkm						thisupd, nextupd);
1132109998Smarkm		else if (inf[DB_type][0] == DB_TYPE_REV)
1133109998Smarkm			{
1134109998Smarkm			ASN1_OBJECT *inst = NULL;
1135109998Smarkm			ASN1_TIME *revtm = NULL;
1136109998Smarkm			ASN1_GENERALIZEDTIME *invtm = NULL;
1137109998Smarkm			OCSP_SINGLERESP *single;
1138109998Smarkm			int reason = -1;
1139109998Smarkm			unpack_revinfo(&revtm, &reason, &inst, &invtm, inf[DB_rev_date]);
1140109998Smarkm			single = OCSP_basic_add1_status(bs, cid,
1141109998Smarkm						V_OCSP_CERTSTATUS_REVOKED,
1142109998Smarkm						reason, revtm,
1143109998Smarkm						thisupd, nextupd);
1144109998Smarkm			if (invtm)
1145109998Smarkm				OCSP_SINGLERESP_add1_ext_i2d(single, NID_invalidity_date, invtm, 0, 0);
1146109998Smarkm			else if (inst)
1147109998Smarkm				OCSP_SINGLERESP_add1_ext_i2d(single, NID_hold_instruction_code, inst, 0, 0);
1148109998Smarkm			ASN1_OBJECT_free(inst);
1149109998Smarkm			ASN1_TIME_free(revtm);
1150109998Smarkm			ASN1_GENERALIZEDTIME_free(invtm);
1151109998Smarkm			}
1152109998Smarkm		}
1153109998Smarkm
1154109998Smarkm	OCSP_copy_nonce(bs, req);
1155238405Sjkim
1156238405Sjkim	OCSP_basic_sign(bs, rcert, rkey, NULL, rother, flags);
1157109998Smarkm
1158109998Smarkm	*resp = OCSP_response_create(OCSP_RESPONSE_STATUS_SUCCESSFUL, bs);
1159109998Smarkm
1160109998Smarkm	end:
1161109998Smarkm	ASN1_TIME_free(thisupd);
1162109998Smarkm	ASN1_TIME_free(nextupd);
1163109998Smarkm	OCSP_CERTID_free(ca_id);
1164109998Smarkm	OCSP_BASICRESP_free(bs);
1165109998Smarkm	return ret;
1166109998Smarkm
1167109998Smarkm	}
1168109998Smarkm
1169127128Snectarstatic char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser)
1170109998Smarkm	{
1171109998Smarkm	int i;
1172109998Smarkm	BIGNUM *bn = NULL;
1173109998Smarkm	char *itmp, *row[DB_NUMBER],**rrow;
1174109998Smarkm	for (i = 0; i < DB_NUMBER; i++) row[i] = NULL;
1175109998Smarkm	bn = ASN1_INTEGER_to_BN(ser,NULL);
1176194206Ssimon	OPENSSL_assert(bn); /* FIXME: should report an error at this point and abort */
1177109998Smarkm	if (BN_is_zero(bn))
1178109998Smarkm		itmp = BUF_strdup("00");
1179109998Smarkm	else
1180109998Smarkm		itmp = BN_bn2hex(bn);
1181109998Smarkm	row[DB_serial] = itmp;
1182109998Smarkm	BN_free(bn);
1183127128Snectar	rrow=TXT_DB_get_by_index(db->db,DB_serial,row);
1184109998Smarkm	OPENSSL_free(itmp);
1185109998Smarkm	return rrow;
1186109998Smarkm	}
1187109998Smarkm
1188109998Smarkm/* Quick and dirty OCSP server: read in and parse input request */
1189109998Smarkm
1190109998Smarkmstatic BIO *init_responder(char *port)
1191109998Smarkm	{
1192109998Smarkm	BIO *acbio = NULL, *bufbio = NULL;
1193109998Smarkm	bufbio = BIO_new(BIO_f_buffer());
1194109998Smarkm	if (!bufbio)
1195109998Smarkm		goto err;
1196111147Snectar#ifndef OPENSSL_NO_SOCK
1197109998Smarkm	acbio = BIO_new_accept(port);
1198111147Snectar#else
1199111147Snectar	BIO_printf(bio_err, "Error setting up accept BIO - sockets not supported.\n");
1200111147Snectar#endif
1201109998Smarkm	if (!acbio)
1202109998Smarkm		goto err;
1203109998Smarkm	BIO_set_accept_bios(acbio, bufbio);
1204109998Smarkm	bufbio = NULL;
1205109998Smarkm
1206109998Smarkm	if (BIO_do_accept(acbio) <= 0)
1207109998Smarkm		{
1208109998Smarkm			BIO_printf(bio_err, "Error setting up accept BIO\n");
1209109998Smarkm			ERR_print_errors(bio_err);
1210109998Smarkm			goto err;
1211109998Smarkm		}
1212109998Smarkm
1213109998Smarkm	return acbio;
1214109998Smarkm
1215109998Smarkm	err:
1216109998Smarkm	BIO_free_all(acbio);
1217109998Smarkm	BIO_free(bufbio);
1218109998Smarkm	return NULL;
1219109998Smarkm	}
1220109998Smarkm
1221109998Smarkmstatic int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, char *port)
1222109998Smarkm	{
1223109998Smarkm	int have_post = 0, len;
1224109998Smarkm	OCSP_REQUEST *req = NULL;
1225109998Smarkm	char inbuf[1024];
1226109998Smarkm	BIO *cbio = NULL;
1227109998Smarkm
1228109998Smarkm	if (BIO_do_accept(acbio) <= 0)
1229109998Smarkm		{
1230109998Smarkm			BIO_printf(bio_err, "Error accepting connection\n");
1231109998Smarkm			ERR_print_errors(bio_err);
1232109998Smarkm			return 0;
1233109998Smarkm		}
1234109998Smarkm
1235109998Smarkm	cbio = BIO_pop(acbio);
1236109998Smarkm	*pcbio = cbio;
1237109998Smarkm
1238109998Smarkm	for(;;)
1239109998Smarkm		{
1240109998Smarkm		len = BIO_gets(cbio, inbuf, sizeof inbuf);
1241109998Smarkm		if (len <= 0)
1242109998Smarkm			return 1;
1243109998Smarkm		/* Look for "POST" signalling start of query */
1244109998Smarkm		if (!have_post)
1245109998Smarkm			{
1246109998Smarkm			if(strncmp(inbuf, "POST", 4))
1247109998Smarkm				{
1248109998Smarkm				BIO_printf(bio_err, "Invalid request\n");
1249109998Smarkm				return 1;
1250109998Smarkm				}
1251109998Smarkm			have_post = 1;
1252109998Smarkm			}
1253109998Smarkm		/* Look for end of headers */
1254109998Smarkm		if ((inbuf[0] == '\r') || (inbuf[0] == '\n'))
1255109998Smarkm			break;
1256109998Smarkm		}
1257109998Smarkm
1258109998Smarkm	/* Try to read OCSP request */
1259109998Smarkm
1260109998Smarkm	req = d2i_OCSP_REQUEST_bio(cbio, NULL);
1261109998Smarkm
1262109998Smarkm	if (!req)
1263109998Smarkm		{
1264109998Smarkm		BIO_printf(bio_err, "Error parsing OCSP request\n");
1265109998Smarkm		ERR_print_errors(bio_err);
1266109998Smarkm		}
1267109998Smarkm
1268109998Smarkm	*preq = req;
1269109998Smarkm
1270109998Smarkm	return 1;
1271109998Smarkm
1272109998Smarkm	}
1273109998Smarkm
1274109998Smarkmstatic int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp)
1275109998Smarkm	{
1276109998Smarkm	char http_resp[] =
1277109998Smarkm		"HTTP/1.0 200 OK\r\nContent-type: application/ocsp-response\r\n"
1278109998Smarkm		"Content-Length: %d\r\n\r\n";
1279109998Smarkm	if (!cbio)
1280109998Smarkm		return 0;
1281109998Smarkm	BIO_printf(cbio, http_resp, i2d_OCSP_RESPONSE(resp, NULL));
1282109998Smarkm	i2d_OCSP_RESPONSE_bio(cbio, resp);
1283194206Ssimon	(void)BIO_flush(cbio);
1284109998Smarkm	return 1;
1285109998Smarkm	}
1286109998Smarkm
1287194206Ssimonstatic OCSP_RESPONSE *query_responder(BIO *err, BIO *cbio, char *path,
1288238405Sjkim				STACK_OF(CONF_VALUE) *headers,
1289194206Ssimon				OCSP_REQUEST *req, int req_timeout)
1290194206Ssimon	{
1291194206Ssimon	int fd;
1292194206Ssimon	int rv;
1293238405Sjkim	int i;
1294194206Ssimon	OCSP_REQ_CTX *ctx = NULL;
1295194206Ssimon	OCSP_RESPONSE *rsp = NULL;
1296194206Ssimon	fd_set confds;
1297194206Ssimon	struct timeval tv;
1298194206Ssimon
1299194206Ssimon	if (req_timeout != -1)
1300194206Ssimon		BIO_set_nbio(cbio, 1);
1301194206Ssimon
1302194206Ssimon	rv = BIO_do_connect(cbio);
1303194206Ssimon
1304194206Ssimon	if ((rv <= 0) && ((req_timeout == -1) || !BIO_should_retry(cbio)))
1305194206Ssimon		{
1306194206Ssimon		BIO_puts(err, "Error connecting BIO\n");
1307194206Ssimon		return NULL;
1308194206Ssimon		}
1309194206Ssimon
1310194206Ssimon	if (BIO_get_fd(cbio, &fd) <= 0)
1311194206Ssimon		{
1312194206Ssimon		BIO_puts(err, "Can't get connection fd\n");
1313194206Ssimon		goto err;
1314194206Ssimon		}
1315194206Ssimon
1316238405Sjkim	if (req_timeout != -1 && rv <= 0)
1317194206Ssimon		{
1318194206Ssimon		FD_ZERO(&confds);
1319194206Ssimon		openssl_fdset(fd, &confds);
1320194206Ssimon		tv.tv_usec = 0;
1321194206Ssimon		tv.tv_sec = req_timeout;
1322194206Ssimon		rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv);
1323194206Ssimon		if (rv == 0)
1324194206Ssimon			{
1325194206Ssimon			BIO_puts(err, "Timeout on connect\n");
1326194206Ssimon			return NULL;
1327194206Ssimon			}
1328194206Ssimon		}
1329194206Ssimon
1330194206Ssimon
1331238405Sjkim	ctx = OCSP_sendreq_new(cbio, path, NULL, -1);
1332194206Ssimon	if (!ctx)
1333194206Ssimon		return NULL;
1334238405Sjkim
1335238405Sjkim	for (i = 0; i < sk_CONF_VALUE_num(headers); i++)
1336238405Sjkim		{
1337238405Sjkim		CONF_VALUE *hdr = sk_CONF_VALUE_value(headers, i);
1338238405Sjkim		if (!OCSP_REQ_CTX_add1_header(ctx, hdr->name, hdr->value))
1339238405Sjkim			goto err;
1340238405Sjkim		}
1341238405Sjkim
1342238405Sjkim	if (!OCSP_REQ_CTX_set1_req(ctx, req))
1343238405Sjkim		goto err;
1344194206Ssimon
1345194206Ssimon	for (;;)
1346194206Ssimon		{
1347194206Ssimon		rv = OCSP_sendreq_nbio(&rsp, ctx);
1348194206Ssimon		if (rv != -1)
1349194206Ssimon			break;
1350238405Sjkim		if (req_timeout == -1)
1351238405Sjkim			continue;
1352194206Ssimon		FD_ZERO(&confds);
1353194206Ssimon		openssl_fdset(fd, &confds);
1354194206Ssimon		tv.tv_usec = 0;
1355194206Ssimon		tv.tv_sec = req_timeout;
1356194206Ssimon		if (BIO_should_read(cbio))
1357194206Ssimon			rv = select(fd + 1, (void *)&confds, NULL, NULL, &tv);
1358194206Ssimon		else if (BIO_should_write(cbio))
1359194206Ssimon			rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv);
1360194206Ssimon		else
1361194206Ssimon			{
1362194206Ssimon			BIO_puts(err, "Unexpected retry condition\n");
1363194206Ssimon			goto err;
1364194206Ssimon			}
1365194206Ssimon		if (rv == 0)
1366194206Ssimon			{
1367194206Ssimon			BIO_puts(err, "Timeout on request\n");
1368194206Ssimon			break;
1369194206Ssimon			}
1370194206Ssimon		if (rv == -1)
1371194206Ssimon			{
1372194206Ssimon			BIO_puts(err, "Select error\n");
1373194206Ssimon			break;
1374194206Ssimon			}
1375238405Sjkim
1376194206Ssimon		}
1377194206Ssimon	err:
1378194206Ssimon	if (ctx)
1379194206Ssimon		OCSP_REQ_CTX_free(ctx);
1380194206Ssimon
1381194206Ssimon	return rsp;
1382194206Ssimon	}
1383194206Ssimon
1384194206SsimonOCSP_RESPONSE *process_responder(BIO *err, OCSP_REQUEST *req,
1385194206Ssimon			char *host, char *path, char *port, int use_ssl,
1386238405Sjkim			STACK_OF(CONF_VALUE) *headers,
1387194206Ssimon			int req_timeout)
1388194206Ssimon	{
1389194206Ssimon	BIO *cbio = NULL;
1390194206Ssimon	SSL_CTX *ctx = NULL;
1391194206Ssimon	OCSP_RESPONSE *resp = NULL;
1392194206Ssimon	cbio = BIO_new_connect(host);
1393194206Ssimon	if (!cbio)
1394194206Ssimon		{
1395194206Ssimon		BIO_printf(err, "Error creating connect BIO\n");
1396194206Ssimon		goto end;
1397194206Ssimon		}
1398194206Ssimon	if (port) BIO_set_conn_port(cbio, port);
1399194206Ssimon	if (use_ssl == 1)
1400194206Ssimon		{
1401194206Ssimon		BIO *sbio;
1402194206Ssimon		ctx = SSL_CTX_new(SSLv23_client_method());
1403194206Ssimon		if (ctx == NULL)
1404194206Ssimon			{
1405194206Ssimon			BIO_printf(err, "Error creating SSL context.\n");
1406194206Ssimon			goto end;
1407194206Ssimon			}
1408194206Ssimon		SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
1409194206Ssimon		sbio = BIO_new_ssl(ctx, 1);
1410194206Ssimon		cbio = BIO_push(sbio, cbio);
1411194206Ssimon		}
1412238405Sjkim	resp = query_responder(err, cbio, path, headers, req, req_timeout);
1413194206Ssimon	if (!resp)
1414279264Sdelphij		BIO_printf(bio_err, "Error querying OCSP responder\n");
1415194206Ssimon	end:
1416238405Sjkim	if (cbio)
1417238405Sjkim		BIO_free_all(cbio);
1418194206Ssimon	if (ctx)
1419194206Ssimon		SSL_CTX_free(ctx);
1420194206Ssimon	return resp;
1421194206Ssimon	}
1422194206Ssimon
1423194206Ssimon#endif
1424