removing non-existing file from the build
[folly.git] / folly / wangle / ssl / TLSTicketKeyManager.cpp
1 /*
2  *  Copyright (c) 2015, Facebook, Inc.
3  *  All rights reserved.
4  *
5  *  This source code is licensed under the BSD-style license found in the
6  *  LICENSE file in the root directory of this source tree. An additional grant
7  *  of patent rights can be found in the PATENTS file in the same directory.
8  *
9  */
10 #include <folly/wangle/ssl/TLSTicketKeyManager.h>
11
12 #include <folly/wangle/ssl/SSLStats.h>
13 #include <folly/wangle/ssl/SSLUtil.h>
14
15 #include <folly/String.h>
16 #include <openssl/aes.h>
17 #include <openssl/rand.h>
18 #include <openssl/ssl.h>
19 #include <folly/io/async/AsyncTimeout.h>
20
21 #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
22 using std::string;
23
24 namespace {
25
26 const int kTLSTicketKeyNameLen = 4;
27 const int kTLSTicketKeySaltLen = 12;
28
29 }
30
31 namespace folly {
32
33
34 // TLSTicketKeyManager Implementation
35 int32_t TLSTicketKeyManager::sExDataIndex_ = -1;
36
37 TLSTicketKeyManager::TLSTicketKeyManager(SSLContext* ctx, SSLStats* stats)
38   : ctx_(ctx),
39     randState_(0),
40     stats_(stats) {
41   SSLUtil::getSSLCtxExIndex(&sExDataIndex_);
42   SSL_CTX_set_ex_data(ctx_->getSSLCtx(), sExDataIndex_, this);
43 }
44
45 TLSTicketKeyManager::~TLSTicketKeyManager() {
46 }
47
48 int
49 TLSTicketKeyManager::callback(SSL* ssl, unsigned char* keyName,
50                               unsigned char* iv,
51                               EVP_CIPHER_CTX* cipherCtx,
52                               HMAC_CTX* hmacCtx, int encrypt) {
53   TLSTicketKeyManager* manager = nullptr;
54   SSL_CTX* ctx = SSL_get_SSL_CTX(ssl);
55   manager = (TLSTicketKeyManager *)SSL_CTX_get_ex_data(ctx, sExDataIndex_);
56
57   if (manager == nullptr) {
58     LOG(FATAL) << "Null TLSTicketKeyManager in callback" ;
59     return -1;
60   }
61   return manager->processTicket(ssl, keyName, iv, cipherCtx, hmacCtx, encrypt);
62 }
63
64 int
65 TLSTicketKeyManager::processTicket(SSL* ssl, unsigned char* keyName,
66                                    unsigned char* iv,
67                                    EVP_CIPHER_CTX* cipherCtx,
68                                    HMAC_CTX* hmacCtx, int encrypt) {
69   uint8_t salt[kTLSTicketKeySaltLen];
70   uint8_t* saltptr = nullptr;
71   uint8_t output[SHA256_DIGEST_LENGTH];
72   uint8_t* hmacKey = nullptr;
73   uint8_t* aesKey = nullptr;
74   TLSTicketKeySource* key = nullptr;
75   int result = 0;
76
77   if (encrypt) {
78     key = findEncryptionKey();
79     if (key == nullptr) {
80       // no keys available to encrypt
81       VLOG(2) << "No TLS ticket key found";
82       return -1;
83     }
84     VLOG(4) << "Encrypting new ticket with key name=" <<
85       SSLUtil::hexlify(key->keyName_);
86
87     // Get a random salt and write out key name
88     RAND_pseudo_bytes(salt, (int)sizeof(salt));
89     memcpy(keyName, key->keyName_.data(), kTLSTicketKeyNameLen);
90     memcpy(keyName + kTLSTicketKeyNameLen, salt, kTLSTicketKeySaltLen);
91
92     // Create the unique keys by hashing with the salt
93     makeUniqueKeys(key->keySource_, sizeof(key->keySource_), salt, output);
94     // This relies on the fact that SHA256 has 32 bytes of output
95     // and that AES-128 keys are 16 bytes
96     hmacKey = output;
97     aesKey = output + SHA256_DIGEST_LENGTH / 2;
98
99     // Initialize iv and cipher/mac CTX
100     RAND_pseudo_bytes(iv, AES_BLOCK_SIZE);
101     HMAC_Init_ex(hmacCtx, hmacKey, SHA256_DIGEST_LENGTH / 2,
102                  EVP_sha256(), nullptr);
103     EVP_EncryptInit_ex(cipherCtx, EVP_aes_128_cbc(), nullptr, aesKey, iv);
104
105     result = 1;
106   } else {
107     key = findDecryptionKey(keyName);
108     if (key == nullptr) {
109       // no ticket found for decryption - will issue a new ticket
110       if (VLOG_IS_ON(4)) {
111         string skeyName((char *)keyName, kTLSTicketKeyNameLen);
112         VLOG(4) << "Can't find ticket key with name=" <<
113           SSLUtil::hexlify(skeyName)<< ", will generate new ticket";
114       }
115
116       result = 0;
117     } else {
118       VLOG(4) << "Decrypting ticket with key name=" <<
119         SSLUtil::hexlify(key->keyName_);
120
121       // Reconstruct the unique key via the salt
122       saltptr = keyName + kTLSTicketKeyNameLen;
123       makeUniqueKeys(key->keySource_, sizeof(key->keySource_), saltptr, output);
124       hmacKey = output;
125       aesKey = output + SHA256_DIGEST_LENGTH / 2;
126
127       // Initialize cipher/mac CTX
128       HMAC_Init_ex(hmacCtx, hmacKey, SHA256_DIGEST_LENGTH / 2,
129                    EVP_sha256(), nullptr);
130       EVP_DecryptInit_ex(cipherCtx, EVP_aes_128_cbc(), nullptr, aesKey, iv);
131
132       result = 1;
133     }
134   }
135   // result records whether a ticket key was found to decrypt this ticket,
136   // not wether the session was re-used.
137   if (stats_) {
138     stats_->recordTLSTicket(encrypt, result);
139   }
140
141   return result;
142 }
143
144 bool
145 TLSTicketKeyManager::setTLSTicketKeySeeds(
146     const std::vector<std::string>& oldSeeds,
147     const std::vector<std::string>& currentSeeds,
148     const std::vector<std::string>& newSeeds) {
149
150   bool result = true;
151
152   activeKeys_.clear();
153   ticketKeys_.clear();
154   ticketSeeds_.clear();
155   const std::vector<string> *seedList = &oldSeeds;
156   for (uint32_t i = 0; i < 3; i++) {
157     TLSTicketSeedType type = (TLSTicketSeedType)i;
158     if (type == SEED_CURRENT) {
159       seedList = &currentSeeds;
160     } else if (type == SEED_NEW) {
161       seedList = &newSeeds;
162     }
163
164     for (const auto& seedInput: *seedList) {
165       TLSTicketSeed* seed = insertSeed(seedInput, type);
166       if (seed == nullptr) {
167         result = false;
168         continue;
169       }
170       insertNewKey(seed, 1, nullptr);
171     }
172   }
173   if (!result) {
174     VLOG(2) << "One or more seeds failed to decode";
175   }
176
177   if (ticketKeys_.size() == 0 || activeKeys_.size() == 0) {
178     LOG(WARNING) << "No keys configured, falling back to default";
179     SSL_CTX_set_tlsext_ticket_key_cb(ctx_->getSSLCtx(), nullptr);
180     return false;
181   }
182   SSL_CTX_set_tlsext_ticket_key_cb(ctx_->getSSLCtx(),
183                                    TLSTicketKeyManager::callback);
184
185   return true;
186 }
187
188 string
189 TLSTicketKeyManager::makeKeyName(TLSTicketSeed* seed, uint32_t n,
190                                  unsigned char* nameBuf) {
191   SHA256_CTX ctx;
192
193   SHA256_Init(&ctx);
194   SHA256_Update(&ctx, seed->seedName_, sizeof(seed->seedName_));
195   SHA256_Update(&ctx, &n, sizeof(n));
196   SHA256_Final(nameBuf, &ctx);
197   return string((char *)nameBuf, kTLSTicketKeyNameLen);
198 }
199
200 TLSTicketKeyManager::TLSTicketKeySource*
201 TLSTicketKeyManager::insertNewKey(TLSTicketSeed* seed, uint32_t hashCount,
202                                   TLSTicketKeySource* prevKey) {
203   unsigned char nameBuf[SHA256_DIGEST_LENGTH];
204   std::unique_ptr<TLSTicketKeySource> newKey(new TLSTicketKeySource);
205
206   // This function supports hash chaining but it is not currently used.
207
208   if (prevKey != nullptr) {
209     hashNth(prevKey->keySource_, sizeof(prevKey->keySource_),
210             newKey->keySource_, 1);
211   } else {
212     // can't go backwards or the current is missing, start from the beginning
213     hashNth((unsigned char *)seed->seed_.data(), seed->seed_.length(),
214             newKey->keySource_, hashCount);
215   }
216
217   newKey->hashCount_ = hashCount;
218   newKey->keyName_ = makeKeyName(seed, hashCount, nameBuf);
219   newKey->type_ = seed->type_;
220   auto it = ticketKeys_.insert(std::make_pair(newKey->keyName_,
221         std::move(newKey)));
222
223   auto key = it.first->second.get();
224   if (key->type_ == SEED_CURRENT) {
225     activeKeys_.push_back(key);
226   }
227   VLOG(4) << "Adding key for " << hashCount << " type=" <<
228     (uint32_t)key->type_ << " Name=" << SSLUtil::hexlify(key->keyName_);
229
230   return key;
231 }
232
233 void
234 TLSTicketKeyManager::hashNth(const unsigned char* input, size_t input_len,
235                              unsigned char* output, uint32_t n) {
236   assert(n > 0);
237   for (uint32_t i = 0; i < n; i++) {
238     SHA256(input, input_len, output);
239     input = output;
240     input_len = SHA256_DIGEST_LENGTH;
241   }
242 }
243
244 TLSTicketKeyManager::TLSTicketSeed *
245 TLSTicketKeyManager::insertSeed(const string& seedInput,
246                                 TLSTicketSeedType type) {
247   TLSTicketSeed* seed = nullptr;
248   string seedOutput;
249
250   if (!folly::unhexlify<string, string>(seedInput, seedOutput)) {
251     LOG(WARNING) << "Failed to decode seed type=" << (uint32_t)type <<
252       " seed=" << seedInput;
253     return seed;
254   }
255
256   seed = new TLSTicketSeed();
257   seed->seed_ = seedOutput;
258   seed->type_ = type;
259   SHA256((unsigned char *)seedOutput.data(), seedOutput.length(),
260          seed->seedName_);
261   ticketSeeds_.push_back(std::unique_ptr<TLSTicketSeed>(seed));
262
263   return seed;
264 }
265
266 TLSTicketKeyManager::TLSTicketKeySource *
267 TLSTicketKeyManager::findEncryptionKey() {
268   TLSTicketKeySource* result = nullptr;
269   // call to rand here is a bit hokey since it's not cryptographically
270   // random, and is predictably seeded with 0.  However, activeKeys_
271   // is probably not going to have very many keys in it, and most
272   // likely only 1.
273   size_t numKeys = activeKeys_.size();
274   if (numKeys > 0) {
275     result = activeKeys_[rand_r(&randState_) % numKeys];
276   }
277   return result;
278 }
279
280 TLSTicketKeyManager::TLSTicketKeySource *
281 TLSTicketKeyManager::findDecryptionKey(unsigned char* keyName) {
282   string name((char *)keyName, kTLSTicketKeyNameLen);
283   TLSTicketKeySource* key = nullptr;
284   TLSTicketKeyMap::iterator mapit = ticketKeys_.find(name);
285   if (mapit != ticketKeys_.end()) {
286     key = mapit->second.get();
287   }
288   return key;
289 }
290
291 void
292 TLSTicketKeyManager::makeUniqueKeys(unsigned char* parentKey,
293                                     size_t keyLen,
294                                     unsigned char* salt,
295                                     unsigned char* output) {
296   SHA256_CTX hash_ctx;
297
298   SHA256_Init(&hash_ctx);
299   SHA256_Update(&hash_ctx, parentKey, keyLen);
300   SHA256_Update(&hash_ctx, salt, kTLSTicketKeySaltLen);
301   SHA256_Final(output, &hash_ctx);
302 }
303
304 } // namespace
305 #endif