2 * Copyright (c) 2015, Facebook, Inc.
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.
12 #include <folly/io/async/SSLContext.h>
13 #include <folly/io/async/EventBase.h>
17 #ifndef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
18 class TLSTicketKeyManager {};
22 * The TLSTicketKeyManager handles TLS ticket key encryption and decryption in
23 * a way that facilitates sharing the ticket keys across a range of servers.
24 * Hash chaining is employed to achieve frequent key rotation with minimal
25 * configuration change. The scheme is as follows:
27 * The manager is supplied with three lists of seeds (old, current and new).
28 * The config should be updated with new seeds periodically (e.g., daily).
29 * 3 config changes are recommended to achieve the smoothest seed rotation
31 * 1. Introduce new seed in the push prior to rotation
33 * 3. Remove old seeds in the push following rotation
35 * Multiple seeds are supported but only a single seed is required.
37 * Generating encryption keys from the seed works as follows. For a given
38 * seed, hash forward N times where N is currently the constant 1.
39 * This is the base key. The name of the base key is the first 4
40 * bytes of hash(hash(seed), N). This is copied into the first 4 bytes of the
41 * TLS ticket key name field.
43 * For each new ticket encryption, the manager generates a random 12 byte salt.
44 * Hash the salt and the base key together to form the encryption key for
45 * that ticket. The salt is included in the ticket's 'key name' field so it
46 * can be used to derive the decryption key. The salt is copied into the second
47 * 8 bytes of the TLS ticket key name field.
49 * A key is valid for decryption for the lifetime of the instance.
50 * Sessions will be valid for less time than that, which results in an extra
51 * symmetric decryption to discover the session is expired.
53 * A TLSTicketKeyManager should be used in only one thread, and should have
54 * a 1:1 relationship with the SSLContext provided.
57 class TLSTicketKeyManager : private boost::noncopyable {
60 explicit TLSTicketKeyManager(folly::SSLContext* ctx,
63 virtual ~TLSTicketKeyManager();
66 * SSL callback to set up encryption/decryption context for a TLS Ticket Key.
68 * This will be supplied to the SSL library via
69 * SSL_CTX_set_tlsext_ticket_key_cb.
71 static int callback(SSL* ssl, unsigned char* keyName,
73 EVP_CIPHER_CTX* cipherCtx,
74 HMAC_CTX* hmacCtx, int encrypt);
77 * Initialize the manager with three sets of seeds. There must be at least
78 * one current seed, or the manager will revert to the default SSL behavior.
80 * @param oldSeeds Seeds previously used which can still decrypt.
81 * @param currentSeeds Seeds to use for new ticket encryptions.
82 * @param newSeeds Seeds which will be used soon, can be used to decrypt
83 * in case some servers in the cluster have already rotated.
85 bool setTLSTicketKeySeeds(const std::vector<std::string>& oldSeeds,
86 const std::vector<std::string>& currentSeeds,
87 const std::vector<std::string>& newSeeds);
90 enum TLSTicketSeedType {
96 /* The seeds supplied by the configuration */
97 struct TLSTicketSeed {
99 TLSTicketSeedType type_;
100 unsigned char seedName_[SHA256_DIGEST_LENGTH];
103 struct TLSTicketKeySource {
105 std::string keyName_;
106 TLSTicketSeedType type_;
107 unsigned char keySource_[SHA256_DIGEST_LENGTH];
111 * Method to setup encryption/decryption context for a TLS Ticket Key
113 * OpenSSL documentation is thin on the return value semantics.
115 * For encrypt=1, return < 0 on error, >= 0 for successfully initialized
116 * For encrypt=0, return < 0 on error, 0 on key not found
117 * 1 on key found, 2 renew_ticket
119 * renew_ticket means a new ticket will be issued. We could return this value
120 * when receiving a ticket encrypted with a key derived from an OLD seed.
121 * However, session_timeout seconds after deploying with a seed
122 * rotated from CURRENT -> OLD, there will be no valid tickets outstanding
123 * encrypted with the old key. This grace period means no unnecessary
124 * handshakes will be performed. If the seed is believed compromised, it
125 * should NOT be configured as an OLD seed.
127 int processTicket(SSL* ssl, unsigned char* keyName,
129 EVP_CIPHER_CTX* cipherCtx,
130 HMAC_CTX* hmacCtx, int encrypt);
132 // Creates the name for the nth key generated from seed
133 std::string makeKeyName(TLSTicketSeed* seed, uint32_t n,
134 unsigned char* nameBuf);
137 * Creates the key hashCount hashes from the given seed and inserts it in
138 * ticketKeys. A naked pointer to the key is returned for additional
139 * processing if needed.
141 TLSTicketKeySource* insertNewKey(TLSTicketSeed* seed, uint32_t hashCount,
142 TLSTicketKeySource* prevKeySource);
145 * hashes input N times placing result in output, which must be at least
146 * SHA256_DIGEST_LENGTH long.
148 void hashNth(const unsigned char* input, size_t input_len,
149 unsigned char* output, uint32_t n);
152 * Adds the given seed to the manager
154 TLSTicketSeed* insertSeed(const std::string& seedInput,
155 TLSTicketSeedType type);
158 * Locate a key for encrypting a new ticket
160 TLSTicketKeySource* findEncryptionKey();
163 * Locate a key for decrypting a ticket with the given keyName
165 TLSTicketKeySource* findDecryptionKey(unsigned char* keyName);
168 * Derive a unique key from the parent key and the salt via hashing
170 void makeUniqueKeys(unsigned char* parentKey, size_t keyLen,
171 unsigned char* salt, unsigned char* output);
174 * For standalone decryption utility
176 friend int decrypt_fb_ticket(folly::TLSTicketKeyManager* manager,
177 const std::string& testTicket,
178 SSL_SESSION **psess);
180 typedef std::vector<std::unique_ptr<TLSTicketSeed>> TLSTicketSeedList;
181 typedef std::map<std::string, std::unique_ptr<TLSTicketKeySource> >
183 typedef std::vector<TLSTicketKeySource *> TLSActiveKeyList;
185 TLSTicketSeedList ticketSeeds_;
186 // All key sources that can be used for decryption
187 TLSTicketKeyMap ticketKeys_;
188 // Key sources that can be used for encryption
189 TLSActiveKeyList activeKeys_;
191 folly::SSLContext* ctx_;
193 SSLStats* stats_{nullptr};
195 static int32_t sExDataIndex_;