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