16f9291ceSJung-uk Kim /* 2*e71b7053SJung-uk Kim * Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved. 3*e71b7053SJung-uk Kim * 4*e71b7053SJung-uk Kim * Licensed under the OpenSSL license (the "License"). You may not use 5*e71b7053SJung-uk Kim * this file except in compliance with the License. You can obtain a copy 6*e71b7053SJung-uk Kim * in the file LICENSE in the source distribution or at 7*e71b7053SJung-uk Kim * https://www.openssl.org/source/license.html 85c87c606SMark Murray */ 91f13597dSJung-uk Kim 10*e71b7053SJung-uk Kim #include <openssl/opensslconf.h> 11*e71b7053SJung-uk Kim 12*e71b7053SJung-uk Kim #ifdef OPENSSL_NO_OCSP 13*e71b7053SJung-uk Kim NON_EMPTY_TRANSLATION_UNIT 14*e71b7053SJung-uk Kim #else 151f13597dSJung-uk Kim # ifdef OPENSSL_SYS_VMS 161f13597dSJung-uk Kim # define _XOPEN_SOURCE_EXTENDED/* So fd_set and friends get properly defined 176f9291ceSJung-uk Kim * on OpenVMS */ 181f13597dSJung-uk Kim # endif 191f13597dSJung-uk Kim 205c87c606SMark Murray # include <stdio.h> 21db522d3aSSimon L. B. Nielsen # include <stdlib.h> 225c87c606SMark Murray # include <string.h> 231f13597dSJung-uk Kim # include <time.h> 24*e71b7053SJung-uk Kim # include <ctype.h> 25*e71b7053SJung-uk Kim 26*e71b7053SJung-uk Kim /* Needs to be included before the openssl headers */ 27*e71b7053SJung-uk Kim # include "apps.h" 28*e71b7053SJung-uk Kim # include "progs.h" 29*e71b7053SJung-uk Kim # include "internal/sockets.h" 30db522d3aSSimon L. B. Nielsen # include <openssl/e_os2.h> 311f13597dSJung-uk Kim # include <openssl/crypto.h> 32db522d3aSSimon L. B. Nielsen # include <openssl/err.h> 331f13597dSJung-uk Kim # include <openssl/ssl.h> 341f13597dSJung-uk Kim # include <openssl/evp.h> 351f13597dSJung-uk Kim # include <openssl/bn.h> 361f13597dSJung-uk Kim # include <openssl/x509v3.h> 37*e71b7053SJung-uk Kim # include <openssl/rand.h> 381f13597dSJung-uk Kim 39*e71b7053SJung-uk Kim # if defined(OPENSSL_SYS_UNIX) && !defined(OPENSSL_NO_SOCK) \ 40*e71b7053SJung-uk Kim && !defined(OPENSSL_NO_POSIX_IO) 41*e71b7053SJung-uk Kim # define OCSP_DAEMON 42*e71b7053SJung-uk Kim # include <sys/types.h> 43*e71b7053SJung-uk Kim # include <sys/wait.h> 44*e71b7053SJung-uk Kim # include <syslog.h> 45*e71b7053SJung-uk Kim # include <signal.h> 46*e71b7053SJung-uk Kim # define MAXERRLEN 1000 /* limit error text sent to syslog to 1000 bytes */ 471f13597dSJung-uk Kim # else 48*e71b7053SJung-uk Kim # undef LOG_INFO 49*e71b7053SJung-uk Kim # undef LOG_WARNING 50*e71b7053SJung-uk Kim # undef LOG_ERR 51*e71b7053SJung-uk Kim # define LOG_INFO 0 52*e71b7053SJung-uk Kim # define LOG_WARNING 1 53*e71b7053SJung-uk Kim # define LOG_ERR 2 541f13597dSJung-uk Kim # endif 555c87c606SMark Murray 565c87c606SMark Murray /* Maximum leeway in validity period: default 5 minutes */ 575c87c606SMark Murray # define MAX_VALIDITY_PERIOD (5 * 60) 585c87c606SMark Murray 596f9291ceSJung-uk Kim static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, 606f9291ceSJung-uk Kim const EVP_MD *cert_id_md, X509 *issuer, 615c87c606SMark Murray STACK_OF(OCSP_CERTID) *ids); 626f9291ceSJung-uk Kim static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, 636f9291ceSJung-uk Kim const EVP_MD *cert_id_md, X509 *issuer, 645c87c606SMark Murray STACK_OF(OCSP_CERTID) *ids); 65*e71b7053SJung-uk Kim static void print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req, 661f13597dSJung-uk Kim STACK_OF(OPENSSL_STRING) *names, 671f13597dSJung-uk Kim STACK_OF(OCSP_CERTID) *ids, long nsec, 681f13597dSJung-uk Kim long maxage); 69*e71b7053SJung-uk Kim static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req, 70*e71b7053SJung-uk Kim CA_DB *db, STACK_OF(X509) *ca, X509 *rcert, 717bded2dbSJung-uk Kim EVP_PKEY *rkey, const EVP_MD *md, 72*e71b7053SJung-uk Kim STACK_OF(OPENSSL_STRING) *sigopts, 737bded2dbSJung-uk Kim STACK_OF(X509) *rother, unsigned long flags, 747bded2dbSJung-uk Kim int nmin, int ndays, int badsig); 755c87c606SMark Murray 76ced566fdSJacques Vidrine static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser); 777bded2dbSJung-uk Kim static BIO *init_responder(const char *port); 78*e71b7053SJung-uk Kim static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, int timeout); 795c87c606SMark Murray static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp); 80*e71b7053SJung-uk Kim static void log_message(int level, const char *fmt, ...); 81*e71b7053SJung-uk Kim static char *prog; 82*e71b7053SJung-uk Kim static int multi = 0; 83*e71b7053SJung-uk Kim 84*e71b7053SJung-uk Kim # ifdef OCSP_DAEMON 85*e71b7053SJung-uk Kim static int acfd = (int) INVALID_SOCKET; 86*e71b7053SJung-uk Kim static int index_changed(CA_DB *); 87*e71b7053SJung-uk Kim static void spawn_loop(void); 88*e71b7053SJung-uk Kim static int print_syslog(const char *str, size_t len, void *levPtr); 89*e71b7053SJung-uk Kim static void sock_timeout(int signum); 90*e71b7053SJung-uk Kim # endif 91*e71b7053SJung-uk Kim 92*e71b7053SJung-uk Kim # ifndef OPENSSL_NO_SOCK 93*e71b7053SJung-uk Kim static OCSP_RESPONSE *query_responder(BIO *cbio, const char *host, 94*e71b7053SJung-uk Kim const char *path, 957bded2dbSJung-uk Kim const STACK_OF(CONF_VALUE) *headers, 96db522d3aSSimon L. B. Nielsen OCSP_REQUEST *req, int req_timeout); 97*e71b7053SJung-uk Kim # endif 985c87c606SMark Murray 99*e71b7053SJung-uk Kim typedef enum OPTION_choice { 100*e71b7053SJung-uk Kim OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, 101*e71b7053SJung-uk Kim OPT_OUTFILE, OPT_TIMEOUT, OPT_URL, OPT_HOST, OPT_PORT, 102*e71b7053SJung-uk Kim OPT_IGNORE_ERR, OPT_NOVERIFY, OPT_NONCE, OPT_NO_NONCE, 103*e71b7053SJung-uk Kim OPT_RESP_NO_CERTS, OPT_RESP_KEY_ID, OPT_NO_CERTS, 104*e71b7053SJung-uk Kim OPT_NO_SIGNATURE_VERIFY, OPT_NO_CERT_VERIFY, OPT_NO_CHAIN, 105*e71b7053SJung-uk Kim OPT_NO_CERT_CHECKS, OPT_NO_EXPLICIT, OPT_TRUST_OTHER, 106*e71b7053SJung-uk Kim OPT_NO_INTERN, OPT_BADSIG, OPT_TEXT, OPT_REQ_TEXT, OPT_RESP_TEXT, 107*e71b7053SJung-uk Kim OPT_REQIN, OPT_RESPIN, OPT_SIGNER, OPT_VAFILE, OPT_SIGN_OTHER, 108*e71b7053SJung-uk Kim OPT_VERIFY_OTHER, OPT_CAFILE, OPT_CAPATH, OPT_NOCAFILE, OPT_NOCAPATH, 109*e71b7053SJung-uk Kim OPT_VALIDITY_PERIOD, OPT_STATUS_AGE, OPT_SIGNKEY, OPT_REQOUT, 110*e71b7053SJung-uk Kim OPT_RESPOUT, OPT_PATH, OPT_ISSUER, OPT_CERT, OPT_SERIAL, 111*e71b7053SJung-uk Kim OPT_INDEX, OPT_CA, OPT_NMIN, OPT_REQUEST, OPT_NDAYS, OPT_RSIGNER, 112*e71b7053SJung-uk Kim OPT_RKEY, OPT_ROTHER, OPT_RMD, OPT_RSIGOPT, OPT_HEADER, 113*e71b7053SJung-uk Kim OPT_V_ENUM, 114*e71b7053SJung-uk Kim OPT_MD, 115*e71b7053SJung-uk Kim OPT_MULTI 116*e71b7053SJung-uk Kim } OPTION_CHOICE; 1175c87c606SMark Murray 118*e71b7053SJung-uk Kim const OPTIONS ocsp_options[] = { 119*e71b7053SJung-uk Kim {"help", OPT_HELP, '-', "Display this summary"}, 120*e71b7053SJung-uk Kim {"out", OPT_OUTFILE, '>', "Output filename"}, 121*e71b7053SJung-uk Kim {"timeout", OPT_TIMEOUT, 'p', 122*e71b7053SJung-uk Kim "Connection timeout (in seconds) to the OCSP responder"}, 123*e71b7053SJung-uk Kim {"url", OPT_URL, 's', "Responder URL"}, 124*e71b7053SJung-uk Kim {"host", OPT_HOST, 's', "TCP/IP hostname:port to connect to"}, 125*e71b7053SJung-uk Kim {"port", OPT_PORT, 'p', "Port to run responder on"}, 126*e71b7053SJung-uk Kim {"ignore_err", OPT_IGNORE_ERR, '-', 127*e71b7053SJung-uk Kim "Ignore error on OCSP request or response and continue running"}, 128*e71b7053SJung-uk Kim {"noverify", OPT_NOVERIFY, '-', "Don't verify response at all"}, 129*e71b7053SJung-uk Kim {"nonce", OPT_NONCE, '-', "Add OCSP nonce to request"}, 130*e71b7053SJung-uk Kim {"no_nonce", OPT_NO_NONCE, '-', "Don't add OCSP nonce to request"}, 131*e71b7053SJung-uk Kim {"resp_no_certs", OPT_RESP_NO_CERTS, '-', 132*e71b7053SJung-uk Kim "Don't include any certificates in response"}, 133*e71b7053SJung-uk Kim {"resp_key_id", OPT_RESP_KEY_ID, '-', 134*e71b7053SJung-uk Kim "Identify response by signing certificate key ID"}, 135*e71b7053SJung-uk Kim # ifdef OCSP_DAEMON 136*e71b7053SJung-uk Kim {"multi", OPT_MULTI, 'p', "run multiple responder processes"}, 137*e71b7053SJung-uk Kim # endif 138*e71b7053SJung-uk Kim {"no_certs", OPT_NO_CERTS, '-', 139*e71b7053SJung-uk Kim "Don't include any certificates in signed request"}, 140*e71b7053SJung-uk Kim {"no_signature_verify", OPT_NO_SIGNATURE_VERIFY, '-', 141*e71b7053SJung-uk Kim "Don't check signature on response"}, 142*e71b7053SJung-uk Kim {"no_cert_verify", OPT_NO_CERT_VERIFY, '-', 143*e71b7053SJung-uk Kim "Don't check signing certificate"}, 144*e71b7053SJung-uk Kim {"no_chain", OPT_NO_CHAIN, '-', "Don't chain verify response"}, 145*e71b7053SJung-uk Kim {"no_cert_checks", OPT_NO_CERT_CHECKS, '-', 146*e71b7053SJung-uk Kim "Don't do additional checks on signing certificate"}, 147*e71b7053SJung-uk Kim {"no_explicit", OPT_NO_EXPLICIT, '-', 148*e71b7053SJung-uk Kim "Do not explicitly check the chain, just verify the root"}, 149*e71b7053SJung-uk Kim {"trust_other", OPT_TRUST_OTHER, '-', 150*e71b7053SJung-uk Kim "Don't verify additional certificates"}, 151*e71b7053SJung-uk Kim {"no_intern", OPT_NO_INTERN, '-', 152*e71b7053SJung-uk Kim "Don't search certificates contained in response for signer"}, 153*e71b7053SJung-uk Kim {"badsig", OPT_BADSIG, '-', 154*e71b7053SJung-uk Kim "Corrupt last byte of loaded OSCP response signature (for test)"}, 155*e71b7053SJung-uk Kim {"text", OPT_TEXT, '-', "Print text form of request and response"}, 156*e71b7053SJung-uk Kim {"req_text", OPT_REQ_TEXT, '-', "Print text form of request"}, 157*e71b7053SJung-uk Kim {"resp_text", OPT_RESP_TEXT, '-', "Print text form of response"}, 158*e71b7053SJung-uk Kim {"reqin", OPT_REQIN, 's', "File with the DER-encoded request"}, 159*e71b7053SJung-uk Kim {"respin", OPT_RESPIN, 's', "File with the DER-encoded response"}, 160*e71b7053SJung-uk Kim {"signer", OPT_SIGNER, '<', "Certificate to sign OCSP request with"}, 161*e71b7053SJung-uk Kim {"VAfile", OPT_VAFILE, '<', "Validator certificates file"}, 162*e71b7053SJung-uk Kim {"sign_other", OPT_SIGN_OTHER, '<', 163*e71b7053SJung-uk Kim "Additional certificates to include in signed request"}, 164*e71b7053SJung-uk Kim {"verify_other", OPT_VERIFY_OTHER, '<', 165*e71b7053SJung-uk Kim "Additional certificates to search for signer"}, 166*e71b7053SJung-uk Kim {"CAfile", OPT_CAFILE, '<', "Trusted certificates file"}, 167*e71b7053SJung-uk Kim {"CApath", OPT_CAPATH, '<', "Trusted certificates directory"}, 168*e71b7053SJung-uk Kim {"no-CAfile", OPT_NOCAFILE, '-', 169*e71b7053SJung-uk Kim "Do not load the default certificates file"}, 170*e71b7053SJung-uk Kim {"no-CApath", OPT_NOCAPATH, '-', 171*e71b7053SJung-uk Kim "Do not load certificates from the default certificates directory"}, 172*e71b7053SJung-uk Kim {"validity_period", OPT_VALIDITY_PERIOD, 'u', 173*e71b7053SJung-uk Kim "Maximum validity discrepancy in seconds"}, 174*e71b7053SJung-uk Kim {"status_age", OPT_STATUS_AGE, 'p', "Maximum status age in seconds"}, 175*e71b7053SJung-uk Kim {"signkey", OPT_SIGNKEY, 's', "Private key to sign OCSP request with"}, 176*e71b7053SJung-uk Kim {"reqout", OPT_REQOUT, 's', "Output file for the DER-encoded request"}, 177*e71b7053SJung-uk Kim {"respout", OPT_RESPOUT, 's', "Output file for the DER-encoded response"}, 178*e71b7053SJung-uk Kim {"path", OPT_PATH, 's', "Path to use in OCSP request"}, 179*e71b7053SJung-uk Kim {"issuer", OPT_ISSUER, '<', "Issuer certificate"}, 180*e71b7053SJung-uk Kim {"cert", OPT_CERT, '<', "Certificate to check"}, 181*e71b7053SJung-uk Kim {"serial", OPT_SERIAL, 's', "Serial number to check"}, 182*e71b7053SJung-uk Kim {"index", OPT_INDEX, '<', "Certificate status index file"}, 183*e71b7053SJung-uk Kim {"CA", OPT_CA, '<', "CA certificate"}, 184*e71b7053SJung-uk Kim {"nmin", OPT_NMIN, 'p', "Number of minutes before next update"}, 185*e71b7053SJung-uk Kim {"nrequest", OPT_REQUEST, 'p', 186*e71b7053SJung-uk Kim "Number of requests to accept (default unlimited)"}, 187*e71b7053SJung-uk Kim {"ndays", OPT_NDAYS, 'p', "Number of days before next update"}, 188*e71b7053SJung-uk Kim {"rsigner", OPT_RSIGNER, '<', 189*e71b7053SJung-uk Kim "Responder certificate to sign responses with"}, 190*e71b7053SJung-uk Kim {"rkey", OPT_RKEY, '<', "Responder key to sign responses with"}, 191*e71b7053SJung-uk Kim {"rother", OPT_ROTHER, '<', "Other certificates to include in response"}, 192*e71b7053SJung-uk Kim {"rmd", OPT_RMD, 's', "Digest Algorithm to use in signature of OCSP response"}, 193*e71b7053SJung-uk Kim {"rsigopt", OPT_RSIGOPT, 's', "OCSP response signature parameter in n:v form"}, 194*e71b7053SJung-uk Kim {"header", OPT_HEADER, 's', "key=value header to add"}, 195*e71b7053SJung-uk Kim {"", OPT_MD, '-', "Any supported digest algorithm (sha1,sha256, ... )"}, 196*e71b7053SJung-uk Kim OPT_V_OPTIONS, 197*e71b7053SJung-uk Kim {NULL} 198*e71b7053SJung-uk Kim }; 1995c87c606SMark Murray 200*e71b7053SJung-uk Kim int ocsp_main(int argc, char **argv) 2015c87c606SMark Murray { 202*e71b7053SJung-uk Kim BIO *acbio = NULL, *cbio = NULL, *derbio = NULL, *out = NULL; 203*e71b7053SJung-uk Kim const EVP_MD *cert_id_md = NULL, *rsign_md = NULL; 204*e71b7053SJung-uk Kim STACK_OF(OPENSSL_STRING) *rsign_sigopts = NULL; 205*e71b7053SJung-uk Kim int trailing_md = 0; 206*e71b7053SJung-uk Kim CA_DB *rdb = NULL; 207*e71b7053SJung-uk Kim EVP_PKEY *key = NULL, *rkey = NULL; 208*e71b7053SJung-uk Kim OCSP_BASICRESP *bs = NULL; 2095c87c606SMark Murray OCSP_REQUEST *req = NULL; 2105c87c606SMark Murray OCSP_RESPONSE *resp = NULL; 211*e71b7053SJung-uk Kim STACK_OF(CONF_VALUE) *headers = NULL; 212*e71b7053SJung-uk Kim STACK_OF(OCSP_CERTID) *ids = NULL; 213*e71b7053SJung-uk Kim STACK_OF(OPENSSL_STRING) *reqnames = NULL; 214*e71b7053SJung-uk Kim STACK_OF(X509) *sign_other = NULL, *verify_other = NULL, *rother = NULL; 215*e71b7053SJung-uk Kim STACK_OF(X509) *issuers = NULL; 2165c87c606SMark Murray X509 *issuer = NULL, *cert = NULL; 217*e71b7053SJung-uk Kim STACK_OF(X509) *rca_cert = NULL; 2185c87c606SMark Murray X509 *signer = NULL, *rsigner = NULL; 2195c87c606SMark Murray X509_STORE *store = NULL; 2207bded2dbSJung-uk Kim X509_VERIFY_PARAM *vpm = NULL; 221*e71b7053SJung-uk Kim const char *CAfile = NULL, *CApath = NULL; 222*e71b7053SJung-uk Kim char *header, *value; 223*e71b7053SJung-uk Kim char *host = NULL, *port = NULL, *path = "/", *outfile = NULL; 224*e71b7053SJung-uk Kim char *rca_filename = NULL, *reqin = NULL, *respin = NULL; 225*e71b7053SJung-uk Kim char *reqout = NULL, *respout = NULL, *ridx_filename = NULL; 226*e71b7053SJung-uk Kim char *rsignfile = NULL, *rkeyfile = NULL; 2275c87c606SMark Murray char *sign_certfile = NULL, *verify_certfile = NULL, *rcertfile = NULL; 228*e71b7053SJung-uk Kim char *signfile = NULL, *keyfile = NULL; 229*e71b7053SJung-uk Kim char *thost = NULL, *tport = NULL, *tpath = NULL; 230*e71b7053SJung-uk Kim int noCAfile = 0, noCApath = 0; 231*e71b7053SJung-uk Kim int accept_count = -1, add_nonce = 1, noverify = 0, use_ssl = -1; 232*e71b7053SJung-uk Kim int vpmtouched = 0, badsig = 0, i, ignore_err = 0, nmin = 0, ndays = -1; 233*e71b7053SJung-uk Kim int req_text = 0, resp_text = 0, ret = 1; 234*e71b7053SJung-uk Kim int req_timeout = -1; 235*e71b7053SJung-uk Kim long nsec = MAX_VALIDITY_PERIOD, maxage = -1; 2365c87c606SMark Murray unsigned long sign_flags = 0, verify_flags = 0, rflags = 0; 237*e71b7053SJung-uk Kim OPTION_CHOICE o; 2385c87c606SMark Murray 2391f13597dSJung-uk Kim reqnames = sk_OPENSSL_STRING_new_null(); 240*e71b7053SJung-uk Kim if (reqnames == NULL) 241*e71b7053SJung-uk Kim goto end; 2425c87c606SMark Murray ids = sk_OCSP_CERTID_new_null(); 243*e71b7053SJung-uk Kim if (ids == NULL) 244*e71b7053SJung-uk Kim goto end; 245*e71b7053SJung-uk Kim if ((vpm = X509_VERIFY_PARAM_new()) == NULL) 246*e71b7053SJung-uk Kim return 1; 247*e71b7053SJung-uk Kim 248*e71b7053SJung-uk Kim prog = opt_init(argc, argv, ocsp_options); 249*e71b7053SJung-uk Kim while ((o = opt_next()) != OPT_EOF) { 250*e71b7053SJung-uk Kim switch (o) { 251*e71b7053SJung-uk Kim case OPT_EOF: 252*e71b7053SJung-uk Kim case OPT_ERR: 253*e71b7053SJung-uk Kim opthelp: 254*e71b7053SJung-uk Kim BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); 255*e71b7053SJung-uk Kim goto end; 256*e71b7053SJung-uk Kim case OPT_HELP: 257*e71b7053SJung-uk Kim ret = 0; 258*e71b7053SJung-uk Kim opt_help(ocsp_options); 259*e71b7053SJung-uk Kim goto end; 260*e71b7053SJung-uk Kim case OPT_OUTFILE: 261*e71b7053SJung-uk Kim outfile = opt_arg(); 262*e71b7053SJung-uk Kim break; 263*e71b7053SJung-uk Kim case OPT_TIMEOUT: 264*e71b7053SJung-uk Kim #ifndef OPENSSL_NO_SOCK 265*e71b7053SJung-uk Kim req_timeout = atoi(opt_arg()); 266*e71b7053SJung-uk Kim #endif 267*e71b7053SJung-uk Kim break; 268*e71b7053SJung-uk Kim case OPT_URL: 26994ad176cSJung-uk Kim OPENSSL_free(thost); 27094ad176cSJung-uk Kim OPENSSL_free(tport); 27194ad176cSJung-uk Kim OPENSSL_free(tpath); 2727bded2dbSJung-uk Kim thost = tport = tpath = NULL; 273*e71b7053SJung-uk Kim if (!OCSP_parse_url(opt_arg(), &host, &port, &path, &use_ssl)) { 274*e71b7053SJung-uk Kim BIO_printf(bio_err, "%s Error parsing URL\n", prog); 275*e71b7053SJung-uk Kim goto end; 2765c87c606SMark Murray } 27794ad176cSJung-uk Kim thost = host; 27894ad176cSJung-uk Kim tport = port; 27994ad176cSJung-uk Kim tpath = path; 280*e71b7053SJung-uk Kim break; 281*e71b7053SJung-uk Kim case OPT_HOST: 282*e71b7053SJung-uk Kim host = opt_arg(); 283*e71b7053SJung-uk Kim break; 284*e71b7053SJung-uk Kim case OPT_PORT: 285*e71b7053SJung-uk Kim port = opt_arg(); 286*e71b7053SJung-uk Kim break; 287*e71b7053SJung-uk Kim case OPT_IGNORE_ERR: 28850ef0093SJacques Vidrine ignore_err = 1; 289*e71b7053SJung-uk Kim break; 290*e71b7053SJung-uk Kim case OPT_NOVERIFY: 2915c87c606SMark Murray noverify = 1; 292*e71b7053SJung-uk Kim break; 293*e71b7053SJung-uk Kim case OPT_NONCE: 2945c87c606SMark Murray add_nonce = 2; 295*e71b7053SJung-uk Kim break; 296*e71b7053SJung-uk Kim case OPT_NO_NONCE: 2975c87c606SMark Murray add_nonce = 0; 298*e71b7053SJung-uk Kim break; 299*e71b7053SJung-uk Kim case OPT_RESP_NO_CERTS: 3005c87c606SMark Murray rflags |= OCSP_NOCERTS; 301*e71b7053SJung-uk Kim break; 302*e71b7053SJung-uk Kim case OPT_RESP_KEY_ID: 3035c87c606SMark Murray rflags |= OCSP_RESPID_KEY; 304*e71b7053SJung-uk Kim break; 305*e71b7053SJung-uk Kim case OPT_NO_CERTS: 3065c87c606SMark Murray sign_flags |= OCSP_NOCERTS; 307*e71b7053SJung-uk Kim break; 308*e71b7053SJung-uk Kim case OPT_NO_SIGNATURE_VERIFY: 3095c87c606SMark Murray verify_flags |= OCSP_NOSIGS; 310*e71b7053SJung-uk Kim break; 311*e71b7053SJung-uk Kim case OPT_NO_CERT_VERIFY: 3125c87c606SMark Murray verify_flags |= OCSP_NOVERIFY; 313*e71b7053SJung-uk Kim break; 314*e71b7053SJung-uk Kim case OPT_NO_CHAIN: 3155c87c606SMark Murray verify_flags |= OCSP_NOCHAIN; 316*e71b7053SJung-uk Kim break; 317*e71b7053SJung-uk Kim case OPT_NO_CERT_CHECKS: 3185c87c606SMark Murray verify_flags |= OCSP_NOCHECKS; 319*e71b7053SJung-uk Kim break; 320*e71b7053SJung-uk Kim case OPT_NO_EXPLICIT: 3215c87c606SMark Murray verify_flags |= OCSP_NOEXPLICIT; 322*e71b7053SJung-uk Kim break; 323*e71b7053SJung-uk Kim case OPT_TRUST_OTHER: 3245c87c606SMark Murray verify_flags |= OCSP_TRUSTOTHER; 325*e71b7053SJung-uk Kim break; 326*e71b7053SJung-uk Kim case OPT_NO_INTERN: 3275c87c606SMark Murray verify_flags |= OCSP_NOINTERN; 328*e71b7053SJung-uk Kim break; 329*e71b7053SJung-uk Kim case OPT_BADSIG: 3307bded2dbSJung-uk Kim badsig = 1; 331*e71b7053SJung-uk Kim break; 332*e71b7053SJung-uk Kim case OPT_TEXT: 333*e71b7053SJung-uk Kim req_text = resp_text = 1; 334*e71b7053SJung-uk Kim break; 335*e71b7053SJung-uk Kim case OPT_REQ_TEXT: 3365c87c606SMark Murray req_text = 1; 337*e71b7053SJung-uk Kim break; 338*e71b7053SJung-uk Kim case OPT_RESP_TEXT: 3395c87c606SMark Murray resp_text = 1; 340*e71b7053SJung-uk Kim break; 341*e71b7053SJung-uk Kim case OPT_REQIN: 342*e71b7053SJung-uk Kim reqin = opt_arg(); 343*e71b7053SJung-uk Kim break; 344*e71b7053SJung-uk Kim case OPT_RESPIN: 345*e71b7053SJung-uk Kim respin = opt_arg(); 346*e71b7053SJung-uk Kim break; 347*e71b7053SJung-uk Kim case OPT_SIGNER: 348*e71b7053SJung-uk Kim signfile = opt_arg(); 349*e71b7053SJung-uk Kim break; 350*e71b7053SJung-uk Kim case OPT_VAFILE: 351*e71b7053SJung-uk Kim verify_certfile = opt_arg(); 3525c87c606SMark Murray verify_flags |= OCSP_TRUSTOTHER; 353*e71b7053SJung-uk Kim break; 354*e71b7053SJung-uk Kim case OPT_SIGN_OTHER: 355*e71b7053SJung-uk Kim sign_certfile = opt_arg(); 356*e71b7053SJung-uk Kim break; 357*e71b7053SJung-uk Kim case OPT_VERIFY_OTHER: 358*e71b7053SJung-uk Kim verify_certfile = opt_arg(); 359*e71b7053SJung-uk Kim break; 360*e71b7053SJung-uk Kim case OPT_CAFILE: 361*e71b7053SJung-uk Kim CAfile = opt_arg(); 362*e71b7053SJung-uk Kim break; 363*e71b7053SJung-uk Kim case OPT_CAPATH: 364*e71b7053SJung-uk Kim CApath = opt_arg(); 365*e71b7053SJung-uk Kim break; 366*e71b7053SJung-uk Kim case OPT_NOCAFILE: 367*e71b7053SJung-uk Kim noCAfile = 1; 368*e71b7053SJung-uk Kim break; 369*e71b7053SJung-uk Kim case OPT_NOCAPATH: 370*e71b7053SJung-uk Kim noCApath = 1; 371*e71b7053SJung-uk Kim break; 372*e71b7053SJung-uk Kim case OPT_V_CASES: 373*e71b7053SJung-uk Kim if (!opt_verify(o, vpm)) 3747bded2dbSJung-uk Kim goto end; 375*e71b7053SJung-uk Kim vpmtouched++; 376*e71b7053SJung-uk Kim break; 377*e71b7053SJung-uk Kim case OPT_VALIDITY_PERIOD: 378*e71b7053SJung-uk Kim opt_long(opt_arg(), &nsec); 379*e71b7053SJung-uk Kim break; 380*e71b7053SJung-uk Kim case OPT_STATUS_AGE: 381*e71b7053SJung-uk Kim opt_long(opt_arg(), &maxage); 382*e71b7053SJung-uk Kim break; 383*e71b7053SJung-uk Kim case OPT_SIGNKEY: 384*e71b7053SJung-uk Kim keyfile = opt_arg(); 385*e71b7053SJung-uk Kim break; 386*e71b7053SJung-uk Kim case OPT_REQOUT: 387*e71b7053SJung-uk Kim reqout = opt_arg(); 388*e71b7053SJung-uk Kim break; 389*e71b7053SJung-uk Kim case OPT_RESPOUT: 390*e71b7053SJung-uk Kim respout = opt_arg(); 391*e71b7053SJung-uk Kim break; 392*e71b7053SJung-uk Kim case OPT_PATH: 393*e71b7053SJung-uk Kim path = opt_arg(); 394*e71b7053SJung-uk Kim break; 395*e71b7053SJung-uk Kim case OPT_ISSUER: 396*e71b7053SJung-uk Kim issuer = load_cert(opt_arg(), FORMAT_PEM, "issuer certificate"); 397*e71b7053SJung-uk Kim if (issuer == NULL) 3986f9291ceSJung-uk Kim goto end; 399*e71b7053SJung-uk Kim if (issuers == NULL) { 400*e71b7053SJung-uk Kim if ((issuers = sk_X509_new_null()) == NULL) 401*e71b7053SJung-uk Kim goto end; 402*e71b7053SJung-uk Kim } 403*e71b7053SJung-uk Kim sk_X509_push(issuers, issuer); 404*e71b7053SJung-uk Kim break; 405*e71b7053SJung-uk Kim case OPT_CERT: 4065c87c606SMark Murray X509_free(cert); 407*e71b7053SJung-uk Kim cert = load_cert(opt_arg(), FORMAT_PEM, "certificate"); 408*e71b7053SJung-uk Kim if (cert == NULL) 4096f9291ceSJung-uk Kim goto end; 410*e71b7053SJung-uk Kim if (cert_id_md == NULL) 4116f9291ceSJung-uk Kim cert_id_md = EVP_sha1(); 4121f13597dSJung-uk Kim if (!add_ocsp_cert(&req, cert, cert_id_md, issuer, ids)) 4135c87c606SMark Murray goto end; 414*e71b7053SJung-uk Kim if (!sk_OPENSSL_STRING_push(reqnames, opt_arg())) 4155c87c606SMark Murray goto end; 416*e71b7053SJung-uk Kim trailing_md = 0; 417*e71b7053SJung-uk Kim break; 418*e71b7053SJung-uk Kim case OPT_SERIAL: 419*e71b7053SJung-uk Kim if (cert_id_md == NULL) 4206f9291ceSJung-uk Kim cert_id_md = EVP_sha1(); 421*e71b7053SJung-uk Kim if (!add_ocsp_serial(&req, opt_arg(), cert_id_md, issuer, ids)) 4225c87c606SMark Murray goto end; 423*e71b7053SJung-uk Kim if (!sk_OPENSSL_STRING_push(reqnames, opt_arg())) 4245c87c606SMark Murray goto end; 425*e71b7053SJung-uk Kim trailing_md = 0; 426*e71b7053SJung-uk Kim break; 427*e71b7053SJung-uk Kim case OPT_INDEX: 428*e71b7053SJung-uk Kim ridx_filename = opt_arg(); 429*e71b7053SJung-uk Kim break; 430*e71b7053SJung-uk Kim case OPT_CA: 431*e71b7053SJung-uk Kim rca_filename = opt_arg(); 432*e71b7053SJung-uk Kim break; 433*e71b7053SJung-uk Kim case OPT_NMIN: 434*e71b7053SJung-uk Kim opt_int(opt_arg(), &nmin); 4355c87c606SMark Murray if (ndays == -1) 4365c87c606SMark Murray ndays = 0; 437*e71b7053SJung-uk Kim break; 438*e71b7053SJung-uk Kim case OPT_REQUEST: 439*e71b7053SJung-uk Kim opt_int(opt_arg(), &accept_count); 440*e71b7053SJung-uk Kim break; 441*e71b7053SJung-uk Kim case OPT_NDAYS: 442*e71b7053SJung-uk Kim ndays = atoi(opt_arg()); 443*e71b7053SJung-uk Kim break; 444*e71b7053SJung-uk Kim case OPT_RSIGNER: 445*e71b7053SJung-uk Kim rsignfile = opt_arg(); 446*e71b7053SJung-uk Kim break; 447*e71b7053SJung-uk Kim case OPT_RKEY: 448*e71b7053SJung-uk Kim rkeyfile = opt_arg(); 449*e71b7053SJung-uk Kim break; 450*e71b7053SJung-uk Kim case OPT_ROTHER: 451*e71b7053SJung-uk Kim rcertfile = opt_arg(); 452*e71b7053SJung-uk Kim break; 453*e71b7053SJung-uk Kim case OPT_RMD: /* Response MessageDigest */ 454*e71b7053SJung-uk Kim if (!opt_md(opt_arg(), &rsign_md)) 455*e71b7053SJung-uk Kim goto end; 456*e71b7053SJung-uk Kim break; 457*e71b7053SJung-uk Kim case OPT_RSIGOPT: 458*e71b7053SJung-uk Kim if (rsign_sigopts == NULL) 459*e71b7053SJung-uk Kim rsign_sigopts = sk_OPENSSL_STRING_new_null(); 460*e71b7053SJung-uk Kim if (rsign_sigopts == NULL || !sk_OPENSSL_STRING_push(rsign_sigopts, opt_arg())) 461*e71b7053SJung-uk Kim goto end; 462*e71b7053SJung-uk Kim break; 463*e71b7053SJung-uk Kim case OPT_HEADER: 464*e71b7053SJung-uk Kim header = opt_arg(); 465*e71b7053SJung-uk Kim value = strchr(header, '='); 466*e71b7053SJung-uk Kim if (value == NULL) { 467*e71b7053SJung-uk Kim BIO_printf(bio_err, "Missing = in header key=value\n"); 468*e71b7053SJung-uk Kim goto opthelp; 4695c87c606SMark Murray } 470*e71b7053SJung-uk Kim *value++ = '\0'; 471*e71b7053SJung-uk Kim if (!X509V3_add_value(header, value, &headers)) 472*e71b7053SJung-uk Kim goto end; 473*e71b7053SJung-uk Kim break; 474*e71b7053SJung-uk Kim case OPT_MD: 475*e71b7053SJung-uk Kim if (trailing_md) { 476*e71b7053SJung-uk Kim BIO_printf(bio_err, 477*e71b7053SJung-uk Kim "%s: Digest must be before -cert or -serial\n", 478*e71b7053SJung-uk Kim prog); 479*e71b7053SJung-uk Kim goto opthelp; 4805c87c606SMark Murray } 481*e71b7053SJung-uk Kim if (!opt_md(opt_unknown(), &cert_id_md)) 482*e71b7053SJung-uk Kim goto opthelp; 483*e71b7053SJung-uk Kim trailing_md = 1; 484*e71b7053SJung-uk Kim break; 485*e71b7053SJung-uk Kim case OPT_MULTI: 486*e71b7053SJung-uk Kim # ifdef OCSP_DAEMON 487*e71b7053SJung-uk Kim multi = atoi(opt_arg()); 488*e71b7053SJung-uk Kim # endif 489*e71b7053SJung-uk Kim break; 4901f13597dSJung-uk Kim } 4915c87c606SMark Murray } 492*e71b7053SJung-uk Kim if (trailing_md) { 493*e71b7053SJung-uk Kim BIO_printf(bio_err, "%s: Digest must be before -cert or -serial\n", 494*e71b7053SJung-uk Kim prog); 495*e71b7053SJung-uk Kim goto opthelp; 496*e71b7053SJung-uk Kim } 497*e71b7053SJung-uk Kim argc = opt_num_rest(); 498*e71b7053SJung-uk Kim if (argc != 0) 499*e71b7053SJung-uk Kim goto opthelp; 5005c87c606SMark Murray 5015c87c606SMark Murray /* Have we anything to do? */ 502*e71b7053SJung-uk Kim if (req == NULL && reqin == NULL 503*e71b7053SJung-uk Kim && respin == NULL && !(port != NULL && ridx_filename != NULL)) 504*e71b7053SJung-uk Kim goto opthelp; 5055c87c606SMark Murray 506*e71b7053SJung-uk Kim out = bio_open_default(outfile, 'w', FORMAT_TEXT); 507*e71b7053SJung-uk Kim if (out == NULL) 5085c87c606SMark Murray goto end; 5095c87c606SMark Murray 510*e71b7053SJung-uk Kim if (req == NULL && (add_nonce != 2)) 5116f9291ceSJung-uk Kim add_nonce = 0; 5125c87c606SMark Murray 513*e71b7053SJung-uk Kim if (req == NULL && reqin != NULL) { 514*e71b7053SJung-uk Kim derbio = bio_open_default(reqin, 'r', FORMAT_ASN1); 515*e71b7053SJung-uk Kim if (derbio == NULL) 5165c87c606SMark Murray goto end; 5175c87c606SMark Murray req = d2i_OCSP_REQUEST_bio(derbio, NULL); 5185c87c606SMark Murray BIO_free(derbio); 519*e71b7053SJung-uk Kim if (req == NULL) { 5205c87c606SMark Murray BIO_printf(bio_err, "Error reading OCSP request\n"); 5215c87c606SMark Murray goto end; 5225c87c606SMark Murray } 5235c87c606SMark Murray } 5245c87c606SMark Murray 525*e71b7053SJung-uk Kim if (req == NULL && port != NULL) { 5265c87c606SMark Murray acbio = init_responder(port); 527*e71b7053SJung-uk Kim if (acbio == NULL) 5285c87c606SMark Murray goto end; 5295c87c606SMark Murray } 5305c87c606SMark Murray 531*e71b7053SJung-uk Kim if (rsignfile != NULL) { 532*e71b7053SJung-uk Kim if (rkeyfile == NULL) 5336f9291ceSJung-uk Kim rkeyfile = rsignfile; 534*e71b7053SJung-uk Kim rsigner = load_cert(rsignfile, FORMAT_PEM, "responder certificate"); 535*e71b7053SJung-uk Kim if (rsigner == NULL) { 5365c87c606SMark Murray BIO_printf(bio_err, "Error loading responder certificate\n"); 5375c87c606SMark Murray goto end; 5385c87c606SMark Murray } 539*e71b7053SJung-uk Kim if (!load_certs(rca_filename, &rca_cert, FORMAT_PEM, 540*e71b7053SJung-uk Kim NULL, "CA certificate")) 541*e71b7053SJung-uk Kim goto end; 542*e71b7053SJung-uk Kim if (rcertfile != NULL) { 543*e71b7053SJung-uk Kim if (!load_certs(rcertfile, &rother, FORMAT_PEM, NULL, 544*e71b7053SJung-uk Kim "responder other certificates")) 5456f9291ceSJung-uk Kim goto end; 5465c87c606SMark Murray } 547*e71b7053SJung-uk Kim rkey = load_key(rkeyfile, FORMAT_PEM, 0, NULL, NULL, 5485c87c606SMark Murray "responder private key"); 549*e71b7053SJung-uk Kim if (rkey == NULL) 5505c87c606SMark Murray goto end; 5515c87c606SMark Murray } 552*e71b7053SJung-uk Kim 553*e71b7053SJung-uk Kim if (ridx_filename != NULL 554*e71b7053SJung-uk Kim && (rkey == NULL || rsigner == NULL || rca_cert == NULL)) { 555*e71b7053SJung-uk Kim BIO_printf(bio_err, 556*e71b7053SJung-uk Kim "Responder mode requires certificate, key, and CA.\n"); 557*e71b7053SJung-uk Kim goto end; 558*e71b7053SJung-uk Kim } 559*e71b7053SJung-uk Kim 560*e71b7053SJung-uk Kim if (ridx_filename != NULL) { 561*e71b7053SJung-uk Kim rdb = load_index(ridx_filename, NULL); 562*e71b7053SJung-uk Kim if (rdb == NULL || index_index(rdb) <= 0) { 563*e71b7053SJung-uk Kim ret = 1; 564*e71b7053SJung-uk Kim goto end; 565*e71b7053SJung-uk Kim } 566*e71b7053SJung-uk Kim } 567*e71b7053SJung-uk Kim 568*e71b7053SJung-uk Kim # ifdef OCSP_DAEMON 569*e71b7053SJung-uk Kim if (multi && acbio != NULL) 570*e71b7053SJung-uk Kim spawn_loop(); 571*e71b7053SJung-uk Kim if (acbio != NULL && req_timeout > 0) 572*e71b7053SJung-uk Kim signal(SIGALRM, sock_timeout); 573*e71b7053SJung-uk Kim #endif 574*e71b7053SJung-uk Kim 575*e71b7053SJung-uk Kim if (acbio != NULL) 576*e71b7053SJung-uk Kim log_message(LOG_INFO, "waiting for OCSP client connections..."); 5775c87c606SMark Murray 5785c87c606SMark Murray redo_accept: 5795c87c606SMark Murray 580*e71b7053SJung-uk Kim if (acbio != NULL) { 581*e71b7053SJung-uk Kim # ifdef OCSP_DAEMON 582*e71b7053SJung-uk Kim if (index_changed(rdb)) { 583*e71b7053SJung-uk Kim CA_DB *newrdb = load_index(ridx_filename, NULL); 584*e71b7053SJung-uk Kim 585*e71b7053SJung-uk Kim if (newrdb != NULL && index_index(newrdb) > 0) { 586*e71b7053SJung-uk Kim free_index(rdb); 587*e71b7053SJung-uk Kim rdb = newrdb; 588*e71b7053SJung-uk Kim } else { 589*e71b7053SJung-uk Kim free_index(newrdb); 590*e71b7053SJung-uk Kim log_message(LOG_ERR, "error reloading updated index: %s", 591*e71b7053SJung-uk Kim ridx_filename); 592*e71b7053SJung-uk Kim } 593*e71b7053SJung-uk Kim } 594*e71b7053SJung-uk Kim # endif 595*e71b7053SJung-uk Kim 596*e71b7053SJung-uk Kim req = NULL; 597*e71b7053SJung-uk Kim if (!do_responder(&req, &cbio, acbio, req_timeout)) 598*e71b7053SJung-uk Kim goto redo_accept; 599*e71b7053SJung-uk Kim 600*e71b7053SJung-uk Kim if (req == NULL) { 6016f9291ceSJung-uk Kim resp = 6026f9291ceSJung-uk Kim OCSP_response_create(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, 6036f9291ceSJung-uk Kim NULL); 6045c87c606SMark Murray send_ocsp_response(cbio, resp); 6055c87c606SMark Murray goto done_resp; 6065c87c606SMark Murray } 6075c87c606SMark Murray } 6085c87c606SMark Murray 609*e71b7053SJung-uk Kim if (req == NULL 610*e71b7053SJung-uk Kim && (signfile != NULL || reqout != NULL 611*e71b7053SJung-uk Kim || host != NULL || add_nonce || ridx_filename != NULL)) { 6125c87c606SMark Murray BIO_printf(bio_err, "Need an OCSP request for this operation!\n"); 6135c87c606SMark Murray goto end; 6145c87c606SMark Murray } 6155c87c606SMark Murray 616*e71b7053SJung-uk Kim if (req != NULL && add_nonce) 6176f9291ceSJung-uk Kim OCSP_request_add1_nonce(req, NULL, -1); 6185c87c606SMark Murray 619*e71b7053SJung-uk Kim if (signfile != NULL) { 620*e71b7053SJung-uk Kim if (keyfile == NULL) 6216f9291ceSJung-uk Kim keyfile = signfile; 622*e71b7053SJung-uk Kim signer = load_cert(signfile, FORMAT_PEM, "signer certificate"); 623*e71b7053SJung-uk Kim if (signer == NULL) { 6245c87c606SMark Murray BIO_printf(bio_err, "Error loading signer certificate\n"); 6255c87c606SMark Murray goto end; 6265c87c606SMark Murray } 627*e71b7053SJung-uk Kim if (sign_certfile != NULL) { 628*e71b7053SJung-uk Kim if (!load_certs(sign_certfile, &sign_other, FORMAT_PEM, NULL, 629*e71b7053SJung-uk Kim "signer certificates")) 6306f9291ceSJung-uk Kim goto end; 6315c87c606SMark Murray } 632*e71b7053SJung-uk Kim key = load_key(keyfile, FORMAT_PEM, 0, NULL, NULL, 6335c87c606SMark Murray "signer private key"); 634*e71b7053SJung-uk Kim if (key == NULL) 6355c87c606SMark Murray goto end; 6361f13597dSJung-uk Kim 6376f9291ceSJung-uk Kim if (!OCSP_request_sign 6386f9291ceSJung-uk Kim (req, signer, key, NULL, sign_other, sign_flags)) { 6395c87c606SMark Murray BIO_printf(bio_err, "Error signing OCSP request\n"); 6405c87c606SMark Murray goto end; 6415c87c606SMark Murray } 6425c87c606SMark Murray } 6435c87c606SMark Murray 644*e71b7053SJung-uk Kim if (req_text && req != NULL) 6456f9291ceSJung-uk Kim OCSP_REQUEST_print(out, req, 0); 6465c87c606SMark Murray 647*e71b7053SJung-uk Kim if (reqout != NULL) { 648*e71b7053SJung-uk Kim derbio = bio_open_default(reqout, 'w', FORMAT_ASN1); 649*e71b7053SJung-uk Kim if (derbio == NULL) 6505c87c606SMark Murray goto end; 6515c87c606SMark Murray i2d_OCSP_REQUEST_bio(derbio, req); 6525c87c606SMark Murray BIO_free(derbio); 6535c87c606SMark Murray } 6545c87c606SMark Murray 655*e71b7053SJung-uk Kim if (rdb != NULL) { 656*e71b7053SJung-uk Kim make_ocsp_response(bio_err, &resp, req, rdb, rca_cert, rsigner, rkey, 657*e71b7053SJung-uk Kim rsign_md, rsign_sigopts, rother, rflags, nmin, ndays, badsig); 658*e71b7053SJung-uk Kim if (cbio != NULL) 6595c87c606SMark Murray send_ocsp_response(cbio, resp); 660*e71b7053SJung-uk Kim } else if (host != NULL) { 661fceca8a3SJacques Vidrine # ifndef OPENSSL_NO_SOCK 662*e71b7053SJung-uk Kim resp = process_responder(req, host, path, 6631f13597dSJung-uk Kim port, use_ssl, headers, req_timeout); 664*e71b7053SJung-uk Kim if (resp == NULL) 665db522d3aSSimon L. B. Nielsen goto end; 666fceca8a3SJacques Vidrine # else 6676f9291ceSJung-uk Kim BIO_printf(bio_err, 6686f9291ceSJung-uk Kim "Error creating connect BIO - sockets not supported.\n"); 669fceca8a3SJacques Vidrine goto end; 670fceca8a3SJacques Vidrine # endif 671*e71b7053SJung-uk Kim } else if (respin != NULL) { 672*e71b7053SJung-uk Kim derbio = bio_open_default(respin, 'r', FORMAT_ASN1); 673*e71b7053SJung-uk Kim if (derbio == NULL) 6745c87c606SMark Murray goto end; 6755c87c606SMark Murray resp = d2i_OCSP_RESPONSE_bio(derbio, NULL); 6765c87c606SMark Murray BIO_free(derbio); 677*e71b7053SJung-uk Kim if (resp == NULL) { 6785c87c606SMark Murray BIO_printf(bio_err, "Error reading OCSP response\n"); 6795c87c606SMark Murray goto end; 6805c87c606SMark Murray } 6816f9291ceSJung-uk Kim } else { 6825c87c606SMark Murray ret = 0; 6835c87c606SMark Murray goto end; 6845c87c606SMark Murray } 6855c87c606SMark Murray 6865c87c606SMark Murray done_resp: 6875c87c606SMark Murray 688*e71b7053SJung-uk Kim if (respout != NULL) { 689*e71b7053SJung-uk Kim derbio = bio_open_default(respout, 'w', FORMAT_ASN1); 690*e71b7053SJung-uk Kim if (derbio == NULL) 6915c87c606SMark Murray goto end; 6925c87c606SMark Murray i2d_OCSP_RESPONSE_bio(derbio, resp); 6935c87c606SMark Murray BIO_free(derbio); 6945c87c606SMark Murray } 6955c87c606SMark Murray 6965c87c606SMark Murray i = OCSP_response_status(resp); 6976f9291ceSJung-uk Kim if (i != OCSP_RESPONSE_STATUS_SUCCESSFUL) { 6983b4e3dcbSSimon L. B. Nielsen BIO_printf(out, "Responder Error: %s (%d)\n", 6995c87c606SMark Murray OCSP_response_status_str(i), i); 700*e71b7053SJung-uk Kim if (!ignore_err) 7015c87c606SMark Murray goto end; 7025c87c606SMark Murray } 7035c87c606SMark Murray 7046f9291ceSJung-uk Kim if (resp_text) 7056f9291ceSJung-uk Kim OCSP_RESPONSE_print(out, resp, 0); 7065c87c606SMark Murray 7075c87c606SMark Murray /* If running as responder don't verify our own response */ 708*e71b7053SJung-uk Kim if (cbio != NULL) { 709*e71b7053SJung-uk Kim /* If not unlimited, see if we took all we should. */ 710*e71b7053SJung-uk Kim if (accept_count != -1 && --accept_count <= 0) { 711*e71b7053SJung-uk Kim ret = 0; 712*e71b7053SJung-uk Kim goto end; 713*e71b7053SJung-uk Kim } 7145c87c606SMark Murray BIO_free_all(cbio); 7155c87c606SMark Murray cbio = NULL; 7165c87c606SMark Murray OCSP_REQUEST_free(req); 7175c87c606SMark Murray req = NULL; 7185c87c606SMark Murray OCSP_RESPONSE_free(resp); 7195c87c606SMark Murray resp = NULL; 7205c87c606SMark Murray goto redo_accept; 7215c87c606SMark Murray } 722*e71b7053SJung-uk Kim if (ridx_filename != NULL) { 7237bded2dbSJung-uk Kim ret = 0; 7245c87c606SMark Murray goto end; 7255c87c606SMark Murray } 7265c87c606SMark Murray 727*e71b7053SJung-uk Kim if (store == NULL) { 728*e71b7053SJung-uk Kim store = setup_verify(CAfile, CApath, noCAfile, noCApath); 7295c87c606SMark Murray if (!store) 7305c87c606SMark Murray goto end; 731*e71b7053SJung-uk Kim } 732*e71b7053SJung-uk Kim if (vpmtouched) 7337bded2dbSJung-uk Kim X509_STORE_set1_param(store, vpm); 734*e71b7053SJung-uk Kim if (verify_certfile != NULL) { 735*e71b7053SJung-uk Kim if (!load_certs(verify_certfile, &verify_other, FORMAT_PEM, NULL, 736*e71b7053SJung-uk Kim "validator certificate")) 7376f9291ceSJung-uk Kim goto end; 7385c87c606SMark Murray } 7395c87c606SMark Murray 7405c87c606SMark Murray bs = OCSP_response_get1_basic(resp); 741*e71b7053SJung-uk Kim if (bs == NULL) { 7425c87c606SMark Murray BIO_printf(bio_err, "Error parsing response\n"); 7435c87c606SMark Murray goto end; 7445c87c606SMark Murray } 7455c87c606SMark Murray 7467bded2dbSJung-uk Kim ret = 0; 7477bded2dbSJung-uk Kim 7486f9291ceSJung-uk Kim if (!noverify) { 749*e71b7053SJung-uk Kim if (req != NULL && ((i = OCSP_check_nonce(req, bs)) <= 0)) { 7505c87c606SMark Murray if (i == -1) 7515c87c606SMark Murray BIO_printf(bio_err, "WARNING: no nonce in response\n"); 7526f9291ceSJung-uk Kim else { 7535c87c606SMark Murray BIO_printf(bio_err, "Nonce Verify error\n"); 7547bded2dbSJung-uk Kim ret = 1; 7555c87c606SMark Murray goto end; 7565c87c606SMark Murray } 7575c87c606SMark Murray } 7585c87c606SMark Murray 7595c87c606SMark Murray i = OCSP_basic_verify(bs, verify_other, store, verify_flags); 760*e71b7053SJung-uk Kim if (i <= 0 && issuers) { 761*e71b7053SJung-uk Kim i = OCSP_basic_verify(bs, issuers, store, OCSP_TRUSTOTHER); 762*e71b7053SJung-uk Kim if (i > 0) 763*e71b7053SJung-uk Kim ERR_clear_error(); 764*e71b7053SJung-uk Kim } 7656f9291ceSJung-uk Kim if (i <= 0) { 7663b4e3dcbSSimon L. B. Nielsen BIO_printf(bio_err, "Response Verify Failure\n"); 7675c87c606SMark Murray ERR_print_errors(bio_err); 7687bded2dbSJung-uk Kim ret = 1; 769*e71b7053SJung-uk Kim } else { 7705c87c606SMark Murray BIO_printf(bio_err, "Response verify OK\n"); 771*e71b7053SJung-uk Kim } 7725c87c606SMark Murray } 7735c87c606SMark Murray 774*e71b7053SJung-uk Kim print_ocsp_summary(out, bs, req, reqnames, ids, nsec, maxage); 7755c87c606SMark Murray 7765c87c606SMark Murray end: 7775c87c606SMark Murray ERR_print_errors(bio_err); 7785c87c606SMark Murray X509_free(signer); 7795c87c606SMark Murray X509_STORE_free(store); 7807bded2dbSJung-uk Kim X509_VERIFY_PARAM_free(vpm); 781*e71b7053SJung-uk Kim sk_OPENSSL_STRING_free(rsign_sigopts); 7825c87c606SMark Murray EVP_PKEY_free(key); 7835c87c606SMark Murray EVP_PKEY_free(rkey); 7845c87c606SMark Murray X509_free(cert); 785*e71b7053SJung-uk Kim sk_X509_pop_free(issuers, X509_free); 7865c87c606SMark Murray X509_free(rsigner); 787*e71b7053SJung-uk Kim sk_X509_pop_free(rca_cert, X509_free); 788ced566fdSJacques Vidrine free_index(rdb); 7895c87c606SMark Murray BIO_free_all(cbio); 7905c87c606SMark Murray BIO_free_all(acbio); 791*e71b7053SJung-uk Kim BIO_free_all(out); 7925c87c606SMark Murray OCSP_REQUEST_free(req); 7935c87c606SMark Murray OCSP_RESPONSE_free(resp); 7945c87c606SMark Murray OCSP_BASICRESP_free(bs); 7951f13597dSJung-uk Kim sk_OPENSSL_STRING_free(reqnames); 7965c87c606SMark Murray sk_OCSP_CERTID_free(ids); 7975c87c606SMark Murray sk_X509_pop_free(sign_other, X509_free); 7985c87c606SMark Murray sk_X509_pop_free(verify_other, X509_free); 7991f13597dSJung-uk Kim sk_CONF_VALUE_pop_free(headers, X509V3_conf_free); 80094ad176cSJung-uk Kim OPENSSL_free(thost); 80194ad176cSJung-uk Kim OPENSSL_free(tport); 80294ad176cSJung-uk Kim OPENSSL_free(tpath); 8035c87c606SMark Murray 804*e71b7053SJung-uk Kim return ret; 8055c87c606SMark Murray } 8065c87c606SMark Murray 807*e71b7053SJung-uk Kim static void 808*e71b7053SJung-uk Kim log_message(int level, const char *fmt, ...) 809*e71b7053SJung-uk Kim { 810*e71b7053SJung-uk Kim va_list ap; 811*e71b7053SJung-uk Kim 812*e71b7053SJung-uk Kim va_start(ap, fmt); 813*e71b7053SJung-uk Kim # ifdef OCSP_DAEMON 814*e71b7053SJung-uk Kim if (multi) { 815*e71b7053SJung-uk Kim char buf[1024]; 816*e71b7053SJung-uk Kim if (vsnprintf(buf, sizeof(buf), fmt, ap) > 0) { 817*e71b7053SJung-uk Kim syslog(level, "%s", buf); 818*e71b7053SJung-uk Kim } 819*e71b7053SJung-uk Kim if (level >= LOG_ERR) 820*e71b7053SJung-uk Kim ERR_print_errors_cb(print_syslog, &level); 821*e71b7053SJung-uk Kim } 822*e71b7053SJung-uk Kim # endif 823*e71b7053SJung-uk Kim if (!multi) { 824*e71b7053SJung-uk Kim BIO_printf(bio_err, "%s: ", prog); 825*e71b7053SJung-uk Kim BIO_vprintf(bio_err, fmt, ap); 826*e71b7053SJung-uk Kim BIO_printf(bio_err, "\n"); 827*e71b7053SJung-uk Kim } 828*e71b7053SJung-uk Kim va_end(ap); 829*e71b7053SJung-uk Kim } 830*e71b7053SJung-uk Kim 831*e71b7053SJung-uk Kim # ifdef OCSP_DAEMON 832*e71b7053SJung-uk Kim 833*e71b7053SJung-uk Kim static int print_syslog(const char *str, size_t len, void *levPtr) 834*e71b7053SJung-uk Kim { 835*e71b7053SJung-uk Kim int level = *(int *)levPtr; 836*e71b7053SJung-uk Kim int ilen = (len > MAXERRLEN) ? MAXERRLEN : len; 837*e71b7053SJung-uk Kim 838*e71b7053SJung-uk Kim syslog(level, "%.*s", ilen, str); 839*e71b7053SJung-uk Kim 840*e71b7053SJung-uk Kim return ilen; 841*e71b7053SJung-uk Kim } 842*e71b7053SJung-uk Kim 843*e71b7053SJung-uk Kim static int index_changed(CA_DB *rdb) 844*e71b7053SJung-uk Kim { 845*e71b7053SJung-uk Kim struct stat sb; 846*e71b7053SJung-uk Kim 847*e71b7053SJung-uk Kim if (rdb != NULL && stat(rdb->dbfname, &sb) != -1) { 848*e71b7053SJung-uk Kim if (rdb->dbst.st_mtime != sb.st_mtime 849*e71b7053SJung-uk Kim || rdb->dbst.st_ctime != sb.st_ctime 850*e71b7053SJung-uk Kim || rdb->dbst.st_ino != sb.st_ino 851*e71b7053SJung-uk Kim || rdb->dbst.st_dev != sb.st_dev) { 852*e71b7053SJung-uk Kim syslog(LOG_INFO, "index file changed, reloading"); 853*e71b7053SJung-uk Kim return 1; 854*e71b7053SJung-uk Kim } 855*e71b7053SJung-uk Kim } 856*e71b7053SJung-uk Kim return 0; 857*e71b7053SJung-uk Kim } 858*e71b7053SJung-uk Kim 859*e71b7053SJung-uk Kim static void killall(int ret, pid_t *kidpids) 860*e71b7053SJung-uk Kim { 861*e71b7053SJung-uk Kim int i; 862*e71b7053SJung-uk Kim 863*e71b7053SJung-uk Kim for (i = 0; i < multi; ++i) 864*e71b7053SJung-uk Kim if (kidpids[i] != 0) 865*e71b7053SJung-uk Kim (void)kill(kidpids[i], SIGTERM); 866*e71b7053SJung-uk Kim sleep(1); 867*e71b7053SJung-uk Kim exit(ret); 868*e71b7053SJung-uk Kim } 869*e71b7053SJung-uk Kim 870*e71b7053SJung-uk Kim static int termsig = 0; 871*e71b7053SJung-uk Kim 872*e71b7053SJung-uk Kim static void noteterm (int sig) 873*e71b7053SJung-uk Kim { 874*e71b7053SJung-uk Kim termsig = sig; 875*e71b7053SJung-uk Kim } 876*e71b7053SJung-uk Kim 877*e71b7053SJung-uk Kim /* 878*e71b7053SJung-uk Kim * Loop spawning up to `multi` child processes, only child processes return 879*e71b7053SJung-uk Kim * from this function. The parent process loops until receiving a termination 880*e71b7053SJung-uk Kim * signal, kills extant children and exits without returning. 881*e71b7053SJung-uk Kim */ 882*e71b7053SJung-uk Kim static void spawn_loop(void) 883*e71b7053SJung-uk Kim { 884*e71b7053SJung-uk Kim pid_t *kidpids = NULL; 885*e71b7053SJung-uk Kim int status; 886*e71b7053SJung-uk Kim int procs = 0; 887*e71b7053SJung-uk Kim int i; 888*e71b7053SJung-uk Kim 889*e71b7053SJung-uk Kim openlog(prog, LOG_PID, LOG_DAEMON); 890*e71b7053SJung-uk Kim 891*e71b7053SJung-uk Kim if (setpgid(0, 0)) { 892*e71b7053SJung-uk Kim syslog(LOG_ERR, "fatal: error detaching from parent process group: %s", 893*e71b7053SJung-uk Kim strerror(errno)); 894*e71b7053SJung-uk Kim exit(1); 895*e71b7053SJung-uk Kim } 896*e71b7053SJung-uk Kim kidpids = app_malloc(multi * sizeof(*kidpids), "child PID array"); 897*e71b7053SJung-uk Kim for (i = 0; i < multi; ++i) 898*e71b7053SJung-uk Kim kidpids[i] = 0; 899*e71b7053SJung-uk Kim 900*e71b7053SJung-uk Kim signal(SIGINT, noteterm); 901*e71b7053SJung-uk Kim signal(SIGTERM, noteterm); 902*e71b7053SJung-uk Kim 903*e71b7053SJung-uk Kim while (termsig == 0) { 904*e71b7053SJung-uk Kim pid_t fpid; 905*e71b7053SJung-uk Kim 906*e71b7053SJung-uk Kim /* 907*e71b7053SJung-uk Kim * Wait for a child to replace when we're at the limit. 908*e71b7053SJung-uk Kim * Slow down if a child exited abnormally or waitpid() < 0 909*e71b7053SJung-uk Kim */ 910*e71b7053SJung-uk Kim while (termsig == 0 && procs >= multi) { 911*e71b7053SJung-uk Kim if ((fpid = waitpid(-1, &status, 0)) > 0) { 912*e71b7053SJung-uk Kim for (i = 0; i < procs; ++i) { 913*e71b7053SJung-uk Kim if (kidpids[i] == fpid) { 914*e71b7053SJung-uk Kim kidpids[i] = 0; 915*e71b7053SJung-uk Kim --procs; 916*e71b7053SJung-uk Kim break; 917*e71b7053SJung-uk Kim } 918*e71b7053SJung-uk Kim } 919*e71b7053SJung-uk Kim if (i >= multi) { 920*e71b7053SJung-uk Kim syslog(LOG_ERR, "fatal: internal error: " 921*e71b7053SJung-uk Kim "no matching child slot for pid: %ld", 922*e71b7053SJung-uk Kim (long) fpid); 923*e71b7053SJung-uk Kim killall(1, kidpids); 924*e71b7053SJung-uk Kim } 925*e71b7053SJung-uk Kim if (status != 0) { 926*e71b7053SJung-uk Kim if (WIFEXITED(status)) 927*e71b7053SJung-uk Kim syslog(LOG_WARNING, "child process: %ld, exit status: %d", 928*e71b7053SJung-uk Kim (long)fpid, WEXITSTATUS(status)); 929*e71b7053SJung-uk Kim else if (WIFSIGNALED(status)) 930*e71b7053SJung-uk Kim syslog(LOG_WARNING, "child process: %ld, term signal %d%s", 931*e71b7053SJung-uk Kim (long)fpid, WTERMSIG(status), 932*e71b7053SJung-uk Kim #ifdef WCOREDUMP 933*e71b7053SJung-uk Kim WCOREDUMP(status) ? " (core dumped)" : 934*e71b7053SJung-uk Kim #endif 935*e71b7053SJung-uk Kim ""); 936*e71b7053SJung-uk Kim sleep(1); 937*e71b7053SJung-uk Kim } 938*e71b7053SJung-uk Kim break; 939*e71b7053SJung-uk Kim } else if (errno != EINTR) { 940*e71b7053SJung-uk Kim syslog(LOG_ERR, "fatal: waitpid(): %s", strerror(errno)); 941*e71b7053SJung-uk Kim killall(1, kidpids); 942*e71b7053SJung-uk Kim } 943*e71b7053SJung-uk Kim } 944*e71b7053SJung-uk Kim if (termsig) 945*e71b7053SJung-uk Kim break; 946*e71b7053SJung-uk Kim 947*e71b7053SJung-uk Kim switch(fpid = fork()) { 948*e71b7053SJung-uk Kim case -1: /* error */ 949*e71b7053SJung-uk Kim /* System critically low on memory, pause and try again later */ 950*e71b7053SJung-uk Kim sleep(30); 951*e71b7053SJung-uk Kim break; 952*e71b7053SJung-uk Kim case 0: /* child */ 953*e71b7053SJung-uk Kim signal(SIGINT, SIG_DFL); 954*e71b7053SJung-uk Kim signal(SIGTERM, SIG_DFL); 955*e71b7053SJung-uk Kim if (termsig) 956*e71b7053SJung-uk Kim _exit(0); 957*e71b7053SJung-uk Kim if (RAND_poll() <= 0) { 958*e71b7053SJung-uk Kim syslog(LOG_ERR, "fatal: RAND_poll() failed"); 959*e71b7053SJung-uk Kim _exit(1); 960*e71b7053SJung-uk Kim } 961*e71b7053SJung-uk Kim return; 962*e71b7053SJung-uk Kim default: /* parent */ 963*e71b7053SJung-uk Kim for (i = 0; i < multi; ++i) { 964*e71b7053SJung-uk Kim if (kidpids[i] == 0) { 965*e71b7053SJung-uk Kim kidpids[i] = fpid; 966*e71b7053SJung-uk Kim procs++; 967*e71b7053SJung-uk Kim break; 968*e71b7053SJung-uk Kim } 969*e71b7053SJung-uk Kim } 970*e71b7053SJung-uk Kim if (i >= multi) { 971*e71b7053SJung-uk Kim syslog(LOG_ERR, "fatal: internal error: no free child slots"); 972*e71b7053SJung-uk Kim killall(1, kidpids); 973*e71b7053SJung-uk Kim } 974*e71b7053SJung-uk Kim break; 975*e71b7053SJung-uk Kim } 976*e71b7053SJung-uk Kim } 977*e71b7053SJung-uk Kim 978*e71b7053SJung-uk Kim /* The loop above can only break on termsig */ 979*e71b7053SJung-uk Kim syslog(LOG_INFO, "terminating on signal: %d", termsig); 980*e71b7053SJung-uk Kim killall(0, kidpids); 981*e71b7053SJung-uk Kim } 982*e71b7053SJung-uk Kim # endif 983*e71b7053SJung-uk Kim 9846f9291ceSJung-uk Kim static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, 9856f9291ceSJung-uk Kim const EVP_MD *cert_id_md, X509 *issuer, 9865c87c606SMark Murray STACK_OF(OCSP_CERTID) *ids) 9875c87c606SMark Murray { 9885c87c606SMark Murray OCSP_CERTID *id; 989*e71b7053SJung-uk Kim 990*e71b7053SJung-uk Kim if (issuer == NULL) { 9915c87c606SMark Murray BIO_printf(bio_err, "No issuer certificate specified\n"); 9925c87c606SMark Murray return 0; 9935c87c606SMark Murray } 994*e71b7053SJung-uk Kim if (*req == NULL) 9956f9291ceSJung-uk Kim *req = OCSP_REQUEST_new(); 996*e71b7053SJung-uk Kim if (*req == NULL) 9976f9291ceSJung-uk Kim goto err; 9981f13597dSJung-uk Kim id = OCSP_cert_to_id(cert_id_md, cert, issuer); 999*e71b7053SJung-uk Kim if (id == NULL || !sk_OCSP_CERTID_push(ids, id)) 10006f9291ceSJung-uk Kim goto err; 10016f9291ceSJung-uk Kim if (!OCSP_request_add0_id(*req, id)) 10026f9291ceSJung-uk Kim goto err; 10035c87c606SMark Murray return 1; 10045c87c606SMark Murray 10055c87c606SMark Murray err: 10065c87c606SMark Murray BIO_printf(bio_err, "Error Creating OCSP request\n"); 10075c87c606SMark Murray return 0; 10085c87c606SMark Murray } 10095c87c606SMark Murray 10106f9291ceSJung-uk Kim static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, 10116f9291ceSJung-uk Kim const EVP_MD *cert_id_md, X509 *issuer, 10125c87c606SMark Murray STACK_OF(OCSP_CERTID) *ids) 10135c87c606SMark Murray { 10145c87c606SMark Murray OCSP_CERTID *id; 10155c87c606SMark Murray X509_NAME *iname; 10165c87c606SMark Murray ASN1_BIT_STRING *ikey; 10175c87c606SMark Murray ASN1_INTEGER *sno; 1018*e71b7053SJung-uk Kim 1019*e71b7053SJung-uk Kim if (issuer == NULL) { 10205c87c606SMark Murray BIO_printf(bio_err, "No issuer certificate specified\n"); 10215c87c606SMark Murray return 0; 10225c87c606SMark Murray } 1023*e71b7053SJung-uk Kim if (*req == NULL) 10246f9291ceSJung-uk Kim *req = OCSP_REQUEST_new(); 1025*e71b7053SJung-uk Kim if (*req == NULL) 10266f9291ceSJung-uk Kim goto err; 10275c87c606SMark Murray iname = X509_get_subject_name(issuer); 10285c87c606SMark Murray ikey = X509_get0_pubkey_bitstr(issuer); 10295c87c606SMark Murray sno = s2i_ASN1_INTEGER(NULL, serial); 1030*e71b7053SJung-uk Kim if (sno == NULL) { 10315c87c606SMark Murray BIO_printf(bio_err, "Error converting serial number %s\n", serial); 10325c87c606SMark Murray return 0; 10335c87c606SMark Murray } 10341f13597dSJung-uk Kim id = OCSP_cert_id_new(cert_id_md, iname, ikey, sno); 10355c87c606SMark Murray ASN1_INTEGER_free(sno); 1036*e71b7053SJung-uk Kim if (id == NULL || !sk_OCSP_CERTID_push(ids, id)) 10376f9291ceSJung-uk Kim goto err; 10386f9291ceSJung-uk Kim if (!OCSP_request_add0_id(*req, id)) 10396f9291ceSJung-uk Kim goto err; 10405c87c606SMark Murray return 1; 10415c87c606SMark Murray 10425c87c606SMark Murray err: 10435c87c606SMark Murray BIO_printf(bio_err, "Error Creating OCSP request\n"); 10445c87c606SMark Murray return 0; 10455c87c606SMark Murray } 10465c87c606SMark Murray 1047*e71b7053SJung-uk Kim static void print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req, 10481f13597dSJung-uk Kim STACK_OF(OPENSSL_STRING) *names, 10491f13597dSJung-uk Kim STACK_OF(OCSP_CERTID) *ids, long nsec, 10501f13597dSJung-uk Kim long maxage) 10515c87c606SMark Murray { 10525c87c606SMark Murray OCSP_CERTID *id; 1053*e71b7053SJung-uk Kim const char *name; 1054*e71b7053SJung-uk Kim int i, status, reason; 10555c87c606SMark Murray ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; 10565c87c606SMark Murray 1057*e71b7053SJung-uk Kim if (bs == NULL || req == NULL || !sk_OPENSSL_STRING_num(names) 10586f9291ceSJung-uk Kim || !sk_OCSP_CERTID_num(ids)) 1059*e71b7053SJung-uk Kim return; 10605c87c606SMark Murray 10616f9291ceSJung-uk Kim for (i = 0; i < sk_OCSP_CERTID_num(ids); i++) { 10625c87c606SMark Murray id = sk_OCSP_CERTID_value(ids, i); 10631f13597dSJung-uk Kim name = sk_OPENSSL_STRING_value(names, i); 10645c87c606SMark Murray BIO_printf(out, "%s: ", name); 10655c87c606SMark Murray 10665c87c606SMark Murray if (!OCSP_resp_find_status(bs, id, &status, &reason, 10676f9291ceSJung-uk Kim &rev, &thisupd, &nextupd)) { 10685c87c606SMark Murray BIO_puts(out, "ERROR: No Status found.\n"); 10695c87c606SMark Murray continue; 10705c87c606SMark Murray } 10715c87c606SMark Murray 10726f9291ceSJung-uk Kim /* 10736f9291ceSJung-uk Kim * Check validity: if invalid write to output BIO so we know which 10746f9291ceSJung-uk Kim * response this refers to. 10755c87c606SMark Murray */ 10766f9291ceSJung-uk Kim if (!OCSP_check_validity(thisupd, nextupd, nsec, maxage)) { 10775c87c606SMark Murray BIO_puts(out, "WARNING: Status times invalid.\n"); 10785c87c606SMark Murray ERR_print_errors(out); 10795c87c606SMark Murray } 10805c87c606SMark Murray BIO_printf(out, "%s\n", OCSP_cert_status_str(status)); 10815c87c606SMark Murray 10825c87c606SMark Murray BIO_puts(out, "\tThis Update: "); 10835c87c606SMark Murray ASN1_GENERALIZEDTIME_print(out, thisupd); 10845c87c606SMark Murray BIO_puts(out, "\n"); 10855c87c606SMark Murray 10866f9291ceSJung-uk Kim if (nextupd) { 10875c87c606SMark Murray BIO_puts(out, "\tNext Update: "); 10885c87c606SMark Murray ASN1_GENERALIZEDTIME_print(out, nextupd); 10895c87c606SMark Murray BIO_puts(out, "\n"); 10905c87c606SMark Murray } 10915c87c606SMark Murray 10925c87c606SMark Murray if (status != V_OCSP_CERTSTATUS_REVOKED) 10935c87c606SMark Murray continue; 10945c87c606SMark Murray 10955c87c606SMark Murray if (reason != -1) 10966f9291ceSJung-uk Kim BIO_printf(out, "\tReason: %s\n", OCSP_crl_reason_str(reason)); 10975c87c606SMark Murray 10985c87c606SMark Murray BIO_puts(out, "\tRevocation Time: "); 10995c87c606SMark Murray ASN1_GENERALIZEDTIME_print(out, rev); 11005c87c606SMark Murray BIO_puts(out, "\n"); 11015c87c606SMark Murray } 11025c87c606SMark Murray } 11035c87c606SMark Murray 1104*e71b7053SJung-uk Kim static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req, 1105*e71b7053SJung-uk Kim CA_DB *db, STACK_OF(X509) *ca, X509 *rcert, 11067bded2dbSJung-uk Kim EVP_PKEY *rkey, const EVP_MD *rmd, 1107*e71b7053SJung-uk Kim STACK_OF(OPENSSL_STRING) *sigopts, 11087bded2dbSJung-uk Kim STACK_OF(X509) *rother, unsigned long flags, 11097bded2dbSJung-uk Kim int nmin, int ndays, int badsig) 11105c87c606SMark Murray { 11115c87c606SMark Murray ASN1_TIME *thisupd = NULL, *nextupd = NULL; 1112*e71b7053SJung-uk Kim OCSP_CERTID *cid; 11135c87c606SMark Murray OCSP_BASICRESP *bs = NULL; 1114*e71b7053SJung-uk Kim int i, id_count; 1115*e71b7053SJung-uk Kim EVP_MD_CTX *mctx = NULL; 1116*e71b7053SJung-uk Kim EVP_PKEY_CTX *pkctx = NULL; 11175c87c606SMark Murray 11185c87c606SMark Murray id_count = OCSP_request_onereq_count(req); 11195c87c606SMark Murray 11206f9291ceSJung-uk Kim if (id_count <= 0) { 11216f9291ceSJung-uk Kim *resp = 11226f9291ceSJung-uk Kim OCSP_response_create(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, NULL); 11235c87c606SMark Murray goto end; 11245c87c606SMark Murray } 11255c87c606SMark Murray 11265c87c606SMark Murray bs = OCSP_BASICRESP_new(); 11275c87c606SMark Murray thisupd = X509_gmtime_adj(NULL, 0); 11285c87c606SMark Murray if (ndays != -1) 11298180e704SJung-uk Kim nextupd = X509_time_adj_ex(NULL, ndays, nmin * 60, NULL); 11305c87c606SMark Murray 11315c87c606SMark Murray /* Examine each certificate id in the request */ 11326f9291ceSJung-uk Kim for (i = 0; i < id_count; i++) { 11335c87c606SMark Murray OCSP_ONEREQ *one; 11345c87c606SMark Murray ASN1_INTEGER *serial; 11355c87c606SMark Murray char **inf; 1136*e71b7053SJung-uk Kim int jj; 1137*e71b7053SJung-uk Kim int found = 0; 11381f13597dSJung-uk Kim ASN1_OBJECT *cert_id_md_oid; 11391f13597dSJung-uk Kim const EVP_MD *cert_id_md; 11405c87c606SMark Murray one = OCSP_request_onereq_get0(req, i); 11415c87c606SMark Murray cid = OCSP_onereq_get0_id(one); 11421f13597dSJung-uk Kim 11431f13597dSJung-uk Kim OCSP_id_get0_info(NULL, &cert_id_md_oid, NULL, NULL, cid); 11441f13597dSJung-uk Kim 11451f13597dSJung-uk Kim cert_id_md = EVP_get_digestbyobj(cert_id_md_oid); 1146*e71b7053SJung-uk Kim if (cert_id_md == NULL) { 11471f13597dSJung-uk Kim *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_INTERNALERROR, 11481f13597dSJung-uk Kim NULL); 11491f13597dSJung-uk Kim goto end; 11501f13597dSJung-uk Kim } 1151*e71b7053SJung-uk Kim for (jj = 0; jj < sk_X509_num(ca) && !found; jj++) { 1152*e71b7053SJung-uk Kim X509 *ca_cert = sk_X509_value(ca, jj); 1153*e71b7053SJung-uk Kim OCSP_CERTID *ca_id = OCSP_cert_to_id(cert_id_md, NULL, ca_cert); 11541f13597dSJung-uk Kim 1155*e71b7053SJung-uk Kim if (OCSP_id_issuer_cmp(ca_id, cid) == 0) 1156*e71b7053SJung-uk Kim found = 1; 1157*e71b7053SJung-uk Kim 1158*e71b7053SJung-uk Kim OCSP_CERTID_free(ca_id); 1159*e71b7053SJung-uk Kim } 1160*e71b7053SJung-uk Kim 1161*e71b7053SJung-uk Kim if (!found) { 11625c87c606SMark Murray OCSP_basic_add1_status(bs, cid, 11635c87c606SMark Murray V_OCSP_CERTSTATUS_UNKNOWN, 11646f9291ceSJung-uk Kim 0, NULL, thisupd, nextupd); 11655c87c606SMark Murray continue; 11665c87c606SMark Murray } 11675c87c606SMark Murray OCSP_id_get0_info(NULL, NULL, NULL, &serial, cid); 11685c87c606SMark Murray inf = lookup_serial(db, serial); 1169*e71b7053SJung-uk Kim if (inf == NULL) { 11705c87c606SMark Murray OCSP_basic_add1_status(bs, cid, 11715c87c606SMark Murray V_OCSP_CERTSTATUS_UNKNOWN, 11726f9291ceSJung-uk Kim 0, NULL, thisupd, nextupd); 1173*e71b7053SJung-uk Kim } else if (inf[DB_type][0] == DB_TYPE_VAL) { 11745c87c606SMark Murray OCSP_basic_add1_status(bs, cid, 11755c87c606SMark Murray V_OCSP_CERTSTATUS_GOOD, 11766f9291ceSJung-uk Kim 0, NULL, thisupd, nextupd); 1177*e71b7053SJung-uk Kim } else if (inf[DB_type][0] == DB_TYPE_REV) { 11785c87c606SMark Murray ASN1_OBJECT *inst = NULL; 11795c87c606SMark Murray ASN1_TIME *revtm = NULL; 11805c87c606SMark Murray ASN1_GENERALIZEDTIME *invtm = NULL; 11815c87c606SMark Murray OCSP_SINGLERESP *single; 11825c87c606SMark Murray int reason = -1; 11835c87c606SMark Murray unpack_revinfo(&revtm, &reason, &inst, &invtm, inf[DB_rev_date]); 11845c87c606SMark Murray single = OCSP_basic_add1_status(bs, cid, 11855c87c606SMark Murray V_OCSP_CERTSTATUS_REVOKED, 11866f9291ceSJung-uk Kim reason, revtm, thisupd, nextupd); 1187*e71b7053SJung-uk Kim if (invtm != NULL) 11886f9291ceSJung-uk Kim OCSP_SINGLERESP_add1_ext_i2d(single, NID_invalidity_date, 11896f9291ceSJung-uk Kim invtm, 0, 0); 1190*e71b7053SJung-uk Kim else if (inst != NULL) 11916f9291ceSJung-uk Kim OCSP_SINGLERESP_add1_ext_i2d(single, 11926f9291ceSJung-uk Kim NID_hold_instruction_code, inst, 11936f9291ceSJung-uk Kim 0, 0); 11945c87c606SMark Murray ASN1_OBJECT_free(inst); 11955c87c606SMark Murray ASN1_TIME_free(revtm); 11965c87c606SMark Murray ASN1_GENERALIZEDTIME_free(invtm); 11975c87c606SMark Murray } 11985c87c606SMark Murray } 11995c87c606SMark Murray 12005c87c606SMark Murray OCSP_copy_nonce(bs, req); 12015c87c606SMark Murray 1202*e71b7053SJung-uk Kim mctx = EVP_MD_CTX_new(); 1203*e71b7053SJung-uk Kim if ( mctx == NULL || !EVP_DigestSignInit(mctx, &pkctx, rmd, NULL, rkey)) { 1204*e71b7053SJung-uk Kim *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_INTERNALERROR, NULL); 1205*e71b7053SJung-uk Kim goto end; 1206*e71b7053SJung-uk Kim } 1207*e71b7053SJung-uk Kim for (i = 0; i < sk_OPENSSL_STRING_num(sigopts); i++) { 1208*e71b7053SJung-uk Kim char *sigopt = sk_OPENSSL_STRING_value(sigopts, i); 12097bded2dbSJung-uk Kim 1210*e71b7053SJung-uk Kim if (pkey_ctrl_string(pkctx, sigopt) <= 0) { 1211*e71b7053SJung-uk Kim BIO_printf(err, "parameter error \"%s\"\n", sigopt); 1212*e71b7053SJung-uk Kim ERR_print_errors(bio_err); 1213*e71b7053SJung-uk Kim *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_INTERNALERROR, 1214*e71b7053SJung-uk Kim NULL); 1215*e71b7053SJung-uk Kim goto end; 1216*e71b7053SJung-uk Kim } 1217*e71b7053SJung-uk Kim } 1218*e71b7053SJung-uk Kim OCSP_basic_sign_ctx(bs, rcert, mctx, rother, flags); 1219*e71b7053SJung-uk Kim 1220*e71b7053SJung-uk Kim if (badsig) { 1221*e71b7053SJung-uk Kim const ASN1_OCTET_STRING *sig = OCSP_resp_get0_signature(bs); 1222*e71b7053SJung-uk Kim corrupt_signature(sig); 1223*e71b7053SJung-uk Kim } 12245c87c606SMark Murray 12255c87c606SMark Murray *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_SUCCESSFUL, bs); 12265c87c606SMark Murray 12275c87c606SMark Murray end: 1228*e71b7053SJung-uk Kim EVP_MD_CTX_free(mctx); 12295c87c606SMark Murray ASN1_TIME_free(thisupd); 12305c87c606SMark Murray ASN1_TIME_free(nextupd); 12315c87c606SMark Murray OCSP_BASICRESP_free(bs); 12325c87c606SMark Murray } 12335c87c606SMark Murray 1234ced566fdSJacques Vidrine static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser) 12355c87c606SMark Murray { 12365c87c606SMark Murray int i; 12375c87c606SMark Murray BIGNUM *bn = NULL; 12385c87c606SMark Murray char *itmp, *row[DB_NUMBER], **rrow; 12396f9291ceSJung-uk Kim for (i = 0; i < DB_NUMBER; i++) 12406f9291ceSJung-uk Kim row[i] = NULL; 12415c87c606SMark Murray bn = ASN1_INTEGER_to_BN(ser, NULL); 12426f9291ceSJung-uk Kim OPENSSL_assert(bn); /* FIXME: should report an error at this 12436f9291ceSJung-uk Kim * point and abort */ 12445c87c606SMark Murray if (BN_is_zero(bn)) 1245*e71b7053SJung-uk Kim itmp = OPENSSL_strdup("00"); 12465c87c606SMark Murray else 12475c87c606SMark Murray itmp = BN_bn2hex(bn); 12485c87c606SMark Murray row[DB_serial] = itmp; 12495c87c606SMark Murray BN_free(bn); 1250ced566fdSJacques Vidrine rrow = TXT_DB_get_by_index(db->db, DB_serial, row); 12515c87c606SMark Murray OPENSSL_free(itmp); 12525c87c606SMark Murray return rrow; 12535c87c606SMark Murray } 12545c87c606SMark Murray 12555c87c606SMark Murray /* Quick and dirty OCSP server: read in and parse input request */ 12565c87c606SMark Murray 12577bded2dbSJung-uk Kim static BIO *init_responder(const char *port) 12585c87c606SMark Murray { 1259*e71b7053SJung-uk Kim # ifdef OPENSSL_NO_SOCK 12606f9291ceSJung-uk Kim BIO_printf(bio_err, 12616f9291ceSJung-uk Kim "Error setting up accept BIO - sockets not supported.\n"); 1262*e71b7053SJung-uk Kim return NULL; 1263*e71b7053SJung-uk Kim # else 1264*e71b7053SJung-uk Kim BIO *acbio = NULL, *bufbio = NULL; 1265*e71b7053SJung-uk Kim 1266*e71b7053SJung-uk Kim bufbio = BIO_new(BIO_f_buffer()); 1267*e71b7053SJung-uk Kim if (bufbio == NULL) 12685c87c606SMark Murray goto err; 1269*e71b7053SJung-uk Kim acbio = BIO_new(BIO_s_accept()); 1270*e71b7053SJung-uk Kim if (acbio == NULL 1271*e71b7053SJung-uk Kim || BIO_set_bind_mode(acbio, BIO_BIND_REUSEADDR) < 0 1272*e71b7053SJung-uk Kim || BIO_set_accept_port(acbio, port) < 0) { 1273*e71b7053SJung-uk Kim log_message(LOG_ERR, "Error setting up accept BIO"); 1274*e71b7053SJung-uk Kim goto err; 1275*e71b7053SJung-uk Kim } 1276*e71b7053SJung-uk Kim 12775c87c606SMark Murray BIO_set_accept_bios(acbio, bufbio); 12785c87c606SMark Murray bufbio = NULL; 12796f9291ceSJung-uk Kim if (BIO_do_accept(acbio) <= 0) { 1280*e71b7053SJung-uk Kim log_message(LOG_ERR, "Error starting accept"); 12815c87c606SMark Murray goto err; 12825c87c606SMark Murray } 12835c87c606SMark Murray 12845c87c606SMark Murray return acbio; 12855c87c606SMark Murray 12865c87c606SMark Murray err: 12875c87c606SMark Murray BIO_free_all(acbio); 12885c87c606SMark Murray BIO_free(bufbio); 12895c87c606SMark Murray return NULL; 1290*e71b7053SJung-uk Kim # endif 12915c87c606SMark Murray } 12925c87c606SMark Murray 1293*e71b7053SJung-uk Kim # ifndef OPENSSL_NO_SOCK 1294*e71b7053SJung-uk Kim /* 1295*e71b7053SJung-uk Kim * Decode %xx URL-decoding in-place. Ignores mal-formed sequences. 1296*e71b7053SJung-uk Kim */ 1297*e71b7053SJung-uk Kim static int urldecode(char *p) 1298*e71b7053SJung-uk Kim { 1299*e71b7053SJung-uk Kim unsigned char *out = (unsigned char *)p; 1300*e71b7053SJung-uk Kim unsigned char *save = out; 1301*e71b7053SJung-uk Kim 1302*e71b7053SJung-uk Kim for (; *p; p++) { 1303*e71b7053SJung-uk Kim if (*p != '%') 1304*e71b7053SJung-uk Kim *out++ = *p; 1305*e71b7053SJung-uk Kim else if (isxdigit(_UC(p[1])) && isxdigit(_UC(p[2]))) { 1306*e71b7053SJung-uk Kim /* Don't check, can't fail because of ixdigit() call. */ 1307*e71b7053SJung-uk Kim *out++ = (OPENSSL_hexchar2int(p[1]) << 4) 1308*e71b7053SJung-uk Kim | OPENSSL_hexchar2int(p[2]); 1309*e71b7053SJung-uk Kim p += 2; 1310*e71b7053SJung-uk Kim } 1311*e71b7053SJung-uk Kim else 1312*e71b7053SJung-uk Kim return -1; 1313*e71b7053SJung-uk Kim } 1314*e71b7053SJung-uk Kim *out = '\0'; 1315*e71b7053SJung-uk Kim return (int)(out - save); 1316*e71b7053SJung-uk Kim } 1317*e71b7053SJung-uk Kim # endif 1318*e71b7053SJung-uk Kim 1319*e71b7053SJung-uk Kim # ifdef OCSP_DAEMON 1320*e71b7053SJung-uk Kim static void sock_timeout(int signum) 1321*e71b7053SJung-uk Kim { 1322*e71b7053SJung-uk Kim if (acfd != (int)INVALID_SOCKET) 1323*e71b7053SJung-uk Kim (void)shutdown(acfd, SHUT_RD); 1324*e71b7053SJung-uk Kim } 1325*e71b7053SJung-uk Kim # endif 1326*e71b7053SJung-uk Kim 13276f9291ceSJung-uk Kim static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, 1328*e71b7053SJung-uk Kim int timeout) 13295c87c606SMark Murray { 1330*e71b7053SJung-uk Kim # ifdef OPENSSL_NO_SOCK 13315c87c606SMark Murray return 0; 1332*e71b7053SJung-uk Kim # else 1333*e71b7053SJung-uk Kim int len; 1334*e71b7053SJung-uk Kim OCSP_REQUEST *req = NULL; 1335*e71b7053SJung-uk Kim char inbuf[2048], reqbuf[2048]; 1336*e71b7053SJung-uk Kim char *p, *q; 1337*e71b7053SJung-uk Kim BIO *cbio = NULL, *getbio = NULL, *b64 = NULL; 1338*e71b7053SJung-uk Kim const char *client; 1339*e71b7053SJung-uk Kim 1340*e71b7053SJung-uk Kim *preq = NULL; 1341*e71b7053SJung-uk Kim 1342*e71b7053SJung-uk Kim /* Connection loss before accept() is routine, ignore silently */ 1343*e71b7053SJung-uk Kim if (BIO_do_accept(acbio) <= 0) 1344*e71b7053SJung-uk Kim return 0; 13455c87c606SMark Murray 13465c87c606SMark Murray cbio = BIO_pop(acbio); 13475c87c606SMark Murray *pcbio = cbio; 1348*e71b7053SJung-uk Kim client = BIO_get_peer_name(cbio); 13495c87c606SMark Murray 1350*e71b7053SJung-uk Kim # ifdef OCSP_DAEMON 1351*e71b7053SJung-uk Kim if (timeout > 0) { 1352*e71b7053SJung-uk Kim (void) BIO_get_fd(cbio, &acfd); 1353*e71b7053SJung-uk Kim alarm(timeout); 1354*e71b7053SJung-uk Kim } 1355*e71b7053SJung-uk Kim # endif 1356*e71b7053SJung-uk Kim 1357*e71b7053SJung-uk Kim /* Read the request line. */ 1358*e71b7053SJung-uk Kim len = BIO_gets(cbio, reqbuf, sizeof(reqbuf)); 1359*e71b7053SJung-uk Kim if (len <= 0) 1360*e71b7053SJung-uk Kim goto out; 1361*e71b7053SJung-uk Kim 1362*e71b7053SJung-uk Kim if (strncmp(reqbuf, "GET ", 4) == 0) { 1363*e71b7053SJung-uk Kim /* Expecting GET {sp} /URL {sp} HTTP/1.x */ 1364*e71b7053SJung-uk Kim for (p = reqbuf + 4; *p == ' '; ++p) 1365*e71b7053SJung-uk Kim continue; 1366*e71b7053SJung-uk Kim if (*p != '/') { 1367*e71b7053SJung-uk Kim log_message(LOG_INFO, "Invalid request -- bad URL: %s", client); 1368*e71b7053SJung-uk Kim goto out; 1369*e71b7053SJung-uk Kim } 1370*e71b7053SJung-uk Kim p++; 1371*e71b7053SJung-uk Kim 1372*e71b7053SJung-uk Kim /* Splice off the HTTP version identifier. */ 1373*e71b7053SJung-uk Kim for (q = p; *q; q++) 1374*e71b7053SJung-uk Kim if (*q == ' ') 1375*e71b7053SJung-uk Kim break; 1376*e71b7053SJung-uk Kim if (strncmp(q, " HTTP/1.", 8) != 0) { 1377*e71b7053SJung-uk Kim log_message(LOG_INFO, 1378*e71b7053SJung-uk Kim "Invalid request -- bad HTTP version: %s", client); 1379*e71b7053SJung-uk Kim goto out; 1380*e71b7053SJung-uk Kim } 1381*e71b7053SJung-uk Kim *q = '\0'; 1382*e71b7053SJung-uk Kim 1383*e71b7053SJung-uk Kim /* 1384*e71b7053SJung-uk Kim * Skip "GET / HTTP..." requests often used by load-balancers 1385*e71b7053SJung-uk Kim */ 1386*e71b7053SJung-uk Kim if (p[1] == '\0') 1387*e71b7053SJung-uk Kim goto out; 1388*e71b7053SJung-uk Kim 1389*e71b7053SJung-uk Kim len = urldecode(p); 1390*e71b7053SJung-uk Kim if (len <= 0) { 1391*e71b7053SJung-uk Kim log_message(LOG_INFO, 1392*e71b7053SJung-uk Kim "Invalid request -- bad URL encoding: %s", client); 1393*e71b7053SJung-uk Kim goto out; 1394*e71b7053SJung-uk Kim } 1395*e71b7053SJung-uk Kim if ((getbio = BIO_new_mem_buf(p, len)) == NULL 1396*e71b7053SJung-uk Kim || (b64 = BIO_new(BIO_f_base64())) == NULL) { 1397*e71b7053SJung-uk Kim log_message(LOG_ERR, "Could not allocate base64 bio: %s", client); 1398*e71b7053SJung-uk Kim goto out; 1399*e71b7053SJung-uk Kim } 1400*e71b7053SJung-uk Kim BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); 1401*e71b7053SJung-uk Kim getbio = BIO_push(b64, getbio); 1402*e71b7053SJung-uk Kim } else if (strncmp(reqbuf, "POST ", 5) != 0) { 1403*e71b7053SJung-uk Kim log_message(LOG_INFO, "Invalid request -- bad HTTP verb: %s", client); 1404*e71b7053SJung-uk Kim goto out; 1405*e71b7053SJung-uk Kim } 1406*e71b7053SJung-uk Kim 1407*e71b7053SJung-uk Kim /* Read and skip past the headers. */ 14086f9291ceSJung-uk Kim for (;;) { 1409dee36b4fSJung-uk Kim len = BIO_gets(cbio, inbuf, sizeof(inbuf)); 14105c87c606SMark Murray if (len <= 0) 1411*e71b7053SJung-uk Kim goto out; 14125c87c606SMark Murray if ((inbuf[0] == '\r') || (inbuf[0] == '\n')) 14135c87c606SMark Murray break; 14145c87c606SMark Murray } 14155c87c606SMark Murray 1416*e71b7053SJung-uk Kim # ifdef OCSP_DAEMON 1417*e71b7053SJung-uk Kim /* Clear alarm before we close the client socket */ 1418*e71b7053SJung-uk Kim alarm(0); 1419*e71b7053SJung-uk Kim timeout = 0; 1420*e71b7053SJung-uk Kim # endif 1421*e71b7053SJung-uk Kim 14225c87c606SMark Murray /* Try to read OCSP request */ 1423*e71b7053SJung-uk Kim if (getbio != NULL) { 1424*e71b7053SJung-uk Kim req = d2i_OCSP_REQUEST_bio(getbio, NULL); 1425*e71b7053SJung-uk Kim BIO_free_all(getbio); 1426*e71b7053SJung-uk Kim } else { 14275c87c606SMark Murray req = d2i_OCSP_REQUEST_bio(cbio, NULL); 14285c87c606SMark Murray } 14295c87c606SMark Murray 1430*e71b7053SJung-uk Kim if (req == NULL) 1431*e71b7053SJung-uk Kim log_message(LOG_ERR, "Error parsing OCSP request"); 1432*e71b7053SJung-uk Kim 14335c87c606SMark Murray *preq = req; 14345c87c606SMark Murray 1435*e71b7053SJung-uk Kim out: 1436*e71b7053SJung-uk Kim # ifdef OCSP_DAEMON 1437*e71b7053SJung-uk Kim if (timeout > 0) 1438*e71b7053SJung-uk Kim alarm(0); 1439*e71b7053SJung-uk Kim acfd = (int)INVALID_SOCKET; 1440*e71b7053SJung-uk Kim # endif 14415c87c606SMark Murray return 1; 1442*e71b7053SJung-uk Kim # endif 14435c87c606SMark Murray } 14445c87c606SMark Murray 14455c87c606SMark Murray static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp) 14465c87c606SMark Murray { 14475c87c606SMark Murray char http_resp[] = 14485c87c606SMark Murray "HTTP/1.0 200 OK\r\nContent-type: application/ocsp-response\r\n" 14495c87c606SMark Murray "Content-Length: %d\r\n\r\n"; 1450*e71b7053SJung-uk Kim if (cbio == NULL) 14515c87c606SMark Murray return 0; 14525c87c606SMark Murray BIO_printf(cbio, http_resp, i2d_OCSP_RESPONSE(resp, NULL)); 14535c87c606SMark Murray i2d_OCSP_RESPONSE_bio(cbio, resp); 1454db522d3aSSimon L. B. Nielsen (void)BIO_flush(cbio); 14555c87c606SMark Murray return 1; 14565c87c606SMark Murray } 14575c87c606SMark Murray 1458*e71b7053SJung-uk Kim # ifndef OPENSSL_NO_SOCK 1459*e71b7053SJung-uk Kim static OCSP_RESPONSE *query_responder(BIO *cbio, const char *host, 1460*e71b7053SJung-uk Kim const char *path, 14617bded2dbSJung-uk Kim const STACK_OF(CONF_VALUE) *headers, 1462db522d3aSSimon L. B. Nielsen OCSP_REQUEST *req, int req_timeout) 1463db522d3aSSimon L. B. Nielsen { 1464db522d3aSSimon L. B. Nielsen int fd; 1465db522d3aSSimon L. B. Nielsen int rv; 14661f13597dSJung-uk Kim int i; 1467*e71b7053SJung-uk Kim int add_host = 1; 1468db522d3aSSimon L. B. Nielsen OCSP_REQ_CTX *ctx = NULL; 1469db522d3aSSimon L. B. Nielsen OCSP_RESPONSE *rsp = NULL; 1470db522d3aSSimon L. B. Nielsen fd_set confds; 1471db522d3aSSimon L. B. Nielsen struct timeval tv; 1472db522d3aSSimon L. B. Nielsen 1473db522d3aSSimon L. B. Nielsen if (req_timeout != -1) 1474db522d3aSSimon L. B. Nielsen BIO_set_nbio(cbio, 1); 1475db522d3aSSimon L. B. Nielsen 1476db522d3aSSimon L. B. Nielsen rv = BIO_do_connect(cbio); 1477db522d3aSSimon L. B. Nielsen 14786f9291ceSJung-uk Kim if ((rv <= 0) && ((req_timeout == -1) || !BIO_should_retry(cbio))) { 1479*e71b7053SJung-uk Kim BIO_puts(bio_err, "Error connecting BIO\n"); 1480db522d3aSSimon L. B. Nielsen return NULL; 1481db522d3aSSimon L. B. Nielsen } 1482db522d3aSSimon L. B. Nielsen 148380815a77SJung-uk Kim if (BIO_get_fd(cbio, &fd) < 0) { 148480815a77SJung-uk Kim BIO_puts(bio_err, "Can't get connection fd\n"); 1485db522d3aSSimon L. B. Nielsen goto err; 1486db522d3aSSimon L. B. Nielsen } 1487db522d3aSSimon L. B. Nielsen 14886f9291ceSJung-uk Kim if (req_timeout != -1 && rv <= 0) { 1489db522d3aSSimon L. B. Nielsen FD_ZERO(&confds); 1490db522d3aSSimon L. B. Nielsen openssl_fdset(fd, &confds); 1491db522d3aSSimon L. B. Nielsen tv.tv_usec = 0; 1492db522d3aSSimon L. B. Nielsen tv.tv_sec = req_timeout; 1493db522d3aSSimon L. B. Nielsen rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv); 14946f9291ceSJung-uk Kim if (rv == 0) { 1495*e71b7053SJung-uk Kim BIO_puts(bio_err, "Timeout on connect\n"); 1496db522d3aSSimon L. B. Nielsen return NULL; 1497db522d3aSSimon L. B. Nielsen } 1498db522d3aSSimon L. B. Nielsen } 1499db522d3aSSimon L. B. Nielsen 15001f13597dSJung-uk Kim ctx = OCSP_sendreq_new(cbio, path, NULL, -1); 1501*e71b7053SJung-uk Kim if (ctx == NULL) 1502db522d3aSSimon L. B. Nielsen return NULL; 1503db522d3aSSimon L. B. Nielsen 15046f9291ceSJung-uk Kim for (i = 0; i < sk_CONF_VALUE_num(headers); i++) { 15051f13597dSJung-uk Kim CONF_VALUE *hdr = sk_CONF_VALUE_value(headers, i); 1506*e71b7053SJung-uk Kim if (add_host == 1 && strcasecmp("host", hdr->name) == 0) 1507*e71b7053SJung-uk Kim add_host = 0; 15081f13597dSJung-uk Kim if (!OCSP_REQ_CTX_add1_header(ctx, hdr->name, hdr->value)) 15091f13597dSJung-uk Kim goto err; 15101f13597dSJung-uk Kim } 15111f13597dSJung-uk Kim 1512*e71b7053SJung-uk Kim if (add_host == 1 && OCSP_REQ_CTX_add1_header(ctx, "Host", host) == 0) 1513*e71b7053SJung-uk Kim goto err; 1514*e71b7053SJung-uk Kim 15151f13597dSJung-uk Kim if (!OCSP_REQ_CTX_set1_req(ctx, req)) 15161f13597dSJung-uk Kim goto err; 15171f13597dSJung-uk Kim 15186f9291ceSJung-uk Kim for (;;) { 1519db522d3aSSimon L. B. Nielsen rv = OCSP_sendreq_nbio(&rsp, ctx); 1520db522d3aSSimon L. B. Nielsen if (rv != -1) 1521db522d3aSSimon L. B. Nielsen break; 15221f13597dSJung-uk Kim if (req_timeout == -1) 15231f13597dSJung-uk Kim continue; 1524db522d3aSSimon L. B. Nielsen FD_ZERO(&confds); 1525db522d3aSSimon L. B. Nielsen openssl_fdset(fd, &confds); 1526db522d3aSSimon L. B. Nielsen tv.tv_usec = 0; 1527db522d3aSSimon L. B. Nielsen tv.tv_sec = req_timeout; 1528*e71b7053SJung-uk Kim if (BIO_should_read(cbio)) { 1529db522d3aSSimon L. B. Nielsen rv = select(fd + 1, (void *)&confds, NULL, NULL, &tv); 1530*e71b7053SJung-uk Kim } else if (BIO_should_write(cbio)) { 1531db522d3aSSimon L. B. Nielsen rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv); 1532*e71b7053SJung-uk Kim } else { 1533*e71b7053SJung-uk Kim BIO_puts(bio_err, "Unexpected retry condition\n"); 1534db522d3aSSimon L. B. Nielsen goto err; 1535db522d3aSSimon L. B. Nielsen } 15366f9291ceSJung-uk Kim if (rv == 0) { 1537*e71b7053SJung-uk Kim BIO_puts(bio_err, "Timeout on request\n"); 1538db522d3aSSimon L. B. Nielsen break; 1539db522d3aSSimon L. B. Nielsen } 15406f9291ceSJung-uk Kim if (rv == -1) { 1541*e71b7053SJung-uk Kim BIO_puts(bio_err, "Select error\n"); 1542db522d3aSSimon L. B. Nielsen break; 1543db522d3aSSimon L. B. Nielsen } 1544db522d3aSSimon L. B. Nielsen 1545db522d3aSSimon L. B. Nielsen } 1546db522d3aSSimon L. B. Nielsen err: 1547db522d3aSSimon L. B. Nielsen OCSP_REQ_CTX_free(ctx); 1548db522d3aSSimon L. B. Nielsen 1549db522d3aSSimon L. B. Nielsen return rsp; 1550db522d3aSSimon L. B. Nielsen } 1551db522d3aSSimon L. B. Nielsen 1552*e71b7053SJung-uk Kim OCSP_RESPONSE *process_responder(OCSP_REQUEST *req, 15537bded2dbSJung-uk Kim const char *host, const char *path, 15547bded2dbSJung-uk Kim const char *port, int use_ssl, 1555*e71b7053SJung-uk Kim STACK_OF(CONF_VALUE) *headers, 1556db522d3aSSimon L. B. Nielsen int req_timeout) 1557db522d3aSSimon L. B. Nielsen { 1558db522d3aSSimon L. B. Nielsen BIO *cbio = NULL; 1559db522d3aSSimon L. B. Nielsen SSL_CTX *ctx = NULL; 1560db522d3aSSimon L. B. Nielsen OCSP_RESPONSE *resp = NULL; 1561*e71b7053SJung-uk Kim 1562db522d3aSSimon L. B. Nielsen cbio = BIO_new_connect(host); 1563*e71b7053SJung-uk Kim if (cbio == NULL) { 1564*e71b7053SJung-uk Kim BIO_printf(bio_err, "Error creating connect BIO\n"); 1565db522d3aSSimon L. B. Nielsen goto end; 1566db522d3aSSimon L. B. Nielsen } 1567*e71b7053SJung-uk Kim if (port != NULL) 15686f9291ceSJung-uk Kim BIO_set_conn_port(cbio, port); 15696f9291ceSJung-uk Kim if (use_ssl == 1) { 1570db522d3aSSimon L. B. Nielsen BIO *sbio; 1571*e71b7053SJung-uk Kim ctx = SSL_CTX_new(TLS_client_method()); 15726f9291ceSJung-uk Kim if (ctx == NULL) { 1573*e71b7053SJung-uk Kim BIO_printf(bio_err, "Error creating SSL context.\n"); 1574db522d3aSSimon L. B. Nielsen goto end; 1575db522d3aSSimon L. B. Nielsen } 1576db522d3aSSimon L. B. Nielsen SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); 1577db522d3aSSimon L. B. Nielsen sbio = BIO_new_ssl(ctx, 1); 1578db522d3aSSimon L. B. Nielsen cbio = BIO_push(sbio, cbio); 1579db522d3aSSimon L. B. Nielsen } 1580*e71b7053SJung-uk Kim 1581*e71b7053SJung-uk Kim resp = query_responder(cbio, host, path, headers, req, req_timeout); 1582*e71b7053SJung-uk Kim if (resp == NULL) 1583a93cbc2bSJung-uk Kim BIO_printf(bio_err, "Error querying OCSP responder\n"); 1584db522d3aSSimon L. B. Nielsen end: 1585db522d3aSSimon L. B. Nielsen BIO_free_all(cbio); 15861f13597dSJung-uk Kim SSL_CTX_free(ctx); 1587db522d3aSSimon L. B. Nielsen return resp; 1588db522d3aSSimon L. B. Nielsen } 1589*e71b7053SJung-uk Kim # endif 1590db522d3aSSimon L. B. Nielsen 1591fceca8a3SJacques Vidrine #endif 1592