Merge branch 'nghttpx-verify-ocsp'

This commit is contained in:
Tatsuhiro Tsujikawa 2017-05-25 23:37:34 +09:00
commit db7483ef10
7 changed files with 113 additions and 3 deletions

View File

@ -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 = [

View File

@ -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,

View File

@ -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";

View File

@ -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,

View File

@ -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();

View File

@ -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

View File

@ -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