CachePeer::CachePeer(const char * const hostname):
name(xstrdup(hostname)),
- host(xstrdup(hostname))
+ host(xstrdup(hostname)),
+ tlsContext(secure, sslContext)
{
Tolower(host); // but .name preserves original spelling
}
xfree(domain);
}
+Security::FuturePeerContext *
+CachePeer::securityContext()
+{
+ if (secure.encryptTransport)
+ return &tlsContext;
+ return nullptr;
+}
+
void
CachePeer::noteSuccess()
{
/// \returns the effective connect timeout for the given peer
time_t connectTimeout() const;
+ /// TLS settings for communicating with this TLS cache_peer (if encryption
+ /// is required; see secure.encryptTransport) or nil (otherwise)
+ Security::FuturePeerContext *securityContext();
+
/// n-th cache_peer directive, starting with 1
u_int index = 0;
char *domain = nullptr; ///< Forced domain
+ // TODO: Remove secure and sslContext when FuturePeerContext below becomes PeerContext
/// security settings for peer connection
Security::PeerOptions secure;
Security::ContextPointer sslContext;
+ Security::FuturePeerContext tlsContext;
+
Security::SessionStatePointer sslSession;
int front_end_https = 0; ///< 0 - off, 1 - on, 2 - auto
external_acl *externalAclHelperList;
struct {
+ Security::FuturePeerContext *defaultPeerContext;
+ // TODO: Remove when FuturePeerContext above becomes PeerContext
Security::ContextPointer sslContext;
#if USE_OPENSSL
char *foreignIntermediateCertsPath;
Adaptation::Icap::ServiceRep::ServiceRep(const ServiceConfigPointer &svcCfg):
AsyncJob("Adaptation::Icap::ServiceRep"), Adaptation::Service(svcCfg),
+ tlsContext(writeableCfg().secure, sslContext),
theOptions(nullptr), theOptionsFetcher(nullptr), theLastUpdate(0),
theBusyConns(0),
theAllWaiters(0),
void noteAdaptationAnswer(const Answer &answer) override;
Security::ContextPointer sslContext;
+ // TODO: Remove sslContext above when FuturePeerContext below becomes PeerContext
+ Security::FuturePeerContext tlsContext;
Security::SessionStatePointer sslSession;
private:
/* Security::PeerConnector API */
bool initialize(Security::SessionPointer &) override;
void noteNegotiationDone(ErrorState *error) override;
- Security::ContextPointer getTlsContext() override {
- return icapService->sslContext;
- }
+ Security::FuturePeerContext *peerContext() const override { return &icapService->tlsContext; }
private:
/* Acl::ChecklistFiller API */
#if USE_OPENSSL
Ssl::useSquidUntrusted(Config.ssl_client.sslContext.get());
#endif
+ Config.ssl_client.defaultPeerContext = new Security::FuturePeerContext(Security::ProxyOutgoingConfig, Config.ssl_client.sslContext);
}
for (const auto &p: CurrentCachePeers()) {
{
free_all();
Dns::ResolveClientAddressesAsap = false;
+ delete Config.ssl_client.defaultPeerContext;
+ Config.ssl_client.defaultPeerContext = nullptr;
Config.ssl_client.sslContext.reset();
#if USE_OPENSSL
Ssl::unloadSquidUntrusted();
CBDATA_NAMESPACED_CLASS_INIT(Security, BlindPeerConnector);
-Security::ContextPointer
-Security::BlindPeerConnector::getTlsContext()
+Security::FuturePeerContext *
+Security::BlindPeerConnector::peerContext() const
{
- const CachePeer *peer = serverConnection()->getPeer();
+ const auto peer = serverConnection()->getPeer();
if (peer && peer->secure.encryptTransport)
- return peer->sslContext;
+ return peer->securityContext();
- return ::Config.ssl_client.sslContext;
+ return Config.ssl_client.defaultPeerContext;
}
bool
namespace Security
{
-/// A simple PeerConnector for SSL/TLS cache_peers. No SslBump capabilities.
+/// A PeerConnector for TLS cache_peers and origin servers. No SslBump capabilities.
class BlindPeerConnector: public Security::PeerConnector {
CBDATA_CHILD(BlindPeerConnector);
public:
/// \returns true on successful initialization
bool initialize(Security::SessionPointer &) override;
- /// Return the configured TLS context object
- Security::ContextPointer getTlsContext() override;
+ FuturePeerContext *peerContext() const override;
/// On success, stores the used TLS session for later use.
/// On error, informs the peer.
{
Must(Comm::IsConnOpen(serverConnection()));
- Security::ContextPointer ctx(getTlsContext());
- debugs(83, 5, serverConnection() << ", ctx=" << (void*)ctx.get());
+ const auto ctx = peerContext();
+ debugs(83, 5, serverConnection() << ", ctx=" << ctx);
- if (!ctx || !Security::CreateClientSession(ctx, serverConnection(), "server https start")) {
+ if (!ctx || !Security::CreateClientSession(*ctx, serverConnection(), "server https start")) {
const auto xerrno = errno;
if (!ctx) {
debugs(83, DBG_IMPORTANT, "ERROR: initializing TLS connection: No security context.");
downloadedCerts.reset(sk_X509_new_null());
sk_X509_push(downloadedCerts.get(), cert);
- ContextPointer ctx(getTlsContext());
+ const auto ctx = peerContext()->raw;
const auto certsList = SSL_get_peer_cert_chain(&sconn);
if (!Ssl::findIssuerCertificate(cert, certsList, ctx)) {
if (const auto issuerUri = Ssl::findIssuerUri(cert)) {
}
debugs(83, 5, "server certificates: " << sk_X509_num(certs));
- const auto ctx = getTlsContext();
+ const auto optionalContext = peerContext();
+ if (!optionalContext) {
+ debugs(83, 3, "cannot compute due to disabled TLS support");
+ return false;
+ }
+ const auto ctx = optionalContext->raw;
if (!Ssl::missingChainCertificatesUrls(urlsOfMissingCerts, *certs, ctx))
return false; // missingChainCertificatesUrls() reports the exact reason
/// \param error if not NULL the SSL negotiation was aborted with an error
virtual void noteNegotiationDone(ErrorState *) {}
- /// Must implemented by the kid classes to return the TLS context object to use
- /// for building the encryption context objects.
- virtual Security::ContextPointer getTlsContext() = 0;
+ /// peer's security context
+ /// \returns nil if Squid is built without TLS support (XXX: Prevent PeerConnector creation in those cases instead)
+ virtual FuturePeerContext *peerContext() const = 0;
/// mimics FwdState to minimize changes to FwdState::initiate/negotiateSsl
Comm::ConnectionPointer const &serverConnection() const { return serverConn; }
bool encryptTransport = false;
};
+// XXX: Remove this shim after upgrading legacy code to store PeerContext
+// objects instead of disjoint PeerOptons and Context objects (where PeerContext
+// is a class that creates and manages {PeerOptions, ContextPointer} pair).
+/// A combination of PeerOptions and the corresponding Context.
+class FuturePeerContext
+{
+public:
+ FuturePeerContext(PeerOptions &o, const ContextPointer &c): options(o), raw(c) {}
+
+ PeerOptions &options; ///< TLS context configuration
+ const ContextPointer &raw; ///< TLS context configured using options
+};
+
/// configuration options for DIRECT server access
extern PeerOptions ProxyOutgoingConfig;
}
bool
-Security::CreateClientSession(const Security::ContextPointer &ctx, const Comm::ConnectionPointer &c, const char *squidCtx)
+Security::CreateClientSession(FuturePeerContext &ctx, const Comm::ConnectionPointer &c, const char *squidCtx)
{
- if (!c || !c->getPeer())
- return CreateSession(ctx, c, Security::ProxyOutgoingConfig, Security::Io::BIO_TO_SERVER, squidCtx);
-
- auto *peer = c->getPeer();
- return CreateSession(ctx, c, peer->secure, Security::Io::BIO_TO_SERVER, squidCtx);
+ // TODO: We cannot make ctx constant because CreateSession() takes
+ // non-constant ctx.options (PeerOptions). It does that because GnuTLS
+ // needs to call PeerOptions::updateSessionOptions(), which is not constant
+ // because it compiles options (just in case) every time. To achieve
+ // const-correctness, we should compile PeerOptions once, not every time.
+ return CreateSession(ctx.raw, c, ctx.options, Security::Io::BIO_TO_SERVER, squidCtx);
}
bool
namespace Security {
+// XXX: Should be only in src/security/forward.h (which should not include us
+// because that #include creates a circular reference and problems like this).
+class FuturePeerContext;
+
/// Creates TLS Client connection structure (aka 'session' state) and initializes TLS/SSL I/O (Comm and BIO).
/// On errors, emits DBG_IMPORTANT with details and returns false.
-bool CreateClientSession(const Security::ContextPointer &, const Comm::ConnectionPointer &, const char *squidCtx);
+bool CreateClientSession(FuturePeerContext &, const Comm::ConnectionPointer &, const char *squidCtx);
class PeerOptions;
class ServerOptions;
+class FuturePeerContext;
+
class ErrorDetail;
typedef RefCount<ErrorDetail> ErrorDetailPointer;
return Ssl::bumpSplice;
}
-Security::ContextPointer
-Ssl::PeekingPeerConnector::getTlsContext()
+Security::FuturePeerContext *
+Ssl::PeekingPeerConnector::peerContext() const
{
- return ::Config.ssl_client.sslContext;
+ return ::Config.ssl_client.defaultPeerContext;
}
bool
srvBio->recordInput(true);
srvBio->mode(csd->sslBumpMode);
} else {
- // Set client SSL options
- ::Security::ProxyOutgoingConfig.updateSessionOptions(serverSession);
-
const bool redirected = request->flags.redirected && ::Config.onoff.redir_rewrites_host;
const char *sniServer = (!hostName || redirected) ?
request->url.host() :
/* Security::PeerConnector API */
bool initialize(Security::SessionPointer &) override;
- Security::ContextPointer getTlsContext() override;
+ Security::FuturePeerContext *peerContext() const override;
void noteWantWrite() override;
void noteNegotiationError(const Security::ErrorDetailPointer &) override;
void noteNegotiationDone(ErrorState *error) override;
{STUB_NOP}
bool BlindPeerConnector::initialize(Security::SessionPointer &) STUB_RETVAL(false)
-Security::ContextPointer BlindPeerConnector::getTlsContext() STUB_RETVAL(Security::ContextPointer())
+FuturePeerContext *BlindPeerConnector::peerContext() const STUB_RETVAL(nullptr)
void BlindPeerConnector::noteNegotiationDone(ErrorState *) STUB
}
void PeerConnector::noteWantRead() STUB
void PeerConnector::noteWantWrite() STUB
void PeerConnector::noteNegotiationError(const Security::ErrorDetailPointer &) STUB
-// virtual Security::ContextPointer getTlsContext() = 0;
void PeerConnector::bail(ErrorState *) STUB
void PeerConnector::sendSuccess() STUB
void PeerConnector::callBack() STUB
#include "security/PeerOptions.h"
Security::PeerOptions Security::ProxyOutgoingConfig;
+
Security::PeerOptions::PeerOptions() {
#if USE_OPENSSL
parsedOptions = 0;
#include "security/Session.h"
namespace Security {
-bool CreateClientSession(const Security::ContextPointer &, const Comm::ConnectionPointer &, const char *) STUB_RETVAL(false)
+bool CreateClientSession(FuturePeerContext &, const Comm::ConnectionPointer &, const char *) STUB_RETVAL(false)
bool CreateServerSession(const Security::ContextPointer &, const Comm::ConnectionPointer &, Security::PeerOptions &, const char *) STUB_RETVAL(false)
void SessionSendGoodbye(const Security::SessionPointer &) STUB
bool SessionIsResumed(const Security::SessionPointer &) STUB_RETVAL(false)