1*dcc2b9cfStb /* $OpenBSD: ocsp.c,v 1.26 2024/08/31 18:39:25 tb Exp $ */ 2dab3f910Sjsing /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 3dab3f910Sjsing * project 2000. 4dab3f910Sjsing */ 5dab3f910Sjsing /* ==================================================================== 6dab3f910Sjsing * Copyright (c) 1999 The OpenSSL Project. All rights reserved. 7dab3f910Sjsing * 8dab3f910Sjsing * Redistribution and use in source and binary forms, with or without 9dab3f910Sjsing * modification, are permitted provided that the following conditions 10dab3f910Sjsing * are met: 11dab3f910Sjsing * 12dab3f910Sjsing * 1. Redistributions of source code must retain the above copyright 13dab3f910Sjsing * notice, this list of conditions and the following disclaimer. 14dab3f910Sjsing * 15dab3f910Sjsing * 2. Redistributions in binary form must reproduce the above copyright 16dab3f910Sjsing * notice, this list of conditions and the following disclaimer in 17dab3f910Sjsing * the documentation and/or other materials provided with the 18dab3f910Sjsing * distribution. 19dab3f910Sjsing * 20dab3f910Sjsing * 3. All advertising materials mentioning features or use of this 21dab3f910Sjsing * software must display the following acknowledgment: 22dab3f910Sjsing * "This product includes software developed by the OpenSSL Project 23dab3f910Sjsing * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24dab3f910Sjsing * 25dab3f910Sjsing * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26dab3f910Sjsing * endorse or promote products derived from this software without 27dab3f910Sjsing * prior written permission. For written permission, please contact 28dab3f910Sjsing * licensing@OpenSSL.org. 29dab3f910Sjsing * 30dab3f910Sjsing * 5. Products derived from this software may not be called "OpenSSL" 31dab3f910Sjsing * nor may "OpenSSL" appear in their names without prior written 32dab3f910Sjsing * permission of the OpenSSL Project. 33dab3f910Sjsing * 34dab3f910Sjsing * 6. Redistributions of any form whatsoever must retain the following 35dab3f910Sjsing * acknowledgment: 36dab3f910Sjsing * "This product includes software developed by the OpenSSL Project 37dab3f910Sjsing * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38dab3f910Sjsing * 39dab3f910Sjsing * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40dab3f910Sjsing * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41dab3f910Sjsing * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42dab3f910Sjsing * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43dab3f910Sjsing * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44dab3f910Sjsing * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45dab3f910Sjsing * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46dab3f910Sjsing * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47dab3f910Sjsing * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48dab3f910Sjsing * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49dab3f910Sjsing * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50dab3f910Sjsing * OF THE POSSIBILITY OF SUCH DAMAGE. 51dab3f910Sjsing * ==================================================================== 52dab3f910Sjsing * 53dab3f910Sjsing * This product includes cryptographic software written by Eric Young 54dab3f910Sjsing * (eay@cryptsoft.com). This product includes software written by Tim 55dab3f910Sjsing * Hudson (tjh@cryptsoft.com). 56dab3f910Sjsing * 57dab3f910Sjsing */ 58dab3f910Sjsing #ifndef OPENSSL_NO_OCSP 59dab3f910Sjsing 60230ab7bfSderaadt #include <sys/types.h> 61dab3f910Sjsing 62dab3f910Sjsing #include <stdio.h> 63dab3f910Sjsing #include <stdlib.h> 64dab3f910Sjsing #include <limits.h> 65dab3f910Sjsing #include <string.h> 66230ab7bfSderaadt #include <poll.h> 67dab3f910Sjsing #include <time.h> 68dab3f910Sjsing 69dab3f910Sjsing /* Needs to be included before the openssl headers! */ 70dab3f910Sjsing #include "apps.h" 71dab3f910Sjsing 72dab3f910Sjsing #include <openssl/bn.h> 7329c2232eStb #include <openssl/conf.h> 74dab3f910Sjsing #include <openssl/crypto.h> 75dab3f910Sjsing #include <openssl/err.h> 76dab3f910Sjsing #include <openssl/evp.h> 77dab3f910Sjsing #include <openssl/ssl.h> 78dab3f910Sjsing #include <openssl/x509v3.h> 79dab3f910Sjsing 80dab3f910Sjsing /* Maximum leeway in validity period: default 5 minutes */ 81dab3f910Sjsing #define MAX_VALIDITY_PERIOD (5 * 60) 82dab3f910Sjsing 83bc14ef1fSinoguchi static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, 84bc14ef1fSinoguchi const EVP_MD *cert_id_md, X509 *issuer, STACK_OF(OCSP_CERTID) *ids); 85bc14ef1fSinoguchi static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, 86bc14ef1fSinoguchi const EVP_MD *cert_id_md, X509 *issuer, STACK_OF(OCSP_CERTID) *ids); 87dab3f910Sjsing static int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req, 88bc14ef1fSinoguchi STACK_OF(OPENSSL_STRING) *names, STACK_OF(OCSP_CERTID) *ids, long nsec, 89dab3f910Sjsing long maxage); 90dab3f910Sjsing 91bc14ef1fSinoguchi static int make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req, 92bc14ef1fSinoguchi CA_DB *db, X509 *ca, X509 *rcert, EVP_PKEY *rkey, STACK_OF(X509) *rother, 93bc14ef1fSinoguchi unsigned long flags, int nmin, int ndays); 94dab3f910Sjsing 95dab3f910Sjsing static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser); 96dab3f910Sjsing static BIO *init_responder(char *port); 97bc14ef1fSinoguchi static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, 98bc14ef1fSinoguchi char *port); 99dab3f910Sjsing static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp); 100dab3f910Sjsing static OCSP_RESPONSE *query_responder(BIO *err, BIO *cbio, char *path, 1017b609544Stb STACK_OF(CONF_VALUE) *headers, const char *host, OCSP_REQUEST *req, 1027b609544Stb int req_timeout); 103dab3f910Sjsing 10492c3ac0cSinoguchi static struct { 10592c3ac0cSinoguchi int accept_count; 10692c3ac0cSinoguchi int add_nonce; 10792c3ac0cSinoguchi char *CAfile; 10892c3ac0cSinoguchi char *CApath; 10992c3ac0cSinoguchi X509 *cert; 11092c3ac0cSinoguchi const EVP_MD *cert_id_md; 11192c3ac0cSinoguchi STACK_OF(CONF_VALUE) *headers; 11292c3ac0cSinoguchi char *host; 11392c3ac0cSinoguchi STACK_OF(OCSP_CERTID) *ids; 11492c3ac0cSinoguchi int ignore_err; 11592c3ac0cSinoguchi X509 *issuer; 11692c3ac0cSinoguchi char *keyfile; 11792c3ac0cSinoguchi long maxage; 11892c3ac0cSinoguchi int ndays; 11992c3ac0cSinoguchi int nmin; 12092c3ac0cSinoguchi int no_usage; 12192c3ac0cSinoguchi int noverify; 12292c3ac0cSinoguchi long nsec; 12392c3ac0cSinoguchi char *outfile; 12492c3ac0cSinoguchi char *path; 12592c3ac0cSinoguchi char *port; 12692c3ac0cSinoguchi char *rca_filename; 12792c3ac0cSinoguchi char *rcertfile; 12892c3ac0cSinoguchi OCSP_REQUEST *req; 12992c3ac0cSinoguchi int req_text; 13092c3ac0cSinoguchi int req_timeout; 13192c3ac0cSinoguchi char *reqin; 13292c3ac0cSinoguchi STACK_OF(OPENSSL_STRING) *reqnames; 13392c3ac0cSinoguchi char *reqout; 13492c3ac0cSinoguchi int resp_text; 13592c3ac0cSinoguchi char *respin; 13692c3ac0cSinoguchi char *respout; 13792c3ac0cSinoguchi unsigned long rflags; 13892c3ac0cSinoguchi char *ridx_filename; 13992c3ac0cSinoguchi char *rkeyfile; 14092c3ac0cSinoguchi char *rsignfile; 14192c3ac0cSinoguchi char *sign_certfile; 14292c3ac0cSinoguchi unsigned long sign_flags; 14392c3ac0cSinoguchi char *signfile; 14492c3ac0cSinoguchi int use_ssl; 14592c3ac0cSinoguchi char *verify_certfile; 14692c3ac0cSinoguchi unsigned long verify_flags; 147e7718adaStb } cfg; 14892c3ac0cSinoguchi 14992c3ac0cSinoguchi static int 15092c3ac0cSinoguchi ocsp_opt_cert(char *arg) 15192c3ac0cSinoguchi { 152e7718adaStb X509_free(cfg.cert); 153e7718adaStb cfg.cert = load_cert(bio_err, arg, FORMAT_PEM, NULL, 15492c3ac0cSinoguchi "certificate"); 155e7718adaStb if (cfg.cert == NULL) { 156e7718adaStb cfg.no_usage = 1; 15792c3ac0cSinoguchi return (1); 15892c3ac0cSinoguchi } 159e7718adaStb if (cfg.cert_id_md == NULL) 160e7718adaStb cfg.cert_id_md = EVP_sha1(); 161e7718adaStb if (!add_ocsp_cert(&cfg.req, cfg.cert, 162e7718adaStb cfg.cert_id_md, cfg.issuer, cfg.ids)) { 163e7718adaStb cfg.no_usage = 1; 16492c3ac0cSinoguchi return (1); 16592c3ac0cSinoguchi } 166e7718adaStb if (!sk_OPENSSL_STRING_push(cfg.reqnames, arg)) { 167e7718adaStb cfg.no_usage = 1; 16892c3ac0cSinoguchi return (1); 16992c3ac0cSinoguchi } 17092c3ac0cSinoguchi return (0); 17192c3ac0cSinoguchi } 17292c3ac0cSinoguchi 17392c3ac0cSinoguchi static int 17492c3ac0cSinoguchi ocsp_opt_cert_id_md(int argc, char **argv, int *argsused) 17592c3ac0cSinoguchi { 17692c3ac0cSinoguchi char *name = argv[0]; 17792c3ac0cSinoguchi 17892c3ac0cSinoguchi if (*name++ != '-') 17992c3ac0cSinoguchi return (1); 18092c3ac0cSinoguchi 181e7718adaStb if ((cfg.cert_id_md = EVP_get_digestbyname(name)) == NULL) 18292c3ac0cSinoguchi return (1); 18392c3ac0cSinoguchi 18492c3ac0cSinoguchi *argsused = 1; 18592c3ac0cSinoguchi return (0); 18692c3ac0cSinoguchi } 18792c3ac0cSinoguchi 18892c3ac0cSinoguchi static int 18929c2232eStb x509v3_add_value(const char *name, const char *value, 190*dcc2b9cfStb STACK_OF(CONF_VALUE) **out_extlist) 19129c2232eStb { 192*dcc2b9cfStb STACK_OF(CONF_VALUE) *extlist = NULL; 193*dcc2b9cfStb CONF_VALUE *conf_value = NULL; 194*dcc2b9cfStb int ret = 0; 19529c2232eStb 196*dcc2b9cfStb if ((conf_value = calloc(1, sizeof(*conf_value))) == NULL) { 197*dcc2b9cfStb X509V3error(ERR_R_MALLOC_FAILURE); 19829c2232eStb goto err; 199*dcc2b9cfStb } 20029c2232eStb if (name != NULL) { 201*dcc2b9cfStb if ((conf_value->name = strdup(name)) == NULL) { 202*dcc2b9cfStb X509V3error(ERR_R_MALLOC_FAILURE); 20329c2232eStb goto err; 20429c2232eStb } 205*dcc2b9cfStb } 20629c2232eStb if (value != NULL) { 207*dcc2b9cfStb if ((conf_value->value = strdup(value)) == NULL) { 208*dcc2b9cfStb X509V3error(ERR_R_MALLOC_FAILURE); 209*dcc2b9cfStb goto err; 210*dcc2b9cfStb } 211*dcc2b9cfStb } 212*dcc2b9cfStb 213*dcc2b9cfStb if ((extlist = *out_extlist) == NULL) 214*dcc2b9cfStb extlist = sk_CONF_VALUE_new_null(); 215*dcc2b9cfStb if (extlist == NULL) { 216*dcc2b9cfStb X509V3error(ERR_R_MALLOC_FAILURE); 21729c2232eStb goto err; 21829c2232eStb } 21929c2232eStb 220*dcc2b9cfStb if (!sk_CONF_VALUE_push(extlist, conf_value)) { 221*dcc2b9cfStb X509V3error(ERR_R_MALLOC_FAILURE); 22229c2232eStb goto err; 22329c2232eStb } 224*dcc2b9cfStb conf_value = NULL; 22529c2232eStb 226*dcc2b9cfStb *out_extlist = extlist; 227*dcc2b9cfStb extlist = NULL; 22829c2232eStb 229*dcc2b9cfStb ret = 1; 23029c2232eStb 23129c2232eStb err: 232*dcc2b9cfStb if (extlist != *out_extlist) 233*dcc2b9cfStb sk_CONF_VALUE_pop_free(extlist, X509V3_conf_free); 234*dcc2b9cfStb X509V3_conf_free(conf_value); 235*dcc2b9cfStb 236*dcc2b9cfStb return ret; 23729c2232eStb } 23829c2232eStb 23929c2232eStb static int 24092c3ac0cSinoguchi ocsp_opt_header(int argc, char **argv, int *argsused) 24192c3ac0cSinoguchi { 24292c3ac0cSinoguchi if (argc < 3 || argv[1] == NULL || argv[2] == NULL) 24392c3ac0cSinoguchi return (1); 24492c3ac0cSinoguchi 24529c2232eStb if (!x509v3_add_value(argv[1], argv[2], &cfg.headers)) { 246e7718adaStb cfg.no_usage = 1; 24792c3ac0cSinoguchi return (1); 24892c3ac0cSinoguchi } 24992c3ac0cSinoguchi 25092c3ac0cSinoguchi *argsused = 3; 25192c3ac0cSinoguchi return (0); 25292c3ac0cSinoguchi } 25392c3ac0cSinoguchi 25492c3ac0cSinoguchi static int 25592c3ac0cSinoguchi ocsp_opt_host(char *arg) 25692c3ac0cSinoguchi { 257e7718adaStb if (cfg.use_ssl != -1) 25892c3ac0cSinoguchi return (1); 25992c3ac0cSinoguchi 260e7718adaStb cfg.host = arg; 26192c3ac0cSinoguchi return (0); 26292c3ac0cSinoguchi } 26392c3ac0cSinoguchi 26492c3ac0cSinoguchi static int 26592c3ac0cSinoguchi ocsp_opt_issuer(char *arg) 26692c3ac0cSinoguchi { 267e7718adaStb X509_free(cfg.issuer); 268e7718adaStb cfg.issuer = load_cert(bio_err, arg, FORMAT_PEM, NULL, 26992c3ac0cSinoguchi "issuer certificate"); 270e7718adaStb if (cfg.issuer == NULL) { 271e7718adaStb cfg.no_usage = 1; 27292c3ac0cSinoguchi return (1); 27392c3ac0cSinoguchi } 27492c3ac0cSinoguchi return (0); 27592c3ac0cSinoguchi } 27692c3ac0cSinoguchi 27792c3ac0cSinoguchi static int 27892c3ac0cSinoguchi ocsp_opt_ndays(char *arg) 27992c3ac0cSinoguchi { 28092c3ac0cSinoguchi const char *errstr = NULL; 28192c3ac0cSinoguchi 282e7718adaStb cfg.ndays = strtonum(arg, 0, INT_MAX, &errstr); 28392c3ac0cSinoguchi if (errstr != NULL) { 28492c3ac0cSinoguchi BIO_printf(bio_err, "Illegal update period %s: %s\n", 28592c3ac0cSinoguchi arg, errstr); 28692c3ac0cSinoguchi return (1); 28792c3ac0cSinoguchi } 28892c3ac0cSinoguchi return (0); 28992c3ac0cSinoguchi } 29092c3ac0cSinoguchi 29192c3ac0cSinoguchi static int 29292c3ac0cSinoguchi ocsp_opt_nmin(char *arg) 29392c3ac0cSinoguchi { 29492c3ac0cSinoguchi const char *errstr = NULL; 29592c3ac0cSinoguchi 296e7718adaStb cfg.nmin = strtonum(arg, 0, INT_MAX, &errstr); 29792c3ac0cSinoguchi if (errstr != NULL) { 29892c3ac0cSinoguchi BIO_printf(bio_err, "Illegal update period %s: %s\n", 29992c3ac0cSinoguchi arg, errstr); 30092c3ac0cSinoguchi return (1); 30192c3ac0cSinoguchi } 30292c3ac0cSinoguchi 303e7718adaStb if (cfg.ndays != -1) 30492c3ac0cSinoguchi return (1); 30592c3ac0cSinoguchi 306e7718adaStb cfg.ndays = 0; 30792c3ac0cSinoguchi return (0); 30892c3ac0cSinoguchi } 30992c3ac0cSinoguchi 31092c3ac0cSinoguchi static int 31192c3ac0cSinoguchi ocsp_opt_nrequest(char *arg) 31292c3ac0cSinoguchi { 31392c3ac0cSinoguchi const char *errstr = NULL; 31492c3ac0cSinoguchi 315e7718adaStb cfg.accept_count = strtonum(arg, 0, INT_MAX, &errstr); 31692c3ac0cSinoguchi if (errstr != NULL) { 31792c3ac0cSinoguchi BIO_printf(bio_err, "Illegal accept count %s: %s\n", 31892c3ac0cSinoguchi arg, errstr); 31992c3ac0cSinoguchi return (1); 32092c3ac0cSinoguchi } 32192c3ac0cSinoguchi return (0); 32292c3ac0cSinoguchi } 32392c3ac0cSinoguchi 32492c3ac0cSinoguchi static int 32592c3ac0cSinoguchi ocsp_opt_port(char *arg) 32692c3ac0cSinoguchi { 327e7718adaStb if (cfg.use_ssl != -1) 32892c3ac0cSinoguchi return (1); 32992c3ac0cSinoguchi 330e7718adaStb cfg.port = arg; 33192c3ac0cSinoguchi return (0); 33292c3ac0cSinoguchi } 33392c3ac0cSinoguchi 33492c3ac0cSinoguchi static int 33592c3ac0cSinoguchi ocsp_opt_serial(char *arg) 33692c3ac0cSinoguchi { 337e7718adaStb if (cfg.cert_id_md == NULL) 338e7718adaStb cfg.cert_id_md = EVP_sha1(); 339e7718adaStb if (!add_ocsp_serial(&cfg.req, arg, cfg.cert_id_md, 340e7718adaStb cfg.issuer, cfg.ids)) { 341e7718adaStb cfg.no_usage = 1; 34292c3ac0cSinoguchi return (1); 34392c3ac0cSinoguchi } 344e7718adaStb if (!sk_OPENSSL_STRING_push(cfg.reqnames, arg)) { 345e7718adaStb cfg.no_usage = 1; 34692c3ac0cSinoguchi return (1); 34792c3ac0cSinoguchi } 34892c3ac0cSinoguchi return (0); 34992c3ac0cSinoguchi } 35092c3ac0cSinoguchi 35192c3ac0cSinoguchi static int 35292c3ac0cSinoguchi ocsp_opt_status_age(char *arg) 35392c3ac0cSinoguchi { 35492c3ac0cSinoguchi const char *errstr = NULL; 35592c3ac0cSinoguchi 356e7718adaStb cfg.maxage = strtonum(arg, 0, LONG_MAX, &errstr); 35792c3ac0cSinoguchi if (errstr != NULL) { 35892c3ac0cSinoguchi BIO_printf(bio_err, "Illegal validity age %s: %s\n", 35992c3ac0cSinoguchi arg, errstr); 36092c3ac0cSinoguchi return (1); 36192c3ac0cSinoguchi } 36292c3ac0cSinoguchi return (0); 36392c3ac0cSinoguchi } 36492c3ac0cSinoguchi 36592c3ac0cSinoguchi static int 36692c3ac0cSinoguchi ocsp_opt_text(void) 36792c3ac0cSinoguchi { 368e7718adaStb cfg.req_text = 1; 369e7718adaStb cfg.resp_text = 1; 37092c3ac0cSinoguchi return (0); 37192c3ac0cSinoguchi } 37292c3ac0cSinoguchi 37392c3ac0cSinoguchi static int 37492c3ac0cSinoguchi ocsp_opt_timeout(char *arg) 37592c3ac0cSinoguchi { 37692c3ac0cSinoguchi const char *errstr = NULL; 37792c3ac0cSinoguchi 378e7718adaStb cfg.req_timeout = strtonum(arg, 0, INT_MAX, &errstr); 37992c3ac0cSinoguchi if (errstr != NULL) { 38092c3ac0cSinoguchi BIO_printf(bio_err, "Illegal timeout value %s: %s\n", 38192c3ac0cSinoguchi arg, errstr); 38292c3ac0cSinoguchi return (1); 38392c3ac0cSinoguchi } 38492c3ac0cSinoguchi return (0); 38592c3ac0cSinoguchi } 38692c3ac0cSinoguchi 38792c3ac0cSinoguchi static int 38892c3ac0cSinoguchi ocsp_opt_url(char *arg) 38992c3ac0cSinoguchi { 390e7718adaStb if (cfg.host == NULL && cfg.port == NULL && 391e7718adaStb cfg.path == NULL) { 392e7718adaStb if (!OCSP_parse_url(arg, &cfg.host, &cfg.port, 393e7718adaStb &cfg.path, &cfg.use_ssl)) { 39492c3ac0cSinoguchi BIO_printf(bio_err, "Error parsing URL\n"); 39592c3ac0cSinoguchi return (1); 39692c3ac0cSinoguchi } 39792c3ac0cSinoguchi } 39892c3ac0cSinoguchi return (0); 39992c3ac0cSinoguchi } 40092c3ac0cSinoguchi 40192c3ac0cSinoguchi static int 40292c3ac0cSinoguchi ocsp_opt_vafile(char *arg) 40392c3ac0cSinoguchi { 404e7718adaStb cfg.verify_certfile = arg; 405e7718adaStb cfg.verify_flags |= OCSP_TRUSTOTHER; 40692c3ac0cSinoguchi return (0); 40792c3ac0cSinoguchi } 40892c3ac0cSinoguchi 40992c3ac0cSinoguchi static int 41092c3ac0cSinoguchi ocsp_opt_validity_period(char *arg) 41192c3ac0cSinoguchi { 41292c3ac0cSinoguchi const char *errstr = NULL; 41392c3ac0cSinoguchi 414e7718adaStb cfg.nsec = strtonum(arg, 0, LONG_MAX, &errstr); 41592c3ac0cSinoguchi if (errstr != NULL) { 41692c3ac0cSinoguchi BIO_printf(bio_err, "Illegal validity period %s: %s\n", 41792c3ac0cSinoguchi arg, errstr); 41892c3ac0cSinoguchi return (1); 41992c3ac0cSinoguchi } 42092c3ac0cSinoguchi return (0); 42192c3ac0cSinoguchi } 42292c3ac0cSinoguchi 42392c3ac0cSinoguchi static const struct option ocsp_options[] = { 42492c3ac0cSinoguchi { 42592c3ac0cSinoguchi .name = "CA", 42692c3ac0cSinoguchi .argname = "file", 42792c3ac0cSinoguchi .desc = "CA certificate corresponding to the revocation information", 42892c3ac0cSinoguchi .type = OPTION_ARG, 429e7718adaStb .opt.arg = &cfg.rca_filename, 43092c3ac0cSinoguchi }, 43192c3ac0cSinoguchi { 43292c3ac0cSinoguchi .name = "CAfile", 43392c3ac0cSinoguchi .argname = "file", 43492c3ac0cSinoguchi .desc = "Trusted certificates file", 43592c3ac0cSinoguchi .type = OPTION_ARG, 436e7718adaStb .opt.arg = &cfg.CAfile, 43792c3ac0cSinoguchi }, 43892c3ac0cSinoguchi { 43992c3ac0cSinoguchi .name = "CApath", 44092c3ac0cSinoguchi .argname = "directory", 44192c3ac0cSinoguchi .desc = "Trusted certificates directory", 44292c3ac0cSinoguchi .type = OPTION_ARG, 443e7718adaStb .opt.arg = &cfg.CApath, 44492c3ac0cSinoguchi }, 44592c3ac0cSinoguchi { 44692c3ac0cSinoguchi .name = "cert", 44792c3ac0cSinoguchi .argname = "file", 44892c3ac0cSinoguchi .desc = "Certificate to check", 44992c3ac0cSinoguchi .type = OPTION_ARG_FUNC, 45092c3ac0cSinoguchi .opt.argfunc = ocsp_opt_cert, 45192c3ac0cSinoguchi }, 45292c3ac0cSinoguchi { 45392c3ac0cSinoguchi .name = "header", 45492c3ac0cSinoguchi .argname = "name value", 45592c3ac0cSinoguchi .desc = "Add the header name with the value to the request", 45692c3ac0cSinoguchi .type = OPTION_ARGV_FUNC, 45792c3ac0cSinoguchi .opt.argvfunc = ocsp_opt_header, 45892c3ac0cSinoguchi }, 45992c3ac0cSinoguchi { 46092c3ac0cSinoguchi .name = "host", 46192c3ac0cSinoguchi .argname = "hostname:port", 46292c3ac0cSinoguchi .desc = "Send OCSP request to host on port", 46392c3ac0cSinoguchi .type = OPTION_ARG_FUNC, 46492c3ac0cSinoguchi .opt.argfunc = ocsp_opt_host, 46592c3ac0cSinoguchi }, 46692c3ac0cSinoguchi { 46792c3ac0cSinoguchi .name = "ignore_err", 46892c3ac0cSinoguchi .desc = "Ignore the invalid response", 46992c3ac0cSinoguchi .type = OPTION_FLAG, 470e7718adaStb .opt.flag = &cfg.ignore_err, 47192c3ac0cSinoguchi }, 47292c3ac0cSinoguchi { 47392c3ac0cSinoguchi .name = "index", 47492c3ac0cSinoguchi .argname = "indexfile", 47592c3ac0cSinoguchi .desc = "Certificate status index file", 47692c3ac0cSinoguchi .type = OPTION_ARG, 477e7718adaStb .opt.arg = &cfg.ridx_filename, 47892c3ac0cSinoguchi }, 47992c3ac0cSinoguchi { 48092c3ac0cSinoguchi .name = "issuer", 48192c3ac0cSinoguchi .argname = "file", 48292c3ac0cSinoguchi .desc = "Issuer certificate", 48392c3ac0cSinoguchi .type = OPTION_ARG_FUNC, 48492c3ac0cSinoguchi .opt.argfunc = ocsp_opt_issuer, 48592c3ac0cSinoguchi }, 48692c3ac0cSinoguchi { 48792c3ac0cSinoguchi .name = "ndays", 48892c3ac0cSinoguchi .argname = "days", 48992c3ac0cSinoguchi .desc = "Number of days before next update", 49092c3ac0cSinoguchi .type = OPTION_ARG_FUNC, 49192c3ac0cSinoguchi .opt.argfunc = ocsp_opt_ndays, 49292c3ac0cSinoguchi }, 49392c3ac0cSinoguchi { 49492c3ac0cSinoguchi .name = "nmin", 49592c3ac0cSinoguchi .argname = "minutes", 49692c3ac0cSinoguchi .desc = "Number of minutes before next update", 49792c3ac0cSinoguchi .type = OPTION_ARG_FUNC, 49892c3ac0cSinoguchi .opt.argfunc = ocsp_opt_nmin, 49992c3ac0cSinoguchi }, 50092c3ac0cSinoguchi { 50192c3ac0cSinoguchi .name = "no_cert_checks", 50292c3ac0cSinoguchi .desc = "Don't do additional checks on signing certificate", 50392c3ac0cSinoguchi .type = OPTION_UL_VALUE_OR, 504e7718adaStb .opt.ulvalue = &cfg.verify_flags, 50592c3ac0cSinoguchi .ulvalue = OCSP_NOCHECKS, 50692c3ac0cSinoguchi }, 50792c3ac0cSinoguchi { 50892c3ac0cSinoguchi .name = "no_cert_verify", 50992c3ac0cSinoguchi .desc = "Don't check signing certificate", 51092c3ac0cSinoguchi .type = OPTION_UL_VALUE_OR, 511e7718adaStb .opt.ulvalue = &cfg.verify_flags, 51292c3ac0cSinoguchi .ulvalue = OCSP_NOVERIFY, 51392c3ac0cSinoguchi }, 51492c3ac0cSinoguchi { 51592c3ac0cSinoguchi .name = "no_certs", 51692c3ac0cSinoguchi .desc = "Don't include any certificates in signed request", 51792c3ac0cSinoguchi .type = OPTION_UL_VALUE_OR, 518e7718adaStb .opt.ulvalue = &cfg.sign_flags, 51992c3ac0cSinoguchi .ulvalue = OCSP_NOCERTS, 52092c3ac0cSinoguchi }, 52192c3ac0cSinoguchi { 52292c3ac0cSinoguchi .name = "no_chain", 52392c3ac0cSinoguchi .desc = "Don't use certificates in the response", 52492c3ac0cSinoguchi .type = OPTION_UL_VALUE_OR, 525e7718adaStb .opt.ulvalue = &cfg.verify_flags, 52692c3ac0cSinoguchi .ulvalue = OCSP_NOCHAIN, 52792c3ac0cSinoguchi }, 52892c3ac0cSinoguchi { 52992c3ac0cSinoguchi .name = "no_explicit", 53092c3ac0cSinoguchi .desc = "Don't check the explicit trust for OCSP signing", 53192c3ac0cSinoguchi .type = OPTION_UL_VALUE_OR, 532e7718adaStb .opt.ulvalue = &cfg.verify_flags, 53392c3ac0cSinoguchi .ulvalue = OCSP_NOEXPLICIT, 53492c3ac0cSinoguchi }, 53592c3ac0cSinoguchi { 53692c3ac0cSinoguchi .name = "no_intern", 53792c3ac0cSinoguchi .desc = "Don't search certificates contained in response for signer", 53892c3ac0cSinoguchi .type = OPTION_UL_VALUE_OR, 539e7718adaStb .opt.ulvalue = &cfg.verify_flags, 54092c3ac0cSinoguchi .ulvalue = OCSP_NOINTERN, 54192c3ac0cSinoguchi }, 54292c3ac0cSinoguchi { 54392c3ac0cSinoguchi .name = "no_nonce", 54492c3ac0cSinoguchi .desc = "Don't add OCSP nonce to request", 54592c3ac0cSinoguchi .type = OPTION_VALUE, 546e7718adaStb .opt.value = &cfg.add_nonce, 54792c3ac0cSinoguchi .value = 0, 54892c3ac0cSinoguchi }, 54992c3ac0cSinoguchi { 55092c3ac0cSinoguchi .name = "no_signature_verify", 55192c3ac0cSinoguchi .desc = "Don't check signature on response", 55292c3ac0cSinoguchi .type = OPTION_UL_VALUE_OR, 553e7718adaStb .opt.ulvalue = &cfg.verify_flags, 55492c3ac0cSinoguchi .ulvalue = OCSP_NOSIGS, 55592c3ac0cSinoguchi }, 55692c3ac0cSinoguchi { 55792c3ac0cSinoguchi .name = "nonce", 55892c3ac0cSinoguchi .desc = "Add OCSP nonce to request", 55992c3ac0cSinoguchi .type = OPTION_VALUE, 560e7718adaStb .opt.value = &cfg.add_nonce, 56192c3ac0cSinoguchi .value = 2, 56292c3ac0cSinoguchi }, 56392c3ac0cSinoguchi { 56492c3ac0cSinoguchi .name = "noverify", 56592c3ac0cSinoguchi .desc = "Don't verify response at all", 56692c3ac0cSinoguchi .type = OPTION_FLAG, 567e7718adaStb .opt.flag = &cfg.noverify, 56892c3ac0cSinoguchi }, 56992c3ac0cSinoguchi { 57092c3ac0cSinoguchi .name = "nrequest", 57192c3ac0cSinoguchi .argname = "number", 57292c3ac0cSinoguchi .desc = "Number of requests to accept (default unlimited)", 57392c3ac0cSinoguchi .type = OPTION_ARG_FUNC, 57492c3ac0cSinoguchi .opt.argfunc = ocsp_opt_nrequest, 57592c3ac0cSinoguchi }, 57692c3ac0cSinoguchi { 57792c3ac0cSinoguchi .name = "out", 57892c3ac0cSinoguchi .argname = "file", 57992c3ac0cSinoguchi .desc = "Output filename", 58092c3ac0cSinoguchi .type = OPTION_ARG, 581e7718adaStb .opt.arg = &cfg.outfile, 58292c3ac0cSinoguchi }, 58392c3ac0cSinoguchi { 58492c3ac0cSinoguchi .name = "path", 58592c3ac0cSinoguchi .argname = "path", 58692c3ac0cSinoguchi .desc = "Path to use in OCSP request", 58792c3ac0cSinoguchi .type = OPTION_ARG, 588e7718adaStb .opt.arg = &cfg.path, 58992c3ac0cSinoguchi }, 59092c3ac0cSinoguchi { 59192c3ac0cSinoguchi .name = "port", 59292c3ac0cSinoguchi .argname = "portnum", 59392c3ac0cSinoguchi .desc = "Port to run responder on", 59492c3ac0cSinoguchi .type = OPTION_ARG_FUNC, 59592c3ac0cSinoguchi .opt.argfunc = ocsp_opt_port, 59692c3ac0cSinoguchi }, 59792c3ac0cSinoguchi { 59892c3ac0cSinoguchi .name = "req_text", 59992c3ac0cSinoguchi .desc = "Print text form of request", 60092c3ac0cSinoguchi .type = OPTION_FLAG, 601e7718adaStb .opt.flag = &cfg.req_text, 60292c3ac0cSinoguchi }, 60392c3ac0cSinoguchi { 60492c3ac0cSinoguchi .name = "reqin", 60592c3ac0cSinoguchi .argname = "file", 60692c3ac0cSinoguchi .desc = "Read DER encoded OCSP request from \"file\"", 60792c3ac0cSinoguchi .type = OPTION_ARG, 608e7718adaStb .opt.arg = &cfg.reqin, 60992c3ac0cSinoguchi }, 61092c3ac0cSinoguchi { 61192c3ac0cSinoguchi .name = "reqout", 61292c3ac0cSinoguchi .argname = "file", 61392c3ac0cSinoguchi .desc = "Write DER encoded OCSP request to \"file\"", 61492c3ac0cSinoguchi .type = OPTION_ARG, 615e7718adaStb .opt.arg = &cfg.reqout, 61692c3ac0cSinoguchi }, 61792c3ac0cSinoguchi { 61892c3ac0cSinoguchi .name = "resp_key_id", 61992c3ac0cSinoguchi .desc = "Identify response by signing certificate key ID", 62092c3ac0cSinoguchi .type = OPTION_UL_VALUE_OR, 621e7718adaStb .opt.ulvalue = &cfg.rflags, 62292c3ac0cSinoguchi .ulvalue = OCSP_RESPID_KEY, 62392c3ac0cSinoguchi }, 62492c3ac0cSinoguchi { 62592c3ac0cSinoguchi .name = "resp_no_certs", 62692c3ac0cSinoguchi .desc = "Don't include any certificates in response", 62792c3ac0cSinoguchi .type = OPTION_UL_VALUE_OR, 628e7718adaStb .opt.ulvalue = &cfg.rflags, 62992c3ac0cSinoguchi .ulvalue = OCSP_NOCERTS, 63092c3ac0cSinoguchi }, 63192c3ac0cSinoguchi { 63292c3ac0cSinoguchi .name = "resp_text", 63392c3ac0cSinoguchi .desc = "Print text form of response", 63492c3ac0cSinoguchi .type = OPTION_FLAG, 635e7718adaStb .opt.flag = &cfg.resp_text, 63692c3ac0cSinoguchi }, 63792c3ac0cSinoguchi { 63892c3ac0cSinoguchi .name = "respin", 63992c3ac0cSinoguchi .argname = "file", 64092c3ac0cSinoguchi .desc = "Read DER encoded OCSP response from \"file\"", 64192c3ac0cSinoguchi .type = OPTION_ARG, 642e7718adaStb .opt.arg = &cfg.respin, 64392c3ac0cSinoguchi }, 64492c3ac0cSinoguchi { 64592c3ac0cSinoguchi .name = "respout", 64692c3ac0cSinoguchi .argname = "file", 64792c3ac0cSinoguchi .desc = "Write DER encoded OCSP response to \"file\"", 64892c3ac0cSinoguchi .type = OPTION_ARG, 649e7718adaStb .opt.arg = &cfg.respout, 65092c3ac0cSinoguchi }, 65192c3ac0cSinoguchi { 65292c3ac0cSinoguchi .name = "rkey", 65392c3ac0cSinoguchi .argname = "file", 65492c3ac0cSinoguchi .desc = "Responder key to sign responses with", 65592c3ac0cSinoguchi .type = OPTION_ARG, 656e7718adaStb .opt.arg = &cfg.rkeyfile, 65792c3ac0cSinoguchi }, 65892c3ac0cSinoguchi { 65992c3ac0cSinoguchi .name = "rother", 66092c3ac0cSinoguchi .argname = "file", 66192c3ac0cSinoguchi .desc = "Other certificates to include in response", 66292c3ac0cSinoguchi .type = OPTION_ARG, 663e7718adaStb .opt.arg = &cfg.rcertfile, 66492c3ac0cSinoguchi }, 66592c3ac0cSinoguchi { 66692c3ac0cSinoguchi .name = "rsigner", 66792c3ac0cSinoguchi .argname = "file", 66892c3ac0cSinoguchi .desc = "Responder certificate to sign responses with", 66992c3ac0cSinoguchi .type = OPTION_ARG, 670e7718adaStb .opt.arg = &cfg.rsignfile, 67192c3ac0cSinoguchi }, 67292c3ac0cSinoguchi { 67392c3ac0cSinoguchi .name = "serial", 67492c3ac0cSinoguchi .argname = "num", 67592c3ac0cSinoguchi .desc = "Serial number to check", 67692c3ac0cSinoguchi .type = OPTION_ARG_FUNC, 67792c3ac0cSinoguchi .opt.argfunc = ocsp_opt_serial, 67892c3ac0cSinoguchi }, 67992c3ac0cSinoguchi { 68092c3ac0cSinoguchi .name = "sign_other", 68192c3ac0cSinoguchi .argname = "file", 68292c3ac0cSinoguchi .desc = "Additional certificates to include in signed request", 68392c3ac0cSinoguchi .type = OPTION_ARG, 684e7718adaStb .opt.arg = &cfg.sign_certfile, 68592c3ac0cSinoguchi }, 68692c3ac0cSinoguchi { 68792c3ac0cSinoguchi .name = "signer", 68892c3ac0cSinoguchi .argname = "file", 68992c3ac0cSinoguchi .desc = "Certificate to sign OCSP request with", 69092c3ac0cSinoguchi .type = OPTION_ARG, 691e7718adaStb .opt.arg = &cfg.signfile, 69292c3ac0cSinoguchi }, 69392c3ac0cSinoguchi { 69492c3ac0cSinoguchi .name = "signkey", 69592c3ac0cSinoguchi .argname = "file", 69692c3ac0cSinoguchi .desc = "Private key to sign OCSP request with", 69792c3ac0cSinoguchi .type = OPTION_ARG, 698e7718adaStb .opt.arg = &cfg.keyfile, 69992c3ac0cSinoguchi }, 70092c3ac0cSinoguchi { 70192c3ac0cSinoguchi .name = "status_age", 70292c3ac0cSinoguchi .argname = "age", 70392c3ac0cSinoguchi .desc = "Maximum status age in seconds", 70492c3ac0cSinoguchi .type = OPTION_ARG_FUNC, 70592c3ac0cSinoguchi .opt.argfunc = ocsp_opt_status_age, 70692c3ac0cSinoguchi }, 70792c3ac0cSinoguchi { 70892c3ac0cSinoguchi .name = "text", 70992c3ac0cSinoguchi .desc = "Print text form of request and response", 71092c3ac0cSinoguchi .type = OPTION_FUNC, 71192c3ac0cSinoguchi .opt.func = ocsp_opt_text, 71292c3ac0cSinoguchi }, 71392c3ac0cSinoguchi { 71492c3ac0cSinoguchi .name = "timeout", 71592c3ac0cSinoguchi .argname = "seconds", 71692c3ac0cSinoguchi .desc = "Connection timeout to the OCSP responder in seconds", 71792c3ac0cSinoguchi .type = OPTION_ARG_FUNC, 71892c3ac0cSinoguchi .opt.argfunc = ocsp_opt_timeout, 71992c3ac0cSinoguchi }, 72092c3ac0cSinoguchi { 72192c3ac0cSinoguchi .name = "trust_other", 72292c3ac0cSinoguchi .desc = "Don't verify additional certificates", 72392c3ac0cSinoguchi .type = OPTION_UL_VALUE_OR, 724e7718adaStb .opt.ulvalue = &cfg.verify_flags, 72592c3ac0cSinoguchi .ulvalue = OCSP_TRUSTOTHER, 72692c3ac0cSinoguchi }, 72792c3ac0cSinoguchi { 72892c3ac0cSinoguchi .name = "url", 72992c3ac0cSinoguchi .argname = "responder_url", 73092c3ac0cSinoguchi .desc = "OCSP responder URL", 73192c3ac0cSinoguchi .type = OPTION_ARG_FUNC, 73292c3ac0cSinoguchi .opt.argfunc = ocsp_opt_url, 73392c3ac0cSinoguchi }, 73492c3ac0cSinoguchi { 73592c3ac0cSinoguchi .name = "VAfile", 73692c3ac0cSinoguchi .argname = "file", 73792c3ac0cSinoguchi .desc = "Explicitly trusted responder certificates", 73892c3ac0cSinoguchi .type = OPTION_ARG_FUNC, 73992c3ac0cSinoguchi .opt.argfunc = ocsp_opt_vafile, 74092c3ac0cSinoguchi }, 74192c3ac0cSinoguchi { 74292c3ac0cSinoguchi .name = "validity_period", 74392c3ac0cSinoguchi .argname = "n", 74492c3ac0cSinoguchi .desc = "Maximum validity discrepancy in seconds", 74592c3ac0cSinoguchi .type = OPTION_ARG_FUNC, 74692c3ac0cSinoguchi .opt.argfunc = ocsp_opt_validity_period, 74792c3ac0cSinoguchi }, 74892c3ac0cSinoguchi { 74992c3ac0cSinoguchi .name = "verify_other", 75092c3ac0cSinoguchi .argname = "file", 75192c3ac0cSinoguchi .desc = "Additional certificates to search for signer", 75292c3ac0cSinoguchi .type = OPTION_ARG, 753e7718adaStb .opt.arg = &cfg.verify_certfile, 75492c3ac0cSinoguchi }, 75592c3ac0cSinoguchi { 75692c3ac0cSinoguchi .name = NULL, 75792c3ac0cSinoguchi .desc = "", 75892c3ac0cSinoguchi .type = OPTION_ARGV_FUNC, 75992c3ac0cSinoguchi .opt.argvfunc = ocsp_opt_cert_id_md, 76092c3ac0cSinoguchi }, 76192c3ac0cSinoguchi { NULL }, 76292c3ac0cSinoguchi }; 76392c3ac0cSinoguchi 76492c3ac0cSinoguchi static void 76592c3ac0cSinoguchi ocsp_usage(void) 76692c3ac0cSinoguchi { 76792c3ac0cSinoguchi fprintf(stderr, "usage: ocsp " 76892c3ac0cSinoguchi "[-CA file] [-CAfile file] [-CApath directory] [-cert file]\n" 76992c3ac0cSinoguchi " [-dgst alg] [-header name value] [-host hostname:port]\n" 77092c3ac0cSinoguchi " [-ignore_err] [-index indexfile] [-issuer file]\n" 77192c3ac0cSinoguchi " [-ndays days] [-nmin minutes] [-no_cert_checks]\n" 77292c3ac0cSinoguchi " [-no_cert_verify] [-no_certs] [-no_chain] [-no_explicit]\n" 77392c3ac0cSinoguchi " [-no_intern] [-no_nonce] [-no_signature_verify] [-nonce]\n" 77492c3ac0cSinoguchi " [-noverify] [-nrequest number] [-out file] [-path path]\n" 77592c3ac0cSinoguchi " [-port portnum] [-req_text] [-reqin file] [-reqout file]\n" 77692c3ac0cSinoguchi " [-resp_key_id] [-resp_no_certs] [-resp_text] [-respin file]\n" 77792c3ac0cSinoguchi " [-respout file] [-rkey file] [-rother file] [-rsigner file]\n" 77892c3ac0cSinoguchi " [-serial num] [-sign_other file] [-signer file]\n" 77992c3ac0cSinoguchi " [-signkey file] [-status_age age] [-text]\n" 78092c3ac0cSinoguchi " [-timeout seconds] [-trust_other] [-url responder_url]\n" 78192c3ac0cSinoguchi " [-VAfile file] [-validity_period nsec] [-verify_other file]\n"); 78292c3ac0cSinoguchi fprintf(stderr, "\n"); 78392c3ac0cSinoguchi options_usage(ocsp_options); 78492c3ac0cSinoguchi fprintf(stderr, "\n"); 78592c3ac0cSinoguchi } 78692c3ac0cSinoguchi 787dab3f910Sjsing int 788dab3f910Sjsing ocsp_main(int argc, char **argv) 789dab3f910Sjsing { 790dab3f910Sjsing OCSP_RESPONSE *resp = NULL; 791dab3f910Sjsing OCSP_BASICRESP *bs = NULL; 792dab3f910Sjsing X509 *signer = NULL, *rsigner = NULL; 793dab3f910Sjsing EVP_PKEY *key = NULL, *rkey = NULL; 794dab3f910Sjsing BIO *acbio = NULL, *cbio = NULL; 795dab3f910Sjsing BIO *derbio = NULL; 796dab3f910Sjsing BIO *out = NULL; 797dab3f910Sjsing X509_STORE *store = NULL; 798dab3f910Sjsing STACK_OF(X509) *sign_other = NULL, *verify_other = NULL, *rother = NULL; 799dab3f910Sjsing int ret = 1; 800dab3f910Sjsing int badarg = 0; 801dab3f910Sjsing int i; 802dab3f910Sjsing X509 *rca_cert = NULL; 803dab3f910Sjsing CA_DB *rdb = NULL; 804dab3f910Sjsing 80551811eadSderaadt if (pledge("stdio cpath wpath rpath inet dns tty", NULL) == -1) { 8069bc487adSdoug perror("pledge"); 807e370f0eeSdoug exit(1); 808e370f0eeSdoug } 8099bc487adSdoug 810e7718adaStb memset(&cfg, 0, sizeof(cfg)); 811e7718adaStb cfg.accept_count = -1; 812e7718adaStb cfg.add_nonce = 1; 813e7718adaStb if ((cfg.ids = sk_OCSP_CERTID_new_null()) == NULL) 814dab3f910Sjsing goto end; 815e7718adaStb cfg.maxage = -1; 816e7718adaStb cfg.ndays = -1; 817e7718adaStb cfg.nsec = MAX_VALIDITY_PERIOD; 818e7718adaStb cfg.req_timeout = -1; 819e7718adaStb if ((cfg.reqnames = sk_OPENSSL_STRING_new_null()) == NULL) 820dab3f910Sjsing goto end; 821e7718adaStb cfg.use_ssl = -1; 82292c3ac0cSinoguchi 82392c3ac0cSinoguchi if (options_parse(argc, argv, ocsp_options, NULL, NULL) != 0) { 824e7718adaStb if (cfg.no_usage) 825dab3f910Sjsing goto end; 826dab3f910Sjsing else 827dab3f910Sjsing badarg = 1; 828dab3f910Sjsing } 829dab3f910Sjsing 830dab3f910Sjsing /* Have we anything to do? */ 831e7718adaStb if (!cfg.req && !cfg.reqin && !cfg.respin && 832e7718adaStb !(cfg.port && cfg.ridx_filename)) 833dab3f910Sjsing badarg = 1; 834dab3f910Sjsing 835dab3f910Sjsing if (badarg) { 83692c3ac0cSinoguchi ocsp_usage(); 837dab3f910Sjsing goto end; 838dab3f910Sjsing } 839e7718adaStb if (cfg.outfile) 840e7718adaStb out = BIO_new_file(cfg.outfile, "w"); 841dab3f910Sjsing else 842dab3f910Sjsing out = BIO_new_fp(stdout, BIO_NOCLOSE); 843dab3f910Sjsing 844dab3f910Sjsing if (!out) { 845dab3f910Sjsing BIO_printf(bio_err, "Error opening output file\n"); 846dab3f910Sjsing goto end; 847dab3f910Sjsing } 848e7718adaStb if (!cfg.req && (cfg.add_nonce != 2)) 849e7718adaStb cfg.add_nonce = 0; 850dab3f910Sjsing 851e7718adaStb if (!cfg.req && cfg.reqin) { 852e7718adaStb derbio = BIO_new_file(cfg.reqin, "rb"); 853dab3f910Sjsing if (!derbio) { 854bc14ef1fSinoguchi BIO_printf(bio_err, 855bc14ef1fSinoguchi "Error Opening OCSP request file\n"); 856dab3f910Sjsing goto end; 857dab3f910Sjsing } 858e7718adaStb cfg.req = d2i_OCSP_REQUEST_bio(derbio, NULL); 859dab3f910Sjsing BIO_free(derbio); 860e7718adaStb if (!cfg.req) { 861dab3f910Sjsing BIO_printf(bio_err, "Error reading OCSP request\n"); 862dab3f910Sjsing goto end; 863dab3f910Sjsing } 864dab3f910Sjsing } 865e7718adaStb if (!cfg.req && cfg.port) { 866e7718adaStb acbio = init_responder(cfg.port); 867dab3f910Sjsing if (!acbio) 868dab3f910Sjsing goto end; 869dab3f910Sjsing } 870e7718adaStb if (cfg.rsignfile && !rdb) { 871e7718adaStb if (!cfg.rkeyfile) 872e7718adaStb cfg.rkeyfile = cfg.rsignfile; 873e7718adaStb rsigner = load_cert(bio_err, cfg.rsignfile, FORMAT_PEM, 8745284dfeaSbcook NULL, "responder certificate"); 875dab3f910Sjsing if (!rsigner) { 876bc14ef1fSinoguchi BIO_printf(bio_err, 877bc14ef1fSinoguchi "Error loading responder certificate\n"); 878dab3f910Sjsing goto end; 879dab3f910Sjsing } 880e7718adaStb rca_cert = load_cert(bio_err, cfg.rca_filename, 881bc14ef1fSinoguchi FORMAT_PEM, NULL, "CA certificate"); 882e7718adaStb if (cfg.rcertfile) { 883e7718adaStb rother = load_certs(bio_err, cfg.rcertfile, 884bc14ef1fSinoguchi FORMAT_PEM, NULL, "responder other certificates"); 885dab3f910Sjsing if (!rother) 886dab3f910Sjsing goto end; 887dab3f910Sjsing } 888e7718adaStb rkey = load_key(bio_err, cfg.rkeyfile, FORMAT_PEM, 0, 889bc14ef1fSinoguchi NULL, "responder private key"); 890dab3f910Sjsing if (!rkey) 891dab3f910Sjsing goto end; 892dab3f910Sjsing } 893dab3f910Sjsing if (acbio) 894dab3f910Sjsing BIO_printf(bio_err, "Waiting for OCSP client connections...\n"); 895dab3f910Sjsing 896dab3f910Sjsing redo_accept: 897dab3f910Sjsing 898dab3f910Sjsing if (acbio) { 899e7718adaStb if (!do_responder(&cfg.req, &cbio, acbio, 900e7718adaStb cfg.port)) 901dab3f910Sjsing goto end; 902e7718adaStb if (!cfg.req) { 903bc14ef1fSinoguchi resp = OCSP_response_create( 904bc14ef1fSinoguchi OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, NULL); 905dab3f910Sjsing send_ocsp_response(cbio, resp); 906dab3f910Sjsing goto done_resp; 907dab3f910Sjsing } 908dab3f910Sjsing } 909e7718adaStb if (!cfg.req && 910e7718adaStb (cfg.signfile || cfg.reqout || cfg.host || 911e7718adaStb cfg.add_nonce || cfg.ridx_filename)) { 912bc14ef1fSinoguchi BIO_printf(bio_err, 913bc14ef1fSinoguchi "Need an OCSP request for this operation!\n"); 914dab3f910Sjsing goto end; 915dab3f910Sjsing } 916e7718adaStb if (cfg.req && cfg.add_nonce) 917e7718adaStb OCSP_request_add1_nonce(cfg.req, NULL, -1); 918dab3f910Sjsing 919e7718adaStb if (cfg.signfile) { 920e7718adaStb if (!cfg.keyfile) 921e7718adaStb cfg.keyfile = cfg.signfile; 922e7718adaStb signer = load_cert(bio_err, cfg.signfile, FORMAT_PEM, 9235284dfeaSbcook NULL, "signer certificate"); 924dab3f910Sjsing if (!signer) { 925bc14ef1fSinoguchi BIO_printf(bio_err, 926bc14ef1fSinoguchi "Error loading signer certificate\n"); 927dab3f910Sjsing goto end; 928dab3f910Sjsing } 929e7718adaStb if (cfg.sign_certfile) { 930bc14ef1fSinoguchi sign_other = load_certs(bio_err, 931e7718adaStb cfg.sign_certfile, FORMAT_PEM, NULL, 932bc14ef1fSinoguchi "signer certificates"); 933dab3f910Sjsing if (!sign_other) 934dab3f910Sjsing goto end; 935dab3f910Sjsing } 936e7718adaStb key = load_key(bio_err, cfg.keyfile, FORMAT_PEM, 0, 937bc14ef1fSinoguchi NULL, "signer private key"); 938dab3f910Sjsing if (!key) 939dab3f910Sjsing goto end; 940dab3f910Sjsing 941e7718adaStb if (!OCSP_request_sign(cfg.req, signer, key, NULL, 942e7718adaStb sign_other, cfg.sign_flags)) { 943dab3f910Sjsing BIO_printf(bio_err, "Error signing OCSP request\n"); 944dab3f910Sjsing goto end; 945dab3f910Sjsing } 946dab3f910Sjsing } 947e7718adaStb if (cfg.req_text && cfg.req) 948e7718adaStb OCSP_REQUEST_print(out, cfg.req, 0); 949dab3f910Sjsing 950e7718adaStb if (cfg.reqout) { 951e7718adaStb derbio = BIO_new_file(cfg.reqout, "wb"); 952dab3f910Sjsing if (!derbio) { 953bc14ef1fSinoguchi BIO_printf(bio_err, "Error opening file %s\n", 954e7718adaStb cfg.reqout); 955dab3f910Sjsing goto end; 956dab3f910Sjsing } 957e7718adaStb i2d_OCSP_REQUEST_bio(derbio, cfg.req); 958dab3f910Sjsing BIO_free(derbio); 959dab3f910Sjsing } 960e7718adaStb if (cfg.ridx_filename && (!rkey || !rsigner || !rca_cert)) { 961bc14ef1fSinoguchi BIO_printf(bio_err, 962bc14ef1fSinoguchi "Need a responder certificate, key and CA for this operation!\n"); 963dab3f910Sjsing goto end; 964dab3f910Sjsing } 965e7718adaStb if (cfg.ridx_filename && !rdb) { 966e7718adaStb rdb = load_index(cfg.ridx_filename, NULL); 967dab3f910Sjsing if (!rdb) 968dab3f910Sjsing goto end; 969dab3f910Sjsing if (!index_index(rdb)) 970dab3f910Sjsing goto end; 971dab3f910Sjsing } 972dab3f910Sjsing if (rdb) { 973e7718adaStb i = make_ocsp_response(&resp, cfg.req, rdb, rca_cert, 974e7718adaStb rsigner, rkey, rother, cfg.rflags, 975e7718adaStb cfg.nmin, cfg.ndays); 976dab3f910Sjsing if (cbio) 977dab3f910Sjsing send_ocsp_response(cbio, resp); 978e7718adaStb } else if (cfg.host) { 979e7718adaStb resp = process_responder(bio_err, cfg.req, 980e7718adaStb cfg.host, 981e7718adaStb cfg.path ? cfg.path : "/", 982e7718adaStb cfg.port, cfg.use_ssl, cfg.headers, 983e7718adaStb cfg.req_timeout); 984dab3f910Sjsing if (!resp) 985dab3f910Sjsing goto end; 986e7718adaStb } else if (cfg.respin) { 987e7718adaStb derbio = BIO_new_file(cfg.respin, "rb"); 988dab3f910Sjsing if (!derbio) { 989bc14ef1fSinoguchi BIO_printf(bio_err, 990bc14ef1fSinoguchi "Error Opening OCSP response file\n"); 991dab3f910Sjsing goto end; 992dab3f910Sjsing } 993dab3f910Sjsing resp = d2i_OCSP_RESPONSE_bio(derbio, NULL); 994dab3f910Sjsing BIO_free(derbio); 995dab3f910Sjsing if (!resp) { 996dab3f910Sjsing BIO_printf(bio_err, "Error reading OCSP response\n"); 997dab3f910Sjsing goto end; 998dab3f910Sjsing } 999dab3f910Sjsing } else { 1000dab3f910Sjsing ret = 0; 1001dab3f910Sjsing goto end; 1002dab3f910Sjsing } 1003dab3f910Sjsing 1004dab3f910Sjsing done_resp: 1005dab3f910Sjsing 1006e7718adaStb if (cfg.respout) { 1007e7718adaStb derbio = BIO_new_file(cfg.respout, "wb"); 1008dab3f910Sjsing if (!derbio) { 1009bc14ef1fSinoguchi BIO_printf(bio_err, "Error opening file %s\n", 1010e7718adaStb cfg.respout); 1011dab3f910Sjsing goto end; 1012dab3f910Sjsing } 1013dab3f910Sjsing i2d_OCSP_RESPONSE_bio(derbio, resp); 1014dab3f910Sjsing BIO_free(derbio); 1015dab3f910Sjsing } 1016dab3f910Sjsing i = OCSP_response_status(resp); 1017dab3f910Sjsing 1018dab3f910Sjsing if (i != OCSP_RESPONSE_STATUS_SUCCESSFUL) { 1019c48dfb0cSbeck BIO_printf(bio_err, "Responder Error: %s (%d)\n", 1020dab3f910Sjsing OCSP_response_status_str(i), i); 1021e7718adaStb if (cfg.ignore_err) 1022dab3f910Sjsing goto redo_accept; 1023c48dfb0cSbeck ret = 1; 1024dab3f910Sjsing goto end; 1025dab3f910Sjsing } 1026e7718adaStb if (cfg.resp_text) 1027dab3f910Sjsing OCSP_RESPONSE_print(out, resp, 0); 1028dab3f910Sjsing 1029dab3f910Sjsing /* If running as responder don't verify our own response */ 1030dab3f910Sjsing if (cbio) { 1031e7718adaStb if (cfg.accept_count > 0) 1032e7718adaStb cfg.accept_count--; 1033dab3f910Sjsing /* Redo if more connections needed */ 1034e7718adaStb if (cfg.accept_count) { 1035dab3f910Sjsing BIO_free_all(cbio); 1036dab3f910Sjsing cbio = NULL; 1037e7718adaStb OCSP_REQUEST_free(cfg.req); 1038e7718adaStb cfg.req = NULL; 1039dab3f910Sjsing OCSP_RESPONSE_free(resp); 1040dab3f910Sjsing resp = NULL; 1041dab3f910Sjsing goto redo_accept; 1042dab3f910Sjsing } 1043dab3f910Sjsing goto end; 1044dab3f910Sjsing } 1045dab3f910Sjsing if (!store) 1046e7718adaStb store = setup_verify(bio_err, cfg.CAfile, 1047e7718adaStb cfg.CApath); 1048dab3f910Sjsing if (!store) 1049dab3f910Sjsing goto end; 1050e7718adaStb if (cfg.verify_certfile) { 1051e7718adaStb verify_other = load_certs(bio_err, cfg.verify_certfile, 1052bc14ef1fSinoguchi FORMAT_PEM, NULL, "validator certificate"); 1053dab3f910Sjsing if (!verify_other) 1054dab3f910Sjsing goto end; 1055dab3f910Sjsing } 1056dab3f910Sjsing bs = OCSP_response_get1_basic(resp); 1057dab3f910Sjsing 1058dab3f910Sjsing if (!bs) { 1059dab3f910Sjsing BIO_printf(bio_err, "Error parsing response\n"); 1060dab3f910Sjsing goto end; 1061dab3f910Sjsing } 1062e7718adaStb if (!cfg.noverify) { 1063e7718adaStb if (cfg.req && 1064e7718adaStb ((i = OCSP_check_nonce(cfg.req, bs)) <= 0)) { 1065bc14ef1fSinoguchi if (i == -1) { 1066bc14ef1fSinoguchi BIO_printf(bio_err, 1067bc14ef1fSinoguchi "WARNING: no nonce in response\n"); 1068bc14ef1fSinoguchi } else { 1069dab3f910Sjsing BIO_printf(bio_err, "Nonce Verify error\n"); 1070dab3f910Sjsing goto end; 1071dab3f910Sjsing } 1072dab3f910Sjsing } 1073bc14ef1fSinoguchi i = OCSP_basic_verify(bs, verify_other, store, 1074e7718adaStb cfg.verify_flags); 1075dab3f910Sjsing if (i < 0) 1076dab3f910Sjsing i = OCSP_basic_verify(bs, NULL, store, 0); 1077dab3f910Sjsing 1078dab3f910Sjsing if (i <= 0) { 1079dab3f910Sjsing BIO_printf(bio_err, "Response Verify Failure\n"); 1080dab3f910Sjsing ERR_print_errors(bio_err); 1081bc14ef1fSinoguchi } else { 1082dab3f910Sjsing BIO_printf(bio_err, "Response verify OK\n"); 1083dab3f910Sjsing } 1084bc14ef1fSinoguchi } 1085e7718adaStb if (!print_ocsp_summary(out, bs, cfg.req, cfg.reqnames, 1086e7718adaStb cfg.ids, cfg.nsec, cfg.maxage)) 1087dab3f910Sjsing goto end; 1088dab3f910Sjsing 1089dab3f910Sjsing ret = 0; 1090dab3f910Sjsing 1091dab3f910Sjsing end: 1092dab3f910Sjsing ERR_print_errors(bio_err); 1093dab3f910Sjsing X509_free(signer); 1094dab3f910Sjsing X509_STORE_free(store); 1095dab3f910Sjsing EVP_PKEY_free(key); 1096dab3f910Sjsing EVP_PKEY_free(rkey); 1097e7718adaStb X509_free(cfg.issuer); 1098e7718adaStb X509_free(cfg.cert); 1099dab3f910Sjsing X509_free(rsigner); 1100dab3f910Sjsing X509_free(rca_cert); 1101dab3f910Sjsing free_index(rdb); 1102dab3f910Sjsing BIO_free_all(cbio); 1103dab3f910Sjsing BIO_free_all(acbio); 1104dab3f910Sjsing BIO_free(out); 1105e7718adaStb OCSP_REQUEST_free(cfg.req); 1106dab3f910Sjsing OCSP_RESPONSE_free(resp); 1107dab3f910Sjsing OCSP_BASICRESP_free(bs); 1108e7718adaStb sk_OPENSSL_STRING_free(cfg.reqnames); 1109e7718adaStb sk_OCSP_CERTID_free(cfg.ids); 1110dab3f910Sjsing sk_X509_pop_free(sign_other, X509_free); 1111dab3f910Sjsing sk_X509_pop_free(verify_other, X509_free); 1112e7718adaStb sk_CONF_VALUE_pop_free(cfg.headers, X509V3_conf_free); 1113dab3f910Sjsing 1114e7718adaStb if (cfg.use_ssl != -1) { 1115e7718adaStb free(cfg.host); 1116e7718adaStb free(cfg.port); 1117e7718adaStb free(cfg.path); 1118dab3f910Sjsing } 1119dab3f910Sjsing return (ret); 1120dab3f910Sjsing } 1121dab3f910Sjsing 1122dab3f910Sjsing static int 1123bc14ef1fSinoguchi add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, const EVP_MD *cert_id_md, 1124bc14ef1fSinoguchi X509 *issuer, STACK_OF(OCSP_CERTID) *ids) 1125dab3f910Sjsing { 1126dab3f910Sjsing OCSP_CERTID *id; 1127bc14ef1fSinoguchi 1128dab3f910Sjsing if (!issuer) { 1129dab3f910Sjsing BIO_printf(bio_err, "No issuer certificate specified\n"); 1130dab3f910Sjsing return 0; 1131dab3f910Sjsing } 1132dab3f910Sjsing if (!*req) 1133dab3f910Sjsing *req = OCSP_REQUEST_new(); 1134dab3f910Sjsing if (!*req) 1135dab3f910Sjsing goto err; 1136dab3f910Sjsing id = OCSP_cert_to_id(cert_id_md, cert, issuer); 1137dab3f910Sjsing if (!id || !sk_OCSP_CERTID_push(ids, id)) 1138dab3f910Sjsing goto err; 1139dab3f910Sjsing if (!OCSP_request_add0_id(*req, id)) 1140dab3f910Sjsing goto err; 1141dab3f910Sjsing return 1; 1142dab3f910Sjsing 1143dab3f910Sjsing err: 1144dab3f910Sjsing BIO_printf(bio_err, "Error Creating OCSP request\n"); 1145dab3f910Sjsing return 0; 1146dab3f910Sjsing } 1147dab3f910Sjsing 1148dab3f910Sjsing static int 1149bc14ef1fSinoguchi add_ocsp_serial(OCSP_REQUEST **req, char *serial, const EVP_MD *cert_id_md, 1150bc14ef1fSinoguchi X509 *issuer, STACK_OF(OCSP_CERTID) *ids) 1151dab3f910Sjsing { 1152dab3f910Sjsing OCSP_CERTID *id; 1153dab3f910Sjsing X509_NAME *iname; 1154dab3f910Sjsing ASN1_BIT_STRING *ikey; 1155dab3f910Sjsing ASN1_INTEGER *sno; 1156bc14ef1fSinoguchi 1157dab3f910Sjsing if (!issuer) { 1158dab3f910Sjsing BIO_printf(bio_err, "No issuer certificate specified\n"); 1159dab3f910Sjsing return 0; 1160dab3f910Sjsing } 1161dab3f910Sjsing if (!*req) 1162dab3f910Sjsing *req = OCSP_REQUEST_new(); 1163dab3f910Sjsing if (!*req) 1164dab3f910Sjsing goto err; 1165dab3f910Sjsing iname = X509_get_subject_name(issuer); 1166dab3f910Sjsing ikey = X509_get0_pubkey_bitstr(issuer); 1167dab3f910Sjsing sno = s2i_ASN1_INTEGER(NULL, serial); 1168dab3f910Sjsing if (!sno) { 1169bc14ef1fSinoguchi BIO_printf(bio_err, "Error converting serial number %s\n", 1170bc14ef1fSinoguchi serial); 1171dab3f910Sjsing return 0; 1172dab3f910Sjsing } 1173dab3f910Sjsing id = OCSP_cert_id_new(cert_id_md, iname, ikey, sno); 1174dab3f910Sjsing ASN1_INTEGER_free(sno); 1175dab3f910Sjsing if (!id || !sk_OCSP_CERTID_push(ids, id)) 1176dab3f910Sjsing goto err; 1177dab3f910Sjsing if (!OCSP_request_add0_id(*req, id)) 1178dab3f910Sjsing goto err; 1179dab3f910Sjsing return 1; 1180dab3f910Sjsing 1181dab3f910Sjsing err: 1182dab3f910Sjsing BIO_printf(bio_err, "Error Creating OCSP request\n"); 1183dab3f910Sjsing return 0; 1184dab3f910Sjsing } 1185dab3f910Sjsing 1186dab3f910Sjsing static int 1187dab3f910Sjsing print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req, 1188bc14ef1fSinoguchi STACK_OF(OPENSSL_STRING) *names, STACK_OF(OCSP_CERTID) *ids, long nsec, 1189dab3f910Sjsing long maxage) 1190dab3f910Sjsing { 1191dab3f910Sjsing OCSP_CERTID *id; 1192dab3f910Sjsing char *name; 1193dab3f910Sjsing int i; 1194dab3f910Sjsing int status, reason; 1195dab3f910Sjsing 1196dab3f910Sjsing ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; 1197dab3f910Sjsing 1198bc14ef1fSinoguchi if (!bs || !req || !sk_OPENSSL_STRING_num(names) || 1199bc14ef1fSinoguchi !sk_OCSP_CERTID_num(ids)) 1200dab3f910Sjsing return 1; 1201dab3f910Sjsing 1202dab3f910Sjsing for (i = 0; i < sk_OCSP_CERTID_num(ids); i++) { 1203dab3f910Sjsing id = sk_OCSP_CERTID_value(ids, i); 1204dab3f910Sjsing name = sk_OPENSSL_STRING_value(names, i); 1205dab3f910Sjsing BIO_printf(out, "%s: ", name); 1206dab3f910Sjsing 1207dab3f910Sjsing if (!OCSP_resp_find_status(bs, id, &status, &reason, 1208dab3f910Sjsing &rev, &thisupd, &nextupd)) { 1209dab3f910Sjsing BIO_puts(out, "ERROR: No Status found.\n"); 1210dab3f910Sjsing continue; 1211dab3f910Sjsing } 1212dab3f910Sjsing /* 1213dab3f910Sjsing * Check validity: if invalid write to output BIO so we know 1214dab3f910Sjsing * which response this refers to. 1215dab3f910Sjsing */ 1216dab3f910Sjsing if (!OCSP_check_validity(thisupd, nextupd, nsec, maxage)) { 1217dab3f910Sjsing BIO_puts(out, "WARNING: Status times invalid.\n"); 1218dab3f910Sjsing ERR_print_errors(out); 1219dab3f910Sjsing } 1220dab3f910Sjsing BIO_printf(out, "%s\n", OCSP_cert_status_str(status)); 1221dab3f910Sjsing 1222dab3f910Sjsing BIO_puts(out, "\tThis Update: "); 1223dab3f910Sjsing ASN1_GENERALIZEDTIME_print(out, thisupd); 1224dab3f910Sjsing BIO_puts(out, "\n"); 1225dab3f910Sjsing 1226dab3f910Sjsing if (nextupd) { 1227dab3f910Sjsing BIO_puts(out, "\tNext Update: "); 1228dab3f910Sjsing ASN1_GENERALIZEDTIME_print(out, nextupd); 1229dab3f910Sjsing BIO_puts(out, "\n"); 1230dab3f910Sjsing } 1231dab3f910Sjsing if (status != V_OCSP_CERTSTATUS_REVOKED) 1232dab3f910Sjsing continue; 1233dab3f910Sjsing 1234dab3f910Sjsing if (reason != -1) 1235dab3f910Sjsing BIO_printf(out, "\tReason: %s\n", 1236dab3f910Sjsing OCSP_crl_reason_str(reason)); 1237dab3f910Sjsing 1238dab3f910Sjsing BIO_puts(out, "\tRevocation Time: "); 1239dab3f910Sjsing ASN1_GENERALIZEDTIME_print(out, rev); 1240dab3f910Sjsing BIO_puts(out, "\n"); 1241dab3f910Sjsing } 1242dab3f910Sjsing 1243dab3f910Sjsing return 1; 1244dab3f910Sjsing } 1245dab3f910Sjsing 1246dab3f910Sjsing 1247dab3f910Sjsing static int 1248dab3f910Sjsing make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req, CA_DB *db, 1249bc14ef1fSinoguchi X509 *ca, X509 *rcert, EVP_PKEY *rkey, STACK_OF(X509) *rother, 1250bc14ef1fSinoguchi unsigned long flags, int nmin, int ndays) 1251dab3f910Sjsing { 1252dab3f910Sjsing ASN1_TIME *thisupd = NULL, *nextupd = NULL; 1253dab3f910Sjsing OCSP_CERTID *cid, *ca_id = NULL; 1254dab3f910Sjsing OCSP_BASICRESP *bs = NULL; 1255dab3f910Sjsing int i, id_count, ret = 1; 1256dab3f910Sjsing 1257dab3f910Sjsing id_count = OCSP_request_onereq_count(req); 1258dab3f910Sjsing 1259dab3f910Sjsing if (id_count <= 0) { 1260bc14ef1fSinoguchi *resp = OCSP_response_create( 1261bc14ef1fSinoguchi OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, NULL); 1262dab3f910Sjsing goto end; 1263dab3f910Sjsing } 1264dab3f910Sjsing bs = OCSP_BASICRESP_new(); 1265dab3f910Sjsing thisupd = X509_gmtime_adj(NULL, 0); 1266dab3f910Sjsing if (ndays != -1) 1267dab3f910Sjsing nextupd = X509_gmtime_adj(NULL, nmin * 60 + ndays * 3600 * 24); 1268dab3f910Sjsing 1269dab3f910Sjsing /* Examine each certificate id in the request */ 1270dab3f910Sjsing for (i = 0; i < id_count; i++) { 1271dab3f910Sjsing OCSP_ONEREQ *one; 1272dab3f910Sjsing ASN1_INTEGER *serial; 1273dab3f910Sjsing char **inf; 1274dab3f910Sjsing ASN1_OBJECT *cert_id_md_oid; 1275dab3f910Sjsing const EVP_MD *cert_id_md; 1276dab3f910Sjsing one = OCSP_request_onereq_get0(req, i); 1277dab3f910Sjsing cid = OCSP_onereq_get0_id(one); 1278dab3f910Sjsing 1279dab3f910Sjsing OCSP_id_get0_info(NULL, &cert_id_md_oid, NULL, NULL, cid); 1280dab3f910Sjsing 1281dab3f910Sjsing cert_id_md = EVP_get_digestbyobj(cert_id_md_oid); 1282dab3f910Sjsing if (!cert_id_md) { 1283bc14ef1fSinoguchi *resp = OCSP_response_create( 1284bc14ef1fSinoguchi OCSP_RESPONSE_STATUS_INTERNALERROR, NULL); 1285dab3f910Sjsing goto end; 1286dab3f910Sjsing } 1287dab3f910Sjsing OCSP_CERTID_free(ca_id); 1288dab3f910Sjsing ca_id = OCSP_cert_to_id(cert_id_md, NULL, ca); 1289dab3f910Sjsing 1290dab3f910Sjsing /* Is this request about our CA? */ 1291dab3f910Sjsing if (OCSP_id_issuer_cmp(ca_id, cid)) { 1292dab3f910Sjsing OCSP_basic_add1_status(bs, cid, 1293bc14ef1fSinoguchi V_OCSP_CERTSTATUS_UNKNOWN, 0, NULL, 1294dab3f910Sjsing thisupd, nextupd); 1295dab3f910Sjsing continue; 1296dab3f910Sjsing } 1297dab3f910Sjsing OCSP_id_get0_info(NULL, NULL, NULL, &serial, cid); 1298dab3f910Sjsing inf = lookup_serial(db, serial); 1299bc14ef1fSinoguchi if (!inf) { 1300dab3f910Sjsing OCSP_basic_add1_status(bs, cid, 1301bc14ef1fSinoguchi V_OCSP_CERTSTATUS_UNKNOWN, 0, NULL, 1302dab3f910Sjsing thisupd, nextupd); 1303bc14ef1fSinoguchi } else if (inf[DB_type][0] == DB_TYPE_VAL) { 1304dab3f910Sjsing OCSP_basic_add1_status(bs, cid, 1305bc14ef1fSinoguchi V_OCSP_CERTSTATUS_GOOD, 0, NULL, 1306dab3f910Sjsing thisupd, nextupd); 1307bc14ef1fSinoguchi } else if (inf[DB_type][0] == DB_TYPE_REV) { 1308dab3f910Sjsing ASN1_OBJECT *inst = NULL; 1309dab3f910Sjsing ASN1_TIME *revtm = NULL; 1310dab3f910Sjsing ASN1_GENERALIZEDTIME *invtm = NULL; 1311dab3f910Sjsing OCSP_SINGLERESP *single; 1312dab3f910Sjsing int reason = -1; 1313bc14ef1fSinoguchi 1314bc14ef1fSinoguchi unpack_revinfo(&revtm, &reason, &inst, &invtm, 1315bc14ef1fSinoguchi inf[DB_rev_date]); 1316dab3f910Sjsing single = OCSP_basic_add1_status(bs, cid, 1317dab3f910Sjsing V_OCSP_CERTSTATUS_REVOKED, 1318dab3f910Sjsing reason, revtm, 1319dab3f910Sjsing thisupd, nextupd); 1320dab3f910Sjsing if (invtm) 1321bc14ef1fSinoguchi OCSP_SINGLERESP_add1_ext_i2d(single, 1322bc14ef1fSinoguchi NID_invalidity_date, invtm, 0, 0); 1323dab3f910Sjsing else if (inst) 1324bc14ef1fSinoguchi OCSP_SINGLERESP_add1_ext_i2d(single, 1325bc14ef1fSinoguchi NID_hold_instruction_code, inst, 0, 0); 1326dab3f910Sjsing ASN1_OBJECT_free(inst); 1327dab3f910Sjsing ASN1_TIME_free(revtm); 1328dab3f910Sjsing ASN1_GENERALIZEDTIME_free(invtm); 1329dab3f910Sjsing } 1330dab3f910Sjsing } 1331dab3f910Sjsing 1332dab3f910Sjsing OCSP_copy_nonce(bs, req); 1333dab3f910Sjsing 1334dab3f910Sjsing OCSP_basic_sign(bs, rcert, rkey, NULL, rother, flags); 1335dab3f910Sjsing 1336dab3f910Sjsing *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_SUCCESSFUL, bs); 1337dab3f910Sjsing 1338dab3f910Sjsing end: 1339dab3f910Sjsing ASN1_TIME_free(thisupd); 1340dab3f910Sjsing ASN1_TIME_free(nextupd); 1341dab3f910Sjsing OCSP_CERTID_free(ca_id); 1342dab3f910Sjsing OCSP_BASICRESP_free(bs); 1343dab3f910Sjsing return ret; 1344dab3f910Sjsing } 1345dab3f910Sjsing 1346dab3f910Sjsing static char ** 1347dab3f910Sjsing lookup_serial(CA_DB *db, ASN1_INTEGER *ser) 1348dab3f910Sjsing { 1349dab3f910Sjsing int i; 1350dab3f910Sjsing BIGNUM *bn = NULL; 1351dab3f910Sjsing char *itmp, *row[DB_NUMBER], **rrow; 1352bc14ef1fSinoguchi 1353dab3f910Sjsing for (i = 0; i < DB_NUMBER; i++) 1354dab3f910Sjsing row[i] = NULL; 1355dab3f910Sjsing bn = ASN1_INTEGER_to_BN(ser, NULL); 1356dab3f910Sjsing OPENSSL_assert(bn); /* FIXME: should report an error at this 1357dab3f910Sjsing * point and abort */ 1358dab3f910Sjsing if (BN_is_zero(bn)) 1359dab3f910Sjsing itmp = strdup("00"); 1360dab3f910Sjsing else 1361dab3f910Sjsing itmp = BN_bn2hex(bn); 1362dab3f910Sjsing row[DB_serial] = itmp; 1363dab3f910Sjsing BN_free(bn); 1364dab3f910Sjsing rrow = TXT_DB_get_by_index(db->db, DB_serial, row); 1365dab3f910Sjsing free(itmp); 1366dab3f910Sjsing return rrow; 1367dab3f910Sjsing } 1368dab3f910Sjsing 1369dab3f910Sjsing /* Quick and dirty OCSP server: read in and parse input request */ 1370dab3f910Sjsing 1371dab3f910Sjsing static BIO * 1372dab3f910Sjsing init_responder(char *port) 1373dab3f910Sjsing { 1374dab3f910Sjsing BIO *acbio = NULL, *bufbio = NULL; 1375bc14ef1fSinoguchi 1376dab3f910Sjsing bufbio = BIO_new(BIO_f_buffer()); 1377dab3f910Sjsing if (!bufbio) 1378dab3f910Sjsing goto err; 1379dab3f910Sjsing acbio = BIO_new_accept(port); 1380dab3f910Sjsing if (!acbio) 1381dab3f910Sjsing goto err; 138284decd30Sbeck BIO_set_bind_mode(acbio, BIO_BIND_REUSEADDR); 1383dab3f910Sjsing BIO_set_accept_bios(acbio, bufbio); 1384dab3f910Sjsing bufbio = NULL; 1385dab3f910Sjsing 1386dab3f910Sjsing if (BIO_do_accept(acbio) <= 0) { 1387dab3f910Sjsing BIO_printf(bio_err, "Error setting up accept BIO\n"); 1388dab3f910Sjsing ERR_print_errors(bio_err); 1389dab3f910Sjsing goto err; 1390dab3f910Sjsing } 1391dab3f910Sjsing return acbio; 1392dab3f910Sjsing 1393dab3f910Sjsing err: 1394dab3f910Sjsing BIO_free_all(acbio); 1395dab3f910Sjsing BIO_free(bufbio); 1396dab3f910Sjsing return NULL; 1397dab3f910Sjsing } 1398dab3f910Sjsing 1399dab3f910Sjsing static int 1400dab3f910Sjsing do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, char *port) 1401dab3f910Sjsing { 1402dab3f910Sjsing int have_post = 0, len; 1403dab3f910Sjsing OCSP_REQUEST *req = NULL; 1404dab3f910Sjsing char inbuf[1024]; 1405dab3f910Sjsing BIO *cbio = NULL; 1406dab3f910Sjsing 1407dab3f910Sjsing if (BIO_do_accept(acbio) <= 0) { 1408dab3f910Sjsing BIO_printf(bio_err, "Error accepting connection\n"); 1409dab3f910Sjsing ERR_print_errors(bio_err); 1410dab3f910Sjsing return 0; 1411dab3f910Sjsing } 1412dab3f910Sjsing cbio = BIO_pop(acbio); 1413dab3f910Sjsing *pcbio = cbio; 1414dab3f910Sjsing 1415dab3f910Sjsing for (;;) { 1416dab3f910Sjsing len = BIO_gets(cbio, inbuf, sizeof inbuf); 1417dab3f910Sjsing if (len <= 0) 1418dab3f910Sjsing return 1; 1419dab3f910Sjsing /* Look for "POST" signalling start of query */ 1420dab3f910Sjsing if (!have_post) { 1421dab3f910Sjsing if (strncmp(inbuf, "POST", 4)) { 1422dab3f910Sjsing BIO_printf(bio_err, "Invalid request\n"); 1423dab3f910Sjsing return 1; 1424dab3f910Sjsing } 1425dab3f910Sjsing have_post = 1; 1426dab3f910Sjsing } 1427dab3f910Sjsing /* Look for end of headers */ 1428dab3f910Sjsing if ((inbuf[0] == '\r') || (inbuf[0] == '\n')) 1429dab3f910Sjsing break; 1430dab3f910Sjsing } 1431dab3f910Sjsing 1432dab3f910Sjsing /* Try to read OCSP request */ 1433dab3f910Sjsing 1434dab3f910Sjsing req = d2i_OCSP_REQUEST_bio(cbio, NULL); 1435dab3f910Sjsing 1436dab3f910Sjsing if (!req) { 1437dab3f910Sjsing BIO_printf(bio_err, "Error parsing OCSP request\n"); 1438dab3f910Sjsing ERR_print_errors(bio_err); 1439dab3f910Sjsing } 1440dab3f910Sjsing *preq = req; 1441dab3f910Sjsing 1442dab3f910Sjsing return 1; 1443dab3f910Sjsing } 1444dab3f910Sjsing 1445dab3f910Sjsing static int 1446dab3f910Sjsing send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp) 1447dab3f910Sjsing { 1448dab3f910Sjsing static const char http_resp[] = 1449dab3f910Sjsing "HTTP/1.0 200 OK\r\nContent-type: application/ocsp-response\r\n" 1450dab3f910Sjsing "Content-Length: %d\r\n\r\n"; 1451bc14ef1fSinoguchi 1452dab3f910Sjsing if (!cbio) 1453dab3f910Sjsing return 0; 1454dab3f910Sjsing BIO_printf(cbio, http_resp, i2d_OCSP_RESPONSE(resp, NULL)); 1455dab3f910Sjsing i2d_OCSP_RESPONSE_bio(cbio, resp); 1456dab3f910Sjsing (void) BIO_flush(cbio); 1457dab3f910Sjsing return 1; 1458dab3f910Sjsing } 1459dab3f910Sjsing 1460dab3f910Sjsing static OCSP_RESPONSE * 1461bc14ef1fSinoguchi query_responder(BIO *err, BIO *cbio, char *path, STACK_OF(CONF_VALUE) *headers, 14627b609544Stb const char *host, OCSP_REQUEST *req, int req_timeout) 1463dab3f910Sjsing { 1464dab3f910Sjsing int fd; 1465dab3f910Sjsing int rv; 1466dab3f910Sjsing int i; 14677b609544Stb int have_host = 0; 1468dab3f910Sjsing OCSP_REQ_CTX *ctx = NULL; 1469dab3f910Sjsing OCSP_RESPONSE *rsp = NULL; 1470230ab7bfSderaadt struct pollfd pfd[1]; 1471dab3f910Sjsing 1472dab3f910Sjsing if (req_timeout != -1) 1473dab3f910Sjsing BIO_set_nbio(cbio, 1); 1474dab3f910Sjsing 1475dab3f910Sjsing rv = BIO_do_connect(cbio); 1476dab3f910Sjsing 1477dab3f910Sjsing if ((rv <= 0) && ((req_timeout == -1) || !BIO_should_retry(cbio))) { 1478dab3f910Sjsing BIO_puts(err, "Error connecting BIO\n"); 1479dab3f910Sjsing return NULL; 1480dab3f910Sjsing } 1481e8302d26Sderaadt if (BIO_get_fd(cbio, &fd) < 0) { 1482dab3f910Sjsing BIO_puts(err, "Can't get connection fd\n"); 1483dab3f910Sjsing goto err; 1484dab3f910Sjsing } 1485dab3f910Sjsing if (req_timeout != -1 && rv <= 0) { 1486230ab7bfSderaadt pfd[0].fd = fd; 1487230ab7bfSderaadt pfd[0].events = POLLOUT; 1488230ab7bfSderaadt rv = poll(pfd, 1, req_timeout * 1000); 1489dab3f910Sjsing if (rv == 0) { 1490dab3f910Sjsing BIO_puts(err, "Timeout on connect\n"); 1491dab3f910Sjsing return NULL; 1492dab3f910Sjsing } 1493230ab7bfSderaadt if (rv == -1) { 1494230ab7bfSderaadt BIO_puts(err, "Poll error\n"); 1495230ab7bfSderaadt return NULL; 1496230ab7bfSderaadt } 1497dab3f910Sjsing } 1498dab3f910Sjsing ctx = OCSP_sendreq_new(cbio, path, NULL, -1); 1499dab3f910Sjsing if (!ctx) 1500dab3f910Sjsing return NULL; 1501dab3f910Sjsing 1502dab3f910Sjsing for (i = 0; i < sk_CONF_VALUE_num(headers); i++) { 1503dab3f910Sjsing CONF_VALUE *hdr = sk_CONF_VALUE_value(headers, i); 15047b609544Stb if (strcasecmp("host", hdr->name) == 0) 15057b609544Stb have_host = 1; 1506dab3f910Sjsing if (!OCSP_REQ_CTX_add1_header(ctx, hdr->name, hdr->value)) 1507dab3f910Sjsing goto err; 1508dab3f910Sjsing } 1509dab3f910Sjsing 15107b609544Stb if (!have_host) { 15117b609544Stb if (!OCSP_REQ_CTX_add1_header(ctx, "Host", host)) 15127b609544Stb goto err; 15137b609544Stb } 15147b609544Stb 1515dab3f910Sjsing if (!OCSP_REQ_CTX_set1_req(ctx, req)) 1516dab3f910Sjsing goto err; 1517dab3f910Sjsing 1518dab3f910Sjsing for (;;) { 1519dab3f910Sjsing rv = OCSP_sendreq_nbio(&rsp, ctx); 1520dab3f910Sjsing if (rv != -1) 1521dab3f910Sjsing break; 1522dab3f910Sjsing if (req_timeout == -1) 1523dab3f910Sjsing continue; 1524230ab7bfSderaadt pfd[0].fd = fd; 1525bc14ef1fSinoguchi if (BIO_should_read(cbio)) { 1526230ab7bfSderaadt pfd[0].events = POLLIN; 1527bc14ef1fSinoguchi } else if (BIO_should_write(cbio)) { 1528230ab7bfSderaadt pfd[0].events = POLLOUT; 1529bc14ef1fSinoguchi } else { 1530dab3f910Sjsing BIO_puts(err, "Unexpected retry condition\n"); 1531dab3f910Sjsing goto err; 1532dab3f910Sjsing } 1533230ab7bfSderaadt rv = poll(pfd, 1, req_timeout * 1000); 1534dab3f910Sjsing if (rv == 0) { 1535dab3f910Sjsing BIO_puts(err, "Timeout on request\n"); 1536dab3f910Sjsing break; 1537dab3f910Sjsing } 1538230ab7bfSderaadt if (rv == -1 || (pfd[0].revents & (POLLERR|POLLNVAL))) { 1539230ab7bfSderaadt BIO_puts(err, "Poll error\n"); 1540dab3f910Sjsing break; 1541dab3f910Sjsing } 1542dab3f910Sjsing } 1543bc14ef1fSinoguchi 1544dab3f910Sjsing err: 1545dab3f910Sjsing OCSP_REQ_CTX_free(ctx); 1546dab3f910Sjsing return rsp; 1547dab3f910Sjsing } 1548dab3f910Sjsing 1549dab3f910Sjsing OCSP_RESPONSE * 1550bc14ef1fSinoguchi process_responder(BIO *err, OCSP_REQUEST *req, char *host, char *path, 1551bc14ef1fSinoguchi char *port, int use_ssl, STACK_OF(CONF_VALUE) *headers, int req_timeout) 1552dab3f910Sjsing { 1553dab3f910Sjsing BIO *cbio = NULL; 1554dab3f910Sjsing SSL_CTX *ctx = NULL; 1555dab3f910Sjsing OCSP_RESPONSE *resp = NULL; 1556bc14ef1fSinoguchi 1557dab3f910Sjsing cbio = BIO_new_connect(host); 1558dab3f910Sjsing if (!cbio) { 1559dab3f910Sjsing BIO_printf(err, "Error creating connect BIO\n"); 1560dab3f910Sjsing goto end; 1561dab3f910Sjsing } 1562dab3f910Sjsing if (port) 1563dab3f910Sjsing BIO_set_conn_port(cbio, port); 1564dab3f910Sjsing if (use_ssl == 1) { 1565dab3f910Sjsing BIO *sbio; 15665eedcc54Sinoguchi ctx = SSL_CTX_new(TLS_client_method()); 1567dab3f910Sjsing if (ctx == NULL) { 1568dab3f910Sjsing BIO_printf(err, "Error creating SSL context.\n"); 1569dab3f910Sjsing goto end; 1570dab3f910Sjsing } 1571dab3f910Sjsing SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); 1572dab3f910Sjsing sbio = BIO_new_ssl(ctx, 1); 1573dab3f910Sjsing cbio = BIO_push(sbio, cbio); 1574dab3f910Sjsing } 15757b609544Stb resp = query_responder(err, cbio, path, headers, host, req, req_timeout); 1576dab3f910Sjsing if (!resp) 1577dab3f910Sjsing BIO_printf(bio_err, "Error querying OCSP responder\n"); 1578bc14ef1fSinoguchi 1579dab3f910Sjsing end: 1580dab3f910Sjsing BIO_free_all(cbio); 1581dab3f910Sjsing SSL_CTX_free(ctx); 1582dab3f910Sjsing return resp; 1583dab3f910Sjsing } 1584dab3f910Sjsing #endif 1585