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