Skip to content

Commit f473934

Browse files
jmswenfacebook-github-bot
authored andcommitted
Improve TLS ticket key generation
Summary: Improve the way AsyncMcServer generates TLS ticket keys. Reviewed By: glamtechie Differential Revision: D4565521 fbshipit-source-id: 7391c76d2af64bf583b38721c7a38f406f66a469
1 parent 1c427a0 commit f473934

9 files changed

Lines changed: 134 additions & 28 deletions

‎mcrouter/Server-inl.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ bool runServer(
9494
} else {
9595
opts.ports = standaloneOpts.ports;
9696
opts.sslPorts = standaloneOpts.ssl_ports;
97+
opts.tlsTicketKeySeedPath = standaloneOpts.tls_ticket_key_seed_path;
9798
opts.pemCertPath = mcrouterOpts.pem_cert_path;
9899
opts.pemKeyPath = mcrouterOpts.pem_key_path;
99100
opts.pemCaPath = mcrouterOpts.pem_ca_path;

‎mcrouter/lib/network/AsyncMcServer.cpp‎

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,17 @@
1818
#include <cstdio>
1919
#include <mutex>
2020
#include <thread>
21+
#include <vector>
2122

2223
#include <folly/Memory.h>
24+
#include <folly/SharedMutex.h>
2325
#include <folly/String.h>
2426
#include <folly/io/async/AsyncServerSocket.h>
2527
#include <folly/io/async/EventBase.h>
2628
#include <folly/io/async/SSLContext.h>
2729
#include <folly/io/async/ScopedEventBaseThread.h>
30+
#include <wangle/ssl/TLSCredProcessor.h>
31+
#include <wangle/ssl/TLSTicketKeySeeds.h>
2832

2933
#include "mcrouter/lib/network/AsyncMcServerWorker.h"
3034
#include "mcrouter/lib/network/ThreadLocalSSLContextProvider.h"
@@ -168,9 +172,14 @@ class McServerThread {
168172
int fd,
169173
const folly::SocketAddress& clientAddr) noexcept override final {
170174
if (secure_) {
171-
auto& opts = mcServerThread_->server_.opts_;
172-
auto sslCtx =
173-
getSSLContext(opts.pemCertPath, opts.pemKeyPath, opts.pemCaPath);
175+
const auto& server = mcServerThread_->server_;
176+
auto& opts = server.opts_;
177+
auto sslCtx = getSSLContext(
178+
opts.pemCertPath,
179+
opts.pemKeyPath,
180+
opts.pemCaPath,
181+
server.getTicketKeySeeds());
182+
174183
if (sslCtx) {
175184
sslCtx->setVerificationOption(
176185
folly::SSLContext::SSLVerifyPeerEnum::VERIFY_REQ_CLIENT_CERT);
@@ -346,6 +355,14 @@ AsyncMcServer::AsyncMcServer(Options opts) : opts_(std::move(opts)) {
346355
}
347356
}
348357

358+
if (!opts_.tlsTicketKeySeedPath.empty()) {
359+
if (auto initialSeeds = wangle::TLSCredProcessor::processTLSTickets(
360+
opts_.tlsTicketKeySeedPath)) {
361+
tlsTicketKeySeeds_ = std::move(*initialSeeds);
362+
}
363+
startPollingTicketKeySeeds();
364+
}
365+
349366
if (opts_.numThreads == 0) {
350367
throw std::invalid_argument(folly::sformat(
351368
"Unexpected option: opts_.numThreads={}", opts_.numThreads));
@@ -466,5 +483,27 @@ void AsyncMcServer::join() {
466483
thread->join();
467484
}
468485
}
486+
487+
void AsyncMcServer::setTicketKeySeeds(wangle::TLSTicketKeySeeds seeds) {
488+
folly::SharedMutex::WriteHolder writeGuard(tlsTicketKeySeedsLock_);
489+
tlsTicketKeySeeds_ = std::move(seeds);
490+
}
491+
492+
wangle::TLSTicketKeySeeds AsyncMcServer::getTicketKeySeeds() const {
493+
folly::SharedMutex::ReadHolder readGuard(tlsTicketKeySeedsLock_);
494+
return tlsTicketKeySeeds_;
469495
}
470-
} // facebook::memcache
496+
497+
void AsyncMcServer::startPollingTicketKeySeeds() {
498+
// Caller assumed to have checked opts_.tlsTicketKeySeedPath is non-empty
499+
ticketKeySeedPoller_ = folly::make_unique<wangle::TLSCredProcessor>(
500+
opts_.tlsTicketKeySeedPath, opts_.pemCertPath);
501+
ticketKeySeedPoller_->addTicketCallback(
502+
[this](wangle::TLSTicketKeySeeds updatedSeeds) {
503+
setTicketKeySeeds(std::move(updatedSeeds));
504+
VLOG(0) << "Updated TLSTicketKeySeeds";
505+
});
506+
}
507+
508+
} // memcache
509+
} // facebook

‎mcrouter/lib/network/AsyncMcServer.h‎

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717

1818
#include <sys/socket.h>
1919

20+
#include <folly/SharedMutex.h>
21+
#include <wangle/ssl/TLSTicketKeySeeds.h>
22+
2023
#include "mcrouter/lib/network/AsyncMcServerWorkerOptions.h"
2124
#include "mcrouter/lib/network/CongestionController.h"
2225

@@ -25,6 +28,10 @@ class EventBase;
2528
class ScopedEventBaseThread;
2629
} // folly
2730

31+
namespace wangle {
32+
class TLSCredProcessor;
33+
} // wangle
34+
2835
namespace facebook {
2936
namespace memcache {
3037

@@ -80,6 +87,12 @@ class AsyncMcServer {
8087
std::string pemKeyPath;
8188
std::string pemCaPath;
8289

90+
/**
91+
* Path to JSON file containing old, current, and new seeds used for TLS
92+
* ticket key generation.
93+
*/
94+
std::string tlsTicketKeySeedPath;
95+
8396
/**
8497
* Number of threads to spawn, must be positive.
8598
*/
@@ -168,22 +181,35 @@ class AsyncMcServer {
168181
*/
169182
void join();
170183

184+
/**
185+
* Getter/setter for seeds to be used to generate keys encrypting TLS tickets.
186+
*/
187+
void setTicketKeySeeds(wangle::TLSTicketKeySeeds seeds);
188+
wangle::TLSTicketKeySeeds getTicketKeySeeds() const;
189+
171190
private:
172191
std::unique_ptr<folly::ScopedEventBaseThread> auxiliaryEvbThread_;
173192
Options opts_;
174193
std::vector<std::unique_ptr<McServerThread>> threads_;
175194

195+
std::unique_ptr<wangle::TLSCredProcessor> ticketKeySeedPoller_;
196+
wangle::TLSTicketKeySeeds tlsTicketKeySeeds_;
197+
mutable folly::SharedMutex tlsTicketKeySeedsLock_;
198+
176199
std::atomic<bool> alive_{true};
177200
std::function<void()> onShutdown_;
178201

179202
enum class SignalShutdownState : uint64_t { STARTUP, SHUTDOWN, SPAWNED };
180203
std::atomic<SignalShutdownState> signalShutdownState_{
181204
SignalShutdownState::STARTUP};
182205

206+
void startPollingTicketKeySeeds();
207+
183208
AsyncMcServer(const AsyncMcServer&) = delete;
184209
AsyncMcServer& operator=(const AsyncMcServer&) = delete;
185210

186211
friend class McServerThread;
187212
};
188-
}
189-
} // facebook::memcache
213+
214+
} // memcache
215+
} // facebook

‎mcrouter/lib/network/ThreadLocalSSLContextProvider.cpp‎

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include <folly/io/async/SSLContext.h>
1515
#include <wangle/ssl/TLSTicketKeyManager.h>
16+
#include <wangle/ssl/TLSTicketKeySeeds.h>
1617

1718
#include "mcrouter/lib/fbi/cpp/LogFailure.h"
1819

@@ -155,7 +156,8 @@ std::shared_ptr<SSLContext> handleSSLCertsUpdate(
155156
std::shared_ptr<SSLContext> getSSLContext(
156157
folly::StringPiece pemCertPath,
157158
folly::StringPiece pemKeyPath,
158-
folly::StringPiece pemCaPath) {
159+
folly::StringPiece pemCaPath,
160+
folly::Optional<wangle::TLSTicketKeySeeds> ticketKeySeeds) {
159161
static constexpr std::chrono::minutes kSslReloadInterval{30};
160162
thread_local std::unordered_map<CertPaths, ContextInfo, CertPathsHasher>
161163
localContexts;
@@ -193,20 +195,27 @@ std::shared_ptr<SSLContext> getSSLContext(
193195
SSL_CTX_set_timeout(contextInfo.context->getSSLCtx(), kSessionLifeTime);
194196

195197
#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
196-
auto mgr = folly::make_unique<wangle::TLSTicketKeyManager>(
197-
contextInfo.context.get(), nullptr);
198-
mgr->setTLSTicketKeySeeds({"aaaa"}, {"bbbb"}, {"cccc"});
199-
200-
/* store in the map */
201-
const auto mapKey =
202-
reinterpret_cast<uintptr_t>(contextInfo.context.get());
203-
assert(contextToTicketMgr()->find(mapKey) == contextToTicketMgr()->end());
204-
contextToTicketMgr()->emplace(mapKey, std::move(mgr));
198+
if (ticketKeySeeds.hasValue()) {
199+
auto mgr = folly::make_unique<wangle::TLSTicketKeyManager>(
200+
contextInfo.context.get(), nullptr);
201+
mgr->setTLSTicketKeySeeds(
202+
std::move(ticketKeySeeds->oldSeeds),
203+
std::move(ticketKeySeeds->currentSeeds),
204+
std::move(ticketKeySeeds->newSeeds));
205+
206+
/* store in the map */
207+
const auto mapKey =
208+
reinterpret_cast<uintptr_t>(contextInfo.context.get());
209+
assert(
210+
contextToTicketMgr()->find(mapKey) == contextToTicketMgr()->end());
211+
contextToTicketMgr()->emplace(mapKey, std::move(mgr));
212+
}
205213
#endif
206214
}
207215
}
208216

209217
return contextInfo.context;
210218
}
211-
}
212-
} // facebook::memcache
219+
220+
} // memcache
221+
} // facebook

‎mcrouter/lib/network/ThreadLocalSSLContextProvider.h‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@
99
*/
1010
#pragma once
1111

12+
#include <memory>
13+
14+
#include <folly/Optional.h>
1215
#include <folly/Range.h>
16+
#include <wangle/ssl/TLSTicketKeySeeds.h>
1317

1418
namespace folly {
1519
class SSLContext;
@@ -26,6 +30,8 @@ namespace memcache {
2630
std::shared_ptr<folly::SSLContext> getSSLContext(
2731
folly::StringPiece pemCertPath,
2832
folly::StringPiece pemKeyPath,
29-
folly::StringPiece pemCaPath);
30-
}
31-
} // facebook::memcache
33+
folly::StringPiece pemCaPath,
34+
folly::Optional<wangle::TLSTicketKeySeeds> = folly::none);
35+
36+
} // memcache
37+
} // facebook

‎mcrouter/lib/network/test/AsyncMcClientTestSync.cpp‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -642,8 +642,15 @@ TEST(AsyncMcClient, curruptedUmbrellaReply) {
642642
}
643643

644644
TEST(AsyncMcClient, SslSessionCache) {
645-
auto server =
646-
TestServer::create(true, true, 10, 250, 100, true, 4 /* nThreads */);
645+
auto server = TestServer::create(
646+
true,
647+
true,
648+
10,
649+
250,
650+
100,
651+
true,
652+
4 /* nThreads */,
653+
true /* useTicketKeySeeds */);
647654
auto constexpr nConnAttempts = 10;
648655

649656
for (int i = 0; i < nConnAttempts; i++) {

‎mcrouter/lib/network/test/TestClientServerUtil.cpp‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <folly/fibers/EventBaseLoopController.h>
2121
#include <folly/fibers/FiberManager.h>
2222
#include <folly/io/async/EventBase.h>
23+
#include <wangle/ssl/TLSTicketKeySeeds.h>
2324

2425
#include "mcrouter/lib/IOBufUtil.h"
2526
#include "mcrouter/lib/fbi/cpp/util.h"
@@ -142,8 +143,9 @@ TestServer::TestServer(
142143
int timeoutMs,
143144
size_t maxConns,
144145
bool useDefaultVersion,
145-
size_t numThreads)
146-
: outOfOrder_(outOfOrder) {
146+
size_t numThreads,
147+
bool useTicketKeySeeds)
148+
: outOfOrder_(outOfOrder), useTicketKeySeeds_(useSsl && useTicketKeySeeds) {
147149
opts_.existingSocketFd = sock_.getSocketFd();
148150
opts_.numThreads = numThreads;
149151
opts_.worker.defaultVersionHandler = useDefaultVersion;
@@ -161,6 +163,12 @@ void TestServer::run(std::function<void(AsyncMcServerWorker&)> init) {
161163
LOG(INFO) << "Spawning AsyncMcServer";
162164

163165
server_ = folly::make_unique<AsyncMcServer>(opts_);
166+
if (useTicketKeySeeds_) {
167+
wangle::TLSTicketKeySeeds seeds{
168+
.oldSeeds = {"aaaa"}, .currentSeeds = {"bbbb"}, .newSeeds = {"cccc"},
169+
};
170+
server_->setTicketKeySeeds(std::move(seeds));
171+
}
164172
server_->spawn(
165173
[this, init](size_t, folly::EventBase& evb, AsyncMcServerWorker& worker) {
166174
init(worker);

‎mcrouter/lib/network/test/TestClientServerUtil.h‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,17 @@ class TestServer {
7777
int timeoutMs = 250,
7878
size_t maxConns = 100,
7979
bool useDefaultVersion = false,
80-
size_t numThreads = 1) {
80+
size_t numThreads = 1,
81+
bool useTicketKeySeeds = false) {
8182
std::unique_ptr<TestServer> server(new TestServer(
8283
outOfOrder,
8384
useSsl,
8485
maxInflight,
8586
timeoutMs,
8687
maxConns,
8788
useDefaultVersion,
88-
numThreads));
89+
numThreads,
90+
useTicketKeySeeds));
8991
server->run([& s = *server](AsyncMcServerWorker & worker) {
9092
worker.setOnRequest(
9193
MemcacheRequestHandler<OnRequest>(s.shutdown_, s.outOfOrder_));
@@ -116,6 +118,7 @@ class TestServer {
116118
AsyncMcServer::Options opts_;
117119
std::unique_ptr<AsyncMcServer> server_;
118120
bool outOfOrder_{false};
121+
bool useTicketKeySeeds_{false};
119122
std::atomic<bool> shutdown_{false};
120123
std::atomic<size_t> acceptedConns_{0};
121124

@@ -126,7 +129,8 @@ class TestServer {
126129
int timeoutMs,
127130
size_t maxConns,
128131
bool useDefaultVersion,
129-
size_t numThreads);
132+
size_t numThreads,
133+
bool useTicketKeySeeds);
130134

131135
void run(std::function<void(AsyncMcServerWorker&)> init);
132136
};

‎mcrouter/standalone_options_list.h‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ MCROUTER_OPTION_OTHER(
3939
no_short,
4040
"SSL Port(s) to listen on (comma separated)")
4141

42+
MCROUTER_OPTION_STRING(
43+
tls_ticket_key_seed_path, "",
44+
"tls-ticket-key-seed-path", no_short,
45+
"Path to file containing JSON object for old, current, and new seeds"
46+
" used to generate TLS ticket keys")
47+
4248
MCROUTER_OPTION_INTEGER(
4349
int,
4450
listen_sock_fd,

0 commit comments

Comments
 (0)