2 * Copyright (C) 1996-2019 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-Bump Server/Peer negotiation */
12 #include "acl/FilledChecklist.h"
13 #include "client_side.h"
14 #include "errorpage.h"
16 #include "http/Stream.h"
17 #include "HttpRequest.h"
18 #include "security/NegotiationHistory.h"
19 #include "SquidConfig.h"
21 #include "ssl/PeekingPeerConnector.h"
22 #include "ssl/ServerBump.h"
24 CBDATA_NAMESPACED_CLASS_INIT(Ssl
, PeekingPeerConnector
);
26 void switchToTunnel(HttpRequest
*request
, Comm::ConnectionPointer
& clientConn
, Comm::ConnectionPointer
&srvConn
);
29 Ssl::PeekingPeerConnector::cbCheckForPeekAndSpliceDone(Acl::Answer answer
, void *data
)
31 Ssl::PeekingPeerConnector
*peerConnect
= (Ssl::PeekingPeerConnector
*) data
;
32 // Use job calls to add done() checks and other job logic/protections.
33 CallJobHere1(83, 7, CbcPointer
<PeekingPeerConnector
>(peerConnect
), Ssl::PeekingPeerConnector
, checkForPeekAndSpliceDone
, answer
);
37 Ssl::PeekingPeerConnector::checkForPeekAndSpliceDone(Acl::Answer answer
)
39 const Ssl::BumpMode finalAction
= answer
.allowed() ?
40 static_cast<Ssl::BumpMode
>(answer
.kind
):
41 checkForPeekAndSpliceGuess();
42 checkForPeekAndSpliceMatched(finalAction
);
46 Ssl::PeekingPeerConnector::checkForPeekAndSplice()
48 // Mark Step3 of bumping
49 if (request
->clientConnectionManager
.valid()) {
50 if (Ssl::ServerBump
*serverBump
= request
->clientConnectionManager
->serverBump()) {
51 serverBump
->step
= Ssl::bumpStep3
;
55 handleServerCertificate();
57 ACLFilledChecklist
*acl_checklist
= new ACLFilledChecklist(
58 ::Config
.accessList
.ssl_bump
,
59 request
.getRaw(), NULL
);
60 acl_checklist
->al
= al
;
61 acl_checklist
->banAction(Acl::Answer(ACCESS_ALLOWED
, Ssl::bumpNone
));
62 acl_checklist
->banAction(Acl::Answer(ACCESS_ALLOWED
, Ssl::bumpPeek
));
63 acl_checklist
->banAction(Acl::Answer(ACCESS_ALLOWED
, Ssl::bumpStare
));
64 acl_checklist
->banAction(Acl::Answer(ACCESS_ALLOWED
, Ssl::bumpClientFirst
));
65 acl_checklist
->banAction(Acl::Answer(ACCESS_ALLOWED
, Ssl::bumpServerFirst
));
66 Security::SessionPointer
session(fd_table
[serverConn
->fd
].ssl
);
67 BIO
*b
= SSL_get_rbio(session
.get());
68 Ssl::ServerBio
*srvBio
= static_cast<Ssl::ServerBio
*>(BIO_get_data(b
));
69 if (!srvBio
->canSplice())
70 acl_checklist
->banAction(Acl::Answer(ACCESS_ALLOWED
, Ssl::bumpSplice
));
71 if (!srvBio
->canBump())
72 acl_checklist
->banAction(Acl::Answer(ACCESS_ALLOWED
, Ssl::bumpBump
));
73 acl_checklist
->syncAle(request
.getRaw(), nullptr);
74 acl_checklist
->nonBlockingCheck(Ssl::PeekingPeerConnector::cbCheckForPeekAndSpliceDone
, this);
78 Ssl::PeekingPeerConnector::checkForPeekAndSpliceMatched(const Ssl::BumpMode action
)
80 Security::SessionPointer
session(fd_table
[serverConn
->fd
].ssl
);
81 BIO
*b
= SSL_get_rbio(session
.get());
82 Ssl::ServerBio
*srvBio
= static_cast<Ssl::ServerBio
*>(BIO_get_data(b
));
83 debugs(83,5, "Will check for peek and splice on FD " << serverConn
->fd
);
85 Ssl::BumpMode finalAction
= action
;
86 Must(finalAction
== Ssl::bumpSplice
|| finalAction
== Ssl::bumpBump
|| finalAction
== Ssl::bumpTerminate
);
87 // Record final decision
88 if (request
->clientConnectionManager
.valid()) {
89 request
->clientConnectionManager
->sslBumpMode
= finalAction
;
90 request
->clientConnectionManager
->serverBump()->act
.step3
= finalAction
;
92 al
->ssl
.bumpMode
= finalAction
;
94 if (finalAction
== Ssl::bumpTerminate
) {
97 } else if (finalAction
!= Ssl::bumpSplice
) {
98 //Allow write, proceed with the connection
99 srvBio
->holdWrite(false);
100 srvBio
->recordInput(false);
101 debugs(83,5, "Retry the fwdNegotiateSSL on FD " << serverConn
->fd
);
102 Security::PeerConnector::noteWantWrite();
105 // Ssl Negotiation stops here. Last SSL checks for valid certificates
106 // and if done, switch to tunnel mode
107 if (sslFinalized()) {
108 debugs(83,5, "Abort NegotiateSSL on FD " << serverConn
->fd
<< " and splice the connection");
115 Ssl::PeekingPeerConnector::checkForPeekAndSpliceGuess() const
117 if (const ConnStateData
*csd
= request
->clientConnectionManager
.valid()) {
118 const Ssl::BumpMode currentMode
= csd
->sslBumpMode
;
119 if (currentMode
== Ssl::bumpStare
) {
120 debugs(83,5, "default to bumping after staring");
121 return Ssl::bumpBump
;
123 debugs(83,5, "default to splicing after " << currentMode
);
125 debugs(83,3, "default to splicing due to missing info");
128 return Ssl::bumpSplice
;
131 Security::ContextPointer
132 Ssl::PeekingPeerConnector::getTlsContext()
134 return ::Config
.ssl_client
.sslContext
;
138 Ssl::PeekingPeerConnector::initialize(Security::SessionPointer
&serverSession
)
140 if (!Security::PeerConnector::initialize(serverSession
))
143 if (ConnStateData
*csd
= request
->clientConnectionManager
.valid()) {
145 // client connection is required in the case we need to splice
146 // or terminate client and server connections
147 assert(clientConn
!= NULL
);
148 SBuf
*hostName
= NULL
;
150 //Enable Status_request TLS extension, required to bump some clients
151 SSL_set_tlsext_status_type(serverSession
.get(), TLSEXT_STATUSTYPE_ocsp
);
153 const Security::TlsDetails::Pointer details
= csd
->tlsParser
.details
;
154 if (details
&& !details
->serverName
.isEmpty())
155 hostName
= new SBuf(details
->serverName
);
158 // While we are peeking at the certificate, we may not know the server
159 // name that the client will request (after interception or CONNECT)
160 // unless it was the CONNECT request with a user-typed address.
161 const bool isConnectRequest
= !csd
->port
->flags
.isIntercepted();
162 if (!request
->flags
.sslPeek
|| isConnectRequest
)
163 hostName
= new SBuf(request
->url
.host());
167 SSL_set_ex_data(serverSession
.get(), ssl_ex_index_server
, (void*)hostName
);
169 Must(!csd
->serverBump() || csd
->serverBump()->step
<= Ssl::bumpStep2
);
170 if (csd
->sslBumpMode
== Ssl::bumpPeek
|| csd
->sslBumpMode
== Ssl::bumpStare
) {
171 auto clientSession
= fd_table
[clientConn
->fd
].ssl
.get();
173 BIO
*bc
= SSL_get_rbio(clientSession
);
174 Ssl::ClientBio
*cltBio
= static_cast<Ssl::ClientBio
*>(BIO_get_data(bc
));
176 if (details
&& details
->tlsVersion
.protocol
!= AnyP::PROTO_NONE
)
177 applyTlsDetailsToSSL(serverSession
.get(), details
, csd
->sslBumpMode
);
179 BIO
*b
= SSL_get_rbio(serverSession
.get());
180 Ssl::ServerBio
*srvBio
= static_cast<Ssl::ServerBio
*>(BIO_get_data(b
));
182 // inherit client features such as TLS version and SNI
183 srvBio
->setClientFeatures(details
, cltBio
->rBufData());
184 srvBio
->recordInput(true);
185 srvBio
->mode(csd
->sslBumpMode
);
187 // Set client SSL options
188 ::Security::ProxyOutgoingConfig
.updateSessionOptions(serverSession
);
190 const bool redirected
= request
->flags
.redirected
&& ::Config
.onoff
.redir_rewrites_host
;
191 const char *sniServer
= (!hostName
|| redirected
) ?
192 request
->url
.host() :
195 setClientSNI(serverSession
.get(), sniServer
);
198 if (Ssl::ServerBump
*serverBump
= csd
->serverBump()) {
199 serverBump
->attachServerSession(serverSession
);
200 // store peeked cert to check SQUID_X509_V_ERR_CERT_CHANGE
201 if (X509
*peeked_cert
= serverBump
->serverCert
.get()) {
202 X509_up_ref(peeked_cert
);
203 SSL_set_ex_data(serverSession
.get(), ssl_ex_index_ssl_peeked_cert
, peeked_cert
);
212 Ssl::PeekingPeerConnector::noteNegotiationDone(ErrorState
*error
)
214 // Check the list error with
215 if (!request
->clientConnectionManager
.valid() || !fd_table
[serverConnection()->fd
].ssl
)
218 // remember the server certificate from the ErrorDetail object
219 if (Ssl::ServerBump
*serverBump
= request
->clientConnectionManager
->serverBump()) {
220 if (!serverBump
->serverCert
.get()) {
221 // remember the server certificate from the ErrorDetail object
222 if (error
&& error
->detail
&& error
->detail
->peerCert())
223 serverBump
->serverCert
.resetAndLock(error
->detail
->peerCert());
225 handleServerCertificate();
230 // For intercepted connections, set the host name to the server
231 // certificate CN. Otherwise, we just hope that CONNECT is using
232 // a user-entered address (a host name or a user-entered IP).
233 const bool isConnectRequest
= !request
->clientConnectionManager
->port
->flags
.isIntercepted();
234 if (request
->flags
.sslPeek
&& !isConnectRequest
) {
235 if (X509
*srvX509
= serverBump
->serverCert
.get()) {
236 if (const char *name
= Ssl::CommonHostName(srvX509
)) {
237 request
->url
.host(name
);
238 debugs(83, 3, "reset request host: " << name
);
246 serverCertificateVerified();
248 switchToTunnel(request
.getRaw(), clientConn
, serverConn
);
249 tunnelInsteadOfNegotiating();
255 Ssl::PeekingPeerConnector::noteWantWrite()
257 const int fd
= serverConnection()->fd
;
258 Security::SessionPointer
session(fd_table
[fd
].ssl
);
259 BIO
*b
= SSL_get_rbio(session
.get());
260 Ssl::ServerBio
*srvBio
= static_cast<Ssl::ServerBio
*>(BIO_get_data(b
));
262 if ((srvBio
->bumpMode() == Ssl::bumpPeek
|| srvBio
->bumpMode() == Ssl::bumpStare
) && srvBio
->holdWrite()) {
263 debugs(81, 3, "hold write on SSL connection on FD " << fd
);
264 checkForPeekAndSplice();
268 Security::PeerConnector::noteWantWrite();
272 Ssl::PeekingPeerConnector::noteNegotiationError(const int result
, const int ssl_error
, const int ssl_lib_error
)
274 const int fd
= serverConnection()->fd
;
275 Security::SessionPointer
session(fd_table
[fd
].ssl
);
276 BIO
*b
= SSL_get_rbio(session
.get());
277 Ssl::ServerBio
*srvBio
= static_cast<Ssl::ServerBio
*>(BIO_get_data(b
));
279 // In Peek mode, the ClientHello message sent to the server. If the
280 // server resuming a previous (spliced) SSL session with the client,
281 // then probably we are here because local SSL object does not know
282 // anything about the session being resumed.
284 if (srvBio
->bumpMode() == Ssl::bumpPeek
&& (resumingSession
= srvBio
->resumingSession())) {
285 // we currently splice all resumed sessions unconditionally
286 // if (const bool spliceResumed = true) {
287 bypassCertValidator();
288 checkForPeekAndSpliceMatched(Ssl::bumpSplice
);
290 // } // else fall through to find a matching ssl_bump action (with limited info)
293 // If we are in peek-and-splice mode and still we did not write to
294 // server yet, try to see if we should splice.
295 // In this case the connection can be saved.
296 // If the checklist decision is do not splice a new error will
297 // occur in the next SSL_connect call, and we will fail again.
298 // Abort on certificate validation errors to avoid splicing and
300 // Abort if no certificate found probably because of malformed or
301 // unsupported server Hello message (TODO: make configurable).
302 if (!SSL_get_ex_data(session
.get(), ssl_ex_index_ssl_error_detail
) &&
303 (srvBio
->bumpMode() == Ssl::bumpPeek
|| srvBio
->bumpMode() == Ssl::bumpStare
) && srvBio
->holdWrite()) {
304 Security::CertPointer
serverCert(SSL_get_peer_certificate(session
.get()));
306 debugs(81, 3, "Error (" << Security::ErrorString(ssl_lib_error
) << ") but, hold write on SSL connection on FD " << fd
);
307 checkForPeekAndSplice();
312 // else call parent noteNegotiationError to produce an error page
313 Security::PeerConnector::noteNegotiationError(result
, ssl_error
, ssl_lib_error
);
317 Ssl::PeekingPeerConnector::handleServerCertificate()
319 if (serverCertificateHandled
)
322 if (ConnStateData
*csd
= request
->clientConnectionManager
.valid()) {
323 const int fd
= serverConnection()->fd
;
324 Security::SessionPointer
session(fd_table
[fd
].ssl
);
325 Security::CertPointer
serverCert(SSL_get_peer_certificate(session
.get()));
329 serverCertificateHandled
= true;
331 // remember the server certificate for later use
332 if (Ssl::ServerBump
*serverBump
= csd
->serverBump()) {
333 serverBump
->serverCert
= std::move(serverCert
);
339 Ssl::PeekingPeerConnector::serverCertificateVerified()
341 if (ConnStateData
*csd
= request
->clientConnectionManager
.valid()) {
342 Security::CertPointer serverCert
;
343 if(Ssl::ServerBump
*serverBump
= csd
->serverBump())
344 serverCert
.resetAndLock(serverBump
->serverCert
.get());
346 const int fd
= serverConnection()->fd
;
347 Security::SessionPointer
session(fd_table
[fd
].ssl
);
348 serverCert
.resetWithoutLocking(SSL_get_peer_certificate(session
.get()));
351 csd
->resetSslCommonName(Ssl::CommonHostName(serverCert
.get()));
352 debugs(83, 5, "HTTPS server CN: " << csd
->sslCommonName() <<
353 " bumped: " << *serverConnection());
359 Ssl::PeekingPeerConnector::tunnelInsteadOfNegotiating()
361 Must(callback
!= NULL
);
362 CbDialer
*dialer
= dynamic_cast<CbDialer
*>(callback
->getDialer());
364 dialer
->answer().tunneled
= true;
365 debugs(83, 5, "The SSL negotiation with server aborted");