• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 12595591960

03 Jan 2025 09:27AM UTC coverage: 62.774% (+2.5%) from 60.245%
12595591960

Pull #15008

github

web-flow
Merge c2a2749d3 into 788f396a7
Pull Request #15008: Do not follow CNAME records for ANY or CNAME queries

30393 of 78644 branches covered (38.65%)

Branch coverage included in aggregate %.

105822 of 138350 relevant lines covered (76.49%)

4613078.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

61.51
/pdns/libssl.cc
1
#include "config.h"
2
#include "libssl.hh"
3

4
#ifdef HAVE_LIBSSL
5

6
#include <atomic>
7
#include <fstream>
8
#include <cstring>
9
#include <mutex>
10
#include <unordered_map>
11
#include <pthread.h>
12

13
#include <openssl/conf.h>
14
#if defined(DNSDIST) && (OPENSSL_VERSION_MAJOR < 3 || !defined(HAVE_TLS_PROVIDERS))
15
#ifndef OPENSSL_NO_ENGINE
16
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage): used by the preprocessor below
17
#define DNSDIST_ENABLE_LIBSSL_ENGINE 1
18
#include <openssl/engine.h>
19
#endif
20
#endif
21
#include <openssl/err.h>
22
#ifndef DISABLE_OCSP_STAPLING
23
#include <openssl/ocsp.h>
24
#endif /* DISABLE_OCSP_STAPLING */
25
#include <openssl/pkcs12.h>
26
#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
27
#include <openssl/provider.h>
28
#endif /* defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 */
29
#include <openssl/rand.h>
30
#include <openssl/ssl.h>
31
#include <fcntl.h>
32

33
#if OPENSSL_VERSION_MAJOR >= 3
34
#include <openssl/param_build.h>
35
#include <openssl/core.h>
36
#include <openssl/core_names.h>
37
#include <openssl/evp.h>
38
#else
39
#include <openssl/hmac.h>
40
#endif
41

42
#ifdef HAVE_LIBSODIUM
43
#include <sodium.h>
44
#endif /* HAVE_LIBSODIUM */
45

46
#undef CERT
47
#include "misc.hh"
48
#include "tcpiohandler.hh"
49

50
#if (OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2090100fL)
51
/* OpenSSL < 1.1.0 needs support for threading/locking in the calling application. */
52

53
#include "lock.hh"
54
static std::vector<std::mutex> openssllocks;
55

56
extern "C" {
57
static void openssl_pthreads_locking_callback(int mode, int type, const char *file, int line)
58
{
59
  if (mode & CRYPTO_LOCK) {
60
    openssllocks.at(type).lock();
61

62
  } else {
63
    openssllocks.at(type).unlock();
64
  }
65
}
66

67
static unsigned long openssl_pthreads_id_callback()
68
{
69
  return (unsigned long)pthread_self();
70
}
71
}
72

73
static void openssl_thread_setup()
74
{
75
  openssllocks = std::vector<std::mutex>(CRYPTO_num_locks());
76
  CRYPTO_set_id_callback(&openssl_pthreads_id_callback);
77
  CRYPTO_set_locking_callback(&openssl_pthreads_locking_callback);
78
}
79

80
static void openssl_thread_cleanup()
81
{
82
  CRYPTO_set_locking_callback(nullptr);
83
  openssllocks.clear();
84
}
85

86
#endif /* (OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2090100fL) */
87

88
static std::atomic<uint64_t> s_users;
89

90
#if OPENSSL_VERSION_MAJOR >= 3 && defined(HAVE_TLS_PROVIDERS)
91
static LockGuarded<std::unordered_map<std::string, std::unique_ptr<OSSL_PROVIDER, decltype(&OSSL_PROVIDER_unload)>>> s_providers;
92
#else
93
#if defined(DNSDIST_ENABLE_LIBSSL_ENGINE)
94
static LockGuarded<std::unordered_map<std::string, std::unique_ptr<ENGINE, decltype(&ENGINE_free)>>> s_engines;
95
#endif
96
#endif
97

98
static int s_ticketsKeyIndex{-1};
99
static int s_countersIndex{-1};
100
static int s_keyLogIndex{-1};
101

102
void registerOpenSSLUser()
103
{
104✔
104
  if (s_users.fetch_add(1) == 0) {
104✔
105
#ifdef HAVE_OPENSSL_INIT_CRYPTO
72✔
106
#ifndef DISABLE_OPENSSL_ERROR_STRINGS
72✔
107
    uint64_t cryptoOpts = OPENSSL_INIT_LOAD_CONFIG;
72✔
108
    const uint64_t sslOpts = 0;
72✔
109
#else /* DISABLE_OPENSSL_ERROR_STRINGS */
110
    uint64_t cryptoOpts = OPENSSL_INIT_LOAD_CONFIG|OPENSSL_INIT_NO_LOAD_CRYPTO_STRINGS;
111
    const uint64_t sslOpts = OPENSSL_INIT_NO_LOAD_SSL_STRINGS;
112
#endif /* DISABLE_OPENSSL_ERROR_STRINGS */
113
    /* load the default configuration file (or one specified via OPENSSL_CONF),
114
       which can then be used to load engines.
115
    */
116
#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
72✔
117
    /* Since 661595ca0933fe631faeadd14a189acd5d4185e0 we can no longer rely on the ciphers and digests
118
       required for TLS to be loaded by OPENSSL_init_ssl(), so let's give up and load everything */
119
#else /* OPENSSL_VERSION_MAJOR >= 3 */
120
    /* Do not load all ciphers and digests, we only need a few of them and these
121
       will be loaded by OPENSSL_init_ssl(). */
122
    cryptoOpts |= OPENSSL_INIT_NO_ADD_ALL_CIPHERS|OPENSSL_INIT_NO_ADD_ALL_DIGESTS;
123
#endif /* OPENSSL_VERSION_MAJOR >= 3 */
124

125
    OPENSSL_init_crypto(cryptoOpts, nullptr);
72✔
126
    OPENSSL_init_ssl(sslOpts, nullptr);
72✔
127
#endif /* HAVE_OPENSSL_INIT_CRYPTO */
72✔
128

129
#if (OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined LIBRESSL_VERSION_NUMBER && LIBRESSL_VERSION_NUMBER < 0x2090100fL))
130
    /* load error strings for both libcrypto and libssl */
131
    SSL_load_error_strings();
132
    /* load all ciphers and digests needed for TLS support */
133
    OpenSSL_add_ssl_algorithms();
134
    openssl_thread_setup();
135
#endif
136
    s_ticketsKeyIndex = SSL_CTX_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
72✔
137

138
    if (s_ticketsKeyIndex == -1) {
72!
139
      throw std::runtime_error("Error getting an index for tickets key");
×
140
    }
×
141

142
    s_countersIndex = SSL_CTX_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
72✔
143

144
    if (s_countersIndex == -1) {
72!
145
      throw std::runtime_error("Error getting an index for counters");
×
146
    }
×
147

148
    s_keyLogIndex = SSL_CTX_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
72✔
149

150
    if (s_keyLogIndex == -1) {
72!
151
      throw std::runtime_error("Error getting an index for TLS key logging");
×
152
    }
×
153
  }
72✔
154
}
104✔
155

156
void unregisterOpenSSLUser()
157
{
9✔
158
  if (s_users.fetch_sub(1) == 1) {
9!
159
#if defined(DNSDIST_ENABLE_LIBSSL_ENGINE)
160
    for (auto& [name, engine] : *s_engines.lock()) {
×
161
      ENGINE_finish(engine.get());
162
      engine.reset();
163
    }
164
    s_engines.lock()->clear();
165
#endif /* PDNS_ENABLE_LIBSSL_ENGINE */
166
#if (OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined LIBRESSL_VERSION_NUMBER && LIBRESSL_VERSION_NUMBER < 0x2090100fL))
167
    ERR_free_strings();
168

169
    EVP_cleanup();
170

171
    CONF_modules_finish();
172
    CONF_modules_free();
173
    CONF_modules_unload(1);
174

175
    CRYPTO_cleanup_all_ex_data();
176
    openssl_thread_cleanup();
177
#endif
178
  }
×
179
}
9✔
180

181
#if defined(HAVE_LIBSSL) && OPENSSL_VERSION_MAJOR >= 3 && defined(HAVE_TLS_PROVIDERS)
182
std::pair<bool, std::string> libssl_load_provider(const std::string& providerName)
183
{
184
  if (s_users.load() == 0) {
185
    /* We need to make sure that OpenSSL has been properly initialized before loading an engine.
186
       This messes up our accounting a bit, so some memory might not be properly released when
187
       the program exits when engines are in use. */
188
    registerOpenSSLUser();
189
  }
190

191
  auto providers = s_providers.lock();
192
  if (providers->count(providerName) > 0) {
193
    return { false, "TLS provider already loaded" };
194
  }
195

196
  auto provider = std::unique_ptr<OSSL_PROVIDER, decltype(&OSSL_PROVIDER_unload)>(OSSL_PROVIDER_load(nullptr, providerName.c_str()), OSSL_PROVIDER_unload);
197
  if (provider == nullptr) {
198
    return { false, "unable to load TLS provider '" + providerName + "'" };
199
  }
200

201
  providers->insert({providerName, std::move(provider)});
202
  return { true, "" };
203
}
204
#endif /* HAVE_LIBSSL && OPENSSL_VERSION_MAJOR >= 3 && HAVE_TLS_PROVIDERS */
205

206
#if defined(HAVE_LIBSSL) && !HAVE_TLS_PROVIDERS
207
std::pair<bool, std::string> libssl_load_engine([[maybe_unused]] const std::string& engineName, [[maybe_unused]] const std::optional<std::string>& defaultString)
208
{
×
209
#if defined(OPENSSL_NO_ENGINE)
210
  return { false, "OpenSSL has been built without engine support" };
211
#elif !defined(DNSDIST_ENABLE_LIBSSL_ENGINE)
212
  return { false, "SSL engine support not enabled" };
213
#else /* DNSDIST_ENABLE_LIBSSL_ENGINE */
214
  if (s_users.load() == 0) {
×
215
    /* We need to make sure that OpenSSL has been properly initialized before loading an engine.
216
       This messes up our accounting a bit, so some memory might not be properly released when
217
       the program exits when engines are in use. */
218
    registerOpenSSLUser();
219
  }
220

221
  auto engines = s_engines.lock();
222
  if (engines->count(engineName) > 0) {
×
223
    return { false, "TLS engine already loaded" };
224
  }
225

226
  auto engine = std::unique_ptr<ENGINE, decltype(&ENGINE_free)>(ENGINE_by_id(engineName.c_str()), ENGINE_free);
227
  if (engine == nullptr) {
×
228
    return { false, "unable to load TLS engine '" + engineName + "'" };
229
  }
230

231
  if (!ENGINE_init(engine.get())) {
×
232
    return { false, "Unable to init TLS engine '" + engineName + "'" };
233
  }
234

235
  if (defaultString) {
×
236
    if (ENGINE_set_default_string(engine.get(), defaultString->c_str()) == 0) {
×
237
      return { false, "error while setting the TLS engine default string" };
238
    }
239
  }
240

241
  engines->insert({engineName, std::move(engine)});
242
  return { true, "" };
243
#endif /* DNSDIST_ENABLE_LIBSSL_ENGINE */
244
}
×
245
#endif /* HAVE_LIBSSL && !HAVE_TLS_PROVIDERS */
246

247
void* libssl_get_ticket_key_callback_data(SSL* s)
248
{
750✔
249
  SSL_CTX* sslCtx = SSL_get_SSL_CTX(s);
750✔
250
  if (sslCtx == nullptr) {
750!
251
    return nullptr;
×
252
  }
×
253

254
  return SSL_CTX_get_ex_data(sslCtx, s_ticketsKeyIndex);
750✔
255
}
750✔
256

257
void libssl_set_ticket_key_callback_data(SSL_CTX* ctx, void* data)
258
{
73✔
259
  SSL_CTX_set_ex_data(ctx, s_ticketsKeyIndex, data);
73✔
260
}
73✔
261

262
#if OPENSSL_VERSION_MAJOR >= 3
263
int libssl_ticket_key_callback(SSL* /* s */, OpenSSLTLSTicketKeysRing& keyring, unsigned char keyName[TLS_TICKETS_KEY_NAME_SIZE], unsigned char* iv, EVP_CIPHER_CTX* ectx, EVP_MAC_CTX* hctx, int enc)
264
#else
265
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)
266
#endif
267
{
750✔
268
  if (enc != 0) {
750✔
269
    const auto key = keyring.getEncryptionKey();
706✔
270
    if (key == nullptr) {
706!
271
      return -1;
×
272
    }
×
273

274
    return key->encrypt(keyName, iv, ectx, hctx);
706✔
275
  }
706✔
276

277
  bool activeEncryptionKey = false;
44✔
278

279
  const auto key = keyring.getDecryptionKey(keyName, activeEncryptionKey);
44✔
280
  if (key == nullptr) {
44✔
281
    /* we don't know this key, just create a new ticket */
282
    return 0;
9✔
283
  }
9✔
284

285
  if (!key->decrypt(iv, ectx, hctx)) {
35!
286
    return -1;
×
287
  }
×
288

289
  if (!activeEncryptionKey) {
35✔
290
    /* this key is not active, please encrypt the ticket content with the currently active one */
291
    return 2;
12✔
292
  }
12✔
293

294
  return 1;
23✔
295
}
35✔
296

297
static int libssl_server_name_callback(SSL* ssl, int* /* alert */, void* /* arg */)
298
{
390✔
299
  if (SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name) != nullptr) {
390!
300
    return SSL_TLSEXT_ERR_OK;
390✔
301
  }
390✔
302

303
  return SSL_TLSEXT_ERR_NOACK;
×
304
}
390✔
305

306
static void libssl_info_callback(const SSL *ssl, int where, int /* ret */)
307
{
7,660✔
308
  SSL_CTX* sslCtx = SSL_get_SSL_CTX(ssl);
7,660✔
309
  if (sslCtx == nullptr) {
7,660!
310
    return;
×
311
  }
×
312

313
  TLSErrorCounters* counters = reinterpret_cast<TLSErrorCounters*>(SSL_CTX_get_ex_data(sslCtx, s_countersIndex));
7,660✔
314
  if (counters == nullptr) {
7,660!
315
    return;
×
316
  }
×
317

318
  if (where & SSL_CB_ALERT) {
7,660✔
319
    const long lastError = ERR_peek_last_error();
645✔
320
    switch (ERR_GET_REASON(lastError)) {
645✔
321
#ifdef SSL_R_DH_KEY_TOO_SMALL
×
322
    case SSL_R_DH_KEY_TOO_SMALL:
×
323
      ++counters->d_dhKeyTooSmall;
×
324
      break;
×
325
#endif /* SSL_R_DH_KEY_TOO_SMALL */
×
326
    case SSL_R_NO_SHARED_CIPHER:
×
327
      ++counters->d_noSharedCipher;
×
328
      break;
×
329
    case SSL_R_UNKNOWN_PROTOCOL:
×
330
      ++counters->d_unknownProtocol;
×
331
      break;
×
332
    case SSL_R_UNSUPPORTED_PROTOCOL:
×
333
#ifdef SSL_R_VERSION_TOO_LOW
×
334
    case SSL_R_VERSION_TOO_LOW:
×
335
#endif /* SSL_R_VERSION_TOO_LOW */
×
336
      ++counters->d_unsupportedProtocol;
×
337
      break;
×
338
    case SSL_R_INAPPROPRIATE_FALLBACK:
×
339
      ++counters->d_inappropriateFallBack;
×
340
      break;
×
341
    case SSL_R_UNKNOWN_CIPHER_TYPE:
×
342
      ++counters->d_unknownCipherType;
×
343
      break;
×
344
    case SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE:
×
345
      ++counters->d_unknownKeyExchangeType;
×
346
      break;
×
347
    case SSL_R_UNSUPPORTED_ELLIPTIC_CURVE:
×
348
      ++counters->d_unsupportedEC;
×
349
      break;
×
350
    default:
645!
351
      break;
645✔
352
    }
645✔
353
  }
645✔
354
}
7,660✔
355

356
void libssl_set_error_counters_callback(std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)>& ctx, TLSErrorCounters* counters)
357
{
76✔
358
  SSL_CTX_set_ex_data(ctx.get(), s_countersIndex, counters);
76✔
359
  SSL_CTX_set_info_callback(ctx.get(), libssl_info_callback);
76✔
360
}
76✔
361

362
#ifndef DISABLE_OCSP_STAPLING
363
int libssl_ocsp_stapling_callback(SSL* ssl, const std::map<int, std::string>& ocspMap)
364
{
6✔
365
  auto pkey = SSL_get_privatekey(ssl);
6✔
366
  if (pkey == nullptr) {
6!
367
    return SSL_TLSEXT_ERR_NOACK;
×
368
  }
×
369

370
  /* look for an OCSP response for the corresponding private key type (RSA, ECDSA..) */
371
  const auto& data = ocspMap.find(EVP_PKEY_base_id(pkey));
6✔
372
  if (data == ocspMap.end()) {
6!
373
    return SSL_TLSEXT_ERR_NOACK;
×
374
  }
×
375

376
  /* we need to allocate a copy because OpenSSL will free the pointer passed to SSL_set_tlsext_status_ocsp_resp() */
377
  void* copy = OPENSSL_malloc(data->second.size());
6✔
378
  if (copy == nullptr) {
6!
379
    return SSL_TLSEXT_ERR_NOACK;
×
380
  }
×
381

382
  memcpy(copy, data->second.data(), data->second.size());
6✔
383
  SSL_set_tlsext_status_ocsp_resp(ssl, copy, data->second.size());
6✔
384
  return SSL_TLSEXT_ERR_OK;
6✔
385
}
6✔
386

387
static bool libssl_validate_ocsp_response(const std::string& response)
388
{
11✔
389
  auto responsePtr = reinterpret_cast<const unsigned char *>(response.data());
11✔
390
  std::unique_ptr<OCSP_RESPONSE, void(*)(OCSP_RESPONSE*)> resp(d2i_OCSP_RESPONSE(nullptr, &responsePtr, response.size()), OCSP_RESPONSE_free);
11✔
391
  if (resp == nullptr) {
11✔
392
    throw std::runtime_error("Unable to parse OCSP response");
3✔
393
  }
3✔
394

395
  int status = OCSP_response_status(resp.get());
8✔
396
  if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
8!
397
    throw std::runtime_error("OCSP response status is not successful: " + std::to_string(status));
×
398
  }
×
399

400
  std::unique_ptr<OCSP_BASICRESP, void(*)(OCSP_BASICRESP*)> basic(OCSP_response_get1_basic(resp.get()), OCSP_BASICRESP_free);
8✔
401
  if (basic == nullptr) {
8!
402
    throw std::runtime_error("Error getting a basic OCSP response");
×
403
  }
×
404

405
  if (OCSP_resp_count(basic.get()) != 1) {
8!
406
    throw std::runtime_error("More than one single response in an OCSP basic response");
×
407
  }
×
408

409
  auto singleResponse = OCSP_resp_get0(basic.get(), 0);
8✔
410
  if (singleResponse == nullptr) {
8!
411
    throw std::runtime_error("Error getting a single response from the basic OCSP response");
×
412
  }
×
413

414
  int reason;
8✔
415
  ASN1_GENERALIZEDTIME* revTime = nullptr;
8✔
416
  ASN1_GENERALIZEDTIME* thisUpdate = nullptr;
8✔
417
  ASN1_GENERALIZEDTIME* nextUpdate = nullptr;
8✔
418

419
  auto singleResponseStatus = OCSP_single_get0_status(singleResponse, &reason, &revTime, &thisUpdate, &nextUpdate);
8✔
420
  if (singleResponseStatus != V_OCSP_CERTSTATUS_GOOD) {
8!
421
    throw std::runtime_error("Invalid status for OCSP single response (" + std::to_string(singleResponseStatus) + ")");
×
422
  }
×
423
  if (thisUpdate == nullptr || nextUpdate == nullptr) {
8!
424
    throw std::runtime_error("Error getting validity of OCSP single response");
×
425
  }
×
426

427
  auto validityResult = OCSP_check_validity(thisUpdate, nextUpdate, /* 5 minutes of leeway */ 5 * 60, -1);
8✔
428
  if (validityResult == 0) {
8!
429
    throw std::runtime_error("OCSP single response is not yet, or no longer, valid");
×
430
  }
×
431

432
  return true;
8✔
433
}
8✔
434

435
static std::map<int, std::string> libssl_load_ocsp_responses(const std::vector<std::string>& ocspFiles, std::vector<int> keyTypes, std::vector<std::string>& warnings)
436
{
11✔
437
  std::map<int, std::string> ocspResponses;
11✔
438

439
  if (ocspFiles.size() > keyTypes.size()) {
11!
440
    throw std::runtime_error("More OCSP files than certificates and keys loaded!");
×
441
  }
×
442

443
  size_t count = 0;
11✔
444
  for (const auto& filename : ocspFiles) {
11✔
445
    std::ifstream file(filename, std::ios::binary);
11✔
446
    std::string content;
11✔
447
    while (file) {
22✔
448
      char buffer[4096];
11✔
449
      file.read(buffer, sizeof(buffer));
11✔
450
      if (file.bad()) {
11!
451
        file.close();
×
452
        warnings.push_back("Unable to load OCSP response from " + filename);
×
453
        continue;
×
454
      }
×
455
      content.append(buffer, file.gcount());
11✔
456
    }
11✔
457
    file.close();
11✔
458

459
    try {
11✔
460
      libssl_validate_ocsp_response(content);
11✔
461
      ocspResponses.insert({keyTypes.at(count), std::move(content)});
11✔
462
    }
11✔
463
    catch (const std::exception& e) {
11✔
464
      warnings.push_back("Error checking the validity of OCSP response from '" + filename + "': " + e.what());
3✔
465
      continue;
3✔
466
    }
3✔
467
    ++count;
8✔
468
  }
8✔
469

470
  return ocspResponses;
11✔
471
}
11✔
472

473
#ifdef HAVE_OCSP_BASIC_SIGN
474
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)
475
{
10✔
476
  const EVP_MD* rmd = EVP_sha256();
10✔
477

478
  auto filePtr = pdns::UniqueFilePtr(fopen(certFile.c_str(), "r"));
10✔
479
  if (!filePtr) {
10!
480
    throw std::runtime_error("Unable to open '" + certFile + "' when loading the certificate to generate an OCSP response");
×
481
  }
×
482
  auto cert = std::unique_ptr<X509, void(*)(X509*)>(PEM_read_X509_AUX(filePtr.get(), nullptr, nullptr, nullptr), X509_free);
10✔
483

484
  filePtr = pdns::UniqueFilePtr(fopen(caCert.c_str(), "r"));
10✔
485
  if (!filePtr) {
10!
486
    throw std::runtime_error("Unable to open '" + caCert + "' when loading the issuer certificate to generate an OCSP response");
×
487
  }
×
488
  auto issuer = std::unique_ptr<X509, void(*)(X509*)>(PEM_read_X509_AUX(filePtr.get(), nullptr, nullptr, nullptr), X509_free);
10✔
489
  filePtr = pdns::UniqueFilePtr(fopen(caKey.c_str(), "r"));
10✔
490
  if (!filePtr) {
10!
491
    throw std::runtime_error("Unable to open '" + caKey + "' when loading the issuer key to generate an OCSP response");
×
492
  }
×
493
  auto issuerKey = std::unique_ptr<EVP_PKEY, void(*)(EVP_PKEY*)>(PEM_read_PrivateKey(filePtr.get(), nullptr, nullptr, nullptr), EVP_PKEY_free);
10✔
494
  filePtr.reset();
10✔
495

496
  auto bs = std::unique_ptr<OCSP_BASICRESP, void(*)(OCSP_BASICRESP*)>(OCSP_BASICRESP_new(), OCSP_BASICRESP_free);
10✔
497
  auto thisupd = std::unique_ptr<ASN1_TIME, void(*)(ASN1_TIME*)>(X509_gmtime_adj(nullptr, 0), ASN1_TIME_free);
10✔
498
  auto nextupd = std::unique_ptr<ASN1_TIME, void(*)(ASN1_TIME*)>(X509_time_adj_ex(nullptr, ndays, nmin * 60, nullptr), ASN1_TIME_free);
10✔
499

500
  auto cid = std::unique_ptr<OCSP_CERTID, void(*)(OCSP_CERTID*)>(OCSP_cert_to_id(rmd, cert.get(), issuer.get()), OCSP_CERTID_free);
10✔
501
  OCSP_basic_add1_status(bs.get(), cid.get(), V_OCSP_CERTSTATUS_GOOD, 0, nullptr, thisupd.get(), nextupd.get());
10✔
502

503
  if (OCSP_basic_sign(bs.get(), issuer.get(), issuerKey.get(), rmd, nullptr, OCSP_NOCERTS) != 1) {
10!
504
    throw std::runtime_error("Error while signing the OCSP response");
×
505
  }
×
506

507
  auto resp = std::unique_ptr<OCSP_RESPONSE, void(*)(OCSP_RESPONSE*)>(OCSP_response_create(OCSP_RESPONSE_STATUS_SUCCESSFUL, bs.get()), OCSP_RESPONSE_free);
10✔
508
  auto bio = std::unique_ptr<BIO, void(*)(BIO*)>(BIO_new_file(outFile.c_str(), "wb"), BIO_vfree);
10✔
509
  if (!bio) {
10!
510
    throw std::runtime_error("Error opening file for writing the OCSP response");
×
511
  }
×
512

513
  // i2d_OCSP_RESPONSE_bio(bio.get(), resp.get()) is unusable from C++ because of an invalid cast
514
  ASN1_i2d_bio((i2d_of_void*)i2d_OCSP_RESPONSE, bio.get(), (unsigned char*)resp.get());
10✔
515

516
  return true;
10✔
517
}
10✔
518
#endif /* HAVE_OCSP_BASIC_SIGN */
519
#endif /* DISABLE_OCSP_STAPLING */
520

521
static int libssl_get_last_key_type(std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)>& ctx)
522
{
76✔
523
#ifdef HAVE_SSL_CTX_GET0_PRIVATEKEY
76✔
524
  auto pkey = SSL_CTX_get0_privatekey(ctx.get());
76✔
525
#else
526
  auto temp = std::unique_ptr<SSL, void(*)(SSL*)>(SSL_new(ctx.get()), SSL_free);
527
  if (!temp) {
528
    return -1;
529
  }
530
  auto pkey = SSL_get_privatekey(temp.get());
531
#endif
532

533
  if (!pkey) {
76!
534
    return -1;
×
535
  }
×
536

537
  return EVP_PKEY_base_id(pkey);
76✔
538
}
76✔
539

540
LibsslTLSVersion libssl_tls_version_from_string(const std::string& str)
541
{
×
542
  if (str == "tls1.0") {
×
543
    return LibsslTLSVersion::TLS10;
×
544
  }
×
545
  if (str == "tls1.1") {
×
546
    return LibsslTLSVersion::TLS11;
×
547
  }
×
548
  if (str == "tls1.2") {
×
549
    return LibsslTLSVersion::TLS12;
×
550
  }
×
551
  if (str == "tls1.3") {
×
552
    return LibsslTLSVersion::TLS13;
×
553
  }
×
554
  throw std::runtime_error("Unknown TLS version '" + str);
×
555
}
×
556

557
const std::string& libssl_tls_version_to_string(LibsslTLSVersion version)
558
{
×
559
  static const std::map<LibsslTLSVersion, std::string> versions = {
×
560
    { LibsslTLSVersion::TLS10, "tls1.0" },
×
561
    { LibsslTLSVersion::TLS11, "tls1.1" },
×
562
    { LibsslTLSVersion::TLS12, "tls1.2" },
×
563
    { LibsslTLSVersion::TLS13, "tls1.3" }
×
564
  };
×
565

566
  const auto& it = versions.find(version);
×
567
  if (it == versions.end()) {
×
568
    throw std::runtime_error("Unknown TLS version (" + std::to_string((int)version) + ")");
×
569
  }
×
570
  return it->second;
×
571
}
×
572

573
bool libssl_set_min_tls_version(std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)>& ctx, LibsslTLSVersion version)
574
{
76✔
575
#if defined(HAVE_SSL_CTX_SET_MIN_PROTO_VERSION) || defined(SSL_CTX_set_min_proto_version)
76✔
576
  /* These functions have been introduced in 1.1.0, and the use of SSL_OP_NO_* is deprecated
577
     Warning: SSL_CTX_set_min_proto_version is a function-like macro in OpenSSL */
578
  int vers;
76✔
579
  switch(version) {
76✔
580
  case LibsslTLSVersion::TLS10:
76!
581
    vers = TLS1_VERSION;
76✔
582
    break;
76✔
583
  case LibsslTLSVersion::TLS11:
×
584
    vers = TLS1_1_VERSION;
×
585
    break;
×
586
  case LibsslTLSVersion::TLS12:
×
587
    vers = TLS1_2_VERSION;
×
588
    break;
×
589
  case LibsslTLSVersion::TLS13:
×
590
#ifdef TLS1_3_VERSION
×
591
    vers = TLS1_3_VERSION;
×
592
#else
593
    return false;
594
#endif /* TLS1_3_VERSION */
595
    break;
×
596
  default:
×
597
    return false;
×
598
  }
76✔
599

600
  if (SSL_CTX_set_min_proto_version(ctx.get(), vers) != 1) {
76!
601
    return false;
×
602
  }
×
603
  return true;
76✔
604
#else
605
  long vers = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
606
  switch(version) {
607
  case LibsslTLSVersion::TLS10:
608
    break;
609
  case LibsslTLSVersion::TLS11:
610
    vers |= SSL_OP_NO_TLSv1;
611
    break;
612
  case LibsslTLSVersion::TLS12:
613
    vers |= SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
614
    break;
615
  case LibsslTLSVersion::TLS13:
616
    vers |= SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2;
617
    break;
618
  default:
619
    return false;
620
  }
621

622
  long options = SSL_CTX_get_options(ctx.get());
623
  SSL_CTX_set_options(ctx.get(), options | vers);
624
  return true;
625
#endif
626
}
76✔
627

628
OpenSSLTLSTicketKeysRing::OpenSSLTLSTicketKeysRing(size_t capacity)
629
{
75✔
630
  d_ticketKeys.write_lock()->set_capacity(capacity);
75✔
631
}
75✔
632

633
OpenSSLTLSTicketKeysRing::~OpenSSLTLSTicketKeysRing() = default;
7✔
634

635
void OpenSSLTLSTicketKeysRing::addKey(std::shared_ptr<OpenSSLTLSTicketKey>&& newKey)
636
{
226✔
637
  d_ticketKeys.write_lock()->push_front(std::move(newKey));
226✔
638
  if (TLSCtx::hasTicketsKeyAddedHook()) {
226✔
639
    auto key = d_ticketKeys.read_lock()->front();
2✔
640
    auto keyContent = key->content();
2✔
641
    TLSCtx::getTicketsKeyAddedHook()(keyContent);
2✔
642
    // fills mem with 0's
643
    OPENSSL_cleanse(keyContent.data(), keyContent.size());
2✔
644
  }
2✔
645
}
226✔
646

647
std::shared_ptr<OpenSSLTLSTicketKey> OpenSSLTLSTicketKeysRing::getEncryptionKey()
648
{
706✔
649
  return d_ticketKeys.read_lock()->front();
706✔
650
}
706✔
651

652
std::shared_ptr<OpenSSLTLSTicketKey> OpenSSLTLSTicketKeysRing::getDecryptionKey(unsigned char name[TLS_TICKETS_KEY_NAME_SIZE], bool& activeKey)
653
{
44✔
654
  auto keys = d_ticketKeys.read_lock();
44✔
655
  for (auto& key : *keys) {
128✔
656
    if (key->nameMatches(name)) {
128✔
657
      activeKey = (key == keys->front());
35✔
658
      return key;
35✔
659
    }
35✔
660
  }
128✔
661
  return nullptr;
9✔
662
}
44✔
663

664
size_t OpenSSLTLSTicketKeysRing::getKeysCount()
665
{
6✔
666
  return d_ticketKeys.read_lock()->size();
6✔
667
}
6✔
668

669
void OpenSSLTLSTicketKeysRing::loadTicketsKeys(const std::string& keyFile)
670
{
18✔
671
  bool keyLoaded = false;
18✔
672
  std::ifstream file(keyFile);
18✔
673
  try {
18✔
674
    do {
102✔
675
      auto newKey = std::make_shared<OpenSSLTLSTicketKey>(file);
102✔
676
      addKey(std::move(newKey));
102✔
677
      keyLoaded = true;
102✔
678
    }
102✔
679
    while (!file.fail());
102✔
680
  }
18✔
681
  catch (const std::exception& e) {
18✔
682
    /* if we haven't been able to load at least one key, fail */
683
    if (!keyLoaded) {
18!
684
      throw;
×
685
    }
×
686
  }
18✔
687

688
  file.close();
18✔
689
}
18✔
690

691
void OpenSSLTLSTicketKeysRing::loadTicketsKey(const std::string& key)
692
{
1✔
693
  bool keyLoaded = false;
1✔
694
  try {
1✔
695
    auto newKey = std::make_shared<OpenSSLTLSTicketKey>(key);
1✔
696
    addKey(std::move(newKey));
1✔
697
    keyLoaded = true;
1✔
698
  }
1✔
699
  catch (const std::exception& e) {
1✔
700
    /* if we haven't been able to load at least one key, fail */
701
    if (!keyLoaded) {
×
702
      throw;
×
703
    }
×
704
  }
×
705
}
1✔
706

707
void OpenSSLTLSTicketKeysRing::rotateTicketsKey(time_t /* now */)
708
{
141✔
709
  auto newKey = std::make_shared<OpenSSLTLSTicketKey>();
141✔
710
  addKey(std::move(newKey));
141✔
711
}
141✔
712

713
OpenSSLTLSTicketKey::OpenSSLTLSTicketKey()
714
{
141✔
715
  if (RAND_bytes(d_name, sizeof(d_name)) != 1) {
141!
716
    throw std::runtime_error("Error while generating the name of the OpenSSL TLS ticket key");
×
717
  }
×
718

719
  if (RAND_bytes(d_cipherKey, sizeof(d_cipherKey)) != 1) {
141!
720
    throw std::runtime_error("Error while generating the cipher key of the OpenSSL TLS ticket key");
×
721
  }
×
722

723
  if (RAND_bytes(d_hmacKey, sizeof(d_hmacKey)) != 1) {
141!
724
    throw std::runtime_error("Error while generating the HMAC key of the OpenSSL TLS ticket key");
×
725
  }
×
726
#ifdef HAVE_LIBSODIUM
141✔
727
  sodium_mlock(d_name, sizeof(d_name));
141✔
728
  sodium_mlock(d_cipherKey, sizeof(d_cipherKey));
141✔
729
  sodium_mlock(d_hmacKey, sizeof(d_hmacKey));
141✔
730
#endif /* HAVE_LIBSODIUM */
141✔
731
}
141✔
732

733
OpenSSLTLSTicketKey::OpenSSLTLSTicketKey(std::ifstream& file)
734
{
102✔
735
  file.read(reinterpret_cast<char*>(d_name), sizeof(d_name));
102✔
736
  file.read(reinterpret_cast<char*>(d_cipherKey), sizeof(d_cipherKey));
102✔
737
  file.read(reinterpret_cast<char*>(d_hmacKey), sizeof(d_hmacKey));
102✔
738

739
  if (file.fail()) {
102✔
740
    throw std::runtime_error("Unable to load a ticket key from the OpenSSL tickets key file");
18✔
741
  }
18✔
742
#ifdef HAVE_LIBSODIUM
84✔
743
  sodium_mlock(d_name, sizeof(d_name));
84✔
744
  sodium_mlock(d_cipherKey, sizeof(d_cipherKey));
84✔
745
  sodium_mlock(d_hmacKey, sizeof(d_hmacKey));
84✔
746
#endif /* HAVE_LIBSODIUM */
84✔
747
}
84✔
748

749
OpenSSLTLSTicketKey::OpenSSLTLSTicketKey(const std::string& key)
750
{
1✔
751
  if (key.size() != (sizeof(d_name) + sizeof(d_cipherKey) + sizeof(d_hmacKey))) {
1!
752
    throw std::runtime_error("Unable to load a ticket key from given data");
×
753
  }
×
754
  size_t from = 0;
1✔
755
  memcpy(d_name, &key.at(from), sizeof(d_name));
1✔
756
  from += sizeof(d_name);
1✔
757
  memcpy(d_cipherKey, &key.at(from), sizeof(d_cipherKey));
1✔
758
  from += sizeof(d_cipherKey);
1✔
759
  memcpy(d_hmacKey, &key.at(from), sizeof(d_hmacKey));
1✔
760

761
#ifdef HAVE_LIBSODIUM
1✔
762
  sodium_mlock(d_name, sizeof(d_name));
1✔
763
  sodium_mlock(d_cipherKey, sizeof(d_cipherKey));
1✔
764
  sodium_mlock(d_hmacKey, sizeof(d_hmacKey));
1✔
765
#endif /* HAVE_LIBSODIUM */
1✔
766
}
1✔
767

768
OpenSSLTLSTicketKey::~OpenSSLTLSTicketKey()
769
{
147✔
770
#ifdef HAVE_LIBSODIUM
147✔
771
  sodium_munlock(d_name, sizeof(d_name));
147✔
772
  sodium_munlock(d_cipherKey, sizeof(d_cipherKey));
147✔
773
  sodium_munlock(d_hmacKey, sizeof(d_hmacKey));
147✔
774
#else
775
  OPENSSL_cleanse(d_name, sizeof(d_name));
776
  OPENSSL_cleanse(d_cipherKey, sizeof(d_cipherKey));
777
  OPENSSL_cleanse(d_hmacKey, sizeof(d_hmacKey));
778
#endif /* HAVE_LIBSODIUM */
779
}
147✔
780

781
bool OpenSSLTLSTicketKey::nameMatches(const unsigned char name[TLS_TICKETS_KEY_NAME_SIZE]) const
782
{
128✔
783
  return (memcmp(d_name, name, sizeof(d_name)) == 0);
128✔
784
}
128✔
785

786
std::string OpenSSLTLSTicketKey::content() const
787
{
2✔
788
  std::string result{};
2✔
789
  result.reserve(TLS_TICKETS_KEY_NAME_SIZE + TLS_TICKETS_CIPHER_KEY_SIZE + TLS_TICKETS_MAC_KEY_SIZE);
2✔
790
  // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
791
  result.append(reinterpret_cast<const char*>(d_name), TLS_TICKETS_KEY_NAME_SIZE);
2✔
792
  result.append(reinterpret_cast<const char*>(d_cipherKey), TLS_TICKETS_CIPHER_KEY_SIZE);
2✔
793
  result.append(reinterpret_cast<const char*>(d_hmacKey), TLS_TICKETS_MAC_KEY_SIZE);
2✔
794
  // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
795

796
  return result;
2✔
797
}
2✔
798

799
#if OPENSSL_VERSION_MAJOR >= 3
800
static const std::string sha256KeyName{"sha256"};
801
#endif
802

803
#if OPENSSL_VERSION_MAJOR >= 3
804
int OpenSSLTLSTicketKey::encrypt(unsigned char keyName[TLS_TICKETS_KEY_NAME_SIZE], unsigned char* iv, EVP_CIPHER_CTX* ectx, EVP_MAC_CTX* hctx) const
805
#else
806
int OpenSSLTLSTicketKey::encrypt(unsigned char keyName[TLS_TICKETS_KEY_NAME_SIZE], unsigned char* iv, EVP_CIPHER_CTX* ectx, HMAC_CTX* hctx) const
807
#endif
808
{
706✔
809
  memcpy(keyName, d_name, sizeof(d_name));
706✔
810

811
  if (RAND_bytes(iv, EVP_MAX_IV_LENGTH) != 1) {
706!
812
    return -1;
×
813
  }
×
814

815
  if (EVP_EncryptInit_ex(ectx, TLS_TICKETS_CIPHER_ALGO(), nullptr, d_cipherKey, iv) != 1) {
706!
816
    return -1;
×
817
  }
×
818

819
#if OPENSSL_VERSION_MAJOR >= 3
706✔
820
  using ParamsBuilder = std::unique_ptr<OSSL_PARAM_BLD, decltype(&OSSL_PARAM_BLD_free)>;
706✔
821
  using Params = std::unique_ptr<OSSL_PARAM, decltype(&OSSL_PARAM_free)>;
706✔
822

823
  auto params_build = ParamsBuilder(OSSL_PARAM_BLD_new(), OSSL_PARAM_BLD_free);
706✔
824
  if (params_build == nullptr) {
706!
825
    return -1;
×
826
  }
×
827

828
  if (OSSL_PARAM_BLD_push_utf8_string(params_build.get(), OSSL_MAC_PARAM_DIGEST, sha256KeyName.c_str(), sha256KeyName.size()) == 0) {
706!
829
    return -1;
×
830
  }
×
831

832
  auto params = Params(OSSL_PARAM_BLD_to_param(params_build.get()), OSSL_PARAM_free);
706✔
833
  if (params == nullptr) {
706!
834
    return -1;
×
835
  }
×
836

837
  if (EVP_MAC_CTX_set_params(hctx, params.get()) == 0) {
706!
838
    return -1;
×
839
  }
×
840

841
  if (EVP_MAC_init(hctx, d_hmacKey, sizeof(d_hmacKey), nullptr) == 0) {
706!
842
    return -1;
×
843
  }
×
844
#else
845
  if (HMAC_Init_ex(hctx, d_hmacKey, sizeof(d_hmacKey), TLS_TICKETS_MAC_ALGO(), nullptr) != 1) {
846
    return -1;
847
  }
848
#endif
849

850
  return 1;
706✔
851
}
706✔
852

853
#if OPENSSL_VERSION_MAJOR >= 3
854
bool OpenSSLTLSTicketKey::decrypt(const unsigned char* iv, EVP_CIPHER_CTX* ectx, EVP_MAC_CTX* hctx) const
855
#else
856
bool OpenSSLTLSTicketKey::decrypt(const unsigned char* iv, EVP_CIPHER_CTX* ectx, HMAC_CTX* hctx) const
857
#endif
858
{
35✔
859
#if OPENSSL_VERSION_MAJOR >= 3
35✔
860
  using ParamsBuilder = std::unique_ptr<OSSL_PARAM_BLD, decltype(&OSSL_PARAM_BLD_free)>;
35✔
861
  using Params = std::unique_ptr<OSSL_PARAM, decltype(&OSSL_PARAM_free)>;
35✔
862

863
  auto params_build = ParamsBuilder(OSSL_PARAM_BLD_new(), OSSL_PARAM_BLD_free);
35✔
864
  if (params_build == nullptr) {
35!
865
    return false;
×
866
  }
×
867

868
  if (OSSL_PARAM_BLD_push_utf8_string(params_build.get(), OSSL_MAC_PARAM_DIGEST, sha256KeyName.c_str(), sha256KeyName.size()) == 0) {
35!
869
    return false;
×
870
  }
×
871

872
  auto params = Params(OSSL_PARAM_BLD_to_param(params_build.get()), OSSL_PARAM_free);
35✔
873
  if (params == nullptr) {
35!
874
    return false;
×
875
  }
×
876

877
  if (EVP_MAC_CTX_set_params(hctx, params.get()) == 0) {
35!
878
    return false;
×
879
  }
×
880

881
  if (EVP_MAC_init(hctx, d_hmacKey, sizeof(d_hmacKey), nullptr) == 0) {
35!
882
    return false;
×
883
  }
×
884
#else
885
  if (HMAC_Init_ex(hctx, d_hmacKey, sizeof(d_hmacKey), TLS_TICKETS_MAC_ALGO(), nullptr) != 1) {
886
    return false;
887
  }
888
#endif
889

890
  if (EVP_DecryptInit_ex(ectx, TLS_TICKETS_CIPHER_ALGO(), nullptr, d_cipherKey, iv) != 1) {
35!
891
    return false;
×
892
  }
×
893

894
  return true;
35✔
895
}
35✔
896

897
std::pair<std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)>, std::vector<std::string>> libssl_init_server_context(const TLSConfig& config,
898
                                                                                                                  std::map<int, std::string>& ocspResponses)
899
{
76✔
900
  std::vector<std::string> warnings;
76✔
901
  auto ctx = std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)>(SSL_CTX_new(SSLv23_server_method()), SSL_CTX_free);
76✔
902

903
  if (!ctx) {
76!
904
    throw pdns::OpenSSL::error("Error creating an OpenSSL server context");
×
905
  }
×
906

907
  int sslOptions =
76✔
908
    SSL_OP_NO_SSLv2 |
76✔
909
    SSL_OP_NO_SSLv3 |
76✔
910
    SSL_OP_NO_COMPRESSION |
76✔
911
    SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
76✔
912
    SSL_OP_SINGLE_DH_USE |
76✔
913
    SSL_OP_SINGLE_ECDH_USE;
76✔
914

915
  if (!config.d_enableTickets || config.d_numberOfTicketsKeys == 0) {
76!
916
    /* for TLS 1.3 this means no stateless tickets, but stateful tickets might still be issued,
917
       which is something we don't want. */
918
    sslOptions |= SSL_OP_NO_TICKET;
3✔
919
    /* really disable all tickets */
920
#ifdef HAVE_SSL_CTX_SET_NUM_TICKETS
3✔
921
    SSL_CTX_set_num_tickets(ctx.get(), 0);
3✔
922
#endif /* HAVE_SSL_CTX_SET_NUM_TICKETS */
3✔
923
  }
3✔
924

925
  if (config.d_ktls) {
76!
926
#ifdef SSL_OP_ENABLE_KTLS
×
927
    sslOptions |= SSL_OP_ENABLE_KTLS;
×
928
#endif /* SSL_OP_ENABLE_KTLS */
×
929
  }
×
930

931
  if (config.d_sessionTimeout > 0) {
76!
932
    SSL_CTX_set_timeout(ctx.get(), config.d_sessionTimeout);
×
933
  }
×
934

935
  if (config.d_preferServerCiphers) {
76!
936
    sslOptions |= SSL_OP_CIPHER_SERVER_PREFERENCE;
76✔
937
#ifdef SSL_OP_PRIORITIZE_CHACHA
76✔
938
    sslOptions |= SSL_OP_PRIORITIZE_CHACHA;
76✔
939
#endif /* SSL_OP_PRIORITIZE_CHACHA */
76✔
940
  }
76✔
941

942
  if (!config.d_enableRenegotiation) {
76!
943
#ifdef SSL_OP_NO_RENEGOTIATION
76✔
944
    sslOptions |= SSL_OP_NO_RENEGOTIATION;
76✔
945
#elif defined(SSL_OP_NO_CLIENT_RENEGOTIATION)
946
    sslOptions |= SSL_OP_NO_CLIENT_RENEGOTIATION;
947
#endif
948
  }
76✔
949

950
#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF
76✔
951
  sslOptions |= SSL_OP_IGNORE_UNEXPECTED_EOF;
76✔
952
#endif
76✔
953

954
  SSL_CTX_set_options(ctx.get(), sslOptions);
76✔
955
  if (!libssl_set_min_tls_version(ctx, config.d_minTLSVersion)) {
76!
956
    throw std::runtime_error("Failed to set the minimum version to '" + libssl_tls_version_to_string(config.d_minTLSVersion));
×
957
  }
×
958

959
#ifdef SSL_CTX_set_ecdh_auto
76✔
960
  SSL_CTX_set_ecdh_auto(ctx.get(), 1);
76✔
961
#endif
76✔
962

963
  if (config.d_maxStoredSessions == 0) {
76✔
964
    /* disable stored sessions entirely */
965
    SSL_CTX_set_session_cache_mode(ctx.get(), SSL_SESS_CACHE_OFF);
3✔
966
  }
3✔
967
  else {
73✔
968
    /* use the internal built-in cache to store sessions */
969
    SSL_CTX_set_session_cache_mode(ctx.get(), SSL_SESS_CACHE_SERVER);
73✔
970
    SSL_CTX_sess_set_cache_size(ctx.get(), config.d_maxStoredSessions);
73✔
971
  }
73✔
972

973
  long mode = 0;
76✔
974
#ifdef SSL_MODE_RELEASE_BUFFERS
76✔
975
  if (config.d_releaseBuffers) {
76!
976
    mode |= SSL_MODE_RELEASE_BUFFERS;
76✔
977
  }
76✔
978
#endif
76✔
979

980
  if (config.d_asyncMode) {
76!
981
#ifdef SSL_MODE_ASYNC
×
982
    mode |= SSL_MODE_ASYNC;
×
983
#else
984
    warnings.push_back("Warning: TLS async mode requested but not supported");
985
#endif
986
  }
×
987

988
  SSL_CTX_set_mode(ctx.get(), mode);
76✔
989

990
  /* we need to set this callback to acknowledge the server name sent by the client,
991
     otherwise it will not stored in the session and will not be accessible when the
992
     session is resumed, causing SSL_get_servername to return nullptr */
993
  SSL_CTX_set_tlsext_servername_callback(ctx.get(), &libssl_server_name_callback);
76✔
994

995
  std::vector<int> keyTypes;
76✔
996
  /* load certificate and private key */
997
  for (const auto& pair : config.d_certKeyPairs) {
76✔
998
    if (!pair.d_key) {
76✔
999
#if defined(HAVE_SSL_CTX_USE_CERT_AND_KEY)
4✔
1000
      // If no separate key is given, treat it as a pkcs12 file
1001
      auto filePtr = pdns::UniqueFilePtr(fopen(pair.d_cert.c_str(), "r"));
4✔
1002
      if (!filePtr) {
4!
1003
        throw std::runtime_error("Unable to open file " + pair.d_cert);
×
1004
      }
×
1005
      auto p12 = std::unique_ptr<PKCS12, void(*)(PKCS12*)>(d2i_PKCS12_fp(filePtr.get(), nullptr), PKCS12_free);
4✔
1006
      if (!p12) {
4!
1007
        throw std::runtime_error("Unable to open PKCS12 file " + pair.d_cert);
×
1008
      }
×
1009
      EVP_PKEY *keyptr = nullptr;
4✔
1010
      X509 *certptr = nullptr;
4✔
1011
      STACK_OF(X509) *captr = nullptr;
4✔
1012
      if (!PKCS12_parse(p12.get(), (pair.d_password ? pair.d_password->c_str() : nullptr), &keyptr, &certptr, &captr)) {
4!
1013
#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
×
1014
        bool failed = true;
×
1015
        /* we might be opening a PKCS12 file that uses RC2 CBC or 3DES CBC which, since OpenSSL 3.0.0, requires loading the legacy provider */
1016
        auto libCtx = OSSL_LIB_CTX_get0_global_default();
×
1017
        /* check whether the legacy provider is already loaded */
1018
        if (!OSSL_PROVIDER_available(libCtx, "legacy")) {
×
1019
          /* it's not */
1020
          auto provider = OSSL_PROVIDER_load(libCtx, "legacy");
×
1021
          if (provider != nullptr) {
×
1022
            if (PKCS12_parse(p12.get(), (pair.d_password ? pair.d_password->c_str() : nullptr), &keyptr, &certptr, &captr)) {
×
1023
              failed = false;
×
1024
            }
×
1025
            /* we do not want to keep that provider around after that */
1026
            OSSL_PROVIDER_unload(provider);
×
1027
          }
×
1028
        }
×
1029
        if (failed) {
×
1030
#endif /* defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 */
×
1031
          ERR_print_errors_fp(stderr);
×
1032
          throw std::runtime_error("An error occured while parsing PKCS12 file " + pair.d_cert);
×
1033
#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
×
1034
        }
×
1035
#endif /* defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 */
×
1036
      }
×
1037
      auto key = std::unique_ptr<EVP_PKEY, void(*)(EVP_PKEY*)>(keyptr, EVP_PKEY_free);
4✔
1038
      auto cert = std::unique_ptr<X509, void(*)(X509*)>(certptr, X509_free);
4✔
1039
      auto ca = std::unique_ptr<STACK_OF(X509), void(*)(STACK_OF(X509)*)>(captr, [](STACK_OF(X509)* st){ sk_X509_free(st); });
4✔
1040

1041
      if (SSL_CTX_use_cert_and_key(ctx.get(), cert.get(), key.get(), ca.get(), 1) != 1) {
4!
1042
        ERR_print_errors_fp(stderr);
×
1043
        throw std::runtime_error("An error occurred while trying to load the TLS certificate and key from PKCS12 file " + pair.d_cert);
×
1044
      }
×
1045
#else
1046
      throw std::runtime_error("PKCS12 files are not supported by your openssl version");
1047
#endif /* HAVE_SSL_CTX_USE_CERT_AND_KEY */
1048
    } else {
72✔
1049
      if (SSL_CTX_use_certificate_chain_file(ctx.get(), pair.d_cert.c_str()) != 1) {
72!
1050
        ERR_print_errors_fp(stderr);
×
1051
        throw std::runtime_error("An error occurred while trying to load the TLS server certificate file: " + pair.d_cert);
×
1052
      }
×
1053
      if (SSL_CTX_use_PrivateKey_file(ctx.get(), pair.d_key->c_str(), SSL_FILETYPE_PEM) != 1) {
72!
1054
        ERR_print_errors_fp(stderr);
×
1055
        throw std::runtime_error("An error occurred while trying to load the TLS server private key file: " + pair.d_key.value());
×
1056
      }
×
1057
    }
72✔
1058
    if (SSL_CTX_check_private_key(ctx.get()) != 1) {
76!
1059
      ERR_print_errors_fp(stderr);
×
1060
      throw std::runtime_error("The key from '" + pair.d_key.value() + "' does not match the certificate from '" + pair.d_cert + "'");
×
1061
    }
×
1062
    /* store the type of the new key, we might need it later to select the right OCSP stapling response */
1063
    auto keyType = libssl_get_last_key_type(ctx);
76✔
1064
    if (keyType < 0) {
76!
1065
      throw std::runtime_error("The key from '" + pair.d_key.value() + "' has an unknown type");
×
1066
    }
×
1067
    keyTypes.push_back(keyType);
76✔
1068
 }
76✔
1069

1070
#ifndef DISABLE_OCSP_STAPLING
76✔
1071
  if (!config.d_ocspFiles.empty()) {
76✔
1072
    try {
11✔
1073
      ocspResponses = libssl_load_ocsp_responses(config.d_ocspFiles, std::move(keyTypes), warnings);
11✔
1074
    }
11✔
1075
    catch(const std::exception& e) {
11✔
1076
      throw std::runtime_error("Unable to load OCSP responses: " + std::string(e.what()));
×
1077
    }
×
1078
  }
11✔
1079
#endif /* DISABLE_OCSP_STAPLING */
76✔
1080

1081
  if (!config.d_ciphers.empty() && SSL_CTX_set_cipher_list(ctx.get(), config.d_ciphers.c_str()) != 1) {
76!
1082
    throw std::runtime_error("The TLS ciphers could not be set: " + config.d_ciphers);
×
1083
  }
×
1084

1085
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
76✔
1086
  if (!config.d_ciphers13.empty() && SSL_CTX_set_ciphersuites(ctx.get(), config.d_ciphers13.c_str()) != 1) {
76!
1087
    throw std::runtime_error("The TLS 1.3 ciphers could not be set: " + config.d_ciphers13);
×
1088
  }
×
1089
#endif /* HAVE_SSL_CTX_SET_CIPHERSUITES */
76✔
1090

1091
  return {std::move(ctx), std::move(warnings)};
76✔
1092
}
76✔
1093

1094
#ifdef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK
1095
static void libssl_key_log_file_callback(const SSL* ssl, const char* line)
1096
{
80✔
1097
  SSL_CTX* sslCtx = SSL_get_SSL_CTX(ssl);
80✔
1098
  if (sslCtx == nullptr) {
80!
1099
    return;
×
1100
  }
×
1101

1102
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): OpenSSL's API
1103
  auto* filePtr = reinterpret_cast<FILE*>(SSL_CTX_get_ex_data(sslCtx, s_keyLogIndex));
80✔
1104
  if (filePtr == nullptr) {
80!
1105
    return;
×
1106
  }
×
1107

1108
  fprintf(filePtr, "%s\n", line);
80✔
1109
  fflush(filePtr);
80✔
1110
}
80✔
1111
#endif /* HAVE_SSL_CTX_SET_KEYLOG_CALLBACK */
1112

1113
pdns::UniqueFilePtr libssl_set_key_log_file(SSL_CTX* ctx, const std::string& logFile)
1114
{
4✔
1115
#ifdef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK
4✔
1116
  auto filePtr = pdns::openFileForWriting(logFile, 0600, false, true);
4✔
1117
  if (!filePtr) {
4!
1118
    auto error = errno;
×
1119
    throw std::runtime_error("Error opening file " + logFile + " for writing: " + stringerror(error));
×
1120
  }
×
1121
  SSL_CTX_set_ex_data(ctx, s_keyLogIndex, filePtr.get());
4✔
1122
  SSL_CTX_set_keylog_callback(ctx, &libssl_key_log_file_callback);
4✔
1123
  return filePtr;
4✔
1124
#else
1125
  return pdns::UniqueFilePtr(nullptr);
1126
#endif /* HAVE_SSL_CTX_SET_KEYLOG_CALLBACK */
1127
}
4✔
1128

1129
/* called in a client context, if the client advertised more than one ALPN value and the server returned more than one as well, to select the one to use. */
1130
void libssl_set_alpn_select_callback(SSL_CTX* ctx, int (*cb)(SSL* s, const unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen, void* arg), void* arg)
1131
{
52✔
1132
#ifdef HAVE_SSL_CTX_SET_ALPN_SELECT_CB
52✔
1133
  SSL_CTX_set_alpn_select_cb(ctx, cb, arg);
52✔
1134
#endif
52✔
1135
}
52✔
1136

1137
bool libssl_set_alpn_protos(SSL_CTX* ctx, const std::vector<std::vector<uint8_t>>& protos)
1138
{
29✔
1139
#ifdef HAVE_SSL_CTX_SET_ALPN_PROTOS
29✔
1140
  std::vector<uint8_t> wire;
29✔
1141
  for (const auto& proto : protos) {
29✔
1142
    if (proto.size() > std::numeric_limits<uint8_t>::max()) {
18!
1143
      throw std::runtime_error("Invalid ALPN value");
×
1144
    }
×
1145
    uint8_t length = proto.size();
18✔
1146
    wire.push_back(length);
18✔
1147
    wire.insert(wire.end(), proto.begin(), proto.end());
18✔
1148
  }
18✔
1149
  return SSL_CTX_set_alpn_protos(ctx, wire.data(), wire.size()) == 0;
29✔
1150
#else
1151
  return false;
1152
#endif
1153
}
29✔
1154

1155

1156
std::string libssl_get_error_string()
1157
{
1✔
1158
  BIO *mem = BIO_new(BIO_s_mem());
1✔
1159
  ERR_print_errors(mem);
1✔
1160
  char *p;
1✔
1161
  size_t len = BIO_get_mem_data(mem, &p);
1✔
1162
  std::string msg(p, len);
1✔
1163
  // replace newlines by /
1164
  if (msg.back() == '\n') {
1!
1165
    msg.pop_back();
1✔
1166
  }
1✔
1167
  std::replace(msg.begin(), msg.end(), '\n', '/');
1✔
1168
  BIO_free(mem);
1✔
1169
  return msg;
1✔
1170
}
1✔
1171
#endif /* HAVE_LIBSSL */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc