nghttpx: Add encryption support for TLS ticket key retrieval
This commit is contained in:
parent
3297a303bf
commit
3a41e4dd1a
|
@ -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 = [
|
||||||
|
|
48
src/shrpx.cc
48
src/shrpx.cc
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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.);
|
||||||
|
|
Loading…
Reference in New Issue