Annotation of src/usr.bin/openssl/ocsp.c, Revision 1.19
1.19 ! inoguchi 1: /* $OpenBSD: ocsp.c,v 1.18 2020/09/09 13:08:38 inoguchi Exp $ */
1.1 jsing 2: /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3: * project 2000.
4: */
5: /* ====================================================================
6: * Copyright (c) 1999 The OpenSSL Project. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: *
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: *
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in
17: * the documentation and/or other materials provided with the
18: * distribution.
19: *
20: * 3. All advertising materials mentioning features or use of this
21: * software must display the following acknowledgment:
22: * "This product includes software developed by the OpenSSL Project
23: * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24: *
25: * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26: * endorse or promote products derived from this software without
27: * prior written permission. For written permission, please contact
28: * licensing@OpenSSL.org.
29: *
30: * 5. Products derived from this software may not be called "OpenSSL"
31: * nor may "OpenSSL" appear in their names without prior written
32: * permission of the OpenSSL Project.
33: *
34: * 6. Redistributions of any form whatsoever must retain the following
35: * acknowledgment:
36: * "This product includes software developed by the OpenSSL Project
37: * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38: *
39: * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40: * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
43: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50: * OF THE POSSIBILITY OF SUCH DAMAGE.
51: * ====================================================================
52: *
53: * This product includes cryptographic software written by Eric Young
54: * (eay@cryptsoft.com). This product includes software written by Tim
55: * Hudson (tjh@cryptsoft.com).
56: *
57: */
58: #ifndef OPENSSL_NO_OCSP
59:
1.2 deraadt 60: #include <sys/types.h>
1.1 jsing 61:
62: #include <stdio.h>
63: #include <stdlib.h>
64: #include <limits.h>
65: #include <string.h>
1.2 deraadt 66: #include <poll.h>
1.1 jsing 67: #include <time.h>
68:
69: /* Needs to be included before the openssl headers! */
70: #include "apps.h"
71:
72: #include <openssl/bn.h>
73: #include <openssl/crypto.h>
74: #include <openssl/err.h>
75: #include <openssl/evp.h>
76: #include <openssl/ssl.h>
77: #include <openssl/x509v3.h>
78:
79: /* Maximum leeway in validity period: default 5 minutes */
80: #define MAX_VALIDITY_PERIOD (5 * 60)
81:
1.19 ! inoguchi 82: static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert,
! 83: const EVP_MD *cert_id_md, X509 *issuer, STACK_OF(OCSP_CERTID) *ids);
! 84: static int add_ocsp_serial(OCSP_REQUEST **req, char *serial,
! 85: const EVP_MD *cert_id_md, X509 *issuer, STACK_OF(OCSP_CERTID) *ids);
1.17 inoguchi 86: static int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req,
1.19 ! inoguchi 87: STACK_OF(OPENSSL_STRING) *names, STACK_OF(OCSP_CERTID) *ids, long nsec,
1.1 jsing 88: long maxage);
89:
1.19 ! inoguchi 90: static int make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req,
! 91: CA_DB *db, X509 *ca, X509 *rcert, EVP_PKEY *rkey, STACK_OF(X509) *rother,
! 92: unsigned long flags, int nmin, int ndays);
1.1 jsing 93:
1.17 inoguchi 94: static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser);
1.1 jsing 95: static BIO *init_responder(char *port);
1.19 ! inoguchi 96: static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio,
! 97: char *port);
1.17 inoguchi 98: static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp);
99: static OCSP_RESPONSE *query_responder(BIO *err, BIO *cbio, char *path,
1.19 ! inoguchi 100: STACK_OF(CONF_VALUE) *headers, OCSP_REQUEST *req, int req_timeout);
1.1 jsing 101:
1.16 inoguchi 102: static struct {
103: int accept_count;
104: int add_nonce;
105: char *CAfile;
106: char *CApath;
107: X509 *cert;
108: const EVP_MD *cert_id_md;
1.17 inoguchi 109: STACK_OF(CONF_VALUE) *headers;
1.16 inoguchi 110: char *host;
1.17 inoguchi 111: STACK_OF(OCSP_CERTID) *ids;
1.16 inoguchi 112: int ignore_err;
113: X509 *issuer;
114: char *keyfile;
115: long maxage;
116: int ndays;
117: int nmin;
118: int no_usage;
119: int noverify;
120: long nsec;
121: char *outfile;
122: char *path;
123: char *port;
124: char *rca_filename;
125: char *rcertfile;
126: OCSP_REQUEST *req;
127: int req_text;
128: int req_timeout;
129: char *reqin;
1.17 inoguchi 130: STACK_OF(OPENSSL_STRING) *reqnames;
1.16 inoguchi 131: char *reqout;
132: int resp_text;
133: char *respin;
134: char *respout;
135: unsigned long rflags;
136: char *ridx_filename;
137: char *rkeyfile;
138: char *rsignfile;
139: char *sign_certfile;
140: unsigned long sign_flags;
141: char *signfile;
142: int use_ssl;
143: char *verify_certfile;
144: unsigned long verify_flags;
145: } ocsp_config;
146:
147: static int
148: ocsp_opt_cert(char *arg)
149: {
150: X509_free(ocsp_config.cert);
151: ocsp_config.cert = load_cert(bio_err, arg, FORMAT_PEM, NULL,
152: "certificate");
153: if (ocsp_config.cert == NULL) {
154: ocsp_config.no_usage = 1;
155: return (1);
156: }
157: if (ocsp_config.cert_id_md == NULL)
158: ocsp_config.cert_id_md = EVP_sha1();
159: if (!add_ocsp_cert(&ocsp_config.req, ocsp_config.cert,
160: ocsp_config.cert_id_md, ocsp_config.issuer, ocsp_config.ids)) {
161: ocsp_config.no_usage = 1;
162: return (1);
163: }
164: if (!sk_OPENSSL_STRING_push(ocsp_config.reqnames, arg)) {
165: ocsp_config.no_usage = 1;
166: return (1);
167: }
168: return (0);
169: }
170:
171: static int
172: ocsp_opt_cert_id_md(int argc, char **argv, int *argsused)
173: {
174: char *name = argv[0];
175:
176: if (*name++ != '-')
177: return (1);
178:
179: if ((ocsp_config.cert_id_md = EVP_get_digestbyname(name)) == NULL)
180: return (1);
181:
182: *argsused = 1;
183: return (0);
184: }
185:
186: static int
187: ocsp_opt_header(int argc, char **argv, int *argsused)
188: {
189: if (argc < 3 || argv[1] == NULL || argv[2] == NULL)
190: return (1);
191:
192: if (!X509V3_add_value(argv[1], argv[2], &ocsp_config.headers)) {
193: ocsp_config.no_usage = 1;
194: return (1);
195: }
196:
197: *argsused = 3;
198: return (0);
199: }
200:
201: static int
202: ocsp_opt_host(char *arg)
203: {
204: if (ocsp_config.use_ssl != -1)
205: return (1);
206:
207: ocsp_config.host = arg;
208: return (0);
209: }
210:
211: static int
212: ocsp_opt_issuer(char *arg)
213: {
214: X509_free(ocsp_config.issuer);
215: ocsp_config.issuer = load_cert(bio_err, arg, FORMAT_PEM, NULL,
216: "issuer certificate");
217: if (ocsp_config.issuer == NULL) {
218: ocsp_config.no_usage = 1;
219: return (1);
220: }
221: return (0);
222: }
223:
224: static int
225: ocsp_opt_ndays(char *arg)
226: {
227: const char *errstr = NULL;
228:
229: ocsp_config.ndays = strtonum(arg, 0, INT_MAX, &errstr);
230: if (errstr != NULL) {
231: BIO_printf(bio_err, "Illegal update period %s: %s\n",
232: arg, errstr);
233: return (1);
234: }
235: return (0);
236: }
237:
238: static int
239: ocsp_opt_nmin(char *arg)
240: {
241: const char *errstr = NULL;
242:
243: ocsp_config.nmin = strtonum(arg, 0, INT_MAX, &errstr);
244: if (errstr != NULL) {
245: BIO_printf(bio_err, "Illegal update period %s: %s\n",
246: arg, errstr);
247: return (1);
248: }
249:
250: if (ocsp_config.ndays != -1)
251: return (1);
252:
253: ocsp_config.ndays = 0;
254: return (0);
255: }
256:
257: static int
258: ocsp_opt_nrequest(char *arg)
259: {
260: const char *errstr = NULL;
261:
262: ocsp_config.accept_count = strtonum(arg, 0, INT_MAX, &errstr);
263: if (errstr != NULL) {
264: BIO_printf(bio_err, "Illegal accept count %s: %s\n",
265: arg, errstr);
266: return (1);
267: }
268: return (0);
269: }
270:
271: static int
272: ocsp_opt_port(char *arg)
273: {
274: if (ocsp_config.use_ssl != -1)
275: return (1);
276:
277: ocsp_config.port = arg;
278: return (0);
279: }
280:
281: static int
282: ocsp_opt_serial(char *arg)
283: {
284: if (ocsp_config.cert_id_md == NULL)
285: ocsp_config.cert_id_md = EVP_sha1();
286: if (!add_ocsp_serial(&ocsp_config.req, arg, ocsp_config.cert_id_md,
287: ocsp_config.issuer, ocsp_config.ids)) {
288: ocsp_config.no_usage = 1;
289: return (1);
290: }
291: if (!sk_OPENSSL_STRING_push(ocsp_config.reqnames, arg)) {
292: ocsp_config.no_usage = 1;
293: return (1);
294: }
295: return (0);
296: }
297:
298: static int
299: ocsp_opt_status_age(char *arg)
300: {
301: const char *errstr = NULL;
302:
303: ocsp_config.maxage = strtonum(arg, 0, LONG_MAX, &errstr);
304: if (errstr != NULL) {
305: BIO_printf(bio_err, "Illegal validity age %s: %s\n",
306: arg, errstr);
307: return (1);
308: }
309: return (0);
310: }
311:
312: static int
313: ocsp_opt_text(void)
314: {
315: ocsp_config.req_text = 1;
316: ocsp_config.resp_text = 1;
317: return (0);
318: }
319:
320: static int
321: ocsp_opt_timeout(char *arg)
322: {
323: const char *errstr = NULL;
324:
325: ocsp_config.req_timeout = strtonum(arg, 0, INT_MAX, &errstr);
326: if (errstr != NULL) {
327: BIO_printf(bio_err, "Illegal timeout value %s: %s\n",
328: arg, errstr);
329: return (1);
330: }
331: return (0);
332: }
333:
334: static int
335: ocsp_opt_url(char *arg)
336: {
337: if (ocsp_config.host == NULL && ocsp_config.port == NULL &&
338: ocsp_config.path == NULL) {
339: if (!OCSP_parse_url(arg, &ocsp_config.host, &ocsp_config.port,
340: &ocsp_config.path, &ocsp_config.use_ssl)) {
341: BIO_printf(bio_err, "Error parsing URL\n");
342: return (1);
343: }
344: }
345: return (0);
346: }
347:
348: static int
349: ocsp_opt_vafile(char *arg)
350: {
351: ocsp_config.verify_certfile = arg;
352: ocsp_config.verify_flags |= OCSP_TRUSTOTHER;
353: return (0);
354: }
355:
356: static int
357: ocsp_opt_validity_period(char *arg)
358: {
359: const char *errstr = NULL;
360:
361: ocsp_config.nsec = strtonum(arg, 0, LONG_MAX, &errstr);
362: if (errstr != NULL) {
363: BIO_printf(bio_err, "Illegal validity period %s: %s\n",
364: arg, errstr);
365: return (1);
366: }
367: return (0);
368: }
369:
370: static const struct option ocsp_options[] = {
371: {
372: .name = "CA",
373: .argname = "file",
374: .desc = "CA certificate corresponding to the revocation information",
375: .type = OPTION_ARG,
376: .opt.arg = &ocsp_config.rca_filename,
377: },
378: {
379: .name = "CAfile",
380: .argname = "file",
381: .desc = "Trusted certificates file",
382: .type = OPTION_ARG,
383: .opt.arg = &ocsp_config.CAfile,
384: },
385: {
386: .name = "CApath",
387: .argname = "directory",
388: .desc = "Trusted certificates directory",
389: .type = OPTION_ARG,
390: .opt.arg = &ocsp_config.CApath,
391: },
392: {
393: .name = "cert",
394: .argname = "file",
395: .desc = "Certificate to check",
396: .type = OPTION_ARG_FUNC,
397: .opt.argfunc = ocsp_opt_cert,
398: },
399: {
400: .name = "header",
401: .argname = "name value",
402: .desc = "Add the header name with the value to the request",
403: .type = OPTION_ARGV_FUNC,
404: .opt.argvfunc = ocsp_opt_header,
405: },
406: {
407: .name = "host",
408: .argname = "hostname:port",
409: .desc = "Send OCSP request to host on port",
410: .type = OPTION_ARG_FUNC,
411: .opt.argfunc = ocsp_opt_host,
412: },
413: {
414: .name = "ignore_err",
415: .desc = "Ignore the invalid response",
416: .type = OPTION_FLAG,
417: .opt.flag = &ocsp_config.ignore_err,
418: },
419: {
420: .name = "index",
421: .argname = "indexfile",
422: .desc = "Certificate status index file",
423: .type = OPTION_ARG,
424: .opt.arg = &ocsp_config.ridx_filename,
425: },
426: {
427: .name = "issuer",
428: .argname = "file",
429: .desc = "Issuer certificate",
430: .type = OPTION_ARG_FUNC,
431: .opt.argfunc = ocsp_opt_issuer,
432: },
433: {
434: .name = "ndays",
435: .argname = "days",
436: .desc = "Number of days before next update",
437: .type = OPTION_ARG_FUNC,
438: .opt.argfunc = ocsp_opt_ndays,
439: },
440: {
441: .name = "nmin",
442: .argname = "minutes",
443: .desc = "Number of minutes before next update",
444: .type = OPTION_ARG_FUNC,
445: .opt.argfunc = ocsp_opt_nmin,
446: },
447: {
448: .name = "no_cert_checks",
449: .desc = "Don't do additional checks on signing certificate",
450: .type = OPTION_UL_VALUE_OR,
451: .opt.ulvalue = &ocsp_config.verify_flags,
452: .ulvalue = OCSP_NOCHECKS,
453: },
454: {
455: .name = "no_cert_verify",
456: .desc = "Don't check signing certificate",
457: .type = OPTION_UL_VALUE_OR,
458: .opt.ulvalue = &ocsp_config.verify_flags,
459: .ulvalue = OCSP_NOVERIFY,
460: },
461: {
462: .name = "no_certs",
463: .desc = "Don't include any certificates in signed request",
464: .type = OPTION_UL_VALUE_OR,
465: .opt.ulvalue = &ocsp_config.sign_flags,
466: .ulvalue = OCSP_NOCERTS,
467: },
468: {
469: .name = "no_chain",
470: .desc = "Don't use certificates in the response",
471: .type = OPTION_UL_VALUE_OR,
472: .opt.ulvalue = &ocsp_config.verify_flags,
473: .ulvalue = OCSP_NOCHAIN,
474: },
475: {
476: .name = "no_explicit",
477: .desc = "Don't check the explicit trust for OCSP signing",
478: .type = OPTION_UL_VALUE_OR,
479: .opt.ulvalue = &ocsp_config.verify_flags,
480: .ulvalue = OCSP_NOEXPLICIT,
481: },
482: {
483: .name = "no_intern",
484: .desc = "Don't search certificates contained in response for signer",
485: .type = OPTION_UL_VALUE_OR,
486: .opt.ulvalue = &ocsp_config.verify_flags,
487: .ulvalue = OCSP_NOINTERN,
488: },
489: {
490: .name = "no_nonce",
491: .desc = "Don't add OCSP nonce to request",
492: .type = OPTION_VALUE,
493: .opt.value = &ocsp_config.add_nonce,
494: .value = 0,
495: },
496: {
497: .name = "no_signature_verify",
498: .desc = "Don't check signature on response",
499: .type = OPTION_UL_VALUE_OR,
500: .opt.ulvalue = &ocsp_config.verify_flags,
501: .ulvalue = OCSP_NOSIGS,
502: },
503: {
504: .name = "nonce",
505: .desc = "Add OCSP nonce to request",
506: .type = OPTION_VALUE,
507: .opt.value = &ocsp_config.add_nonce,
508: .value = 2,
509: },
510: {
511: .name = "noverify",
512: .desc = "Don't verify response at all",
513: .type = OPTION_FLAG,
514: .opt.flag = &ocsp_config.noverify,
515: },
516: {
517: .name = "nrequest",
518: .argname = "number",
519: .desc = "Number of requests to accept (default unlimited)",
520: .type = OPTION_ARG_FUNC,
521: .opt.argfunc = ocsp_opt_nrequest,
522: },
523: {
524: .name = "out",
525: .argname = "file",
526: .desc = "Output filename",
527: .type = OPTION_ARG,
528: .opt.arg = &ocsp_config.outfile,
529: },
530: {
531: .name = "path",
532: .argname = "path",
533: .desc = "Path to use in OCSP request",
534: .type = OPTION_ARG,
535: .opt.arg = &ocsp_config.path,
536: },
537: {
538: .name = "port",
539: .argname = "portnum",
540: .desc = "Port to run responder on",
541: .type = OPTION_ARG_FUNC,
542: .opt.argfunc = ocsp_opt_port,
543: },
544: {
545: .name = "req_text",
546: .desc = "Print text form of request",
547: .type = OPTION_FLAG,
548: .opt.flag = &ocsp_config.req_text,
549: },
550: {
551: .name = "reqin",
552: .argname = "file",
553: .desc = "Read DER encoded OCSP request from \"file\"",
554: .type = OPTION_ARG,
555: .opt.arg = &ocsp_config.reqin,
556: },
557: {
558: .name = "reqout",
559: .argname = "file",
560: .desc = "Write DER encoded OCSP request to \"file\"",
561: .type = OPTION_ARG,
562: .opt.arg = &ocsp_config.reqout,
563: },
564: {
565: .name = "resp_key_id",
566: .desc = "Identify response by signing certificate key ID",
567: .type = OPTION_UL_VALUE_OR,
568: .opt.ulvalue = &ocsp_config.rflags,
569: .ulvalue = OCSP_RESPID_KEY,
570: },
571: {
572: .name = "resp_no_certs",
573: .desc = "Don't include any certificates in response",
574: .type = OPTION_UL_VALUE_OR,
575: .opt.ulvalue = &ocsp_config.rflags,
576: .ulvalue = OCSP_NOCERTS,
577: },
578: {
579: .name = "resp_text",
580: .desc = "Print text form of response",
581: .type = OPTION_FLAG,
582: .opt.flag = &ocsp_config.resp_text,
583: },
584: {
585: .name = "respin",
586: .argname = "file",
587: .desc = "Read DER encoded OCSP response from \"file\"",
588: .type = OPTION_ARG,
589: .opt.arg = &ocsp_config.respin,
590: },
591: {
592: .name = "respout",
593: .argname = "file",
594: .desc = "Write DER encoded OCSP response to \"file\"",
595: .type = OPTION_ARG,
596: .opt.arg = &ocsp_config.respout,
597: },
598: {
599: .name = "rkey",
600: .argname = "file",
601: .desc = "Responder key to sign responses with",
602: .type = OPTION_ARG,
603: .opt.arg = &ocsp_config.rkeyfile,
604: },
605: {
606: .name = "rother",
607: .argname = "file",
608: .desc = "Other certificates to include in response",
609: .type = OPTION_ARG,
610: .opt.arg = &ocsp_config.rcertfile,
611: },
612: {
613: .name = "rsigner",
614: .argname = "file",
615: .desc = "Responder certificate to sign responses with",
616: .type = OPTION_ARG,
617: .opt.arg = &ocsp_config.rsignfile,
618: },
619: {
620: .name = "serial",
621: .argname = "num",
622: .desc = "Serial number to check",
623: .type = OPTION_ARG_FUNC,
624: .opt.argfunc = ocsp_opt_serial,
625: },
626: {
627: .name = "sign_other",
628: .argname = "file",
629: .desc = "Additional certificates to include in signed request",
630: .type = OPTION_ARG,
631: .opt.arg = &ocsp_config.sign_certfile,
632: },
633: {
634: .name = "signer",
635: .argname = "file",
636: .desc = "Certificate to sign OCSP request with",
637: .type = OPTION_ARG,
638: .opt.arg = &ocsp_config.signfile,
639: },
640: {
641: .name = "signkey",
642: .argname = "file",
643: .desc = "Private key to sign OCSP request with",
644: .type = OPTION_ARG,
645: .opt.arg = &ocsp_config.keyfile,
646: },
647: {
648: .name = "status_age",
649: .argname = "age",
650: .desc = "Maximum status age in seconds",
651: .type = OPTION_ARG_FUNC,
652: .opt.argfunc = ocsp_opt_status_age,
653: },
654: {
655: .name = "text",
656: .desc = "Print text form of request and response",
657: .type = OPTION_FUNC,
658: .opt.func = ocsp_opt_text,
659: },
660: {
661: .name = "timeout",
662: .argname = "seconds",
663: .desc = "Connection timeout to the OCSP responder in seconds",
664: .type = OPTION_ARG_FUNC,
665: .opt.argfunc = ocsp_opt_timeout,
666: },
667: {
668: .name = "trust_other",
669: .desc = "Don't verify additional certificates",
670: .type = OPTION_UL_VALUE_OR,
671: .opt.ulvalue = &ocsp_config.verify_flags,
672: .ulvalue = OCSP_TRUSTOTHER,
673: },
674: {
675: .name = "url",
676: .argname = "responder_url",
677: .desc = "OCSP responder URL",
678: .type = OPTION_ARG_FUNC,
679: .opt.argfunc = ocsp_opt_url,
680: },
681: {
682: .name = "VAfile",
683: .argname = "file",
684: .desc = "Explicitly trusted responder certificates",
685: .type = OPTION_ARG_FUNC,
686: .opt.argfunc = ocsp_opt_vafile,
687: },
688: {
689: .name = "validity_period",
690: .argname = "n",
691: .desc = "Maximum validity discrepancy in seconds",
692: .type = OPTION_ARG_FUNC,
693: .opt.argfunc = ocsp_opt_validity_period,
694: },
695: {
696: .name = "verify_other",
697: .argname = "file",
698: .desc = "Additional certificates to search for signer",
699: .type = OPTION_ARG,
700: .opt.arg = &ocsp_config.verify_certfile,
701: },
702: {
703: .name = NULL,
704: .desc = "",
705: .type = OPTION_ARGV_FUNC,
706: .opt.argvfunc = ocsp_opt_cert_id_md,
707: },
708: { NULL },
709: };
710:
711: static void
712: ocsp_usage(void)
713: {
714: fprintf(stderr, "usage: ocsp "
715: "[-CA file] [-CAfile file] [-CApath directory] [-cert file]\n"
716: " [-dgst alg] [-header name value] [-host hostname:port]\n"
717: " [-ignore_err] [-index indexfile] [-issuer file]\n"
718: " [-ndays days] [-nmin minutes] [-no_cert_checks]\n"
719: " [-no_cert_verify] [-no_certs] [-no_chain] [-no_explicit]\n"
720: " [-no_intern] [-no_nonce] [-no_signature_verify] [-nonce]\n"
721: " [-noverify] [-nrequest number] [-out file] [-path path]\n"
722: " [-port portnum] [-req_text] [-reqin file] [-reqout file]\n"
723: " [-resp_key_id] [-resp_no_certs] [-resp_text] [-respin file]\n"
724: " [-respout file] [-rkey file] [-rother file] [-rsigner file]\n"
725: " [-serial num] [-sign_other file] [-signer file]\n"
726: " [-signkey file] [-status_age age] [-text]\n"
727: " [-timeout seconds] [-trust_other] [-url responder_url]\n"
728: " [-VAfile file] [-validity_period nsec] [-verify_other file]\n");
729: fprintf(stderr, "\n");
730: options_usage(ocsp_options);
731: fprintf(stderr, "\n");
732: }
733:
1.1 jsing 734: int
735: ocsp_main(int argc, char **argv)
736: {
737: OCSP_RESPONSE *resp = NULL;
738: OCSP_BASICRESP *bs = NULL;
739: X509 *signer = NULL, *rsigner = NULL;
740: EVP_PKEY *key = NULL, *rkey = NULL;
741: BIO *acbio = NULL, *cbio = NULL;
742: BIO *derbio = NULL;
743: BIO *out = NULL;
744: X509_STORE *store = NULL;
1.17 inoguchi 745: STACK_OF(X509) *sign_other = NULL, *verify_other = NULL, *rother = NULL;
1.1 jsing 746: int ret = 1;
747: int badarg = 0;
748: int i;
749: X509 *rca_cert = NULL;
750: CA_DB *rdb = NULL;
1.6 doug 751:
752: if (single_execution) {
1.11 deraadt 753: if (pledge("stdio cpath wpath rpath inet dns tty", NULL) == -1) {
1.6 doug 754: perror("pledge");
1.7 doug 755: exit(1);
756: }
1.6 doug 757: }
1.1 jsing 758:
1.16 inoguchi 759: memset(&ocsp_config, 0, sizeof(ocsp_config));
760: ocsp_config.accept_count = -1;
761: ocsp_config.add_nonce = 1;
762: if ((ocsp_config.ids = sk_OCSP_CERTID_new_null()) == NULL)
763: goto end;
764: ocsp_config.maxage = -1;
765: ocsp_config.ndays = -1;
766: ocsp_config.nsec = MAX_VALIDITY_PERIOD;
767: ocsp_config.req_timeout = -1;
768: if ((ocsp_config.reqnames = sk_OPENSSL_STRING_new_null()) == NULL)
769: goto end;
770: ocsp_config.use_ssl = -1;
771:
772: if (options_parse(argc, argv, ocsp_options, NULL, NULL) != 0) {
773: if (ocsp_config.no_usage)
774: goto end;
775: else
1.1 jsing 776: badarg = 1;
777: }
778:
779: /* Have we anything to do? */
1.19 ! inoguchi 780: if (!ocsp_config.req && !ocsp_config.reqin && !ocsp_config.respin &&
! 781: !(ocsp_config.port && ocsp_config.ridx_filename))
1.1 jsing 782: badarg = 1;
783:
784: if (badarg) {
1.16 inoguchi 785: ocsp_usage();
1.1 jsing 786: goto end;
787: }
1.16 inoguchi 788: if (ocsp_config.outfile)
789: out = BIO_new_file(ocsp_config.outfile, "w");
1.1 jsing 790: else
791: out = BIO_new_fp(stdout, BIO_NOCLOSE);
792:
793: if (!out) {
794: BIO_printf(bio_err, "Error opening output file\n");
795: goto end;
796: }
1.16 inoguchi 797: if (!ocsp_config.req && (ocsp_config.add_nonce != 2))
798: ocsp_config.add_nonce = 0;
1.1 jsing 799:
1.16 inoguchi 800: if (!ocsp_config.req && ocsp_config.reqin) {
801: derbio = BIO_new_file(ocsp_config.reqin, "rb");
1.1 jsing 802: if (!derbio) {
1.19 ! inoguchi 803: BIO_printf(bio_err,
! 804: "Error Opening OCSP request file\n");
1.1 jsing 805: goto end;
806: }
1.16 inoguchi 807: ocsp_config.req = d2i_OCSP_REQUEST_bio(derbio, NULL);
1.1 jsing 808: BIO_free(derbio);
1.16 inoguchi 809: if (!ocsp_config.req) {
1.1 jsing 810: BIO_printf(bio_err, "Error reading OCSP request\n");
811: goto end;
812: }
813: }
1.16 inoguchi 814: if (!ocsp_config.req && ocsp_config.port) {
815: acbio = init_responder(ocsp_config.port);
1.1 jsing 816: if (!acbio)
817: goto end;
818: }
1.16 inoguchi 819: if (ocsp_config.rsignfile && !rdb) {
820: if (!ocsp_config.rkeyfile)
821: ocsp_config.rkeyfile = ocsp_config.rsignfile;
822: rsigner = load_cert(bio_err, ocsp_config.rsignfile, FORMAT_PEM,
1.4 bcook 823: NULL, "responder certificate");
1.1 jsing 824: if (!rsigner) {
1.19 ! inoguchi 825: BIO_printf(bio_err,
! 826: "Error loading responder certificate\n");
1.1 jsing 827: goto end;
828: }
1.19 ! inoguchi 829: rca_cert = load_cert(bio_err, ocsp_config.rca_filename,
! 830: FORMAT_PEM, NULL, "CA certificate");
1.16 inoguchi 831: if (ocsp_config.rcertfile) {
1.19 ! inoguchi 832: rother = load_certs(bio_err, ocsp_config.rcertfile,
! 833: FORMAT_PEM, NULL, "responder other certificates");
1.1 jsing 834: if (!rother)
835: goto end;
836: }
1.19 ! inoguchi 837: rkey = load_key(bio_err, ocsp_config.rkeyfile, FORMAT_PEM, 0,
! 838: NULL, "responder private key");
1.1 jsing 839: if (!rkey)
840: goto end;
841: }
842: if (acbio)
843: BIO_printf(bio_err, "Waiting for OCSP client connections...\n");
844:
1.19 ! inoguchi 845: redo_accept:
1.1 jsing 846:
847: if (acbio) {
1.19 ! inoguchi 848: if (!do_responder(&ocsp_config.req, &cbio, acbio,
! 849: ocsp_config.port))
1.1 jsing 850: goto end;
1.16 inoguchi 851: if (!ocsp_config.req) {
1.19 ! inoguchi 852: resp = OCSP_response_create(
! 853: OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, NULL);
1.1 jsing 854: send_ocsp_response(cbio, resp);
855: goto done_resp;
856: }
857: }
1.19 ! inoguchi 858: if (!ocsp_config.req &&
! 859: (ocsp_config.signfile || ocsp_config.reqout || ocsp_config.host ||
! 860: ocsp_config.add_nonce || ocsp_config.ridx_filename)) {
! 861: BIO_printf(bio_err,
! 862: "Need an OCSP request for this operation!\n");
1.1 jsing 863: goto end;
864: }
1.16 inoguchi 865: if (ocsp_config.req && ocsp_config.add_nonce)
866: OCSP_request_add1_nonce(ocsp_config.req, NULL, -1);
1.1 jsing 867:
1.16 inoguchi 868: if (ocsp_config.signfile) {
869: if (!ocsp_config.keyfile)
870: ocsp_config.keyfile = ocsp_config.signfile;
871: signer = load_cert(bio_err, ocsp_config.signfile, FORMAT_PEM,
1.4 bcook 872: NULL, "signer certificate");
1.1 jsing 873: if (!signer) {
1.19 ! inoguchi 874: BIO_printf(bio_err,
! 875: "Error loading signer certificate\n");
1.1 jsing 876: goto end;
877: }
1.16 inoguchi 878: if (ocsp_config.sign_certfile) {
1.19 ! inoguchi 879: sign_other = load_certs(bio_err,
! 880: ocsp_config.sign_certfile, FORMAT_PEM, NULL,
! 881: "signer certificates");
1.1 jsing 882: if (!sign_other)
883: goto end;
884: }
1.19 ! inoguchi 885: key = load_key(bio_err, ocsp_config.keyfile, FORMAT_PEM, 0,
! 886: NULL, "signer private key");
1.1 jsing 887: if (!key)
888: goto end;
889:
1.19 ! inoguchi 890: if (!OCSP_request_sign(ocsp_config.req, signer, key, NULL,
! 891: sign_other, ocsp_config.sign_flags)) {
1.1 jsing 892: BIO_printf(bio_err, "Error signing OCSP request\n");
893: goto end;
894: }
895: }
1.16 inoguchi 896: if (ocsp_config.req_text && ocsp_config.req)
897: OCSP_REQUEST_print(out, ocsp_config.req, 0);
1.1 jsing 898:
1.16 inoguchi 899: if (ocsp_config.reqout) {
900: derbio = BIO_new_file(ocsp_config.reqout, "wb");
1.1 jsing 901: if (!derbio) {
1.19 ! inoguchi 902: BIO_printf(bio_err, "Error opening file %s\n",
! 903: ocsp_config.reqout);
1.1 jsing 904: goto end;
905: }
1.16 inoguchi 906: i2d_OCSP_REQUEST_bio(derbio, ocsp_config.req);
1.1 jsing 907: BIO_free(derbio);
908: }
1.16 inoguchi 909: if (ocsp_config.ridx_filename && (!rkey || !rsigner || !rca_cert)) {
1.19 ! inoguchi 910: BIO_printf(bio_err,
! 911: "Need a responder certificate, key and CA for this operation!\n");
1.1 jsing 912: goto end;
913: }
1.16 inoguchi 914: if (ocsp_config.ridx_filename && !rdb) {
915: rdb = load_index(ocsp_config.ridx_filename, NULL);
1.1 jsing 916: if (!rdb)
917: goto end;
918: if (!index_index(rdb))
919: goto end;
920: }
921: if (rdb) {
1.19 ! inoguchi 922: i = make_ocsp_response(&resp, ocsp_config.req, rdb, rca_cert,
! 923: rsigner, rkey, rother, ocsp_config.rflags,
! 924: ocsp_config.nmin, ocsp_config.ndays);
1.1 jsing 925: if (cbio)
926: send_ocsp_response(cbio, resp);
1.16 inoguchi 927: } else if (ocsp_config.host) {
1.19 ! inoguchi 928: resp = process_responder(bio_err, ocsp_config.req,
! 929: ocsp_config.host,
! 930: ocsp_config.path ? ocsp_config.path : "/",
! 931: ocsp_config.port, ocsp_config.use_ssl, ocsp_config.headers,
! 932: ocsp_config.req_timeout);
1.1 jsing 933: if (!resp)
934: goto end;
1.16 inoguchi 935: } else if (ocsp_config.respin) {
936: derbio = BIO_new_file(ocsp_config.respin, "rb");
1.1 jsing 937: if (!derbio) {
1.19 ! inoguchi 938: BIO_printf(bio_err,
! 939: "Error Opening OCSP response file\n");
1.1 jsing 940: goto end;
941: }
942: resp = d2i_OCSP_RESPONSE_bio(derbio, NULL);
943: BIO_free(derbio);
944: if (!resp) {
945: BIO_printf(bio_err, "Error reading OCSP response\n");
946: goto end;
947: }
948: } else {
949: ret = 0;
950: goto end;
951: }
952:
1.19 ! inoguchi 953: done_resp:
1.1 jsing 954:
1.16 inoguchi 955: if (ocsp_config.respout) {
956: derbio = BIO_new_file(ocsp_config.respout, "wb");
1.1 jsing 957: if (!derbio) {
1.19 ! inoguchi 958: BIO_printf(bio_err, "Error opening file %s\n",
! 959: ocsp_config.respout);
1.1 jsing 960: goto end;
961: }
962: i2d_OCSP_RESPONSE_bio(derbio, resp);
963: BIO_free(derbio);
964: }
965: i = OCSP_response_status(resp);
966:
967: if (i != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
1.9 beck 968: BIO_printf(bio_err, "Responder Error: %s (%d)\n",
1.1 jsing 969: OCSP_response_status_str(i), i);
1.16 inoguchi 970: if (ocsp_config.ignore_err)
1.1 jsing 971: goto redo_accept;
1.9 beck 972: ret = 1;
1.1 jsing 973: goto end;
974: }
1.16 inoguchi 975: if (ocsp_config.resp_text)
1.1 jsing 976: OCSP_RESPONSE_print(out, resp, 0);
977:
978: /* If running as responder don't verify our own response */
979: if (cbio) {
1.16 inoguchi 980: if (ocsp_config.accept_count > 0)
981: ocsp_config.accept_count--;
1.1 jsing 982: /* Redo if more connections needed */
1.16 inoguchi 983: if (ocsp_config.accept_count) {
1.1 jsing 984: BIO_free_all(cbio);
985: cbio = NULL;
1.16 inoguchi 986: OCSP_REQUEST_free(ocsp_config.req);
987: ocsp_config.req = NULL;
1.1 jsing 988: OCSP_RESPONSE_free(resp);
989: resp = NULL;
990: goto redo_accept;
991: }
992: goto end;
993: }
994: if (!store)
1.19 ! inoguchi 995: store = setup_verify(bio_err, ocsp_config.CAfile,
! 996: ocsp_config.CApath);
1.1 jsing 997: if (!store)
998: goto end;
1.16 inoguchi 999: if (ocsp_config.verify_certfile) {
1.19 ! inoguchi 1000: verify_other = load_certs(bio_err, ocsp_config.verify_certfile,
! 1001: FORMAT_PEM, NULL, "validator certificate");
1.1 jsing 1002: if (!verify_other)
1003: goto end;
1004: }
1005: bs = OCSP_response_get1_basic(resp);
1006:
1007: if (!bs) {
1008: BIO_printf(bio_err, "Error parsing response\n");
1009: goto end;
1010: }
1.16 inoguchi 1011: if (!ocsp_config.noverify) {
1.19 ! inoguchi 1012: if (ocsp_config.req &&
! 1013: ((i = OCSP_check_nonce(ocsp_config.req, bs)) <= 0)) {
! 1014: if (i == -1) {
! 1015: BIO_printf(bio_err,
! 1016: "WARNING: no nonce in response\n");
! 1017: } else {
1.1 jsing 1018: BIO_printf(bio_err, "Nonce Verify error\n");
1019: goto end;
1020: }
1021: }
1.19 ! inoguchi 1022: i = OCSP_basic_verify(bs, verify_other, store,
! 1023: ocsp_config.verify_flags);
1.1 jsing 1024: if (i < 0)
1025: i = OCSP_basic_verify(bs, NULL, store, 0);
1026:
1027: if (i <= 0) {
1028: BIO_printf(bio_err, "Response Verify Failure\n");
1029: ERR_print_errors(bio_err);
1.19 ! inoguchi 1030: } else {
1.1 jsing 1031: BIO_printf(bio_err, "Response verify OK\n");
1.19 ! inoguchi 1032: }
1.1 jsing 1033: }
1.19 ! inoguchi 1034: if (!print_ocsp_summary(out, bs, ocsp_config.req, ocsp_config.reqnames,
! 1035: ocsp_config.ids, ocsp_config.nsec, ocsp_config.maxage))
1.1 jsing 1036: goto end;
1037:
1038: ret = 0;
1039:
1.14 jsing 1040: end:
1.1 jsing 1041: ERR_print_errors(bio_err);
1042: X509_free(signer);
1043: X509_STORE_free(store);
1044: EVP_PKEY_free(key);
1045: EVP_PKEY_free(rkey);
1.16 inoguchi 1046: X509_free(ocsp_config.issuer);
1047: X509_free(ocsp_config.cert);
1.1 jsing 1048: X509_free(rsigner);
1049: X509_free(rca_cert);
1050: free_index(rdb);
1051: BIO_free_all(cbio);
1052: BIO_free_all(acbio);
1053: BIO_free(out);
1.16 inoguchi 1054: OCSP_REQUEST_free(ocsp_config.req);
1.1 jsing 1055: OCSP_RESPONSE_free(resp);
1056: OCSP_BASICRESP_free(bs);
1.16 inoguchi 1057: sk_OPENSSL_STRING_free(ocsp_config.reqnames);
1058: sk_OCSP_CERTID_free(ocsp_config.ids);
1.1 jsing 1059: sk_X509_pop_free(sign_other, X509_free);
1060: sk_X509_pop_free(verify_other, X509_free);
1.16 inoguchi 1061: sk_CONF_VALUE_pop_free(ocsp_config.headers, X509V3_conf_free);
1.1 jsing 1062:
1.16 inoguchi 1063: if (ocsp_config.use_ssl != -1) {
1064: free(ocsp_config.host);
1065: free(ocsp_config.port);
1066: free(ocsp_config.path);
1.1 jsing 1067: }
1068: return (ret);
1069: }
1070:
1071: static int
1.19 ! inoguchi 1072: add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, const EVP_MD *cert_id_md,
! 1073: X509 *issuer, STACK_OF(OCSP_CERTID) *ids)
1.1 jsing 1074: {
1075: OCSP_CERTID *id;
1.19 ! inoguchi 1076:
1.1 jsing 1077: if (!issuer) {
1078: BIO_printf(bio_err, "No issuer certificate specified\n");
1079: return 0;
1080: }
1081: if (!*req)
1082: *req = OCSP_REQUEST_new();
1083: if (!*req)
1084: goto err;
1085: id = OCSP_cert_to_id(cert_id_md, cert, issuer);
1086: if (!id || !sk_OCSP_CERTID_push(ids, id))
1087: goto err;
1088: if (!OCSP_request_add0_id(*req, id))
1089: goto err;
1090: return 1;
1091:
1.14 jsing 1092: err:
1.1 jsing 1093: BIO_printf(bio_err, "Error Creating OCSP request\n");
1094: return 0;
1095: }
1096:
1097: static int
1.19 ! inoguchi 1098: add_ocsp_serial(OCSP_REQUEST **req, char *serial, const EVP_MD *cert_id_md,
! 1099: X509 *issuer, STACK_OF(OCSP_CERTID) *ids)
1.1 jsing 1100: {
1101: OCSP_CERTID *id;
1102: X509_NAME *iname;
1103: ASN1_BIT_STRING *ikey;
1104: ASN1_INTEGER *sno;
1.19 ! inoguchi 1105:
1.1 jsing 1106: if (!issuer) {
1107: BIO_printf(bio_err, "No issuer certificate specified\n");
1108: return 0;
1109: }
1110: if (!*req)
1111: *req = OCSP_REQUEST_new();
1112: if (!*req)
1113: goto err;
1114: iname = X509_get_subject_name(issuer);
1115: ikey = X509_get0_pubkey_bitstr(issuer);
1116: sno = s2i_ASN1_INTEGER(NULL, serial);
1117: if (!sno) {
1.19 ! inoguchi 1118: BIO_printf(bio_err, "Error converting serial number %s\n",
! 1119: serial);
1.1 jsing 1120: return 0;
1121: }
1122: id = OCSP_cert_id_new(cert_id_md, iname, ikey, sno);
1123: ASN1_INTEGER_free(sno);
1124: if (!id || !sk_OCSP_CERTID_push(ids, id))
1125: goto err;
1126: if (!OCSP_request_add0_id(*req, id))
1127: goto err;
1128: return 1;
1129:
1.14 jsing 1130: err:
1.1 jsing 1131: BIO_printf(bio_err, "Error Creating OCSP request\n");
1132: return 0;
1133: }
1134:
1135: static int
1.17 inoguchi 1136: print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req,
1.19 ! inoguchi 1137: STACK_OF(OPENSSL_STRING) *names, STACK_OF(OCSP_CERTID) *ids, long nsec,
1.1 jsing 1138: long maxage)
1139: {
1140: OCSP_CERTID *id;
1141: char *name;
1142: int i;
1143: int status, reason;
1144:
1145: ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
1146:
1.19 ! inoguchi 1147: if (!bs || !req || !sk_OPENSSL_STRING_num(names) ||
! 1148: !sk_OCSP_CERTID_num(ids))
1.1 jsing 1149: return 1;
1150:
1151: for (i = 0; i < sk_OCSP_CERTID_num(ids); i++) {
1152: id = sk_OCSP_CERTID_value(ids, i);
1153: name = sk_OPENSSL_STRING_value(names, i);
1154: BIO_printf(out, "%s: ", name);
1155:
1156: if (!OCSP_resp_find_status(bs, id, &status, &reason,
1157: &rev, &thisupd, &nextupd)) {
1158: BIO_puts(out, "ERROR: No Status found.\n");
1159: continue;
1160: }
1161: /*
1162: * Check validity: if invalid write to output BIO so we know
1163: * which response this refers to.
1164: */
1165: if (!OCSP_check_validity(thisupd, nextupd, nsec, maxage)) {
1166: BIO_puts(out, "WARNING: Status times invalid.\n");
1167: ERR_print_errors(out);
1168: }
1169: BIO_printf(out, "%s\n", OCSP_cert_status_str(status));
1170:
1171: BIO_puts(out, "\tThis Update: ");
1172: ASN1_GENERALIZEDTIME_print(out, thisupd);
1173: BIO_puts(out, "\n");
1174:
1175: if (nextupd) {
1176: BIO_puts(out, "\tNext Update: ");
1177: ASN1_GENERALIZEDTIME_print(out, nextupd);
1178: BIO_puts(out, "\n");
1179: }
1180: if (status != V_OCSP_CERTSTATUS_REVOKED)
1181: continue;
1182:
1183: if (reason != -1)
1184: BIO_printf(out, "\tReason: %s\n",
1185: OCSP_crl_reason_str(reason));
1186:
1187: BIO_puts(out, "\tRevocation Time: ");
1188: ASN1_GENERALIZEDTIME_print(out, rev);
1189: BIO_puts(out, "\n");
1190: }
1191:
1192: return 1;
1193: }
1194:
1195:
1196: static int
1.17 inoguchi 1197: make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req, CA_DB *db,
1.19 ! inoguchi 1198: X509 *ca, X509 *rcert, EVP_PKEY *rkey, STACK_OF(X509) *rother,
! 1199: unsigned long flags, int nmin, int ndays)
1.1 jsing 1200: {
1201: ASN1_TIME *thisupd = NULL, *nextupd = NULL;
1202: OCSP_CERTID *cid, *ca_id = NULL;
1203: OCSP_BASICRESP *bs = NULL;
1204: int i, id_count, ret = 1;
1205:
1206: id_count = OCSP_request_onereq_count(req);
1207:
1208: if (id_count <= 0) {
1.19 ! inoguchi 1209: *resp = OCSP_response_create(
! 1210: OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, NULL);
1.1 jsing 1211: goto end;
1212: }
1213: bs = OCSP_BASICRESP_new();
1214: thisupd = X509_gmtime_adj(NULL, 0);
1215: if (ndays != -1)
1216: nextupd = X509_gmtime_adj(NULL, nmin * 60 + ndays * 3600 * 24);
1217:
1218: /* Examine each certificate id in the request */
1219: for (i = 0; i < id_count; i++) {
1220: OCSP_ONEREQ *one;
1221: ASN1_INTEGER *serial;
1222: char **inf;
1223: ASN1_OBJECT *cert_id_md_oid;
1224: const EVP_MD *cert_id_md;
1225: one = OCSP_request_onereq_get0(req, i);
1226: cid = OCSP_onereq_get0_id(one);
1227:
1228: OCSP_id_get0_info(NULL, &cert_id_md_oid, NULL, NULL, cid);
1229:
1230: cert_id_md = EVP_get_digestbyobj(cert_id_md_oid);
1231: if (!cert_id_md) {
1.19 ! inoguchi 1232: *resp = OCSP_response_create(
! 1233: OCSP_RESPONSE_STATUS_INTERNALERROR, NULL);
1.1 jsing 1234: goto end;
1235: }
1.15 jsing 1236: OCSP_CERTID_free(ca_id);
1.1 jsing 1237: ca_id = OCSP_cert_to_id(cert_id_md, NULL, ca);
1238:
1239: /* Is this request about our CA? */
1240: if (OCSP_id_issuer_cmp(ca_id, cid)) {
1241: OCSP_basic_add1_status(bs, cid,
1.19 ! inoguchi 1242: V_OCSP_CERTSTATUS_UNKNOWN, 0, NULL,
1.1 jsing 1243: thisupd, nextupd);
1244: continue;
1245: }
1246: OCSP_id_get0_info(NULL, NULL, NULL, &serial, cid);
1247: inf = lookup_serial(db, serial);
1.19 ! inoguchi 1248: if (!inf) {
1.1 jsing 1249: OCSP_basic_add1_status(bs, cid,
1.19 ! inoguchi 1250: V_OCSP_CERTSTATUS_UNKNOWN, 0, NULL,
1.1 jsing 1251: thisupd, nextupd);
1.19 ! inoguchi 1252: } else if (inf[DB_type][0] == DB_TYPE_VAL) {
1.1 jsing 1253: OCSP_basic_add1_status(bs, cid,
1.19 ! inoguchi 1254: V_OCSP_CERTSTATUS_GOOD, 0, NULL,
1.1 jsing 1255: thisupd, nextupd);
1.19 ! inoguchi 1256: } else if (inf[DB_type][0] == DB_TYPE_REV) {
1.1 jsing 1257: ASN1_OBJECT *inst = NULL;
1258: ASN1_TIME *revtm = NULL;
1259: ASN1_GENERALIZEDTIME *invtm = NULL;
1260: OCSP_SINGLERESP *single;
1261: int reason = -1;
1.19 ! inoguchi 1262:
! 1263: unpack_revinfo(&revtm, &reason, &inst, &invtm,
! 1264: inf[DB_rev_date]);
1.1 jsing 1265: single = OCSP_basic_add1_status(bs, cid,
1266: V_OCSP_CERTSTATUS_REVOKED,
1267: reason, revtm,
1268: thisupd, nextupd);
1269: if (invtm)
1.19 ! inoguchi 1270: OCSP_SINGLERESP_add1_ext_i2d(single,
! 1271: NID_invalidity_date, invtm, 0, 0);
1.1 jsing 1272: else if (inst)
1.19 ! inoguchi 1273: OCSP_SINGLERESP_add1_ext_i2d(single,
! 1274: NID_hold_instruction_code, inst, 0, 0);
1.1 jsing 1275: ASN1_OBJECT_free(inst);
1276: ASN1_TIME_free(revtm);
1277: ASN1_GENERALIZEDTIME_free(invtm);
1278: }
1279: }
1280:
1281: OCSP_copy_nonce(bs, req);
1282:
1283: OCSP_basic_sign(bs, rcert, rkey, NULL, rother, flags);
1284:
1285: *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_SUCCESSFUL, bs);
1286:
1.14 jsing 1287: end:
1.1 jsing 1288: ASN1_TIME_free(thisupd);
1289: ASN1_TIME_free(nextupd);
1290: OCSP_CERTID_free(ca_id);
1291: OCSP_BASICRESP_free(bs);
1292: return ret;
1293: }
1294:
1295: static char **
1.17 inoguchi 1296: lookup_serial(CA_DB *db, ASN1_INTEGER *ser)
1.1 jsing 1297: {
1298: int i;
1299: BIGNUM *bn = NULL;
1300: char *itmp, *row[DB_NUMBER], **rrow;
1.19 ! inoguchi 1301:
1.1 jsing 1302: for (i = 0; i < DB_NUMBER; i++)
1303: row[i] = NULL;
1304: bn = ASN1_INTEGER_to_BN(ser, NULL);
1305: OPENSSL_assert(bn); /* FIXME: should report an error at this
1306: * point and abort */
1307: if (BN_is_zero(bn))
1308: itmp = strdup("00");
1309: else
1310: itmp = BN_bn2hex(bn);
1311: row[DB_serial] = itmp;
1312: BN_free(bn);
1313: rrow = TXT_DB_get_by_index(db->db, DB_serial, row);
1314: free(itmp);
1315: return rrow;
1316: }
1317:
1318: /* Quick and dirty OCSP server: read in and parse input request */
1319:
1320: static BIO *
1321: init_responder(char *port)
1322: {
1323: BIO *acbio = NULL, *bufbio = NULL;
1.19 ! inoguchi 1324:
1.1 jsing 1325: bufbio = BIO_new(BIO_f_buffer());
1326: if (!bufbio)
1327: goto err;
1328: acbio = BIO_new_accept(port);
1329: if (!acbio)
1330: goto err;
1331: BIO_set_accept_bios(acbio, bufbio);
1332: bufbio = NULL;
1333:
1334: if (BIO_do_accept(acbio) <= 0) {
1335: BIO_printf(bio_err, "Error setting up accept BIO\n");
1336: ERR_print_errors(bio_err);
1337: goto err;
1338: }
1339: return acbio;
1340:
1.14 jsing 1341: err:
1.1 jsing 1342: BIO_free_all(acbio);
1343: BIO_free(bufbio);
1344: return NULL;
1345: }
1346:
1347: static int
1.17 inoguchi 1348: do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, char *port)
1.1 jsing 1349: {
1350: int have_post = 0, len;
1351: OCSP_REQUEST *req = NULL;
1352: char inbuf[1024];
1353: BIO *cbio = NULL;
1354:
1355: if (BIO_do_accept(acbio) <= 0) {
1356: BIO_printf(bio_err, "Error accepting connection\n");
1357: ERR_print_errors(bio_err);
1358: return 0;
1359: }
1360: cbio = BIO_pop(acbio);
1361: *pcbio = cbio;
1362:
1363: for (;;) {
1364: len = BIO_gets(cbio, inbuf, sizeof inbuf);
1365: if (len <= 0)
1366: return 1;
1367: /* Look for "POST" signalling start of query */
1368: if (!have_post) {
1369: if (strncmp(inbuf, "POST", 4)) {
1370: BIO_printf(bio_err, "Invalid request\n");
1371: return 1;
1372: }
1373: have_post = 1;
1374: }
1375: /* Look for end of headers */
1376: if ((inbuf[0] == '\r') || (inbuf[0] == '\n'))
1377: break;
1378: }
1379:
1380: /* Try to read OCSP request */
1381:
1382: req = d2i_OCSP_REQUEST_bio(cbio, NULL);
1383:
1384: if (!req) {
1385: BIO_printf(bio_err, "Error parsing OCSP request\n");
1386: ERR_print_errors(bio_err);
1387: }
1388: *preq = req;
1389:
1390: return 1;
1391: }
1392:
1393: static int
1.17 inoguchi 1394: send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp)
1.1 jsing 1395: {
1396: static const char http_resp[] =
1397: "HTTP/1.0 200 OK\r\nContent-type: application/ocsp-response\r\n"
1398: "Content-Length: %d\r\n\r\n";
1.19 ! inoguchi 1399:
1.1 jsing 1400: if (!cbio)
1401: return 0;
1402: BIO_printf(cbio, http_resp, i2d_OCSP_RESPONSE(resp, NULL));
1403: i2d_OCSP_RESPONSE_bio(cbio, resp);
1404: (void) BIO_flush(cbio);
1405: return 1;
1406: }
1407:
1408: static OCSP_RESPONSE *
1.19 ! inoguchi 1409: query_responder(BIO *err, BIO *cbio, char *path, STACK_OF(CONF_VALUE) *headers,
1.17 inoguchi 1410: OCSP_REQUEST *req, int req_timeout)
1.1 jsing 1411: {
1412: int fd;
1413: int rv;
1414: int i;
1415: OCSP_REQ_CTX *ctx = NULL;
1416: OCSP_RESPONSE *rsp = NULL;
1.2 deraadt 1417: struct pollfd pfd[1];
1.1 jsing 1418:
1419: if (req_timeout != -1)
1420: BIO_set_nbio(cbio, 1);
1421:
1422: rv = BIO_do_connect(cbio);
1423:
1424: if ((rv <= 0) && ((req_timeout == -1) || !BIO_should_retry(cbio))) {
1425: BIO_puts(err, "Error connecting BIO\n");
1426: return NULL;
1427: }
1.5 deraadt 1428: if (BIO_get_fd(cbio, &fd) < 0) {
1.1 jsing 1429: BIO_puts(err, "Can't get connection fd\n");
1430: goto err;
1431: }
1432: if (req_timeout != -1 && rv <= 0) {
1.2 deraadt 1433: pfd[0].fd = fd;
1434: pfd[0].events = POLLOUT;
1435: rv = poll(pfd, 1, req_timeout * 1000);
1.1 jsing 1436: if (rv == 0) {
1437: BIO_puts(err, "Timeout on connect\n");
1438: return NULL;
1439: }
1.2 deraadt 1440: if (rv == -1) {
1441: BIO_puts(err, "Poll error\n");
1442: return NULL;
1443: }
1.1 jsing 1444: }
1445: ctx = OCSP_sendreq_new(cbio, path, NULL, -1);
1446: if (!ctx)
1447: return NULL;
1448:
1449: for (i = 0; i < sk_CONF_VALUE_num(headers); i++) {
1450: CONF_VALUE *hdr = sk_CONF_VALUE_value(headers, i);
1451: if (!OCSP_REQ_CTX_add1_header(ctx, hdr->name, hdr->value))
1452: goto err;
1453: }
1454:
1455: if (!OCSP_REQ_CTX_set1_req(ctx, req))
1456: goto err;
1457:
1458: for (;;) {
1459: rv = OCSP_sendreq_nbio(&rsp, ctx);
1460: if (rv != -1)
1461: break;
1462: if (req_timeout == -1)
1463: continue;
1.2 deraadt 1464: pfd[0].fd = fd;
1.19 ! inoguchi 1465: if (BIO_should_read(cbio)) {
1.2 deraadt 1466: pfd[0].events = POLLIN;
1.19 ! inoguchi 1467: } else if (BIO_should_write(cbio)) {
1.2 deraadt 1468: pfd[0].events = POLLOUT;
1.19 ! inoguchi 1469: } else {
1.1 jsing 1470: BIO_puts(err, "Unexpected retry condition\n");
1471: goto err;
1472: }
1.2 deraadt 1473: rv = poll(pfd, 1, req_timeout * 1000);
1.1 jsing 1474: if (rv == 0) {
1475: BIO_puts(err, "Timeout on request\n");
1476: break;
1477: }
1.2 deraadt 1478: if (rv == -1 || (pfd[0].revents & (POLLERR|POLLNVAL))) {
1479: BIO_puts(err, "Poll error\n");
1.1 jsing 1480: break;
1481: }
1482: }
1.19 ! inoguchi 1483:
1.14 jsing 1484: err:
1.15 jsing 1485: OCSP_REQ_CTX_free(ctx);
1.1 jsing 1486: return rsp;
1487: }
1488:
1489: OCSP_RESPONSE *
1.19 ! inoguchi 1490: process_responder(BIO *err, OCSP_REQUEST *req, char *host, char *path,
! 1491: char *port, int use_ssl, STACK_OF(CONF_VALUE) *headers, int req_timeout)
1.1 jsing 1492: {
1493: BIO *cbio = NULL;
1494: SSL_CTX *ctx = NULL;
1495: OCSP_RESPONSE *resp = NULL;
1.19 ! inoguchi 1496:
1.1 jsing 1497: cbio = BIO_new_connect(host);
1498: if (!cbio) {
1499: BIO_printf(err, "Error creating connect BIO\n");
1500: goto end;
1501: }
1502: if (port)
1503: BIO_set_conn_port(cbio, port);
1504: if (use_ssl == 1) {
1505: BIO *sbio;
1.18 inoguchi 1506: ctx = SSL_CTX_new(TLS_client_method());
1.1 jsing 1507: if (ctx == NULL) {
1508: BIO_printf(err, "Error creating SSL context.\n");
1509: goto end;
1510: }
1511: SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
1512: sbio = BIO_new_ssl(ctx, 1);
1513: cbio = BIO_push(sbio, cbio);
1514: }
1515: resp = query_responder(err, cbio, path, headers, req, req_timeout);
1516: if (!resp)
1517: BIO_printf(bio_err, "Error querying OCSP responder\n");
1.19 ! inoguchi 1518:
1.14 jsing 1519: end:
1.15 jsing 1520: BIO_free_all(cbio);
1521: SSL_CTX_free(ctx);
1.1 jsing 1522: return resp;
1523: }
1524: #endif