nghttpx: Add encryption support for TLS ticket key retrieval

This commit is contained in:
Tatsuhiro Tsujikawa 2016-02-13 18:17:11 +09:00
parent 3297a303bf
commit 3a41e4dd1a
7 changed files with 115 additions and 13 deletions

View File

@ -117,7 +117,10 @@ OPTIONS = [
"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-cert-file",
"tls-session-cache-memcached-private-key-file" "tls-session-cache-memcached-private-key-file",
"tls-ticket-key-memcached-tls",
"tls-ticket-key-memcached-cert-file",
"tls-ticket-key-memcached-private-key-file"
] ]
LOGVARS = [ LOGVARS = [

View File

@ -1520,16 +1520,16 @@ 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-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 +1550,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.
@ -2414,6 +2423,11 @@ int main(int argc, char **argv) {
&flag, 109}, &flag, 109},
{SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE, {SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE,
required_argument, &flag, 110}, 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},
{nullptr, 0, nullptr, 0}}; {nullptr, 0, nullptr, 0}};
int option_index = 0; int option_index = 0;
@ -2886,6 +2900,20 @@ int main(int argc, char **argv) {
cmdcfgs.emplace_back( cmdcfgs.emplace_back(
SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE, optarg); SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE, optarg);
break; 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;
default: default:
break; break;
} }

View File

@ -764,9 +764,12 @@ enum {
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_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,
@ -1328,6 +1331,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;
@ -1363,6 +1369,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;
@ -1429,6 +1440,16 @@ int option_lookup_token(const char *name, size_t namelen) {
break; break;
} }
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 44: case 44:
switch (name[43]) { switch (name[43]) {
case 'e': case 'e':
@ -2267,6 +2288,18 @@ int parse_config(const char *opt, const char *optarg,
case SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE: case SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE:
mod_config()->tls.session_cache.memcached.private_key_file = optarg; 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; return 0;
case SHRPX_OPTID_CONF: case SHRPX_OPTID_CONF:
LOG(WARN) << "conf: ignored"; LOG(WARN) << "conf: ignored";

View File

@ -215,6 +215,12 @@ constexpr char SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE[] =
"tls-session-cache-memcached-cert-file"; "tls-session-cache-memcached-cert-file";
constexpr char SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE[] = constexpr char SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE[] =
"tls-session-cache-memcached-private-key-file"; "tls-session-cache-memcached-private-key-file";
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 size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
@ -341,6 +347,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.
@ -348,6 +357,7 @@ 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;
bool tls;
} memcached; } memcached;
std::vector<std::string> files; std::vector<std::string> files;
const EVP_CIPHER *cipher; const EVP_CIPHER *cipher;

View File

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

@ -420,14 +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>(
nullptr, "", nullptr)); &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.);