[BACK]Return to ocsp.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / openssl

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