]>
Commit | Line | Data |
---|---|---|
ede152ec RG |
1 | |
2 | #include "config.h" | |
3 | #include "libssl.hh" | |
4 | ||
5 | #ifdef HAVE_LIBSSL | |
6 | ||
7 | #include <atomic> | |
be3183ed RG |
8 | #include <fstream> |
9 | #include <cstring> | |
f0941861 | 10 | #include <mutex> |
ede152ec | 11 | #include <pthread.h> |
be3183ed | 12 | |
ede152ec RG |
13 | #include <openssl/conf.h> |
14 | #include <openssl/err.h> | |
be3183ed | 15 | #include <openssl/ocsp.h> |
ede152ec RG |
16 | #include <openssl/rand.h> |
17 | #include <openssl/ssl.h> | |
18 | ||
0ef9ab19 RG |
19 | #ifdef HAVE_LIBSODIUM |
20 | #include <sodium.h> | |
21 | #endif /* HAVE_LIBSODIUM */ | |
22 | ||
18e4fac1 | 23 | #if (OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2090100fL) |
ede152ec | 24 | /* OpenSSL < 1.1.0 needs support for threading/locking in the calling application. */ |
f0941861 RG |
25 | |
26 | #include "lock.hh" | |
27 | static std::vector<std::mutex> openssllocks; | |
ede152ec RG |
28 | |
29 | extern "C" { | |
30 | static void openssl_pthreads_locking_callback(int mode, int type, const char *file, int line) | |
31 | { | |
32 | if (mode & CRYPTO_LOCK) { | |
f0941861 | 33 | openssllocks.at(type).lock(); |
ede152ec RG |
34 | |
35 | } else { | |
f0941861 | 36 | openssllocks.at(type).unlock(); |
ede152ec RG |
37 | } |
38 | } | |
39 | ||
40 | static unsigned long openssl_pthreads_id_callback() | |
41 | { | |
42 | return (unsigned long)pthread_self(); | |
43 | } | |
44 | } | |
45 | ||
46 | static void openssl_thread_setup() | |
47 | { | |
f0941861 RG |
48 | openssllocks = std::vector<std::mutex>(CRYPTO_num_locks()); |
49 | CRYPTO_set_id_callback(&openssl_pthreads_id_callback); | |
50 | CRYPTO_set_locking_callback(&openssl_pthreads_locking_callback); | |
ede152ec RG |
51 | } |
52 | ||
53 | static void openssl_thread_cleanup() | |
54 | { | |
f0941861 RG |
55 | CRYPTO_set_locking_callback(nullptr); |
56 | openssllocks.clear(); | |
ede152ec RG |
57 | } |
58 | ||
18e4fac1 | 59 | #endif /* (OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2090100fL) */ |
ede152ec | 60 | |
0ef9ab19 RG |
61 | static std::atomic<uint64_t> s_users; |
62 | static int s_ticketsKeyIndex{-1}; | |
f34fdcc5 | 63 | static int s_countersIndex{-1}; |
7f8a5a32 | 64 | static int s_keyLogIndex{-1}; |
0ef9ab19 | 65 | |
ede152ec RG |
66 | void registerOpenSSLUser() |
67 | { | |
68 | if (s_users.fetch_add(1) == 0) { | |
629440d4 | 69 | #ifdef HAVE_OPENSSL_INIT_CRYPTO |
81fe6363 RG |
70 | /* load the default configuration file (or one specified via OPENSSL_CONF), |
71 | which can then be used to load engines */ | |
72 | OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, nullptr); | |
18e4fac1 RG |
73 | #endif |
74 | ||
75 | #if (OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined LIBRESSL_VERSION_NUMBER && LIBRESSL_VERSION_NUMBER < 0x2090100fL)) | |
7f8a5a32 RG |
76 | SSL_load_error_strings(); |
77 | OpenSSL_add_ssl_algorithms(); | |
78 | openssl_thread_setup(); | |
79 | #endif | |
0ef9ab19 RG |
80 | s_ticketsKeyIndex = SSL_CTX_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr); |
81 | ||
82 | if (s_ticketsKeyIndex == -1) { | |
83 | throw std::runtime_error("Error getting an index for tickets key"); | |
84 | } | |
f34fdcc5 RG |
85 | |
86 | s_countersIndex = SSL_CTX_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr); | |
87 | ||
88 | if (s_countersIndex == -1) { | |
89 | throw std::runtime_error("Error getting an index for counters"); | |
90 | } | |
7f8a5a32 RG |
91 | |
92 | s_keyLogIndex = SSL_CTX_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr); | |
93 | ||
94 | if (s_keyLogIndex == -1) { | |
95 | throw std::runtime_error("Error getting an index for TLS key logging"); | |
96 | } | |
0ef9ab19 | 97 | } |
ede152ec RG |
98 | } |
99 | ||
100 | void unregisterOpenSSLUser() | |
101 | { | |
102 | if (s_users.fetch_sub(1) == 1) { | |
18e4fac1 | 103 | #if (OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined LIBRESSL_VERSION_NUMBER && LIBRESSL_VERSION_NUMBER < 0x2090100fL)) |
ede152ec RG |
104 | ERR_free_strings(); |
105 | ||
106 | EVP_cleanup(); | |
107 | ||
108 | CONF_modules_finish(); | |
109 | CONF_modules_free(); | |
110 | CONF_modules_unload(1); | |
111 | ||
112 | CRYPTO_cleanup_all_ex_data(); | |
113 | openssl_thread_cleanup(); | |
4479df79 | 114 | #endif |
0ef9ab19 RG |
115 | } |
116 | } | |
117 | ||
118 | void* libssl_get_ticket_key_callback_data(SSL* s) | |
119 | { | |
120 | SSL_CTX* sslCtx = SSL_get_SSL_CTX(s); | |
121 | if (sslCtx == nullptr) { | |
122 | return nullptr; | |
123 | } | |
124 | ||
125 | return SSL_CTX_get_ex_data(sslCtx, s_ticketsKeyIndex); | |
126 | } | |
127 | ||
128 | void libssl_set_ticket_key_callback_data(SSL_CTX* ctx, void* data) | |
129 | { | |
130 | SSL_CTX_set_ex_data(ctx, s_ticketsKeyIndex, data); | |
131 | } | |
132 | ||
133 | int libssl_ticket_key_callback(SSL *s, OpenSSLTLSTicketKeysRing& keyring, unsigned char keyName[TLS_TICKETS_KEY_NAME_SIZE], unsigned char *iv, EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc) | |
134 | { | |
135 | if (enc) { | |
136 | const auto key = keyring.getEncryptionKey(); | |
137 | if (key == nullptr) { | |
138 | return -1; | |
139 | } | |
140 | ||
141 | return key->encrypt(keyName, iv, ectx, hctx); | |
142 | } | |
143 | ||
144 | bool activeEncryptionKey = false; | |
145 | ||
146 | const auto key = keyring.getDecryptionKey(keyName, activeEncryptionKey); | |
147 | if (key == nullptr) { | |
148 | /* we don't know this key, just create a new ticket */ | |
149 | return 0; | |
150 | } | |
151 | ||
152 | if (key->decrypt(iv, ectx, hctx) == false) { | |
153 | return -1; | |
154 | } | |
155 | ||
156 | if (!activeEncryptionKey) { | |
157 | /* this key is not active, please encrypt the ticket content with the currently active one */ | |
158 | return 2; | |
159 | } | |
160 | ||
161 | return 1; | |
ede152ec RG |
162 | } |
163 | ||
f34fdcc5 RG |
164 | static void libssl_info_callback(const SSL *ssl, int where, int ret) |
165 | { | |
166 | SSL_CTX* sslCtx = SSL_get_SSL_CTX(ssl); | |
167 | if (sslCtx == nullptr) { | |
168 | return; | |
169 | } | |
170 | ||
171 | TLSErrorCounters* counters = reinterpret_cast<TLSErrorCounters*>(SSL_CTX_get_ex_data(sslCtx, s_countersIndex)); | |
172 | if (counters == nullptr) { | |
173 | return; | |
174 | } | |
175 | ||
176 | if (where & SSL_CB_ALERT) { | |
177 | const long lastError = ERR_peek_last_error(); | |
178 | switch (ERR_GET_REASON(lastError)) { | |
179 | #ifdef SSL_R_DH_KEY_TOO_SMALL | |
180 | case SSL_R_DH_KEY_TOO_SMALL: | |
181 | ++counters->d_dhKeyTooSmall; | |
182 | break; | |
183 | #endif /* SSL_R_DH_KEY_TOO_SMALL */ | |
184 | case SSL_R_NO_SHARED_CIPHER: | |
185 | ++counters->d_noSharedCipher; | |
186 | break; | |
187 | case SSL_R_UNKNOWN_PROTOCOL: | |
188 | ++counters->d_unknownProtocol; | |
189 | break; | |
190 | case SSL_R_UNSUPPORTED_PROTOCOL: | |
191 | #ifdef SSL_R_VERSION_TOO_LOW | |
192 | case SSL_R_VERSION_TOO_LOW: | |
193 | #endif /* SSL_R_VERSION_TOO_LOW */ | |
194 | ++counters->d_unsupportedProtocol; | |
195 | break; | |
196 | case SSL_R_INAPPROPRIATE_FALLBACK: | |
197 | ++counters->d_inappropriateFallBack; | |
198 | break; | |
199 | case SSL_R_UNKNOWN_CIPHER_TYPE: | |
200 | ++counters->d_unknownCipherType; | |
201 | break; | |
202 | case SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE: | |
203 | ++counters->d_unknownKeyExchangeType; | |
204 | break; | |
205 | case SSL_R_UNSUPPORTED_ELLIPTIC_CURVE: | |
206 | ++counters->d_unsupportedEC; | |
207 | break; | |
208 | default: | |
209 | break; | |
210 | } | |
211 | } | |
212 | } | |
213 | ||
214 | void libssl_set_error_counters_callback(std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)>& ctx, TLSErrorCounters* counters) | |
215 | { | |
216 | SSL_CTX_set_ex_data(ctx.get(), s_countersIndex, counters); | |
217 | SSL_CTX_set_info_callback(ctx.get(), libssl_info_callback); | |
218 | } | |
219 | ||
be3183ed RG |
220 | int libssl_ocsp_stapling_callback(SSL* ssl, const std::map<int, std::string>& ocspMap) |
221 | { | |
222 | auto pkey = SSL_get_privatekey(ssl); | |
223 | if (pkey == nullptr) { | |
224 | return SSL_TLSEXT_ERR_NOACK; | |
225 | } | |
226 | ||
227 | /* look for an OCSP response for the corresponding private key type (RSA, ECDSA..) */ | |
228 | const auto& data = ocspMap.find(EVP_PKEY_base_id(pkey)); | |
229 | if (data == ocspMap.end()) { | |
230 | return SSL_TLSEXT_ERR_NOACK; | |
231 | } | |
232 | ||
233 | /* we need to allocate a copy because OpenSSL will free the pointer passed to SSL_set_tlsext_status_ocsp_resp() */ | |
234 | void* copy = OPENSSL_malloc(data->second.size()); | |
235 | if (copy == nullptr) { | |
236 | return SSL_TLSEXT_ERR_NOACK; | |
237 | } | |
238 | ||
239 | memcpy(copy, data->second.data(), data->second.size()); | |
240 | SSL_set_tlsext_status_ocsp_resp(ssl, copy, data->second.size()); | |
241 | return SSL_TLSEXT_ERR_OK; | |
242 | } | |
243 | ||
244 | static bool libssl_validate_ocsp_response(const std::string& response) | |
245 | { | |
246 | auto responsePtr = reinterpret_cast<const unsigned char *>(response.data()); | |
247 | std::unique_ptr<OCSP_RESPONSE, void(*)(OCSP_RESPONSE*)> resp(d2i_OCSP_RESPONSE(nullptr, &responsePtr, response.size()), OCSP_RESPONSE_free); | |
248 | if (resp == nullptr) { | |
249 | throw std::runtime_error("Unable to parse OCSP response"); | |
250 | } | |
251 | ||
252 | int status = OCSP_response_status(resp.get()); | |
253 | if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { | |
254 | throw std::runtime_error("OCSP response status is not successful: " + std::to_string(status)); | |
255 | } | |
256 | ||
257 | std::unique_ptr<OCSP_BASICRESP, void(*)(OCSP_BASICRESP*)> basic(OCSP_response_get1_basic(resp.get()), OCSP_BASICRESP_free); | |
258 | if (basic == nullptr) { | |
259 | throw std::runtime_error("Error getting a basic OCSP response"); | |
260 | } | |
261 | ||
262 | if (OCSP_resp_count(basic.get()) != 1) { | |
263 | throw std::runtime_error("More than one single response in an OCSP basic response"); | |
264 | } | |
265 | ||
266 | auto singleResponse = OCSP_resp_get0(basic.get(), 0); | |
267 | if (singleResponse == nullptr) { | |
268 | throw std::runtime_error("Error getting a single response from the basic OCSP response"); | |
269 | } | |
270 | ||
271 | int reason; | |
272 | ASN1_GENERALIZEDTIME* revTime = nullptr; | |
273 | ASN1_GENERALIZEDTIME* thisUpdate = nullptr; | |
274 | ASN1_GENERALIZEDTIME* nextUpdate = nullptr; | |
275 | ||
276 | auto singleResponseStatus = OCSP_single_get0_status(singleResponse, &reason, &revTime, &thisUpdate, &nextUpdate); | |
277 | if (singleResponseStatus != V_OCSP_CERTSTATUS_GOOD) { | |
278 | throw std::runtime_error("Invalid status for OCSP single response (" + std::to_string(singleResponseStatus) + ")"); | |
279 | } | |
280 | if (thisUpdate == nullptr || nextUpdate == nullptr) { | |
281 | throw std::runtime_error("Error getting validity of OCSP single response"); | |
282 | } | |
283 | ||
284 | auto validityResult = OCSP_check_validity(thisUpdate, nextUpdate, /* 5 minutes of leeway */ 5 * 60, -1); | |
285 | if (validityResult == 0) { | |
286 | throw std::runtime_error("OCSP single response is not yet, or no longer, valid"); | |
287 | } | |
288 | ||
289 | return true; | |
290 | } | |
291 | ||
292 | std::map<int, std::string> libssl_load_ocsp_responses(const std::vector<std::string>& ocspFiles, std::vector<int> keyTypes) | |
293 | { | |
294 | std::map<int, std::string> ocspResponses; | |
295 | ||
296 | if (ocspFiles.size() > keyTypes.size()) { | |
297 | throw std::runtime_error("More OCSP files than certificates and keys loaded!"); | |
298 | } | |
299 | ||
300 | size_t count = 0; | |
301 | for (const auto& filename : ocspFiles) { | |
302 | std::ifstream file(filename, std::ios::binary); | |
303 | std::string content; | |
304 | while(file) { | |
305 | char buffer[4096]; | |
306 | file.read(buffer, sizeof(buffer)); | |
307 | if (file.bad()) { | |
308 | file.close(); | |
309 | throw std::runtime_error("Unable to load OCSP response from '" + filename + "'"); | |
310 | } | |
311 | content.append(buffer, file.gcount()); | |
312 | } | |
313 | file.close(); | |
314 | ||
315 | try { | |
316 | libssl_validate_ocsp_response(content); | |
317 | ocspResponses.insert({keyTypes.at(count), std::move(content)}); | |
318 | } | |
319 | catch (const std::exception& e) { | |
320 | throw std::runtime_error("Error checking the validity of OCSP response from '" + filename + "': " + e.what()); | |
321 | } | |
322 | ++count; | |
323 | } | |
324 | ||
325 | return ocspResponses; | |
326 | } | |
327 | ||
328 | int libssl_get_last_key_type(std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)>& ctx) | |
329 | { | |
629440d4 | 330 | #ifdef HAVE_SSL_CTX_GET0_PRIVATEKEY |
be3183ed RG |
331 | auto pkey = SSL_CTX_get0_privatekey(ctx.get()); |
332 | #else | |
333 | auto temp = std::unique_ptr<SSL, void(*)(SSL*)>(SSL_new(ctx.get()), SSL_free); | |
334 | if (!temp) { | |
335 | return -1; | |
336 | } | |
337 | auto pkey = SSL_get_privatekey(temp.get()); | |
338 | #endif | |
339 | ||
340 | if (!pkey) { | |
341 | return -1; | |
342 | } | |
343 | ||
344 | return EVP_PKEY_base_id(pkey); | |
345 | } | |
346 | ||
8c15553e RG |
347 | #ifdef HAVE_OCSP_BASIC_SIGN |
348 | bool libssl_generate_ocsp_response(const std::string& certFile, const std::string& caCert, const std::string& caKey, const std::string& outFile, int ndays, int nmin) | |
349 | { | |
350 | const EVP_MD* rmd = EVP_sha256(); | |
351 | ||
352 | auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(certFile.c_str(), "r"), fclose); | |
353 | if (!fp) { | |
354 | throw std::runtime_error("Unable to open '" + certFile + "' when loading the certificate to generate an OCSP response"); | |
355 | } | |
356 | auto cert = std::unique_ptr<X509, void(*)(X509*)>(PEM_read_X509_AUX(fp.get(), nullptr, nullptr, nullptr), X509_free); | |
357 | ||
358 | fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(caCert.c_str(), "r"), fclose); | |
359 | if (!fp) { | |
360 | throw std::runtime_error("Unable to open '" + caCert + "' when loading the issuer certificate to generate an OCSP response"); | |
361 | } | |
362 | auto issuer = std::unique_ptr<X509, void(*)(X509*)>(PEM_read_X509_AUX(fp.get(), nullptr, nullptr, nullptr), X509_free); | |
363 | fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(caKey.c_str(), "r"), fclose); | |
364 | if (!fp) { | |
365 | throw std::runtime_error("Unable to open '" + caKey + "' when loading the issuer key to generate an OCSP response"); | |
366 | } | |
367 | auto issuerKey = std::unique_ptr<EVP_PKEY, void(*)(EVP_PKEY*)>(PEM_read_PrivateKey(fp.get(), nullptr, nullptr, nullptr), EVP_PKEY_free); | |
368 | fp.reset(); | |
369 | ||
370 | auto bs = std::unique_ptr<OCSP_BASICRESP, void(*)(OCSP_BASICRESP*)>(OCSP_BASICRESP_new(), OCSP_BASICRESP_free); | |
371 | auto thisupd = std::unique_ptr<ASN1_TIME, void(*)(ASN1_TIME*)>(X509_gmtime_adj(nullptr, 0), ASN1_TIME_free); | |
372 | auto nextupd = std::unique_ptr<ASN1_TIME, void(*)(ASN1_TIME*)>(X509_time_adj_ex(nullptr, ndays, nmin * 60, nullptr), ASN1_TIME_free); | |
373 | ||
374 | auto cid = std::unique_ptr<OCSP_CERTID, void(*)(OCSP_CERTID*)>(OCSP_cert_to_id(rmd, cert.get(), issuer.get()), OCSP_CERTID_free); | |
375 | OCSP_basic_add1_status(bs.get(), cid.get(), V_OCSP_CERTSTATUS_GOOD, 0, nullptr, thisupd.get(), nextupd.get()); | |
376 | ||
377 | if (OCSP_basic_sign(bs.get(), issuer.get(), issuerKey.get(), rmd, nullptr, OCSP_NOCERTS) != 1) { | |
378 | throw std::runtime_error("Error while signing the OCSP response"); | |
379 | } | |
380 | ||
381 | auto resp = std::unique_ptr<OCSP_RESPONSE, void(*)(OCSP_RESPONSE*)>(OCSP_response_create(OCSP_RESPONSE_STATUS_SUCCESSFUL, bs.get()), OCSP_RESPONSE_free); | |
382 | auto bio = std::unique_ptr<BIO, void(*)(BIO*)>(BIO_new_file(outFile.c_str(), "wb"), BIO_vfree); | |
383 | if (!bio) { | |
384 | throw std::runtime_error("Error opening file for writing the OCSP response"); | |
385 | } | |
386 | ||
387 | // i2d_OCSP_RESPONSE_bio(bio.get(), resp.get()) is unusable from C++ because of an invalid cast | |
388 | ASN1_i2d_bio((i2d_of_void*)i2d_OCSP_RESPONSE, bio.get(), (unsigned char*)resp.get()); | |
389 | ||
390 | return true; | |
391 | } | |
392 | #endif /* HAVE_OCSP_BASIC_SIGN */ | |
393 | ||
be8355a2 RG |
394 | LibsslTLSVersion libssl_tls_version_from_string(const std::string& str) |
395 | { | |
396 | if (str == "tls1.0") { | |
397 | return LibsslTLSVersion::TLS10; | |
398 | } | |
399 | if (str == "tls1.1") { | |
400 | return LibsslTLSVersion::TLS11; | |
401 | } | |
402 | if (str == "tls1.2") { | |
403 | return LibsslTLSVersion::TLS12; | |
404 | } | |
405 | if (str == "tls1.3") { | |
406 | return LibsslTLSVersion::TLS13; | |
407 | } | |
408 | throw std::runtime_error("Unknown TLS version '" + str); | |
409 | } | |
410 | ||
656a5e55 RG |
411 | const std::string& libssl_tls_version_to_string(LibsslTLSVersion version) |
412 | { | |
413 | static const std::map<LibsslTLSVersion, std::string> versions = { | |
414 | { LibsslTLSVersion::TLS10, "tls1.0" }, | |
415 | { LibsslTLSVersion::TLS11, "tls1.1" }, | |
416 | { LibsslTLSVersion::TLS12, "tls1.2" }, | |
417 | { LibsslTLSVersion::TLS13, "tls1.3" } | |
418 | }; | |
419 | ||
420 | const auto& it = versions.find(version); | |
421 | if (it == versions.end()) { | |
422 | throw std::runtime_error("Unknown TLS version (" + std::to_string((int)version) + ")"); | |
423 | } | |
424 | return it->second; | |
425 | } | |
426 | ||
be8355a2 RG |
427 | bool libssl_set_min_tls_version(std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)>& ctx, LibsslTLSVersion version) |
428 | { | |
629440d4 RG |
429 | #if defined(HAVE_SSL_CTX_SET_MIN_PROTO_VERSION) || defined(SSL_CTX_set_min_proto_version) |
430 | /* These functions have been introduced in 1.1.0, and the use of SSL_OP_NO_* is deprecated | |
431 | Warning: SSL_CTX_set_min_proto_version is a function-like macro in OpenSSL */ | |
be8355a2 RG |
432 | int vers; |
433 | switch(version) { | |
434 | case LibsslTLSVersion::TLS10: | |
435 | vers = TLS1_VERSION; | |
436 | break; | |
437 | case LibsslTLSVersion::TLS11: | |
438 | vers = TLS1_1_VERSION; | |
439 | break; | |
440 | case LibsslTLSVersion::TLS12: | |
441 | vers = TLS1_2_VERSION; | |
442 | break; | |
443 | case LibsslTLSVersion::TLS13: | |
656a5e55 | 444 | #ifdef TLS1_3_VERSION |
be8355a2 | 445 | vers = TLS1_3_VERSION; |
656a5e55 RG |
446 | #else |
447 | return false; | |
448 | #endif /* TLS1_3_VERSION */ | |
be8355a2 RG |
449 | break; |
450 | default: | |
451 | return false; | |
452 | } | |
453 | ||
454 | if (SSL_CTX_set_min_proto_version(ctx.get(), vers) != 1) { | |
455 | return false; | |
456 | } | |
457 | return true; | |
458 | #else | |
459 | long vers = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; | |
460 | switch(version) { | |
461 | case LibsslTLSVersion::TLS10: | |
462 | break; | |
463 | case LibsslTLSVersion::TLS11: | |
464 | vers |= SSL_OP_NO_TLSv1; | |
465 | break; | |
466 | case LibsslTLSVersion::TLS12: | |
467 | vers |= SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1; | |
468 | break; | |
469 | case LibsslTLSVersion::TLS13: | |
470 | vers |= SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2; | |
471 | break; | |
472 | default: | |
473 | return false; | |
474 | } | |
475 | ||
476 | long options = SSL_CTX_get_options(ctx.get()); | |
477 | SSL_CTX_set_options(ctx.get(), options | vers); | |
478 | return true; | |
479 | #endif | |
480 | } | |
481 | ||
0ef9ab19 RG |
482 | OpenSSLTLSTicketKeysRing::OpenSSLTLSTicketKeysRing(size_t capacity) |
483 | { | |
0ef9ab19 RG |
484 | d_ticketKeys.set_capacity(capacity); |
485 | } | |
486 | ||
487 | OpenSSLTLSTicketKeysRing::~OpenSSLTLSTicketKeysRing() | |
488 | { | |
0ef9ab19 RG |
489 | } |
490 | ||
491 | void OpenSSLTLSTicketKeysRing::addKey(std::shared_ptr<OpenSSLTLSTicketKey> newKey) | |
492 | { | |
493 | WriteLock wl(&d_lock); | |
494 | d_ticketKeys.push_front(newKey); | |
495 | } | |
496 | ||
497 | std::shared_ptr<OpenSSLTLSTicketKey> OpenSSLTLSTicketKeysRing::getEncryptionKey() | |
498 | { | |
499 | ReadLock rl(&d_lock); | |
500 | return d_ticketKeys.front(); | |
501 | } | |
502 | ||
503 | std::shared_ptr<OpenSSLTLSTicketKey> OpenSSLTLSTicketKeysRing::getDecryptionKey(unsigned char name[TLS_TICKETS_KEY_NAME_SIZE], bool& activeKey) | |
504 | { | |
505 | ReadLock rl(&d_lock); | |
506 | for (auto& key : d_ticketKeys) { | |
507 | if (key->nameMatches(name)) { | |
508 | activeKey = (key == d_ticketKeys.front()); | |
509 | return key; | |
510 | } | |
511 | } | |
512 | return nullptr; | |
513 | } | |
514 | ||
515 | size_t OpenSSLTLSTicketKeysRing::getKeysCount() | |
516 | { | |
517 | ReadLock rl(&d_lock); | |
518 | return d_ticketKeys.size(); | |
519 | } | |
520 | ||
521 | void OpenSSLTLSTicketKeysRing::loadTicketsKeys(const std::string& keyFile) | |
522 | { | |
523 | bool keyLoaded = false; | |
524 | std::ifstream file(keyFile); | |
525 | try { | |
526 | do { | |
527 | auto newKey = std::make_shared<OpenSSLTLSTicketKey>(file); | |
528 | addKey(newKey); | |
529 | keyLoaded = true; | |
530 | } | |
531 | while (!file.fail()); | |
532 | } | |
533 | catch (const std::exception& e) { | |
534 | /* if we haven't been able to load at least one key, fail */ | |
535 | if (!keyLoaded) { | |
536 | throw; | |
537 | } | |
538 | } | |
539 | ||
540 | file.close(); | |
541 | } | |
542 | ||
543 | void OpenSSLTLSTicketKeysRing::rotateTicketsKey(time_t now) | |
544 | { | |
545 | auto newKey = std::make_shared<OpenSSLTLSTicketKey>(); | |
546 | addKey(newKey); | |
547 | } | |
548 | ||
549 | OpenSSLTLSTicketKey::OpenSSLTLSTicketKey() | |
550 | { | |
551 | if (RAND_bytes(d_name, sizeof(d_name)) != 1) { | |
552 | throw std::runtime_error("Error while generating the name of the OpenSSL TLS ticket key"); | |
553 | } | |
554 | ||
555 | if (RAND_bytes(d_cipherKey, sizeof(d_cipherKey)) != 1) { | |
556 | throw std::runtime_error("Error while generating the cipher key of the OpenSSL TLS ticket key"); | |
557 | } | |
558 | ||
559 | if (RAND_bytes(d_hmacKey, sizeof(d_hmacKey)) != 1) { | |
560 | throw std::runtime_error("Error while generating the HMAC key of the OpenSSL TLS ticket key"); | |
561 | } | |
562 | #ifdef HAVE_LIBSODIUM | |
563 | sodium_mlock(d_name, sizeof(d_name)); | |
564 | sodium_mlock(d_cipherKey, sizeof(d_cipherKey)); | |
565 | sodium_mlock(d_hmacKey, sizeof(d_hmacKey)); | |
566 | #endif /* HAVE_LIBSODIUM */ | |
567 | } | |
568 | ||
569 | OpenSSLTLSTicketKey::OpenSSLTLSTicketKey(ifstream& file) | |
570 | { | |
571 | file.read(reinterpret_cast<char*>(d_name), sizeof(d_name)); | |
572 | file.read(reinterpret_cast<char*>(d_cipherKey), sizeof(d_cipherKey)); | |
573 | file.read(reinterpret_cast<char*>(d_hmacKey), sizeof(d_hmacKey)); | |
574 | ||
575 | if (file.fail()) { | |
576 | throw std::runtime_error("Unable to load a ticket key from the OpenSSL tickets key file"); | |
577 | } | |
578 | #ifdef HAVE_LIBSODIUM | |
579 | sodium_mlock(d_name, sizeof(d_name)); | |
580 | sodium_mlock(d_cipherKey, sizeof(d_cipherKey)); | |
581 | sodium_mlock(d_hmacKey, sizeof(d_hmacKey)); | |
582 | #endif /* HAVE_LIBSODIUM */ | |
583 | } | |
584 | ||
585 | OpenSSLTLSTicketKey::~OpenSSLTLSTicketKey() | |
586 | { | |
587 | #ifdef HAVE_LIBSODIUM | |
588 | sodium_munlock(d_name, sizeof(d_name)); | |
589 | sodium_munlock(d_cipherKey, sizeof(d_cipherKey)); | |
590 | sodium_munlock(d_hmacKey, sizeof(d_hmacKey)); | |
591 | #else | |
592 | OPENSSL_cleanse(d_name, sizeof(d_name)); | |
593 | OPENSSL_cleanse(d_cipherKey, sizeof(d_cipherKey)); | |
594 | OPENSSL_cleanse(d_hmacKey, sizeof(d_hmacKey)); | |
595 | #endif /* HAVE_LIBSODIUM */ | |
596 | } | |
597 | ||
598 | bool OpenSSLTLSTicketKey::nameMatches(const unsigned char name[TLS_TICKETS_KEY_NAME_SIZE]) const | |
599 | { | |
600 | return (memcmp(d_name, name, sizeof(d_name)) == 0); | |
601 | } | |
602 | ||
603 | int OpenSSLTLSTicketKey::encrypt(unsigned char keyName[TLS_TICKETS_KEY_NAME_SIZE], unsigned char *iv, EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx) const | |
604 | { | |
605 | memcpy(keyName, d_name, sizeof(d_name)); | |
606 | ||
607 | if (RAND_bytes(iv, EVP_MAX_IV_LENGTH) != 1) { | |
608 | return -1; | |
609 | } | |
610 | ||
611 | if (EVP_EncryptInit_ex(ectx, TLS_TICKETS_CIPHER_ALGO(), nullptr, d_cipherKey, iv) != 1) { | |
612 | return -1; | |
613 | } | |
614 | ||
615 | if (HMAC_Init_ex(hctx, d_hmacKey, sizeof(d_hmacKey), TLS_TICKETS_MAC_ALGO(), nullptr) != 1) { | |
616 | return -1; | |
617 | } | |
618 | ||
619 | return 1; | |
620 | } | |
621 | ||
622 | bool OpenSSLTLSTicketKey::decrypt(const unsigned char* iv, EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx) const | |
623 | { | |
624 | if (HMAC_Init_ex(hctx, d_hmacKey, sizeof(d_hmacKey), TLS_TICKETS_MAC_ALGO(), nullptr) != 1) { | |
625 | return false; | |
626 | } | |
627 | ||
628 | if (EVP_DecryptInit_ex(ectx, TLS_TICKETS_CIPHER_ALGO(), nullptr, d_cipherKey, iv) != 1) { | |
629 | return false; | |
630 | } | |
631 | ||
632 | return true; | |
633 | } | |
634 | ||
b54e94dc RG |
635 | std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)> libssl_init_server_context(const TLSConfig& config, |
636 | std::map<int, std::string>& ocspResponses) | |
637 | { | |
638 | auto ctx = std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)>(SSL_CTX_new(SSLv23_server_method()), SSL_CTX_free); | |
639 | ||
640 | int sslOptions = | |
641 | SSL_OP_NO_SSLv2 | | |
642 | SSL_OP_NO_SSLv3 | | |
643 | SSL_OP_NO_COMPRESSION | | |
644 | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | | |
645 | SSL_OP_SINGLE_DH_USE | | |
646 | SSL_OP_SINGLE_ECDH_USE; | |
647 | ||
648 | if (!config.d_enableTickets || config.d_numberOfTicketsKeys == 0) { | |
649 | /* for TLS 1.3 this means no stateless tickets, but stateful tickets might still be issued, | |
650 | which is something we don't want. */ | |
651 | sslOptions |= SSL_OP_NO_TICKET; | |
652 | /* really disable all tickets */ | |
653 | #ifdef HAVE_SSL_CTX_SET_NUM_TICKETS | |
654 | SSL_CTX_set_num_tickets(ctx.get(), 0); | |
655 | #endif /* HAVE_SSL_CTX_SET_NUM_TICKETS */ | |
656 | } | |
657 | ||
25426675 MH |
658 | if (config.d_sessionTimeout > 0) { |
659 | SSL_CTX_set_timeout(ctx.get(), config.d_sessionTimeout); | |
660 | } | |
661 | ||
b54e94dc RG |
662 | if (config.d_preferServerCiphers) { |
663 | sslOptions |= SSL_OP_CIPHER_SERVER_PREFERENCE; | |
664 | } | |
665 | ||
666 | SSL_CTX_set_options(ctx.get(), sslOptions); | |
667 | if (!libssl_set_min_tls_version(ctx, config.d_minTLSVersion)) { | |
668 | throw std::runtime_error("Failed to set the minimum version to '" + libssl_tls_version_to_string(config.d_minTLSVersion)); | |
669 | } | |
670 | ||
671 | #ifdef SSL_CTX_set_ecdh_auto | |
672 | SSL_CTX_set_ecdh_auto(ctx.get(), 1); | |
673 | #endif | |
674 | ||
675 | if (config.d_maxStoredSessions == 0) { | |
676 | /* disable stored sessions entirely */ | |
677 | SSL_CTX_set_session_cache_mode(ctx.get(), SSL_SESS_CACHE_OFF); | |
678 | } | |
679 | else { | |
680 | /* use the internal built-in cache to store sessions */ | |
681 | SSL_CTX_set_session_cache_mode(ctx.get(), SSL_SESS_CACHE_SERVER); | |
682 | SSL_CTX_sess_set_cache_size(ctx.get(), config.d_maxStoredSessions); | |
683 | } | |
684 | ||
685 | std::vector<int> keyTypes; | |
686 | /* load certificate and private key */ | |
687 | for (const auto& pair : config.d_certKeyPairs) { | |
688 | if (SSL_CTX_use_certificate_chain_file(ctx.get(), pair.first.c_str()) != 1) { | |
689 | ERR_print_errors_fp(stderr); | |
690 | throw std::runtime_error("An error occurred while trying to load the TLS server certificate file: " + pair.first); | |
691 | } | |
692 | if (SSL_CTX_use_PrivateKey_file(ctx.get(), pair.second.c_str(), SSL_FILETYPE_PEM) != 1) { | |
693 | ERR_print_errors_fp(stderr); | |
694 | throw std::runtime_error("An error occurred while trying to load the TLS server private key file: " + pair.second); | |
695 | } | |
696 | if (SSL_CTX_check_private_key(ctx.get()) != 1) { | |
697 | ERR_print_errors_fp(stderr); | |
698 | throw std::runtime_error("The key from '" + pair.second + "' does not match the certificate from '" + pair.first + "'"); | |
699 | } | |
700 | /* store the type of the new key, we might need it later to select the right OCSP stapling response */ | |
701 | auto keyType = libssl_get_last_key_type(ctx); | |
702 | if (keyType < 0) { | |
703 | throw std::runtime_error("The key from '" + pair.second + "' has an unknown type"); | |
704 | } | |
705 | keyTypes.push_back(keyType); | |
706 | } | |
707 | ||
708 | if (!config.d_ocspFiles.empty()) { | |
709 | try { | |
710 | ocspResponses = libssl_load_ocsp_responses(config.d_ocspFiles, keyTypes); | |
711 | } | |
712 | catch(const std::exception& e) { | |
713 | throw std::runtime_error("Unable to load OCSP responses: " + std::string(e.what())); | |
714 | } | |
715 | } | |
716 | ||
717 | if (!config.d_ciphers.empty() && SSL_CTX_set_cipher_list(ctx.get(), config.d_ciphers.c_str()) != 1) { | |
718 | throw std::runtime_error("The TLS ciphers could not be set: " + config.d_ciphers); | |
719 | } | |
720 | ||
721 | #ifdef HAVE_SSL_CTX_SET_CIPHERSUITES | |
722 | if (!config.d_ciphers13.empty() && SSL_CTX_set_ciphersuites(ctx.get(), config.d_ciphers13.c_str()) != 1) { | |
723 | throw std::runtime_error("The TLS 1.3 ciphers could not be set: " + config.d_ciphers13); | |
724 | } | |
725 | #endif /* HAVE_SSL_CTX_SET_CIPHERSUITES */ | |
726 | ||
727 | return ctx; | |
728 | } | |
729 | ||
7f8a5a32 RG |
730 | #ifdef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK |
731 | static void libssl_key_log_file_callback(const SSL* ssl, const char* line) | |
732 | { | |
733 | SSL_CTX* sslCtx = SSL_get_SSL_CTX(ssl); | |
734 | if (sslCtx == nullptr) { | |
735 | return; | |
736 | } | |
737 | ||
738 | auto fp = reinterpret_cast<FILE*>(SSL_CTX_get_ex_data(sslCtx, s_keyLogIndex)); | |
739 | if (fp == nullptr) { | |
740 | return; | |
741 | } | |
742 | ||
743 | fprintf(fp, "%s\n", line); | |
9b56c83d | 744 | fflush(fp); |
7f8a5a32 RG |
745 | } |
746 | #endif /* HAVE_SSL_CTX_SET_KEYLOG_CALLBACK */ | |
747 | ||
748 | std::unique_ptr<FILE, int(*)(FILE*)> libssl_set_key_log_file(std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)>& ctx, const std::string& logFile) | |
749 | { | |
750 | #ifdef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK | |
751 | auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(logFile.c_str(), "a"), fclose); | |
752 | if (!fp) { | |
753 | throw std::runtime_error("Error opening TLS log file '" + logFile + "'"); | |
754 | } | |
755 | ||
756 | SSL_CTX_set_ex_data(ctx.get(), s_keyLogIndex, fp.get()); | |
757 | SSL_CTX_set_keylog_callback(ctx.get(), &libssl_key_log_file_callback); | |
758 | ||
759 | return fp; | |
760 | #else | |
761 | return std::unique_ptr<FILE, int(*)(FILE*)>(nullptr, fclose); | |
762 | #endif /* HAVE_SSL_CTX_SET_KEYLOG_CALLBACK */ | |
763 | } | |
764 | ||
ede152ec | 765 | #endif /* HAVE_LIBSSL */ |