34 const time_t timeout):
35 AsyncJob(
"Ssl::PeekingPeerConnector"),
36 Security::PeerConnector(aServerConn, aCallback, alp, timeout),
37 clientConn(aClientConn),
39 serverCertificateHandled(false)
44 const auto serverBump = csd->serverBump();
64 checkForPeekAndSpliceGuess();
65 checkForPeekAndSpliceMatched(finalAction);
71 handleServerCertificate();
74 acl_checklist->al = al;
81 BIO *b = SSL_get_rbio(session.get());
87 acl_checklist->syncAle(request.getRaw(),
nullptr);
95 BIO *b = SSL_get_rbio(session.get());
97 debugs(83,5,
"Will check for peek and splice on FD " << serverConn->fd);
102 if (request->clientConnectionManager.valid()) {
103 request->clientConnectionManager->sslBumpMode = finalAction;
104 request->clientConnectionManager->serverBump()->act.step3 = finalAction;
106 al->ssl.bumpMode = finalAction;
111 clientConn =
nullptr;
116 debugs(83,5,
"Retry the fwdNegotiateSSL on FD " << serverConn->fd);
122 if (sslFinalized() && callback)
130 if (
const ConnStateData *csd = request->clientConnectionManager.valid()) {
133 debugs(83,5,
"default to bumping after staring");
136 debugs(83,5,
"default to splicing after " << currentMode);
138 debugs(83,3,
"default to splicing due to missing info");
147 return ::Config.ssl_client.defaultPeerContext;
161 if (
ConnStateData *csd = request->clientConnectionManager.valid()) {
163 SBuf *hostName =
nullptr;
166 SSL_set_tlsext_status_type(serverSession.get(), TLSEXT_STATUSTYPE_ocsp);
169 if (details && !details->serverName.isEmpty())
170 hostName =
new SBuf(details->serverName);
176 const bool isConnectRequest = !csd->port->flags.isIntercepted();
177 if (!request->flags.sslPeek || isConnectRequest)
178 hostName =
new SBuf(request->url.host());
185 auto clientSession =
fd_table[clientConn->fd].ssl.get();
187 BIO *bc = SSL_get_rbio(clientSession);
193 BIO *b = SSL_get_rbio(serverSession.get());
199 srvBio->
mode(csd->sslBumpMode);
201#if defined(SSL_OP_LEGACY_SERVER_CONNECT)
211 if (csd->sslBumpMode ==
Ssl::bumpPeek && SSL_OP_LEGACY_SERVER_CONNECT) {
212 const auto adjustedOptions = SSL_set_options(serverSession.get(), SSL_OP_LEGACY_SERVER_CONNECT);
213 debugs(83, 5,
"post-SSL_OP_LEGACY_SERVER_CONNECT options for session=" << serverSession <<
": " <<
asHex(adjustedOptions));
217 const bool redirected = request->flags.redirected && ::Config.onoff.redir_rewrites_host;
218 const char *sniServer = (!hostName || redirected) ?
219 request->url.host() :
226 serverBump->attachServerSession(serverSession);
228 if (X509 *peeked_cert = serverBump->serverCert.get()) {
229 X509_up_ref(peeked_cert);
242 if (!request->clientConnectionManager.valid() || !
fd_table[serverConnection()->fd].ssl)
246 if (
Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
247 if (!serverBump->serverCert.get()) {
250 if (errDetail && errDetail->peerCert())
251 serverBump->serverCert.resetAndLock(errDetail->peerCert());
253 handleServerCertificate();
261 const bool isConnectRequest = !request->clientConnectionManager->port->flags.isIntercepted();
262 if (request->flags.sslPeek && !isConnectRequest) {
263 if (X509 *srvX509 = serverBump->serverCert.get()) {
265 request->url.host(name);
266 debugs(83, 3,
"reset request host: " << name);
274 serverCertificateVerified();
289 fd_table[serverConn->fd].useDefaultIo();
291 fd_table[clientConn->fd].useDefaultIo();
294 const auto session =
fd_table[serverConn->fd].ssl;
295 auto b = SSL_get_rbio(session.get());
298 debugs(83, 5,
"will tunnel instead of negotiating TLS");
299 switchToTunnel(request.getRaw(), clientConn, serverConn, srvBio->rBufData());
300 answer().tunneled =
true;
308 const int fd = serverConnection()->fd;
310 BIO *b = SSL_get_rbio(session.get());
314 debugs(81, 3,
"hold write on SSL connection on FD " << fd);
315 checkForPeekAndSplice();
325 const int fd = serverConnection()->fd;
327 BIO *b = SSL_get_rbio(session.get());
331 auto bypassValidator =
false;
337 bypassValidator =
true;
347 bypassValidator =
true;
351 if (bypassValidator) {
352 bypassCertValidator();
374 debugs(81, 3,
"hold TLS write on FD " << fd <<
" despite " << errorDetail);
375 checkForPeekAndSplice();
387 if (serverCertificateHandled)
390 if (
ConnStateData *csd = request->clientConnectionManager.valid()) {
391 const int fd = serverConnection()->fd;
397 serverCertificateHandled =
true;
401 serverBump->serverCert = std::move(serverCert);
409 if (
ConnStateData *csd = request->clientConnectionManager.valid()) {
414 const int fd = serverConnection()->fd;
420 debugs(83, 5,
"HTTPS server CN: " << csd->sslCommonName() <<
421 " bumped: " << *serverConnection());
#define CallJobHere1(debugSection, debugLevel, job, Class, method, arg1)
#define Here()
source code location of the caller
AsHex< Integer > asHex(const Integer n)
a helper to ease AsHex object creation
void error(char *format,...)
void applyTlsDetailsToSSL(SSL *ssl, Security::TlsDetails::Pointer const &details, Ssl::BumpMode bumpMode)
#define CBDATA_NAMESPACED_CLASS_INIT(namespace, type)
static MakingPointer Make(const acl_access *a, HttpRequest *r)
static void NonBlockingCheck(MakingPointer &&p, ACLCB *cb, void *data)
int kind
the matched custom access list verb (or zero)
a smart AsyncCall pointer for delivery of future results
Cbc * valid() const
was set and is valid
CbcPointer< ConnStateData > clientConnectionManager
A combination of PeerOptions and the corresponding Context.
void resetWithoutLocking(T *t)
Reset raw pointer - unlock any previous one and save new one without locking.
T * get() const
Returns raw and possibly nullptr pointer.
virtual bool initialize(Security::SessionPointer &)
virtual void noteNegotiationError(const Security::ErrorDetailPointer &)
Called when the SSL_connect function aborts with an SSL negotiation error.
virtual void noteWantWrite()
HttpRequestPointer request
peer connection trigger or cause
const SBuf & rBufData()
The buffered input data.
A PeerConnector for HTTP origin servers. Capable of SslBumping.
bool initialize(Security::SessionPointer &) override
void checkForPeekAndSpliceDone(Acl::Answer)
Callback function for ssl_bump acl check in step3 SSL bump step.
void noteNegotiationError(const Security::ErrorDetailPointer &) override
Called when the SSL_connect function aborts with an SSL negotiation error.
void startTunneling()
Abruptly stops TLS negotiation and starts tunneling.
void checkForPeekAndSpliceMatched(const Ssl::BumpMode finalMode)
Handles the final bumping decision.
void checkForPeekAndSplice()
void noteNegotiationDone(ErrorState *error) override
void handleServerCertificate()
static void cbCheckForPeekAndSpliceDone(Acl::Answer, void *data)
A wrapper function for checkForPeekAndSpliceDone for use with acl.
PeekingPeerConnector(HttpRequestPointer &aRequest, const Comm::ConnectionPointer &aServerConn, const Comm::ConnectionPointer &aClientConn, const AsyncCallback< Security::EncryptorAnswer > &aCallback, const AccessLogEntryPointer &alp, time_t timeout=0)
Security::FuturePeerContext * peerContext() const override
void serverCertificateVerified()
Ssl::BumpMode checkForPeekAndSpliceGuess() const
Guesses the final bumping decision when no ssl_bump rules match.
void noteWantWrite() override
void mode(Ssl::BumpMode m)
The bumping mode.
bool holdWrite() const
The write hold state.
void recordInput(bool r)
Enables or disables the input data recording, for internal analysis.
bool canBump()
Whether we can bump or not the SSL stream.
void setClientFeatures(Security::TlsDetails::Pointer const &details, SBuf const &hello)
Sets the random number to use in client SSL HELLO message.
bool encryptedCertificates() const
Ssl::BumpMode bumpMode()
return the bumping mode
bool canSplice()
Whether we can splice or not the SSL stream.
an std::runtime_error with thrower location info
#define debugs(SECTION, LEVEL, CONTENT)
@ ERR_SECURE_CONNECT_FAIL
int ssl_ex_index_ssl_peeked_cert
int ssl_ex_index_ssl_error_detail
void setClientSNI(SSL *ssl, const char *fqdn)
const char * CommonHostName(X509 *x509)
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Network/connection security abstraction layer.
std::shared_ptr< SSL > SessionPointer
void * BIO_get_data(BIO *table)
void switchToTunnel(HttpRequest *request, const Comm::ConnectionPointer &clientConn, const Comm::ConnectionPointer &srvConn, const SBuf &preReadServerData)