Merge branch 'nghttpx-memcached-tls'

This commit is contained in:
Tatsuhiro Tsujikawa 2016-02-13 18:47:06 +09:00
commit 9037641592
16 changed files with 567 additions and 79 deletions

View File

@ -92,6 +92,7 @@ OPTIONS = [
"tls-ticket-key-cipher", "tls-ticket-key-cipher",
"host-rewrite", "host-rewrite",
"tls-session-cache-memcached", "tls-session-cache-memcached",
"tls-session-cache-memcached-tls",
"tls-ticket-key-memcached", "tls-ticket-key-memcached",
"tls-ticket-key-memcached-interval", "tls-ticket-key-memcached-interval",
"tls-ticket-key-memcached-max-retry", "tls-ticket-key-memcached-max-retry",
@ -114,7 +115,14 @@ OPTIONS = [
"max-header-fields", "max-header-fields",
"no-http2-cipher-black-list", "no-http2-cipher-black-list",
"backend-http1-tls", "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",
"tls-session-cache-memcached-address-family",
"tls-ticket-key-memcached-tls",
"tls-ticket-key-memcached-cert-file",
"tls-ticket-key-memcached-private-key-file",
"tls-ticket-key-memcached-address-family",
] ]
LOGVARS = [ LOGVARS = [

View File

@ -1051,6 +1051,13 @@ void fill_default_config() {
memcachedconf.max_retry = 3; memcachedconf.max_retry = 3;
memcachedconf.max_fail = 2; memcachedconf.max_fail = 2;
memcachedconf.interval = 10_min; memcachedconf.interval = 10_min;
memcachedconf.family = AF_UNSPEC;
}
auto &session_cacheconf = tlsconf.session_cache;
{
auto &memcachedconf = session_cacheconf.memcached;
memcachedconf.family = AF_UNSPEC;
} }
ticketconf.cipher = EVP_aes_128_cbc(); ticketconf.cipher = EVP_aes_128_cbc();
@ -1520,16 +1527,23 @@ SSL/TLS:
ticket key sharing between nghttpx instances is not ticket key sharing between nghttpx instances is not
required. required.
--tls-ticket-key-memcached=<HOST>,<PORT> --tls-ticket-key-memcached=<HOST>,<PORT>
Specify address of memcached server to store session Specify address of memcached server to get TLS ticket
cache. This enables shared TLS ticket key between keys for session resumption. This enables shared TLS
multiple nghttpx instances. nghttpx does not set TLS ticket key between multiple nghttpx instances. nghttpx
ticket key to memcached. The external ticket key does not set TLS ticket key to memcached. The external
generator is required. nghttpx just gets TLS ticket ticket key generator is required. nghttpx just gets TLS
keys from memcached, and use them, possibly replacing ticket keys from memcached, and use them, possibly
current set of keys. It is up to extern TLS ticket key replacing current set of keys. It is up to extern TLS
generator to rotate keys frequently. See "TLS SESSION ticket key generator to rotate keys frequently. See
TICKET RESUMPTION" section in manual page to know the "TLS SESSION TICKET RESUMPTION" section in manual page
data format in memcached entry. to know the data format in memcached entry.
--tls-ticket-key-memcached-address-family=(auto|IPv4|IPv6)
Specify address family of memcached connections to get
TLS ticket keys. If "auto" is given, both IPv4 and IPv6
are considered. If "IPv4" is given, only IPv4 address
is considered. If "IPv6" is given, only IPv6 address is
considered.
Default: auto
--tls-ticket-key-memcached-interval=<DURATION> --tls-ticket-key-memcached-interval=<DURATION>
Set interval to get TLS ticket keys from memcached. Set interval to get TLS ticket keys from memcached.
Default: )" Default: )"
@ -1550,6 +1564,15 @@ SSL/TLS:
Specify cipher to encrypt TLS session ticket. Specify Specify cipher to encrypt TLS session ticket. Specify
either aes-128-cbc or aes-256-cbc. By default, either aes-128-cbc or aes-256-cbc. By default,
aes-128-cbc is used. aes-128-cbc is used.
--tls-ticket-key-memcached-tls
Enable SSL/TLS on memcached connections to get TLS
ticket keys.
--tls-ticket-key-memcached-cert-file=<PATH>
Path to client certificate for memcached connections to
get TLS ticket keys.
--tls-ticket-key-memcached-private-key-file=<PATH>
Path to client private key for memcached connections to
get TLS ticket keys.
--fetch-ocsp-response-file=<PATH> --fetch-ocsp-response-file=<PATH>
Path to fetch-ocsp-response script file. It should be Path to fetch-ocsp-response script file. It should be
absolute path. absolute path.
@ -1564,6 +1587,22 @@ SSL/TLS:
Specify address of memcached server to store session Specify address of memcached server to store session
cache. This enables shared session cache between cache. This enables shared session cache between
multiple nghttpx instances. multiple nghttpx instances.
--tls-session-cache-memcached-address-family=(auto|IPv4|IPv6)
Specify address family of memcached connections to store
session cache. If "auto" is given, both IPv4 and IPv6
are considered. If "IPv4" is given, only IPv4 address
is considered. If "IPv6" is given, only IPv6 address is
considered.
Default: auto
--tls-session-cache-memcached-tls
Enable SSL/TLS on memcached connections to store session
cache.
--tls-session-cache-memcached-cert-file=<PATH>
Path to client certificate for memcached connections to
store session cache.
--tls-session-cache-memcached-private-key-file=<PATH>
Path to client private key for memcached connections to
store session cache.
--tls-dyn-rec-warmup-threshold=<SIZE> --tls-dyn-rec-warmup-threshold=<SIZE>
Specify the threshold size for TLS dynamic record size Specify the threshold size for TLS dynamic record size
behaviour. During a TLS session, after the threshold behaviour. During a TLS session, after the threshold
@ -2181,7 +2220,7 @@ void process_options(
auto &memcachedconf = tlsconf.session_cache.memcached; auto &memcachedconf = tlsconf.session_cache.memcached;
if (memcachedconf.host) { if (memcachedconf.host) {
if (resolve_hostname(&memcachedconf.addr, memcachedconf.host.get(), if (resolve_hostname(&memcachedconf.addr, memcachedconf.host.get(),
memcachedconf.port, AF_UNSPEC) == -1) { memcachedconf.port, memcachedconf.family) == -1) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
@ -2191,7 +2230,7 @@ void process_options(
auto &memcachedconf = tlsconf.ticket.memcached; auto &memcachedconf = tlsconf.ticket.memcached;
if (memcachedconf.host) { if (memcachedconf.host) {
if (resolve_hostname(&memcachedconf.addr, memcachedconf.host.get(), if (resolve_hostname(&memcachedconf.addr, memcachedconf.host.get(),
memcachedconf.port, AF_UNSPEC) == -1) { memcachedconf.port, memcachedconf.family) == -1) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
@ -2400,6 +2439,20 @@ int main(int argc, char **argv) {
{SHRPX_OPT_BACKEND_HTTP1_TLS, no_argument, &flag, 106}, {SHRPX_OPT_BACKEND_HTTP1_TLS, no_argument, &flag, 106},
{SHRPX_OPT_BACKEND_TLS_SESSION_CACHE_PER_WORKER, required_argument, {SHRPX_OPT_BACKEND_TLS_SESSION_CACHE_PER_WORKER, required_argument,
&flag, 107}, &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},
{SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_TLS, no_argument, &flag, 111},
{SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_CERT_FILE, required_argument, &flag,
112},
{SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE, required_argument,
&flag, 113},
{SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY, required_argument,
&flag, 114},
{SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY,
required_argument, &flag, 115},
{nullptr, 0, nullptr, 0}}; {nullptr, 0, nullptr, 0}};
int option_index = 0; int option_index = 0;
@ -2858,6 +2911,44 @@ int main(int argc, char **argv) {
cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_TLS_SESSION_CACHE_PER_WORKER, cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_TLS_SESSION_CACHE_PER_WORKER,
optarg); optarg);
break; break;
case 108:
// --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;
case 111:
// --tls-ticket-key-memcached-tls
cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_TLS, "yes");
break;
case 112:
// --tls-ticket-key-memcached-cert-file
cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_CERT_FILE,
optarg);
break;
case 113:
// --tls-ticket-key-memcached-private-key-file
cmdcfgs.emplace_back(
SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE, optarg);
break;
case 114:
// --tls-ticket-key-memcached-address-family
cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY,
optarg);
break;
case 115:
// --tls-session-cache-memcached-address-family
cmdcfgs.emplace_back(
SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY, optarg);
break;
default: default:
break; break;
} }

View File

@ -575,6 +575,26 @@ std::vector<LogFragment> parse_log_format(const char *optarg) {
return res; return res;
} }
namespace {
int parse_address_family(int *dest, const char *opt, const char *optarg) {
if (util::strieq("auto", optarg)) {
*dest = AF_UNSPEC;
return 0;
}
if (util::strieq("IPv4", optarg)) {
*dest = AF_INET;
return 0;
}
if (util::strieq("IPv6", optarg)) {
*dest = AF_INET6;
return 0;
}
LOG(ERROR) << opt << ": bad value: '" << optarg << "'";
return -1;
}
} // namespace
namespace { namespace {
int parse_duration(ev_tstamp *dest, const char *opt, const char *optarg) { int parse_duration(ev_tstamp *dest, const char *opt, const char *optarg) {
auto t = util::parse_duration_with_unit(optarg); auto t = util::parse_duration_with_unit(optarg);
@ -758,12 +778,20 @@ enum {
SHRPX_OPTID_TLS_DYN_REC_WARMUP_THRESHOLD, SHRPX_OPTID_TLS_DYN_REC_WARMUP_THRESHOLD,
SHRPX_OPTID_TLS_PROTO_LIST, SHRPX_OPTID_TLS_PROTO_LIST,
SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED, SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED,
SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY,
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_CIPHER,
SHRPX_OPTID_TLS_TICKET_KEY_FILE, SHRPX_OPTID_TLS_TICKET_KEY_FILE,
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED, SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED,
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY,
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_CERT_FILE,
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_INTERVAL, SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_INTERVAL,
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_MAX_FAIL, SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_MAX_FAIL,
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_MAX_RETRY, SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_MAX_RETRY,
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE,
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_TLS,
SHRPX_OPTID_USER, SHRPX_OPTID_USER,
SHRPX_OPTID_VERIFY_CLIENT, SHRPX_OPTID_VERIFY_CLIENT,
SHRPX_OPTID_VERIFY_CLIENT_CACERT, SHRPX_OPTID_VERIFY_CLIENT_CACERT,
@ -1325,6 +1353,9 @@ int option_lookup_token(const char *name, size_t namelen) {
if (util::strieq_l("http2-max-concurrent-stream", name, 27)) { if (util::strieq_l("http2-max-concurrent-stream", name, 27)) {
return SHRPX_OPTID_HTTP2_MAX_CONCURRENT_STREAMS; return SHRPX_OPTID_HTTP2_MAX_CONCURRENT_STREAMS;
} }
if (util::strieq_l("tls-ticket-key-memcached-tl", name, 27)) {
return SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_TLS;
}
break; break;
} }
break; break;
@ -1337,6 +1368,15 @@ int option_lookup_token(const char *name, size_t namelen) {
break; break;
} }
break; break;
case 31:
switch (name[30]) {
case 's':
if (util::strieq_l("tls-session-cache-memcached-tl", name, 30)) {
return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_TLS;
}
break;
}
break;
case 33: case 33:
switch (name[32]) { switch (name[32]) {
case 'l': case 'l':
@ -1351,6 +1391,11 @@ int option_lookup_token(const char *name, size_t namelen) {
break; break;
case 34: case 34:
switch (name[33]) { switch (name[33]) {
case 'e':
if (util::strieq_l("tls-ticket-key-memcached-cert-fil", name, 33)) {
return SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_CERT_FILE;
}
break;
case 'r': case 'r':
if (util::strieq_l("frontend-http2-dump-request-heade", name, 33)) { if (util::strieq_l("frontend-http2-dump-request-heade", name, 33)) {
return SHRPX_OPTID_FRONTEND_HTTP2_DUMP_REQUEST_HEADER; return SHRPX_OPTID_FRONTEND_HTTP2_DUMP_REQUEST_HEADER;
@ -1396,6 +1441,11 @@ int option_lookup_token(const char *name, size_t namelen) {
break; break;
case 37: case 37:
switch (name[36]) { 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': case 's':
if (util::strieq_l("frontend-http2-connection-window-bit", name, 36)) { if (util::strieq_l("frontend-http2-connection-window-bit", name, 36)) {
return SHRPX_OPTID_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS; return SHRPX_OPTID_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS;
@ -1412,6 +1462,45 @@ int option_lookup_token(const char *name, size_t namelen) {
break; break;
} }
break; break;
case 39:
switch (name[38]) {
case 'y':
if (util::strieq_l("tls-ticket-key-memcached-address-famil", name, 38)) {
return SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY;
}
break;
}
break;
case 41:
switch (name[40]) {
case 'e':
if (util::strieq_l("tls-ticket-key-memcached-private-key-fil", name,
40)) {
return SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE;
}
break;
}
break;
case 42:
switch (name[41]) {
case 'y':
if (util::strieq_l("tls-session-cache-memcached-address-famil", name,
41)) {
return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY;
}
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; return -1;
} }
@ -2229,6 +2318,36 @@ int parse_config(const char *opt, const char *optarg,
case SHRPX_OPTID_BACKEND_TLS_SESSION_CACHE_PER_WORKER: case SHRPX_OPTID_BACKEND_TLS_SESSION_CACHE_PER_WORKER:
return parse_uint(&mod_config()->tls.downstream_session_cache_per_worker, return parse_uint(&mod_config()->tls.downstream_session_cache_per_worker,
opt, optarg); opt, 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_TLS_TICKET_KEY_MEMCACHED_TLS:
mod_config()->tls.ticket.memcached.tls = util::strieq(optarg, "yes");
return 0;
case SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_CERT_FILE:
mod_config()->tls.ticket.memcached.cert_file = optarg;
return 0;
case SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE:
mod_config()->tls.ticket.memcached.private_key_file = optarg;
return 0;
case SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY:
return parse_address_family(&mod_config()->tls.ticket.memcached.family, opt,
optarg);
case SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY:
return parse_address_family(
&mod_config()->tls.session_cache.memcached.family, opt, optarg);
case SHRPX_OPTID_CONF: case SHRPX_OPTID_CONF:
LOG(WARN) << "conf: ignored"; LOG(WARN) << "conf: ignored";

View File

@ -209,6 +209,22 @@ constexpr char SHRPX_OPT_NO_HTTP2_CIPHER_BLACK_LIST[] =
constexpr char SHRPX_OPT_BACKEND_HTTP1_TLS[] = "backend-http1-tls"; constexpr char SHRPX_OPT_BACKEND_HTTP1_TLS[] = "backend-http1-tls";
constexpr char SHRPX_OPT_BACKEND_TLS_SESSION_CACHE_PER_WORKER[] = constexpr char SHRPX_OPT_BACKEND_TLS_SESSION_CACHE_PER_WORKER[] =
"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 char SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY[] =
"tls-session-cache-memcached-address-family";
constexpr char SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_TLS[] =
"tls-ticket-key-memcached-tls";
constexpr char SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_CERT_FILE[] =
"tls-ticket-key-memcached-cert-file";
constexpr char SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE[] =
"tls-ticket-key-memcached-private-key-file";
constexpr char SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY[] =
"tls-ticket-key-memcached-address-family";
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
@ -335,6 +351,9 @@ struct TLSConfig {
Address addr; Address addr;
uint16_t port; uint16_t port;
std::unique_ptr<char[]> host; std::unique_ptr<char[]> host;
// Client private key and certificate for authentication
ImmutableString private_key_file;
ImmutableString cert_file;
ev_tstamp interval; ev_tstamp interval;
// Maximum number of retries when getting TLS ticket key from // Maximum number of retries when getting TLS ticket key from
// mamcached, due to network error. // mamcached, due to network error.
@ -342,6 +361,10 @@ struct TLSConfig {
// Maximum number of consecutive error from memcached, when this // Maximum number of consecutive error from memcached, when this
// limit reached, TLS ticket is disabled. // limit reached, TLS ticket is disabled.
size_t max_fail; size_t max_fail;
// Address family of memcached connection. One of either
// AF_INET, AF_INET6 or AF_UNSPEC.
int family;
bool tls;
} memcached; } memcached;
std::vector<std::string> files; std::vector<std::string> files;
const EVP_CIPHER *cipher; const EVP_CIPHER *cipher;
@ -355,6 +378,13 @@ struct TLSConfig {
Address addr; Address addr;
uint16_t port; uint16_t port;
std::unique_ptr<char[]> host; std::unique_ptr<char[]> host;
// Client private key and certificate for authentication
ImmutableString private_key_file;
ImmutableString cert_file;
// Address family of memcached connection. One of either
// AF_INET, AF_INET6 or AF_UNSPEC.
int family;
bool tls;
} memcached; } memcached;
} session_cache; } session_cache;

View File

@ -193,8 +193,24 @@ int ConnectionHandler::create_single_worker() {
all_ssl_ctx_.push_back(cl_ssl_ctx); all_ssl_ctx_.push_back(cl_ssl_ctx);
} }
single_worker_ = make_unique<Worker>(loop_, sv_ssl_ctx, cl_ssl_ctx, cert_tree, auto &tlsconf = get_config()->tls;
ticket_keys_); auto &memcachedconf = get_config()->tls.session_cache.memcached;
SSL_CTX *session_cache_ssl_ctx = nullptr;
if (memcachedconf.tls) {
session_cache_ssl_ctx = ssl::create_ssl_client_context(
#ifdef HAVE_NEVERBLEED
nb_.get(),
#endif // HAVE_NEVERBLEED
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);
}
single_worker_ =
make_unique<Worker>(loop_, sv_ssl_ctx, cl_ssl_ctx, session_cache_ssl_ctx,
cert_tree, ticket_keys_);
#ifdef HAVE_MRUBY #ifdef HAVE_MRUBY
if (single_worker_->create_mruby_context() != 0) { if (single_worker_->create_mruby_context() != 0) {
return -1; return -1;
@ -225,11 +241,26 @@ int ConnectionHandler::create_worker_thread(size_t num) {
all_ssl_ctx_.push_back(cl_ssl_ctx); all_ssl_ctx_.push_back(cl_ssl_ctx);
} }
auto &tlsconf = get_config()->tls;
auto &memcachedconf = get_config()->tls.session_cache.memcached;
for (size_t i = 0; i < num; ++i) { for (size_t i = 0; i < num; ++i) {
auto loop = ev_loop_new(0); auto loop = ev_loop_new(0);
auto worker = make_unique<Worker>(loop, sv_ssl_ctx, cl_ssl_ctx, cert_tree, SSL_CTX *session_cache_ssl_ctx = nullptr;
ticket_keys_); if (memcachedconf.tls) {
session_cache_ssl_ctx = ssl::create_ssl_client_context(
#ifdef HAVE_NEVERBLEED
nb_.get(),
#endif // HAVE_NEVERBLEED
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 =
make_unique<Worker>(loop, sv_ssl_ctx, cl_ssl_ctx, session_cache_ssl_ctx,
cert_tree, ticket_keys_);
#ifdef HAVE_MRUBY #ifdef HAVE_MRUBY
if (worker->create_mruby_context() != 0) { if (worker->create_mruby_context() != 0) {
return -1; return -1;
@ -728,6 +759,23 @@ void ConnectionHandler::schedule_next_tls_ticket_key_memcached_get(
ev_timer_start(loop_, w); ev_timer_start(loop_, w);
} }
SSL_CTX *ConnectionHandler::create_tls_ticket_key_memcached_ssl_ctx() {
auto &tlsconf = get_config()->tls;
auto &memcachedconf = get_config()->tls.ticket.memcached;
auto ssl_ctx = ssl::create_ssl_client_context(
#ifdef HAVE_NEVERBLEED
nb_.get(),
#endif // HAVE_NEVERBLEED
StringRef::from_maybe_nullptr(tlsconf.cacert.get()),
StringRef(memcachedconf.cert_file),
StringRef(memcachedconf.private_key_file), StringRef(), nullptr);
all_ssl_ctx_.push_back(ssl_ctx);
return ssl_ctx;
}
#ifdef HAVE_NEVERBLEED #ifdef HAVE_NEVERBLEED
void ConnectionHandler::set_neverbleed(std::unique_ptr<neverbleed_t> nb) { void ConnectionHandler::set_neverbleed(std::unique_ptr<neverbleed_t> nb) {
nb_ = std::move(nb); nb_ = std::move(nb);

View File

@ -129,6 +129,7 @@ public:
on_tls_ticket_key_get_success(const std::shared_ptr<TicketKeys> &ticket_keys, on_tls_ticket_key_get_success(const std::shared_ptr<TicketKeys> &ticket_keys,
ev_timer *w); ev_timer *w);
void schedule_next_tls_ticket_key_memcached_get(ev_timer *w); void schedule_next_tls_ticket_key_memcached_get(ev_timer *w);
SSL_CTX *create_tls_ticket_key_memcached_ssl_ctx();
#ifdef HAVE_NEVERBLEED #ifdef HAVE_NEVERBLEED
void set_neverbleed(std::unique_ptr<neverbleed_t> nb); void set_neverbleed(std::unique_ptr<neverbleed_t> nb);

View File

@ -32,6 +32,7 @@
#include "shrpx_memcached_request.h" #include "shrpx_memcached_request.h"
#include "shrpx_memcached_result.h" #include "shrpx_memcached_result.h"
#include "shrpx_config.h" #include "shrpx_config.h"
#include "shrpx_ssl.h"
#include "util.h" #include "util.h"
namespace shrpx { namespace shrpx {
@ -78,7 +79,7 @@ void connectcb(struct ev_loop *loop, ev_io *w, int revents) {
auto conn = static_cast<Connection *>(w->data); auto conn = static_cast<Connection *>(w->data);
auto mconn = static_cast<MemcachedConnection *>(conn->data); auto mconn = static_cast<MemcachedConnection *>(conn->data);
if (mconn->on_connect() != 0) { if (mconn->connected() != 0) {
mconn->disconnect(); mconn->disconnect();
return; return;
} }
@ -91,11 +92,17 @@ constexpr ev_tstamp write_timeout = 10.;
constexpr ev_tstamp read_timeout = 10.; constexpr ev_tstamp read_timeout = 10.;
MemcachedConnection::MemcachedConnection(const Address *addr, MemcachedConnection::MemcachedConnection(const Address *addr,
struct ev_loop *loop) struct ev_loop *loop, SSL_CTX *ssl_ctx,
: conn_(loop, -1, nullptr, nullptr, write_timeout, read_timeout, {}, {}, const StringRef &sni_name,
MemchunkPool *mcpool)
: conn_(loop, -1, nullptr, mcpool, write_timeout, read_timeout, {}, {},
connectcb, readcb, timeoutcb, this, 0, 0.), connectcb, readcb, timeoutcb, this, 0, 0.),
do_read_(&MemcachedConnection::noop),
do_write_(&MemcachedConnection::noop),
sni_name_(sni_name.str()),
parse_state_{}, parse_state_{},
addr_(addr), addr_(addr),
ssl_ctx_(ssl_ctx),
sendsum_(0), sendsum_(0),
connected_(false) {} connected_(false) {}
@ -127,11 +134,21 @@ void MemcachedConnection::disconnect() {
assert(recvbuf_.rleft() == 0); assert(recvbuf_.rleft() == 0);
recvbuf_.reset(); recvbuf_.reset();
do_read_ = do_write_ = &MemcachedConnection::noop;
} }
int MemcachedConnection::initiate_connection() { int MemcachedConnection::initiate_connection() {
assert(conn_.fd == -1); assert(conn_.fd == -1);
if (ssl_ctx_ && !conn_.tls.ssl) {
auto ssl = ssl::create_ssl(ssl_ctx_);
if (!ssl) {
return -1;
}
conn_.set_ssl(ssl);
}
conn_.fd = util::create_nonblock_socket(addr_->su.storage.ss_family); conn_.fd = util::create_nonblock_socket(addr_->su.storage.ss_family);
if (conn_.fd == -1) { if (conn_.fd == -1) {
@ -153,6 +170,14 @@ int MemcachedConnection::initiate_connection() {
return -1; return -1;
} }
if (ssl_ctx_) {
if (!util::numeric_host(sni_name_.c_str())) {
SSL_set_tlsext_host_name(conn_.tls.ssl, sni_name_.c_str());
}
conn_.prepare_client_handshake();
}
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {
MCLOG(INFO, this) << "Connecting to memcached server"; MCLOG(INFO, this) << "Connecting to memcached server";
} }
@ -168,7 +193,7 @@ int MemcachedConnection::initiate_connection() {
return 0; return 0;
} }
int MemcachedConnection::on_connect() { int MemcachedConnection::connected() {
if (!util::check_socket_connected(conn_.fd)) { if (!util::check_socket_connected(conn_.fd)) {
conn_.wlimit.stopw(); conn_.wlimit.stopw();
@ -185,15 +210,59 @@ int MemcachedConnection::on_connect() {
connected_ = true; connected_ = true;
ev_set_cb(&conn_.wev, writecb);
conn_.rlimit.startw(); conn_.rlimit.startw();
ev_timer_again(conn_.loop, &conn_.rt); ev_timer_again(conn_.loop, &conn_.rt);
ev_set_cb(&conn_.wev, writecb);
if (conn_.tls.ssl) {
do_read_ = &MemcachedConnection::tls_handshake;
do_write_ = &MemcachedConnection::tls_handshake;
return 0;
}
do_read_ = &MemcachedConnection::read_clear;
do_write_ = &MemcachedConnection::write_clear;
return 0; return 0;
} }
int MemcachedConnection::on_write() { int MemcachedConnection::on_write() { return do_write_(*this); }
int MemcachedConnection::on_read() { return do_read_(*this); }
int MemcachedConnection::tls_handshake() {
ERR_clear_error();
ev_timer_again(conn_.loop, &conn_.rt);
auto rv = conn_.tls_handshake();
if (rv == SHRPX_ERR_INPROGRESS) {
return 0;
}
if (rv < 0) {
return rv;
}
if (LOG_ENABLED(INFO)) {
LOG(INFO) << "SSL/TLS handshake completed";
}
auto &tlsconf = get_config()->tls;
if (!tlsconf.insecure &&
ssl::check_cert(conn_.tls.ssl, addr_, StringRef(sni_name_)) != 0) {
return -1;
}
do_read_ = &MemcachedConnection::read_tls;
do_write_ = &MemcachedConnection::write_tls;
return on_write();
}
int MemcachedConnection::write_tls() {
if (!connected_) { if (!connected_) {
return 0; return 0;
} }
@ -207,19 +276,30 @@ int MemcachedConnection::on_write() {
return 0; return 0;
} }
int rv; std::array<struct iovec, MAX_WR_IOVCNT> iov;
std::array<uint8_t, 16_k> buf;
for (; !sendq_.empty();) { for (; !sendq_.empty();) {
rv = send_request(); auto iovcnt = fill_request_buffer(iov.data(), iov.size());
auto p = std::begin(buf);
for (size_t i = 0; i < iovcnt; ++i) {
auto &v = iov[i];
auto n = std::min(static_cast<size_t>(std::end(buf) - p), v.iov_len);
p = std::copy_n(static_cast<uint8_t *>(v.iov_base), n, p);
if (p == std::end(buf)) {
break;
}
}
if (rv < 0) { auto nwrite = conn_.write_tls(buf.data(), p - std::begin(buf));
if (nwrite < 0) {
return -1; return -1;
} }
if (nwrite == 0) {
if (rv == 1) {
// blocked
return 0; return 0;
} }
drain_send_queue(nwrite);
} }
conn_.wlimit.stopw(); conn_.wlimit.stopw();
@ -228,7 +308,70 @@ int MemcachedConnection::on_write() {
return 0; return 0;
} }
int MemcachedConnection::on_read() { int MemcachedConnection::read_tls() {
if (!connected_) {
return 0;
}
ev_timer_again(conn_.loop, &conn_.rt);
for (;;) {
auto nread = conn_.read_tls(recvbuf_.last, recvbuf_.wleft());
if (nread == 0) {
return 0;
}
if (nread < 0) {
return -1;
}
recvbuf_.write(nread);
if (parse_packet() != 0) {
return -1;
}
}
return 0;
}
int MemcachedConnection::write_clear() {
if (!connected_) {
return 0;
}
ev_timer_again(conn_.loop, &conn_.rt);
if (sendq_.empty()) {
conn_.wlimit.stopw();
ev_timer_stop(conn_.loop, &conn_.wt);
return 0;
}
std::array<struct iovec, MAX_WR_IOVCNT> iov;
for (; !sendq_.empty();) {
auto iovcnt = fill_request_buffer(iov.data(), iov.size());
auto nwrite = conn_.writev_clear(iov.data(), iovcnt);
if (nwrite < 0) {
return -1;
}
if (nwrite == 0) {
return 0;
}
drain_send_queue(nwrite);
}
conn_.wlimit.stopw();
ev_timer_stop(conn_.loop, &conn_.wt);
return 0;
}
int MemcachedConnection::read_clear() {
if (!connected_) { if (!connected_) {
return 0; return 0;
} }
@ -415,9 +558,8 @@ int MemcachedConnection::parse_packet() {
#define MAX_WR_IOVCNT DEFAULT_WR_IOVCNT #define MAX_WR_IOVCNT DEFAULT_WR_IOVCNT
#endif // !defined(IOV_MAX) || IOV_MAX >= DEFAULT_WR_IOVCNT #endif // !defined(IOV_MAX) || IOV_MAX >= DEFAULT_WR_IOVCNT
int MemcachedConnection::send_request() { size_t MemcachedConnection::fill_request_buffer(struct iovec *iov,
ssize_t nwrite; size_t iovlen) {
if (sendsum_ == 0) { if (sendsum_ == 0) {
for (auto &req : sendq_) { for (auto &req : sendq_) {
if (req->canceled) { if (req->canceled) {
@ -438,32 +580,27 @@ int MemcachedConnection::send_request() {
} }
} }
std::array<struct iovec, DEFAULT_WR_IOVCNT> iov; size_t iovcnt = 0;
size_t iovlen = 0;
for (auto &buf : sendbufv_) { for (auto &buf : sendbufv_) {
if (iovlen + 2 > iov.size()) { if (iovcnt + 2 > iovlen) {
break; break;
} }
auto req = buf.req; auto req = buf.req;
if (buf.headbuf.rleft()) { if (buf.headbuf.rleft()) {
iov[iovlen++] = {buf.headbuf.pos, buf.headbuf.rleft()}; iov[iovcnt++] = {buf.headbuf.pos, buf.headbuf.rleft()};
} }
if (buf.send_value_left) { if (buf.send_value_left) {
iov[iovlen++] = {req->value.data() + req->value.size() - iov[iovcnt++] = {req->value.data() + req->value.size() -
buf.send_value_left, buf.send_value_left,
buf.send_value_left}; buf.send_value_left};
} }
} }
nwrite = conn_.writev_clear(iov.data(), iovlen); return iovcnt;
if (nwrite < 0) { }
return -1;
}
if (nwrite == 0) {
return 1;
}
void MemcachedConnection::drain_send_queue(size_t nwrite) {
sendsum_ -= nwrite; sendsum_ -= nwrite;
while (nwrite > 0) { while (nwrite > 0) {
@ -488,8 +625,6 @@ int MemcachedConnection::send_request() {
recvq_.push_back(std::move(sendq_.front())); recvq_.push_back(std::move(sendq_.front()));
sendq_.pop_front(); sendq_.pop_front();
} }
return 0;
} }
size_t MemcachedConnection::serialized_size(MemcachedRequest *req) { size_t MemcachedConnection::serialized_size(MemcachedRequest *req) {
@ -549,4 +684,6 @@ int MemcachedConnection::add_request(std::unique_ptr<MemcachedRequest> req) {
// TODO should we start write timer too? // TODO should we start write timer too?
void MemcachedConnection::signal_write() { conn_.wlimit.startw(); } void MemcachedConnection::signal_write() { conn_.wlimit.startw(); }
int MemcachedConnection::noop() { return 0; }
} // namespace shrpx } // namespace shrpx

View File

@ -93,7 +93,9 @@ constexpr uint8_t MEMCACHED_RES_MAGIC = 0x81;
// https://code.google.com/p/memcached/wiki/MemcacheBinaryProtocol // https://code.google.com/p/memcached/wiki/MemcacheBinaryProtocol
class MemcachedConnection { class MemcachedConnection {
public: public:
MemcachedConnection(const Address *addr, struct ev_loop *loop); MemcachedConnection(const Address *addr, struct ev_loop *loop,
SSL_CTX *ssl_ctx, const StringRef &sni_name,
MemchunkPool *mcpool);
~MemcachedConnection(); ~MemcachedConnection();
void disconnect(); void disconnect();
@ -101,23 +103,38 @@ public:
int add_request(std::unique_ptr<MemcachedRequest> req); int add_request(std::unique_ptr<MemcachedRequest> req);
int initiate_connection(); int initiate_connection();
int on_connect(); int connected();
int on_write(); int on_write();
int on_read(); int on_read();
int send_request();
int write_clear();
int read_clear();
int tls_handshake();
int write_tls();
int read_tls();
size_t fill_request_buffer(struct iovec *iov, size_t iovlen);
void drain_send_queue(size_t nwrite);
void make_request(MemcachedSendbuf *sendbuf, MemcachedRequest *req); void make_request(MemcachedSendbuf *sendbuf, MemcachedRequest *req);
int parse_packet(); int parse_packet();
size_t serialized_size(MemcachedRequest *req); size_t serialized_size(MemcachedRequest *req);
void signal_write(); void signal_write();
int noop();
private: private:
Connection conn_; Connection conn_;
std::deque<std::unique_ptr<MemcachedRequest>> recvq_; std::deque<std::unique_ptr<MemcachedRequest>> recvq_;
std::deque<std::unique_ptr<MemcachedRequest>> sendq_; std::deque<std::unique_ptr<MemcachedRequest>> sendq_;
std::deque<MemcachedSendbuf> sendbufv_; std::deque<MemcachedSendbuf> sendbufv_;
std::function<int(MemcachedConnection &)> do_read_, do_write_;
std::string sni_name_;
MemcachedParseState parse_state_; MemcachedParseState parse_state_;
const Address *addr_; const Address *addr_;
SSL_CTX *ssl_ctx_;
// Sum of the bytes to be transmitted in sendbufv_. // Sum of the bytes to be transmitted in sendbufv_.
size_t sendsum_; size_t sendsum_;
bool connected_; bool connected_;

View File

@ -31,8 +31,12 @@
namespace shrpx { namespace shrpx {
MemcachedDispatcher::MemcachedDispatcher(const Address *addr, MemcachedDispatcher::MemcachedDispatcher(const Address *addr,
struct ev_loop *loop) struct ev_loop *loop, SSL_CTX *ssl_ctx,
: loop_(loop), mconn_(make_unique<MemcachedConnection>(addr, loop_)) {} const StringRef &sni_name,
MemchunkPool *mcpool)
: loop_(loop),
mconn_(make_unique<MemcachedConnection>(addr, loop_, ssl_ctx, sni_name,
mcpool)) {}
MemcachedDispatcher::~MemcachedDispatcher() {} MemcachedDispatcher::~MemcachedDispatcher() {}

View File

@ -31,6 +31,10 @@
#include <ev.h> #include <ev.h>
#include <openssl/ssl.h>
#include "memchunk.h"
namespace shrpx { namespace shrpx {
struct MemcachedRequest; struct MemcachedRequest;
@ -39,7 +43,9 @@ struct Address;
class MemcachedDispatcher { class MemcachedDispatcher {
public: public:
MemcachedDispatcher(const Address *addr, struct ev_loop *loop); MemcachedDispatcher(const Address *addr, struct ev_loop *loop,
SSL_CTX *ssl_ctx, const StringRef &sni_name,
MemchunkPool *mcpool);
~MemcachedDispatcher(); ~MemcachedDispatcher();
int add_request(std::unique_ptr<MemcachedRequest> req); int add_request(std::unique_ptr<MemcachedRequest> req);

View File

@ -662,8 +662,8 @@ SSL_CTX *create_ssl_client_context(
#ifdef HAVE_NEVERBLEED #ifdef HAVE_NEVERBLEED
neverbleed_t *nb, neverbleed_t *nb,
#endif // HAVE_NEVERBLEED #endif // HAVE_NEVERBLEED
const char *cacert, const char *cert_file, const char *private_key_file, const StringRef &cacert, const StringRef &cert_file,
const StringRef &alpn, const StringRef &private_key_file, const StringRef &alpn,
int (*next_proto_select_cb)(SSL *s, unsigned char **out, int (*next_proto_select_cb)(SSL *s, unsigned char **out,
unsigned char *outlen, const unsigned char *in, unsigned char *outlen, const unsigned char *in,
unsigned int inlen, void *arg)) { unsigned int inlen, void *arg)) {
@ -702,8 +702,8 @@ SSL_CTX *create_ssl_client_context(
<< ERR_error_string(ERR_get_error(), nullptr); << ERR_error_string(ERR_get_error(), nullptr);
} }
if (cacert) { if (!cacert.empty()) {
if (SSL_CTX_load_verify_locations(ssl_ctx, cacert, nullptr) != 1) { if (SSL_CTX_load_verify_locations(ssl_ctx, cacert.c_str(), nullptr) != 1) {
LOG(FATAL) << "Could not load trusted ca certificates from " << cacert LOG(FATAL) << "Could not load trusted ca certificates from " << cacert
<< ": " << ERR_error_string(ERR_get_error(), nullptr); << ": " << ERR_error_string(ERR_get_error(), nullptr);
@ -711,8 +711,8 @@ SSL_CTX *create_ssl_client_context(
} }
} }
if (cert_file) { if (!cert_file.empty()) {
if (SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file) != 1) { if (SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file.c_str()) != 1) {
LOG(FATAL) << "Could not load client certificate from " << cert_file LOG(FATAL) << "Could not load client certificate from " << cert_file
<< ": " << ERR_error_string(ERR_get_error(), nullptr); << ": " << 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 #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) { SSL_FILETYPE_PEM) != 1) {
LOG(FATAL) << "Could not load client private key from " LOG(FATAL) << "Could not load client private key from "
<< private_key_file << ": " << private_key_file << ": "
@ -731,7 +731,7 @@ SSL_CTX *create_ssl_client_context(
} }
#else // HAVE_NEVERBLEED #else // HAVE_NEVERBLEED
std::array<char, NEVERBLEED_ERRBUF_SIZE> errbuf; std::array<char, NEVERBLEED_ERRBUF_SIZE> 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) { errbuf.data()) != 1) {
LOG(FATAL) << "neverbleed_load_private_key_file: could not load client " LOG(FATAL) << "neverbleed_load_private_key_file: could not load client "
"private key from " << private_key_file << ": " "private key from " << private_key_file << ": "
@ -982,7 +982,7 @@ int verify_hostname(X509 *cert, const char *hostname, size_t hlen,
} }
} // namespace } // namespace
int check_cert(SSL *ssl, const DownstreamAddr *addr) { int check_cert(SSL *ssl, const Address *addr, const StringRef &host) {
auto cert = SSL_get_peer_certificate(ssl); auto cert = SSL_get_peer_certificate(ssl);
if (!cert) { if (!cert) {
LOG(ERROR) << "No certificate found"; LOG(ERROR) << "No certificate found";
@ -996,18 +996,21 @@ int check_cert(SSL *ssl, const DownstreamAddr *addr) {
return -1; return -1;
} }
auto &backend_sni_name = get_config()->tls.backend_sni_name; if (verify_hostname(cert, host.c_str(), host.size(), addr) != 0) {
auto hostname = !backend_sni_name.empty() ? StringRef(backend_sni_name)
: StringRef(addr->host);
if (verify_hostname(cert, hostname.c_str(), hostname.size(), &addr->addr) !=
0) {
LOG(ERROR) << "Certificate verification failed: hostname does not match"; LOG(ERROR) << "Certificate verification failed: hostname does not match";
return -1; return -1;
} }
return 0; return 0;
} }
int check_cert(SSL *ssl, const DownstreamAddr *addr) {
auto &backend_sni_name = get_config()->tls.backend_sni_name;
auto hostname = !backend_sni_name.empty() ? StringRef(backend_sni_name)
: StringRef(addr->host);
return check_cert(ssl, &addr->addr, hostname);
}
CertLookupTree::CertLookupTree() { CertLookupTree::CertLookupTree() {
root_.ssl_ctx = nullptr; root_.ssl_ctx = nullptr;
root_.str = nullptr; root_.str = nullptr;
@ -1320,8 +1323,10 @@ SSL_CTX *setup_downstream_client_ssl_context(
#ifdef HAVE_NEVERBLEED #ifdef HAVE_NEVERBLEED
nb, nb,
#endif // HAVE_NEVERBLEED #endif // HAVE_NEVERBLEED
tlsconf.cacert.get(), tlsconf.client.cert_file.get(), StringRef::from_maybe_nullptr(tlsconf.cacert.get()),
tlsconf.client.private_key_file.get(), alpn, next_proto_select_cb); 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() { CertLookupTree *create_cert_lookup_tree() {

View File

@ -46,6 +46,7 @@ class Worker;
class DownstreamConnectionPool; class DownstreamConnectionPool;
struct DownstreamAddr; struct DownstreamAddr;
struct UpstreamAddr; struct UpstreamAddr;
struct Address;
namespace ssl { namespace ssl {
@ -74,8 +75,8 @@ SSL_CTX *create_ssl_client_context(
#ifdef HAVE_NEVERBLEED #ifdef HAVE_NEVERBLEED
neverbleed_t *nb, neverbleed_t *nb,
#endif // HAVE_NEVERBLEED #endif // HAVE_NEVERBLEED
const char *cacert, const char *cert_file, const char *private_key_file, const StringRef &cacert, const StringRef &cert_file,
const StringRef &alpn, const StringRef &private_key_file, const StringRef &alpn,
int (*next_proto_select_cb)(SSL *s, unsigned char **out, int (*next_proto_select_cb)(SSL *s, unsigned char **out,
unsigned char *outlen, const unsigned char *in, unsigned char *outlen, const unsigned char *in,
unsigned int inlen, void *arg)); unsigned int inlen, void *arg));
@ -83,9 +84,8 @@ SSL_CTX *create_ssl_client_context(
ClientHandler *accept_connection(Worker *worker, int fd, sockaddr *addr, ClientHandler *accept_connection(Worker *worker, int fd, sockaddr *addr,
int addrlen, const UpstreamAddr *faddr); int addrlen, const UpstreamAddr *faddr);
// Check peer's certificate against first downstream address in // Check peer's certificate against given |address| and |host|.
// Config::downstream_addrs. We only consider first downstream since int check_cert(SSL *ssl, const Address *addr, const StringRef &host);
// we use this function for HTTP/2 downstream link only.
int check_cert(SSL *ssl, const DownstreamAddr *addr); int check_cert(SSL *ssl, const DownstreamAddr *addr);
// Retrieves DNS and IP address in subjectAltNames and commonName from // Retrieves DNS and IP address in subjectAltNames and commonName from

View File

@ -68,6 +68,7 @@ std::random_device rd;
} // namespace } // namespace
Worker::Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx, Worker::Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx,
SSL_CTX *tls_session_cache_memcached_ssl_ctx,
ssl::CertLookupTree *cert_tree, ssl::CertLookupTree *cert_tree,
const std::shared_ptr<TicketKeys> &ticket_keys) const std::shared_ptr<TicketKeys> &ticket_keys)
: randgen_(rd()), : randgen_(rd()),
@ -92,7 +93,9 @@ Worker::Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx,
if (session_cacheconf.memcached.host) { if (session_cacheconf.memcached.host) {
session_cache_memcached_dispatcher_ = make_unique<MemcachedDispatcher>( session_cache_memcached_dispatcher_ = make_unique<MemcachedDispatcher>(
&session_cacheconf.memcached.addr, loop); &session_cacheconf.memcached.addr, loop,
tls_session_cache_memcached_ssl_ctx,
session_cacheconf.memcached.host.get(), &mcpool_);
} }
auto &downstreamconf = get_config()->conn.downstream; auto &downstreamconf = get_config()->conn.downstream;

View File

@ -112,6 +112,7 @@ struct SessionCacheEntry {
class Worker { class Worker {
public: public:
Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx, Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx,
SSL_CTX *tls_session_cache_memcached_ssl_ctx,
ssl::CertLookupTree *cert_tree, ssl::CertLookupTree *cert_tree,
const std::shared_ptr<TicketKeys> &ticket_keys); const std::shared_ptr<TicketKeys> &ticket_keys);
~Worker(); ~Worker();

View File

@ -420,13 +420,24 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) {
#endif // HAVE_NEVERBLEED #endif // HAVE_NEVERBLEED
MemchunkPool mcpool;
ev_timer renew_ticket_key_timer; ev_timer renew_ticket_key_timer;
if (!upstreamconf.no_tls) { if (!upstreamconf.no_tls) {
auto &ticketconf = get_config()->tls.ticket; auto &ticketconf = get_config()->tls.ticket;
auto &memcachedconf = ticketconf.memcached;
if (ticketconf.memcached.host) { if (ticketconf.memcached.host) {
SSL_CTX *ssl_ctx = nullptr;
if (memcachedconf.tls) {
ssl_ctx = conn_handler.create_tls_ticket_key_memcached_ssl_ctx();
}
conn_handler.set_tls_ticket_key_memcached_dispatcher( conn_handler.set_tls_ticket_key_memcached_dispatcher(
make_unique<MemcachedDispatcher>(&ticketconf.memcached.addr, loop)); make_unique<MemcachedDispatcher>(
&ticketconf.memcached.addr, loop, ssl_ctx,
StringRef(memcachedconf.host.get()), &mcpool));
ev_timer_init(&renew_ticket_key_timer, memcached_get_ticket_key_cb, 0., ev_timer_init(&renew_ticket_key_timer, memcached_get_ticket_key_cb, 0.,
0.); 0.);

View File

@ -402,6 +402,13 @@ public:
static StringRef from_lit(const CharT(&s)[N]) { static StringRef from_lit(const CharT(&s)[N]) {
return StringRef(s, N - 1); 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 begin() const { return base; };
const_iterator cbegin() const { return base; }; const_iterator cbegin() const { return base; };