21 #include <openssl/aes.h> 22 #include <openssl/rand.h> 23 #include <openssl/ssl.h> 28 #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB 33 const int kTLSTicketKeyNameLen = 4;
34 const int kTLSTicketKeySaltLen = 12;
42 int32_t TLSTicketKeyManager::sExDataIndex_ = -1;
44 TLSTicketKeyManager::TLSTicketKeyManager(
47 :
ctx_(ctx), stats_(stats) {
49 SSL_CTX_set_ex_data(
ctx_->getSSLCtx(), sExDataIndex_,
this);
52 TLSTicketKeyManager::~TLSTicketKeyManager() {
56 TLSTicketKeyManager::callback(SSL* ssl,
unsigned char* keyName,
58 EVP_CIPHER_CTX* cipherCtx,
59 HMAC_CTX* hmacCtx,
int encrypt) {
60 TLSTicketKeyManager* manager =
nullptr;
61 SSL_CTX* ctx = SSL_get_SSL_CTX(ssl);
62 manager = (TLSTicketKeyManager *)SSL_CTX_get_ex_data(ctx, sExDataIndex_);
64 if (manager ==
nullptr) {
65 LOG(FATAL) <<
"Null TLSTicketKeyManager in callback" ;
67 return manager->processTicket(ssl, keyName, iv, cipherCtx, hmacCtx, encrypt);
71 TLSTicketKeyManager::processTicket(SSL*,
unsigned char* keyName,
73 EVP_CIPHER_CTX* cipherCtx,
74 HMAC_CTX* hmacCtx,
int encrypt) {
75 uint8_t salt[kTLSTicketKeySaltLen];
80 TLSTicketKeySource* key =
nullptr;
84 key = findEncryptionKey();
87 VLOG(2) <<
"No TLS ticket key found";
90 VLOG(4) <<
"Encrypting new ticket with key name=" <<
94 if (RAND_bytes(salt, (
int)
sizeof(salt)) != 1 &&
95 ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_RAND) {
98 memcpy(keyName, key->keyName_.data(), kTLSTicketKeyNameLen);
99 memcpy(keyName + kTLSTicketKeyNameLen, salt, kTLSTicketKeySaltLen);
102 makeUniqueKeys(key->keySource_,
sizeof(key->keySource_), salt, output);
106 aesKey = output + SHA256_DIGEST_LENGTH / 2;
109 if (RAND_bytes(iv, AES_BLOCK_SIZE) != 1 &&
110 ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_RAND) {
113 HMAC_Init_ex(hmacCtx, hmacKey, SHA256_DIGEST_LENGTH / 2,
114 EVP_sha256(),
nullptr);
115 EVP_EncryptInit_ex(cipherCtx, EVP_aes_128_cbc(),
nullptr, aesKey, iv);
119 key = findDecryptionKey(keyName);
120 if (key ==
nullptr) {
123 string skeyName((
char *)keyName, kTLSTicketKeyNameLen);
124 VLOG(4) <<
"Can't find ticket key with name=" <<
130 VLOG(4) <<
"Decrypting ticket with key name=" <<
134 saltptr = keyName + kTLSTicketKeyNameLen;
135 makeUniqueKeys(key->keySource_,
sizeof(key->keySource_), saltptr, output);
137 aesKey = output + SHA256_DIGEST_LENGTH / 2;
140 HMAC_Init_ex(hmacCtx, hmacKey, SHA256_DIGEST_LENGTH / 2,
141 EVP_sha256(),
nullptr);
142 EVP_DecryptInit_ex(cipherCtx, EVP_aes_128_cbc(),
nullptr, aesKey, iv);
150 stats_->recordTLSTicket(encrypt, result);
157 TLSTicketKeyManager::setTLSTicketKeySeeds(
158 const std::vector<std::string>& oldSeeds,
159 const std::vector<std::string>& currentSeeds,
160 const std::vector<std::string>& newSeeds) {
162 recordTlsTicketRotation(oldSeeds, currentSeeds, newSeeds);
168 ticketSeeds_.clear();
169 const std::vector<string> *seedList = &oldSeeds;
171 TLSTicketSeedType
type = (TLSTicketSeedType)
i;
172 if (type == SEED_CURRENT) {
173 seedList = ¤tSeeds;
174 }
else if (type == SEED_NEW) {
175 seedList = &newSeeds;
178 for (
const auto& seedInput: *seedList) {
179 TLSTicketSeed*
seed = insertSeed(seedInput, type);
180 if (seed ==
nullptr) {
184 insertNewKey(seed, 1,
nullptr);
188 VLOG(2) <<
"One or more seeds failed to decode";
191 if (ticketKeys_.size() == 0 || activeKeys_.size() == 0) {
192 LOG(WARNING) <<
"No keys configured, falling back to default";
193 SSL_CTX_set_tlsext_ticket_key_cb(
ctx_->getSSLCtx(),
nullptr);
196 SSL_CTX_set_tlsext_ticket_key_cb(
ctx_->getSSLCtx(),
197 TLSTicketKeyManager::callback);
203 TLSTicketKeyManager::getTLSTicketKeySeeds(
204 std::vector<std::string>& oldSeeds,
205 std::vector<std::string>& currentSeeds,
206 std::vector<std::string>& newSeeds)
const {
208 currentSeeds.clear();
211 for (
const auto&
seed : ticketSeeds_) {
217 if (
seed->type_ == TLSTicketSeedType::SEED_OLD) {
218 oldSeeds.push_back(hexSeed);
219 }
else if(
seed->type_ == TLSTicketSeedType::SEED_CURRENT) {
220 currentSeeds.push_back(hexSeed);
222 newSeeds.push_back(hexSeed);
228 void TLSTicketKeyManager::recordTlsTicketRotation(
229 const std::vector<std::string>& oldSeeds,
230 const std::vector<std::string>& currentSeeds,
231 const std::vector<std::string>& newSeeds) {
233 TLSTicketKeySeeds
next{oldSeeds, currentSeeds, newSeeds};
235 getTLSTicketKeySeeds(
236 current.oldSeeds, current.currentSeeds, current.newSeeds);
237 stats_->recordTLSTicketRotation(current.isValidRotation(
next));
242 TLSTicketKeyManager::makeKeyName(TLSTicketSeed*
seed,
uint32_t n,
243 unsigned char* nameBuf) {
247 SHA256_Update(&ctx, seed->seedName_,
sizeof(seed->seedName_));
248 SHA256_Update(&ctx, &n,
sizeof(n));
249 SHA256_Final(nameBuf, &ctx);
250 return string((
char *)nameBuf, kTLSTicketKeyNameLen);
253 TLSTicketKeyManager::TLSTicketKeySource*
254 TLSTicketKeyManager::insertNewKey(TLSTicketSeed* seed,
uint32_t hashCount,
255 TLSTicketKeySource* prevKey) {
256 unsigned char nameBuf[SHA256_DIGEST_LENGTH];
257 std::unique_ptr<TLSTicketKeySource> newKey(
new TLSTicketKeySource);
261 if (prevKey !=
nullptr) {
262 hashNth(prevKey->keySource_,
sizeof(prevKey->keySource_),
263 newKey->keySource_, 1);
266 hashNth((
unsigned char *)seed->seed_.data(), seed->seed_.length(),
267 newKey->keySource_, hashCount);
270 newKey->hashCount_ = hashCount;
271 newKey->keyName_ = makeKeyName(seed, hashCount, nameBuf);
272 newKey->type_ = seed->type_;
273 auto newKeyName = newKey->keyName_;
274 auto it = ticketKeys_.insert(std::make_pair(
std::move(newKeyName),
277 auto key = it.first->second.get();
278 if (key->type_ == SEED_CURRENT) {
279 activeKeys_.push_back(key);
281 VLOG(4) <<
"Adding key for " << hashCount <<
" type=" <<
288 TLSTicketKeyManager::hashNth(
const unsigned char* input,
size_t input_len,
289 unsigned char* output,
uint32_t n) {
292 SHA256(input, input_len, output);
294 input_len = SHA256_DIGEST_LENGTH;
298 TLSTicketKeyManager::TLSTicketSeed *
299 TLSTicketKeyManager::insertSeed(
const string& seedInput,
300 TLSTicketSeedType type) {
301 TLSTicketSeed* seed =
nullptr;
304 if (!folly::unhexlify<string, string>(seedInput, seedOutput)) {
305 LOG(WARNING) <<
"Failed to decode seed type=" << (
uint32_t)type <<
306 " seed=" << seedInput;
310 seed =
new TLSTicketSeed();
311 seed->seed_ = seedOutput;
313 SHA256((
unsigned char *)seedOutput.data(), seedOutput.length(),
315 ticketSeeds_.push_back(std::unique_ptr<TLSTicketSeed>(seed));
320 TLSTicketKeyManager::TLSTicketKeySource *
321 TLSTicketKeyManager::findEncryptionKey() {
322 TLSTicketKeySource* result =
nullptr;
327 size_t numKeys = activeKeys_.size();
330 result = activeKeys_[
i];
335 TLSTicketKeyManager::TLSTicketKeySource *
336 TLSTicketKeyManager::findDecryptionKey(
unsigned char* keyName) {
337 string name((
char *)keyName, kTLSTicketKeyNameLen);
338 TLSTicketKeySource* key =
nullptr;
339 TLSTicketKeyMap::iterator mapit = ticketKeys_.find(
name);
340 if (mapit != ticketKeys_.end()) {
341 key = mapit->second.get();
347 TLSTicketKeyManager::makeUniqueKeys(
unsigned char* parentKey,
350 unsigned char* output) {
353 SHA256_Init(&hash_ctx);
354 SHA256_Update(&hash_ctx, parentKey, keyLen);
355 SHA256_Update(&hash_ctx, salt, kTLSTicketKeySaltLen);
356 SHA256_Final(output, &hash_ctx);
constexpr detail::Map< Move > move
static void getSSLCtxExIndex(int *pindex)
std::shared_ptr< FizzServerContext > ctx_
static std::string hexlify(const std::string &binary)
bool hexlify(const InputString &input, OutputString &output, bool append_output)