Skip to content

Commit

Permalink
nghttpx: Verify OCSP response
Browse files Browse the repository at this point in the history
At least we should make sure that the OCSP response is targeted to the
expected certificate.  This is important because we pass the file path
to the external script, and if the file is replaced because of
renewal, and nghttpx has not reloaded its configuration, the
certificate nghttpx has loaded and the one included in the file
differ.  Verifying the OCSP response detects this, and avoids to send
wrong OCSP response.
  • Loading branch information
tatsuhiro-t committed May 25, 2017
1 parent 7f31278 commit 1428a5e
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 3 deletions.
7 changes: 4 additions & 3 deletions src/shrpx_connection_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -620,8 +620,9 @@ void ConnectionHandler::handle_ocsp_complete() {
<< " finished successfully";
}

if (tls::verify_ocsp_response(ssl_ctx, ocsp_.resp.data(),
ocsp_.resp.size()) == 0) {
#ifndef OPENSSL_IS_BORINGSSL
{
#ifdef HAVE_ATOMIC_STD_SHARED_PTR
std::atomic_store_explicit(
&tls_ctx_data->ocsp_data,
Expand All @@ -632,10 +633,10 @@ void ConnectionHandler::handle_ocsp_complete() {
tls_ctx_data->ocsp_data =
std::make_shared<std::vector<uint8_t>>(std::move(ocsp_.resp));
#endif // !HAVE_ATOMIC_STD_SHARED_PTR
}
#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
}

++ocsp_.next;
proceed_next_cert_ocsp();
Expand Down
79 changes: 79 additions & 0 deletions src/shrpx_tls.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include <openssl/x509v3.h>
#include <openssl/rand.h>
#include <openssl/dh.h>
#include <openssl/ocsp.h>

#include <nghttp2/nghttp2.h>

Expand Down Expand Up @@ -1818,6 +1819,84 @@ int proto_version_from_string(const StringRef &v) {
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 shrpx
5 changes: 5 additions & 0 deletions src/shrpx_tls.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,11 @@ X509 *load_certificate(const char *filename);
// TLS version string.
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 shrpx
Expand Down

0 comments on commit 1428a5e

Please sign in to comment.