]> git.ipfire.org Git - thirdparty/squid.git/blame - src/security/ServerOptions.cc
Maintenance: update --with-gnutls detection (#1685)
[thirdparty/squid.git] / src / security / ServerOptions.cc
CommitLineData
474f076e 1/*
b8ae064d 2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
474f076e
AJ
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9#include "squid.h"
cf487124 10#include "anyp/PortCfg.h"
a4dd5bfa 11#include "base/IoManip.h"
474f076e 12#include "base/Packable.h"
cf487124 13#include "cache_cf.h"
742236c7 14#include "error/SysErrorDetail.h"
cf487124 15#include "fatal.h"
474f076e
AJ
16#include "globals.h"
17#include "security/ServerOptions.h"
cf487124
AJ
18#include "security/Session.h"
19#include "SquidConfig.h"
0a28c16a 20#if USE_OPENSSL
24b30fdc 21#include "compat/openssl.h"
0a28c16a 22#include "ssl/support.h"
474f076e 23
742236c7
AJ
24#if HAVE_OPENSSL_DECODER_H
25#include <openssl/decoder.h>
26#endif
474f076e
AJ
27#if HAVE_OPENSSL_ERR_H
28#include <openssl/err.h>
29#endif
474f076e
AJ
30#endif
31
1f8b5f0e 32#include <limits>
33
621f4299
AJ
34Security::ServerOptions &
35Security::ServerOptions::operator =(const Security::ServerOptions &old) {
36 if (this != &old) {
37 Security::PeerOptions::operator =(old);
38 clientCaFile = old.clientCaFile;
39 dh = old.dh;
40 dhParamsFile = old.dhParamsFile;
41 eecdhCurve = old.eecdhCurve;
42 parsedDhParams = old.parsedDhParams;
43#if USE_OPENSSL
44 if (auto *stk = SSL_dup_CA_list(old.clientCaStack.get()))
45 clientCaStack = Security::ServerOptions::X509_NAME_STACK_Pointer(stk);
cf487124 46 else
621f4299 47#endif
cf487124
AJ
48 clientCaStack = nullptr;
49
50 staticContextSessionId = old.staticContextSessionId;
51 generateHostCertificates = old.generateHostCertificates;
51e09c08
AJ
52 signingCa = old.signingCa;
53 untrustedSigningCa = old.untrustedSigningCa;
cf487124 54 dynamicCertMemCacheSize = old.dynamicCertMemCacheSize;
621f4299
AJ
55 }
56 return *this;
57}
58
474f076e
AJ
59void
60Security::ServerOptions::parse(const char *token)
61{
62 if (!*token) {
63 // config says just "ssl" or "tls" (or "tls-")
64 encryptTransport = true;
65 return;
66 }
67
68 // parse the server-only options
fbffd8a3
AR
69 if (strncmp(token, "clientca=", 9) == 0) {
70 clientCaFile = SBuf(token + 9);
71 } else if (strncmp(token, "dh=", 3) == 0) {
474f076e
AJ
72 // clear any previous Diffi-Helman configuration
73 dh.clear();
74 dhParamsFile.clear();
75 eecdhCurve.clear();
76
77 dh.append(token + 3);
78
79 if (!dh.isEmpty()) {
80 auto pos = dh.find(':');
81 if (pos != SBuf::npos) { // tls-dh=eecdhCurve:dhParamsFile
82 eecdhCurve = dh.substr(0,pos);
83 dhParamsFile = dh.substr(pos+1);
84 } else { // tls-dh=dhParamsFile
85 dhParamsFile = dh;
86 // empty eecdhCurve means "do not use EECDH"
87 }
88 }
89
104deb98
AJ
90 loadDhParams();
91
474f076e
AJ
92 } else if (strncmp(token, "dhparams=", 9) == 0) {
93 if (!eecdhCurve.isEmpty()) {
d816f28d 94 debugs(83, DBG_PARSE_NOTE(1), "WARNING: UPGRADE: EECDH settings in tls-dh= override dhparams=");
474f076e
AJ
95 return;
96 }
97
98 // backward compatibility for dhparams= configuration
99 dh.clear();
100 dh.append(token + 9);
101 dhParamsFile = dh;
102
104deb98
AJ
103 loadDhParams();
104
cf487124
AJ
105 } else if (strncmp(token, "dynamic_cert_mem_cache_size=", 28) == 0) {
106 parseBytesOptionValue(&dynamicCertMemCacheSize, "bytes", token + 28);
107 // XXX: parseBytesOptionValue() self_destruct()s on invalid values,
108 // probably making this comparison and misleading ERROR unnecessary.
109 if (dynamicCertMemCacheSize == std::numeric_limits<size_t>::max()) {
110 debugs(3, DBG_CRITICAL, "ERROR: Cannot allocate memory for '" << token << "'. Using default of 4MB instead.");
111 dynamicCertMemCacheSize = 4*1024*1024; // 4 MB
112 }
113
114 } else if (strcmp(token, "generate-host-certificates") == 0) {
115 generateHostCertificates = true;
116 } else if (strcmp(token, "generate-host-certificates=on") == 0) {
117 generateHostCertificates = true;
118 } else if (strcmp(token, "generate-host-certificates=off") == 0) {
119 generateHostCertificates = false;
120
121 } else if (strncmp(token, "context=", 8) == 0) {
122#if USE_OPENSSL
123 staticContextSessionId = SBuf(token+8);
124 // to hide its arguably sensitive value, do not print token in these debugs
125 if (staticContextSessionId.length() > SSL_MAX_SSL_SESSION_ID_LENGTH) {
126 debugs(83, DBG_CRITICAL, "FATAL: Option 'context=' value is too long. Maximum " << SSL_MAX_SSL_SESSION_ID_LENGTH << " characters.");
127 self_destruct();
128 }
129#else
130 debugs(83, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: Option 'context=' requires --with-openssl. Ignoring.");
131#endif
132
474f076e
AJ
133 } else {
134 // parse generic TLS options
135 Security::PeerOptions::parse(token);
136 }
137}
138
139void
90153ed6 140Security::ServerOptions::dumpCfg(std::ostream &os, const char *pfx) const
474f076e
AJ
141{
142 // dump out the generic TLS options
90153ed6 143 Security::PeerOptions::dumpCfg(os, pfx);
474f076e
AJ
144
145 if (!encryptTransport)
146 return; // no other settings are relevant
147
148 // dump the server-only options
149 if (!dh.isEmpty())
90153ed6 150 os << ' ' << pfx << "dh=" << dh;
cf487124
AJ
151
152 if (!generateHostCertificates)
90153ed6 153 os << ' ' << pfx << "generate-host-certificates=off";
cf487124
AJ
154
155 if (dynamicCertMemCacheSize != 4*1024*1024) // 4MB default, no 'tls-' prefix
90153ed6 156 os << ' ' << "dynamic_cert_mem_cache_size=" << dynamicCertMemCacheSize << "bytes";
cf487124
AJ
157
158 if (!staticContextSessionId.isEmpty())
90153ed6 159 os << ' ' << pfx << "context=" << staticContextSessionId;
474f076e
AJ
160}
161
64769c79 162Security::ContextPointer
885f0ecf
AJ
163Security::ServerOptions::createBlankContext() const
164{
64769c79 165 Security::ContextPointer ctx;
885f0ecf 166#if USE_OPENSSL
0a28c16a
AJ
167 Ssl::Initialize();
168
64769c79 169 SSL_CTX *t = SSL_CTX_new(TLS_server_method());
885f0ecf 170 if (!t) {
ea574635
AJ
171 const auto x = ERR_get_error();
172 debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate TLS server context: " << Security::ErrorString(x));
885f0ecf 173 }
df473b36 174 ctx = convertContextFromRawPtr(t);
885f0ecf 175
c813943d 176#elif HAVE_LIBGNUTLS
885f0ecf 177 // Initialize for X.509 certificate exchange
64769c79 178 gnutls_certificate_credentials_t t;
83b053a0 179 if (const auto x = gnutls_certificate_allocate_credentials(&t)) {
ea574635 180 debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate TLS server context: " << Security::ErrorString(x));
885f0ecf 181 }
df473b36 182 ctx = convertContextFromRawPtr(t);
885f0ecf
AJ
183
184#else
185 debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate TLS server context: No TLS library");
186
187#endif
188
64769c79 189 return ctx;
885f0ecf
AJ
190}
191
51e09c08
AJ
192void
193Security::ServerOptions::initServerContexts(AnyP::PortCfg &port)
194{
195 const char *portType = AnyP::ProtocolType_str[port.transport.protocol];
196 for (auto &keyData : certs) {
197 keyData.loadFromFiles(port, portType);
198 }
199
200 if (generateHostCertificates) {
201 createSigningContexts(port);
1700fab7 202 }
51e09c08 203
1700fab7 204 if (!certs.empty() && !createStaticServerContext(port)) {
51e09c08
AJ
205 char buf[128];
206 fatalf("%s_port %s initialization error", portType, port.s.toUrl(buf, sizeof(buf)));
207 }
1700fab7
AJ
208
209 // if generate-host-certificates=off and certs is empty, no contexts may be created.
210 // features depending on contexts do their own checks and error messages later.
51e09c08
AJ
211}
212
9ad528b8 213bool
8b082ed9 214Security::ServerOptions::createStaticServerContext(AnyP::PortCfg &)
c75aba02
AJ
215{
216 updateTlsVersionLimits();
217
9ad528b8 218 Security::ContextPointer t(createBlankContext());
c75aba02 219 if (t) {
51e09c08 220
c75aba02 221#if USE_OPENSSL
51e09c08
AJ
222 if (certs.size() > 1) {
223 // NOTE: calling SSL_CTX_use_certificate() repeatedly _replaces_ the previous cert details.
224 // so we cannot use it and support multiple server certificates with OpenSSL.
2f8abb64 225 debugs(83, DBG_CRITICAL, "ERROR: OpenSSL does not support multiple server certificates. Ignoring additional cert= parameters.");
51e09c08
AJ
226 }
227
228 const auto &keys = certs.front();
229
230 if (!SSL_CTX_use_certificate(t.get(), keys.cert.get())) {
231 const auto x = ERR_get_error();
232 debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire TLS certificate '" << keys.certFile << "': " << Security::ErrorString(x));
9ad528b8 233 return false;
51e09c08
AJ
234 }
235
236 if (!SSL_CTX_use_PrivateKey(t.get(), keys.pkey.get())) {
237 const auto x = ERR_get_error();
238 debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire TLS private key '" << keys.privateKeyFile << "': " << Security::ErrorString(x));
239 return false;
240 }
241
242 for (auto cert : keys.chain) {
243 if (SSL_CTX_add_extra_chain_cert(t.get(), cert.get())) {
244 // increase the certificate lock
245 X509_up_ref(cert.get());
246 } else {
247 const auto error = ERR_get_error();
248 debugs(83, DBG_IMPORTANT, "WARNING: can not add certificate to SSL context chain: " << Security::ErrorString(error));
249 }
250 }
251
c813943d 252#elif HAVE_LIBGNUTLS
51e09c08
AJ
253 for (auto &keys : certs) {
254 gnutls_x509_crt_t crt = keys.cert.get();
255 gnutls_x509_privkey_t xkey = keys.pkey.get();
256 const auto x = gnutls_certificate_set_x509_key(t.get(), &crt, 1, xkey);
257 if (x != GNUTLS_E_SUCCESS) {
258 SBuf whichFile = keys.certFile;
259 if (keys.certFile != keys.privateKeyFile) {
260 whichFile.appendf(" and ");
261 whichFile.append(keys.privateKeyFile);
262 }
263 debugs(83, DBG_CRITICAL, "ERROR: Failed to initialize server context with keys from " << whichFile << ": " << Security::ErrorString(x));
264 return false;
265 }
f3a5731a 266 // XXX: add cert chain to the context
51e09c08 267 }
c75aba02 268#endif
51e09c08 269
fbffd8a3
AR
270 if (!loadClientCaFile())
271 return false;
272
273 // by this point all config related files must be loaded
51e09c08
AJ
274 if (!updateContextConfig(t)) {
275 debugs(83, DBG_CRITICAL, "ERROR: Configuring static TLS context");
276 return false;
277 }
c75aba02
AJ
278 }
279
9ad528b8
AJ
280 staticContext = std::move(t);
281 return bool(staticContext);
c75aba02
AJ
282}
283
cf487124 284void
51e09c08 285Security::ServerOptions::createSigningContexts(const AnyP::PortCfg &port)
cf487124 286{
51e09c08
AJ
287 // For signing we do not have a pre-initialized context object. Instead
288 // contexts are generated as needed. This method initializes the cert
289 // and key pointers used to sign those contexts later.
cf487124 290
51e09c08
AJ
291 signingCa = certs.front();
292
293 const char *portType = AnyP::ProtocolType_str[port.transport.protocol];
294 if (!signingCa.cert) {
cf487124 295 char buf[128];
51e09c08
AJ
296 // XXX: we never actually checked that the cert is capable of signing!
297 fatalf("No valid signing certificate configured for %s_port %s", portType, port.s.toUrl(buf, sizeof(buf)));
cf487124
AJ
298 }
299
51e09c08
AJ
300 if (!signingCa.pkey)
301 debugs(3, DBG_IMPORTANT, "No TLS private key configured for " << portType << "_port " << port.s);
cf487124
AJ
302
303#if USE_OPENSSL
51e09c08 304 Ssl::generateUntrustedCert(untrustedSigningCa.cert, untrustedSigningCa.pkey, signingCa.cert, signingCa.pkey);
c813943d 305#elif HAVE_LIBGNUTLS
51e09c08
AJ
306 // TODO: implement for GnuTLS. Just a warning for now since generate is implicitly on for all crypto builds.
307 signingCa.cert.reset();
308 signingCa.pkey.reset();
309 debugs(83, DBG_CRITICAL, "WARNING: Dynamic TLS certificate generation requires --with-openssl.");
310 return;
311#else
312 debugs(83, DBG_CRITICAL, "ERROR: Dynamic TLS certificate generation requires --with-openssl.");
313 return;
cf487124
AJ
314#endif
315
51e09c08 316 if (!untrustedSigningCa.cert) {
cf487124 317 char buf[128];
51e09c08 318 fatalf("Unable to generate signing certificate for untrusted sites for %s_port %s", portType, port.s.toUrl(buf, sizeof(buf)));
cf487124
AJ
319 }
320}
321
621f4299
AJ
322void
323Security::ServerOptions::syncCaFiles()
324{
325 // if caFiles is set, just use that
326 if (caFiles.size())
327 return;
328
329 // otherwise fall back to clientca if it is defined
330 if (!clientCaFile.isEmpty())
331 caFiles.emplace_back(clientCaFile);
332}
333
334/// load clientca= file (if any) into memory.
335/// \retval true clientca is not set, or loaded successfully
336/// \retval false unable to load the file, or not using OpenSSL
337bool
338Security::ServerOptions::loadClientCaFile()
339{
340 if (clientCaFile.isEmpty())
341 return true;
342
343#if USE_OPENSSL
344 auto *stk = SSL_load_client_CA_file(clientCaFile.c_str());
345 clientCaStack = Security::ServerOptions::X509_NAME_STACK_Pointer(stk);
346#endif
347 if (!clientCaStack) {
348 debugs(83, DBG_CRITICAL, "FATAL: Unable to read client CAs from file: " << clientCaFile);
349 }
350
351 return bool(clientCaStack);
352}
353
474f076e 354void
104deb98 355Security::ServerOptions::loadDhParams()
474f076e 356{
104deb98 357 if (dhParamsFile.isEmpty())
474f076e
AJ
358 return;
359
742236c7
AJ
360 // TODO: After loading and validating parameters, also validate that "the
361 // public and private components have the correct mathematical
362 // relationship". See EVP_PKEY_check().
363
104deb98 364#if USE_OPENSSL
742236c7 365#if OPENSSL_VERSION_MAJOR < 3
104deb98
AJ
366 DH *dhp = nullptr;
367 if (FILE *in = fopen(dhParamsFile.c_str(), "r")) {
aee3523a 368 dhp = PEM_read_DHparams(in, nullptr, nullptr, nullptr);
104deb98 369 fclose(in);
742236c7
AJ
370 } else {
371 const auto xerrno = errno;
372 debugs(83, DBG_IMPORTANT, "WARNING: Failed to open '" << dhParamsFile << "'" << ReportSysError(xerrno));
373 return;
474f076e
AJ
374 }
375
104deb98
AJ
376 if (!dhp) {
377 debugs(83, DBG_IMPORTANT, "WARNING: Failed to read DH parameters '" << dhParamsFile << "'");
474f076e
AJ
378 return;
379 }
380
104deb98
AJ
381 int codes;
382 if (DH_check(dhp, &codes) == 0) {
383 if (codes) {
a4dd5bfa 384 debugs(83, DBG_IMPORTANT, "WARNING: Failed to verify DH parameters '" << dhParamsFile << "' (" << asHex(codes) << ")");
104deb98
AJ
385 DH_free(dhp);
386 dhp = nullptr;
387 }
474f076e 388 }
104deb98 389
35b3559c 390 parsedDhParams.resetWithoutLocking(dhp);
742236c7
AJ
391
392#else // OpenSSL 3.0+
393 const auto type = eecdhCurve.isEmpty() ? "DH" : "EC";
394
395 Ssl::ForgetErrors();
396 EVP_PKEY *rawPkey = nullptr;
397 using DecoderContext = std::unique_ptr<OSSL_DECODER_CTX, HardFun<void, OSSL_DECODER_CTX*, &OSSL_DECODER_CTX_free> >;
398 if (const DecoderContext dctx{OSSL_DECODER_CTX_new_for_pkey(&rawPkey, "PEM", nullptr, type, 0, nullptr, nullptr)}) {
399
400 // OpenSSL documentation is vague on this, but OpenSSL code and our
401 // tests suggest that rawPkey remains nil here while rawCtx keeps
402 // rawPkey _address_ for use by the decoder (see OSSL_DECODER_from_fp()
403 // below). Thus, we must not move *rawPkey into a smart pointer until
404 // decoding is over. For cleanup code simplicity, we assert nil rawPkey.
405 assert(!rawPkey);
406
407 if (OSSL_DECODER_CTX_get_num_decoders(dctx.get()) == 0) {
408 debugs(83, DBG_IMPORTANT, "WARNING: No suitable decoders found for " << type << " parameters" << Ssl::ReportAndForgetErrors);
409 return;
410 }
411
412 if (const auto in = fopen(dhParamsFile.c_str(), "r")) {
413 if (OSSL_DECODER_from_fp(dctx.get(), in)) {
414 assert(rawPkey);
415 const Security::DhePointer pkey(rawPkey);
416 // TODO: verify that the loaded parameters match the curve named in eecdhCurve
417
418 if (const Ssl::EVP_PKEY_CTX_Pointer pkeyCtx{EVP_PKEY_CTX_new_from_pkey(nullptr, pkey.get(), nullptr)}) {
419 switch (EVP_PKEY_param_check(pkeyCtx.get())) {
420 case 1: // success
421 parsedDhParams = pkey;
422 break;
423 case -2:
424 debugs(83, DBG_PARSE_NOTE(2), "WARNING: OpenSSL does not support " << type << " parameters check: " << dhParamsFile << Ssl::ReportAndForgetErrors);
425 break;
426 default:
427 debugs(83, DBG_IMPORTANT, "ERROR: Failed to verify " << type << " parameters in " << dhParamsFile << Ssl::ReportAndForgetErrors);
428 break;
429 }
430 } else {
431 // TODO: Reduce error reporting code duplication.
432 debugs(83, DBG_IMPORTANT, "ERROR: Cannot check " << type << " parameters in " << dhParamsFile << Ssl::ReportAndForgetErrors);
433 }
434 } else {
435 debugs(83, DBG_IMPORTANT, "WARNING: Failed to decode " << type << " parameters '" << dhParamsFile << "'" << Ssl::ReportAndForgetErrors);
436 EVP_PKEY_free(rawPkey); // probably still nil, but just in case
437 }
438 fclose(in);
439 } else {
440 const auto xerrno = errno;
441 debugs(83, DBG_IMPORTANT, "WARNING: Failed to open '" << dhParamsFile << "'" << ReportSysError(xerrno));
442 }
443
444 } else {
445 debugs(83, DBG_IMPORTANT, "WARNING: Unable to create decode context for " << type << " parameters" << Ssl::ReportAndForgetErrors);
446 return;
447 }
104deb98 448#endif
742236c7 449#endif // USE_OPENSSL
104deb98
AJ
450}
451
cf487124
AJ
452bool
453Security::ServerOptions::updateContextConfig(Security::ContextPointer &ctx)
454{
455 updateContextOptions(ctx);
456 updateContextSessionId(ctx);
457
458#if USE_OPENSSL
459 if (parsedFlags & SSL_FLAG_NO_SESSION_REUSE) {
460 SSL_CTX_set_session_cache_mode(ctx.get(), SSL_SESS_CACHE_OFF);
461 }
462
463 if (Config.SSL.unclean_shutdown) {
464 debugs(83, 5, "Enabling quiet SSL shutdowns (RFC violation).");
465 SSL_CTX_set_quiet_shutdown(ctx.get(), 1);
466 }
467
468 if (!sslCipher.isEmpty()) {
469 debugs(83, 5, "Using cipher suite " << sslCipher << ".");
470 if (!SSL_CTX_set_cipher_list(ctx.get(), sslCipher.c_str())) {
471 auto ssl_error = ERR_get_error();
472 debugs(83, DBG_CRITICAL, "ERROR: Failed to set SSL cipher suite '" << sslCipher << "': " << Security::ErrorString(ssl_error));
473 return false;
474 }
475 }
476
477 Ssl::MaybeSetupRsaCallback(ctx);
478#endif
479
480 updateContextEecdh(ctx);
481 updateContextCa(ctx);
482 updateContextClientCa(ctx);
483
484#if USE_OPENSSL
c97d832b 485 SSL_CTX_set_mode(ctx.get(), SSL_MODE_NO_AUTO_CHAIN);
cf487124
AJ
486 if (parsedFlags & SSL_FLAG_DONT_VERIFY_DOMAIN)
487 SSL_CTX_set_ex_data(ctx.get(), ssl_ctx_ex_index_dont_verify_domain, (void *) -1);
488
489 Security::SetSessionCacheCallbacks(ctx);
490#endif
491 return true;
492}
493
621f4299
AJ
494void
495Security::ServerOptions::updateContextClientCa(Security::ContextPointer &ctx)
496{
497#if USE_OPENSSL
498 if (clientCaStack) {
499 ERR_clear_error();
500 if (STACK_OF(X509_NAME) *clientca = SSL_dup_CA_list(clientCaStack.get())) {
501 SSL_CTX_set_client_CA_list(ctx.get(), clientca);
502 } else {
503 auto ssl_error = ERR_get_error();
504 debugs(83, DBG_CRITICAL, "ERROR: Failed to dupe the client CA list: " << Security::ErrorString(ssl_error));
505 return;
506 }
507
983fab6e 508 Ssl::ConfigurePeerVerification(ctx, parsedFlags);
621f4299
AJ
509
510 updateContextCrl(ctx);
98f951b7 511 updateContextTrust(ctx);
621f4299
AJ
512
513 } else {
983fab6e 514 Ssl::DisablePeerVerification(ctx);
621f4299 515 }
8b082ed9
FC
516#else
517 (void)ctx;
621f4299
AJ
518#endif
519}
520
104deb98 521void
b23f5f9c 522Security::ServerOptions::updateContextEecdh(Security::ContextPointer &ctx)
104deb98
AJ
523{
524 // set Elliptic Curve details into the server context
525 if (!eecdhCurve.isEmpty()) {
526 debugs(83, 9, "Setting Ephemeral ECDH curve to " << eecdhCurve << ".");
527
528#if USE_OPENSSL && OPENSSL_VERSION_NUMBER >= 0x0090800fL && !defined(OPENSSL_NO_ECDH)
742236c7
AJ
529
530 Ssl::ForgetErrors();
531
104deb98
AJ
532 int nid = OBJ_sn2nid(eecdhCurve.c_str());
533 if (!nid) {
534 debugs(83, DBG_CRITICAL, "ERROR: Unknown EECDH curve '" << eecdhCurve << "'");
535 return;
536 }
537
742236c7 538#if OPENSSL_VERSION_MAJOR < 3
104deb98
AJ
539 auto ecdh = EC_KEY_new_by_curve_name(nid);
540 if (!ecdh) {
ea574635
AJ
541 const auto x = ERR_get_error();
542 debugs(83, DBG_CRITICAL, "ERROR: Unable to configure Ephemeral ECDH: " << Security::ErrorString(x));
104deb98
AJ
543 return;
544 }
545
b23f5f9c 546 if (!SSL_CTX_set_tmp_ecdh(ctx.get(), ecdh)) {
ea574635
AJ
547 const auto x = ERR_get_error();
548 debugs(83, DBG_CRITICAL, "ERROR: Unable to set Ephemeral ECDH: " << Security::ErrorString(x));
104deb98
AJ
549 }
550 EC_KEY_free(ecdh);
551
742236c7
AJ
552#else
553 // TODO: Support multiple group names via SSL_CTX_set1_groups_list().
554 if (!SSL_CTX_set1_groups(ctx.get(), &nid, 1)) {
555 debugs(83, DBG_CRITICAL, "ERROR: Unable to set Ephemeral ECDH: " << Ssl::ReportAndForgetErrors);
556 return;
557 }
558#endif
474f076e 559#else
104deb98
AJ
560 debugs(83, DBG_CRITICAL, "ERROR: EECDH is not available in this build." <<
561 " Please link against OpenSSL>=0.9.8 and ensure OPENSSL_NO_ECDH is not set.");
8b082ed9 562 (void)ctx;
104deb98
AJ
563#endif
564 }
565
566 // set DH parameters into the server context
567#if USE_OPENSSL
b1a522a0 568 if (parsedDhParams) {
b23f5f9c 569 SSL_CTX_set_tmp_dh(ctx.get(), parsedDhParams.get());
104deb98 570 }
474f076e
AJ
571#endif
572}
573
cf487124
AJ
574void
575Security::ServerOptions::updateContextSessionId(Security::ContextPointer &ctx)
576{
577#if USE_OPENSSL
578 if (!staticContextSessionId.isEmpty())
579 SSL_CTX_set_session_id_context(ctx.get(), reinterpret_cast<const unsigned char*>(staticContextSessionId.rawContent()), staticContextSessionId.length());
8b082ed9
FC
580#else
581 (void)ctx;
cf487124
AJ
582#endif
583}
584