+static void log_message(int level, const char *fmt, ...);
+static char *prog;
+static int multi = 0;
+
+# ifdef OCSP_DAEMON
+static int acfd = (int) INVALID_SOCKET;
+static int index_changed(CA_DB *);
+static void spawn_loop(void);
+static int print_syslog(const char *str, size_t len, void *levPtr);
+static void sock_timeout(int signum);
+# endif
+
+# ifndef OPENSSL_NO_SOCK
+static OCSP_RESPONSE *query_responder(BIO *cbio, const char *host,
+ const char *path,
+ const STACK_OF(CONF_VALUE) *headers,
+ OCSP_REQUEST *req, int req_timeout);
+# endif
+
+typedef enum OPTION_choice {
+ OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
+ OPT_OUTFILE, OPT_TIMEOUT, OPT_URL, OPT_HOST, OPT_PORT,
+ OPT_IGNORE_ERR, OPT_NOVERIFY, OPT_NONCE, OPT_NO_NONCE,
+ OPT_RESP_NO_CERTS, OPT_RESP_KEY_ID, OPT_NO_CERTS,
+ OPT_NO_SIGNATURE_VERIFY, OPT_NO_CERT_VERIFY, OPT_NO_CHAIN,
+ OPT_NO_CERT_CHECKS, OPT_NO_EXPLICIT, OPT_TRUST_OTHER,
+ OPT_NO_INTERN, OPT_BADSIG, OPT_TEXT, OPT_REQ_TEXT, OPT_RESP_TEXT,
+ OPT_REQIN, OPT_RESPIN, OPT_SIGNER, OPT_VAFILE, OPT_SIGN_OTHER,
+ OPT_VERIFY_OTHER, OPT_CAFILE, OPT_CAPATH, OPT_NOCAFILE, OPT_NOCAPATH,
+ OPT_VALIDITY_PERIOD, OPT_STATUS_AGE, OPT_SIGNKEY, OPT_REQOUT,
+ OPT_RESPOUT, OPT_PATH, OPT_ISSUER, OPT_CERT, OPT_SERIAL,
+ OPT_INDEX, OPT_CA, OPT_NMIN, OPT_REQUEST, OPT_NDAYS, OPT_RSIGNER,
+ OPT_RKEY, OPT_ROTHER, OPT_RMD, OPT_RSIGOPT, OPT_HEADER,
+ OPT_V_ENUM,
+ OPT_MD,
+ OPT_MULTI
+} OPTION_CHOICE;
+
+const OPTIONS ocsp_options[] = {
+ {"help", OPT_HELP, '-', "Display this summary"},
+ {"out", OPT_OUTFILE, '>', "Output filename"},
+ {"timeout", OPT_TIMEOUT, 'p',
+ "Connection timeout (in seconds) to the OCSP responder"},
+ {"url", OPT_URL, 's', "Responder URL"},
+ {"host", OPT_HOST, 's', "TCP/IP hostname:port to connect to"},
+ {"port", OPT_PORT, 'p', "Port to run responder on"},
+ {"ignore_err", OPT_IGNORE_ERR, '-',
+ "Ignore error on OCSP request or response and continue running"},
+ {"noverify", OPT_NOVERIFY, '-', "Don't verify response at all"},
+ {"nonce", OPT_NONCE, '-', "Add OCSP nonce to request"},
+ {"no_nonce", OPT_NO_NONCE, '-', "Don't add OCSP nonce to request"},
+ {"resp_no_certs", OPT_RESP_NO_CERTS, '-',
+ "Don't include any certificates in response"},
+ {"resp_key_id", OPT_RESP_KEY_ID, '-',
+ "Identify response by signing certificate key ID"},
+# ifdef OCSP_DAEMON
+ {"multi", OPT_MULTI, 'p', "run multiple responder processes"},
+# endif
+ {"no_certs", OPT_NO_CERTS, '-',
+ "Don't include any certificates in signed request"},
+ {"no_signature_verify", OPT_NO_SIGNATURE_VERIFY, '-',
+ "Don't check signature on response"},
+ {"no_cert_verify", OPT_NO_CERT_VERIFY, '-',
+ "Don't check signing certificate"},
+ {"no_chain", OPT_NO_CHAIN, '-', "Don't chain verify response"},
+ {"no_cert_checks", OPT_NO_CERT_CHECKS, '-',
+ "Don't do additional checks on signing certificate"},
+ {"no_explicit", OPT_NO_EXPLICIT, '-',
+ "Do not explicitly check the chain, just verify the root"},
+ {"trust_other", OPT_TRUST_OTHER, '-',
+ "Don't verify additional certificates"},
+ {"no_intern", OPT_NO_INTERN, '-',
+ "Don't search certificates contained in response for signer"},
+ {"badsig", OPT_BADSIG, '-',
+ "Corrupt last byte of loaded OSCP response signature (for test)"},
+ {"text", OPT_TEXT, '-', "Print text form of request and response"},
+ {"req_text", OPT_REQ_TEXT, '-', "Print text form of request"},
+ {"resp_text", OPT_RESP_TEXT, '-', "Print text form of response"},
+ {"reqin", OPT_REQIN, 's', "File with the DER-encoded request"},
+ {"respin", OPT_RESPIN, 's', "File with the DER-encoded response"},
+ {"signer", OPT_SIGNER, '<', "Certificate to sign OCSP request with"},
+ {"VAfile", OPT_VAFILE, '<', "Validator certificates file"},
+ {"sign_other", OPT_SIGN_OTHER, '<',
+ "Additional certificates to include in signed request"},
+ {"verify_other", OPT_VERIFY_OTHER, '<',
+ "Additional certificates to search for signer"},
+ {"CAfile", OPT_CAFILE, '<', "Trusted certificates file"},
+ {"CApath", OPT_CAPATH, '<', "Trusted certificates directory"},
+ {"no-CAfile", OPT_NOCAFILE, '-',
+ "Do not load the default certificates file"},
+ {"no-CApath", OPT_NOCAPATH, '-',
+ "Do not load certificates from the default certificates directory"},
+ {"validity_period", OPT_VALIDITY_PERIOD, 'u',
+ "Maximum validity discrepancy in seconds"},
+ {"status_age", OPT_STATUS_AGE, 'p', "Maximum status age in seconds"},
+ {"signkey", OPT_SIGNKEY, 's', "Private key to sign OCSP request with"},
+ {"reqout", OPT_REQOUT, 's', "Output file for the DER-encoded request"},
+ {"respout", OPT_RESPOUT, 's', "Output file for the DER-encoded response"},
+ {"path", OPT_PATH, 's', "Path to use in OCSP request"},
+ {"issuer", OPT_ISSUER, '<', "Issuer certificate"},
+ {"cert", OPT_CERT, '<', "Certificate to check"},
+ {"serial", OPT_SERIAL, 's', "Serial number to check"},
+ {"index", OPT_INDEX, '<', "Certificate status index file"},
+ {"CA", OPT_CA, '<', "CA certificate"},
+ {"nmin", OPT_NMIN, 'p', "Number of minutes before next update"},
+ {"nrequest", OPT_REQUEST, 'p',
+ "Number of requests to accept (default unlimited)"},
+ {"ndays", OPT_NDAYS, 'p', "Number of days before next update"},
+ {"rsigner", OPT_RSIGNER, '<',
+ "Responder certificate to sign responses with"},
+ {"rkey", OPT_RKEY, '<', "Responder key to sign responses with"},
+ {"rother", OPT_ROTHER, '<', "Other certificates to include in response"},
+ {"rmd", OPT_RMD, 's', "Digest Algorithm to use in signature of OCSP response"},
+ {"rsigopt", OPT_RSIGOPT, 's', "OCSP response signature parameter in n:v form"},
+ {"header", OPT_HEADER, 's', "key=value header to add"},
+ {"", OPT_MD, '-', "Any supported digest algorithm (sha1,sha256, ... )"},
+ OPT_V_OPTIONS,
+ {NULL}
+};
+
+int ocsp_main(int argc, char **argv)
+{
+ BIO *acbio = NULL, *cbio = NULL, *derbio = NULL, *out = NULL;
+ const EVP_MD *cert_id_md = NULL, *rsign_md = NULL;
+ STACK_OF(OPENSSL_STRING) *rsign_sigopts = NULL;
+ int trailing_md = 0;
+ CA_DB *rdb = NULL;
+ EVP_PKEY *key = NULL, *rkey = NULL;
+ OCSP_BASICRESP *bs = NULL;
+ OCSP_REQUEST *req = NULL;
+ OCSP_RESPONSE *resp = NULL;
+ STACK_OF(CONF_VALUE) *headers = NULL;
+ STACK_OF(OCSP_CERTID) *ids = NULL;
+ STACK_OF(OPENSSL_STRING) *reqnames = NULL;
+ STACK_OF(X509) *sign_other = NULL, *verify_other = NULL, *rother = NULL;
+ STACK_OF(X509) *issuers = NULL;
+ X509 *issuer = NULL, *cert = NULL;
+ STACK_OF(X509) *rca_cert = NULL;
+ X509 *signer = NULL, *rsigner = NULL;
+ X509_STORE *store = NULL;
+ X509_VERIFY_PARAM *vpm = NULL;
+ const char *CAfile = NULL, *CApath = NULL;
+ char *header, *value;
+ char *host = NULL, *port = NULL, *path = "/", *outfile = NULL;
+ char *rca_filename = NULL, *reqin = NULL, *respin = NULL;
+ char *reqout = NULL, *respout = NULL, *ridx_filename = NULL;
+ char *rsignfile = NULL, *rkeyfile = NULL;
+ char *sign_certfile = NULL, *verify_certfile = NULL, *rcertfile = NULL;
+ char *signfile = NULL, *keyfile = NULL;
+ char *thost = NULL, *tport = NULL, *tpath = NULL;
+ int noCAfile = 0, noCApath = 0;
+ int accept_count = -1, add_nonce = 1, noverify = 0, use_ssl = -1;
+ int vpmtouched = 0, badsig = 0, i, ignore_err = 0, nmin = 0, ndays = -1;
+ int req_text = 0, resp_text = 0, ret = 1;
+# ifndef OPENSSL_NO_SOCK
+ int req_timeout = -1;
+# endif
+ long nsec = MAX_VALIDITY_PERIOD, maxage = -1;
+ unsigned long sign_flags = 0, verify_flags = 0, rflags = 0;
+ OPTION_CHOICE o;
+
+ reqnames = sk_OPENSSL_STRING_new_null();
+ if (reqnames == NULL)
+ goto end;
+ ids = sk_OCSP_CERTID_new_null();
+ if (ids == NULL)
+ goto end;
+ if ((vpm = X509_VERIFY_PARAM_new()) == NULL)
+ return 1;
+
+ prog = opt_init(argc, argv, ocsp_options);
+ while ((o = opt_next()) != OPT_EOF) {
+ switch (o) {
+ case OPT_EOF:
+ case OPT_ERR:
+ opthelp:
+ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
+ goto end;
+ case OPT_HELP:
+ ret = 0;
+ opt_help(ocsp_options);
+ goto end;
+ case OPT_OUTFILE:
+ outfile = opt_arg();
+ break;
+ case OPT_TIMEOUT:
+#ifndef OPENSSL_NO_SOCK
+ req_timeout = atoi(opt_arg());
+#endif
+ break;
+ case OPT_URL:
+ OPENSSL_free(thost);
+ OPENSSL_free(tport);
+ OPENSSL_free(tpath);
+ thost = tport = tpath = NULL;
+ if (!OCSP_parse_url(opt_arg(), &host, &port, &path, &use_ssl)) {
+ BIO_printf(bio_err, "%s Error parsing URL\n", prog);
+ goto end;
+ }
+ thost = host;
+ tport = port;
+ tpath = path;
+ break;
+ case OPT_HOST:
+ host = opt_arg();
+ break;
+ case OPT_PORT:
+ port = opt_arg();
+ break;
+ case OPT_IGNORE_ERR:
+ ignore_err = 1;
+ break;
+ case OPT_NOVERIFY:
+ noverify = 1;
+ break;
+ case OPT_NONCE:
+ add_nonce = 2;
+ break;
+ case OPT_NO_NONCE:
+ add_nonce = 0;
+ break;
+ case OPT_RESP_NO_CERTS:
+ rflags |= OCSP_NOCERTS;
+ break;
+ case OPT_RESP_KEY_ID:
+ rflags |= OCSP_RESPID_KEY;
+ break;
+ case OPT_NO_CERTS:
+ sign_flags |= OCSP_NOCERTS;
+ break;
+ case OPT_NO_SIGNATURE_VERIFY:
+ verify_flags |= OCSP_NOSIGS;
+ break;
+ case OPT_NO_CERT_VERIFY:
+ verify_flags |= OCSP_NOVERIFY;
+ break;
+ case OPT_NO_CHAIN:
+ verify_flags |= OCSP_NOCHAIN;
+ break;
+ case OPT_NO_CERT_CHECKS:
+ verify_flags |= OCSP_NOCHECKS;
+ break;
+ case OPT_NO_EXPLICIT:
+ verify_flags |= OCSP_NOEXPLICIT;
+ break;
+ case OPT_TRUST_OTHER:
+ verify_flags |= OCSP_TRUSTOTHER;
+ break;
+ case OPT_NO_INTERN:
+ verify_flags |= OCSP_NOINTERN;
+ break;
+ case OPT_BADSIG:
+ badsig = 1;
+ break;
+ case OPT_TEXT:
+ req_text = resp_text = 1;
+ break;
+ case OPT_REQ_TEXT:
+ req_text = 1;
+ break;
+ case OPT_RESP_TEXT:
+ resp_text = 1;
+ break;
+ case OPT_REQIN:
+ reqin = opt_arg();
+ break;
+ case OPT_RESPIN:
+ respin = opt_arg();
+ break;
+ case OPT_SIGNER:
+ signfile = opt_arg();
+ break;
+ case OPT_VAFILE:
+ verify_certfile = opt_arg();
+ verify_flags |= OCSP_TRUSTOTHER;
+ break;
+ case OPT_SIGN_OTHER:
+ sign_certfile = opt_arg();
+ break;
+ case OPT_VERIFY_OTHER:
+ verify_certfile = opt_arg();
+ break;
+ case OPT_CAFILE:
+ CAfile = opt_arg();
+ break;
+ case OPT_CAPATH:
+ CApath = opt_arg();
+ break;
+ case OPT_NOCAFILE:
+ noCAfile = 1;
+ break;
+ case OPT_NOCAPATH:
+ noCApath = 1;
+ break;
+ case OPT_V_CASES:
+ if (!opt_verify(o, vpm))
+ goto end;
+ vpmtouched++;
+ break;
+ case OPT_VALIDITY_PERIOD:
+ opt_long(opt_arg(), &nsec);
+ break;
+ case OPT_STATUS_AGE:
+ opt_long(opt_arg(), &maxage);
+ break;
+ case OPT_SIGNKEY:
+ keyfile = opt_arg();
+ break;
+ case OPT_REQOUT:
+ reqout = opt_arg();
+ break;
+ case OPT_RESPOUT:
+ respout = opt_arg();
+ break;
+ case OPT_PATH:
+ path = opt_arg();
+ break;
+ case OPT_ISSUER:
+ issuer = load_cert(opt_arg(), FORMAT_PEM, "issuer certificate");
+ if (issuer == NULL)
+ goto end;
+ if (issuers == NULL) {
+ if ((issuers = sk_X509_new_null()) == NULL)
+ goto end;
+ }
+ sk_X509_push(issuers, issuer);
+ break;
+ case OPT_CERT:
+ X509_free(cert);
+ cert = load_cert(opt_arg(), FORMAT_PEM, "certificate");
+ if (cert == NULL)
+ goto end;
+ if (cert_id_md == NULL)
+ cert_id_md = EVP_sha1();
+ if (!add_ocsp_cert(&req, cert, cert_id_md, issuer, ids))
+ goto end;
+ if (!sk_OPENSSL_STRING_push(reqnames, opt_arg()))
+ goto end;
+ trailing_md = 0;
+ break;
+ case OPT_SERIAL:
+ if (cert_id_md == NULL)
+ cert_id_md = EVP_sha1();
+ if (!add_ocsp_serial(&req, opt_arg(), cert_id_md, issuer, ids))
+ goto end;
+ if (!sk_OPENSSL_STRING_push(reqnames, opt_arg()))
+ goto end;
+ trailing_md = 0;
+ break;
+ case OPT_INDEX:
+ ridx_filename = opt_arg();
+ break;
+ case OPT_CA:
+ rca_filename = opt_arg();
+ break;
+ case OPT_NMIN:
+ opt_int(opt_arg(), &nmin);
+ if (ndays == -1)
+ ndays = 0;
+ break;
+ case OPT_REQUEST:
+ opt_int(opt_arg(), &accept_count);
+ break;
+ case OPT_NDAYS:
+ ndays = atoi(opt_arg());
+ break;
+ case OPT_RSIGNER:
+ rsignfile = opt_arg();
+ break;
+ case OPT_RKEY:
+ rkeyfile = opt_arg();
+ break;
+ case OPT_ROTHER:
+ rcertfile = opt_arg();
+ break;
+ case OPT_RMD: /* Response MessageDigest */
+ if (!opt_md(opt_arg(), &rsign_md))
+ goto end;
+ break;
+ case OPT_RSIGOPT:
+ if (rsign_sigopts == NULL)
+ rsign_sigopts = sk_OPENSSL_STRING_new_null();
+ if (rsign_sigopts == NULL || !sk_OPENSSL_STRING_push(rsign_sigopts, opt_arg()))
+ goto end;
+ break;
+ case OPT_HEADER:
+ header = opt_arg();
+ value = strchr(header, '=');
+ if (value == NULL) {
+ BIO_printf(bio_err, "Missing = in header key=value\n");
+ goto opthelp;
+ }
+ *value++ = '\0';
+ if (!X509V3_add_value(header, value, &headers))
+ goto end;
+ break;
+ case OPT_MD:
+ if (trailing_md) {
+ BIO_printf(bio_err,
+ "%s: Digest must be before -cert or -serial\n",
+ prog);
+ goto opthelp;
+ }
+ if (!opt_md(opt_unknown(), &cert_id_md))
+ goto opthelp;
+ trailing_md = 1;
+ break;
+# ifdef OCSP_DAEMON
+ case OPT_MULTI:
+ multi = atoi(opt_arg());
+ break;
+# endif
+ }
+ }
+ if (trailing_md) {
+ BIO_printf(bio_err, "%s: Digest must be before -cert or -serial\n",
+ prog);
+ goto opthelp;
+ }
+ argc = opt_num_rest();
+ if (argc != 0)
+ goto opthelp;
+
+ /* Have we anything to do? */
+ if (req == NULL && reqin == NULL
+ && respin == NULL && !(port != NULL && ridx_filename != NULL))
+ goto opthelp;
+
+ out = bio_open_default(outfile, 'w', FORMAT_TEXT);
+ if (out == NULL)
+ goto end;
+
+ if (req == NULL && (add_nonce != 2))
+ add_nonce = 0;
+
+ if (req == NULL && reqin != NULL) {
+ derbio = bio_open_default(reqin, 'r', FORMAT_ASN1);
+ if (derbio == NULL)
+ goto end;
+ req = d2i_OCSP_REQUEST_bio(derbio, NULL);
+ BIO_free(derbio);
+ if (req == NULL) {
+ BIO_printf(bio_err, "Error reading OCSP request\n");
+ goto end;
+ }
+ }
+
+ if (req == NULL && port != NULL) {
+ acbio = init_responder(port);
+ if (acbio == NULL)
+ goto end;
+ }
+
+ if (rsignfile != NULL) {
+ if (rkeyfile == NULL)
+ rkeyfile = rsignfile;
+ rsigner = load_cert(rsignfile, FORMAT_PEM, "responder certificate");
+ if (rsigner == NULL) {
+ BIO_printf(bio_err, "Error loading responder certificate\n");
+ goto end;
+ }
+ if (!load_certs(rca_filename, &rca_cert, FORMAT_PEM,
+ NULL, "CA certificate"))
+ goto end;
+ if (rcertfile != NULL) {
+ if (!load_certs(rcertfile, &rother, FORMAT_PEM, NULL,
+ "responder other certificates"))
+ goto end;
+ }
+ rkey = load_key(rkeyfile, FORMAT_PEM, 0, NULL, NULL,
+ "responder private key");
+ if (rkey == NULL)
+ goto end;
+ }
+
+ if (ridx_filename != NULL
+ && (rkey != NULL || rsigner != NULL || rca_cert != NULL)) {
+ BIO_printf(bio_err,
+ "Responder mode requires certificate, key, and CA.\n");
+ goto end;
+ }
+
+ if (ridx_filename != NULL) {
+ rdb = load_index(ridx_filename, NULL);
+ if (rdb == NULL || !index_index(rdb)) {
+ ret = 1;
+ goto end;
+ }
+ }
+
+# ifdef OCSP_DAEMON
+ if (multi && acbio != NULL)
+ spawn_loop();
+ if (acbio != NULL && req_timeout > 0)
+ signal(SIGALRM, sock_timeout);
+#endif
+
+ if (acbio != NULL)
+ log_message(LOG_INFO, "waiting for OCSP client connections...");
+
+redo_accept:
+
+ if (acbio != NULL) {
+# ifdef OCSP_DAEMON
+ if (index_changed(rdb)) {
+ CA_DB *newrdb = load_index(ridx_filename, NULL);
+
+ if (newrdb != NULL) {
+ free_index(rdb);
+ rdb = newrdb;
+ } else {
+ log_message(LOG_ERR, "error reloading updated index: %s",
+ ridx_filename);
+ }
+ }
+# endif
+
+ req = NULL;
+ if (!do_responder(&req, &cbio, acbio, req_timeout))
+ goto redo_accept;
+
+ if (req == NULL) {
+ resp =
+ OCSP_response_create(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST,
+ NULL);
+ send_ocsp_response(cbio, resp);
+ goto done_resp;
+ }
+ }
+
+ if (req == NULL
+ && (signfile != NULL || reqout != NULL
+ || host != NULL || add_nonce || ridx_filename != NULL)) {
+ BIO_printf(bio_err, "Need an OCSP request for this operation!\n");
+ goto end;
+ }
+
+ if (req != NULL && add_nonce)
+ OCSP_request_add1_nonce(req, NULL, -1);
+
+ if (signfile != NULL) {
+ if (keyfile == NULL)
+ keyfile = signfile;
+ signer = load_cert(signfile, FORMAT_PEM, "signer certificate");
+ if (signer == NULL) {
+ BIO_printf(bio_err, "Error loading signer certificate\n");
+ goto end;
+ }
+ if (sign_certfile != NULL) {
+ if (!load_certs(sign_certfile, &sign_other, FORMAT_PEM, NULL,
+ "signer certificates"))
+ goto end;
+ }
+ key = load_key(keyfile, FORMAT_PEM, 0, NULL, NULL,
+ "signer private key");
+ if (key == NULL)
+ goto end;
+
+ if (!OCSP_request_sign
+ (req, signer, key, NULL, sign_other, sign_flags)) {
+ BIO_printf(bio_err, "Error signing OCSP request\n");
+ goto end;
+ }
+ }
+
+ if (req_text && req != NULL)
+ OCSP_REQUEST_print(out, req, 0);
+
+ if (reqout != NULL) {
+ derbio = bio_open_default(reqout, 'w', FORMAT_ASN1);
+ if (derbio == NULL)
+ goto end;
+ i2d_OCSP_REQUEST_bio(derbio, req);
+ BIO_free(derbio);
+ }
+
+ if (rdb != NULL) {
+ make_ocsp_response(bio_err, &resp, req, rdb, rca_cert, rsigner, rkey,
+ rsign_md, rsign_sigopts, rother, rflags, nmin, ndays, badsig);
+ if (cbio != NULL)
+ send_ocsp_response(cbio, resp);
+ } else if (host != NULL) {
+# ifndef OPENSSL_NO_SOCK
+ resp = process_responder(req, host, path,
+ port, use_ssl, headers, req_timeout);
+ if (resp == NULL)
+ goto end;
+# else
+ BIO_printf(bio_err,
+ "Error creating connect BIO - sockets not supported.\n");
+ goto end;
+# endif
+ } else if (respin != NULL) {
+ derbio = bio_open_default(respin, 'r', FORMAT_ASN1);
+ if (derbio == NULL)
+ goto end;
+ resp = d2i_OCSP_RESPONSE_bio(derbio, NULL);
+ BIO_free(derbio);
+ if (resp == NULL) {
+ BIO_printf(bio_err, "Error reading OCSP response\n");
+ goto end;
+ }
+ } else {
+ ret = 0;
+ goto end;
+ }
+
+ done_resp:
+
+ if (respout != NULL) {
+ derbio = bio_open_default(respout, 'w', FORMAT_ASN1);
+ if (derbio == NULL)
+ goto end;
+ i2d_OCSP_RESPONSE_bio(derbio, resp);
+ BIO_free(derbio);
+ }
+
+ i = OCSP_response_status(resp);
+ if (i != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+ BIO_printf(out, "Responder Error: %s (%d)\n",
+ OCSP_response_status_str(i), i);
+ if (!ignore_err) {
+ ret = 0;
+ goto end;
+ }
+ }
+
+ if (resp_text)
+ OCSP_RESPONSE_print(out, resp, 0);
+
+ /* If running as responder don't verify our own response */
+ if (cbio != NULL) {
+ /* If not unlimited, see if we took all we should. */
+ if (accept_count != -1 && --accept_count <= 0) {
+ ret = 0;
+ goto end;
+ }
+ BIO_free_all(cbio);
+ cbio = NULL;
+ OCSP_REQUEST_free(req);
+ req = NULL;
+ OCSP_RESPONSE_free(resp);
+ resp = NULL;
+ goto redo_accept;
+ }
+ if (ridx_filename != NULL) {
+ ret = 0;
+ goto end;
+ }
+
+ if (store == NULL) {
+ store = setup_verify(CAfile, CApath, noCAfile, noCApath);
+ if (!store)
+ goto end;
+ }
+ if (vpmtouched)
+ X509_STORE_set1_param(store, vpm);
+ if (verify_certfile != NULL) {
+ if (!load_certs(verify_certfile, &verify_other, FORMAT_PEM, NULL,
+ "validator certificate"))
+ goto end;
+ }
+
+ bs = OCSP_response_get1_basic(resp);
+ if (bs == NULL) {
+ BIO_printf(bio_err, "Error parsing response\n");
+ goto end;
+ }
+
+ ret = 0;
+
+ if (!noverify) {
+ if (req != NULL && ((i = OCSP_check_nonce(req, bs)) <= 0)) {
+ if (i == -1)
+ BIO_printf(bio_err, "WARNING: no nonce in response\n");
+ else {
+ BIO_printf(bio_err, "Nonce Verify error\n");
+ ret = 1;
+ goto end;
+ }
+ }
+
+ i = OCSP_basic_verify(bs, verify_other, store, verify_flags);
+ if (i <= 0 && issuers) {
+ i = OCSP_basic_verify(bs, issuers, store, OCSP_TRUSTOTHER);
+ if (i > 0)
+ ERR_clear_error();
+ }
+ if (i <= 0) {
+ BIO_printf(bio_err, "Response Verify Failure\n");
+ ERR_print_errors(bio_err);
+ ret = 1;
+ } else {
+ BIO_printf(bio_err, "Response verify OK\n");
+ }
+ }
+
+ print_ocsp_summary(out, bs, req, reqnames, ids, nsec, maxage);
+
+ end:
+ ERR_print_errors(bio_err);
+ X509_free(signer);
+ X509_STORE_free(store);
+ X509_VERIFY_PARAM_free(vpm);
+ sk_OPENSSL_STRING_free(rsign_sigopts);
+ EVP_PKEY_free(key);
+ EVP_PKEY_free(rkey);
+ X509_free(cert);
+ sk_X509_pop_free(issuers, X509_free);
+ X509_free(rsigner);
+ sk_X509_pop_free(rca_cert, X509_free);
+ free_index(rdb);
+ BIO_free_all(cbio);
+ BIO_free_all(acbio);
+ BIO_free_all(out);
+ OCSP_REQUEST_free(req);
+ OCSP_RESPONSE_free(resp);
+ OCSP_BASICRESP_free(bs);
+ sk_OPENSSL_STRING_free(reqnames);
+ sk_OCSP_CERTID_free(ids);
+ sk_X509_pop_free(sign_other, X509_free);
+ sk_X509_pop_free(verify_other, X509_free);
+ sk_CONF_VALUE_pop_free(headers, X509V3_conf_free);
+ OPENSSL_free(thost);
+ OPENSSL_free(tport);
+ OPENSSL_free(tpath);
+
+ return ret;
+}
+
+static void
+log_message(int level, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+# ifdef OCSP_DAEMON
+ if (multi) {
+ vsyslog(level, fmt, ap);
+ if (level >= LOG_ERR)
+ ERR_print_errors_cb(print_syslog, &level);
+ }
+# endif
+ if (!multi) {
+ BIO_printf(bio_err, "%s: ", prog);
+ BIO_vprintf(bio_err, fmt, ap);
+ BIO_printf(bio_err, "\n");
+ }
+ va_end(ap);
+}
+
+# ifdef OCSP_DAEMON
+
+static int print_syslog(const char *str, size_t len, void *levPtr)
+{
+ int level = *(int *)levPtr;
+ int ilen = (len > MAXERRLEN) ? MAXERRLEN : len;
+
+ syslog(level, "%.*s", ilen, str);
+
+ return ilen;
+}