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

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