1109998Smarkm/* ocsp.c */
2280304Sjkim/*
3280304Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
4280304Sjkim * 2000.
5109998Smarkm */
6109998Smarkm/* ====================================================================
7109998Smarkm * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
8109998Smarkm *
9109998Smarkm * Redistribution and use in source and binary forms, with or without
10109998Smarkm * modification, are permitted provided that the following conditions
11109998Smarkm * are met:
12109998Smarkm *
13109998Smarkm * 1. Redistributions of source code must retain the above copyright
14280304Sjkim *    notice, this list of conditions and the following disclaimer.
15109998Smarkm *
16109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright
17109998Smarkm *    notice, this list of conditions and the following disclaimer in
18109998Smarkm *    the documentation and/or other materials provided with the
19109998Smarkm *    distribution.
20109998Smarkm *
21109998Smarkm * 3. All advertising materials mentioning features or use of this
22109998Smarkm *    software must display the following acknowledgment:
23109998Smarkm *    "This product includes software developed by the OpenSSL Project
24109998Smarkm *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25109998Smarkm *
26109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27109998Smarkm *    endorse or promote products derived from this software without
28109998Smarkm *    prior written permission. For written permission, please contact
29109998Smarkm *    licensing@OpenSSL.org.
30109998Smarkm *
31109998Smarkm * 5. Products derived from this software may not be called "OpenSSL"
32109998Smarkm *    nor may "OpenSSL" appear in their names without prior written
33109998Smarkm *    permission of the OpenSSL Project.
34109998Smarkm *
35109998Smarkm * 6. Redistributions of any form whatsoever must retain the following
36109998Smarkm *    acknowledgment:
37109998Smarkm *    "This product includes software developed by the OpenSSL Project
38109998Smarkm *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39109998Smarkm *
40109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43109998Smarkm * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE.
52109998Smarkm * ====================================================================
53109998Smarkm *
54109998Smarkm * This product includes cryptographic software written by Eric Young
55109998Smarkm * (eay@cryptsoft.com).  This product includes software written by Tim
56109998Smarkm * Hudson (tjh@cryptsoft.com).
57109998Smarkm *
58109998Smarkm */
59111147Snectar#ifndef OPENSSL_NO_OCSP
60238405Sjkim
61280304Sjkim# ifdef OPENSSL_SYS_VMS
62280304Sjkim#  define _XOPEN_SOURCE_EXTENDED/* So fd_set and friends get properly defined
63280304Sjkim                                 * on OpenVMS */
64280304Sjkim# endif
65238405Sjkim
66280304Sjkim# define USE_SOCKETS
67238405Sjkim
68280304Sjkim# include <stdio.h>
69280304Sjkim# include <stdlib.h>
70280304Sjkim# include <string.h>
71280304Sjkim# include <time.h>
72280304Sjkim# include "apps.h"              /* needs to be included before the openssl
73280304Sjkim                                 * headers! */
74280304Sjkim# include <openssl/e_os2.h>
75280304Sjkim# include <openssl/crypto.h>
76280304Sjkim# include <openssl/err.h>
77280304Sjkim# include <openssl/ssl.h>
78280304Sjkim# include <openssl/evp.h>
79280304Sjkim# include <openssl/bn.h>
80280304Sjkim# include <openssl/x509v3.h>
81109998Smarkm
82280304Sjkim# if defined(NETWARE_CLIB)
83238405Sjkim#  ifdef NETWARE_BSDSOCK
84280304Sjkim#   include <sys/socket.h>
85280304Sjkim#   include <sys/bsdskt.h>
86238405Sjkim#  else
87280304Sjkim#   include <novsock2.h>
88238405Sjkim#  endif
89280304Sjkim# elif defined(NETWARE_LIBC)
90238405Sjkim#  ifdef NETWARE_BSDSOCK
91280304Sjkim#   include <sys/select.h>
92238405Sjkim#  else
93280304Sjkim#   include <novsock2.h>
94238405Sjkim#  endif
95280304Sjkim# endif
96280304Sjkim
97109998Smarkm/* Maximum leeway in validity period: default 5 minutes */
98280304Sjkim# define MAX_VALIDITY_PERIOD     (5 * 60)
99109998Smarkm
100280304Sjkimstatic int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert,
101280304Sjkim                         const EVP_MD *cert_id_md, X509 *issuer,
102280304Sjkim                         STACK_OF(OCSP_CERTID) *ids);
103280304Sjkimstatic int add_ocsp_serial(OCSP_REQUEST **req, char *serial,
104280304Sjkim                           const EVP_MD *cert_id_md, X509 *issuer,
105280304Sjkim                           STACK_OF(OCSP_CERTID) *ids);
106109998Smarkmstatic int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req,
107280304Sjkim                              STACK_OF(OPENSSL_STRING) *names,
108280304Sjkim                              STACK_OF(OCSP_CERTID) *ids, long nsec,
109280304Sjkim                              long maxage);
110109998Smarkm
111280304Sjkimstatic int make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req,
112280304Sjkim                              CA_DB *db, X509 *ca, X509 *rcert,
113280304Sjkim                              EVP_PKEY *rkey, STACK_OF(X509) *rother,
114280304Sjkim                              unsigned long flags, int nmin, int ndays);
115109998Smarkm
116127128Snectarstatic char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser);
117109998Smarkmstatic BIO *init_responder(char *port);
118280304Sjkimstatic int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio,
119280304Sjkim                        char *port);
120109998Smarkmstatic int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp);
121194206Ssimonstatic OCSP_RESPONSE *query_responder(BIO *err, BIO *cbio, char *path,
122280304Sjkim                                      STACK_OF(CONF_VALUE) *headers,
123280304Sjkim                                      OCSP_REQUEST *req, int req_timeout);
124109998Smarkm
125280304Sjkim# undef PROG
126280304Sjkim# define PROG ocsp_main
127109998Smarkm
128109998Smarkmint MAIN(int, char **);
129109998Smarkm
130109998Smarkmint MAIN(int argc, char **argv)
131280304Sjkim{
132280304Sjkim    ENGINE *e = NULL;
133280304Sjkim    char **args;
134280304Sjkim    char *host = NULL, *port = NULL, *path = "/";
135280304Sjkim    char *thost = NULL, *tport = NULL, *tpath = NULL;
136280304Sjkim    char *reqin = NULL, *respin = NULL;
137280304Sjkim    char *reqout = NULL, *respout = NULL;
138280304Sjkim    char *signfile = NULL, *keyfile = NULL;
139280304Sjkim    char *rsignfile = NULL, *rkeyfile = NULL;
140280304Sjkim    char *outfile = NULL;
141280304Sjkim    int add_nonce = 1, noverify = 0, use_ssl = -1;
142280304Sjkim    STACK_OF(CONF_VALUE) *headers = NULL;
143280304Sjkim    OCSP_REQUEST *req = NULL;
144280304Sjkim    OCSP_RESPONSE *resp = NULL;
145280304Sjkim    OCSP_BASICRESP *bs = NULL;
146280304Sjkim    X509 *issuer = NULL, *cert = NULL;
147280304Sjkim    X509 *signer = NULL, *rsigner = NULL;
148280304Sjkim    EVP_PKEY *key = NULL, *rkey = NULL;
149280304Sjkim    BIO *acbio = NULL, *cbio = NULL;
150280304Sjkim    BIO *derbio = NULL;
151280304Sjkim    BIO *out = NULL;
152280304Sjkim    int req_timeout = -1;
153280304Sjkim    int req_text = 0, resp_text = 0;
154280304Sjkim    long nsec = MAX_VALIDITY_PERIOD, maxage = -1;
155280304Sjkim    char *CAfile = NULL, *CApath = NULL;
156280304Sjkim    X509_STORE *store = NULL;
157280304Sjkim    STACK_OF(X509) *sign_other = NULL, *verify_other = NULL, *rother = NULL;
158280304Sjkim    char *sign_certfile = NULL, *verify_certfile = NULL, *rcertfile = NULL;
159280304Sjkim    unsigned long sign_flags = 0, verify_flags = 0, rflags = 0;
160280304Sjkim    int ret = 1;
161280304Sjkim    int accept_count = -1;
162280304Sjkim    int badarg = 0;
163280304Sjkim    int i;
164280304Sjkim    int ignore_err = 0;
165280304Sjkim    STACK_OF(OPENSSL_STRING) *reqnames = NULL;
166280304Sjkim    STACK_OF(OCSP_CERTID) *ids = NULL;
167109998Smarkm
168280304Sjkim    X509 *rca_cert = NULL;
169280304Sjkim    char *ridx_filename = NULL;
170280304Sjkim    char *rca_filename = NULL;
171280304Sjkim    CA_DB *rdb = NULL;
172280304Sjkim    int nmin = 0, ndays = -1;
173280304Sjkim    const EVP_MD *cert_id_md = NULL;
174109998Smarkm
175280304Sjkim    if (bio_err == NULL)
176280304Sjkim        bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
177109998Smarkm
178280304Sjkim    if (!load_config(bio_err, NULL))
179280304Sjkim        goto end;
180280304Sjkim    SSL_load_error_strings();
181280304Sjkim    OpenSSL_add_ssl_algorithms();
182280304Sjkim    args = argv + 1;
183280304Sjkim    reqnames = sk_OPENSSL_STRING_new_null();
184280304Sjkim    ids = sk_OCSP_CERTID_new_null();
185280304Sjkim    while (!badarg && *args && *args[0] == '-') {
186280304Sjkim        if (!strcmp(*args, "-out")) {
187280304Sjkim            if (args[1]) {
188280304Sjkim                args++;
189280304Sjkim                outfile = *args;
190280304Sjkim            } else
191280304Sjkim                badarg = 1;
192280304Sjkim        } else if (!strcmp(*args, "-timeout")) {
193280304Sjkim            if (args[1]) {
194280304Sjkim                args++;
195280304Sjkim                req_timeout = atol(*args);
196280304Sjkim                if (req_timeout < 0) {
197280304Sjkim                    BIO_printf(bio_err, "Illegal timeout value %s\n", *args);
198280304Sjkim                    badarg = 1;
199280304Sjkim                }
200280304Sjkim            } else
201280304Sjkim                badarg = 1;
202280304Sjkim        } else if (!strcmp(*args, "-url")) {
203280304Sjkim            if (thost)
204280304Sjkim                OPENSSL_free(thost);
205280304Sjkim            if (tport)
206280304Sjkim                OPENSSL_free(tport);
207280304Sjkim            if (tpath)
208280304Sjkim                OPENSSL_free(tpath);
209280304Sjkim            if (args[1]) {
210280304Sjkim                args++;
211280304Sjkim                if (!OCSP_parse_url(*args, &host, &port, &path, &use_ssl)) {
212280304Sjkim                    BIO_printf(bio_err, "Error parsing URL\n");
213280304Sjkim                    badarg = 1;
214280304Sjkim                }
215280304Sjkim                thost = host;
216280304Sjkim                tport = port;
217280304Sjkim                tpath = path;
218280304Sjkim            } else
219280304Sjkim                badarg = 1;
220280304Sjkim        } else if (!strcmp(*args, "-host")) {
221280304Sjkim            if (args[1]) {
222280304Sjkim                args++;
223280304Sjkim                host = *args;
224280304Sjkim            } else
225280304Sjkim                badarg = 1;
226280304Sjkim        } else if (!strcmp(*args, "-port")) {
227280304Sjkim            if (args[1]) {
228280304Sjkim                args++;
229280304Sjkim                port = *args;
230280304Sjkim            } else
231280304Sjkim                badarg = 1;
232280304Sjkim        } else if (!strcmp(*args, "-header")) {
233280304Sjkim            if (args[1] && args[2]) {
234280304Sjkim                if (!X509V3_add_value(args[1], args[2], &headers))
235280304Sjkim                    goto end;
236280304Sjkim                args += 2;
237280304Sjkim            } else
238280304Sjkim                badarg = 1;
239280304Sjkim        } else if (!strcmp(*args, "-ignore_err"))
240280304Sjkim            ignore_err = 1;
241280304Sjkim        else if (!strcmp(*args, "-noverify"))
242280304Sjkim            noverify = 1;
243280304Sjkim        else if (!strcmp(*args, "-nonce"))
244280304Sjkim            add_nonce = 2;
245280304Sjkim        else if (!strcmp(*args, "-no_nonce"))
246280304Sjkim            add_nonce = 0;
247280304Sjkim        else if (!strcmp(*args, "-resp_no_certs"))
248280304Sjkim            rflags |= OCSP_NOCERTS;
249280304Sjkim        else if (!strcmp(*args, "-resp_key_id"))
250280304Sjkim            rflags |= OCSP_RESPID_KEY;
251280304Sjkim        else if (!strcmp(*args, "-no_certs"))
252280304Sjkim            sign_flags |= OCSP_NOCERTS;
253280304Sjkim        else if (!strcmp(*args, "-no_signature_verify"))
254280304Sjkim            verify_flags |= OCSP_NOSIGS;
255280304Sjkim        else if (!strcmp(*args, "-no_cert_verify"))
256280304Sjkim            verify_flags |= OCSP_NOVERIFY;
257280304Sjkim        else if (!strcmp(*args, "-no_chain"))
258280304Sjkim            verify_flags |= OCSP_NOCHAIN;
259280304Sjkim        else if (!strcmp(*args, "-no_cert_checks"))
260280304Sjkim            verify_flags |= OCSP_NOCHECKS;
261280304Sjkim        else if (!strcmp(*args, "-no_explicit"))
262280304Sjkim            verify_flags |= OCSP_NOEXPLICIT;
263280304Sjkim        else if (!strcmp(*args, "-trust_other"))
264280304Sjkim            verify_flags |= OCSP_TRUSTOTHER;
265280304Sjkim        else if (!strcmp(*args, "-no_intern"))
266280304Sjkim            verify_flags |= OCSP_NOINTERN;
267280304Sjkim        else if (!strcmp(*args, "-text")) {
268280304Sjkim            req_text = 1;
269280304Sjkim            resp_text = 1;
270280304Sjkim        } else if (!strcmp(*args, "-req_text"))
271280304Sjkim            req_text = 1;
272280304Sjkim        else if (!strcmp(*args, "-resp_text"))
273280304Sjkim            resp_text = 1;
274280304Sjkim        else if (!strcmp(*args, "-reqin")) {
275280304Sjkim            if (args[1]) {
276280304Sjkim                args++;
277280304Sjkim                reqin = *args;
278280304Sjkim            } else
279280304Sjkim                badarg = 1;
280280304Sjkim        } else if (!strcmp(*args, "-respin")) {
281280304Sjkim            if (args[1]) {
282280304Sjkim                args++;
283280304Sjkim                respin = *args;
284280304Sjkim            } else
285280304Sjkim                badarg = 1;
286280304Sjkim        } else if (!strcmp(*args, "-signer")) {
287280304Sjkim            if (args[1]) {
288280304Sjkim                args++;
289280304Sjkim                signfile = *args;
290280304Sjkim            } else
291280304Sjkim                badarg = 1;
292280304Sjkim        } else if (!strcmp(*args, "-VAfile")) {
293280304Sjkim            if (args[1]) {
294280304Sjkim                args++;
295280304Sjkim                verify_certfile = *args;
296280304Sjkim                verify_flags |= OCSP_TRUSTOTHER;
297280304Sjkim            } else
298280304Sjkim                badarg = 1;
299280304Sjkim        } else if (!strcmp(*args, "-sign_other")) {
300280304Sjkim            if (args[1]) {
301280304Sjkim                args++;
302280304Sjkim                sign_certfile = *args;
303280304Sjkim            } else
304280304Sjkim                badarg = 1;
305280304Sjkim        } else if (!strcmp(*args, "-verify_other")) {
306280304Sjkim            if (args[1]) {
307280304Sjkim                args++;
308280304Sjkim                verify_certfile = *args;
309280304Sjkim            } else
310280304Sjkim                badarg = 1;
311280304Sjkim        } else if (!strcmp(*args, "-CAfile")) {
312280304Sjkim            if (args[1]) {
313280304Sjkim                args++;
314280304Sjkim                CAfile = *args;
315280304Sjkim            } else
316280304Sjkim                badarg = 1;
317280304Sjkim        } else if (!strcmp(*args, "-CApath")) {
318280304Sjkim            if (args[1]) {
319280304Sjkim                args++;
320280304Sjkim                CApath = *args;
321280304Sjkim            } else
322280304Sjkim                badarg = 1;
323280304Sjkim        } else if (!strcmp(*args, "-validity_period")) {
324280304Sjkim            if (args[1]) {
325280304Sjkim                args++;
326280304Sjkim                nsec = atol(*args);
327280304Sjkim                if (nsec < 0) {
328280304Sjkim                    BIO_printf(bio_err,
329280304Sjkim                               "Illegal validity period %s\n", *args);
330280304Sjkim                    badarg = 1;
331280304Sjkim                }
332280304Sjkim            } else
333280304Sjkim                badarg = 1;
334280304Sjkim        } else if (!strcmp(*args, "-status_age")) {
335280304Sjkim            if (args[1]) {
336280304Sjkim                args++;
337280304Sjkim                maxage = atol(*args);
338280304Sjkim                if (maxage < 0) {
339280304Sjkim                    BIO_printf(bio_err, "Illegal validity age %s\n", *args);
340280304Sjkim                    badarg = 1;
341280304Sjkim                }
342280304Sjkim            } else
343280304Sjkim                badarg = 1;
344280304Sjkim        } else if (!strcmp(*args, "-signkey")) {
345280304Sjkim            if (args[1]) {
346280304Sjkim                args++;
347280304Sjkim                keyfile = *args;
348280304Sjkim            } else
349280304Sjkim                badarg = 1;
350280304Sjkim        } else if (!strcmp(*args, "-reqout")) {
351280304Sjkim            if (args[1]) {
352280304Sjkim                args++;
353280304Sjkim                reqout = *args;
354280304Sjkim            } else
355280304Sjkim                badarg = 1;
356280304Sjkim        } else if (!strcmp(*args, "-respout")) {
357280304Sjkim            if (args[1]) {
358280304Sjkim                args++;
359280304Sjkim                respout = *args;
360280304Sjkim            } else
361280304Sjkim                badarg = 1;
362280304Sjkim        } else if (!strcmp(*args, "-path")) {
363280304Sjkim            if (args[1]) {
364280304Sjkim                args++;
365280304Sjkim                path = *args;
366280304Sjkim            } else
367280304Sjkim                badarg = 1;
368280304Sjkim        } else if (!strcmp(*args, "-issuer")) {
369280304Sjkim            if (args[1]) {
370280304Sjkim                args++;
371280304Sjkim                X509_free(issuer);
372280304Sjkim                issuer = load_cert(bio_err, *args, FORMAT_PEM,
373280304Sjkim                                   NULL, e, "issuer certificate");
374280304Sjkim                if (!issuer)
375280304Sjkim                    goto end;
376280304Sjkim            } else
377280304Sjkim                badarg = 1;
378280304Sjkim        } else if (!strcmp(*args, "-cert")) {
379280304Sjkim            if (args[1]) {
380280304Sjkim                args++;
381280304Sjkim                X509_free(cert);
382280304Sjkim                cert = load_cert(bio_err, *args, FORMAT_PEM,
383280304Sjkim                                 NULL, e, "certificate");
384280304Sjkim                if (!cert)
385280304Sjkim                    goto end;
386280304Sjkim                if (!cert_id_md)
387280304Sjkim                    cert_id_md = EVP_sha1();
388280304Sjkim                if (!add_ocsp_cert(&req, cert, cert_id_md, issuer, ids))
389280304Sjkim                    goto end;
390280304Sjkim                if (!sk_OPENSSL_STRING_push(reqnames, *args))
391280304Sjkim                    goto end;
392280304Sjkim            } else
393280304Sjkim                badarg = 1;
394280304Sjkim        } else if (!strcmp(*args, "-serial")) {
395280304Sjkim            if (args[1]) {
396280304Sjkim                args++;
397280304Sjkim                if (!cert_id_md)
398280304Sjkim                    cert_id_md = EVP_sha1();
399280304Sjkim                if (!add_ocsp_serial(&req, *args, cert_id_md, issuer, ids))
400280304Sjkim                    goto end;
401280304Sjkim                if (!sk_OPENSSL_STRING_push(reqnames, *args))
402280304Sjkim                    goto end;
403280304Sjkim            } else
404280304Sjkim                badarg = 1;
405280304Sjkim        } else if (!strcmp(*args, "-index")) {
406280304Sjkim            if (args[1]) {
407280304Sjkim                args++;
408280304Sjkim                ridx_filename = *args;
409280304Sjkim            } else
410280304Sjkim                badarg = 1;
411280304Sjkim        } else if (!strcmp(*args, "-CA")) {
412280304Sjkim            if (args[1]) {
413280304Sjkim                args++;
414280304Sjkim                rca_filename = *args;
415280304Sjkim            } else
416280304Sjkim                badarg = 1;
417280304Sjkim        } else if (!strcmp(*args, "-nmin")) {
418280304Sjkim            if (args[1]) {
419280304Sjkim                args++;
420280304Sjkim                nmin = atol(*args);
421280304Sjkim                if (nmin < 0) {
422280304Sjkim                    BIO_printf(bio_err, "Illegal update period %s\n", *args);
423280304Sjkim                    badarg = 1;
424280304Sjkim                }
425280304Sjkim            }
426280304Sjkim            if (ndays == -1)
427280304Sjkim                ndays = 0;
428280304Sjkim            else
429280304Sjkim                badarg = 1;
430280304Sjkim        } else if (!strcmp(*args, "-nrequest")) {
431280304Sjkim            if (args[1]) {
432280304Sjkim                args++;
433280304Sjkim                accept_count = atol(*args);
434280304Sjkim                if (accept_count < 0) {
435280304Sjkim                    BIO_printf(bio_err, "Illegal accept count %s\n", *args);
436280304Sjkim                    badarg = 1;
437280304Sjkim                }
438280304Sjkim            } else
439280304Sjkim                badarg = 1;
440280304Sjkim        } else if (!strcmp(*args, "-ndays")) {
441280304Sjkim            if (args[1]) {
442280304Sjkim                args++;
443280304Sjkim                ndays = atol(*args);
444280304Sjkim                if (ndays < 0) {
445280304Sjkim                    BIO_printf(bio_err, "Illegal update period %s\n", *args);
446280304Sjkim                    badarg = 1;
447280304Sjkim                }
448280304Sjkim            } else
449280304Sjkim                badarg = 1;
450280304Sjkim        } else if (!strcmp(*args, "-rsigner")) {
451280304Sjkim            if (args[1]) {
452280304Sjkim                args++;
453280304Sjkim                rsignfile = *args;
454280304Sjkim            } else
455280304Sjkim                badarg = 1;
456280304Sjkim        } else if (!strcmp(*args, "-rkey")) {
457280304Sjkim            if (args[1]) {
458280304Sjkim                args++;
459280304Sjkim                rkeyfile = *args;
460280304Sjkim            } else
461280304Sjkim                badarg = 1;
462280304Sjkim        } else if (!strcmp(*args, "-rother")) {
463280304Sjkim            if (args[1]) {
464280304Sjkim                args++;
465280304Sjkim                rcertfile = *args;
466280304Sjkim            } else
467280304Sjkim                badarg = 1;
468280304Sjkim        } else if ((cert_id_md = EVP_get_digestbyname((*args) + 1)) == NULL) {
469280304Sjkim            badarg = 1;
470280304Sjkim        }
471280304Sjkim        args++;
472280304Sjkim    }
473109998Smarkm
474280304Sjkim    /* Have we anything to do? */
475280304Sjkim    if (!req && !reqin && !respin && !(port && ridx_filename))
476280304Sjkim        badarg = 1;
477109998Smarkm
478280304Sjkim    if (badarg) {
479280304Sjkim        BIO_printf(bio_err, "OCSP utility\n");
480280304Sjkim        BIO_printf(bio_err, "Usage ocsp [options]\n");
481280304Sjkim        BIO_printf(bio_err, "where options are\n");
482280304Sjkim        BIO_printf(bio_err, "-out file            output filename\n");
483280304Sjkim        BIO_printf(bio_err, "-issuer file         issuer certificate\n");
484280304Sjkim        BIO_printf(bio_err, "-cert file           certificate to check\n");
485280304Sjkim        BIO_printf(bio_err, "-serial n            serial number to check\n");
486280304Sjkim        BIO_printf(bio_err,
487280304Sjkim                   "-signer file         certificate to sign OCSP request with\n");
488280304Sjkim        BIO_printf(bio_err,
489280304Sjkim                   "-signkey file        private key to sign OCSP request with\n");
490280304Sjkim        BIO_printf(bio_err,
491280304Sjkim                   "-sign_other file     additional certificates to include in signed request\n");
492280304Sjkim        BIO_printf(bio_err,
493280304Sjkim                   "-no_certs            don't include any certificates in signed request\n");
494280304Sjkim        BIO_printf(bio_err,
495280304Sjkim                   "-req_text            print text form of request\n");
496280304Sjkim        BIO_printf(bio_err,
497280304Sjkim                   "-resp_text           print text form of response\n");
498280304Sjkim        BIO_printf(bio_err,
499280304Sjkim                   "-text                print text form of request and response\n");
500280304Sjkim        BIO_printf(bio_err,
501280304Sjkim                   "-reqout file         write DER encoded OCSP request to \"file\"\n");
502280304Sjkim        BIO_printf(bio_err,
503280304Sjkim                   "-respout file        write DER encoded OCSP reponse to \"file\"\n");
504280304Sjkim        BIO_printf(bio_err,
505280304Sjkim                   "-reqin file          read DER encoded OCSP request from \"file\"\n");
506280304Sjkim        BIO_printf(bio_err,
507280304Sjkim                   "-respin file         read DER encoded OCSP reponse from \"file\"\n");
508280304Sjkim        BIO_printf(bio_err,
509280304Sjkim                   "-nonce               add OCSP nonce to request\n");
510280304Sjkim        BIO_printf(bio_err,
511280304Sjkim                   "-no_nonce            don't add OCSP nonce to request\n");
512280304Sjkim        BIO_printf(bio_err, "-url URL             OCSP responder URL\n");
513280304Sjkim        BIO_printf(bio_err,
514280304Sjkim                   "-host host:n         send OCSP request to host on port n\n");
515280304Sjkim        BIO_printf(bio_err,
516280304Sjkim                   "-path                path to use in OCSP request\n");
517280304Sjkim        BIO_printf(bio_err,
518280304Sjkim                   "-CApath dir          trusted certificates directory\n");
519280304Sjkim        BIO_printf(bio_err,
520280304Sjkim                   "-CAfile file         trusted certificates file\n");
521280304Sjkim        BIO_printf(bio_err,
522284285Sjkim                   "-no_alt_chains       only ever use the first certificate chain found\n");
523284285Sjkim        BIO_printf(bio_err,
524280304Sjkim                   "-VAfile file         validator certificates file\n");
525280304Sjkim        BIO_printf(bio_err,
526280304Sjkim                   "-validity_period n   maximum validity discrepancy in seconds\n");
527280304Sjkim        BIO_printf(bio_err,
528280304Sjkim                   "-status_age n        maximum status age in seconds\n");
529280304Sjkim        BIO_printf(bio_err,
530280304Sjkim                   "-noverify            don't verify response at all\n");
531280304Sjkim        BIO_printf(bio_err,
532280304Sjkim                   "-verify_other file   additional certificates to search for signer\n");
533280304Sjkim        BIO_printf(bio_err,
534280304Sjkim                   "-trust_other         don't verify additional certificates\n");
535280304Sjkim        BIO_printf(bio_err,
536280304Sjkim                   "-no_intern           don't search certificates contained in response for signer\n");
537280304Sjkim        BIO_printf(bio_err,
538280304Sjkim                   "-no_signature_verify don't check signature on response\n");
539280304Sjkim        BIO_printf(bio_err,
540280304Sjkim                   "-no_cert_verify      don't check signing certificate\n");
541280304Sjkim        BIO_printf(bio_err,
542280304Sjkim                   "-no_chain            don't chain verify response\n");
543280304Sjkim        BIO_printf(bio_err,
544280304Sjkim                   "-no_cert_checks      don't do additional checks on signing certificate\n");
545280304Sjkim        BIO_printf(bio_err,
546280304Sjkim                   "-port num            port to run responder on\n");
547280304Sjkim        BIO_printf(bio_err,
548280304Sjkim                   "-index file          certificate status index file\n");
549280304Sjkim        BIO_printf(bio_err, "-CA file             CA certificate\n");
550280304Sjkim        BIO_printf(bio_err,
551280304Sjkim                   "-rsigner file        responder certificate to sign responses with\n");
552280304Sjkim        BIO_printf(bio_err,
553280304Sjkim                   "-rkey file           responder key to sign responses with\n");
554280304Sjkim        BIO_printf(bio_err,
555280304Sjkim                   "-rother file         other certificates to include in response\n");
556280304Sjkim        BIO_printf(bio_err,
557280304Sjkim                   "-resp_no_certs       don't include any certificates in response\n");
558280304Sjkim        BIO_printf(bio_err,
559280304Sjkim                   "-nmin n              number of minutes before next update\n");
560280304Sjkim        BIO_printf(bio_err,
561280304Sjkim                   "-ndays n             number of days before next update\n");
562280304Sjkim        BIO_printf(bio_err,
563280304Sjkim                   "-resp_key_id         identify reponse by signing certificate key ID\n");
564280304Sjkim        BIO_printf(bio_err,
565280304Sjkim                   "-nrequest n          number of requests to accept (default unlimited)\n");
566280304Sjkim        BIO_printf(bio_err,
567280304Sjkim                   "-<dgst alg>          use specified digest in the request\n");
568280304Sjkim        BIO_printf(bio_err,
569280304Sjkim                   "-timeout n           timeout connection to OCSP responder after n seconds\n");
570280304Sjkim        goto end;
571280304Sjkim    }
572109998Smarkm
573280304Sjkim    if (outfile)
574280304Sjkim        out = BIO_new_file(outfile, "w");
575280304Sjkim    else
576280304Sjkim        out = BIO_new_fp(stdout, BIO_NOCLOSE);
577109998Smarkm
578280304Sjkim    if (!out) {
579280304Sjkim        BIO_printf(bio_err, "Error opening output file\n");
580280304Sjkim        goto end;
581280304Sjkim    }
582109998Smarkm
583280304Sjkim    if (!req && (add_nonce != 2))
584280304Sjkim        add_nonce = 0;
585109998Smarkm
586280304Sjkim    if (!req && reqin) {
587280304Sjkim        derbio = BIO_new_file(reqin, "rb");
588280304Sjkim        if (!derbio) {
589280304Sjkim            BIO_printf(bio_err, "Error Opening OCSP request file\n");
590280304Sjkim            goto end;
591280304Sjkim        }
592280304Sjkim        req = d2i_OCSP_REQUEST_bio(derbio, NULL);
593280304Sjkim        BIO_free(derbio);
594280304Sjkim        if (!req) {
595280304Sjkim            BIO_printf(bio_err, "Error reading OCSP request\n");
596280304Sjkim            goto end;
597280304Sjkim        }
598280304Sjkim    }
599109998Smarkm
600280304Sjkim    if (!req && port) {
601280304Sjkim        acbio = init_responder(port);
602280304Sjkim        if (!acbio)
603280304Sjkim            goto end;
604280304Sjkim    }
605109998Smarkm
606280304Sjkim    if (rsignfile && !rdb) {
607280304Sjkim        if (!rkeyfile)
608280304Sjkim            rkeyfile = rsignfile;
609280304Sjkim        rsigner = load_cert(bio_err, rsignfile, FORMAT_PEM,
610280304Sjkim                            NULL, e, "responder certificate");
611280304Sjkim        if (!rsigner) {
612280304Sjkim            BIO_printf(bio_err, "Error loading responder certificate\n");
613280304Sjkim            goto end;
614280304Sjkim        }
615280304Sjkim        rca_cert = load_cert(bio_err, rca_filename, FORMAT_PEM,
616280304Sjkim                             NULL, e, "CA certificate");
617280304Sjkim        if (rcertfile) {
618280304Sjkim            rother = load_certs(bio_err, rcertfile, FORMAT_PEM,
619280304Sjkim                                NULL, e, "responder other certificates");
620280304Sjkim            if (!rother)
621280304Sjkim                goto end;
622280304Sjkim        }
623280304Sjkim        rkey = load_key(bio_err, rkeyfile, FORMAT_PEM, 0, NULL, NULL,
624280304Sjkim                        "responder private key");
625280304Sjkim        if (!rkey)
626280304Sjkim            goto end;
627280304Sjkim    }
628280304Sjkim    if (acbio)
629280304Sjkim        BIO_printf(bio_err, "Waiting for OCSP client connections...\n");
630109998Smarkm
631280304Sjkim redo_accept:
632109998Smarkm
633280304Sjkim    if (acbio) {
634280304Sjkim        if (!do_responder(&req, &cbio, acbio, port))
635280304Sjkim            goto end;
636280304Sjkim        if (!req) {
637280304Sjkim            resp =
638280304Sjkim                OCSP_response_create(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST,
639280304Sjkim                                     NULL);
640280304Sjkim            send_ocsp_response(cbio, resp);
641280304Sjkim            goto done_resp;
642280304Sjkim        }
643280304Sjkim    }
644109998Smarkm
645280304Sjkim    if (!req && (signfile || reqout || host || add_nonce || ridx_filename)) {
646280304Sjkim        BIO_printf(bio_err, "Need an OCSP request for this operation!\n");
647280304Sjkim        goto end;
648280304Sjkim    }
649109998Smarkm
650280304Sjkim    if (req && add_nonce)
651280304Sjkim        OCSP_request_add1_nonce(req, NULL, -1);
652109998Smarkm
653280304Sjkim    if (signfile) {
654280304Sjkim        if (!keyfile)
655280304Sjkim            keyfile = signfile;
656280304Sjkim        signer = load_cert(bio_err, signfile, FORMAT_PEM,
657280304Sjkim                           NULL, e, "signer certificate");
658280304Sjkim        if (!signer) {
659280304Sjkim            BIO_printf(bio_err, "Error loading signer certificate\n");
660280304Sjkim            goto end;
661280304Sjkim        }
662280304Sjkim        if (sign_certfile) {
663280304Sjkim            sign_other = load_certs(bio_err, sign_certfile, FORMAT_PEM,
664280304Sjkim                                    NULL, e, "signer certificates");
665280304Sjkim            if (!sign_other)
666280304Sjkim                goto end;
667280304Sjkim        }
668280304Sjkim        key = load_key(bio_err, keyfile, FORMAT_PEM, 0, NULL, NULL,
669280304Sjkim                       "signer private key");
670280304Sjkim        if (!key)
671280304Sjkim            goto end;
672238405Sjkim
673280304Sjkim        if (!OCSP_request_sign
674280304Sjkim            (req, signer, key, NULL, sign_other, sign_flags)) {
675280304Sjkim            BIO_printf(bio_err, "Error signing OCSP request\n");
676280304Sjkim            goto end;
677280304Sjkim        }
678280304Sjkim    }
679109998Smarkm
680280304Sjkim    if (req_text && req)
681280304Sjkim        OCSP_REQUEST_print(out, req, 0);
682109998Smarkm
683280304Sjkim    if (reqout) {
684280304Sjkim        derbio = BIO_new_file(reqout, "wb");
685280304Sjkim        if (!derbio) {
686280304Sjkim            BIO_printf(bio_err, "Error opening file %s\n", reqout);
687280304Sjkim            goto end;
688280304Sjkim        }
689280304Sjkim        i2d_OCSP_REQUEST_bio(derbio, req);
690280304Sjkim        BIO_free(derbio);
691280304Sjkim    }
692109998Smarkm
693280304Sjkim    if (ridx_filename && (!rkey || !rsigner || !rca_cert)) {
694280304Sjkim        BIO_printf(bio_err,
695280304Sjkim                   "Need a responder certificate, key and CA for this operation!\n");
696280304Sjkim        goto end;
697280304Sjkim    }
698109998Smarkm
699280304Sjkim    if (ridx_filename && !rdb) {
700280304Sjkim        rdb = load_index(ridx_filename, NULL);
701280304Sjkim        if (!rdb)
702280304Sjkim            goto end;
703280304Sjkim        if (!index_index(rdb))
704280304Sjkim            goto end;
705280304Sjkim    }
706109998Smarkm
707280304Sjkim    if (rdb) {
708280304Sjkim        i = make_ocsp_response(&resp, req, rdb, rca_cert, rsigner, rkey,
709280304Sjkim                               rother, rflags, nmin, ndays);
710280304Sjkim        if (cbio)
711280304Sjkim            send_ocsp_response(cbio, resp);
712280304Sjkim    } else if (host) {
713280304Sjkim# ifndef OPENSSL_NO_SOCK
714280304Sjkim        resp = process_responder(bio_err, req, host, path,
715280304Sjkim                                 port, use_ssl, headers, req_timeout);
716280304Sjkim        if (!resp)
717280304Sjkim            goto end;
718280304Sjkim# else
719280304Sjkim        BIO_printf(bio_err,
720280304Sjkim                   "Error creating connect BIO - sockets not supported.\n");
721280304Sjkim        goto end;
722280304Sjkim# endif
723280304Sjkim    } else if (respin) {
724280304Sjkim        derbio = BIO_new_file(respin, "rb");
725280304Sjkim        if (!derbio) {
726280304Sjkim            BIO_printf(bio_err, "Error Opening OCSP response file\n");
727280304Sjkim            goto end;
728280304Sjkim        }
729280304Sjkim        resp = d2i_OCSP_RESPONSE_bio(derbio, NULL);
730280304Sjkim        BIO_free(derbio);
731280304Sjkim        if (!resp) {
732280304Sjkim            BIO_printf(bio_err, "Error reading OCSP response\n");
733280304Sjkim            goto end;
734280304Sjkim        }
735109998Smarkm
736280304Sjkim    } else {
737280304Sjkim        ret = 0;
738280304Sjkim        goto end;
739280304Sjkim    }
740109998Smarkm
741280304Sjkim done_resp:
742109998Smarkm
743280304Sjkim    if (respout) {
744280304Sjkim        derbio = BIO_new_file(respout, "wb");
745280304Sjkim        if (!derbio) {
746280304Sjkim            BIO_printf(bio_err, "Error opening file %s\n", respout);
747280304Sjkim            goto end;
748280304Sjkim        }
749280304Sjkim        i2d_OCSP_RESPONSE_bio(derbio, resp);
750280304Sjkim        BIO_free(derbio);
751280304Sjkim    }
752109998Smarkm
753280304Sjkim    i = OCSP_response_status(resp);
754109998Smarkm
755280304Sjkim    if (i != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
756280304Sjkim        BIO_printf(out, "Responder Error: %s (%d)\n",
757280304Sjkim                   OCSP_response_status_str(i), i);
758280304Sjkim        if (ignore_err)
759280304Sjkim            goto redo_accept;
760280304Sjkim        ret = 0;
761280304Sjkim        goto end;
762280304Sjkim    }
763109998Smarkm
764280304Sjkim    if (resp_text)
765280304Sjkim        OCSP_RESPONSE_print(out, resp, 0);
766109998Smarkm
767280304Sjkim    /* If running as responder don't verify our own response */
768280304Sjkim    if (cbio) {
769280304Sjkim        if (accept_count > 0)
770280304Sjkim            accept_count--;
771280304Sjkim        /* Redo if more connections needed */
772280304Sjkim        if (accept_count) {
773280304Sjkim            BIO_free_all(cbio);
774280304Sjkim            cbio = NULL;
775280304Sjkim            OCSP_REQUEST_free(req);
776280304Sjkim            req = NULL;
777280304Sjkim            OCSP_RESPONSE_free(resp);
778280304Sjkim            resp = NULL;
779280304Sjkim            goto redo_accept;
780280304Sjkim        }
781280304Sjkim        goto end;
782280304Sjkim    }
783109998Smarkm
784280304Sjkim    if (!store)
785280304Sjkim        store = setup_verify(bio_err, CAfile, CApath);
786280304Sjkim    if (!store)
787280304Sjkim        goto end;
788280304Sjkim    if (verify_certfile) {
789280304Sjkim        verify_other = load_certs(bio_err, verify_certfile, FORMAT_PEM,
790280304Sjkim                                  NULL, e, "validator certificate");
791280304Sjkim        if (!verify_other)
792280304Sjkim            goto end;
793280304Sjkim    }
794109998Smarkm
795280304Sjkim    bs = OCSP_response_get1_basic(resp);
796109998Smarkm
797280304Sjkim    if (!bs) {
798280304Sjkim        BIO_printf(bio_err, "Error parsing response\n");
799280304Sjkim        goto end;
800280304Sjkim    }
801109998Smarkm
802280304Sjkim    if (!noverify) {
803280304Sjkim        if (req && ((i = OCSP_check_nonce(req, bs)) <= 0)) {
804280304Sjkim            if (i == -1)
805280304Sjkim                BIO_printf(bio_err, "WARNING: no nonce in response\n");
806280304Sjkim            else {
807280304Sjkim                BIO_printf(bio_err, "Nonce Verify error\n");
808280304Sjkim                goto end;
809280304Sjkim            }
810280304Sjkim        }
811109998Smarkm
812280304Sjkim        i = OCSP_basic_verify(bs, verify_other, store, verify_flags);
813280304Sjkim        if (i < 0)
814280304Sjkim            i = OCSP_basic_verify(bs, NULL, store, 0);
815109998Smarkm
816280304Sjkim        if (i <= 0) {
817280304Sjkim            BIO_printf(bio_err, "Response Verify Failure\n");
818280304Sjkim            ERR_print_errors(bio_err);
819280304Sjkim        } else
820280304Sjkim            BIO_printf(bio_err, "Response verify OK\n");
821109998Smarkm
822280304Sjkim    }
823109998Smarkm
824280304Sjkim    if (!print_ocsp_summary(out, bs, req, reqnames, ids, nsec, maxage))
825280304Sjkim        goto end;
826109998Smarkm
827280304Sjkim    ret = 0;
828109998Smarkm
829280304Sjkim end:
830280304Sjkim    ERR_print_errors(bio_err);
831280304Sjkim    X509_free(signer);
832280304Sjkim    X509_STORE_free(store);
833280304Sjkim    EVP_PKEY_free(key);
834280304Sjkim    EVP_PKEY_free(rkey);
835280304Sjkim    X509_free(issuer);
836280304Sjkim    X509_free(cert);
837280304Sjkim    X509_free(rsigner);
838280304Sjkim    X509_free(rca_cert);
839280304Sjkim    free_index(rdb);
840280304Sjkim    BIO_free_all(cbio);
841280304Sjkim    BIO_free_all(acbio);
842280304Sjkim    BIO_free(out);
843280304Sjkim    OCSP_REQUEST_free(req);
844280304Sjkim    OCSP_RESPONSE_free(resp);
845280304Sjkim    OCSP_BASICRESP_free(bs);
846280304Sjkim    sk_OPENSSL_STRING_free(reqnames);
847280304Sjkim    sk_OCSP_CERTID_free(ids);
848280304Sjkim    sk_X509_pop_free(sign_other, X509_free);
849280304Sjkim    sk_X509_pop_free(verify_other, X509_free);
850280304Sjkim    sk_CONF_VALUE_pop_free(headers, X509V3_conf_free);
851109998Smarkm
852280304Sjkim    if (thost)
853280304Sjkim        OPENSSL_free(thost);
854280304Sjkim    if (tport)
855280304Sjkim        OPENSSL_free(tport);
856280304Sjkim    if (tpath)
857280304Sjkim        OPENSSL_free(tpath);
858280304Sjkim
859280304Sjkim    OPENSSL_EXIT(ret);
860109998Smarkm}
861109998Smarkm
862280304Sjkimstatic int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert,
863280304Sjkim                         const EVP_MD *cert_id_md, X509 *issuer,
864280304Sjkim                         STACK_OF(OCSP_CERTID) *ids)
865280304Sjkim{
866280304Sjkim    OCSP_CERTID *id;
867280304Sjkim    if (!issuer) {
868280304Sjkim        BIO_printf(bio_err, "No issuer certificate specified\n");
869280304Sjkim        return 0;
870280304Sjkim    }
871280304Sjkim    if (!*req)
872280304Sjkim        *req = OCSP_REQUEST_new();
873280304Sjkim    if (!*req)
874280304Sjkim        goto err;
875280304Sjkim    id = OCSP_cert_to_id(cert_id_md, cert, issuer);
876280304Sjkim    if (!id || !sk_OCSP_CERTID_push(ids, id))
877280304Sjkim        goto err;
878280304Sjkim    if (!OCSP_request_add0_id(*req, id))
879280304Sjkim        goto err;
880280304Sjkim    return 1;
881109998Smarkm
882280304Sjkim err:
883280304Sjkim    BIO_printf(bio_err, "Error Creating OCSP request\n");
884280304Sjkim    return 0;
885280304Sjkim}
886109998Smarkm
887280304Sjkimstatic int add_ocsp_serial(OCSP_REQUEST **req, char *serial,
888280304Sjkim                           const EVP_MD *cert_id_md, X509 *issuer,
889280304Sjkim                           STACK_OF(OCSP_CERTID) *ids)
890280304Sjkim{
891280304Sjkim    OCSP_CERTID *id;
892280304Sjkim    X509_NAME *iname;
893280304Sjkim    ASN1_BIT_STRING *ikey;
894280304Sjkim    ASN1_INTEGER *sno;
895280304Sjkim    if (!issuer) {
896280304Sjkim        BIO_printf(bio_err, "No issuer certificate specified\n");
897280304Sjkim        return 0;
898280304Sjkim    }
899280304Sjkim    if (!*req)
900280304Sjkim        *req = OCSP_REQUEST_new();
901280304Sjkim    if (!*req)
902280304Sjkim        goto err;
903280304Sjkim    iname = X509_get_subject_name(issuer);
904280304Sjkim    ikey = X509_get0_pubkey_bitstr(issuer);
905280304Sjkim    sno = s2i_ASN1_INTEGER(NULL, serial);
906280304Sjkim    if (!sno) {
907280304Sjkim        BIO_printf(bio_err, "Error converting serial number %s\n", serial);
908280304Sjkim        return 0;
909280304Sjkim    }
910280304Sjkim    id = OCSP_cert_id_new(cert_id_md, iname, ikey, sno);
911280304Sjkim    ASN1_INTEGER_free(sno);
912280304Sjkim    if (!id || !sk_OCSP_CERTID_push(ids, id))
913280304Sjkim        goto err;
914280304Sjkim    if (!OCSP_request_add0_id(*req, id))
915280304Sjkim        goto err;
916280304Sjkim    return 1;
917109998Smarkm
918280304Sjkim err:
919280304Sjkim    BIO_printf(bio_err, "Error Creating OCSP request\n");
920280304Sjkim    return 0;
921280304Sjkim}
922109998Smarkm
923109998Smarkmstatic int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req,
924280304Sjkim                              STACK_OF(OPENSSL_STRING) *names,
925280304Sjkim                              STACK_OF(OCSP_CERTID) *ids, long nsec,
926280304Sjkim                              long maxage)
927280304Sjkim{
928280304Sjkim    OCSP_CERTID *id;
929280304Sjkim    char *name;
930280304Sjkim    int i;
931109998Smarkm
932280304Sjkim    int status, reason;
933109998Smarkm
934280304Sjkim    ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
935109998Smarkm
936280304Sjkim    if (!bs || !req || !sk_OPENSSL_STRING_num(names)
937280304Sjkim        || !sk_OCSP_CERTID_num(ids))
938280304Sjkim        return 1;
939109998Smarkm
940280304Sjkim    for (i = 0; i < sk_OCSP_CERTID_num(ids); i++) {
941280304Sjkim        id = sk_OCSP_CERTID_value(ids, i);
942280304Sjkim        name = sk_OPENSSL_STRING_value(names, i);
943280304Sjkim        BIO_printf(out, "%s: ", name);
944109998Smarkm
945280304Sjkim        if (!OCSP_resp_find_status(bs, id, &status, &reason,
946280304Sjkim                                   &rev, &thisupd, &nextupd)) {
947280304Sjkim            BIO_puts(out, "ERROR: No Status found.\n");
948280304Sjkim            continue;
949280304Sjkim        }
950109998Smarkm
951280304Sjkim        /*
952280304Sjkim         * Check validity: if invalid write to output BIO so we know which
953280304Sjkim         * response this refers to.
954280304Sjkim         */
955280304Sjkim        if (!OCSP_check_validity(thisupd, nextupd, nsec, maxage)) {
956280304Sjkim            BIO_puts(out, "WARNING: Status times invalid.\n");
957280304Sjkim            ERR_print_errors(out);
958280304Sjkim        }
959280304Sjkim        BIO_printf(out, "%s\n", OCSP_cert_status_str(status));
960109998Smarkm
961280304Sjkim        BIO_puts(out, "\tThis Update: ");
962280304Sjkim        ASN1_GENERALIZEDTIME_print(out, thisupd);
963280304Sjkim        BIO_puts(out, "\n");
964109998Smarkm
965280304Sjkim        if (nextupd) {
966280304Sjkim            BIO_puts(out, "\tNext Update: ");
967280304Sjkim            ASN1_GENERALIZEDTIME_print(out, nextupd);
968280304Sjkim            BIO_puts(out, "\n");
969280304Sjkim        }
970109998Smarkm
971280304Sjkim        if (status != V_OCSP_CERTSTATUS_REVOKED)
972280304Sjkim            continue;
973109998Smarkm
974280304Sjkim        if (reason != -1)
975280304Sjkim            BIO_printf(out, "\tReason: %s\n", OCSP_crl_reason_str(reason));
976109998Smarkm
977280304Sjkim        BIO_puts(out, "\tRevocation Time: ");
978280304Sjkim        ASN1_GENERALIZEDTIME_print(out, rev);
979280304Sjkim        BIO_puts(out, "\n");
980280304Sjkim    }
981109998Smarkm
982280304Sjkim    return 1;
983280304Sjkim}
984109998Smarkm
985280304Sjkimstatic int make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req,
986280304Sjkim                              CA_DB *db, X509 *ca, X509 *rcert,
987280304Sjkim                              EVP_PKEY *rkey, STACK_OF(X509) *rother,
988280304Sjkim                              unsigned long flags, int nmin, int ndays)
989280304Sjkim{
990280304Sjkim    ASN1_TIME *thisupd = NULL, *nextupd = NULL;
991280304Sjkim    OCSP_CERTID *cid, *ca_id = NULL;
992280304Sjkim    OCSP_BASICRESP *bs = NULL;
993280304Sjkim    int i, id_count, ret = 1;
994109998Smarkm
995280304Sjkim    id_count = OCSP_request_onereq_count(req);
996109998Smarkm
997280304Sjkim    if (id_count <= 0) {
998280304Sjkim        *resp =
999280304Sjkim            OCSP_response_create(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, NULL);
1000280304Sjkim        goto end;
1001280304Sjkim    }
1002109998Smarkm
1003280304Sjkim    bs = OCSP_BASICRESP_new();
1004280304Sjkim    thisupd = X509_gmtime_adj(NULL, 0);
1005280304Sjkim    if (ndays != -1)
1006295016Sjkim        nextupd = X509_time_adj_ex(NULL, ndays, nmin * 60, NULL);
1007109998Smarkm
1008280304Sjkim    /* Examine each certificate id in the request */
1009280304Sjkim    for (i = 0; i < id_count; i++) {
1010280304Sjkim        OCSP_ONEREQ *one;
1011280304Sjkim        ASN1_INTEGER *serial;
1012280304Sjkim        char **inf;
1013280304Sjkim        ASN1_OBJECT *cert_id_md_oid;
1014280304Sjkim        const EVP_MD *cert_id_md;
1015280304Sjkim        one = OCSP_request_onereq_get0(req, i);
1016280304Sjkim        cid = OCSP_onereq_get0_id(one);
1017109998Smarkm
1018280304Sjkim        OCSP_id_get0_info(NULL, &cert_id_md_oid, NULL, NULL, cid);
1019109998Smarkm
1020280304Sjkim        cert_id_md = EVP_get_digestbyobj(cert_id_md_oid);
1021280304Sjkim        if (!cert_id_md) {
1022280304Sjkim            *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_INTERNALERROR,
1023280304Sjkim                                         NULL);
1024280304Sjkim            goto end;
1025280304Sjkim        }
1026280304Sjkim        if (ca_id)
1027280304Sjkim            OCSP_CERTID_free(ca_id);
1028280304Sjkim        ca_id = OCSP_cert_to_id(cert_id_md, NULL, ca);
1029238405Sjkim
1030280304Sjkim        /* Is this request about our CA? */
1031280304Sjkim        if (OCSP_id_issuer_cmp(ca_id, cid)) {
1032280304Sjkim            OCSP_basic_add1_status(bs, cid,
1033280304Sjkim                                   V_OCSP_CERTSTATUS_UNKNOWN,
1034280304Sjkim                                   0, NULL, thisupd, nextupd);
1035280304Sjkim            continue;
1036280304Sjkim        }
1037280304Sjkim        OCSP_id_get0_info(NULL, NULL, NULL, &serial, cid);
1038280304Sjkim        inf = lookup_serial(db, serial);
1039280304Sjkim        if (!inf)
1040280304Sjkim            OCSP_basic_add1_status(bs, cid,
1041280304Sjkim                                   V_OCSP_CERTSTATUS_UNKNOWN,
1042280304Sjkim                                   0, NULL, thisupd, nextupd);
1043280304Sjkim        else if (inf[DB_type][0] == DB_TYPE_VAL)
1044280304Sjkim            OCSP_basic_add1_status(bs, cid,
1045280304Sjkim                                   V_OCSP_CERTSTATUS_GOOD,
1046280304Sjkim                                   0, NULL, thisupd, nextupd);
1047280304Sjkim        else if (inf[DB_type][0] == DB_TYPE_REV) {
1048280304Sjkim            ASN1_OBJECT *inst = NULL;
1049280304Sjkim            ASN1_TIME *revtm = NULL;
1050280304Sjkim            ASN1_GENERALIZEDTIME *invtm = NULL;
1051280304Sjkim            OCSP_SINGLERESP *single;
1052280304Sjkim            int reason = -1;
1053280304Sjkim            unpack_revinfo(&revtm, &reason, &inst, &invtm, inf[DB_rev_date]);
1054280304Sjkim            single = OCSP_basic_add1_status(bs, cid,
1055280304Sjkim                                            V_OCSP_CERTSTATUS_REVOKED,
1056280304Sjkim                                            reason, revtm, thisupd, nextupd);
1057280304Sjkim            if (invtm)
1058280304Sjkim                OCSP_SINGLERESP_add1_ext_i2d(single, NID_invalidity_date,
1059280304Sjkim                                             invtm, 0, 0);
1060280304Sjkim            else if (inst)
1061280304Sjkim                OCSP_SINGLERESP_add1_ext_i2d(single,
1062280304Sjkim                                             NID_hold_instruction_code, inst,
1063280304Sjkim                                             0, 0);
1064280304Sjkim            ASN1_OBJECT_free(inst);
1065280304Sjkim            ASN1_TIME_free(revtm);
1066280304Sjkim            ASN1_GENERALIZEDTIME_free(invtm);
1067280304Sjkim        }
1068280304Sjkim    }
1069238405Sjkim
1070280304Sjkim    OCSP_copy_nonce(bs, req);
1071238405Sjkim
1072280304Sjkim    OCSP_basic_sign(bs, rcert, rkey, NULL, rother, flags);
1073109998Smarkm
1074280304Sjkim    *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_SUCCESSFUL, bs);
1075109998Smarkm
1076280304Sjkim end:
1077280304Sjkim    ASN1_TIME_free(thisupd);
1078280304Sjkim    ASN1_TIME_free(nextupd);
1079280304Sjkim    OCSP_CERTID_free(ca_id);
1080280304Sjkim    OCSP_BASICRESP_free(bs);
1081280304Sjkim    return ret;
1082109998Smarkm
1083280304Sjkim}
1084109998Smarkm
1085127128Snectarstatic char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser)
1086280304Sjkim{
1087280304Sjkim    int i;
1088280304Sjkim    BIGNUM *bn = NULL;
1089280304Sjkim    char *itmp, *row[DB_NUMBER], **rrow;
1090280304Sjkim    for (i = 0; i < DB_NUMBER; i++)
1091280304Sjkim        row[i] = NULL;
1092280304Sjkim    bn = ASN1_INTEGER_to_BN(ser, NULL);
1093280304Sjkim    OPENSSL_assert(bn);         /* FIXME: should report an error at this
1094280304Sjkim                                 * point and abort */
1095280304Sjkim    if (BN_is_zero(bn))
1096280304Sjkim        itmp = BUF_strdup("00");
1097280304Sjkim    else
1098280304Sjkim        itmp = BN_bn2hex(bn);
1099280304Sjkim    row[DB_serial] = itmp;
1100280304Sjkim    BN_free(bn);
1101280304Sjkim    rrow = TXT_DB_get_by_index(db->db, DB_serial, row);
1102280304Sjkim    OPENSSL_free(itmp);
1103280304Sjkim    return rrow;
1104280304Sjkim}
1105109998Smarkm
1106109998Smarkm/* Quick and dirty OCSP server: read in and parse input request */
1107109998Smarkm
1108109998Smarkmstatic BIO *init_responder(char *port)
1109280304Sjkim{
1110280304Sjkim    BIO *acbio = NULL, *bufbio = NULL;
1111280304Sjkim    bufbio = BIO_new(BIO_f_buffer());
1112280304Sjkim    if (!bufbio)
1113280304Sjkim        goto err;
1114280304Sjkim# ifndef OPENSSL_NO_SOCK
1115280304Sjkim    acbio = BIO_new_accept(port);
1116280304Sjkim# else
1117280304Sjkim    BIO_printf(bio_err,
1118280304Sjkim               "Error setting up accept BIO - sockets not supported.\n");
1119280304Sjkim# endif
1120280304Sjkim    if (!acbio)
1121280304Sjkim        goto err;
1122280304Sjkim    BIO_set_accept_bios(acbio, bufbio);
1123280304Sjkim    bufbio = NULL;
1124109998Smarkm
1125280304Sjkim    if (BIO_do_accept(acbio) <= 0) {
1126280304Sjkim        BIO_printf(bio_err, "Error setting up accept BIO\n");
1127280304Sjkim        ERR_print_errors(bio_err);
1128280304Sjkim        goto err;
1129280304Sjkim    }
1130109998Smarkm
1131280304Sjkim    return acbio;
1132109998Smarkm
1133280304Sjkim err:
1134280304Sjkim    BIO_free_all(acbio);
1135280304Sjkim    BIO_free(bufbio);
1136280304Sjkim    return NULL;
1137280304Sjkim}
1138109998Smarkm
1139280304Sjkimstatic int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio,
1140280304Sjkim                        char *port)
1141280304Sjkim{
1142280304Sjkim    int have_post = 0, len;
1143280304Sjkim    OCSP_REQUEST *req = NULL;
1144280304Sjkim    char inbuf[1024];
1145280304Sjkim    BIO *cbio = NULL;
1146109998Smarkm
1147280304Sjkim    if (BIO_do_accept(acbio) <= 0) {
1148280304Sjkim        BIO_printf(bio_err, "Error accepting connection\n");
1149280304Sjkim        ERR_print_errors(bio_err);
1150280304Sjkim        return 0;
1151280304Sjkim    }
1152109998Smarkm
1153280304Sjkim    cbio = BIO_pop(acbio);
1154280304Sjkim    *pcbio = cbio;
1155109998Smarkm
1156280304Sjkim    for (;;) {
1157280304Sjkim        len = BIO_gets(cbio, inbuf, sizeof inbuf);
1158280304Sjkim        if (len <= 0)
1159280304Sjkim            return 1;
1160280304Sjkim        /* Look for "POST" signalling start of query */
1161280304Sjkim        if (!have_post) {
1162280304Sjkim            if (strncmp(inbuf, "POST", 4)) {
1163280304Sjkim                BIO_printf(bio_err, "Invalid request\n");
1164280304Sjkim                return 1;
1165280304Sjkim            }
1166280304Sjkim            have_post = 1;
1167280304Sjkim        }
1168280304Sjkim        /* Look for end of headers */
1169280304Sjkim        if ((inbuf[0] == '\r') || (inbuf[0] == '\n'))
1170280304Sjkim            break;
1171280304Sjkim    }
1172109998Smarkm
1173280304Sjkim    /* Try to read OCSP request */
1174109998Smarkm
1175280304Sjkim    req = d2i_OCSP_REQUEST_bio(cbio, NULL);
1176109998Smarkm
1177280304Sjkim    if (!req) {
1178280304Sjkim        BIO_printf(bio_err, "Error parsing OCSP request\n");
1179280304Sjkim        ERR_print_errors(bio_err);
1180280304Sjkim    }
1181109998Smarkm
1182280304Sjkim    *preq = req;
1183109998Smarkm
1184280304Sjkim    return 1;
1185109998Smarkm
1186280304Sjkim}
1187109998Smarkm
1188109998Smarkmstatic int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp)
1189280304Sjkim{
1190280304Sjkim    char http_resp[] =
1191280304Sjkim        "HTTP/1.0 200 OK\r\nContent-type: application/ocsp-response\r\n"
1192280304Sjkim        "Content-Length: %d\r\n\r\n";
1193280304Sjkim    if (!cbio)
1194280304Sjkim        return 0;
1195280304Sjkim    BIO_printf(cbio, http_resp, i2d_OCSP_RESPONSE(resp, NULL));
1196280304Sjkim    i2d_OCSP_RESPONSE_bio(cbio, resp);
1197280304Sjkim    (void)BIO_flush(cbio);
1198280304Sjkim    return 1;
1199280304Sjkim}
1200109998Smarkm
1201194206Ssimonstatic OCSP_RESPONSE *query_responder(BIO *err, BIO *cbio, char *path,
1202280304Sjkim                                      STACK_OF(CONF_VALUE) *headers,
1203280304Sjkim                                      OCSP_REQUEST *req, int req_timeout)
1204280304Sjkim{
1205280304Sjkim    int fd;
1206280304Sjkim    int rv;
1207280304Sjkim    int i;
1208280304Sjkim    OCSP_REQ_CTX *ctx = NULL;
1209280304Sjkim    OCSP_RESPONSE *rsp = NULL;
1210280304Sjkim    fd_set confds;
1211280304Sjkim    struct timeval tv;
1212194206Ssimon
1213280304Sjkim    if (req_timeout != -1)
1214280304Sjkim        BIO_set_nbio(cbio, 1);
1215194206Ssimon
1216280304Sjkim    rv = BIO_do_connect(cbio);
1217194206Ssimon
1218280304Sjkim    if ((rv <= 0) && ((req_timeout == -1) || !BIO_should_retry(cbio))) {
1219280304Sjkim        BIO_puts(err, "Error connecting BIO\n");
1220280304Sjkim        return NULL;
1221280304Sjkim    }
1222194206Ssimon
1223291721Sjkim    if (BIO_get_fd(cbio, &fd) < 0) {
1224291721Sjkim        BIO_puts(bio_err, "Can't get connection fd\n");
1225280304Sjkim        goto err;
1226280304Sjkim    }
1227194206Ssimon
1228280304Sjkim    if (req_timeout != -1 && rv <= 0) {
1229280304Sjkim        FD_ZERO(&confds);
1230280304Sjkim        openssl_fdset(fd, &confds);
1231280304Sjkim        tv.tv_usec = 0;
1232280304Sjkim        tv.tv_sec = req_timeout;
1233280304Sjkim        rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv);
1234280304Sjkim        if (rv == 0) {
1235280304Sjkim            BIO_puts(err, "Timeout on connect\n");
1236280304Sjkim            return NULL;
1237280304Sjkim        }
1238280304Sjkim    }
1239194206Ssimon
1240280304Sjkim    ctx = OCSP_sendreq_new(cbio, path, NULL, -1);
1241280304Sjkim    if (!ctx)
1242280304Sjkim        return NULL;
1243194206Ssimon
1244280304Sjkim    for (i = 0; i < sk_CONF_VALUE_num(headers); i++) {
1245280304Sjkim        CONF_VALUE *hdr = sk_CONF_VALUE_value(headers, i);
1246280304Sjkim        if (!OCSP_REQ_CTX_add1_header(ctx, hdr->name, hdr->value))
1247280304Sjkim            goto err;
1248280304Sjkim    }
1249238405Sjkim
1250280304Sjkim    if (!OCSP_REQ_CTX_set1_req(ctx, req))
1251280304Sjkim        goto err;
1252238405Sjkim
1253280304Sjkim    for (;;) {
1254280304Sjkim        rv = OCSP_sendreq_nbio(&rsp, ctx);
1255280304Sjkim        if (rv != -1)
1256280304Sjkim            break;
1257280304Sjkim        if (req_timeout == -1)
1258280304Sjkim            continue;
1259280304Sjkim        FD_ZERO(&confds);
1260280304Sjkim        openssl_fdset(fd, &confds);
1261280304Sjkim        tv.tv_usec = 0;
1262280304Sjkim        tv.tv_sec = req_timeout;
1263280304Sjkim        if (BIO_should_read(cbio))
1264280304Sjkim            rv = select(fd + 1, (void *)&confds, NULL, NULL, &tv);
1265280304Sjkim        else if (BIO_should_write(cbio))
1266280304Sjkim            rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv);
1267280304Sjkim        else {
1268280304Sjkim            BIO_puts(err, "Unexpected retry condition\n");
1269280304Sjkim            goto err;
1270280304Sjkim        }
1271280304Sjkim        if (rv == 0) {
1272280304Sjkim            BIO_puts(err, "Timeout on request\n");
1273280304Sjkim            break;
1274280304Sjkim        }
1275280304Sjkim        if (rv == -1) {
1276280304Sjkim            BIO_puts(err, "Select error\n");
1277280304Sjkim            break;
1278280304Sjkim        }
1279238405Sjkim
1280280304Sjkim    }
1281280304Sjkim err:
1282280304Sjkim    if (ctx)
1283280304Sjkim        OCSP_REQ_CTX_free(ctx);
1284194206Ssimon
1285280304Sjkim    return rsp;
1286280304Sjkim}
1287194206Ssimon
1288194206SsimonOCSP_RESPONSE *process_responder(BIO *err, OCSP_REQUEST *req,
1289280304Sjkim                                 char *host, char *path, char *port,
1290280304Sjkim                                 int use_ssl, STACK_OF(CONF_VALUE) *headers,
1291280304Sjkim                                 int req_timeout)
1292280304Sjkim{
1293280304Sjkim    BIO *cbio = NULL;
1294280304Sjkim    SSL_CTX *ctx = NULL;
1295280304Sjkim    OCSP_RESPONSE *resp = NULL;
1296280304Sjkim    cbio = BIO_new_connect(host);
1297280304Sjkim    if (!cbio) {
1298280304Sjkim        BIO_printf(err, "Error creating connect BIO\n");
1299280304Sjkim        goto end;
1300280304Sjkim    }
1301280304Sjkim    if (port)
1302280304Sjkim        BIO_set_conn_port(cbio, port);
1303280304Sjkim    if (use_ssl == 1) {
1304280304Sjkim        BIO *sbio;
1305280304Sjkim        ctx = SSL_CTX_new(SSLv23_client_method());
1306280304Sjkim        if (ctx == NULL) {
1307280304Sjkim            BIO_printf(err, "Error creating SSL context.\n");
1308280304Sjkim            goto end;
1309280304Sjkim        }
1310280304Sjkim        SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
1311280304Sjkim        sbio = BIO_new_ssl(ctx, 1);
1312280304Sjkim        cbio = BIO_push(sbio, cbio);
1313280304Sjkim    }
1314280304Sjkim    resp = query_responder(err, cbio, path, headers, req, req_timeout);
1315280304Sjkim    if (!resp)
1316280304Sjkim        BIO_printf(bio_err, "Error querying OCSP responder\n");
1317280304Sjkim end:
1318280304Sjkim    if (cbio)
1319280304Sjkim        BIO_free_all(cbio);
1320280304Sjkim    if (ctx)
1321280304Sjkim        SSL_CTX_free(ctx);
1322280304Sjkim    return resp;
1323280304Sjkim}
1324194206Ssimon
1325194206Ssimon#endif
1326