Annotation of src/usr.bin/openssl/ocsp.c, Revision 1.16
1.16 ! inoguchi 1: /* $OpenBSD: ocsp.c,v 1.15 2018/02/07 05:49:36 jsing 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
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,
90: long maxage);
91:
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,
95: int nmin, int ndays);
96:
97: static char **lookup_serial(CA_DB * db, ASN1_INTEGER * ser);
98: static BIO *init_responder(char *port);
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);
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;
! 112: STACK_OF(CONF_VALUE) * headers;
! 113: char *host;
! 114: STACK_OF(OCSP_CERTID) * ids;
! 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;
! 133: STACK_OF(OPENSSL_STRING) * reqnames;
! 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;
748: STACK_OF(X509) * sign_other = NULL, *verify_other = NULL, *rother = NULL;
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
1050: add_ocsp_cert(OCSP_REQUEST ** req, X509 * cert, const EVP_MD * cert_id_md, X509 * issuer,
1051: STACK_OF(OCSP_CERTID) * ids)
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
1075: add_ocsp_serial(OCSP_REQUEST ** req, char *serial, const EVP_MD * cert_id_md, X509 * issuer,
1076: STACK_OF(OCSP_CERTID) * ids)
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
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,
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
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,
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 **
1272: lookup_serial(CA_DB * db, ASN1_INTEGER * ser)
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
1322: do_responder(OCSP_REQUEST ** preq, BIO ** pcbio, BIO * acbio, char *port)
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
1369: send_ocsp_response(BIO * cbio, OCSP_RESPONSE * resp)
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 *
1383: query_responder(BIO * err, BIO * cbio, char *path,
1384: STACK_OF(CONF_VALUE) * headers,
1385: OCSP_REQUEST * req, int req_timeout)
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 *
1465: process_responder(BIO * err, OCSP_REQUEST * req,
1466: char *host, char *path, char *port, int use_ssl,
1467: STACK_OF(CONF_VALUE) * headers,
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