[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.17

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