Merge branch 'nghttpx-verify-ocsp'
This commit is contained in:
commit
db7483ef10
|
@ -167,6 +167,7 @@ OPTIONS = [
|
||||||
"no-add-x-forwarded-proto",
|
"no-add-x-forwarded-proto",
|
||||||
"no-strip-incoming-x-forwarded-proto",
|
"no-strip-incoming-x-forwarded-proto",
|
||||||
"ocsp-startup",
|
"ocsp-startup",
|
||||||
|
"no-verify-ocsp",
|
||||||
]
|
]
|
||||||
|
|
||||||
LOGVARS = [
|
LOGVARS = [
|
||||||
|
|
|
@ -2240,6 +2240,8 @@ SSL/TLS:
|
||||||
the attempts fail. This feature is useful if OCSP
|
the attempts fail. This feature is useful if OCSP
|
||||||
responses must be available before accepting
|
responses must be available before accepting
|
||||||
connections.
|
connections.
|
||||||
|
--no-verify-ocsp
|
||||||
|
nghttpx does not verify OCSP response.
|
||||||
--no-ocsp Disable OCSP stapling.
|
--no-ocsp Disable OCSP stapling.
|
||||||
--tls-session-cache-memcached=<HOST>,<PORT>[;tls]
|
--tls-session-cache-memcached=<HOST>,<PORT>[;tls]
|
||||||
Specify address of memcached server to store session
|
Specify address of memcached server to store session
|
||||||
|
@ -3191,6 +3193,7 @@ int main(int argc, char **argv) {
|
||||||
{SHRPX_OPT_BACKEND_NO_TLS.c_str(), no_argument, &flag, 27},
|
{SHRPX_OPT_BACKEND_NO_TLS.c_str(), no_argument, &flag, 27},
|
||||||
{SHRPX_OPT_OCSP_STARTUP.c_str(), no_argument, &flag, 28},
|
{SHRPX_OPT_OCSP_STARTUP.c_str(), no_argument, &flag, 28},
|
||||||
{SHRPX_OPT_FRONTEND_NO_TLS.c_str(), no_argument, &flag, 29},
|
{SHRPX_OPT_FRONTEND_NO_TLS.c_str(), no_argument, &flag, 29},
|
||||||
|
{SHRPX_OPT_NO_VERIFY_OCSP.c_str(), no_argument, &flag, 30},
|
||||||
{SHRPX_OPT_BACKEND_TLS_SNI_FIELD.c_str(), required_argument, &flag, 31},
|
{SHRPX_OPT_BACKEND_TLS_SNI_FIELD.c_str(), required_argument, &flag, 31},
|
||||||
{SHRPX_OPT_DH_PARAM_FILE.c_str(), required_argument, &flag, 33},
|
{SHRPX_OPT_DH_PARAM_FILE.c_str(), required_argument, &flag, 33},
|
||||||
{SHRPX_OPT_READ_RATE.c_str(), required_argument, &flag, 34},
|
{SHRPX_OPT_READ_RATE.c_str(), required_argument, &flag, 34},
|
||||||
|
@ -3550,6 +3553,11 @@ int main(int argc, char **argv) {
|
||||||
cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_NO_TLS,
|
cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_NO_TLS,
|
||||||
StringRef::from_lit("yes"));
|
StringRef::from_lit("yes"));
|
||||||
break;
|
break;
|
||||||
|
case 30:
|
||||||
|
// --no-verify-ocsp
|
||||||
|
cmdcfgs.emplace_back(SHRPX_OPT_NO_VERIFY_OCSP,
|
||||||
|
StringRef::from_lit("yes"));
|
||||||
|
break;
|
||||||
case 31:
|
case 31:
|
||||||
// --backend-tls-sni-field
|
// --backend-tls-sni-field
|
||||||
cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_TLS_SNI_FIELD,
|
cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_TLS_SNI_FIELD,
|
||||||
|
|
|
@ -1651,6 +1651,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||||
return SHRPX_OPTID_NO_SERVER_PUSH;
|
return SHRPX_OPTID_NO_SERVER_PUSH;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'p':
|
||||||
|
if (util::strieq_l("no-verify-ocs", name, 13)) {
|
||||||
|
return SHRPX_OPTID_NO_VERIFY_OCSP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
if (util::strieq_l("backend-no-tl", name, 13)) {
|
if (util::strieq_l("backend-no-tl", name, 13)) {
|
||||||
return SHRPX_OPTID_BACKEND_NO_TLS;
|
return SHRPX_OPTID_BACKEND_NO_TLS;
|
||||||
|
@ -3429,6 +3434,10 @@ int parse_config(Config *config, int optid, const StringRef &opt,
|
||||||
case SHRPX_OPTID_OCSP_STARTUP:
|
case SHRPX_OPTID_OCSP_STARTUP:
|
||||||
config->tls.ocsp.startup = util::strieq_l("yes", optarg);
|
config->tls.ocsp.startup = util::strieq_l("yes", optarg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_NO_VERIFY_OCSP:
|
||||||
|
config->tls.ocsp.no_verify = util::strieq_l("yes", optarg);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
case SHRPX_OPTID_CONF:
|
case SHRPX_OPTID_CONF:
|
||||||
LOG(WARN) << "conf: ignored";
|
LOG(WARN) << "conf: ignored";
|
||||||
|
|
|
@ -342,6 +342,7 @@ constexpr auto SHRPX_OPT_NO_ADD_X_FORWARDED_PROTO =
|
||||||
constexpr auto SHRPX_OPT_NO_STRIP_INCOMING_X_FORWARDED_PROTO =
|
constexpr auto SHRPX_OPT_NO_STRIP_INCOMING_X_FORWARDED_PROTO =
|
||||||
StringRef::from_lit("no-strip-incoming-x-forwarded-proto");
|
StringRef::from_lit("no-strip-incoming-x-forwarded-proto");
|
||||||
constexpr auto SHRPX_OPT_OCSP_STARTUP = StringRef::from_lit("ocsp-startup");
|
constexpr auto SHRPX_OPT_OCSP_STARTUP = StringRef::from_lit("ocsp-startup");
|
||||||
|
constexpr auto SHRPX_OPT_NO_VERIFY_OCSP = StringRef::from_lit("no-verify-ocsp");
|
||||||
|
|
||||||
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
|
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
|
||||||
|
|
||||||
|
@ -563,6 +564,7 @@ struct TLSConfig {
|
||||||
StringRef fetch_ocsp_response_file;
|
StringRef fetch_ocsp_response_file;
|
||||||
bool disabled;
|
bool disabled;
|
||||||
bool startup;
|
bool startup;
|
||||||
|
bool no_verify;
|
||||||
} ocsp;
|
} ocsp;
|
||||||
|
|
||||||
// Client verification configurations
|
// Client verification configurations
|
||||||
|
@ -1045,6 +1047,7 @@ enum {
|
||||||
SHRPX_OPTID_NO_SERVER_PUSH,
|
SHRPX_OPTID_NO_SERVER_PUSH,
|
||||||
SHRPX_OPTID_NO_SERVER_REWRITE,
|
SHRPX_OPTID_NO_SERVER_REWRITE,
|
||||||
SHRPX_OPTID_NO_STRIP_INCOMING_X_FORWARDED_PROTO,
|
SHRPX_OPTID_NO_STRIP_INCOMING_X_FORWARDED_PROTO,
|
||||||
|
SHRPX_OPTID_NO_VERIFY_OCSP,
|
||||||
SHRPX_OPTID_NO_VIA,
|
SHRPX_OPTID_NO_VIA,
|
||||||
SHRPX_OPTID_NPN_LIST,
|
SHRPX_OPTID_NPN_LIST,
|
||||||
SHRPX_OPTID_OCSP_STARTUP,
|
SHRPX_OPTID_OCSP_STARTUP,
|
||||||
|
|
|
@ -620,8 +620,13 @@ void ConnectionHandler::handle_ocsp_complete() {
|
||||||
<< " finished successfully";
|
<< " finished successfully";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto config = get_config();
|
||||||
|
auto &tlsconf = config->tls;
|
||||||
|
|
||||||
|
if (tlsconf.ocsp.no_verify ||
|
||||||
|
tls::verify_ocsp_response(ssl_ctx, ocsp_.resp.data(),
|
||||||
|
ocsp_.resp.size()) == 0) {
|
||||||
#ifndef OPENSSL_IS_BORINGSSL
|
#ifndef OPENSSL_IS_BORINGSSL
|
||||||
{
|
|
||||||
#ifdef HAVE_ATOMIC_STD_SHARED_PTR
|
#ifdef HAVE_ATOMIC_STD_SHARED_PTR
|
||||||
std::atomic_store_explicit(
|
std::atomic_store_explicit(
|
||||||
&tls_ctx_data->ocsp_data,
|
&tls_ctx_data->ocsp_data,
|
||||||
|
@ -632,10 +637,10 @@ void ConnectionHandler::handle_ocsp_complete() {
|
||||||
tls_ctx_data->ocsp_data =
|
tls_ctx_data->ocsp_data =
|
||||||
std::make_shared<std::vector<uint8_t>>(std::move(ocsp_.resp));
|
std::make_shared<std::vector<uint8_t>>(std::move(ocsp_.resp));
|
||||||
#endif // !HAVE_ATOMIC_STD_SHARED_PTR
|
#endif // !HAVE_ATOMIC_STD_SHARED_PTR
|
||||||
}
|
|
||||||
#else // OPENSSL_IS_BORINGSSL
|
#else // OPENSSL_IS_BORINGSSL
|
||||||
SSL_CTX_set_ocsp_response(ssl_ctx, ocsp_.resp.data(), ocsp_.resp.size());
|
SSL_CTX_set_ocsp_response(ssl_ctx, ocsp_.resp.data(), ocsp_.resp.size());
|
||||||
#endif // OPENSSL_IS_BORINGSSL
|
#endif // OPENSSL_IS_BORINGSSL
|
||||||
|
}
|
||||||
|
|
||||||
++ocsp_.next;
|
++ocsp_.next;
|
||||||
proceed_next_cert_ocsp();
|
proceed_next_cert_ocsp();
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
#include <openssl/x509v3.h>
|
#include <openssl/x509v3.h>
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
#include <openssl/dh.h>
|
#include <openssl/dh.h>
|
||||||
|
#include <openssl/ocsp.h>
|
||||||
|
|
||||||
#include <nghttp2/nghttp2.h>
|
#include <nghttp2/nghttp2.h>
|
||||||
|
|
||||||
|
@ -1818,6 +1819,84 @@ int proto_version_from_string(const StringRef &v) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int verify_ocsp_response(SSL_CTX *ssl_ctx, const uint8_t *ocsp_resp,
|
||||||
|
size_t ocsp_resplen) {
|
||||||
|
#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
STACK_OF(X509) * chain_certs;
|
||||||
|
SSL_CTX_get0_chain_certs(ssl_ctx, &chain_certs);
|
||||||
|
|
||||||
|
auto resp = d2i_OCSP_RESPONSE(nullptr, &ocsp_resp, ocsp_resplen);
|
||||||
|
if (resp == nullptr) {
|
||||||
|
LOG(ERROR) << "d2i_OCSP_RESPONSE failed";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
auto resp_deleter = defer(OCSP_RESPONSE_free, resp);
|
||||||
|
|
||||||
|
ERR_clear_error();
|
||||||
|
|
||||||
|
auto bs = OCSP_response_get1_basic(resp);
|
||||||
|
if (bs == nullptr) {
|
||||||
|
LOG(ERROR) << "OCSP_response_get1_basic failed: "
|
||||||
|
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
auto bs_deleter = defer(OCSP_BASICRESP_free, bs);
|
||||||
|
|
||||||
|
ERR_clear_error();
|
||||||
|
|
||||||
|
rv = OCSP_basic_verify(bs, chain_certs, nullptr, OCSP_TRUSTOTHER);
|
||||||
|
|
||||||
|
if (rv != 1) {
|
||||||
|
LOG(ERROR) << "OCSP_basic_verify failed: "
|
||||||
|
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sresp = OCSP_resp_get0(bs, 0);
|
||||||
|
if (sresp == nullptr) {
|
||||||
|
LOG(ERROR) << "OCSP response verification failed: no single response";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if OPENSSL_1_1_API
|
||||||
|
auto certid = OCSP_SINGLERESP_get0_id(sresp);
|
||||||
|
#else // !OPENSSL_1_1_API
|
||||||
|
auto certid = sresp->certId;
|
||||||
|
#endif // !OPENSSL_1_1_API
|
||||||
|
assert(certid != nullptr);
|
||||||
|
|
||||||
|
ASN1_INTEGER *serial;
|
||||||
|
rv = OCSP_id_get0_info(nullptr, nullptr, nullptr, &serial,
|
||||||
|
const_cast<OCSP_CERTID *>(certid));
|
||||||
|
if (rv != 1) {
|
||||||
|
LOG(ERROR) << "OCSP_id_get0_info failed";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serial == nullptr) {
|
||||||
|
LOG(ERROR) << "OCSP response does not contain serial number";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cert = SSL_CTX_get0_certificate(ssl_ctx);
|
||||||
|
auto cert_serial = X509_get_serialNumber(cert);
|
||||||
|
|
||||||
|
if (ASN1_INTEGER_cmp(cert_serial, serial)) {
|
||||||
|
LOG(ERROR) << "OCSP verification serial numbers do not match";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
LOG(INFO) << "OCSP verification succeeded";
|
||||||
|
}
|
||||||
|
#endif // !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >=
|
||||||
|
// 0x10002000L
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace tls
|
} // namespace tls
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -264,6 +264,11 @@ X509 *load_certificate(const char *filename);
|
||||||
// TLS version string.
|
// TLS version string.
|
||||||
int proto_version_from_string(const StringRef &v);
|
int proto_version_from_string(const StringRef &v);
|
||||||
|
|
||||||
|
// Verifies OCSP response |ocsp_resp| of length |ocsp_resplen|. This
|
||||||
|
// function returns 0 if it succeeds, or -1.
|
||||||
|
int verify_ocsp_response(SSL_CTX *ssl_ctx, const uint8_t *ocsp_resp,
|
||||||
|
size_t ocsp_resplen);
|
||||||
|
|
||||||
} // namespace tls
|
} // namespace tls
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
Loading…
Reference in New Issue