Squid Web Cache master
Loading...
Searching...
No Matches
support.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2026 The Squid Software Foundation and contributors
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/* DEBUG: section 83 SSL accelerator support */
10
11#include "squid.h"
12
13/* MS Visual Studio Projects are monolithic, so we need the following
14 * #if to exclude the SSL code from compile process when not needed.
15 */
16#if USE_OPENSSL
17
18#include "acl/FilledChecklist.h"
19#include "anyp/Host.h"
20#include "anyp/PortCfg.h"
21#include "anyp/Uri.h"
22#include "fatal.h"
23#include "fd.h"
24#include "fde.h"
25#include "globals.h"
26#include "ip/Address.h"
27#include "ipc/MemMap.h"
28#include "security/CertError.h"
31#include "security/Session.h"
32#include "SquidConfig.h"
33#include "ssl/bio.h"
34#include "ssl/Config.h"
35#include "ssl/ErrorDetail.h"
36#include "ssl/gadgets.h"
37#include "ssl/support.h"
38
39#include <cerrno>
40
41// TODO: Move ssl_ex_index_* global variables from global.cc here.
43
44const EVP_MD *Ssl::DefaultSignHash = nullptr;
45
46std::vector<const char *> Ssl::BumpModeStr = {
47 "none",
48 "client-first",
49 "server-first",
50 "peek",
51 "stare",
52 "bump",
53 "splice",
54 "terminate"
55 /*,"err"*/
56};
57
58namespace Ssl {
59
62{
63public:
64 explicit OneNameMatcher(const AnyP::Host &needle): needle_(needle) {}
65
66protected:
67 /* GeneralNameMatcher API */
68 bool matchDomainName(const Dns::DomainName &) const override;
69 bool matchIp(const Ip::Address &) const override;
70
72};
73
74static CertsIndexedList &
76{
77 static auto untrustedCerts = new CertsIndexedList();
78 return *untrustedCerts;
79}
80
81} // namespace Ssl
82
83bool
85{
86 if (const auto domain = name.domainName())
87 return matchDomainName(*domain);
88 if (const auto ip = name.ip())
89 return matchIp(*ip);
90 Assure(!"unreachable code: the above `if` statements must cover all name variants");
91 return false;
92}
93
94bool
96 // TODO: Add debugs() stream manipulator to safely (i.e. without breaking
97 // cache.log message framing) dump raw input that may contain new lines. Use
98 // here and in similar contexts where we report such raw input.
99 debugs(83, 5, "needle=" << needle_ << " domain=" << rawName);
100 if (needle_.ip()) {
101 // for example, a 127.0.0.1 IP needle does not match DNS:127.0.0.1 SAN
102 debugs(83, 7, "needle is an IP; mismatch");
103 return false;
104 }
105
106 Assure(needle_.domainName());
107 auto domainNeedle = *needle_.domainName();
108
109 auto name = rawName;
110 if (name.length() > 0 && name[0] == '*')
111 name.consume(1);
112
113 return ::matchDomainName(domainNeedle.c_str(), name.c_str(), mdnRejectSubsubDomains) == 0;
114}
115
116bool
118 debugs(83, 5, "needle=" << needle_ << " ip=" << ip);
119 if (const auto needleIp = needle_.ip())
120 return (*needleIp == ip);
121 debugs(83, 7, "needle is not an IP; mismatch");
122 return false;
123}
124
130int
131Ssl::AskPasswordCb(char *buf, int size, int /* rwflag */, void *userdata)
132{
133 FILE *in;
134 int len = 0;
135 char cmdline[1024];
136
137 snprintf(cmdline, sizeof(cmdline), "\"%s\" \"%s\"", ::Config.Program.ssl_password, (const char *)userdata);
138 in = popen(cmdline, "r");
139
140 if (fgets(buf, size, in))
141
142 len = strlen(buf);
143
144 while (len > 0 && (buf[len - 1] == '\n' || buf[len - 1] == '\r'))
145 --len;
146
147 buf[len] = '\0';
148
149 pclose(in);
150
151 return len;
152}
153
155static void
156ssl_ask_password(SSL_CTX * context, const char * prompt)
157{
159 SSL_CTX_set_default_passwd_cb(context, Ssl::AskPasswordCb);
160 SSL_CTX_set_default_passwd_cb_userdata(context, (void *)prompt);
161 }
162}
163
164#if HAVE_LIBSSL_SSL_CTX_SET_TMP_RSA_CALLBACK
165static RSA *
166ssl_temp_rsa_cb(SSL *, int, int keylen)
167{
168 static RSA *rsa_512 = nullptr;
169 static RSA *rsa_1024 = nullptr;
170 static BIGNUM *e = nullptr;
171 RSA *rsa = nullptr;
172 int newkey = 0;
173
174 if (!e) {
175 e = BN_new();
176 if (!e || !BN_set_word(e, RSA_F4)) {
177 debugs(83, DBG_IMPORTANT, "ERROR: ssl_temp_rsa_cb: Failed to set exponent for key " << keylen);
178 BN_free(e);
179 e = nullptr;
180 return nullptr;
181 }
182 }
183
184 switch (keylen) {
185
186 case 512:
187
188 if (!rsa_512) {
189 rsa_512 = RSA_new();
190 if (rsa_512 && RSA_generate_key_ex(rsa_512, 512, e, nullptr)) {
191 newkey = 1;
192 } else {
193 RSA_free(rsa_512);
194 rsa_512 = nullptr;
195 }
196 }
197
198 rsa = rsa_512;
199 break;
200
201 case 1024:
202
203 if (!rsa_1024) {
204 rsa_1024 = RSA_new();
205 if (rsa_1024 && RSA_generate_key_ex(rsa_1024, 1024, e, nullptr)) {
206 newkey = 1;
207 } else {
208 RSA_free(rsa_1024);
209 rsa_1024 = nullptr;
210 }
211 }
212
213 rsa = rsa_1024;
214 break;
215
216 default:
217 debugs(83, DBG_IMPORTANT, "ERROR: ssl_temp_rsa_cb: Unexpected key length " << keylen);
218 return nullptr;
219 }
220
221 if (rsa == NULL) {
222 debugs(83, DBG_IMPORTANT, "ERROR: ssl_temp_rsa_cb: Failed to generate key " << keylen);
223 return nullptr;
224 }
225
226 if (newkey) {
227 if (Debug::Enabled(83, 5))
228 PEM_write_RSAPrivateKey(DebugStream(), rsa, nullptr, nullptr, 0, nullptr, nullptr);
229
230 debugs(83, DBG_IMPORTANT, "Generated ephemeral RSA key of length " << keylen);
231 }
232
233 return rsa;
234}
235#endif
236
237void
239{
240#if HAVE_LIBSSL_SSL_CTX_SET_TMP_RSA_CALLBACK
241 debugs(83, 9, "Setting RSA key generation callback.");
242 SSL_CTX_set_tmp_rsa_callback(ctx.get(), ssl_temp_rsa_cb);
243#else
244 (void)ctx;
245#endif
246}
247
248int Ssl::asn1timeToString(ASN1_TIME *tm, char *buf, int len)
249{
250 BIO *bio;
251 int write = 0;
252 bio = BIO_new(BIO_s_mem());
253 if (bio) {
254 if (ASN1_TIME_print(bio, tm))
255 write = BIO_read(bio, buf, len-1);
256 BIO_free(bio);
257 }
258 buf[write]='\0';
259 return write;
260}
261
262static std::optional<AnyP::Host>
263ParseSubjectAltName(const GENERAL_NAME &san)
264{
265 switch(san.type) {
266 case GEN_DNS: {
267 Assure(san.d.dNSName);
268 // GEN_DNS is an IA5STRING. IA5STRING is a subset of ASCII that does not
269 // need to be converted to UTF-8 (or some such) before we parse it.
270 const auto buffer = Ssl::AsnToSBuf(*san.d.dNSName);
271 return AnyP::Host::ParseWildDomainName(buffer);
272 }
273
274 case GEN_IPADD: {
275 // san.d.iPAddress is OpenSSL ASN1_OCTET_STRING
276 Assure(san.d.iPAddress);
277
278 // RFC 5280 section 4.2.1.6 signals IPv4/IPv6 address family using data length
279
280 if (san.d.iPAddress->length == 4) {
281 struct in_addr addr;
282 static_assert(sizeof(addr.s_addr) == 4);
283 memcpy(&addr.s_addr, san.d.iPAddress->data, sizeof(addr.s_addr));
284 const Ip::Address ip(addr);
285 return AnyP::Host::ParseIp(ip);
286 }
287
288 if (san.d.iPAddress->length == 16) {
289 struct in6_addr addr;
290 static_assert(sizeof(addr.s6_addr) == 16);
291 memcpy(&addr.s6_addr, san.d.iPAddress->data, sizeof(addr.s6_addr));
292 const Ip::Address ip(addr);
293 return AnyP::Host::ParseIp(ip);
294 }
295
296 debugs(83, 3, "unexpected length of an IP address SAN: " << san.d.iPAddress->length);
297 return std::nullopt;
298 }
299
300 default:
301 debugs(83, 3, "unsupported SAN kind: " << san.type);
302 return std::nullopt;
303 }
304}
305
306bool
308{
309 const auto name = X509_get_subject_name(&cert);
310 for (int i = X509_NAME_get_index_by_NID(name, NID_commonName, -1); i >= 0; i = X509_NAME_get_index_by_NID(name, NID_commonName, i)) {
311 debugs(83, 7, "checking CN at " << i);
312 if (const auto cn = ParseCommonNameAt(*name, i)) {
313 if (matcher.match(*cn))
314 return true;
315 }
316 }
317
318 const Ssl::GENERAL_NAME_STACK_Pointer sans(static_cast<STACK_OF(GENERAL_NAME)*>(
319 X509_get_ext_d2i(&cert, NID_subject_alt_name, nullptr, nullptr)));
320 if (sans) {
321 const auto sanCount = sk_GENERAL_NAME_num(sans.get());
322 for (int i = 0; i < sanCount; ++i) {
323 debugs(83, 7, "checking SAN at " << i);
324 const auto rawSan = sk_GENERAL_NAME_value(sans.get(), i);
325 Assure(rawSan);
326 if (const auto san = ParseSubjectAltName(*rawSan)) {
327 if (matcher.match(*san))
328 return true;
329 }
330 }
331 }
332
333 debugs(83, 7, "no matches");
334 return false;
335}
336
337bool
338Ssl::HasSubjectName(X509 &cert, const AnyP::Host &host)
339{
340 return HasMatchingSubjectName(cert, OneNameMatcher(host));
341}
342
345static int
346ssl_verify_cb(int ok, X509_STORE_CTX * ctx)
347{
348 // preserve original ctx->error before SSL_ calls can overwrite it
349 Security::ErrorCode error_no = ok ? SSL_ERROR_NONE : X509_STORE_CTX_get_error(ctx);
350
351 SSL *ssl = (SSL *)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
352 SSL_CTX *sslctx = SSL_get_SSL_CTX(ssl);
353 SBuf *server = (SBuf *)SSL_get_ex_data(ssl, ssl_ex_index_server);
354 void *dont_verify_domain = SSL_CTX_get_ex_data(sslctx, ssl_ctx_ex_index_dont_verify_domain);
355 ACLChecklist *check = (ACLChecklist*)SSL_get_ex_data(ssl, ssl_ex_index_cert_error_check);
356 X509 *peeked_cert = (X509 *)SSL_get_ex_data(ssl, ssl_ex_index_ssl_peeked_cert);
357 Security::CertPointer peer_cert;
359
360 // detect infinite loops
361 uint32_t *validationCounter = static_cast<uint32_t *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_validation_counter));
362 if (!validationCounter) {
363 validationCounter = new uint32_t(1);
364 SSL_set_ex_data(ssl, ssl_ex_index_ssl_validation_counter, validationCounter);
365 } else {
366 // overflows allowed if SQUID_CERT_VALIDATION_ITERATION_MAX >= UINT32_MAX
367 (*validationCounter)++;
368 }
369
370 if ((*validationCounter) >= SQUID_CERT_VALIDATION_ITERATION_MAX) {
371 ok = 0; // or the validation loop will never stop
373 debugs(83, 2, "SQUID_X509_V_ERR_INFINITE_VALIDATION: " <<
374 *validationCounter << " iterations while checking " << *peer_cert);
375 }
376
377 if (ok) {
378 debugs(83, 5, "SSL Certificate signature OK: " << *peer_cert);
379
380 // Check for domain mismatch only if the current certificate is the peer certificate.
381 if (!dont_verify_domain && server && peer_cert.get() == X509_STORE_CTX_get_current_cert(ctx)) {
382 // XXX: This code does not know where the server name came from. The
383 // name may be valid but not compatible with requirements assumed or
384 // enforced by the AnyP::Host::ParseSimpleDomainName() call below.
385 // TODO: Store AnyP::Host (or equivalent) in ssl_ex_index_server.
386 if (const auto host = Ssl::ParseAsSimpleDomainNameOrIp(*server)) {
387 if (Ssl::HasSubjectName(*peer_cert, *host)) {
388 debugs(83, 5, "certificate subject matches " << *host);
389 } else {
390 debugs(83, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Certificate " << *peer_cert << " does not match domainname " << *host);
391 ok = 0;
393 }
394 } else {
395 debugs(83, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Cannot check whether certificate " << *peer_cert << " subject matches malformed domainname " << *server);
396 ok = 0;
398 }
399 }
400 }
401
402 if (ok && peeked_cert) {
403 // Check whether the already peeked certificate matches the new one.
404 if (X509_cmp(peer_cert.get(), peeked_cert) != 0) {
405 debugs(83, 2, "SQUID_X509_V_ERR_CERT_CHANGE: Certificate " << *peer_cert << " does not match peeked certificate");
406 ok = 0;
408 }
409 }
410
411 if (!ok && error_no == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) {
412 if (const auto params = Ssl::VerifyCallbackParameters::Find(*ssl)) {
413 if (params->callerHandlesMissingCertificates) {
414 debugs(83, 3, "hiding X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY");
415 params->hidMissingIssuer = true;
416 ok = 1;
417 }
418 }
419 }
420
421 if (!ok) {
422 Security::CertPointer broken_cert;
423 broken_cert.resetAndLock(X509_STORE_CTX_get_current_cert(ctx));
424 if (!broken_cert)
425 broken_cert = peer_cert;
426
427 Security::CertErrors *errs = static_cast<Security::CertErrors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors));
428 const int depth = X509_STORE_CTX_get_error_depth(ctx);
429 if (!errs) {
430 errs = new Security::CertErrors(Security::CertError(error_no, broken_cert, depth));
431 if (!SSL_set_ex_data(ssl, ssl_ex_index_ssl_errors, (void *)errs)) {
432 debugs(83, 2, "Failed to set ssl error_no in ssl_verify_cb: Certificate " << *peer_cert);
433 delete errs;
434 errs = nullptr;
435 }
436 } else // remember another error number
437 errs->push_back_unique(Security::CertError(error_no, broken_cert, depth));
438
439 if (const auto description = Ssl::GetErrorDescr(error_no))
440 debugs(83, 5, *description << ": " << *peer_cert);
441 else
442 debugs(83, DBG_IMPORTANT, "ERROR: SSL unknown certificate error " << error_no << " in " << *peer_cert);
443
444 // Check if the certificate error can be bypassed.
445 // Infinity validation loop errors can not bypassed.
446 if (error_no != SQUID_X509_V_ERR_INFINITE_VALIDATION) {
447 if (check) {
448 ACLFilledChecklist *filledCheck = Filled(check);
449 const auto savedErrors = filledCheck->sslErrors;
450 const auto sslErrors = std::make_unique<Security::CertErrors>(Security::CertError(error_no, broken_cert));
451 filledCheck->sslErrors = sslErrors.get();
452 filledCheck->serverCert = peer_cert;
453 if (check->fastCheck().allowed()) {
454 debugs(83, 3, "bypassing SSL error " << error_no << " in " << *peer_cert);
455 ok = 1;
456 } else {
457 debugs(83, 5, "confirming SSL error " << error_no);
458 }
459 filledCheck->sslErrors = savedErrors;
460 filledCheck->serverCert.reset();
461 }
462 // If the certificate validator is used then we need to allow all errors and
463 // pass them to certificate validator for more processing
464 else if (Ssl::TheConfig.ssl_crt_validator) {
465 ok = 1;
466 }
467 }
468 }
469
470 if (Ssl::TheConfig.ssl_crt_validator) {
471 // Check if we have stored certificates chain. Store if not.
472 if (!SSL_get_ex_data(ssl, ssl_ex_index_ssl_cert_chain)) {
473 STACK_OF(X509) *certStack = X509_STORE_CTX_get1_chain(ctx);
474 if (certStack && !SSL_set_ex_data(ssl, ssl_ex_index_ssl_cert_chain, certStack))
475 sk_X509_pop_free(certStack, X509_free);
476 }
477 }
478
479 if (!ok && !SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_detail) ) {
480
481 // Find the broken certificate. It may be intermediate.
482 Security::CertPointer broken_cert(peer_cert); // reasonable default if search fails
483 // Our SQUID_X509_V_ERR_DOMAIN_MISMATCH implies peer_cert is at fault.
484 if (error_no != SQUID_X509_V_ERR_DOMAIN_MISMATCH) {
485 if (auto *last_used_cert = X509_STORE_CTX_get_current_cert(ctx))
486 broken_cert.resetAndLock(last_used_cert);
487 }
488
489 std::unique_ptr<Security::ErrorDetail::Pointer> edp(new Security::ErrorDetail::Pointer(
490 new Security::ErrorDetail(error_no, peer_cert, broken_cert)));
491 if (SSL_set_ex_data(ssl, ssl_ex_index_ssl_error_detail, edp.get()))
492 edp.release();
493 else
494 debugs(83, 2, "failed to store a " << *peer_cert << " error detail: " << *edp);
495 }
496
497 return ok;
498}
499
500void
502{
503 int mode;
504
505 // assume each flag is exclusive; flags creator must check this assumption
506 if (flags & SSL_FLAG_DONT_VERIFY_PEER) {
507 debugs(83, DBG_IMPORTANT, "SECURITY WARNING: Peer certificates are not verified for validity!");
508 debugs(83, DBG_IMPORTANT, "WARNING: UPGRADE: The DONT_VERIFY_PEER flag is deprecated. Remove the clientca= option to disable client certificates.");
509 mode = SSL_VERIFY_NONE;
510 }
511 else if (flags & SSL_FLAG_CONDITIONAL_AUTH) {
512 debugs(83, DBG_PARSE_NOTE(3), "will request the client certificate but ignore its absence");
513 mode = SSL_VERIFY_PEER;
514 }
515 else {
516 debugs(83, DBG_PARSE_NOTE(3), "Requiring client certificates.");
517 mode = SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
518 }
519
520 SSL_CTX_set_verify(ctx.get(), mode, (mode != SSL_VERIFY_NONE) ? ssl_verify_cb : nullptr);
521}
522
523void
525{
526 debugs(83, DBG_PARSE_NOTE(3), "Not requiring any client certificates");
527 SSL_CTX_set_verify(ctx.get(),SSL_VERIFY_NONE,nullptr);
528}
529
530static int VerifyCtxCertificates(X509_STORE_CTX *ctx, STACK_OF(X509) *extraCerts);
531
532bool
534{
535 const auto peerCertificatesChain = SSL_get_peer_cert_chain(&sconn);
536
537 // TODO: Replace debugs/return false with returning ErrorDetail::Pointer.
538 // Using Security::ErrorDetail terminology, errors in _this_ function are
539 // "non-validation errors", but VerifyCtxCertificates() errors may be
540 // "certificate validation errors". Callers detail SQUID_TLS_ERR_CONNECT.
541 // Some details should be created right here. Others extracted from OpenSSL.
542 // Why not throw? Most of the reasons detailed in the following commit apply
543 // here as well: https://github.com/measurement-factory/squid/commit/e862d33
544
545 if (!peerCertificatesChain || sk_X509_num(peerCertificatesChain) == 0) {
546 debugs(83, 2, "no server certificates");
547 return false;
548 }
549
550 const auto verificationStore = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(&sconn));
551 if (!verificationStore) {
552 debugs(83, 2, "no certificate store");
553 return false;
554 }
555
556 const X509_STORE_CTX_Pointer storeCtx(X509_STORE_CTX_new());
557 if (!storeCtx) {
558 debugs(83, 2, "cannot create X509_STORE_CTX; likely OOM");
559 return false;
560 }
561
562 const auto peerCert = sk_X509_value(peerCertificatesChain, 0);
563 if (!X509_STORE_CTX_init(storeCtx.get(), verificationStore, peerCert, peerCertificatesChain)) {
564 debugs(83, 2, "cannot initialize X509_STORE_CTX");
565 return false;
566 }
567
568#if defined(SSL_CERT_FLAG_SUITEB_128_LOS)
569 // overwrite context Suite B (RFC 5759) flags with connection non-defaults
570 // SSL_set_cert_flags() return type is long, but its implementation actually
571 // returns an unsigned long flags value expected by X509_STORE_CTX_set_flags
572 const unsigned long certFlags = SSL_set_cert_flags(&sconn, 0);
573 if (const auto suiteBflags = certFlags & SSL_CERT_FLAG_SUITEB_128_LOS)
574 X509_STORE_CTX_set_flags(storeCtx.get(), suiteBflags);
575#endif
576
577 if (!X509_STORE_CTX_set_ex_data(storeCtx.get(), SSL_get_ex_data_X509_STORE_CTX_idx(), &sconn)) {
578 debugs(83, 2, "cannot attach SSL object to X509_STORE_CTX");
579 return false;
580 }
581
582 // If we ever add DANE support to Squid, we will supply DANE details here:
583 // X509_STORE_CTX_set0_dane(storeCtx.get(), SSL_get0_dane(&sconn));
584
585 // tell OpenSSL we are verifying a server certificate
586 if (!X509_STORE_CTX_set_default(storeCtx.get(), "ssl_server")) {
587 debugs(83, 2, "cannot set default verification method to ssl_server");
588 return false;
589 }
590
591 // overwrite context "verification parameters" with connection non-defaults
592 const auto param = X509_STORE_CTX_get0_param(storeCtx.get());
593 if (!param) {
594 debugs(83, 2, "no context verification parameters");
595 return false;
596 }
597#if defined(HAVE_X509_VERIFY_PARAM_SET_AUTH_LEVEL)
598 X509_VERIFY_PARAM_set_auth_level(param, SSL_get_security_level(&sconn));
599#endif
600 if (!X509_VERIFY_PARAM_set1(param, SSL_get0_param(&sconn))) {
601 debugs(83, 2, "cannot overwrite context verification parameters");
602 return false;
603 }
604
605 // copy any connection "verify_callback function" to the validation context
606 // (\ref OpenSSL_vcb_disambiguation)
607 if (const auto cb = SSL_get_verify_callback(&sconn))
608 X509_STORE_CTX_set_verify_cb(storeCtx.get(), cb);
609
610 // verify the server certificate chain in the prepared validation context
611 if (VerifyCtxCertificates(storeCtx.get(), extraCerts.get()) <= 0) {
612 // see also: ssl_verify_cb() details errors via ssl_ex_index_ssl_errors
613 const auto verifyResult = X509_STORE_CTX_get_error(storeCtx.get());
614 debugs(83, 3, "verification failure: " << verifyResult << ' ' << X509_verify_cert_error_string(verifyResult));
615 return false;
616 }
617
618 debugs(83, 7, "success");
619 return true;
620}
621
622/* Ssl::VerifyCallbackParameters */
623
629
632{
633 Must(!Find(sconn));
634 const auto parameters = new VerifyCallbackParameters();
635 if (!SSL_set_ex_data(&sconn, ssl_ex_index_verify_callback_parameters, parameters)) {
636 delete parameters;
637 throw TextException("SSL_set_ex_data() failed; likely OOM", Here());
638 }
639 return parameters;
640}
641
644{
645 const auto parameters = Find(sconn);
646 Must(parameters);
647 return *parameters;
648}
649
650// "dup" function for SSL_get_ex_new_index("cert_err_check")
651#if OPENSSL_VERSION_MAJOR >= 3
652static int
653ssl_dupAclChecklist(CRYPTO_EX_DATA *, const CRYPTO_EX_DATA *, void **,
654 int, long, void *)
655#elif SQUID_USE_CONST_CRYPTO_EX_DATA_DUP
656static int
657ssl_dupAclChecklist(CRYPTO_EX_DATA *, const CRYPTO_EX_DATA *, void *,
658 int, long, void *)
659#else
660static int
661ssl_dupAclChecklist(CRYPTO_EX_DATA *, CRYPTO_EX_DATA *, void *,
662 int, long, void *)
663#endif
664{
665 // We do not support duplication of ACLCheckLists.
666 // If duplication is needed, we can count copies with cbdata.
667 assert(false);
668 return 0;
669}
670
671// "free" function for SSL_get_ex_new_index("cert_err_check")
672static void
673ssl_freeAclChecklist(void *, void *ptr, CRYPTO_EX_DATA *,
674 int, long, void *)
675{
676 delete static_cast<ACLChecklist *>(ptr); // may be NULL
677}
678
679// "free" function for SSL_get_ex_new_index("ssl_error_detail")
680static void
681ssl_free_ErrorDetail(void *, void *ptr, CRYPTO_EX_DATA *,
682 int, long, void *)
683{
684 const auto errDetail = static_cast<Security::ErrorDetail::Pointer*>(ptr);
685 delete errDetail;
686}
687
688static void
689ssl_free_SslErrors(void *, void *ptr, CRYPTO_EX_DATA *,
690 int, long, void *)
691{
692 Security::CertErrors *errs = static_cast <Security::CertErrors*>(ptr);
693 delete errs;
694}
695
696// "free" function for SSL_get_ex_new_index("ssl_ex_index_ssl_validation_counter")
697static void
698ssl_free_int(void *, void *ptr, CRYPTO_EX_DATA *,
699 int, long, void *)
700{
701 uint32_t *counter = static_cast <uint32_t *>(ptr);
702 delete counter;
703}
704
708static void
709ssl_free_CertChain(void *, void *ptr, CRYPTO_EX_DATA *,
710 int, long, void *)
711{
712 STACK_OF(X509) *certsChain = static_cast <STACK_OF(X509) *>(ptr);
713 sk_X509_pop_free(certsChain,X509_free);
714}
715
716// "free" function for X509 certificates
717static void
718ssl_free_X509(void *, void *ptr, CRYPTO_EX_DATA *,
719 int, long, void *)
720{
721 X509 *cert = static_cast <X509 *>(ptr);
722 X509_free(cert);
723}
724
725// "free" function for SBuf
726static void
727ssl_free_SBuf(void *, void *ptr, CRYPTO_EX_DATA *,
728 int, long, void *)
729{
730 SBuf *buf = static_cast <SBuf *>(ptr);
731 delete buf;
732}
733
735static void
736ssl_free_VerifyCallbackParameters(void *, void *ptr, CRYPTO_EX_DATA *,
737 int, long, void *)
738{
739 delete static_cast<Ssl::VerifyCallbackParameters*>(ptr);
740}
741
742void
744{
745 static bool initialized = false;
746 if (initialized)
747 return;
748 initialized = true;
749
751
752 if (::Config.SSL.ssl_engine) {
753#if OPENSSL_VERSION_MAJOR < 3
754 debugs(83, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: Support for ssl_engine is deprecated " <<
755 "in Squids built with OpenSSL 1.x (like this Squid). " <<
756 "It is removed in Squids built with OpenSSL 3.0 or newer.");
757#if !defined(OPENSSL_NO_ENGINE)
758 ENGINE_load_builtin_engines();
759 ENGINE *e;
760 if (!(e = ENGINE_by_id(::Config.SSL.ssl_engine)))
761 fatalf("Unable to find SSL engine '%s'\n", ::Config.SSL.ssl_engine);
762
763 if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
764 const auto ssl_error = ERR_get_error();
765 fatalf("Failed to initialise SSL engine: %s\n", Security::ErrorString(ssl_error));
766 }
767#else /* OPENSSL_NO_ENGINE */
768 throw TextException("Cannot use ssl_engine in Squid built with OpenSSL configured to disable SSL engine support", Here());
769#endif
770
771#else /* OPENSSL_VERSION_MAJOR */
772 throw TextException("Cannot use ssl_engine in Squid built with OpenSSL 3.0 or newer", Here());
773#endif
774 }
775
777 Ssl::DefaultSignHash = EVP_get_digestbyname(defName);
779 fatalf("Sign hash '%s' is not supported\n", defName);
780
781 ssl_ex_index_server = SSL_get_ex_new_index(0, (void *) "server", nullptr, nullptr, ssl_free_SBuf);
782 ssl_ctx_ex_index_dont_verify_domain = SSL_CTX_get_ex_new_index(0, (void *) "dont_verify_domain", nullptr, nullptr, nullptr);
783 ssl_ex_index_cert_error_check = SSL_get_ex_new_index(0, (void *) "cert_error_check", nullptr, &ssl_dupAclChecklist, &ssl_freeAclChecklist);
784 ssl_ex_index_ssl_error_detail = SSL_get_ex_new_index(0, (void *) "ssl_error_detail", nullptr, nullptr, &ssl_free_ErrorDetail);
785 ssl_ex_index_ssl_peeked_cert = SSL_get_ex_new_index(0, (void *) "ssl_peeked_cert", nullptr, nullptr, &ssl_free_X509);
786 ssl_ex_index_ssl_errors = SSL_get_ex_new_index(0, (void *) "ssl_errors", nullptr, nullptr, &ssl_free_SslErrors);
787 ssl_ex_index_ssl_cert_chain = SSL_get_ex_new_index(0, (void *) "ssl_cert_chain", nullptr, nullptr, &ssl_free_CertChain);
788 ssl_ex_index_ssl_validation_counter = SSL_get_ex_new_index(0, (void *) "ssl_validation_counter", nullptr, nullptr, &ssl_free_int);
789 ssl_ex_index_verify_callback_parameters = SSL_get_ex_new_index(0, (void *) "verify_callback_parameters", nullptr, nullptr, &ssl_free_VerifyCallbackParameters);
790}
791
792bool
794{
795 if (!ctx)
796 return false;
797
798 return true;
799}
800
801bool
803{
804 if (!ctx)
805 return false;
806
807 if (!peer.sslCipher.isEmpty()) {
808 debugs(83, 5, "Using cipher suite " << peer.sslCipher << ".");
809
810 const char *cipher = peer.sslCipher.c_str();
811 if (!SSL_CTX_set_cipher_list(ctx.get(), cipher)) {
812 const auto ssl_error = ERR_get_error();
813 fatalf("Failed to set SSL cipher suite '%s': %s\n",
814 cipher, Security::ErrorString(ssl_error));
815 }
816 }
817
818 if (!peer.certs.empty()) {
819 // TODO: support loading multiple cert/key pairs
820 auto &keys = peer.certs.front();
821 if (!keys.certFile.isEmpty()) {
822 debugs(83, 2, "loading client certificate from " << keys.certFile);
823
824 const char *certfile = keys.certFile.c_str();
825 if (!SSL_CTX_use_certificate_chain_file(ctx.get(), certfile)) {
826 const auto ssl_error = ERR_get_error();
827 fatalf("Failed to acquire SSL certificate '%s': %s\n",
828 certfile, Security::ErrorString(ssl_error));
829 }
830
831 debugs(83, 2, "loading private key from " << keys.privateKeyFile);
832 const char *keyfile = keys.privateKeyFile.c_str();
833 ssl_ask_password(ctx.get(), keyfile);
834
835 if (!SSL_CTX_use_PrivateKey_file(ctx.get(), keyfile, SSL_FILETYPE_PEM)) {
836 const auto ssl_error = ERR_get_error();
837 fatalf("Failed to acquire SSL private key '%s': %s\n",
838 keyfile, Security::ErrorString(ssl_error));
839 }
840
841 debugs(83, 5, "Comparing private and public SSL keys.");
842
843 if (!SSL_CTX_check_private_key(ctx.get())) {
844 const auto ssl_error = ERR_get_error();
845 fatalf("SSL private key '%s' does not match public key '%s': %s\n",
846 certfile, keyfile, Security::ErrorString(ssl_error));
847 }
848 }
849 }
850
852
854
855 return true;
856}
857
859static const char *
860ssl_get_attribute(X509_NAME * name, const char *attribute_name)
861{
862 static char buffer[1024];
863 buffer[0] = '\0';
864
865 if (strcmp(attribute_name, "DN") == 0) {
866 X509_NAME_oneline(name, buffer, sizeof(buffer));
867 } else {
868 int nid = OBJ_txt2nid(const_cast<char *>(attribute_name));
869 if (nid == 0) {
870 debugs(83, DBG_IMPORTANT, "WARNING: Unknown SSL attribute name '" << attribute_name << "'");
871 return nullptr;
872 }
873 X509_NAME_get_text_by_NID(name, nid, buffer, sizeof(buffer));
874 }
875
876 return *buffer ? buffer : nullptr;
877}
878
880const char *
881Ssl::GetX509UserAttribute(X509 * cert, const char *attribute_name)
882{
883 X509_NAME *name;
884 const char *ret;
885
886 if (!cert)
887 return nullptr;
888
889 name = X509_get_subject_name(cert);
890
891 ret = ssl_get_attribute(name, attribute_name);
892
893 return ret;
894}
895
896const char *
897Ssl::GetX509Fingerprint(X509 * cert, const char *)
898{
899 static char buf[1024];
900 if (!cert)
901 return nullptr;
902
903 unsigned int n;
904 unsigned char md[EVP_MAX_MD_SIZE];
905 if (!X509_digest(cert, EVP_sha1(), md, &n))
906 return nullptr;
907
908 assert(3 * n + 1 < sizeof(buf));
909
910 char *s = buf;
911 for (unsigned int i=0; i < n; ++i, s += 3) {
912 const char term = (i + 1 < n) ? ':' : '\0';
913 snprintf(s, 4, "%02X%c", md[i], term);
914 }
915
916 return buf;
917}
918
919SBuf
920Ssl::GetX509PEM(X509 * cert)
921{
922 assert(cert);
923
924 Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem()));
925 PEM_write_bio_X509(bio.get(), cert);
926
927 char *ptr;
928 const auto len = BIO_get_mem_data(bio.get(), &ptr);
929 return SBuf(ptr, len);
930}
931
933const char *
934Ssl::GetX509CAAttribute(X509 * cert, const char *attribute_name)
935{
936
937 X509_NAME *name;
938 const char *ret;
939
940 if (!cert)
941 return nullptr;
942
943 name = X509_get_issuer_name(cert);
944
945 ret = ssl_get_attribute(name, attribute_name);
946
947 return ret;
948}
949
950const char *sslGetUserAttribute(SSL *ssl, const char *attribute_name)
951{
952 if (!ssl)
953 return nullptr;
954
955 X509 *cert = SSL_get_peer_certificate(ssl);
956
957 const char *attr = Ssl::GetX509UserAttribute(cert, attribute_name);
958
959 X509_free(cert);
960 return attr;
961}
962
963const char *sslGetCAAttribute(SSL *ssl, const char *attribute_name)
964{
965 if (!ssl)
966 return nullptr;
967
968 X509 *cert = SSL_get_peer_certificate(ssl);
969
970 const char *attr = Ssl::GetX509CAAttribute(cert, attribute_name);
971
972 X509_free(cert);
973 return attr;
974}
975
976const char *
978{
979 return sslGetUserAttribute(ssl, "emailAddress");
980}
981
982SBuf
984{
985 assert(ssl);
986
987 if (const auto cert = SSL_get_peer_certificate(ssl))
988 return Ssl::GetX509PEM(cert);
989
990 return SBuf();
991}
992
993SBuf
995{
996 assert(ssl);
997
998 auto chain = SSL_get_peer_cert_chain(ssl);
999
1000 if (!chain)
1001 return sslGetUserCertificatePEM(ssl);
1002
1003 Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem()));
1004
1005 for (int i = 0; i < sk_X509_num(chain); ++i) {
1006 X509 *cert = sk_X509_value(chain, i);
1007 PEM_write_bio_X509(bio.get(), cert);
1008 }
1009
1010 char *ptr;
1011 const auto len = BIO_get_mem_data(bio.get(), &ptr);
1012 return SBuf(ptr, len);
1013}
1014
1017Ssl::createSSLContext(Security::CertPointer & x509, Security::PrivateKeyPointer & pkey, Security::ServerOptions &options)
1018{
1020
1021 if (!SSL_CTX_use_certificate(ctx.get(), x509.get()))
1022 return Security::ContextPointer();
1023
1024 if (!SSL_CTX_use_PrivateKey(ctx.get(), pkey.get()))
1025 return Security::ContextPointer();
1026
1027 if (!options.updateContextConfig(ctx))
1028 return Security::ContextPointer();
1029
1030 return ctx;
1031}
1032
1035{
1037 Security::PrivateKeyPointer pkey;
1038 if (!readCertAndPrivateKeyFromMemory(cert, pkey, data) || !cert || !pkey)
1039 return Security::ContextPointer();
1040
1041 Security::ContextPointer ctx(createSSLContext(cert, pkey, options));
1042 if (ctx && trusted)
1044 return ctx;
1045}
1046
1049{
1051 Security::PrivateKeyPointer pkey;
1052 if (!generateSslCertificate(cert, pkey, properties) || !cert || !pkey)
1053 return Security::ContextPointer();
1054
1055 Security::ContextPointer ctx(createSSLContext(cert, pkey, options));
1056 if (ctx && trusted)
1058 return ctx;
1059}
1060
1061void
1063{
1064 assert(ctx);
1065 // Add signing certificate to the certificates chain
1066 X509 *signingCert = options.signingCa.cert.get();
1067 if (SSL_CTX_add_extra_chain_cert(ctx.get(), signingCert)) {
1068 // increase the certificate lock
1069 X509_up_ref(signingCert);
1070 } else {
1071 const auto ssl_error = ERR_get_error();
1072 debugs(33, DBG_IMPORTANT, "WARNING: can not add signing certificate to SSL context chain: " << Security::ErrorString(ssl_error));
1073 }
1074
1075 for (auto cert : options.signingCa.chain) {
1076 if (SSL_CTX_add_extra_chain_cert(ctx.get(), cert.get())) {
1077 // increase the certificate lock
1078 X509_up_ref(cert.get());
1079 } else {
1080 const auto error = ERR_get_error();
1081 debugs(83, DBG_IMPORTANT, "WARNING: can not add certificate to SSL dynamic context chain: " << Security::ErrorString(error));
1082 }
1083 }
1084}
1085
1086void
1092
1093bool
1095{
1097 Security::PrivateKeyPointer pkey;
1098 if (!generateSslCertificate(cert, pkey, properties))
1099 return false;
1100
1101 if (!cert)
1102 return false;
1103
1104 if (!pkey)
1105 return false;
1106
1107 if (!SSL_use_certificate(ssl, cert.get()))
1108 return false;
1109
1110 if (!SSL_use_PrivateKey(ssl, pkey.get()))
1111 return false;
1112
1113 return true;
1114}
1115
1116bool
1118{
1120 Security::PrivateKeyPointer pkey;
1121 if (!readCertAndPrivateKeyFromMemory(cert, pkey, data))
1122 return false;
1123
1124 if (!cert || !pkey)
1125 return false;
1126
1127 if (!SSL_use_certificate(ssl, cert.get()))
1128 return false;
1129
1130 if (!SSL_use_PrivateKey(ssl, pkey.get()))
1131 return false;
1132
1133 return true;
1134}
1135
1136bool
1138{
1139#if HAVE_SSL_CTX_GET0_CERTIFICATE
1140 X509 * cert = SSL_CTX_get0_certificate(ctx.get());
1141#elif SQUID_USE_SSLGETCERTIFICATE_HACK
1142 // SSL_get_certificate is buggy in openssl versions 1.0.1d and 1.0.1e
1143 // Try to retrieve certificate directly from Security::ContextPointer object
1144 X509 ***pCert = (X509 ***)ctx->cert;
1145 X509 * cert = pCert && *pCert ? **pCert : NULL;
1146#elif SQUID_SSLGETCERTIFICATE_BUGGY
1147 X509 * cert = nullptr;
1148 assert(0);
1149#else
1150 // Temporary ssl for getting X509 certificate from SSL_CTX.
1152 X509 * cert = SSL_get_certificate(ssl.get());
1153#endif
1154 if (!cert)
1155 return false;
1156 const auto time_notBefore = X509_getm_notBefore(cert);
1157 const auto time_notAfter = X509_getm_notAfter(cert);
1158 return (X509_cmp_current_time(time_notBefore) < 0 && X509_cmp_current_time(time_notAfter) > 0);
1159}
1160
1161void
1162Ssl::setClientSNI(SSL *ssl, const char *fqdn)
1163{
1164 const Ip::Address test(fqdn);
1165 if (!test.isAnyAddr())
1166 return; // raw IP is inappropriate for SNI
1167
1168 //The SSL_CTRL_SET_TLSEXT_HOSTNAME is a openssl macro which indicates
1169 // if the TLS servername extension (SNI) is enabled in openssl library.
1170#if defined(SSL_CTRL_SET_TLSEXT_HOSTNAME)
1171 if (!SSL_set_tlsext_host_name(ssl, fqdn)) {
1172 const auto ssl_error = ERR_get_error();
1173 debugs(83, 3, "WARNING: unable to set TLS servername extension (SNI): " <<
1174 Security::ErrorString(ssl_error) << "\n");
1175 }
1176#else
1177 debugs(83, 7, "no support for TLS servername extension (SNI)");
1178#endif
1179}
1180
1181const char *
1183{
1184 AUTHORITY_INFO_ACCESS *info;
1185 if (!cert)
1186 return nullptr;
1187 info = static_cast<AUTHORITY_INFO_ACCESS *>(X509_get_ext_d2i(cert, NID_info_access, nullptr, nullptr));
1188 if (!info)
1189 return nullptr;
1190
1191 static char uri[MAX_URL];
1192 uri[0] = '\0';
1193
1194 for (int i = 0; i < sk_ACCESS_DESCRIPTION_num(info); i++) {
1195 ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(info, i);
1196 if (OBJ_obj2nid(ad->method) == NID_ad_ca_issuers) {
1197 if (ad->location->type == GEN_URI) {
1198 xstrncpy(uri,
1199 reinterpret_cast<const char *>(
1200 ASN1_STRING_get0_data(ad->location->d.uniformResourceIdentifier)
1201 ),
1202 sizeof(uri));
1203 }
1204 break;
1205 }
1206 }
1207 AUTHORITY_INFO_ACCESS_free(info);
1208 return uri[0] != '\0' ? uri : nullptr;
1209}
1210
1211bool
1212Ssl::loadCerts(const char *certsFile, Ssl::CertsIndexedList &list)
1213{
1214 const BIO_Pointer in(BIO_new_file(certsFile, "r"));
1215 if (!in) {
1216 debugs(83, DBG_IMPORTANT, "ERROR: Failed to open '" << certsFile << "' to load certificates");
1217 return false;
1218 }
1219
1220 while (auto aCert = ReadOptionalCertificate(in)) {
1221 const auto name = Security::SubjectName(*aCert);
1222 list.insert(std::pair<SBuf, X509 *>(name, aCert.release()));
1223 }
1224 debugs(83, 4, "Loaded " << list.size() << " certificates from file: '" << certsFile << "'");
1225 return true;
1226}
1227
1230static X509 *
1232{
1233 const auto name = Security::IssuerName(*cert);
1234 if (name.isEmpty())
1235 return nullptr;
1236
1237 const auto ret = list.equal_range(name);
1238 for (Ssl::CertsIndexedList::iterator it = ret.first; it != ret.second; ++it) {
1239 X509 *issuer = it->second;
1240 if (Security::IssuedBy(*cert, *issuer)) {
1241 return issuer;
1242 }
1243 }
1244 return nullptr;
1245}
1246
1248static X509 *
1249sk_x509_findIssuer(const STACK_OF(X509) *sk, X509 *cert)
1250{
1251 if (!sk)
1252 return nullptr;
1253
1254 const auto certCount = sk_X509_num(sk);
1255 for (int i = 0; i < certCount; ++i) {
1256 const auto issuer = sk_X509_value(sk, i);
1257 if (Security::IssuedBy(*cert, *issuer))
1258 return issuer;
1259 }
1260 return nullptr;
1261}
1262
1265static X509 *
1266findIssuerInCaDb(X509 *cert, const Security::ContextPointer &connContext)
1267{
1268 if (!connContext)
1269 return nullptr;
1270
1271 X509_STORE_CTX *storeCtx = X509_STORE_CTX_new();
1272 if (!storeCtx) {
1273 debugs(83, DBG_IMPORTANT, "ERROR: Failed to allocate STORE_CTX object");
1274 return nullptr;
1275 }
1276
1277 X509 *issuer = nullptr;
1278 X509_STORE *store = SSL_CTX_get_cert_store(connContext.get());
1279 if (X509_STORE_CTX_init(storeCtx, store, nullptr, nullptr)) {
1280 const auto ret = X509_STORE_CTX_get1_issuer(&issuer, storeCtx, cert);
1281 if (ret > 0) {
1282 assert(issuer);
1283 debugs(83, 5, "found " << *issuer);
1284 } else {
1285 debugs(83, ret < 0 ? 2 : 3, "not found or failure: " << ret);
1286 assert(!issuer);
1287 }
1288 } else {
1289 const auto ssl_error = ERR_get_error();
1290 debugs(83, DBG_IMPORTANT, "ERROR: Failed to initialize STORE_CTX object: " << Security::ErrorString(ssl_error));
1291 }
1292
1293 X509_STORE_CTX_free(storeCtx);
1294
1295 return issuer;
1296}
1297
1299Ssl::findIssuerCertificate(X509 *cert, const STACK_OF(X509) *serverCertificates, const Security::ContextPointer &context)
1300{
1301 Must(cert);
1302
1303 // check certificate chain, if any
1304 if (const auto issuer = serverCertificates ? sk_x509_findIssuer(serverCertificates, cert) : nullptr) {
1305 X509_up_ref(issuer);
1306 return Security::CertPointer(issuer);
1307 }
1308
1309 // check untrusted certificates
1310 if (const auto issuer = findCertIssuerFast(SquidUntrustedCerts(), cert)) {
1311 X509_up_ref(issuer);
1312 return Security::CertPointer(issuer);
1313 }
1314
1315 // check trusted CA certificates
1316 if (const auto issuer = findIssuerInCaDb(cert, context)) {
1317 // no X509_up_ref(issuer) because findIssuerInCaDb() ups reference count
1318 return Security::CertPointer(issuer);
1319 }
1320
1321 return Security::CertPointer(nullptr);
1322}
1323
1324bool
1325Ssl::missingChainCertificatesUrls(std::queue<SBuf> &URIs, const STACK_OF(X509) &serverCertificates, const Security::ContextPointer &context)
1326{
1327 for (int i = 0; i < sk_X509_num(&serverCertificates); ++i) {
1328 const auto cert = sk_X509_value(&serverCertificates, i);
1329
1330 if (findIssuerCertificate(cert, &serverCertificates, context))
1331 continue;
1332
1333 if (const auto issuerUri = findIssuerUri(cert)) {
1334 URIs.push(SBuf(issuerUri));
1335 } else {
1336 debugs(83, 3, "Issuer certificate for " <<
1337 *cert <<
1338 " is missing and its URI is not provided");
1339 }
1340 }
1341
1342 debugs(83, (URIs.empty() ? 3 : 5), "found: " << URIs.size());
1343 return !URIs.empty();
1344}
1345
1347static void
1348completeIssuers(X509_STORE_CTX *ctx, STACK_OF(X509) &untrustedCerts)
1349{
1350 debugs(83, 2, "completing " << sk_X509_num(&untrustedCerts) <<
1351 " OpenSSL untrusted certs using " << Ssl::SquidUntrustedCerts().size() <<
1352 " configured untrusted certificates");
1353
1354 const X509_VERIFY_PARAM *param = X509_STORE_CTX_get0_param(ctx);
1355 int depth = X509_VERIFY_PARAM_get_depth(param);
1356 Security::CertPointer current;
1358 int i = 0;
1359 for (i = 0; current && (i < depth); ++i) {
1360 if (Security::SelfSigned(*current)) {
1361 // either ctx->cert is itself self-signed or untrustedCerts
1362 // already contain the self-signed current certificate
1363 break;
1364 }
1365
1366 // untrustedCerts is short, not worth indexing
1367 const Security::ContextPointer nullCtx;
1368 auto issuer = Ssl::findIssuerCertificate(current.get(), &untrustedCerts, nullCtx);
1369 current = issuer;
1370 if (issuer)
1371 sk_X509_push(&untrustedCerts, issuer.release());
1372 }
1373
1374 if (i >= depth)
1375 debugs(83, 2, "exceeded the maximum certificate chain length: " << depth);
1376}
1377
1381static int
1382VerifyCtxCertificates(X509_STORE_CTX *ctx, STACK_OF(X509) *extraCerts)
1383{
1384 // OpenSSL already maintains ctx->untrusted but we cannot modify
1385 // internal OpenSSL list directly. We have to give OpenSSL our own
1386 // list, but it must include certificates on the OpenSSL ctx->untrusted
1387 STACK_OF(X509) *oldUntrusted = X509_STORE_CTX_get0_untrusted(ctx);
1388 // X509_chain_up_ref() increments cert references _and_ dupes the stack
1389 Ssl::X509_STACK_Pointer untrustedCerts(oldUntrusted ? X509_chain_up_ref(oldUntrusted) : sk_X509_new_null());
1390
1391 if (extraCerts) {
1392 for (int i = 0; i < sk_X509_num(extraCerts); ++i) {
1393 const auto cert = sk_X509_value(extraCerts, i);
1394 X509_up_ref(cert);
1395 sk_X509_push(untrustedCerts.get(), cert);
1396 }
1397 }
1398
1399 // If the local untrusted certificates internal database is used
1400 // run completeIssuers to add missing certificates if possible.
1401 if (Ssl::SquidUntrustedCerts().size() > 0)
1402 completeIssuers(ctx, *untrustedCerts);
1403
1404 X509_STORE_CTX_set0_untrusted(ctx, untrustedCerts.get()); // No locking/unlocking, just sets ctx->untrusted
1405 int ret = X509_verify_cert(ctx);
1406 X509_STORE_CTX_set0_untrusted(ctx, oldUntrusted); // Set back the old untrusted list
1407 return ret;
1408}
1409
1425
1429static int
1430untrustedToStoreCtx_cb(X509_STORE_CTX *ctx, void *)
1431{
1432 debugs(83, 4, "Try to use pre-downloaded intermediate certificates");
1433 return VerifyCtxCertificates(ctx, nullptr);
1434}
1435
1436void
1437Ssl::useSquidUntrusted(SSL_CTX *sslContext)
1438{
1439 SSL_CTX_set_cert_verify_callback(sslContext, untrustedToStoreCtx_cb, nullptr);
1440}
1441
1442bool
1444{
1445 return Ssl::loadCerts(path, SquidUntrustedCerts());
1446}
1447
1448void
1450{
1451 if (SquidUntrustedCerts().size()) {
1452 for (const auto &i: SquidUntrustedCerts()) {
1453 X509_free(i.second);
1454 }
1455 SquidUntrustedCerts().clear();
1456 }
1457}
1458
1459bool Ssl::generateUntrustedCert(Security::CertPointer &untrustedCert, Security::PrivateKeyPointer &untrustedPkey, Security::CertPointer const &cert, Security::PrivateKeyPointer const & pkey)
1460{
1461 // Generate the self-signed certificate, using a hard-coded subject prefix
1462 Ssl::CertificateProperties certProperties;
1463 if (const char *cn = CommonHostName(cert.get())) {
1464 certProperties.commonName = "Not trusted by \"";
1465 certProperties.commonName += cn;
1466 certProperties.commonName += "\"";
1467 } else if (const char *org = getOrganization(cert.get())) {
1468 certProperties.commonName = "Not trusted by \"";
1469 certProperties.commonName += org;
1470 certProperties.commonName += "\"";
1471 } else
1472 certProperties.commonName = "Not trusted";
1473 certProperties.setCommonName = true;
1474 // O, OU, and other CA subject fields will be mimicked
1475 // Expiration date and other common properties will be mimicked
1476 certProperties.signAlgorithm = Ssl::algSignSelf;
1477 certProperties.signWithPkey.resetAndLock(pkey.get());
1478 certProperties.mimicCert.resetAndLock(cert.get());
1479 return Ssl::generateSslCertificate(untrustedCert, untrustedPkey, certProperties);
1480}
1481
1483{
1484 bool origSignatureAsKey = false;
1485 if (certProperties.mimicCert) {
1486 if (auto *sig = Ssl::X509_get_signature(certProperties.mimicCert)) {
1487 origSignatureAsKey = true;
1488 key.append((const char *)sig->data, sig->length);
1489 }
1490 }
1491
1492 if (!origSignatureAsKey || certProperties.setCommonName) {
1493 // Use common name instead
1494 key.append(certProperties.commonName.c_str());
1495 }
1496 key.append(certProperties.setCommonName ? '1' : '0');
1497 key.append(certProperties.setValidAfter ? '1' : '0');
1498 key.append(certProperties.setValidBefore ? '1' : '0');
1499 key.append(certProperties.signAlgorithm != Ssl:: algSignEnd ? certSignAlgorithm(certProperties.signAlgorithm) : "-");
1500 key.append(certProperties.signHash ? EVP_MD_name(certProperties.signHash) : "-");
1501
1502 if (certProperties.mimicCert) {
1503 Ssl::BIO_Pointer bio(BIO_new_SBuf(&key));
1504 ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509), bio.get(), (ASN1_VALUE *)certProperties.mimicCert.get());
1505 }
1506}
1507
1508static int
1510{
1511 BIO_set_init(bio, 0);
1512 BIO_set_data(bio, nullptr);
1513 return 1;
1514}
1515
1516static int
1518{
1519 if (!bio)
1520 return 0;
1521 return 1;
1522}
1523
1524static int
1525bio_sbuf_write(BIO* bio, const char* data, int len)
1526{
1527 SBuf *buf = static_cast<SBuf *>(BIO_get_data(bio));
1528 // TODO: Convert exceptions into BIO errors
1529 buf->append(data, len);
1530 return len;
1531}
1532
1533static int
1534bio_sbuf_puts(BIO *bio, const char *data)
1535{
1536 // TODO: use bio_sbuf_write() instead
1537 SBuf *buf = static_cast<SBuf *>(BIO_get_data(bio));
1538 size_t oldLen = buf->length();
1539 buf->append(data);
1540 return buf->length() - oldLen;
1541}
1542
1543static long
1544bio_sbuf_ctrl(BIO *bio, int cmd, long /* num */, void *)
1545{
1546 SBuf *buf = static_cast<SBuf *>(BIO_get_data(bio));
1547 switch (cmd) {
1548 case BIO_CTRL_RESET:
1549 // TODO: Convert exceptions into BIO errors
1550 buf->clear();
1551 return 1;
1552 case BIO_CTRL_FLUSH:
1553 return 1;
1554 default:
1555 return 0;
1556 }
1557}
1558
1560{
1561#if HAVE_LIBCRYPTO_BIO_METH_NEW
1562 static BIO_METHOD *BioSBufMethods = nullptr;
1563 if (!BioSBufMethods) {
1564 BioSBufMethods = BIO_meth_new(BIO_TYPE_MEM, "Squid-SBuf");
1565 BIO_meth_set_write(BioSBufMethods, bio_sbuf_write);
1566 BIO_meth_set_read(BioSBufMethods, nullptr);
1567 BIO_meth_set_puts(BioSBufMethods, bio_sbuf_puts);
1568 BIO_meth_set_gets(BioSBufMethods, nullptr);
1569 BIO_meth_set_ctrl(BioSBufMethods, bio_sbuf_ctrl);
1570 BIO_meth_set_create(BioSBufMethods, bio_sbuf_create);
1571 BIO_meth_set_destroy(BioSBufMethods, bio_sbuf_destroy);
1572 }
1573#else
1574 static BIO_METHOD *BioSBufMethods = new BIO_METHOD({
1575 BIO_TYPE_MEM,
1576 "Squid SBuf",
1578 nullptr,
1580 nullptr,
1584 NULL
1585 });
1586#endif
1587 BIO *bio = BIO_new(BioSBufMethods);
1588 Must(bio);
1589 BIO_set_data(bio, buf);
1590 BIO_set_init(bio, 1);
1591 return bio;
1592}
1593
1594#endif /* USE_OPENSSL */
1595
#define Assure(condition)
Definition Assure.h:35
ACLFilledChecklist * Filled(ACLChecklist *checklist)
convenience and safety wrapper for dynamic_cast<ACLFilledChecklist*>
#define Here()
source code location of the caller
Definition Here.h:15
int size
Definition ModDevPoll.cc:70
class SquidConfig Config
#define Must(condition)
@ mdnRejectSubsubDomains
Definition Uri.h:241
void error(char *format,...)
#define assert(EX)
Definition assert.h:17
static char server[MAXLINE]
Acl::Answer const & fastCheck()
Definition Checklist.cc:298
Security::CertPointer serverCert
CbcPointer< Security::CertErrors > sslErrors
bool allowed() const
Definition Acl.h:82
either a domain name (as defined in DNS RFC 1034) or an IP address
Definition Host.h:25
static std::optional< Host > ParseIp(const Ip::Address &)
converts an already parsed IP address to a Host object
Definition Host.cc:15
auto domainName() const
stored domain name (if any)
Definition Host.h:48
static std::optional< Host > ParseWildDomainName(const SBuf &)
Definition Host.cc:59
auto ip() const
Definition Host.h:45
bool push_back_unique(C const &element)
Definition CbDataList.h:87
static bool Enabled(const int section, const int level)
whether debugging the given section and the given level produces output
Definition Stream.h:75
bool isAnyAddr() const
Definition Address.cc:190
Definition SBuf.h:94
SBuf consume(size_type n=npos)
Definition SBuf.cc:481
const char * c_str()
Definition SBuf.cc:516
size_type length() const
Returns the number of bytes stored in SBuf.
Definition SBuf.h:419
bool isEmpty() const
Definition SBuf.h:435
SBuf & append(const SBuf &S)
Definition SBuf.cc:185
void clear()
Definition SBuf.cc:175
Security::CertPointer cert
public X.509 certificate from certFile
Definition KeyData.h:31
Security::CertList chain
any certificates which must be chained from cert
Definition KeyData.h:35
void reset()
Forget the raw pointer - unlock if any value was set. Become a nil pointer.
T * get() const
Returns raw and possibly nullptr pointer.
TLS squid.conf settings for a remote server peer.
Definition PeerOptions.h:26
std::list< Security::KeyData > certs
details from the cert= and file= config parameters
TLS squid.conf settings for a listening port.
Security::ContextPointer createBlankContext() const override
generate an unset security context object
bool updateContextConfig(Security::ContextPointer &)
update the given TLS security context using squid.conf settings
Security::KeyData signingCa
x509 certificate and key for signing generated certificates
char * ssl_password
struct SquidConfig::@83 Program
struct SquidConfig::@97 SSL
char * certSignHash
char * ssl_engine
Security::PrivateKeyPointer signWithPkey
The key of the signing certificate.
Definition gadgets.h:237
bool setCommonName
Replace the CN field of the mimicking subject with the given.
Definition gadgets.h:240
bool setValidAfter
Do not mimic "Not Valid After" field.
Definition gadgets.h:238
CertSignAlgorithm signAlgorithm
The signing algorithm to use.
Definition gadgets.h:242
bool setValidBefore
Do not mimic "Not Valid Before" field.
Definition gadgets.h:239
Security::CertPointer mimicCert
Certificate to mimic.
Definition gadgets.h:235
const EVP_MD * signHash
The signing hash to use.
Definition gadgets.h:243
std::string commonName
A CN to use for the generated certificate.
Definition gadgets.h:241
an algorithm for checking/testing/comparing X.509 certificate names
Definition support.h:299
bool match(const Ssl::GeneralName &) const
whether the given name satisfies algorithm conditions
Definition support.cc:84
virtual bool matchIp(const Ip::Address &) const =0
virtual bool matchDomainName(const Dns::DomainName &) const =0
GeneralNameMatcher for matching a single AnyP::Host given at construction time.
Definition support.cc:62
AnyP::Host needle_
a name we are looking for
Definition support.cc:71
OneNameMatcher(const AnyP::Host &needle)
Definition support.cc:64
bool matchIp(const Ip::Address &) const override
Definition support.cc:117
bool matchDomainName(const Dns::DomainName &) const override
Definition support.cc:95
static VerifyCallbackParameters & At(Security::Connection &)
Definition support.cc:643
static VerifyCallbackParameters * New(Security::Connection &)
Definition support.cc:631
static VerifyCallbackParameters * Find(Security::Connection &)
Definition support.cc:625
an std::runtime_error with thrower location info
#define DBG_PARSE_NOTE(x)
Definition Stream.h:42
#define DBG_IMPORTANT
Definition Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition Stream.h:192
#define MAX_URL
Definition defines.h:76
static int port
void fatalf(const char *fmt,...)
Definition fatal.cc:68
int ssl_ex_index_server
int ssl_ex_index_ssl_peeked_cert
int ssl_ex_index_ssl_error_detail
int ssl_ctx_ex_index_dont_verify_domain
int ssl_ex_index_ssl_errors
int ssl_ex_index_ssl_validation_counter
int ssl_ex_index_ssl_cert_chain
int ssl_ex_index_cert_error_check
void useSquidUntrusted(SSL_CTX *sslContext)
Definition support.cc:1437
Security::ContextPointer GenerateSslContext(CertificateProperties const &, Security::ServerOptions &, bool trusted)
Definition support.cc:1048
GETX509PEM GetX509PEM
Definition support.h:121
std::vector< const char * > BumpModeStr
Definition support.cc:46
SBuf sslGetUserCertificatePEM(SSL *ssl)
Definition support.cc:983
bool configureSSL(SSL *ssl, CertificateProperties const &properties, AnyP::PortCfg &port)
Definition support.cc:1094
bool generateUntrustedCert(Security::CertPointer &untrustedCert, Security::PrivateKeyPointer &untrustedPkey, Security::CertPointer const &cert, Security::PrivateKeyPointer const &pkey)
Definition support.cc:1459
void chainCertificatesToSSLContext(Security::ContextPointer &, Security::ServerOptions &)
Definition support.cc:1062
void InRamCertificateDbKey(const Ssl::CertificateProperties &certProperties, SBuf &key)
Definition support.cc:1482
const char * sslGetUserAttribute(SSL *ssl, const char *attribute_name)
Definition support.cc:950
BIO * BIO_new_SBuf(SBuf *buf)
Definition support.cc:1559
Security::ContextPointer createSSLContext(Security::CertPointer &x509, Security::PrivateKeyPointer &pkey, Security::ServerOptions &)
Create SSL context and apply ssl certificate and private key to it.
Definition support.cc:1017
bool verifySslCertificate(const Security::ContextPointer &, CertificateProperties const &)
Definition support.cc:1137
bool configureSSLUsingPkeyAndCertFromMemory(SSL *ssl, const char *data, AnyP::PortCfg &port)
Definition support.cc:1117
bool loadCerts(const char *certsFile, Ssl::CertsIndexedList &list)
Definition support.cc:1212
int asn1timeToString(ASN1_TIME *tm, char *buf, int len)
Definition support.cc:248
const char * sslGetCAAttribute(SSL *ssl, const char *attribute_name)
Definition support.cc:963
Security::ContextPointer GenerateSslContextUsingPkeyAndCertFromMemory(const char *data, Security::ServerOptions &, bool trusted)
Definition support.cc:1034
GETX509ATTRIBUTE GetX509Fingerprint
Definition support.h:124
SBuf sslGetUserCertificateChainPEM(SSL *ssl)
Definition support.cc:994
void configureUnconfiguredSslContext(Security::ContextPointer &, Ssl::CertSignAlgorithm signAlgorithm, AnyP::PortCfg &)
Definition support.cc:1087
void setClientSNI(SSL *ssl, const char *fqdn)
Definition support.cc:1162
const char * getOrganization(X509 *x509)
Definition gadgets.cc:1078
bool loadSquidUntrusted(const char *path)
Definition support.cc:1443
const char * CommonHostName(X509 *x509)
Definition gadgets.cc:1073
const char * sslGetUserEmail(SSL *ssl)
Definition support.cc:977
GETX509ATTRIBUTE GetX509UserAttribute
Definition support.h:115
void unloadSquidUntrusted()
Definition support.cc:1449
GETX509ATTRIBUTE GetX509CAAttribute
Definition support.h:118
static void ssl_free_CertChain(void *, void *ptr, CRYPTO_EX_DATA *, int, long, void *)
Definition support.cc:709
static void ssl_ask_password(SSL_CTX *context, const char *prompt)
Definition support.cc:156
static const char * ssl_get_attribute(X509_NAME *name, const char *attribute_name)
Definition support.cc:860
bool generateSslCertificate(Security::CertPointer &cert, Security::PrivateKeyPointer &pkey, CertificateProperties const &properties)
Definition gadgets.cc:815
CertSignAlgorithm
Definition gadgets.h:169
bool readCertAndPrivateKeyFromMemory(Security::CertPointer &cert, Security::PrivateKeyPointer &pkey, char const *bufferToRead)
Definition gadgets.cc:193
const char * certSignAlgorithm(int sg)
Definition gadgets.h:182
@ algSignEnd
Definition gadgets.h:169
@ algSignTrusted
Definition gadgets.h:169
@ algSignSelf
Definition gadgets.h:169
SBuf IssuerName(Certificate &)
The Issuer field of the given certificate (if found) or an empty SBuf.
std::shared_ptr< SSL_CTX > ContextPointer
Definition Context.h:29
SSL Connection
Definition Session.h:49
int ErrorCode
Squid-defined error code (<0), an error code returned by X.509 API, or zero.
Definition forward.h:134
Security::SessionPointer NewSessionObject(const Security::ContextPointer &)
Definition Session.cc:123
std::shared_ptr< SSL > SessionPointer
Definition Session.h:53
CbDataList< Security::CertError > CertErrors
Holds a list of X.509 certificate errors.
Definition forward.h:76
Security::LockingPointer< X509, X509_free_cpp, HardFun< int, X509 *, X509_up_ref > > CertPointer
Definition forward.h:88
long ParsedPortFlags
Definition forward.h:204
bool SelfSigned(Certificate &c)
Whether the given certificate is self-signed.
Definition Certificate.h:34
SBuf SubjectName(Certificate &)
The SubjectName field of the given certificate (if found) or an empty SBuf.
bool IssuedBy(Certificate &cert, Certificate &issuer)
const char * ErrorString(const LibErrorCode code)
converts numeric LibErrorCode into a human-friendlier string
Definition forward.h:152
Definition Xaction.cc:41
bool HasMatchingSubjectName(X509 &, const GeneralNameMatcher &)
Definition support.cc:307
bool HasSubjectName(X509 &, const AnyP::Host &)
whether at least one common or alternate subject name matches the given one
Definition support.cc:338
void DisablePeerVerification(Security::ContextPointer &)
Definition support.cc:524
bool InitClientContext(Security::ContextPointer &, Security::PeerOptions &, Security::ParsedPortFlags)
initialize a TLS client context with OpenSSL specific settings
Definition support.cc:802
std::optional< AnyP::Host > ParseAsSimpleDomainNameOrIp(const SBuf &)
Definition gadgets.cc:542
std::unique_ptr< BIO, HardFun< void, BIO *, &BIO_vfree > > BIO_Pointer
Definition gadgets.h:57
static CertsIndexedList & SquidUntrustedCerts()
Definition support.cc:75
bool VerifyConnCertificates(Security::Connection &, const Ssl::X509_STACK_Pointer &extraCerts)
Definition support.cc:533
std::unique_ptr< X509_STORE_CTX, HardFun< void, X509_STORE_CTX *, &X509_STORE_CTX_free > > X509_STORE_CTX_Pointer
Definition gadgets.h:80
Security::CertPointer findIssuerCertificate(X509 *cert, const STACK_OF(X509) *serverCertificates, const Security::ContextPointer &context)
Definition support.cc:1299
bool missingChainCertificatesUrls(std::queue< SBuf > &URIs, const STACK_OF(X509) &serverCertificates, const Security::ContextPointer &context)
Definition support.cc:1325
Config TheConfig
Definition Config.cc:12
std::optional< AnyP::Host > ParseCommonNameAt(X509_NAME &, int)
interprets X.509 Subject or Issuer name entry (at the given position) as CN
Definition gadgets.cc:550
Security::CertPointer ReadOptionalCertificate(const BIO_Pointer &)
Definition gadgets.cc:837
const ASN1_BIT_STRING * X509_get_signature(const Security::CertPointer &)
Definition gadgets.cc:1109
void Initialize()
Definition support.cc:743
std::optional< SBuf > GetErrorDescr(Security::ErrorCode)
const EVP_MD * DefaultSignHash
Definition support.cc:44
std::unique_ptr< STACK_OF(GENERAL_NAME), sk_GENERAL_NAME_free_wrapper > GENERAL_NAME_STACK_Pointer
Definition gadgets.h:74
int AskPasswordCb(char *buf, int size, int rwflag, void *userdata)
Definition support.cc:131
SBuf AsnToSBuf(const ASN1_STRING &)
converts ASN1_STRING to SBuf
Definition gadgets.cc:519
void MaybeSetupRsaCallback(Security::ContextPointer &)
if required, setup callback for generating ephemeral RSA keys
Definition support.cc:238
const char * findIssuerUri(X509 *cert)
finds certificate issuer URI in the Authority Info Access extension
Definition support.cc:1182
std::unique_ptr< STACK_OF(X509), sk_X509_free_wrapper > X509_STACK_Pointer
Definition gadgets.h:53
std::multimap< SBuf, X509 * > CertsIndexedList
certificates indexed by issuer name
Definition support.h:150
void ConfigurePeerVerification(Security::ContextPointer &, const Security::ParsedPortFlags)
set the certificate verify callback for a context
Definition support.cc:501
bool InitServerContext(Security::ContextPointer &, AnyP::PortCfg &)
initialize a TLS server context with OpenSSL specific settings
Definition support.cc:793
int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param)
Definition openssl.h:292
void * BIO_get_data(BIO *table)
Definition openssl.h:62
#define X509_getm_notAfter
Definition openssl.h:247
void SQUID_OPENSSL_init_ssl(void)
Definition openssl.h:308
#define X509_getm_notBefore
Definition openssl.h:248
X509_VERIFY_PARAM * SSL_get0_param(SSL *ssl)
Definition openssl.h:300
#define X509_STORE_CTX_set0_untrusted
Definition openssl.h:246
void BIO_set_init(BIO *table, int init)
Definition openssl.h:74
STACK_OF(X509) *X509_STORE_CTX_get0_untrusted(X509_STORE_CTX *ctx)
Definition openssl.h:237
X509 * X509_STORE_CTX_get0_cert(X509_STORE_CTX *ctx)
Definition openssl.h:230
const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x)
Definition openssl.h:54
void BIO_set_data(BIO *table, void *data)
Definition openssl.h:68
#define SSL_FLAG_CONDITIONAL_AUTH
Definition forward.h:60
#define SSL_FLAG_DONT_VERIFY_PEER
Definition forward.h:55
@ SQUID_X509_V_ERR_INFINITE_VALIDATION
Definition forward.h:239
@ SQUID_X509_V_ERR_DOMAIN_MISMATCH
Definition forward.h:238
@ SQUID_X509_V_ERR_CERT_CHANGE
Definition forward.h:237
FILE * DebugStream()
Definition debug.cc:355
#define SQUID_SSL_SIGN_HASH_IF_NONE
Definition gadgets.h:46
#define SQUID_CERT_VALIDATION_ITERATION_MAX
Definition support.h:51
static void ssl_free_ErrorDetail(void *, void *ptr, CRYPTO_EX_DATA *, int, long, void *)
Definition support.cc:681
static void ssl_free_X509(void *, void *ptr, CRYPTO_EX_DATA *, int, long, void *)
Definition support.cc:718
static int bio_sbuf_puts(BIO *bio, const char *data)
Definition support.cc:1534
static void ssl_free_SBuf(void *, void *ptr, CRYPTO_EX_DATA *, int, long, void *)
Definition support.cc:727
static int bio_sbuf_destroy(BIO *bio)
Definition support.cc:1517
static void completeIssuers(X509_STORE_CTX *ctx, STACK_OF(X509) &untrustedCerts)
add missing issuer certificates to untrustedCerts
Definition support.cc:1348
static void ssl_free_int(void *, void *ptr, CRYPTO_EX_DATA *, int, long, void *)
Definition support.cc:698
static X509 * findIssuerInCaDb(X509 *cert, const Security::ContextPointer &connContext)
Definition support.cc:1266
static int ssl_dupAclChecklist(CRYPTO_EX_DATA *, CRYPTO_EX_DATA *, void *, int, long, void *)
Definition support.cc:661
static int ssl_verify_cb(int ok, X509_STORE_CTX *ctx)
Definition support.cc:346
static int ssl_ex_index_verify_callback_parameters
Definition support.cc:42
static int untrustedToStoreCtx_cb(X509_STORE_CTX *ctx, void *)
Definition support.cc:1430
static void ssl_freeAclChecklist(void *, void *ptr, CRYPTO_EX_DATA *, int, long, void *)
Definition support.cc:673
static std::optional< AnyP::Host > ParseSubjectAltName(const GENERAL_NAME &san)
Definition support.cc:263
static int bio_sbuf_write(BIO *bio, const char *data, int len)
Definition support.cc:1525
static void ssl_free_SslErrors(void *, void *ptr, CRYPTO_EX_DATA *, int, long, void *)
Definition support.cc:689
static X509 * findCertIssuerFast(Ssl::CertsIndexedList &list, X509 *cert)
Definition support.cc:1231
static int VerifyCtxCertificates(X509_STORE_CTX *ctx, STACK_OF(X509) *extraCerts)
Definition support.cc:1382
static int bio_sbuf_create(BIO *bio)
Definition support.cc:1509
static long bio_sbuf_ctrl(BIO *bio, int cmd, long, void *)
Definition support.cc:1544
static X509 * sk_x509_findIssuer(const STACK_OF(X509) *sk, X509 *cert)
slowly find the issuer certificate of a given cert using linear search
Definition support.cc:1249
static void ssl_free_VerifyCallbackParameters(void *, void *ptr, CRYPTO_EX_DATA *, int, long, void *)
"free" function for the ssl_ex_index_verify_callback_parameters entry
Definition support.cc:736
#define NULL
Definition types.h:145
static char * keys[]
char * xstrncpy(char *dst, const char *src, size_t n)
Definition xstring.cc:37