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

PowerDNS / pdns / 19741624072

27 Nov 2025 03:45PM UTC coverage: 73.086% (+0.02%) from 73.065%
19741624072

Pull #16570

github

web-flow
Merge 08a2cdb1d into f94a3f63f
Pull Request #16570: rec: rewrite all unwrap calls in web.rs

38523 of 63408 branches covered (60.75%)

Branch coverage included in aggregate %.

128044 of 164496 relevant lines covered (77.84%)

6531485.83 hits per line

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

63.43
/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 <openssl/x509v3.h>
32
#include <fcntl.h>
33

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

143
    s_countersIndex = SSL_CTX_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
95✔
144

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

149
    s_keyLogIndex = SSL_CTX_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
95✔
150

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

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

170
    EVP_cleanup();
171

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

176
    CRYPTO_cleanup_all_ex_data();
177
    openssl_thread_cleanup();
178
#endif
179
  }
18✔
180
}
37✔
181

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

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

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

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

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

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

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

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

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

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

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

255
  return SSL_CTX_get_ex_data(sslCtx, s_ticketsKeyIndex);
1,667✔
256
}
1,667✔
257

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

263
#if OPENSSL_VERSION_MAJOR >= 3
264
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)
265
#else
266
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)
267
#endif
268
{
1,119✔
269
  if (enc != 0) {
1,119✔
270
    const auto key = keyring.getEncryptionKey();
864✔
271
    if (key == nullptr) {
864!
272
      return -1;
×
273
    }
×
274

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

278
  bool activeEncryptionKey = false;
255✔
279

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

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

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

295
  return 1;
234✔
296
}
246✔
297

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

304
  return SSL_TLSEXT_ERR_NOACK;
×
305
}
131✔
306

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

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

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

357
void libssl_set_error_counters_callback(SSL_CTX& ctx, TLSErrorCounters* counters)
358
{
172✔
359
  SSL_CTX_set_ex_data(&ctx, s_countersIndex, counters);
172✔
360
  SSL_CTX_set_info_callback(&ctx, libssl_info_callback);
172✔
361
}
172✔
362

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

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

377
  const auto ocsp_resp_size = data->second.size();
6✔
378
  /* the behaviour is alas different in 3.6.0 because of a regression introduced in b1b4b154fd389ac6254d49cfb11aee36c1c51b84:
379
     the value passed to SSL_set_tlsext_status_ocsp_resp() is not freed in 3.6.0 as it is in all other OpenSSL versions.
380
     See https://github.com/openssl/openssl/issues/28888 */
381
#if OPENSSL_VERSION_NUMBER != 0x30600000L
6✔
382
  /* we need to allocate a copy because OpenSSL will free the pointer passed to SSL_set_tlsext_status_ocsp_resp() */
383
  void* ocsp_resp = OPENSSL_malloc(ocsp_resp_size);
6✔
384
  if (ocsp_resp == nullptr) {
6!
385
    return SSL_TLSEXT_ERR_NOACK;
×
386
  }
×
387

388
  memcpy(ocsp_resp, data->second.data(), ocsp_resp_size);
6✔
389
#else
390
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast): the parameter is not freed in this version (3.6.0, see above) but the parameter is not marked const.
391
  void* ocsp_resp = const_cast<char*>(data->second.data());
392
#endif
393
  SSL_set_tlsext_status_ocsp_resp(ssl, ocsp_resp, ocsp_resp_size);
6✔
394
  return SSL_TLSEXT_ERR_OK;
6✔
395
}
6✔
396

397
static bool libssl_validate_ocsp_response(const std::string& response)
398
{
11✔
399
  auto responsePtr = reinterpret_cast<const unsigned char *>(response.data());
11✔
400
  std::unique_ptr<OCSP_RESPONSE, void(*)(OCSP_RESPONSE*)> resp(d2i_OCSP_RESPONSE(nullptr, &responsePtr, response.size()), OCSP_RESPONSE_free);
11✔
401
  if (resp == nullptr) {
11✔
402
    throw std::runtime_error("Unable to parse OCSP response");
3✔
403
  }
3✔
404

405
  int status = OCSP_response_status(resp.get());
8✔
406
  if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
8!
407
    throw std::runtime_error("OCSP response status is not successful: " + std::to_string(status));
×
408
  }
×
409

410
  std::unique_ptr<OCSP_BASICRESP, void(*)(OCSP_BASICRESP*)> basic(OCSP_response_get1_basic(resp.get()), OCSP_BASICRESP_free);
8✔
411
  if (basic == nullptr) {
8!
412
    throw std::runtime_error("Error getting a basic OCSP response");
×
413
  }
×
414

415
  if (OCSP_resp_count(basic.get()) != 1) {
8!
416
    throw std::runtime_error("More than one single response in an OCSP basic response");
×
417
  }
×
418

419
  auto singleResponse = OCSP_resp_get0(basic.get(), 0);
8✔
420
  if (singleResponse == nullptr) {
8!
421
    throw std::runtime_error("Error getting a single response from the basic OCSP response");
×
422
  }
×
423

424
  int reason;
8✔
425
  ASN1_GENERALIZEDTIME* revTime = nullptr;
8✔
426
  ASN1_GENERALIZEDTIME* thisUpdate = nullptr;
8✔
427
  ASN1_GENERALIZEDTIME* nextUpdate = nullptr;
8✔
428

429
  auto singleResponseStatus = OCSP_single_get0_status(singleResponse, &reason, &revTime, &thisUpdate, &nextUpdate);
8✔
430
  if (singleResponseStatus != V_OCSP_CERTSTATUS_GOOD) {
8!
431
    throw std::runtime_error("Invalid status for OCSP single response (" + std::to_string(singleResponseStatus) + ")");
×
432
  }
×
433
  if (thisUpdate == nullptr || nextUpdate == nullptr) {
8!
434
    throw std::runtime_error("Error getting validity of OCSP single response");
×
435
  }
×
436

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

442
  return true;
8✔
443
}
8✔
444

445
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)
446
{
11✔
447
  std::map<int, std::string> ocspResponses;
11✔
448

449
  if (ocspFiles.size() > keyTypes.size()) {
11!
450
    throw std::runtime_error("More OCSP files than certificates and keys loaded!");
×
451
  }
×
452

453
  size_t count = 0;
11✔
454
  for (const auto& filename : ocspFiles) {
11✔
455
    std::ifstream file(filename, std::ios::binary);
11✔
456
    std::string content;
11✔
457
    while (file) {
22✔
458
      char buffer[4096];
11✔
459
      file.read(buffer, sizeof(buffer));
11✔
460
      if (file.bad()) {
11!
461
        file.close();
×
462
        warnings.push_back("Unable to load OCSP response from " + filename);
×
463
        continue;
×
464
      }
×
465
      content.append(buffer, file.gcount());
11✔
466
    }
11✔
467
    file.close();
11✔
468

469
    try {
11✔
470
      libssl_validate_ocsp_response(content);
11✔
471
      ocspResponses.insert({keyTypes.at(count), std::move(content)});
11✔
472
    }
11✔
473
    catch (const std::exception& e) {
11✔
474
      warnings.push_back("Error checking the validity of OCSP response from '" + filename + "': " + e.what());
3✔
475
      continue;
3✔
476
    }
3✔
477
    ++count;
8✔
478
  }
8✔
479

480
  return ocspResponses;
11✔
481
}
11✔
482

483
#ifdef HAVE_OCSP_BASIC_SIGN
484
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)
485
{
10✔
486
  const EVP_MD* rmd = EVP_sha256();
10✔
487

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

494
  filePtr = pdns::UniqueFilePtr(fopen(caCert.c_str(), "r"));
10✔
495
  if (!filePtr) {
10!
496
    throw std::runtime_error("Unable to open '" + caCert + "' when loading the issuer certificate to generate an OCSP response");
×
497
  }
×
498
  auto issuer = std::unique_ptr<X509, void(*)(X509*)>(PEM_read_X509_AUX(filePtr.get(), nullptr, nullptr, nullptr), X509_free);
10✔
499
  filePtr = pdns::UniqueFilePtr(fopen(caKey.c_str(), "r"));
10✔
500
  if (!filePtr) {
10!
501
    throw std::runtime_error("Unable to open '" + caKey + "' when loading the issuer key to generate an OCSP response");
×
502
  }
×
503
  auto issuerKey = std::unique_ptr<EVP_PKEY, void(*)(EVP_PKEY*)>(PEM_read_PrivateKey(filePtr.get(), nullptr, nullptr, nullptr), EVP_PKEY_free);
10✔
504
  filePtr.reset();
10✔
505

506
  auto bs = std::unique_ptr<OCSP_BASICRESP, void(*)(OCSP_BASICRESP*)>(OCSP_BASICRESP_new(), OCSP_BASICRESP_free);
10✔
507
  auto thisupd = std::unique_ptr<ASN1_TIME, void(*)(ASN1_TIME*)>(X509_gmtime_adj(nullptr, 0), ASN1_TIME_free);
10✔
508
  auto nextupd = std::unique_ptr<ASN1_TIME, void(*)(ASN1_TIME*)>(X509_time_adj_ex(nullptr, ndays, nmin * 60, nullptr), ASN1_TIME_free);
10✔
509

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

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

517
  auto resp = std::unique_ptr<OCSP_RESPONSE, void(*)(OCSP_RESPONSE*)>(OCSP_response_create(OCSP_RESPONSE_STATUS_SUCCESSFUL, bs.get()), OCSP_RESPONSE_free);
10✔
518
  auto bio = std::unique_ptr<BIO, void(*)(BIO*)>(BIO_new_file(outFile.c_str(), "wb"), BIO_vfree);
10✔
519
  if (!bio) {
10!
520
    throw std::runtime_error("Error opening file for writing the OCSP response");
×
521
  }
×
522

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

526
  return true;
10✔
527
}
10✔
528
#endif /* HAVE_OCSP_BASIC_SIGN */
529
#endif /* DISABLE_OCSP_STAPLING */
530

531
static int libssl_get_last_key_type(SSL_CTX& ctx)
532
{
101✔
533
#ifdef HAVE_SSL_CTX_GET0_PRIVATEKEY
101✔
534
  auto* pkey = SSL_CTX_get0_privatekey(&ctx);
101✔
535
#else
536
  auto temp = std::unique_ptr<SSL, void(*)(SSL*)>(SSL_new(&ctx), SSL_free);
537
  if (!temp) {
538
    return -1;
539
  }
540
  auto pkey = SSL_get_privatekey(temp.get());
541
#endif
542

543
  if (!pkey) {
101!
544
    return -1;
×
545
  }
×
546

547
  return EVP_PKEY_base_id(pkey);
101✔
548
}
101✔
549

550
struct StackOfNamesDeleter
551
{
552
  void operator()(STACK_OF(GENERAL_NAME)* ptr) const noexcept {
77✔
553
    sk_GENERAL_NAME_pop_free(ptr, GENERAL_NAME_free);
77✔
554
  }
77✔
555
};
556

557
#if defined(OPENSSL_IS_BORINGSSL)
558
/* return type of OpenSSL's sk_XXX_num() */
559
using SSLStackIndex = size_t;
560
#else
561
using SSLStackIndex = int;
562
#endif
563

564
static std::unordered_set<std::string> get_names_from_certificate(const X509* certificate)
565
{
77✔
566
  std::unordered_set<std::string> result;
77✔
567
  auto names = std::unique_ptr<STACK_OF(GENERAL_NAME), StackOfNamesDeleter>(static_cast<STACK_OF(GENERAL_NAME)*>(X509_get_ext_d2i(certificate, NID_subject_alt_name, nullptr, nullptr)));
77✔
568
  if (names) {
77!
569
    for (SSLStackIndex idx = 0; idx < sk_GENERAL_NAME_num(names.get()); idx++) {
306✔
570
      const auto* name = sk_GENERAL_NAME_value(names.get(), idx);
229✔
571
      if (name->type != GEN_DNS) {
229✔
572
        /* ignore GEN_IPADD / name->d.iPAddress (raw IP address bytes), it cannot be used in SNI anyway */
573
        continue;
77✔
574
      }
77✔
575
      unsigned char* str = nullptr;
152✔
576
      if (ASN1_STRING_to_UTF8(&str, name->d.dNSName) < 0) {
152!
577
        continue;
×
578
      }
×
579
      // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): OpenSSL's API
580
      result.emplace(reinterpret_cast<const char*>(str));
152✔
581
      OPENSSL_free(str);
152✔
582
    }
152✔
583
  }
77✔
584

585
  auto* name = X509_get_subject_name(certificate);
77✔
586
  if (name != nullptr) {
77!
587
    int idx = -1;
77✔
588
    while ((idx = X509_NAME_get_index_by_NID(name, NID_commonName, idx)) != -1) {
154✔
589
      const auto* entry = X509_NAME_get_entry(name, idx);
77✔
590
      const auto* value = X509_NAME_ENTRY_get_data(entry);
77✔
591
      unsigned char* str = nullptr;
77✔
592
      if (ASN1_STRING_to_UTF8(&str, value) < 0) {
77!
593
        continue;
×
594
      }
×
595
      // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): OpenSSL's API
596
      result.emplace(reinterpret_cast<const char*>(str));
77✔
597
      OPENSSL_free(str);
77✔
598
    }
77✔
599
  }
77✔
600

601
  return result;
77✔
602
}
77✔
603

604
static std::unordered_set<std::string> get_names_from_last_certificate(const SSL_CTX& ctx)
605
{
77✔
606
  const auto* cert = SSL_CTX_get0_certificate(&ctx);
77✔
607
  if (cert == nullptr) {
77!
608
    return {};
×
609
  }
×
610

611
  return get_names_from_certificate(cert);
77✔
612
}
77✔
613

614
LibsslTLSVersion libssl_tls_version_from_string(const std::string& str)
615
{
44✔
616
  if (str == "tls1.0") {
44!
617
    return LibsslTLSVersion::TLS10;
44✔
618
  }
44✔
619
  if (str == "tls1.1") {
×
620
    return LibsslTLSVersion::TLS11;
×
621
  }
×
622
  if (str == "tls1.2") {
×
623
    return LibsslTLSVersion::TLS12;
×
624
  }
×
625
  if (str == "tls1.3") {
×
626
    return LibsslTLSVersion::TLS13;
×
627
  }
×
628
  throw std::runtime_error("Unknown TLS version '" + str + "'");
×
629
}
×
630

631
const std::string& libssl_tls_version_to_string(LibsslTLSVersion version)
632
{
×
633
  static const std::map<LibsslTLSVersion, std::string> versions = {
×
634
    { LibsslTLSVersion::TLS10, "tls1.0" },
×
635
    { LibsslTLSVersion::TLS11, "tls1.1" },
×
636
    { LibsslTLSVersion::TLS12, "tls1.2" },
×
637
    { LibsslTLSVersion::TLS13, "tls1.3" }
×
638
  };
×
639

640
  const auto& it = versions.find(version);
×
641
  if (it == versions.end()) {
×
642
    throw std::runtime_error("Unknown TLS version (" + std::to_string((int)version) + ")");
×
643
  }
×
644
  return it->second;
×
645
}
×
646

647
static bool libssl_set_min_tls_version(SSL_CTX& ctx, LibsslTLSVersion version)
648
{
101✔
649
#if defined(HAVE_SSL_CTX_SET_MIN_PROTO_VERSION) || defined(SSL_CTX_set_min_proto_version)
101✔
650
  /* These functions have been introduced in 1.1.0, and the use of SSL_OP_NO_* is deprecated
651
     Warning: SSL_CTX_set_min_proto_version is a function-like macro in OpenSSL */
652
  int vers;
101✔
653
  switch(version) {
101✔
654
  case LibsslTLSVersion::TLS10:
101!
655
    vers = TLS1_VERSION;
101✔
656
    break;
101✔
657
  case LibsslTLSVersion::TLS11:
×
658
    vers = TLS1_1_VERSION;
×
659
    break;
×
660
  case LibsslTLSVersion::TLS12:
×
661
    vers = TLS1_2_VERSION;
×
662
    break;
×
663
  case LibsslTLSVersion::TLS13:
×
664
#ifdef TLS1_3_VERSION
×
665
    vers = TLS1_3_VERSION;
×
666
#else
667
    return false;
668
#endif /* TLS1_3_VERSION */
669
    break;
×
670
  default:
×
671
    return false;
×
672
  }
101✔
673

674
  if (SSL_CTX_set_min_proto_version(&ctx, vers) != 1) {
101!
675
    return false;
×
676
  }
×
677
  return true;
101✔
678
#else
679
  long vers = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
680
  switch(version) {
681
  case LibsslTLSVersion::TLS10:
682
    break;
683
  case LibsslTLSVersion::TLS11:
684
    vers |= SSL_OP_NO_TLSv1;
685
    break;
686
  case LibsslTLSVersion::TLS12:
687
    vers |= SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
688
    break;
689
  case LibsslTLSVersion::TLS13:
690
    vers |= SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2;
691
    break;
692
  default:
693
    return false;
694
  }
695

696
  long options = SSL_CTX_get_options(&ctx);
697
  SSL_CTX_set_options(&ctx, options | vers);
698
  return true;
699
#endif
700
}
101✔
701

702
OpenSSLTLSTicketKeysRing::OpenSSLTLSTicketKeysRing(size_t capacity)
703
{
96✔
704
  d_ticketKeys.write_lock()->set_capacity(capacity);
96✔
705
}
96✔
706

707
OpenSSLTLSTicketKeysRing::~OpenSSLTLSTicketKeysRing() = default;
8✔
708

709
void OpenSSLTLSTicketKeysRing::addKey(std::shared_ptr<OpenSSLTLSTicketKey>&& newKey)
710
{
247✔
711
  d_ticketKeys.write_lock()->push_front(std::move(newKey));
247✔
712
  if (TLSCtx::hasTicketsKeyAddedHook()) {
247✔
713
    auto key = d_ticketKeys.read_lock()->front();
2✔
714
    auto keyContent = key->content();
2✔
715
    TLSCtx::getTicketsKeyAddedHook()(keyContent);
2✔
716
    // fills mem with 0's
717
    OPENSSL_cleanse(keyContent.data(), keyContent.size());
2✔
718
  }
2✔
719
}
247✔
720

721
std::shared_ptr<OpenSSLTLSTicketKey> OpenSSLTLSTicketKeysRing::getEncryptionKey()
722
{
864✔
723
  return d_ticketKeys.read_lock()->front();
864✔
724
}
864✔
725

726
std::shared_ptr<OpenSSLTLSTicketKey> OpenSSLTLSTicketKeysRing::getDecryptionKey(unsigned char name[TLS_TICKETS_KEY_NAME_SIZE], bool& activeKey)
727
{
255✔
728
  auto keys = d_ticketKeys.read_lock();
255✔
729
  for (auto& key : *keys) {
339✔
730
    if (key->nameMatches(name)) {
339✔
731
      activeKey = (key == keys->front());
246✔
732
      return key;
246✔
733
    }
246✔
734
  }
339✔
735
  return nullptr;
9✔
736
}
255✔
737

738
size_t OpenSSLTLSTicketKeysRing::getKeysCount()
739
{
12✔
740
  return d_ticketKeys.read_lock()->size();
12✔
741
}
12✔
742

743
void OpenSSLTLSTicketKeysRing::loadTicketsKeys(const std::string& keyFile)
744
{
18✔
745
  bool keyLoaded = false;
18✔
746
  std::ifstream file(keyFile);
18✔
747
  try {
18✔
748
    do {
102✔
749
      auto newKey = std::make_shared<OpenSSLTLSTicketKey>(file);
102✔
750
      addKey(std::move(newKey));
102✔
751
      keyLoaded = true;
102✔
752
    }
102✔
753
    while (!file.fail());
102✔
754
  }
18✔
755
  catch (const std::exception& e) {
18✔
756
    /* if we haven't been able to load at least one key, fail */
757
    if (!keyLoaded) {
18!
758
      throw;
×
759
    }
×
760
  }
18✔
761

762
  file.close();
18✔
763
}
18✔
764

765
void OpenSSLTLSTicketKeysRing::loadTicketsKey(const std::string& key)
766
{
1✔
767
  bool keyLoaded = false;
1✔
768
  try {
1✔
769
    auto newKey = std::make_shared<OpenSSLTLSTicketKey>(key);
1✔
770
    addKey(std::move(newKey));
1✔
771
    keyLoaded = true;
1✔
772
  }
1✔
773
  catch (const std::exception& e) {
1✔
774
    /* if we haven't been able to load at least one key, fail */
775
    if (!keyLoaded) {
×
776
      throw;
×
777
    }
×
778
  }
×
779
}
1✔
780

781
void OpenSSLTLSTicketKeysRing::rotateTicketsKey(time_t /* now */)
782
{
162✔
783
  auto newKey = std::make_shared<OpenSSLTLSTicketKey>();
162✔
784
  addKey(std::move(newKey));
162✔
785
}
162✔
786

787
OpenSSLTLSTicketKey::OpenSSLTLSTicketKey()
788
{
162✔
789
  if (RAND_bytes(d_name, sizeof(d_name)) != 1) {
162!
790
    throw std::runtime_error("Error while generating the name of the OpenSSL TLS ticket key");
×
791
  }
×
792

793
  if (RAND_bytes(d_cipherKey, sizeof(d_cipherKey)) != 1) {
162!
794
    throw std::runtime_error("Error while generating the cipher key of the OpenSSL TLS ticket key");
×
795
  }
×
796

797
  if (RAND_bytes(d_hmacKey, sizeof(d_hmacKey)) != 1) {
162!
798
    throw std::runtime_error("Error while generating the HMAC key of the OpenSSL TLS ticket key");
×
799
  }
×
800
#ifdef HAVE_LIBSODIUM
162✔
801
  sodium_mlock(d_name, sizeof(d_name));
162✔
802
  sodium_mlock(d_cipherKey, sizeof(d_cipherKey));
162✔
803
  sodium_mlock(d_hmacKey, sizeof(d_hmacKey));
162✔
804
#endif /* HAVE_LIBSODIUM */
162✔
805
}
162✔
806

807
OpenSSLTLSTicketKey::OpenSSLTLSTicketKey(std::ifstream& file)
808
{
102✔
809
  file.read(reinterpret_cast<char*>(d_name), sizeof(d_name));
102✔
810
  file.read(reinterpret_cast<char*>(d_cipherKey), sizeof(d_cipherKey));
102✔
811
  file.read(reinterpret_cast<char*>(d_hmacKey), sizeof(d_hmacKey));
102✔
812

813
  if (file.fail()) {
102✔
814
    throw std::runtime_error("Unable to load a ticket key from the OpenSSL tickets key file");
18✔
815
  }
18✔
816
#ifdef HAVE_LIBSODIUM
84✔
817
  sodium_mlock(d_name, sizeof(d_name));
84✔
818
  sodium_mlock(d_cipherKey, sizeof(d_cipherKey));
84✔
819
  sodium_mlock(d_hmacKey, sizeof(d_hmacKey));
84✔
820
#endif /* HAVE_LIBSODIUM */
84✔
821
}
84✔
822

823
OpenSSLTLSTicketKey::OpenSSLTLSTicketKey(const std::string& key)
824
{
1✔
825
  if (key.size() != (sizeof(d_name) + sizeof(d_cipherKey) + sizeof(d_hmacKey))) {
1!
826
    throw std::runtime_error("Unable to load a ticket key from given data");
×
827
  }
×
828
  size_t from = 0;
1✔
829
  memcpy(d_name, &key.at(from), sizeof(d_name));
1✔
830
  from += sizeof(d_name);
1✔
831
  memcpy(d_cipherKey, &key.at(from), sizeof(d_cipherKey));
1✔
832
  from += sizeof(d_cipherKey);
1✔
833
  memcpy(d_hmacKey, &key.at(from), sizeof(d_hmacKey));
1✔
834

835
#ifdef HAVE_LIBSODIUM
1✔
836
  sodium_mlock(d_name, sizeof(d_name));
1✔
837
  sodium_mlock(d_cipherKey, sizeof(d_cipherKey));
1✔
838
  sodium_mlock(d_hmacKey, sizeof(d_hmacKey));
1✔
839
#endif /* HAVE_LIBSODIUM */
1✔
840
}
1✔
841

842
OpenSSLTLSTicketKey::~OpenSSLTLSTicketKey()
843
{
148✔
844
#ifdef HAVE_LIBSODIUM
148✔
845
  sodium_munlock(d_name, sizeof(d_name));
148✔
846
  sodium_munlock(d_cipherKey, sizeof(d_cipherKey));
148✔
847
  sodium_munlock(d_hmacKey, sizeof(d_hmacKey));
148✔
848
#else
849
  OPENSSL_cleanse(d_name, sizeof(d_name));
850
  OPENSSL_cleanse(d_cipherKey, sizeof(d_cipherKey));
851
  OPENSSL_cleanse(d_hmacKey, sizeof(d_hmacKey));
852
#endif /* HAVE_LIBSODIUM */
853
}
148✔
854

855
bool OpenSSLTLSTicketKey::nameMatches(const unsigned char name[TLS_TICKETS_KEY_NAME_SIZE]) const
856
{
339✔
857
  return (memcmp(d_name, name, sizeof(d_name)) == 0);
339✔
858
}
339✔
859

860
std::string OpenSSLTLSTicketKey::content() const
861
{
2✔
862
  std::string result{};
2✔
863
  result.reserve(TLS_TICKETS_KEY_NAME_SIZE + TLS_TICKETS_CIPHER_KEY_SIZE + TLS_TICKETS_MAC_KEY_SIZE);
2✔
864
  // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
865
  result.append(reinterpret_cast<const char*>(d_name), TLS_TICKETS_KEY_NAME_SIZE);
2✔
866
  result.append(reinterpret_cast<const char*>(d_cipherKey), TLS_TICKETS_CIPHER_KEY_SIZE);
2✔
867
  result.append(reinterpret_cast<const char*>(d_hmacKey), TLS_TICKETS_MAC_KEY_SIZE);
2✔
868
  // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
869

870
  return result;
2✔
871
}
2✔
872

873
#if OPENSSL_VERSION_MAJOR >= 3
874
static const std::string sha256KeyName{"sha256"};
875
#endif
876

877
#if OPENSSL_VERSION_MAJOR >= 3
878
int OpenSSLTLSTicketKey::encrypt(unsigned char keyName[TLS_TICKETS_KEY_NAME_SIZE], unsigned char* iv, EVP_CIPHER_CTX* ectx, EVP_MAC_CTX* hctx) const
879
#else
880
int OpenSSLTLSTicketKey::encrypt(unsigned char keyName[TLS_TICKETS_KEY_NAME_SIZE], unsigned char* iv, EVP_CIPHER_CTX* ectx, HMAC_CTX* hctx) const
881
#endif
882
{
864✔
883
  memcpy(keyName, d_name, sizeof(d_name));
864✔
884

885
  if (RAND_bytes(iv, EVP_MAX_IV_LENGTH) != 1) {
864!
886
    return -1;
×
887
  }
×
888

889
  if (EVP_EncryptInit_ex(ectx, TLS_TICKETS_CIPHER_ALGO(), nullptr, d_cipherKey, iv) != 1) {
864!
890
    return -1;
×
891
  }
×
892

893
#if OPENSSL_VERSION_MAJOR >= 3
864✔
894
  using ParamsBuilder = std::unique_ptr<OSSL_PARAM_BLD, decltype(&OSSL_PARAM_BLD_free)>;
864✔
895
  using Params = std::unique_ptr<OSSL_PARAM, decltype(&OSSL_PARAM_free)>;
864✔
896

897
  auto params_build = ParamsBuilder(OSSL_PARAM_BLD_new(), OSSL_PARAM_BLD_free);
864✔
898
  if (params_build == nullptr) {
864!
899
    return -1;
×
900
  }
×
901

902
  if (OSSL_PARAM_BLD_push_utf8_string(params_build.get(), OSSL_MAC_PARAM_DIGEST, sha256KeyName.c_str(), sha256KeyName.size()) == 0) {
864!
903
    return -1;
×
904
  }
×
905

906
  auto params = Params(OSSL_PARAM_BLD_to_param(params_build.get()), OSSL_PARAM_free);
864✔
907
  if (params == nullptr) {
864!
908
    return -1;
×
909
  }
×
910

911
  if (EVP_MAC_CTX_set_params(hctx, params.get()) == 0) {
864!
912
    return -1;
×
913
  }
×
914

915
  if (EVP_MAC_init(hctx, d_hmacKey, sizeof(d_hmacKey), nullptr) == 0) {
864!
916
    return -1;
×
917
  }
×
918
#else
919
  if (HMAC_Init_ex(hctx, d_hmacKey, sizeof(d_hmacKey), TLS_TICKETS_MAC_ALGO(), nullptr) != 1) {
920
    return -1;
921
  }
922
#endif
923

924
  return 1;
864✔
925
}
864✔
926

927
#if OPENSSL_VERSION_MAJOR >= 3
928
bool OpenSSLTLSTicketKey::decrypt(const unsigned char* iv, EVP_CIPHER_CTX* ectx, EVP_MAC_CTX* hctx) const
929
#else
930
bool OpenSSLTLSTicketKey::decrypt(const unsigned char* iv, EVP_CIPHER_CTX* ectx, HMAC_CTX* hctx) const
931
#endif
932
{
246✔
933
#if OPENSSL_VERSION_MAJOR >= 3
246✔
934
  using ParamsBuilder = std::unique_ptr<OSSL_PARAM_BLD, decltype(&OSSL_PARAM_BLD_free)>;
246✔
935
  using Params = std::unique_ptr<OSSL_PARAM, decltype(&OSSL_PARAM_free)>;
246✔
936

937
  auto params_build = ParamsBuilder(OSSL_PARAM_BLD_new(), OSSL_PARAM_BLD_free);
246✔
938
  if (params_build == nullptr) {
246!
939
    return false;
×
940
  }
×
941

942
  if (OSSL_PARAM_BLD_push_utf8_string(params_build.get(), OSSL_MAC_PARAM_DIGEST, sha256KeyName.c_str(), sha256KeyName.size()) == 0) {
246!
943
    return false;
×
944
  }
×
945

946
  auto params = Params(OSSL_PARAM_BLD_to_param(params_build.get()), OSSL_PARAM_free);
246✔
947
  if (params == nullptr) {
246!
948
    return false;
×
949
  }
×
950

951
  if (EVP_MAC_CTX_set_params(hctx, params.get()) == 0) {
246!
952
    return false;
×
953
  }
×
954

955
  if (EVP_MAC_init(hctx, d_hmacKey, sizeof(d_hmacKey), nullptr) == 0) {
246!
956
    return false;
×
957
  }
×
958
#else
959
  if (HMAC_Init_ex(hctx, d_hmacKey, sizeof(d_hmacKey), TLS_TICKETS_MAC_ALGO(), nullptr) != 1) {
960
    return false;
961
  }
962
#endif
963

964
  if (EVP_DecryptInit_ex(ectx, TLS_TICKETS_CIPHER_ALGO(), nullptr, d_cipherKey, iv) != 1) {
246!
965
    return false;
×
966
  }
×
967

968
  return true;
246✔
969
}
246✔
970

971
static std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)> getNewServerContext(const TLSConfig& config, [[maybe_unused]] std::vector<std::string>& warnings)
972
{
101✔
973
  auto ctx = std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)>(SSL_CTX_new(SSLv23_server_method()), SSL_CTX_free);
101✔
974

975
  if (!ctx) {
101!
976
    throw pdns::OpenSSL::error("Error creating an OpenSSL server context");
×
977
  }
×
978

979
  int sslOptions =
101✔
980
    SSL_OP_NO_SSLv2 |
101✔
981
    SSL_OP_NO_SSLv3 |
101✔
982
    SSL_OP_NO_COMPRESSION |
101✔
983
    SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
101✔
984
    SSL_OP_SINGLE_DH_USE |
101✔
985
    SSL_OP_SINGLE_ECDH_USE;
101✔
986

987
  if (!config.d_enableTickets || config.d_numberOfTicketsKeys == 0) {
101!
988
    /* for TLS 1.3 this means no stateless tickets, but stateful tickets might still be issued,
989
       which is something we don't want. */
990
    sslOptions |= SSL_OP_NO_TICKET;
3✔
991
    /* really disable all tickets */
992
#ifdef HAVE_SSL_CTX_SET_NUM_TICKETS
3✔
993
    SSL_CTX_set_num_tickets(ctx.get(), 0);
3✔
994
#endif /* HAVE_SSL_CTX_SET_NUM_TICKETS */
3✔
995
  }
3✔
996

997
  if (config.d_ktls) {
101!
998
#ifdef SSL_OP_ENABLE_KTLS
×
999
    sslOptions |= SSL_OP_ENABLE_KTLS;
×
1000
#endif /* SSL_OP_ENABLE_KTLS */
×
1001
  }
×
1002

1003
  if (config.d_sessionTimeout > 0) {
101!
1004
    SSL_CTX_set_timeout(ctx.get(), config.d_sessionTimeout);
×
1005
  }
×
1006

1007
  if (config.d_preferServerCiphers) {
101!
1008
    sslOptions |= SSL_OP_CIPHER_SERVER_PREFERENCE;
101✔
1009
#ifdef SSL_OP_PRIORITIZE_CHACHA
101✔
1010
    sslOptions |= SSL_OP_PRIORITIZE_CHACHA;
101✔
1011
#endif /* SSL_OP_PRIORITIZE_CHACHA */
101✔
1012
  }
101✔
1013

1014
  if (!config.d_enableRenegotiation) {
101!
1015
#ifdef SSL_OP_NO_RENEGOTIATION
101✔
1016
    sslOptions |= SSL_OP_NO_RENEGOTIATION;
101✔
1017
#elif defined(SSL_OP_NO_CLIENT_RENEGOTIATION)
1018
    sslOptions |= SSL_OP_NO_CLIENT_RENEGOTIATION;
1019
#endif
1020
  }
101✔
1021

1022
#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF
101✔
1023
  sslOptions |= SSL_OP_IGNORE_UNEXPECTED_EOF;
101✔
1024
#endif
101✔
1025

1026
  SSL_CTX_set_options(ctx.get(), sslOptions);
101✔
1027
  if (!libssl_set_min_tls_version(*ctx, config.d_minTLSVersion)) {
101!
1028
    throw std::runtime_error("Failed to set the minimum version to '" + libssl_tls_version_to_string(config.d_minTLSVersion));
×
1029
  }
×
1030

1031
#ifdef SSL_CTX_set_ecdh_auto
101✔
1032
  SSL_CTX_set_ecdh_auto(ctx.get(), 1);
101✔
1033
#endif
101✔
1034

1035
  if (config.d_maxStoredSessions == 0) {
101✔
1036
    /* disable stored sessions entirely */
1037
    SSL_CTX_set_session_cache_mode(ctx.get(), SSL_SESS_CACHE_OFF);
3✔
1038
  }
3✔
1039
  else {
98✔
1040
    /* use the internal built-in cache to store sessions */
1041
    SSL_CTX_set_session_cache_mode(ctx.get(), SSL_SESS_CACHE_SERVER);
98✔
1042
    SSL_CTX_sess_set_cache_size(ctx.get(), config.d_maxStoredSessions);
98✔
1043
  }
98✔
1044

1045
  long mode = 0;
101✔
1046
#ifdef SSL_MODE_RELEASE_BUFFERS
101✔
1047
  if (config.d_releaseBuffers) {
101!
1048
    mode |= SSL_MODE_RELEASE_BUFFERS;
101✔
1049
  }
101✔
1050
#endif
101✔
1051

1052
  if (config.d_asyncMode) {
101!
1053
#ifdef SSL_MODE_ASYNC
×
1054
    mode |= SSL_MODE_ASYNC;
×
1055
#else
1056
    warnings.push_back("Warning: TLS async mode requested but not supported");
1057
#endif
1058
  }
×
1059

1060
  SSL_CTX_set_mode(ctx.get(), mode);
101✔
1061

1062
  /* we need to set this callback to acknowledge the server name sent by the client,
1063
     otherwise it will not stored in the session and will not be accessible when the
1064
     session is resumed, causing SSL_get_servername to return nullptr */
1065
  SSL_CTX_set_tlsext_servername_callback(ctx.get(), &libssl_server_name_callback);
101✔
1066

1067
  return ctx;
101✔
1068
}
101✔
1069

1070
static void mergeNewCertificateAndKey(pdns::libssl::ServerContext& serverContext, pdns::libssl::ServerContext::SharedContext newContext, std::unordered_set<std::string>& names, const std::function<void(pdns::libssl::ServerContext::SharedContext&)>& existingContextCallback)
1071
{
77✔
1072
  for (const auto& name : names) {
152✔
1073
    auto [existingEntry, inserted] = serverContext.d_sniMap.emplace(name, newContext);
152✔
1074
    if (!inserted) {
152✔
1075
      auto& existingContext = existingEntry->second;
4✔
1076
      existingContextCallback(existingContext);
4✔
1077
    }
4✔
1078
    else if (serverContext.d_sniMap.size() == 1) {
148✔
1079
      serverContext.d_defaultContext = newContext;
73✔
1080
    }
73✔
1081
  }
152✔
1082
}
77✔
1083

1084
std::pair<std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)>, std::vector<std::string>> libssl_init_server_context_no_sni(const TLSConfig& config,
1085
                                                                                                                         [[maybe_unused]] std::map<int, std::string>& ocspResponses)
1086
{
24✔
1087
  std::vector<std::string> warnings;
24✔
1088
  auto ctx = getNewServerContext(config, warnings);
24✔
1089

1090
  std::vector<int> keyTypes;
24✔
1091
  /* load certificate and private key */
1092
  for (const auto& pair : config.d_certKeyPairs) {
24✔
1093
    if (!pair.d_key) {
24✔
1094
#if defined(HAVE_SSL_CTX_USE_CERT_AND_KEY)
1✔
1095
      // If no separate key is given, treat it as a pkcs12 file
1096
      auto filePtr = pdns::UniqueFilePtr(fopen(pair.d_cert.c_str(), "r"));
1✔
1097
      if (!filePtr) {
1!
1098
        throw std::runtime_error("Unable to open file " + pair.d_cert);
×
1099
      }
×
1100
      auto p12 = std::unique_ptr<PKCS12, void(*)(PKCS12*)>(d2i_PKCS12_fp(filePtr.get(), nullptr), PKCS12_free);
1✔
1101
      if (!p12) {
1!
1102
        throw std::runtime_error("Unable to open PKCS12 file " + pair.d_cert);
×
1103
      }
×
1104
      EVP_PKEY *keyptr = nullptr;
1✔
1105
      X509 *certptr = nullptr;
1✔
1106
      STACK_OF(X509) *captr = nullptr;
1✔
1107
      if (!PKCS12_parse(p12.get(), (pair.d_password ? pair.d_password->c_str() : nullptr), &keyptr, &certptr, &captr)) {
1!
1108
#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
×
1109
        bool failed = true;
×
1110
        /* 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 */
1111
        auto libCtx = OSSL_LIB_CTX_get0_global_default();
×
1112
        /* check whether the legacy provider is already loaded */
1113
        if (!OSSL_PROVIDER_available(libCtx, "legacy")) {
×
1114
          /* it's not */
1115
          auto provider = OSSL_PROVIDER_load(libCtx, "legacy");
×
1116
          if (provider != nullptr) {
×
1117
            if (PKCS12_parse(p12.get(), (pair.d_password ? pair.d_password->c_str() : nullptr), &keyptr, &certptr, &captr)) {
×
1118
              failed = false;
×
1119
            }
×
1120
            /* we do not want to keep that provider around after that */
1121
            OSSL_PROVIDER_unload(provider);
×
1122
          }
×
1123
        }
×
1124
        if (failed) {
×
1125
#endif /* defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 */
×
1126
          ERR_print_errors_fp(stderr);
×
1127
          throw std::runtime_error("An error occurred while parsing PKCS12 file " + pair.d_cert);
×
1128
#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
×
1129
        }
×
1130
#endif /* defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 */
×
1131
      }
×
1132
      auto key = std::unique_ptr<EVP_PKEY, void(*)(EVP_PKEY*)>(keyptr, EVP_PKEY_free);
1✔
1133
      auto cert = std::unique_ptr<X509, void(*)(X509*)>(certptr, X509_free);
1✔
1134
      auto ca = std::unique_ptr<STACK_OF(X509), void(*)(STACK_OF(X509)*)>(captr, [](STACK_OF(X509)* st){ sk_X509_free(st); });
1✔
1135

1136
      if (SSL_CTX_use_cert_and_key(ctx.get(), cert.get(), key.get(), ca.get(), 1) != 1) {
1!
1137
        ERR_print_errors_fp(stderr);
×
1138
        throw std::runtime_error("An error occurred while trying to load the TLS certificate and key from PKCS12 file " + pair.d_cert);
×
1139
      }
×
1140
#else
1141
      throw std::runtime_error("PKCS12 files are not supported by your openssl version");
1142
#endif /* HAVE_SSL_CTX_USE_CERT_AND_KEY */
1143
    } else {
23✔
1144
      if (SSL_CTX_use_certificate_chain_file(ctx.get(), pair.d_cert.c_str()) != 1) {
23!
1145
        ERR_print_errors_fp(stderr);
×
1146
        throw std::runtime_error("An error occurred while trying to load the TLS server certificate file: " + pair.d_cert);
×
1147
      }
×
1148
      if (SSL_CTX_use_PrivateKey_file(ctx.get(), pair.d_key->c_str(), SSL_FILETYPE_PEM) != 1) {
23!
1149
        ERR_print_errors_fp(stderr);
×
1150
        throw std::runtime_error("An error occurred while trying to load the TLS server private key file: " + pair.d_key.value());
×
1151
      }
×
1152
    }
23✔
1153

1154
    if (SSL_CTX_check_private_key(ctx.get()) != 1) {
24!
1155
      ERR_print_errors_fp(stderr);
×
1156
      throw std::runtime_error("The key from '" + pair.d_key.value() + "' does not match the certificate from '" + pair.d_cert + "'");
×
1157
    }
×
1158
    /* store the type of the new key, we might need it later to select the right OCSP stapling response */
1159
    auto keyType = libssl_get_last_key_type(*ctx);
24✔
1160
    if (keyType < 0) {
24!
1161
      throw std::runtime_error("The key from '" + pair.d_key.value() + "' has an unknown type");
×
1162
    }
×
1163
    keyTypes.push_back(keyType);
24✔
1164
 }
24✔
1165

1166
#ifndef DISABLE_OCSP_STAPLING
24✔
1167
  if (!config.d_ocspFiles.empty()) {
24✔
1168
    try {
4✔
1169
      ocspResponses = libssl_load_ocsp_responses(config.d_ocspFiles, std::move(keyTypes), warnings);
4✔
1170
    }
4✔
1171
    catch(const std::exception& e) {
4✔
1172
      throw std::runtime_error("Unable to load OCSP responses: " + std::string(e.what()));
×
1173
    }
×
1174
  }
4✔
1175
#endif /* DISABLE_OCSP_STAPLING */
24✔
1176

1177
  if (!config.d_ciphers.empty() && SSL_CTX_set_cipher_list(ctx.get(), config.d_ciphers.c_str()) != 1) {
24!
1178
    throw std::runtime_error("The TLS ciphers could not be set: " + config.d_ciphers);
×
1179
  }
×
1180

1181
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
24✔
1182
  if (!config.d_ciphers13.empty() && SSL_CTX_set_ciphersuites(ctx.get(), config.d_ciphers13.c_str()) != 1) {
24!
1183
    throw std::runtime_error("The TLS 1.3 ciphers could not be set: " + config.d_ciphers13);
×
1184
  }
×
1185
#endif /* HAVE_SSL_CTX_SET_CIPHERSUITES */
24✔
1186

1187
  return {std::move(ctx), std::move(warnings)};
24✔
1188
}
24✔
1189

1190
std::pair<pdns::libssl::ServerContext, std::vector<std::string>> libssl_init_server_context(const TLSConfig& config)
1191
{
73✔
1192
  std::vector<std::string> warnings;
73✔
1193
  pdns::libssl::ServerContext serverContext;
73✔
1194

1195
  std::vector<int> keyTypes;
73✔
1196
  /* load certificate and private key */
1197
  for (const auto& pair : config.d_certKeyPairs) {
77✔
1198
    auto uniqueCtx = getNewServerContext(config, warnings);
77✔
1199
    auto ctx = std::shared_ptr<SSL_CTX>(uniqueCtx.release(), SSL_CTX_free);
77✔
1200
    if (!pair.d_key) {
77✔
1201
#if defined(HAVE_SSL_CTX_USE_CERT_AND_KEY)
3✔
1202
      // If no separate key is given, treat it as a pkcs12 file
1203
      auto filePtr = pdns::UniqueFilePtr(fopen(pair.d_cert.c_str(), "r"));
3✔
1204
      if (!filePtr) {
3!
1205
        throw std::runtime_error("Unable to open file " + pair.d_cert);
×
1206
      }
×
1207
      auto p12 = std::unique_ptr<PKCS12, void(*)(PKCS12*)>(d2i_PKCS12_fp(filePtr.get(), nullptr), PKCS12_free);
3✔
1208
      if (!p12) {
3!
1209
        throw std::runtime_error("Unable to open PKCS12 file " + pair.d_cert);
×
1210
      }
×
1211
      EVP_PKEY *keyptr = nullptr;
3✔
1212
      X509 *certptr = nullptr;
3✔
1213
      STACK_OF(X509) *captr = nullptr;
3✔
1214
      if (PKCS12_parse(p12.get(), (pair.d_password ? pair.d_password->c_str() : nullptr), &keyptr, &certptr, &captr) != 1) {
3!
1215
#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
×
1216
        bool failed = true;
×
1217
        /* 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 */
1218
        auto* libCtx = OSSL_LIB_CTX_get0_global_default();
×
1219
        /* check whether the legacy provider is already loaded */
1220
        if (OSSL_PROVIDER_available(libCtx, "legacy") == 0) {
×
1221
          /* it's not */
1222
          auto* provider = OSSL_PROVIDER_load(libCtx, "legacy");
×
1223
          if (provider != nullptr) {
×
1224
            if (PKCS12_parse(p12.get(), (pair.d_password ? pair.d_password->c_str() : nullptr), &keyptr, &certptr, &captr) == 1) {
×
1225
              failed = false;
×
1226
            }
×
1227
            /* we do not want to keep that provider around after that */
1228
            OSSL_PROVIDER_unload(provider);
×
1229
          }
×
1230
        }
×
1231
        if (failed) {
×
1232
#endif /* defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 */
×
1233
          ERR_print_errors_fp(stderr);
×
1234
          throw std::runtime_error("An error occurred while parsing PKCS12 file " + pair.d_cert);
×
1235
#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
×
1236
        }
×
1237
#endif /* defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 */
×
1238
      }
×
1239
      auto key = std::unique_ptr<EVP_PKEY, void(*)(EVP_PKEY*)>(keyptr, EVP_PKEY_free);
3✔
1240
      auto cert = std::unique_ptr<X509, void(*)(X509*)>(certptr, X509_free);
3✔
1241
      auto caList = std::unique_ptr<STACK_OF(X509), void(*)(STACK_OF(X509)*)>(captr, [](STACK_OF(X509)* stack){ sk_X509_free(stack); });
3✔
1242

1243
      auto addCertificateAndKey = [&pair, &key, &cert, &caList](std::shared_ptr<SSL_CTX>& tlsContext) {
3✔
1244
        if (SSL_CTX_use_cert_and_key(tlsContext.get(), cert.get(), key.get(), caList.get(), 1) != 1) {
3!
1245
          ERR_print_errors_fp(stderr);
×
1246
          throw std::runtime_error("An error occurred while trying to load the TLS certificate and key from PKCS12 file " + pair.d_cert);
×
1247
        }
×
1248
      };
3✔
1249

1250
      addCertificateAndKey(ctx);
3✔
1251
      auto names = get_names_from_last_certificate(*ctx);
3✔
1252
      mergeNewCertificateAndKey(serverContext, ctx, names, addCertificateAndKey);
3✔
1253
#else
1254
      throw std::runtime_error("PKCS12 files are not supported by your openssl version");
1255
#endif /* HAVE_SSL_CTX_USE_CERT_AND_KEY */
1256
    } else {
74✔
1257
      auto addCertificateAndKey = [&pair](std::shared_ptr<SSL_CTX>& tlsContext) {
78✔
1258
        if (SSL_CTX_use_certificate_chain_file(tlsContext.get(), pair.d_cert.c_str()) != 1) {
78!
1259
          ERR_print_errors_fp(stderr);
×
1260
          throw std::runtime_error("An error occurred while trying to load the TLS server certificate file: " + pair.d_cert);
×
1261
        }
×
1262
        if (SSL_CTX_use_PrivateKey_file(tlsContext.get(), pair.d_key->c_str(), SSL_FILETYPE_PEM) != 1) {
78!
1263
          ERR_print_errors_fp(stderr);
×
1264
          throw std::runtime_error("An error occurred while trying to load the TLS server private key file: " + pair.d_key.value());
×
1265
        }
×
1266
      };
78✔
1267

1268
      addCertificateAndKey(ctx);
74✔
1269
      auto names = get_names_from_last_certificate(*ctx);
74✔
1270
      mergeNewCertificateAndKey(serverContext, ctx, names, addCertificateAndKey);
74✔
1271
    }
74✔
1272

1273
    if (SSL_CTX_check_private_key(ctx.get()) != 1) {
77!
1274
      ERR_print_errors_fp(stderr);
×
1275
      throw std::runtime_error("The key from '" + pair.d_key.value() + "' does not match the certificate from '" + pair.d_cert + "'");
×
1276
    }
×
1277
    /* store the type of the new key, we might need it later to select the right OCSP stapling response */
1278
    auto keyType = libssl_get_last_key_type(*ctx);
77✔
1279
    if (keyType < 0) {
77!
1280
      throw std::runtime_error("The key from '" + pair.d_key.value() + "' has an unknown type");
×
1281
    }
×
1282
    keyTypes.push_back(keyType);
77✔
1283
 }
77✔
1284

1285
#ifndef DISABLE_OCSP_STAPLING
73✔
1286
  if (!config.d_ocspFiles.empty()) {
73✔
1287
    try {
7✔
1288
      serverContext.d_ocspResponses = libssl_load_ocsp_responses(config.d_ocspFiles, std::move(keyTypes), warnings);
7✔
1289
    }
7✔
1290
    catch(const std::exception& e) {
7✔
1291
      throw std::runtime_error("Unable to load OCSP responses: " + std::string(e.what()));
×
1292
    }
×
1293
  }
7✔
1294
#endif /* DISABLE_OCSP_STAPLING */
73✔
1295

1296
  for (auto& entry : serverContext.d_sniMap) {
148✔
1297
    auto& ctx = entry.second;
148✔
1298
    if (!config.d_ciphers.empty() && SSL_CTX_set_cipher_list(ctx.get(), config.d_ciphers.c_str()) != 1) {
148!
1299
      throw std::runtime_error("The TLS ciphers could not be set: " + config.d_ciphers);
×
1300
    }
×
1301

1302
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
148✔
1303
    if (!config.d_ciphers13.empty() && SSL_CTX_set_ciphersuites(ctx.get(), config.d_ciphers13.c_str()) != 1) {
148!
1304
      throw std::runtime_error("The TLS 1.3 ciphers could not be set: " + config.d_ciphers13);
×
1305
    }
×
1306
#endif /* HAVE_SSL_CTX_SET_CIPHERSUITES */
148✔
1307
  }
148✔
1308

1309
  return {std::move(serverContext), std::move(warnings)};
73✔
1310
}
73✔
1311

1312
#ifdef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK
1313
static void libssl_key_log_file_callback(const SSL* ssl, const char* line)
1314
{
80✔
1315
  SSL_CTX* sslCtx = SSL_get_SSL_CTX(ssl);
80✔
1316
  if (sslCtx == nullptr) {
80!
1317
    return;
×
1318
  }
×
1319

1320
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): OpenSSL's API
1321
  auto* filePtr = reinterpret_cast<FILE*>(SSL_CTX_get_ex_data(sslCtx, s_keyLogIndex));
80✔
1322
  if (filePtr == nullptr) {
80!
1323
    return;
×
1324
  }
×
1325

1326
  fprintf(filePtr, "%s\n", line);
80✔
1327
  fflush(filePtr);
80✔
1328
}
80✔
1329
#endif /* HAVE_SSL_CTX_SET_KEYLOG_CALLBACK */
1330

1331
pdns::UniqueFilePtr libssl_set_key_log_file([[maybe_unused]] SSL_CTX* ctx, [[maybe_unused]] const std::string& logFile)
1332
{
4✔
1333
#ifdef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK
4✔
1334
  auto filePtr = pdns::openFileForWriting(logFile, 0600, false, true);
4✔
1335
  if (!filePtr) {
4!
1336
    auto error = errno;
×
1337
    throw std::runtime_error("Error opening file " + logFile + " for writing: " + stringerror(error));
×
1338
  }
×
1339
  SSL_CTX_set_ex_data(ctx, s_keyLogIndex, filePtr.get());
4✔
1340
  SSL_CTX_set_keylog_callback(ctx, &libssl_key_log_file_callback);
4✔
1341
  return filePtr;
4✔
1342
#else
1343
  return pdns::UniqueFilePtr(nullptr);
1344
#endif /* HAVE_SSL_CTX_SET_KEYLOG_CALLBACK */
1345
}
4✔
1346

1347
/* 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. */
1348
void libssl_set_alpn_select_callback([[maybe_unused]] SSL_CTX* ctx, [[maybe_unused]] int (*callback)(SSL* ssl, const unsigned char** out, unsigned char* outlen, const unsigned char* inPtr, unsigned int inlen, void* arg), [[maybe_unused]] void* arg)
1349
{
148✔
1350
#ifdef HAVE_SSL_CTX_SET_ALPN_SELECT_CB
148✔
1351
  SSL_CTX_set_alpn_select_cb(ctx, callback, arg);
148✔
1352
#endif
148✔
1353
}
148✔
1354

1355
bool libssl_set_alpn_protos([[maybe_unused]] SSL_CTX* ctx, [[maybe_unused]] const std::vector<std::vector<uint8_t>>& protos)
1356
{
49✔
1357
#ifdef HAVE_SSL_CTX_SET_ALPN_PROTOS
49✔
1358
  std::vector<uint8_t> wire;
49✔
1359
  for (const auto& proto : protos) {
49✔
1360
    if (proto.size() > std::numeric_limits<uint8_t>::max()) {
30!
1361
      throw std::runtime_error("Invalid ALPN value");
×
1362
    }
×
1363
    uint8_t length = proto.size();
30✔
1364
    wire.push_back(length);
30✔
1365
    wire.insert(wire.end(), proto.begin(), proto.end());
30✔
1366
  }
30✔
1367
  return SSL_CTX_set_alpn_protos(ctx, wire.data(), wire.size()) == 0;
49✔
1368
#else
1369
  return false;
1370
#endif
1371
}
49✔
1372

1373

1374
std::string libssl_get_error_string()
1375
{
1✔
1376
  BIO *mem = BIO_new(BIO_s_mem());
1✔
1377
  ERR_print_errors(mem);
1✔
1378
  char *p;
1✔
1379
  size_t len = BIO_get_mem_data(mem, &p);
1✔
1380
  std::string msg(p, len);
1✔
1381
  // replace newlines by /
1382
  if (msg.back() == '\n') {
1!
1383
    msg.pop_back();
1✔
1384
  }
1✔
1385
  std::replace(msg.begin(), msg.end(), '\n', '/');
1✔
1386
  BIO_free(mem);
1✔
1387
  return msg;
1✔
1388
}
1✔
1389
#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