2 * Copyright (C) 1996-2018 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(allow_t 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(allow_t 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(allow_t(ACCESS_ALLOWED
, Ssl::bumpNone
));
62 acl_checklist
->banAction(allow_t(ACCESS_ALLOWED
, Ssl::bumpPeek
));
63 acl_checklist
->banAction(allow_t(ACCESS_ALLOWED
, Ssl::bumpStare
));
64 acl_checklist
->banAction(allow_t(ACCESS_ALLOWED
, Ssl::bumpClientFirst
));
65 acl_checklist
->banAction(allow_t(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(allow_t(ACCESS_ALLOWED
, Ssl::bumpSplice
));
71 if (!srvBio
->canBump())
72 acl_checklist
->banAction(allow_t(ACCESS_ALLOWED
, Ssl::bumpBump
));
73 acl_checklist
->nonBlockingCheck(Ssl::PeekingPeerConnector::cbCheckForPeekAndSpliceDone
, this);
77 Ssl::PeekingPeerConnector::checkForPeekAndSpliceMatched(const Ssl::BumpMode action
)
79 Security::SessionPointer
session(fd_table
[serverConn
->fd
].ssl
);
80 BIO
*b
= SSL_get_rbio(session
.get());
81 Ssl::ServerBio
*srvBio
= static_cast<Ssl::ServerBio
*>(BIO_get_data(b
));
82 debugs(83,5, "Will check for peek and splice on FD " << serverConn
->fd
);
84 Ssl::BumpMode finalAction
= action
;
85 Must(finalAction
== Ssl::bumpSplice
|| finalAction
== Ssl::bumpBump
|| finalAction
== Ssl::bumpTerminate
);
86 // Record final decision
87 if (request
->clientConnectionManager
.valid()) {
88 request
->clientConnectionManager
->sslBumpMode
= finalAction
;
89 request
->clientConnectionManager
->serverBump()->act
.step3
= finalAction
;
91 al
->ssl
.bumpMode
= finalAction
;
93 if (finalAction
== Ssl::bumpTerminate
) {
96 } else if (finalAction
!= Ssl::bumpSplice
) {
97 //Allow write, proceed with the connection
98 srvBio
->holdWrite(false);
99 srvBio
->recordInput(false);
100 debugs(83,5, "Retry the fwdNegotiateSSL on FD " << serverConn
->fd
);
101 Security::PeerConnector::noteWantWrite();
104 // Ssl Negotiation stops here. Last SSL checks for valid certificates
105 // and if done, switch to tunnel mode
106 if (sslFinalized()) {
107 debugs(83,5, "Abort NegotiateSSL on FD " << serverConn
->fd
<< " and splice the connection");
114 Ssl::PeekingPeerConnector::checkForPeekAndSpliceGuess() const
116 if (const ConnStateData
*csd
= request
->clientConnectionManager
.valid()) {
117 const Ssl::BumpMode currentMode
= csd
->sslBumpMode
;
118 if (currentMode
== Ssl::bumpStare
) {
119 debugs(83,5, "default to bumping after staring");
120 return Ssl::bumpBump
;
122 debugs(83,5, "default to splicing after " << currentMode
);
124 debugs(83,3, "default to splicing due to missing info");
127 return Ssl::bumpSplice
;
130 Security::ContextPointer
131 Ssl::PeekingPeerConnector::getTlsContext()
133 return ::Config
.ssl_client
.sslContext
;
137 Ssl::PeekingPeerConnector::initialize(Security::SessionPointer
&serverSession
)
139 if (!Security::PeerConnector::initialize(serverSession
))
142 if (ConnStateData
*csd
= request
->clientConnectionManager
.valid()) {
144 // client connection is required in the case we need to splice
145 // or terminate client and server connections
146 assert(clientConn
!= NULL
);
147 SBuf
*hostName
= NULL
;
149 //Enable Status_request TLS extension, required to bump some clients
150 SSL_set_tlsext_status_type(serverSession
.get(), TLSEXT_STATUSTYPE_ocsp
);
152 const Security::TlsDetails::Pointer details
= csd
->tlsParser
.details
;
153 if (details
&& !details
->serverName
.isEmpty())
154 hostName
= new SBuf(details
->serverName
);
157 // While we are peeking at the certificate, we may not know the server
158 // name that the client will request (after interception or CONNECT)
159 // unless it was the CONNECT request with a user-typed address.
160 const bool isConnectRequest
= !csd
->port
->flags
.isIntercepted();
161 if (!request
->flags
.sslPeek
|| isConnectRequest
)
162 hostName
= new SBuf(request
->url
.host());
166 SSL_set_ex_data(serverSession
.get(), ssl_ex_index_server
, (void*)hostName
);
168 Must(!csd
->serverBump() || csd
->serverBump()->step
<= Ssl::bumpStep2
);
169 if (csd
->sslBumpMode
== Ssl::bumpPeek
|| csd
->sslBumpMode
== Ssl::bumpStare
) {
170 auto clientSession
= fd_table
[clientConn
->fd
].ssl
.get();
172 BIO
*bc
= SSL_get_rbio(clientSession
);
173 Ssl::ClientBio
*cltBio
= static_cast<Ssl::ClientBio
*>(BIO_get_data(bc
));
175 if (details
&& details
->tlsVersion
.protocol
!= AnyP::PROTO_NONE
)
176 applyTlsDetailsToSSL(serverSession
.get(), details
, csd
->sslBumpMode
);
178 BIO
*b
= SSL_get_rbio(serverSession
.get());
179 Ssl::ServerBio
*srvBio
= static_cast<Ssl::ServerBio
*>(BIO_get_data(b
));
181 // inherit client features such as TLS version and SNI
182 srvBio
->setClientFeatures(details
, cltBio
->rBufData());
183 srvBio
->recordInput(true);
184 srvBio
->mode(csd
->sslBumpMode
);
186 // Set client SSL options
187 SSL_set_options(serverSession
.get(), ::Security::ProxyOutgoingConfig
.parsedOptions
);
189 // Use SNI TLS extension only when we connect directly
190 // to the origin server and we know the server host name.
191 const char *sniServer
= NULL
;
192 const bool redirected
= request
->flags
.redirected
&& ::Config
.onoff
.redir_rewrites_host
;
193 if (!hostName
|| redirected
)
194 sniServer
= !request
->url
.hostIsNumeric() ? request
->url
.host() : NULL
;
196 sniServer
= hostName
->c_str();
199 Ssl::setClientSNI(serverSession
.get(), sniServer
);
202 if (Ssl::ServerBump
*serverBump
= csd
->serverBump()) {
203 serverBump
->attachServerSession(serverSession
);
204 // store peeked cert to check SQUID_X509_V_ERR_CERT_CHANGE
205 if (X509
*peeked_cert
= serverBump
->serverCert
.get()) {
206 X509_up_ref(peeked_cert
);
207 SSL_set_ex_data(serverSession
.get(), ssl_ex_index_ssl_peeked_cert
, peeked_cert
);
216 Ssl::PeekingPeerConnector::noteNegotiationDone(ErrorState
*error
)
218 // Check the list error with
219 if (!request
->clientConnectionManager
.valid() || !fd_table
[serverConnection()->fd
].ssl
)
222 // remember the server certificate from the ErrorDetail object
223 if (Ssl::ServerBump
*serverBump
= request
->clientConnectionManager
->serverBump()) {
224 if (!serverBump
->serverCert
.get()) {
225 // remember the server certificate from the ErrorDetail object
226 if (error
&& error
->detail
&& error
->detail
->peerCert())
227 serverBump
->serverCert
.resetAndLock(error
->detail
->peerCert());
229 handleServerCertificate();
234 // For intercepted connections, set the host name to the server
235 // certificate CN. Otherwise, we just hope that CONNECT is using
236 // a user-entered address (a host name or a user-entered IP).
237 const bool isConnectRequest
= !request
->clientConnectionManager
->port
->flags
.isIntercepted();
238 if (request
->flags
.sslPeek
&& !isConnectRequest
) {
239 if (X509
*srvX509
= serverBump
->serverCert
.get()) {
240 if (const char *name
= Ssl::CommonHostName(srvX509
)) {
241 request
->url
.host(name
);
242 debugs(83, 3, "reset request host: " << name
);
250 serverCertificateVerified();
252 switchToTunnel(request
.getRaw(), clientConn
, serverConn
);
253 tunnelInsteadOfNegotiating();
259 Ssl::PeekingPeerConnector::noteWantWrite()
261 const int fd
= serverConnection()->fd
;
262 Security::SessionPointer
session(fd_table
[fd
].ssl
);
263 BIO
*b
= SSL_get_rbio(session
.get());
264 Ssl::ServerBio
*srvBio
= static_cast<Ssl::ServerBio
*>(BIO_get_data(b
));
266 if ((srvBio
->bumpMode() == Ssl::bumpPeek
|| srvBio
->bumpMode() == Ssl::bumpStare
) && srvBio
->holdWrite()) {
267 debugs(81, 3, "hold write on SSL connection on FD " << fd
);
268 checkForPeekAndSplice();
272 Security::PeerConnector::noteWantWrite();
276 Ssl::PeekingPeerConnector::noteNegotiationError(const int result
, const int ssl_error
, const int ssl_lib_error
)
278 const int fd
= serverConnection()->fd
;
279 Security::SessionPointer
session(fd_table
[fd
].ssl
);
280 BIO
*b
= SSL_get_rbio(session
.get());
281 Ssl::ServerBio
*srvBio
= static_cast<Ssl::ServerBio
*>(BIO_get_data(b
));
283 // In Peek mode, the ClientHello message sent to the server. If the
284 // server resuming a previous (spliced) SSL session with the client,
285 // then probably we are here because local SSL object does not know
286 // anything about the session being resumed.
288 if (srvBio
->bumpMode() == Ssl::bumpPeek
&& (resumingSession
= srvBio
->resumingSession())) {
289 // we currently splice all resumed sessions unconditionally
290 if (const bool spliceResumed
= true) {
291 bypassCertValidator();
292 checkForPeekAndSpliceMatched(Ssl::bumpSplice
);
294 } // else fall through to find a matching ssl_bump action (with limited info)
297 // If we are in peek-and-splice mode and still we did not write to
298 // server yet, try to see if we should splice.
299 // In this case the connection can be saved.
300 // If the checklist decision is do not splice a new error will
301 // occur in the next SSL_connect call, and we will fail again.
302 // Abort on certificate validation errors to avoid splicing and
304 // Abort if no certificate found probably because of malformed or
305 // unsupported server Hello message (TODO: make configurable).
306 if (!SSL_get_ex_data(session
.get(), ssl_ex_index_ssl_error_detail
) &&
307 (srvBio
->bumpMode() == Ssl::bumpPeek
|| srvBio
->bumpMode() == Ssl::bumpStare
) && srvBio
->holdWrite()) {
308 Security::CertPointer
serverCert(SSL_get_peer_certificate(session
.get()));
310 debugs(81, 3, "Error (" << Security::ErrorString(ssl_lib_error
) << ") but, hold write on SSL connection on FD " << fd
);
311 checkForPeekAndSplice();
316 // else call parent noteNegotiationError to produce an error page
317 Security::PeerConnector::noteNegotiationError(result
, ssl_error
, ssl_lib_error
);
321 Ssl::PeekingPeerConnector::handleServerCertificate()
323 if (serverCertificateHandled
)
326 if (ConnStateData
*csd
= request
->clientConnectionManager
.valid()) {
327 const int fd
= serverConnection()->fd
;
328 Security::SessionPointer
session(fd_table
[fd
].ssl
);
329 Security::CertPointer
serverCert(SSL_get_peer_certificate(session
.get()));
333 serverCertificateHandled
= true;
335 // remember the server certificate for later use
336 if (Ssl::ServerBump
*serverBump
= csd
->serverBump()) {
337 serverBump
->serverCert
= std::move(serverCert
);
343 Ssl::PeekingPeerConnector::serverCertificateVerified()
345 if (ConnStateData
*csd
= request
->clientConnectionManager
.valid()) {
346 Security::CertPointer serverCert
;
347 if(Ssl::ServerBump
*serverBump
= csd
->serverBump())
348 serverCert
.resetAndLock(serverBump
->serverCert
.get());
350 const int fd
= serverConnection()->fd
;
351 Security::SessionPointer
session(fd_table
[fd
].ssl
);
352 serverCert
.resetWithoutLocking(SSL_get_peer_certificate(session
.get()));
355 csd
->resetSslCommonName(Ssl::CommonHostName(serverCert
.get()));
356 debugs(83, 5, "HTTPS server CN: " << csd
->sslCommonName() <<
357 " bumped: " << *serverConnection());
363 Ssl::PeekingPeerConnector::tunnelInsteadOfNegotiating()
365 Must(callback
!= NULL
);
366 CbDialer
*dialer
= dynamic_cast<CbDialer
*>(callback
->getDialer());
368 dialer
->answer().tunneled
= true;
369 debugs(83, 5, "The SSL negotiation with server aborted");