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

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