2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 83 SSL accelerator support */
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.
18 #include "acl/FilledChecklist.h"
19 #include "anyp/Host.h"
20 #include "anyp/PortCfg.h"
26 #include "ip/Address.h"
27 #include "ipc/MemMap.h"
28 #include "security/CertError.h"
29 #include "security/Certificate.h"
30 #include "security/ErrorDetail.h"
31 #include "security/Session.h"
32 #include "SquidConfig.h"
34 #include "ssl/Config.h"
35 #include "ssl/ErrorDetail.h"
36 #include "ssl/gadgets.h"
37 #include "ssl/support.h"
41 // TODO: Move ssl_ex_index_* global variables from global.cc here.
42 static int ssl_ex_index_verify_callback_parameters
= -1;
44 const EVP_MD
*Ssl::DefaultSignHash
= nullptr;
46 std::vector
<const char *> Ssl::BumpModeStr
= {
60 /// GeneralNameMatcher for matching a single AnyP::Host given at construction time
61 class OneNameMatcher
: public GeneralNameMatcher
64 explicit OneNameMatcher(const AnyP::Host
&needle
): needle_(needle
) {}
67 /* GeneralNameMatcher API */
68 bool matchDomainName(const Dns::DomainName
&) const override
;
69 bool matchIp(const Ip::Address
&) const override
;
71 AnyP::Host needle_
; ///< a name we are looking for
74 static CertsIndexedList
&
77 static auto untrustedCerts
= new CertsIndexedList();
78 return *untrustedCerts
;
84 Ssl::GeneralNameMatcher::match(const GeneralName
&name
) const
86 if (const auto domain
= name
.domainName())
87 return matchDomainName(*domain
);
88 if (const auto ip
= name
.ip())
90 Assure(!"unreachable code: the above `if` statements must cover all name variants");
95 Ssl::OneNameMatcher::matchDomainName(const Dns::DomainName
&rawName
) const {
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
);
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");
106 Assure(needle_
.domainName());
107 auto domainNeedle
= *needle_
.domainName();
110 if (name
.length() > 0 && name
[0] == '*')
113 return ::matchDomainName(domainNeedle
.c_str(), name
.c_str(), mdnRejectSubsubDomains
) == 0;
117 Ssl::OneNameMatcher::matchIp(const Ip::Address
&ip
) const {
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");
126 \defgroup ServerProtocolSSLInternal Server-Side SSL Internals
127 \ingroup ServerProtocolSSLAPI
131 Ssl::AskPasswordCb(char *buf
, int size
, int /* rwflag */, void *userdata
)
137 snprintf(cmdline
, sizeof(cmdline
), "\"%s\" \"%s\"", ::Config
.Program
.ssl_password
, (const char *)userdata
);
138 in
= popen(cmdline
, "r");
140 if (fgets(buf
, size
, in
))
144 while (len
> 0 && (buf
[len
- 1] == '\n' || buf
[len
- 1] == '\r'))
154 /// \ingroup ServerProtocolSSLInternal
156 ssl_ask_password(SSL_CTX
* context
, const char * prompt
)
158 if (Config
.Program
.ssl_password
) {
159 SSL_CTX_set_default_passwd_cb(context
, Ssl::AskPasswordCb
);
160 SSL_CTX_set_default_passwd_cb_userdata(context
, (void *)prompt
);
164 #if HAVE_LIBSSL_SSL_CTX_SET_TMP_RSA_CALLBACK
166 ssl_temp_rsa_cb(SSL
*, int, int keylen
)
168 static RSA
*rsa_512
= nullptr;
169 static RSA
*rsa_1024
= nullptr;
170 static BIGNUM
*e
= nullptr;
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
);
190 if (rsa_512
&& RSA_generate_key_ex(rsa_512
, 512, e
, nullptr)) {
204 rsa_1024
= RSA_new();
205 if (rsa_1024
&& RSA_generate_key_ex(rsa_1024
, 1024, e
, nullptr)) {
217 debugs(83, DBG_IMPORTANT
, "ERROR: ssl_temp_rsa_cb: Unexpected key length " << keylen
);
222 debugs(83, DBG_IMPORTANT
, "ERROR: ssl_temp_rsa_cb: Failed to generate key " << keylen
);
227 if (Debug::Enabled(83, 5))
228 PEM_write_RSAPrivateKey(DebugStream(), rsa
, nullptr, nullptr, 0, nullptr, nullptr);
230 debugs(83, DBG_IMPORTANT
, "Generated ephemeral RSA key of length " << keylen
);
238 Ssl::MaybeSetupRsaCallback(Security::ContextPointer
&ctx
)
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
);
248 int Ssl::asn1timeToString(ASN1_TIME
*tm
, char *buf
, int len
)
252 bio
= BIO_new(BIO_s_mem());
254 if (ASN1_TIME_print(bio
, tm
))
255 write
= BIO_read(bio
, buf
, len
-1);
262 static std::optional
<AnyP::Host
>
263 ParseSubjectAltName(const GENERAL_NAME
&san
)
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
);
275 // san.d.iPAddress is OpenSSL ASN1_OCTET_STRING
276 Assure(san
.d
.iPAddress
);
278 // RFC 5280 section 4.2.1.6 signals IPv4/IPv6 address family using data length
280 if (san
.d
.iPAddress
->length
== 4) {
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
);
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
);
296 debugs(83, 3, "unexpected length of an IP address SAN: " << san
.d
.iPAddress
->length
);
301 debugs(83, 3, "unsupported SAN kind: " << san
.type
);
307 Ssl::HasMatchingSubjectName(X509
&cert
, const GeneralNameMatcher
&matcher
)
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
))
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)));
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
);
326 if (const auto san
= ParseSubjectAltName(*rawSan
)) {
327 if (matcher
.match(*san
))
333 debugs(83, 7, "no matches");
338 Ssl::HasSubjectName(X509
&cert
, const AnyP::Host
&host
)
340 return HasMatchingSubjectName(cert
, OneNameMatcher(host
));
343 /// adjusts OpenSSL validation results for each verified certificate in ctx
344 /// OpenSSL "verify_callback function" (\ref OpenSSL_vcb_disambiguation)
346 ssl_verify_cb(int ok
, X509_STORE_CTX
* ctx
)
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
);
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
;
358 peer_cert
.resetAndLock(X509_STORE_CTX_get0_cert(ctx
));
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
);
366 // overflows allowed if SQUID_CERT_VALIDATION_ITERATION_MAX >= UINT32_MAX
367 (*validationCounter
)++;
370 if ((*validationCounter
) >= SQUID_CERT_VALIDATION_ITERATION_MAX
) {
371 ok
= 0; // or the validation loop will never stop
372 error_no
= SQUID_X509_V_ERR_INFINITE_VALIDATION
;
373 debugs(83, 2, "SQUID_X509_V_ERR_INFINITE_VALIDATION: " <<
374 *validationCounter
<< " iterations while checking " << *peer_cert
);
378 debugs(83, 5, "SSL Certificate signature OK: " << *peer_cert
);
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
);
390 debugs(83, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Certificate " << *peer_cert
<< " does not match domainname " << *host
);
392 error_no
= SQUID_X509_V_ERR_DOMAIN_MISMATCH
;
395 debugs(83, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Cannot check whether certificate " << *peer_cert
<< " subject matches malformed domainname " << *server
);
397 error_no
= SQUID_X509_V_ERR_DOMAIN_MISMATCH
;
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");
407 error_no
= SQUID_X509_V_ERR_CERT_CHANGE
;
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;
422 Security::CertPointer broken_cert
;
423 broken_cert
.resetAndLock(X509_STORE_CTX_get_current_cert(ctx
));
425 broken_cert
= peer_cert
;
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
);
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
);
436 } else // remember another error number
437 errs
->push_back_unique(Security::CertError(error_no
, broken_cert
, depth
));
439 if (const auto description
= Ssl::GetErrorDescr(error_no
))
440 debugs(83, 5, *description
<< ": " << *peer_cert
);
442 debugs(83, DBG_IMPORTANT
, "ERROR: SSL unknown certificate error " << error_no
<< " in " << *peer_cert
);
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
) {
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
);
457 debugs(83, 5, "confirming SSL error " << error_no
);
459 filledCheck
->sslErrors
= savedErrors
;
460 filledCheck
->serverCert
.reset();
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
) {
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
);
479 if (!ok
&& !SSL_get_ex_data(ssl
, ssl_ex_index_ssl_error_detail
) ) {
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
);
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()))
494 debugs(83, 2, "failed to store a " << *peer_cert
<< " error detail: " << *edp
);
501 Ssl::ConfigurePeerVerification(Security::ContextPointer
&ctx
, const Security::ParsedPortFlags flags
)
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
;
511 else if (flags
& SSL_FLAG_DELAYED_AUTH
) {
512 debugs(83, DBG_PARSE_NOTE(3), "not requesting client certificates until ACL processing requires one");
513 mode
= SSL_VERIFY_NONE
;
515 else if (flags
& SSL_FLAG_CONDITIONAL_AUTH
) {
516 debugs(83, DBG_PARSE_NOTE(3), "will request the client certificate but ignore its absence");
517 mode
= SSL_VERIFY_PEER
;
520 debugs(83, DBG_PARSE_NOTE(3), "Requiring client certificates.");
521 mode
= SSL_VERIFY_PEER
|SSL_VERIFY_FAIL_IF_NO_PEER_CERT
;
524 SSL_CTX_set_verify(ctx
.get(), mode
, (mode
!= SSL_VERIFY_NONE
) ? ssl_verify_cb
: nullptr);
528 Ssl::DisablePeerVerification(Security::ContextPointer
&ctx
)
530 debugs(83, DBG_PARSE_NOTE(3), "Not requiring any client certificates");
531 SSL_CTX_set_verify(ctx
.get(),SSL_VERIFY_NONE
,nullptr);
534 static int VerifyCtxCertificates(X509_STORE_CTX
*ctx
, STACK_OF(X509
) *extraCerts
);
537 Ssl::VerifyConnCertificates(Security::Connection
&sconn
, const Ssl::X509_STACK_Pointer
&extraCerts
)
539 const auto peerCertificatesChain
= SSL_get_peer_cert_chain(&sconn
);
541 // TODO: Replace debugs/return false with returning ErrorDetail::Pointer.
542 // Using Security::ErrorDetail terminology, errors in _this_ function are
543 // "non-validation errors", but VerifyCtxCertificates() errors may be
544 // "certificate validation errors". Callers detail SQUID_TLS_ERR_CONNECT.
545 // Some details should be created right here. Others extracted from OpenSSL.
546 // Why not throw? Most of the reasons detailed in the following commit apply
547 // here as well: https://github.com/measurement-factory/squid/commit/e862d33
549 if (!peerCertificatesChain
|| sk_X509_num(peerCertificatesChain
) == 0) {
550 debugs(83, 2, "no server certificates");
554 const auto verificationStore
= SSL_CTX_get_cert_store(SSL_get_SSL_CTX(&sconn
));
555 if (!verificationStore
) {
556 debugs(83, 2, "no certificate store");
560 const X509_STORE_CTX_Pointer
storeCtx(X509_STORE_CTX_new());
562 debugs(83, 2, "cannot create X509_STORE_CTX; likely OOM");
566 const auto peerCert
= sk_X509_value(peerCertificatesChain
, 0);
567 if (!X509_STORE_CTX_init(storeCtx
.get(), verificationStore
, peerCert
, peerCertificatesChain
)) {
568 debugs(83, 2, "cannot initialize X509_STORE_CTX");
572 #if defined(SSL_CERT_FLAG_SUITEB_128_LOS)
573 // overwrite context Suite B (RFC 5759) flags with connection non-defaults
574 // SSL_set_cert_flags() return type is long, but its implementation actually
575 // returns an unsigned long flags value expected by X509_STORE_CTX_set_flags
576 const unsigned long certFlags
= SSL_set_cert_flags(&sconn
, 0);
577 if (const auto suiteBflags
= certFlags
& SSL_CERT_FLAG_SUITEB_128_LOS
)
578 X509_STORE_CTX_set_flags(storeCtx
.get(), suiteBflags
);
581 if (!X509_STORE_CTX_set_ex_data(storeCtx
.get(), SSL_get_ex_data_X509_STORE_CTX_idx(), &sconn
)) {
582 debugs(83, 2, "cannot attach SSL object to X509_STORE_CTX");
586 // If we ever add DANE support to Squid, we will supply DANE details here:
587 // X509_STORE_CTX_set0_dane(storeCtx.get(), SSL_get0_dane(&sconn));
589 // tell OpenSSL we are verifying a server certificate
590 if (!X509_STORE_CTX_set_default(storeCtx
.get(), "ssl_server")) {
591 debugs(83, 2, "cannot set default verification method to ssl_server");
595 // overwrite context "verification parameters" with connection non-defaults
596 const auto param
= X509_STORE_CTX_get0_param(storeCtx
.get());
598 debugs(83, 2, "no context verification parameters");
601 #if defined(HAVE_X509_VERIFY_PARAM_SET_AUTH_LEVEL)
602 X509_VERIFY_PARAM_set_auth_level(param
, SSL_get_security_level(&sconn
));
604 if (!X509_VERIFY_PARAM_set1(param
, SSL_get0_param(&sconn
))) {
605 debugs(83, 2, "cannot overwrite context verification parameters");
609 // copy any connection "verify_callback function" to the validation context
610 // (\ref OpenSSL_vcb_disambiguation)
611 if (const auto cb
= SSL_get_verify_callback(&sconn
))
612 X509_STORE_CTX_set_verify_cb(storeCtx
.get(), cb
);
614 // verify the server certificate chain in the prepared validation context
615 if (VerifyCtxCertificates(storeCtx
.get(), extraCerts
.get()) <= 0) {
616 // see also: ssl_verify_cb() details errors via ssl_ex_index_ssl_errors
617 const auto verifyResult
= X509_STORE_CTX_get_error(storeCtx
.get());
618 debugs(83, 3, "verification failure: " << verifyResult
<< ' ' << X509_verify_cert_error_string(verifyResult
));
622 debugs(83, 7, "success");
626 /* Ssl::VerifyCallbackParameters */
628 Ssl::VerifyCallbackParameters
*
629 Ssl::VerifyCallbackParameters::Find(Security::Connection
&sconn
)
631 return static_cast<VerifyCallbackParameters
*>(SSL_get_ex_data(&sconn
, ssl_ex_index_verify_callback_parameters
));
634 Ssl::VerifyCallbackParameters
*
635 Ssl::VerifyCallbackParameters::New(Security::Connection
&sconn
)
638 const auto parameters
= new VerifyCallbackParameters();
639 if (!SSL_set_ex_data(&sconn
, ssl_ex_index_verify_callback_parameters
, parameters
)) {
641 throw TextException("SSL_set_ex_data() failed; likely OOM", Here());
646 Ssl::VerifyCallbackParameters
&
647 Ssl::VerifyCallbackParameters::At(Security::Connection
&sconn
)
649 const auto parameters
= Find(sconn
);
654 // "dup" function for SSL_get_ex_new_index("cert_err_check")
655 #if OPENSSL_VERSION_MAJOR >= 3
657 ssl_dupAclChecklist(CRYPTO_EX_DATA
*, const CRYPTO_EX_DATA
*, void **,
659 #elif SQUID_USE_CONST_CRYPTO_EX_DATA_DUP
661 ssl_dupAclChecklist(CRYPTO_EX_DATA
*, const CRYPTO_EX_DATA
*, void *,
665 ssl_dupAclChecklist(CRYPTO_EX_DATA
*, CRYPTO_EX_DATA
*, void *,
669 // We do not support duplication of ACLCheckLists.
670 // If duplication is needed, we can count copies with cbdata.
675 // "free" function for SSL_get_ex_new_index("cert_err_check")
677 ssl_freeAclChecklist(void *, void *ptr
, CRYPTO_EX_DATA
*,
680 delete static_cast<ACLChecklist
*>(ptr
); // may be NULL
683 // "free" function for SSL_get_ex_new_index("ssl_error_detail")
685 ssl_free_ErrorDetail(void *, void *ptr
, CRYPTO_EX_DATA
*,
688 const auto errDetail
= static_cast<Security::ErrorDetail::Pointer
*>(ptr
);
693 ssl_free_SslErrors(void *, void *ptr
, CRYPTO_EX_DATA
*,
696 Security::CertErrors
*errs
= static_cast <Security::CertErrors
*>(ptr
);
700 // "free" function for SSL_get_ex_new_index("ssl_ex_index_ssl_validation_counter")
702 ssl_free_int(void *, void *ptr
, CRYPTO_EX_DATA
*,
705 uint32_t *counter
= static_cast <uint32_t *>(ptr
);
709 /// \ingroup ServerProtocolSSLInternal
710 /// Callback handler function to release STACK_OF(X509) "ex" data stored
711 /// in an SSL object.
713 ssl_free_CertChain(void *, void *ptr
, CRYPTO_EX_DATA
*,
716 STACK_OF(X509
) *certsChain
= static_cast <STACK_OF(X509
) *>(ptr
);
717 sk_X509_pop_free(certsChain
,X509_free
);
720 // "free" function for X509 certificates
722 ssl_free_X509(void *, void *ptr
, CRYPTO_EX_DATA
*,
725 X509
*cert
= static_cast <X509
*>(ptr
);
729 // "free" function for SBuf
731 ssl_free_SBuf(void *, void *ptr
, CRYPTO_EX_DATA
*,
734 SBuf
*buf
= static_cast <SBuf
*>(ptr
);
738 /// "free" function for the ssl_ex_index_verify_callback_parameters entry
740 ssl_free_VerifyCallbackParameters(void *, void *ptr
, CRYPTO_EX_DATA
*,
743 delete static_cast<Ssl::VerifyCallbackParameters
*>(ptr
);
747 Ssl::Initialize(void)
749 static bool initialized
= false;
754 SQUID_OPENSSL_init_ssl();
756 if (::Config
.SSL
.ssl_engine
) {
757 #if OPENSSL_VERSION_MAJOR < 3
758 debugs(83, DBG_PARSE_NOTE(DBG_IMPORTANT
), "WARNING: Support for ssl_engine is deprecated " <<
759 "in Squids built with OpenSSL 1.x (like this Squid). " <<
760 "It is removed in Squids built with OpenSSL 3.0 or newer.");
761 #if !defined(OPENSSL_NO_ENGINE)
762 ENGINE_load_builtin_engines();
764 if (!(e
= ENGINE_by_id(::Config
.SSL
.ssl_engine
)))
765 fatalf("Unable to find SSL engine '%s'\n", ::Config
.SSL
.ssl_engine
);
767 if (!ENGINE_set_default(e
, ENGINE_METHOD_ALL
)) {
768 const auto ssl_error
= ERR_get_error();
769 fatalf("Failed to initialise SSL engine: %s\n", Security::ErrorString(ssl_error
));
771 #else /* OPENSSL_NO_ENGINE */
772 throw TextException("Cannot use ssl_engine in Squid built with OpenSSL configured to disable SSL engine support", Here());
775 #else /* OPENSSL_VERSION_MAJOR */
776 throw TextException("Cannot use ssl_engine in Squid built with OpenSSL 3.0 or newer", Here());
780 const char *defName
= ::Config
.SSL
.certSignHash
? ::Config
.SSL
.certSignHash
: SQUID_SSL_SIGN_HASH_IF_NONE
;
781 Ssl::DefaultSignHash
= EVP_get_digestbyname(defName
);
782 if (!Ssl::DefaultSignHash
)
783 fatalf("Sign hash '%s' is not supported\n", defName
);
785 ssl_ex_index_server
= SSL_get_ex_new_index(0, (void *) "server", nullptr, nullptr, ssl_free_SBuf
);
786 ssl_ctx_ex_index_dont_verify_domain
= SSL_CTX_get_ex_new_index(0, (void *) "dont_verify_domain", nullptr, nullptr, nullptr);
787 ssl_ex_index_cert_error_check
= SSL_get_ex_new_index(0, (void *) "cert_error_check", nullptr, &ssl_dupAclChecklist
, &ssl_freeAclChecklist
);
788 ssl_ex_index_ssl_error_detail
= SSL_get_ex_new_index(0, (void *) "ssl_error_detail", nullptr, nullptr, &ssl_free_ErrorDetail
);
789 ssl_ex_index_ssl_peeked_cert
= SSL_get_ex_new_index(0, (void *) "ssl_peeked_cert", nullptr, nullptr, &ssl_free_X509
);
790 ssl_ex_index_ssl_errors
= SSL_get_ex_new_index(0, (void *) "ssl_errors", nullptr, nullptr, &ssl_free_SslErrors
);
791 ssl_ex_index_ssl_cert_chain
= SSL_get_ex_new_index(0, (void *) "ssl_cert_chain", nullptr, nullptr, &ssl_free_CertChain
);
792 ssl_ex_index_ssl_validation_counter
= SSL_get_ex_new_index(0, (void *) "ssl_validation_counter", nullptr, nullptr, &ssl_free_int
);
793 ssl_ex_index_verify_callback_parameters
= SSL_get_ex_new_index(0, (void *) "verify_callback_parameters", nullptr, nullptr, &ssl_free_VerifyCallbackParameters
);
797 Ssl::InitServerContext(Security::ContextPointer
&ctx
, AnyP::PortCfg
&)
806 Ssl::InitClientContext(Security::ContextPointer
&ctx
, Security::PeerOptions
&peer
, Security::ParsedPortFlags fl
)
811 if (!peer
.sslCipher
.isEmpty()) {
812 debugs(83, 5, "Using chiper suite " << peer
.sslCipher
<< ".");
814 const char *cipher
= peer
.sslCipher
.c_str();
815 if (!SSL_CTX_set_cipher_list(ctx
.get(), cipher
)) {
816 const auto ssl_error
= ERR_get_error();
817 fatalf("Failed to set SSL cipher suite '%s': %s\n",
818 cipher
, Security::ErrorString(ssl_error
));
822 if (!peer
.certs
.empty()) {
823 // TODO: support loading multiple cert/key pairs
824 auto &keys
= peer
.certs
.front();
825 if (!keys
.certFile
.isEmpty()) {
826 debugs(83, 2, "loading client certificate from " << keys
.certFile
);
828 const char *certfile
= keys
.certFile
.c_str();
829 if (!SSL_CTX_use_certificate_chain_file(ctx
.get(), certfile
)) {
830 const auto ssl_error
= ERR_get_error();
831 fatalf("Failed to acquire SSL certificate '%s': %s\n",
832 certfile
, Security::ErrorString(ssl_error
));
835 debugs(83, 2, "loading private key from " << keys
.privateKeyFile
);
836 const char *keyfile
= keys
.privateKeyFile
.c_str();
837 ssl_ask_password(ctx
.get(), keyfile
);
839 if (!SSL_CTX_use_PrivateKey_file(ctx
.get(), keyfile
, SSL_FILETYPE_PEM
)) {
840 const auto ssl_error
= ERR_get_error();
841 fatalf("Failed to acquire SSL private key '%s': %s\n",
842 keyfile
, Security::ErrorString(ssl_error
));
845 debugs(83, 5, "Comparing private and public SSL keys.");
847 if (!SSL_CTX_check_private_key(ctx
.get())) {
848 const auto ssl_error
= ERR_get_error();
849 fatalf("SSL private key '%s' does not match public key '%s': %s\n",
850 certfile
, keyfile
, Security::ErrorString(ssl_error
));
855 MaybeSetupRsaCallback(ctx
);
857 Ssl::ConfigurePeerVerification(ctx
, fl
);
862 /// \ingroup ServerProtocolSSLInternal
864 ssl_get_attribute(X509_NAME
* name
, const char *attribute_name
)
866 static char buffer
[1024];
869 if (strcmp(attribute_name
, "DN") == 0) {
870 X509_NAME_oneline(name
, buffer
, sizeof(buffer
));
872 int nid
= OBJ_txt2nid(const_cast<char *>(attribute_name
));
874 debugs(83, DBG_IMPORTANT
, "WARNING: Unknown SSL attribute name '" << attribute_name
<< "'");
877 X509_NAME_get_text_by_NID(name
, nid
, buffer
, sizeof(buffer
));
880 return *buffer
? buffer
: nullptr;
883 /// \ingroup ServerProtocolSSLInternal
885 Ssl::GetX509UserAttribute(X509
* cert
, const char *attribute_name
)
893 name
= X509_get_subject_name(cert
);
895 ret
= ssl_get_attribute(name
, attribute_name
);
901 Ssl::GetX509Fingerprint(X509
* cert
, const char *)
903 static char buf
[1024];
908 unsigned char md
[EVP_MAX_MD_SIZE
];
909 if (!X509_digest(cert
, EVP_sha1(), md
, &n
))
912 assert(3 * n
+ 1 < sizeof(buf
));
915 for (unsigned int i
=0; i
< n
; ++i
, s
+= 3) {
916 const char term
= (i
+ 1 < n
) ? ':' : '\0';
917 snprintf(s
, 4, "%02X%c", md
[i
], term
);
924 Ssl::GetX509PEM(X509
* cert
)
928 Ssl::BIO_Pointer
bio(BIO_new(BIO_s_mem()));
929 PEM_write_bio_X509(bio
.get(), cert
);
932 const auto len
= BIO_get_mem_data(bio
.get(), &ptr
);
933 return SBuf(ptr
, len
);
936 /// \ingroup ServerProtocolSSLInternal
938 Ssl::GetX509CAAttribute(X509
* cert
, const char *attribute_name
)
947 name
= X509_get_issuer_name(cert
);
949 ret
= ssl_get_attribute(name
, attribute_name
);
954 const char *sslGetUserAttribute(SSL
*ssl
, const char *attribute_name
)
959 X509
*cert
= SSL_get_peer_certificate(ssl
);
961 const char *attr
= Ssl::GetX509UserAttribute(cert
, attribute_name
);
967 const char *sslGetCAAttribute(SSL
*ssl
, const char *attribute_name
)
972 X509
*cert
= SSL_get_peer_certificate(ssl
);
974 const char *attr
= Ssl::GetX509CAAttribute(cert
, attribute_name
);
981 sslGetUserEmail(SSL
* ssl
)
983 return sslGetUserAttribute(ssl
, "emailAddress");
987 sslGetUserCertificatePEM(SSL
*ssl
)
991 if (const auto cert
= SSL_get_peer_certificate(ssl
))
992 return Ssl::GetX509PEM(cert
);
998 sslGetUserCertificateChainPEM(SSL
*ssl
)
1002 auto chain
= SSL_get_peer_cert_chain(ssl
);
1005 return sslGetUserCertificatePEM(ssl
);
1007 Ssl::BIO_Pointer
bio(BIO_new(BIO_s_mem()));
1009 for (int i
= 0; i
< sk_X509_num(chain
); ++i
) {
1010 X509
*cert
= sk_X509_value(chain
, i
);
1011 PEM_write_bio_X509(bio
.get(), cert
);
1015 const auto len
= BIO_get_mem_data(bio
.get(), &ptr
);
1016 return SBuf(ptr
, len
);
1019 /// Create SSL context and apply ssl certificate and private key to it.
1020 Security::ContextPointer
1021 Ssl::createSSLContext(Security::CertPointer
& x509
, Security::PrivateKeyPointer
& pkey
, Security::ServerOptions
&options
)
1023 Security::ContextPointer
ctx(options
.createBlankContext());
1025 if (!SSL_CTX_use_certificate(ctx
.get(), x509
.get()))
1026 return Security::ContextPointer();
1028 if (!SSL_CTX_use_PrivateKey(ctx
.get(), pkey
.get()))
1029 return Security::ContextPointer();
1031 if (!options
.updateContextConfig(ctx
))
1032 return Security::ContextPointer();
1037 Security::ContextPointer
1038 Ssl::GenerateSslContextUsingPkeyAndCertFromMemory(const char * data
, Security::ServerOptions
&options
, bool trusted
)
1040 Security::CertPointer cert
;
1041 Security::PrivateKeyPointer pkey
;
1042 if (!readCertAndPrivateKeyFromMemory(cert
, pkey
, data
) || !cert
|| !pkey
)
1043 return Security::ContextPointer();
1045 Security::ContextPointer
ctx(createSSLContext(cert
, pkey
, options
));
1047 Ssl::chainCertificatesToSSLContext(ctx
, options
);
1051 Security::ContextPointer
1052 Ssl::GenerateSslContext(CertificateProperties
const &properties
, Security::ServerOptions
&options
, bool trusted
)
1054 Security::CertPointer cert
;
1055 Security::PrivateKeyPointer pkey
;
1056 if (!generateSslCertificate(cert
, pkey
, properties
) || !cert
|| !pkey
)
1057 return Security::ContextPointer();
1059 Security::ContextPointer
ctx(createSSLContext(cert
, pkey
, options
));
1061 Ssl::chainCertificatesToSSLContext(ctx
, options
);
1066 Ssl::chainCertificatesToSSLContext(Security::ContextPointer
&ctx
, Security::ServerOptions
&options
)
1069 // Add signing certificate to the certificates chain
1070 X509
*signingCert
= options
.signingCa
.cert
.get();
1071 if (SSL_CTX_add_extra_chain_cert(ctx
.get(), signingCert
)) {
1072 // increase the certificate lock
1073 X509_up_ref(signingCert
);
1075 const auto ssl_error
= ERR_get_error();
1076 debugs(33, DBG_IMPORTANT
, "WARNING: can not add signing certificate to SSL context chain: " << Security::ErrorString(ssl_error
));
1079 for (auto cert
: options
.signingCa
.chain
) {
1080 if (SSL_CTX_add_extra_chain_cert(ctx
.get(), cert
.get())) {
1081 // increase the certificate lock
1082 X509_up_ref(cert
.get());
1084 const auto error
= ERR_get_error();
1085 debugs(83, DBG_IMPORTANT
, "WARNING: can not add certificate to SSL dynamic context chain: " << Security::ErrorString(error
));
1091 Ssl::configureUnconfiguredSslContext(Security::ContextPointer
&ctx
, Ssl::CertSignAlgorithm signAlgorithm
,AnyP::PortCfg
&port
)
1093 if (ctx
&& signAlgorithm
== Ssl::algSignTrusted
)
1094 Ssl::chainCertificatesToSSLContext(ctx
, port
.secure
);
1098 Ssl::configureSSL(SSL
*ssl
, CertificateProperties
const &properties
, AnyP::PortCfg
&)
1100 Security::CertPointer cert
;
1101 Security::PrivateKeyPointer pkey
;
1102 if (!generateSslCertificate(cert
, pkey
, properties
))
1111 if (!SSL_use_certificate(ssl
, cert
.get()))
1114 if (!SSL_use_PrivateKey(ssl
, pkey
.get()))
1121 Ssl::configureSSLUsingPkeyAndCertFromMemory(SSL
*ssl
, const char *data
, AnyP::PortCfg
&)
1123 Security::CertPointer cert
;
1124 Security::PrivateKeyPointer pkey
;
1125 if (!readCertAndPrivateKeyFromMemory(cert
, pkey
, data
))
1131 if (!SSL_use_certificate(ssl
, cert
.get()))
1134 if (!SSL_use_PrivateKey(ssl
, pkey
.get()))
1141 Ssl::verifySslCertificate(const Security::ContextPointer
&ctx
, CertificateProperties
const &)
1143 #if HAVE_SSL_CTX_GET0_CERTIFICATE
1144 X509
* cert
= SSL_CTX_get0_certificate(ctx
.get());
1145 #elif SQUID_USE_SSLGETCERTIFICATE_HACK
1146 // SSL_get_certificate is buggy in openssl versions 1.0.1d and 1.0.1e
1147 // Try to retrieve certificate directly from Security::ContextPointer object
1148 X509
***pCert
= (X509
***)ctx
->cert
;
1149 X509
* cert
= pCert
&& *pCert
? **pCert
: NULL
;
1150 #elif SQUID_SSLGETCERTIFICATE_BUGGY
1151 X509
* cert
= nullptr;
1154 // Temporary ssl for getting X509 certificate from SSL_CTX.
1155 Security::SessionPointer
ssl(Security::NewSessionObject(ctx
));
1156 X509
* cert
= SSL_get_certificate(ssl
.get());
1160 const auto time_notBefore
= X509_getm_notBefore(cert
);
1161 const auto time_notAfter
= X509_getm_notAfter(cert
);
1162 return (X509_cmp_current_time(time_notBefore
) < 0 && X509_cmp_current_time(time_notAfter
) > 0);
1166 Ssl::setClientSNI(SSL
*ssl
, const char *fqdn
)
1168 const Ip::Address
test(fqdn
);
1169 if (!test
.isAnyAddr())
1170 return; // raw IP is inappropriate for SNI
1172 //The SSL_CTRL_SET_TLSEXT_HOSTNAME is a openssl macro which indicates
1173 // if the TLS servername extension (SNI) is enabled in openssl library.
1174 #if defined(SSL_CTRL_SET_TLSEXT_HOSTNAME)
1175 if (!SSL_set_tlsext_host_name(ssl
, fqdn
)) {
1176 const auto ssl_error
= ERR_get_error();
1177 debugs(83, 3, "WARNING: unable to set TLS servername extension (SNI): " <<
1178 Security::ErrorString(ssl_error
) << "\n");
1181 debugs(83, 7, "no support for TLS servername extension (SNI)");
1186 Ssl::findIssuerUri(X509
*cert
)
1188 AUTHORITY_INFO_ACCESS
*info
;
1191 info
= static_cast<AUTHORITY_INFO_ACCESS
*>(X509_get_ext_d2i(cert
, NID_info_access
, nullptr, nullptr));
1195 static char uri
[MAX_URL
];
1198 for (int i
= 0; i
< sk_ACCESS_DESCRIPTION_num(info
); i
++) {
1199 ACCESS_DESCRIPTION
*ad
= sk_ACCESS_DESCRIPTION_value(info
, i
);
1200 if (OBJ_obj2nid(ad
->method
) == NID_ad_ca_issuers
) {
1201 if (ad
->location
->type
== GEN_URI
) {
1203 reinterpret_cast<const char *>(
1204 ASN1_STRING_get0_data(ad
->location
->d
.uniformResourceIdentifier
)
1211 AUTHORITY_INFO_ACCESS_free(info
);
1212 return uri
[0] != '\0' ? uri
: nullptr;
1216 Ssl::loadCerts(const char *certsFile
, Ssl::CertsIndexedList
&list
)
1218 const BIO_Pointer
in(BIO_new_file(certsFile
, "r"));
1220 debugs(83, DBG_IMPORTANT
, "ERROR: Failed to open '" << certsFile
<< "' to load certificates");
1224 while (auto aCert
= ReadOptionalCertificate(in
)) {
1225 const auto name
= Security::SubjectName(*aCert
);
1226 list
.insert(std::pair
<SBuf
, X509
*>(name
, aCert
.release()));
1228 debugs(83, 4, "Loaded " << list
.size() << " certificates from file: '" << certsFile
<< "'");
1232 /// quickly find the issuer certificate of a certificate cert in the
1233 /// Ssl::CertsIndexedList list
1235 findCertIssuerFast(Ssl::CertsIndexedList
&list
, X509
*cert
)
1237 const auto name
= Security::IssuerName(*cert
);
1241 const auto ret
= list
.equal_range(name
);
1242 for (Ssl::CertsIndexedList::iterator it
= ret
.first
; it
!= ret
.second
; ++it
) {
1243 X509
*issuer
= it
->second
;
1244 if (Security::IssuedBy(*cert
, *issuer
)) {
1251 /// slowly find the issuer certificate of a given cert using linear search
1253 sk_x509_findIssuer(const STACK_OF(X509
) *sk
, X509
*cert
)
1258 const auto certCount
= sk_X509_num(sk
);
1259 for (int i
= 0; i
< certCount
; ++i
) {
1260 const auto issuer
= sk_X509_value(sk
, i
);
1261 if (Security::IssuedBy(*cert
, *issuer
))
1267 /// finds issuer of a given certificate in CA store of the given connContext
1268 /// \returns the cert issuer (after increasing its reference count) or nil
1270 findIssuerInCaDb(X509
*cert
, const Security::ContextPointer
&connContext
)
1275 X509_STORE_CTX
*storeCtx
= X509_STORE_CTX_new();
1277 debugs(83, DBG_IMPORTANT
, "ERROR: Failed to allocate STORE_CTX object");
1281 X509
*issuer
= nullptr;
1282 X509_STORE
*store
= SSL_CTX_get_cert_store(connContext
.get());
1283 if (X509_STORE_CTX_init(storeCtx
, store
, nullptr, nullptr)) {
1284 const auto ret
= X509_STORE_CTX_get1_issuer(&issuer
, storeCtx
, cert
);
1287 debugs(83, 5, "found " << *issuer
);
1289 debugs(83, ret
< 0 ? 2 : 3, "not found or failure: " << ret
);
1293 const auto ssl_error
= ERR_get_error();
1294 debugs(83, DBG_IMPORTANT
, "ERROR: Failed to initialize STORE_CTX object: " << Security::ErrorString(ssl_error
));
1297 X509_STORE_CTX_free(storeCtx
);
1302 Security::CertPointer
1303 Ssl::findIssuerCertificate(X509
*cert
, const STACK_OF(X509
) *serverCertificates
, const Security::ContextPointer
&context
)
1307 // check certificate chain, if any
1308 if (const auto issuer
= serverCertificates
? sk_x509_findIssuer(serverCertificates
, cert
) : nullptr) {
1309 X509_up_ref(issuer
);
1310 return Security::CertPointer(issuer
);
1313 // check untrusted certificates
1314 if (const auto issuer
= findCertIssuerFast(SquidUntrustedCerts(), cert
)) {
1315 X509_up_ref(issuer
);
1316 return Security::CertPointer(issuer
);
1319 // check trusted CA certificates
1320 if (const auto issuer
= findIssuerInCaDb(cert
, context
)) {
1321 // no X509_up_ref(issuer) because findIssuerInCaDb() ups reference count
1322 return Security::CertPointer(issuer
);
1325 return Security::CertPointer(nullptr);
1329 Ssl::missingChainCertificatesUrls(std::queue
<SBuf
> &URIs
, const STACK_OF(X509
) &serverCertificates
, const Security::ContextPointer
&context
)
1331 for (int i
= 0; i
< sk_X509_num(&serverCertificates
); ++i
) {
1332 const auto cert
= sk_X509_value(&serverCertificates
, i
);
1334 if (findIssuerCertificate(cert
, &serverCertificates
, context
))
1337 if (const auto issuerUri
= findIssuerUri(cert
)) {
1338 URIs
.push(SBuf(issuerUri
));
1340 debugs(83, 3, "Issuer certificate for " <<
1342 " is missing and its URI is not provided");
1346 debugs(83, (URIs
.empty() ? 3 : 5), "found: " << URIs
.size());
1347 return !URIs
.empty();
1350 /// add missing issuer certificates to untrustedCerts
1352 completeIssuers(X509_STORE_CTX
*ctx
, STACK_OF(X509
) &untrustedCerts
)
1354 debugs(83, 2, "completing " << sk_X509_num(&untrustedCerts
) <<
1355 " OpenSSL untrusted certs using " << Ssl::SquidUntrustedCerts().size() <<
1356 " configured untrusted certificates");
1358 const X509_VERIFY_PARAM
*param
= X509_STORE_CTX_get0_param(ctx
);
1359 int depth
= X509_VERIFY_PARAM_get_depth(param
);
1360 Security::CertPointer current
;
1361 current
.resetAndLock(X509_STORE_CTX_get0_cert(ctx
));
1363 for (i
= 0; current
&& (i
< depth
); ++i
) {
1364 if (Security::SelfSigned(*current
)) {
1365 // either ctx->cert is itself self-signed or untrustedCerts
1366 // already contain the self-signed current certificate
1370 // untrustedCerts is short, not worth indexing
1371 const Security::ContextPointer nullCtx
;
1372 auto issuer
= Ssl::findIssuerCertificate(current
.get(), &untrustedCerts
, nullCtx
);
1375 sk_X509_push(&untrustedCerts
, issuer
.release());
1379 debugs(83, 2, "exceeded the maximum certificate chain length: " << depth
);
1382 /// Validates certificates while consulting sslproxy_foreign_intermediate_certs
1383 /// and, optionally, the given extra certificates.
1384 /// \returns whatever OpenSSL X509_verify_cert() returns
1386 VerifyCtxCertificates(X509_STORE_CTX
*ctx
, STACK_OF(X509
) *extraCerts
)
1388 // OpenSSL already maintains ctx->untrusted but we cannot modify
1389 // internal OpenSSL list directly. We have to give OpenSSL our own
1390 // list, but it must include certificates on the OpenSSL ctx->untrusted
1391 STACK_OF(X509
) *oldUntrusted
= X509_STORE_CTX_get0_untrusted(ctx
);
1392 // X509_chain_up_ref() increments cert references _and_ dupes the stack
1393 Ssl::X509_STACK_Pointer
untrustedCerts(oldUntrusted
? X509_chain_up_ref(oldUntrusted
) : sk_X509_new_null());
1396 for (int i
= 0; i
< sk_X509_num(extraCerts
); ++i
) {
1397 const auto cert
= sk_X509_value(extraCerts
, i
);
1399 sk_X509_push(untrustedCerts
.get(), cert
);
1403 // If the local untrusted certificates internal database is used
1404 // run completeIssuers to add missing certificates if possible.
1405 if (Ssl::SquidUntrustedCerts().size() > 0)
1406 completeIssuers(ctx
, *untrustedCerts
);
1408 X509_STORE_CTX_set0_untrusted(ctx
, untrustedCerts
.get()); // No locking/unlocking, just sets ctx->untrusted
1409 int ret
= X509_verify_cert(ctx
);
1410 X509_STORE_CTX_set0_untrusted(ctx
, oldUntrusted
); // Set back the old untrusted list
1414 /// \interface OpenSSL_vcb_disambiguation
1416 /// OpenSSL has two very different concepts with nearly identical names:
1418 /// a) A (replaceable) certificate verification function -- X509_verify_cert():
1419 /// This function drives the entire certificate verification algorithm.
1420 /// It can be called directly, but is usually called during SSL_connect().
1421 /// OpenSSL calls this function a "verification callback function".
1422 /// SSL_CTX_set_cert_verify_callback(3) replaces X509_verify_cert() default.
1424 /// b) An (optional) certificate verification adjustment callback:
1425 /// This function, if set, is called at the end of (a) to adjust (a) results.
1426 /// It is never called directly, only from (a).
1427 /// OpenSSL calls this function a "verify_callback function".
1428 /// The SSL_CTX_set_verify(3) family of functions sets this function.
1430 /// Validates certificates while consulting sslproxy_foreign_intermediate_certs
1431 /// but without using any dynamically downloaded intermediate certificates.
1432 /// OpenSSL "verification callback function" (\ref OpenSSL_vcb_disambiguation)
1434 untrustedToStoreCtx_cb(X509_STORE_CTX
*ctx
, void *)
1436 debugs(83, 4, "Try to use pre-downloaded intermediate certificates");
1437 return VerifyCtxCertificates(ctx
, nullptr);
1441 Ssl::useSquidUntrusted(SSL_CTX
*sslContext
)
1443 SSL_CTX_set_cert_verify_callback(sslContext
, untrustedToStoreCtx_cb
, nullptr);
1447 Ssl::loadSquidUntrusted(const char *path
)
1449 return Ssl::loadCerts(path
, SquidUntrustedCerts());
1453 Ssl::unloadSquidUntrusted()
1455 if (SquidUntrustedCerts().size()) {
1456 for (const auto &i
: SquidUntrustedCerts()) {
1457 X509_free(i
.second
);
1459 SquidUntrustedCerts().clear();
1463 bool Ssl::generateUntrustedCert(Security::CertPointer
&untrustedCert
, Security::PrivateKeyPointer
&untrustedPkey
, Security::CertPointer
const &cert
, Security::PrivateKeyPointer
const & pkey
)
1465 // Generate the self-signed certificate, using a hard-coded subject prefix
1466 Ssl::CertificateProperties certProperties
;
1467 if (const char *cn
= CommonHostName(cert
.get())) {
1468 certProperties
.commonName
= "Not trusted by \"";
1469 certProperties
.commonName
+= cn
;
1470 certProperties
.commonName
+= "\"";
1471 } else if (const char *org
= getOrganization(cert
.get())) {
1472 certProperties
.commonName
= "Not trusted by \"";
1473 certProperties
.commonName
+= org
;
1474 certProperties
.commonName
+= "\"";
1476 certProperties
.commonName
= "Not trusted";
1477 certProperties
.setCommonName
= true;
1478 // O, OU, and other CA subject fields will be mimicked
1479 // Expiration date and other common properties will be mimicked
1480 certProperties
.signAlgorithm
= Ssl::algSignSelf
;
1481 certProperties
.signWithPkey
.resetAndLock(pkey
.get());
1482 certProperties
.mimicCert
.resetAndLock(cert
.get());
1483 return Ssl::generateSslCertificate(untrustedCert
, untrustedPkey
, certProperties
);
1486 void Ssl::InRamCertificateDbKey(const Ssl::CertificateProperties
&certProperties
, SBuf
&key
)
1488 bool origSignatureAsKey
= false;
1489 if (certProperties
.mimicCert
) {
1490 if (auto *sig
= Ssl::X509_get_signature(certProperties
.mimicCert
)) {
1491 origSignatureAsKey
= true;
1492 key
.append((const char *)sig
->data
, sig
->length
);
1496 if (!origSignatureAsKey
|| certProperties
.setCommonName
) {
1497 // Use common name instead
1498 key
.append(certProperties
.commonName
.c_str());
1500 key
.append(certProperties
.setCommonName
? '1' : '0');
1501 key
.append(certProperties
.setValidAfter
? '1' : '0');
1502 key
.append(certProperties
.setValidBefore
? '1' : '0');
1503 key
.append(certProperties
.signAlgorithm
!= Ssl:: algSignEnd
? certSignAlgorithm(certProperties
.signAlgorithm
) : "-");
1504 key
.append(certProperties
.signHash
? EVP_MD_name(certProperties
.signHash
) : "-");
1506 if (certProperties
.mimicCert
) {
1507 Ssl::BIO_Pointer
bio(BIO_new_SBuf(&key
));
1508 ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509
), bio
.get(), (ASN1_VALUE
*)certProperties
.mimicCert
.get());
1513 bio_sbuf_create(BIO
* bio
)
1515 BIO_set_init(bio
, 0);
1516 BIO_set_data(bio
, nullptr);
1521 bio_sbuf_destroy(BIO
* bio
)
1529 bio_sbuf_write(BIO
* bio
, const char* data
, int len
)
1531 SBuf
*buf
= static_cast<SBuf
*>(BIO_get_data(bio
));
1532 // TODO: Convert exceptions into BIO errors
1533 buf
->append(data
, len
);
1538 bio_sbuf_puts(BIO
*bio
, const char *data
)
1540 // TODO: use bio_sbuf_write() instead
1541 SBuf
*buf
= static_cast<SBuf
*>(BIO_get_data(bio
));
1542 size_t oldLen
= buf
->length();
1544 return buf
->length() - oldLen
;
1548 bio_sbuf_ctrl(BIO
*bio
, int cmd
, long /* num */, void *)
1550 SBuf
*buf
= static_cast<SBuf
*>(BIO_get_data(bio
));
1552 case BIO_CTRL_RESET
:
1553 // TODO: Convert exceptions into BIO errors
1556 case BIO_CTRL_FLUSH
:
1563 BIO
*Ssl::BIO_new_SBuf(SBuf
*buf
)
1565 #if HAVE_LIBCRYPTO_BIO_METH_NEW
1566 static BIO_METHOD
*BioSBufMethods
= nullptr;
1567 if (!BioSBufMethods
) {
1568 BioSBufMethods
= BIO_meth_new(BIO_TYPE_MEM
, "Squid-SBuf");
1569 BIO_meth_set_write(BioSBufMethods
, bio_sbuf_write
);
1570 BIO_meth_set_read(BioSBufMethods
, nullptr);
1571 BIO_meth_set_puts(BioSBufMethods
, bio_sbuf_puts
);
1572 BIO_meth_set_gets(BioSBufMethods
, nullptr);
1573 BIO_meth_set_ctrl(BioSBufMethods
, bio_sbuf_ctrl
);
1574 BIO_meth_set_create(BioSBufMethods
, bio_sbuf_create
);
1575 BIO_meth_set_destroy(BioSBufMethods
, bio_sbuf_destroy
);
1578 static BIO_METHOD
*BioSBufMethods
= new BIO_METHOD({
1591 BIO
*bio
= BIO_new(BioSBufMethods
);
1593 BIO_set_data(bio
, buf
);
1594 BIO_set_init(bio
, 1);
1598 #endif /* USE_OPENSSL */