From 3297a303bfc0320a24da137616ff17213119b891 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 13 Feb 2016 00:20:38 +0900 Subject: [PATCH] nghttpx: Add client auth options for session cache memcached TLS connection --- gennghttpxfun.py | 4 +++- src/shrpx.cc | 20 ++++++++++++++++++++ src/shrpx_config.cc | 25 +++++++++++++++++++++++++ src/shrpx_config.h | 7 +++++++ src/shrpx_connection_handler.cc | 18 ++++++++++++------ src/shrpx_ssl.cc | 24 +++++++++++++----------- src/shrpx_ssl.h | 4 ++-- src/template.h | 7 +++++++ 8 files changed, 89 insertions(+), 20 deletions(-) diff --git a/gennghttpxfun.py b/gennghttpxfun.py index 500d47a6..0df2c3be 100755 --- a/gennghttpxfun.py +++ b/gennghttpxfun.py @@ -115,7 +115,9 @@ OPTIONS = [ "max-header-fields", "no-http2-cipher-black-list", "backend-http1-tls", - "backend-tls-session-cache-per-worker" + "backend-tls-session-cache-per-worker", + "tls-session-cache-memcached-cert-file", + "tls-session-cache-memcached-private-key-file" ] LOGVARS = [ diff --git a/src/shrpx.cc b/src/shrpx.cc index 04e85664..7f365ed4 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -1567,6 +1567,12 @@ SSL/TLS: --tls-session-cache-memcached-tls Enable SSL/TLS on memcached connections to store session cache. + --tls-session-cache-memcached-cert-file= + Path to client certificate for memcached connections to + store session cache. + --tls-session-cache-memcached-private-key-file= + Path to client private key for memcached connections to + store session cache. --tls-dyn-rec-warmup-threshold= Specify the threshold size for TLS dynamic record size behaviour. During a TLS session, after the threshold @@ -2404,6 +2410,10 @@ int main(int argc, char **argv) { {SHRPX_OPT_BACKEND_TLS_SESSION_CACHE_PER_WORKER, required_argument, &flag, 107}, {SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_TLS, no_argument, &flag, 108}, + {SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE, required_argument, + &flag, 109}, + {SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE, + required_argument, &flag, 110}, {nullptr, 0, nullptr, 0}}; int option_index = 0; @@ -2866,6 +2876,16 @@ int main(int argc, char **argv) { // --tls-session-cache-memcached-tls cmdcfgs.emplace_back(SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_TLS, "yes"); break; + case 109: + // --tls-session-cache-memcached-cert-file + cmdcfgs.emplace_back(SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE, + optarg); + break; + case 110: + // --tls-session-cache-memcached-private-key-file + cmdcfgs.emplace_back( + SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE, optarg); + break; default: break; } diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 68e4da5b..0b0ff5ff 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -758,6 +758,8 @@ enum { SHRPX_OPTID_TLS_DYN_REC_WARMUP_THRESHOLD, SHRPX_OPTID_TLS_PROTO_LIST, SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED, + SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE, + SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE, SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_TLS, SHRPX_OPTID_TLS_TICKET_KEY_CIPHER, SHRPX_OPTID_TLS_TICKET_KEY_FILE, @@ -1406,6 +1408,11 @@ int option_lookup_token(const char *name, size_t namelen) { break; case 37: switch (name[36]) { + case 'e': + if (util::strieq_l("tls-session-cache-memcached-cert-fil", name, 36)) { + return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE; + } + break; case 's': if (util::strieq_l("frontend-http2-connection-window-bit", name, 36)) { return SHRPX_OPTID_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS; @@ -1422,6 +1429,16 @@ int option_lookup_token(const char *name, size_t namelen) { break; } break; + case 44: + switch (name[43]) { + case 'e': + if (util::strieq_l("tls-session-cache-memcached-private-key-fil", name, + 43)) { + return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE; + } + break; + } + break; } return -1; } @@ -2242,6 +2259,14 @@ int parse_config(const char *opt, const char *optarg, case SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_TLS: mod_config()->tls.session_cache.memcached.tls = util::strieq(optarg, "yes"); + return 0; + case SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE: + mod_config()->tls.session_cache.memcached.cert_file = optarg; + + return 0; + case SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE: + mod_config()->tls.session_cache.memcached.private_key_file = optarg; + return 0; case SHRPX_OPTID_CONF: LOG(WARN) << "conf: ignored"; diff --git a/src/shrpx_config.h b/src/shrpx_config.h index 5a67d06e..2bf6aef7 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -211,6 +211,10 @@ constexpr char SHRPX_OPT_BACKEND_TLS_SESSION_CACHE_PER_WORKER[] = "backend-tls-session-cache-per-worker"; constexpr char SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_TLS[] = "tls-session-cache-memcached-tls"; +constexpr char SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE[] = + "tls-session-cache-memcached-cert-file"; +constexpr char SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE[] = + "tls-session-cache-memcached-private-key-file"; constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; @@ -357,6 +361,9 @@ struct TLSConfig { Address addr; uint16_t port; std::unique_ptr host; + // Client private key and certificate for authentication + ImmutableString private_key_file; + ImmutableString cert_file; bool tls; } memcached; } session_cache; diff --git a/src/shrpx_connection_handler.cc b/src/shrpx_connection_handler.cc index 1ff4c7ef..da023d9c 100644 --- a/src/shrpx_connection_handler.cc +++ b/src/shrpx_connection_handler.cc @@ -193,15 +193,18 @@ int ConnectionHandler::create_single_worker() { all_ssl_ctx_.push_back(cl_ssl_ctx); } - auto &session_cacheconf = get_config()->tls.session_cache; + auto &tlsconf = get_config()->tls; + auto &memcachedconf = get_config()->tls.session_cache.memcached; SSL_CTX *session_cache_ssl_ctx = nullptr; - if (session_cacheconf.memcached.tls) { + if (memcachedconf.tls) { session_cache_ssl_ctx = ssl::create_ssl_client_context( #ifdef HAVE_NEVERBLEED nb_.get(), #endif // HAVE_NEVERBLEED - nullptr, nullptr, nullptr, StringRef(), nullptr); + StringRef::from_maybe_nullptr(tlsconf.cacert.get()), + StringRef(memcachedconf.cert_file), + StringRef(memcachedconf.private_key_file), StringRef(), nullptr); all_ssl_ctx_.push_back(session_cache_ssl_ctx); } @@ -238,18 +241,21 @@ int ConnectionHandler::create_worker_thread(size_t num) { all_ssl_ctx_.push_back(cl_ssl_ctx); } - auto &session_cacheconf = get_config()->tls.session_cache; + auto &tlsconf = get_config()->tls; + auto &memcachedconf = get_config()->tls.session_cache.memcached; for (size_t i = 0; i < num; ++i) { auto loop = ev_loop_new(0); SSL_CTX *session_cache_ssl_ctx = nullptr; - if (session_cacheconf.memcached.tls) { + if (memcachedconf.tls) { session_cache_ssl_ctx = ssl::create_ssl_client_context( #ifdef HAVE_NEVERBLEED nb_.get(), #endif // HAVE_NEVERBLEED - nullptr, nullptr, nullptr, StringRef(), nullptr); + StringRef::from_maybe_nullptr(tlsconf.cacert.get()), + StringRef(memcachedconf.cert_file), + StringRef(memcachedconf.private_key_file), StringRef(), nullptr); all_ssl_ctx_.push_back(session_cache_ssl_ctx); } auto worker = diff --git a/src/shrpx_ssl.cc b/src/shrpx_ssl.cc index ee82022d..5d8a2360 100644 --- a/src/shrpx_ssl.cc +++ b/src/shrpx_ssl.cc @@ -662,8 +662,8 @@ SSL_CTX *create_ssl_client_context( #ifdef HAVE_NEVERBLEED neverbleed_t *nb, #endif // HAVE_NEVERBLEED - const char *cacert, const char *cert_file, const char *private_key_file, - const StringRef &alpn, + const StringRef &cacert, const StringRef &cert_file, + const StringRef &private_key_file, const StringRef &alpn, int (*next_proto_select_cb)(SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)) { @@ -702,8 +702,8 @@ SSL_CTX *create_ssl_client_context( << ERR_error_string(ERR_get_error(), nullptr); } - if (cacert) { - if (SSL_CTX_load_verify_locations(ssl_ctx, cacert, nullptr) != 1) { + if (!cacert.empty()) { + if (SSL_CTX_load_verify_locations(ssl_ctx, cacert.c_str(), nullptr) != 1) { LOG(FATAL) << "Could not load trusted ca certificates from " << cacert << ": " << ERR_error_string(ERR_get_error(), nullptr); @@ -711,8 +711,8 @@ SSL_CTX *create_ssl_client_context( } } - if (cert_file) { - if (SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file) != 1) { + if (!cert_file.empty()) { + if (SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file.c_str()) != 1) { LOG(FATAL) << "Could not load client certificate from " << cert_file << ": " << ERR_error_string(ERR_get_error(), nullptr); @@ -720,9 +720,9 @@ SSL_CTX *create_ssl_client_context( } } - if (private_key_file) { + if (!private_key_file.empty()) { #ifndef HAVE_NEVERBLEED - if (SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key_file, + if (SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key_file.c_str(), SSL_FILETYPE_PEM) != 1) { LOG(FATAL) << "Could not load client private key from " << private_key_file << ": " @@ -731,7 +731,7 @@ SSL_CTX *create_ssl_client_context( } #else // HAVE_NEVERBLEED std::array errbuf; - if (neverbleed_load_private_key_file(nb, ssl_ctx, private_key_file, + if (neverbleed_load_private_key_file(nb, ssl_ctx, private_key_file.c_str(), errbuf.data()) != 1) { LOG(FATAL) << "neverbleed_load_private_key_file: could not load client " "private key from " << private_key_file << ": " @@ -1323,8 +1323,10 @@ SSL_CTX *setup_downstream_client_ssl_context( #ifdef HAVE_NEVERBLEED nb, #endif // HAVE_NEVERBLEED - tlsconf.cacert.get(), tlsconf.client.cert_file.get(), - tlsconf.client.private_key_file.get(), alpn, next_proto_select_cb); + StringRef::from_maybe_nullptr(tlsconf.cacert.get()), + StringRef::from_maybe_nullptr(tlsconf.client.cert_file.get()), + StringRef::from_maybe_nullptr(tlsconf.client.private_key_file.get()), + alpn, next_proto_select_cb); } CertLookupTree *create_cert_lookup_tree() { diff --git a/src/shrpx_ssl.h b/src/shrpx_ssl.h index 4152a8ed..ca93da14 100644 --- a/src/shrpx_ssl.h +++ b/src/shrpx_ssl.h @@ -75,8 +75,8 @@ SSL_CTX *create_ssl_client_context( #ifdef HAVE_NEVERBLEED neverbleed_t *nb, #endif // HAVE_NEVERBLEED - const char *cacert, const char *cert_file, const char *private_key_file, - const StringRef &alpn, + const StringRef &cacert, const StringRef &cert_file, + const StringRef &private_key_file, const StringRef &alpn, int (*next_proto_select_cb)(SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)); diff --git a/src/template.h b/src/template.h index 0d4c4ba2..1a48d787 100644 --- a/src/template.h +++ b/src/template.h @@ -402,6 +402,13 @@ public: static StringRef from_lit(const CharT(&s)[N]) { return StringRef(s, N - 1); } + static StringRef from_maybe_nullptr(const char *s) { + if (s == nullptr) { + return StringRef(); + } + + return StringRef(s); + } const_iterator begin() const { return base; }; const_iterator cbegin() const { return base; };