/*
* Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
# include <openssl/x509v3.h>
# include <openssl/rand.h>
-# if defined(OPENSSL_SYS_UNIX) && !defined(OPENSSL_NO_SOCK) \
+#ifndef HAVE_FORK
+# if defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_WINDOWS)
+# define HAVE_FORK 0
+# else
+# define HAVE_FORK 1
+# endif
+#endif
+
+#if HAVE_FORK
+# undef NO_FORK
+#else
+# define NO_FORK
+#endif
+
+# if !defined(NO_FORK) && !defined(OPENSSL_NO_SOCK) \
&& !defined(OPENSSL_NO_POSIX_IO)
# define OCSP_DAEMON
# include <sys/types.h>
# define LOG_ERR 2
# endif
+# if defined(OPENSSL_SYS_VXWORKS)
+/* not supported */
+int setpgid(pid_t pid, pid_t pgid)
+{
+ errno = ENOSYS;
+ return 0;
+}
+/* not supported */
+pid_t fork(void)
+{
+ errno = ENOSYS;
+ return (pid_t) -1;
+}
+# endif
/* Maximum leeway in validity period: default 5 minutes */
# define MAX_VALIDITY_PERIOD (5 * 60)
EVP_PKEY *rkey, const EVP_MD *md,
STACK_OF(OPENSSL_STRING) *sigopts,
STACK_OF(X509) *rother, unsigned long flags,
- int nmin, int ndays, int badsig);
+ int nmin, int ndays, int badsig,
+ const EVP_MD *resp_md);
static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser);
static BIO *init_responder(const char *port);
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_VERIFY_OTHER, OPT_CAFILE, OPT_CAPATH, OPT_CASTORE, OPT_NOCAFILE,
+ OPT_NOCAPATH, OPT_NOCASTORE,
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_RCID,
OPT_V_ENUM,
OPT_MD,
OPT_MULTI
} OPTION_CHOICE;
const OPTIONS ocsp_options[] = {
+ OPT_SECTION("General"),
{"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"},
+ {"CAfile", OPT_CAFILE, '<', "Trusted certificates file"},
+ {"CApath", OPT_CAPATH, '<', "Trusted certificates directory"},
+ {"CAstore", OPT_CASTORE, ':', "Trusted certificates store URI"},
+ {"no-CAfile", OPT_NOCAFILE, '-',
+ "Do not load the default certificates file"},
+ {"no-CApath", OPT_NOCAPATH, '-',
+ "Do not load certificates from the default certificates directory"},
+ {"no-CAstore", OPT_NOCAPATH, '-',
+ "Do not load certificates from the default certificates store"},
+
+ OPT_SECTION("Responder"),
+ {"timeout", OPT_TIMEOUT, 'p',
+ "Connection timeout (in seconds) to the OCSP responder"},
{"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"},
+ {"badsig", OPT_BADSIG, '-',
+ "Corrupt last byte of loaded OSCP response signature (for test)"},
+ {"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)"},
+ {"reqin", OPT_REQIN, 's', "File with the DER-encoded request"},
+ {"signer", OPT_SIGNER, '<', "Certificate to sign OCSP request with"},
+ {"sign_other", OPT_SIGN_OTHER, '<',
+ "Additional certificates to include in signed request"},
+ {"index", OPT_INDEX, '<', "Certificate status index file"},
+ {"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"},
+ {"rcid", OPT_RCID, 's', "Use specified algorithm for cert id in response"},
+ {"", OPT_MD, '-', "Any supported digest algorithm (sha1,sha256, ... )"},
+
+ OPT_SECTION("Client"),
+ {"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"},
+ {"out", OPT_OUTFILE, '>', "Output filename"},
+ {"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"},
{"no_signature_verify", OPT_NO_SIGNATURE_VERIFY, '-',
"Don't check signature on response"},
+ {"resp_key_id", OPT_RESP_KEY_ID, '-',
+ "Identify response by signing certificate key ID"},
{"no_cert_verify", OPT_NO_CERT_VERIFY, '-',
"Don't check signing certificate"},
+ {"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"},
{"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"},
"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"},
+ {"path", OPT_PATH, 's', "Path to use in OCSP request"},
+ {"cert", OPT_CERT, '<', "Certificate to check"},
+ {"serial", OPT_SERIAL, 's', "Serial number to check"},
{"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, ... )"},
+ {"status_age", OPT_STATUS_AGE, 'p', "Maximum status age in seconds"},
+
OPT_V_OPTIONS,
{NULL}
};
STACK_OF(X509) *issuers = NULL;
X509 *issuer = NULL, *cert = NULL;
STACK_OF(X509) *rca_cert = NULL;
+ const EVP_MD *resp_certid_md = NULL;
X509 *signer = NULL, *rsigner = NULL;
X509_STORE *store = NULL;
X509_VERIFY_PARAM *vpm = NULL;
- const char *CAfile = NULL, *CApath = NULL;
+ const char *CAfile = NULL, *CApath = NULL, *CAstore = NULL;
char *header, *value;
char *host = NULL, *port = NULL, *path = "/", *outfile = NULL;
char *rca_filename = NULL, *reqin = NULL, *respin = 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 noCAfile = 0, noCApath = 0, noCAstore = 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;
case OPT_CAPATH:
CApath = opt_arg();
break;
+ case OPT_CASTORE:
+ CAstore = opt_arg();
+ break;
case OPT_NOCAFILE:
noCAfile = 1;
break;
case OPT_NOCAPATH:
noCApath = 1;
break;
+ case OPT_NOCASTORE:
+ noCAstore = 1;
+ break;
case OPT_V_CASES:
if (!opt_verify(o, vpm))
goto end;
if (!X509V3_add_value(header, value, &headers))
goto end;
break;
+ case OPT_RCID:
+ resp_certid_md = EVP_get_digestbyname(opt_arg());
+ if (resp_certid_md == NULL)
+ goto opthelp;
+ break;
case OPT_MD:
if (trailing_md) {
BIO_printf(bio_err,
if (ridx_filename != NULL) {
rdb = load_index(ridx_filename, NULL);
- if (rdb == NULL || !index_index(rdb)) {
+ if (rdb == NULL || index_index(rdb) <= 0) {
ret = 1;
goto end;
}
if (index_changed(rdb)) {
CA_DB *newrdb = load_index(ridx_filename, NULL);
- if (newrdb != NULL) {
+ if (newrdb != NULL && index_index(newrdb) > 0) {
free_index(rdb);
rdb = newrdb;
} else {
+ free_index(newrdb);
log_message(LOG_ERR, "error reloading updated index: %s",
ridx_filename);
}
goto end;
}
- if (req != NULL && add_nonce)
- OCSP_request_add1_nonce(req, NULL, -1);
+ if (req != NULL && add_nonce) {
+ if (!OCSP_request_add1_nonce(req, NULL, -1))
+ goto end;
+ }
if (signfile != NULL) {
if (keyfile == NULL)
if (rdb != NULL) {
make_ocsp_response(bio_err, &resp, req, rdb, rca_cert, rsigner, rkey,
- rsign_md, rsign_sigopts, rother, rflags, nmin, ndays, badsig);
+ rsign_md, rsign_sigopts, rother, rflags, nmin, ndays, badsig,
+ resp_certid_md);
if (cbio != NULL)
send_ocsp_response(cbio, resp);
} else if (host != NULL) {
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;
+ if (!ignore_err)
goto end;
- }
}
if (resp_text)
}
if (store == NULL) {
- store = setup_verify(CAfile, CApath, noCAfile, noCApath);
+ store = setup_verify(CAfile, noCAfile, CApath, noCApath,
+ CAstore, noCAstore);
if (!store)
goto end;
}
for (i = 0; i < multi; ++i)
if (kidpids[i] != 0)
(void)kill(kidpids[i], SIGTERM);
+ OPENSSL_free(kidpids);
sleep(1);
exit(ret);
}
*/
static void spawn_loop(void)
{
- const char *signame;
pid_t *kidpids = NULL;
int status;
int procs = 0;
sleep(30);
break;
case 0: /* child */
+ OPENSSL_free(kidpids);
signal(SIGINT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
if (termsig)
}
/* The loop above can only break on termsig */
- signame = strsignal(termsig);
- syslog(LOG_INFO, "terminating on signal: %s(%d)",
- signame ? signame : "", termsig);
+ syslog(LOG_INFO, "terminating on signal: %d", termsig);
killall(0, kidpids);
}
# endif
EVP_PKEY *rkey, const EVP_MD *rmd,
STACK_OF(OPENSSL_STRING) *sigopts,
STACK_OF(X509) *rother, unsigned long flags,
- int nmin, int ndays, int badsig)
+ int nmin, int ndays, int badsig,
+ const EVP_MD *resp_md)
{
ASN1_TIME *thisupd = NULL, *nextupd = NULL;
OCSP_CERTID *cid;
int found = 0;
ASN1_OBJECT *cert_id_md_oid;
const EVP_MD *cert_id_md;
+ OCSP_CERTID *cid_resp_md = NULL;
+
one = OCSP_request_onereq_get0(req, i);
cid = OCSP_onereq_get0_id(one);
X509 *ca_cert = sk_X509_value(ca, jj);
OCSP_CERTID *ca_id = OCSP_cert_to_id(cert_id_md, NULL, ca_cert);
- if (OCSP_id_issuer_cmp(ca_id, cid) == 0)
+ if (OCSP_id_issuer_cmp(ca_id, cid) == 0) {
found = 1;
-
+ if (resp_md != NULL)
+ cid_resp_md = OCSP_cert_to_id(resp_md, NULL, ca_cert);
+ }
OCSP_CERTID_free(ca_id);
}
+ OCSP_id_get0_info(NULL, NULL, NULL, &serial, cid);
+ inf = lookup_serial(db, serial);
+
+ /* at this point, we can have cid be an alias of cid_resp_md */
+ cid = (cid_resp_md != NULL) ? cid_resp_md : cid;
if (!found) {
OCSP_basic_add1_status(bs, cid,
0, NULL, thisupd, nextupd);
continue;
}
- OCSP_id_get0_info(NULL, NULL, NULL, &serial, cid);
- inf = lookup_serial(db, serial);
if (inf == NULL) {
OCSP_basic_add1_status(bs, cid,
V_OCSP_CERTSTATUS_UNKNOWN,
ASN1_GENERALIZEDTIME *invtm = NULL;
OCSP_SINGLERESP *single;
int reason = -1;
+
unpack_revinfo(&revtm, &reason, &inst, &invtm, inf[DB_rev_date]);
single = OCSP_basic_add1_status(bs, cid,
V_OCSP_CERTSTATUS_REVOKED,
ASN1_TIME_free(revtm);
ASN1_GENERALIZEDTIME_free(invtm);
}
+ OCSP_CERTID_free(cid_resp_md);
}
OCSP_copy_nonce(bs, req);
goto end;
}
}
- OCSP_basic_sign_ctx(bs, rcert, mctx, rother, flags);
+ if (!OCSP_basic_sign_ctx(bs, rcert, mctx, rother, flags)) {
+ *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_INTERNALERROR, bs);
+ goto end;
+ }
if (badsig) {
const ASN1_OCTET_STRING *sig = OCSP_resp_get0_signature(bs);
*q = '\0';
/*
- * Skip "GET / HTTP..." requests often used by load-balancers
+ * Skip "GET / HTTP..." requests often used by load-balancers. Note:
+ * 'p' was incremented above to point to the first byte *after* the
+ * leading slash, so with 'GET / ' it is now an empty string.
*/
- if (p[1] == '\0')
+ if (p[0] == '\0')
goto out;
len = urldecode(p);