2 * Copyright (C) 1996-2016 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
.code
== ACCESS_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
;
92 if (finalAction
== Ssl::bumpTerminate
) {
95 } else if (finalAction
!= Ssl::bumpSplice
) {
96 //Allow write, proceed with the connection
97 srvBio
->holdWrite(false);
98 srvBio
->recordInput(false);
99 debugs(83,5, "Retry the fwdNegotiateSSL on FD " << serverConn
->fd
);
100 Security::PeerConnector::noteWantWrite();
103 // Ssl Negotiation stops here. Last SSL checks for valid certificates
104 // and if done, switch to tunnel mode
105 if (sslFinalized()) {
106 debugs(83,5, "Abort NegotiateSSL on FD " << serverConn
->fd
<< " and splice the connection");
113 Ssl::PeekingPeerConnector::checkForPeekAndSpliceGuess() const
115 if (const ConnStateData
*csd
= request
->clientConnectionManager
.valid()) {
116 const Ssl::BumpMode currentMode
= csd
->sslBumpMode
;
117 if (currentMode
== Ssl::bumpStare
) {
118 debugs(83,5, "default to bumping after staring");
119 return Ssl::bumpBump
;
121 debugs(83,5, "default to splicing after " << currentMode
);
123 debugs(83,3, "default to splicing due to missing info");
126 return Ssl::bumpSplice
;
129 Security::ContextPointer
130 Ssl::PeekingPeerConnector::getTlsContext()
132 return ::Config
.ssl_client
.sslContext
;
136 Ssl::PeekingPeerConnector::initialize(Security::SessionPointer
&serverSession
)
138 if (!Security::PeerConnector::initialize(serverSession
))
141 if (ConnStateData
*csd
= request
->clientConnectionManager
.valid()) {
143 // client connection is required in the case we need to splice
144 // or terminate client and server connections
145 assert(clientConn
!= NULL
);
146 SBuf
*hostName
= NULL
;
148 //Enable Status_request TLS extension, required to bump some clients
149 SSL_set_tlsext_status_type(serverSession
.get(), TLSEXT_STATUSTYPE_ocsp
);
151 const Security::TlsDetails::Pointer details
= csd
->tlsParser
.details
;
152 if (details
&& !details
->serverName
.isEmpty())
153 hostName
= new SBuf(details
->serverName
);
156 // While we are peeking at the certificate, we may not know the server
157 // name that the client will request (after interception or CONNECT)
158 // unless it was the CONNECT request with a user-typed address.
159 const bool isConnectRequest
= !csd
->port
->flags
.isIntercepted();
160 if (!request
->flags
.sslPeek
|| isConnectRequest
)
161 hostName
= new SBuf(request
->url
.host());
165 SSL_set_ex_data(serverSession
.get(), ssl_ex_index_server
, (void*)hostName
);
167 Must(!csd
->serverBump() || csd
->serverBump()->step
<= Ssl::bumpStep2
);
168 if (csd
->sslBumpMode
== Ssl::bumpPeek
|| csd
->sslBumpMode
== Ssl::bumpStare
) {
169 auto clientSession
= fd_table
[clientConn
->fd
].ssl
.get();
171 BIO
*bc
= SSL_get_rbio(clientSession
);
172 Ssl::ClientBio
*cltBio
= static_cast<Ssl::ClientBio
*>(BIO_get_data(bc
));
174 if (details
&& details
->tlsVersion
.protocol
!= AnyP::PROTO_NONE
) {
175 applyTlsDetailsToSSL(serverSession
.get(), details
, csd
->sslBumpMode
);
176 // Should we allow it for all protocols?
177 if (details
->tlsVersion
.protocol
== AnyP::PROTO_TLS
|| details
->tlsVersion
== AnyP::ProtocolVersion(AnyP::PROTO_SSL
, 3, 0)) {
178 BIO
*b
= SSL_get_rbio(serverSession
.get());
179 Ssl::ServerBio
*srvBio
= static_cast<Ssl::ServerBio
*>(BIO_get_data(b
));
180 // Inherite client features, like SSL version, SNI and other
181 srvBio
->setClientFeatures(details
, cltBio
->rBufData());
182 srvBio
->recordInput(true);
183 srvBio
->mode(csd
->sslBumpMode
);
187 // Set client SSL options
188 SSL_set_options(serverSession
.get(), ::Security::ProxyOutgoingConfig
.parsedOptions
);
190 // Use SNI TLS extension only when we connect directly
191 // to the origin server and we know the server host name.
192 const char *sniServer
= NULL
;
193 const bool redirected
= request
->flags
.redirected
&& ::Config
.onoff
.redir_rewrites_host
;
194 if (!hostName
|| redirected
)
195 sniServer
= !request
->url
.hostIsNumeric() ? request
->url
.host() : NULL
;
197 sniServer
= hostName
->c_str();
200 Ssl::setClientSNI(serverSession
.get(), sniServer
);
203 if (Ssl::ServerBump
*serverBump
= csd
->serverBump()) {
204 serverBump
->attachServerSession(serverSession
);
205 // store peeked cert to check SQUID_X509_V_ERR_CERT_CHANGE
206 if (X509
*peeked_cert
= serverBump
->serverCert
.get()) {
207 X509_up_ref(peeked_cert
);
208 SSL_set_ex_data(serverSession
.get(), ssl_ex_index_ssl_peeked_cert
, peeked_cert
);
217 Ssl::PeekingPeerConnector::noteNegotiationDone(ErrorState
*error
)
219 // Check the list error with
220 if (!request
->clientConnectionManager
.valid() || !fd_table
[serverConnection()->fd
].ssl
)
223 // remember the server certificate from the ErrorDetail object
224 if (Ssl::ServerBump
*serverBump
= request
->clientConnectionManager
->serverBump()) {
225 if (!serverBump
->serverCert
.get()) {
226 // remember the server certificate from the ErrorDetail object
227 if (error
&& error
->detail
&& error
->detail
->peerCert())
228 serverBump
->serverCert
.resetAndLock(error
->detail
->peerCert());
230 handleServerCertificate();
235 // For intercepted connections, set the host name to the server
236 // certificate CN. Otherwise, we just hope that CONNECT is using
237 // a user-entered address (a host name or a user-entered IP).
238 const bool isConnectRequest
= !request
->clientConnectionManager
->port
->flags
.isIntercepted();
239 if (request
->flags
.sslPeek
&& !isConnectRequest
) {
240 if (X509
*srvX509
= serverBump
->serverCert
.get()) {
241 if (const char *name
= Ssl::CommonHostName(srvX509
)) {
242 request
->url
.host(name
);
243 debugs(83, 3, "reset request host: " << name
);
251 serverCertificateVerified();
253 switchToTunnel(request
.getRaw(), clientConn
, serverConn
);
254 tunnelInsteadOfNegotiating();
260 Ssl::PeekingPeerConnector::noteWantWrite()
262 const int fd
= serverConnection()->fd
;
263 Security::SessionPointer
session(fd_table
[fd
].ssl
);
264 BIO
*b
= SSL_get_rbio(session
.get());
265 Ssl::ServerBio
*srvBio
= static_cast<Ssl::ServerBio
*>(BIO_get_data(b
));
267 if ((srvBio
->bumpMode() == Ssl::bumpPeek
|| srvBio
->bumpMode() == Ssl::bumpStare
) && srvBio
->holdWrite()) {
268 debugs(81, 3, "hold write on SSL connection on FD " << fd
);
269 checkForPeekAndSplice();
273 Security::PeerConnector::noteWantWrite();
277 Ssl::PeekingPeerConnector::noteNegotiationError(const int result
, const int ssl_error
, const int ssl_lib_error
)
279 const int fd
= serverConnection()->fd
;
280 Security::SessionPointer
session(fd_table
[fd
].ssl
);
281 BIO
*b
= SSL_get_rbio(session
.get());
282 Ssl::ServerBio
*srvBio
= static_cast<Ssl::ServerBio
*>(BIO_get_data(b
));
284 // In Peek mode, the ClientHello message sent to the server. If the
285 // server resuming a previous (spliced) SSL session with the client,
286 // then probably we are here because local SSL object does not know
287 // anything about the session being resumed.
289 if (srvBio
->bumpMode() == Ssl::bumpPeek
&& (resumingSession
= srvBio
->resumingSession())) {
290 // we currently splice all resumed sessions unconditionally
291 if (const bool spliceResumed
= true) {
292 bypassCertValidator();
293 checkForPeekAndSpliceMatched(Ssl::bumpSplice
);
295 } // else fall through to find a matching ssl_bump action (with limited info)
298 // If we are in peek-and-splice mode and still we did not write to
299 // server yet, try to see if we should splice.
300 // In this case the connection can be saved.
301 // If the checklist decision is do not splice a new error will
302 // occur in the next SSL_connect call, and we will fail again.
303 // Abort on certificate validation errors to avoid splicing and
305 // Abort if no certificate found probably because of malformed or
306 // unsupported server Hello message (TODO: make configurable).
307 if (!SSL_get_ex_data(session
.get(), ssl_ex_index_ssl_error_detail
) &&
308 (srvBio
->bumpMode() == Ssl::bumpPeek
|| srvBio
->bumpMode() == Ssl::bumpStare
) && srvBio
->holdWrite()) {
309 Security::CertPointer
serverCert(SSL_get_peer_certificate(session
.get()));
311 debugs(81, 3, "Error (" << Security::ErrorString(ssl_lib_error
) << ") but, hold write on SSL connection on FD " << fd
);
312 checkForPeekAndSplice();
317 // else call parent noteNegotiationError to produce an error page
318 Security::PeerConnector::noteNegotiationError(result
, ssl_error
, ssl_lib_error
);
322 Ssl::PeekingPeerConnector::handleServerCertificate()
324 if (serverCertificateHandled
)
327 if (ConnStateData
*csd
= request
->clientConnectionManager
.valid()) {
328 const int fd
= serverConnection()->fd
;
329 Security::SessionPointer
session(fd_table
[fd
].ssl
);
330 Security::CertPointer
serverCert(SSL_get_peer_certificate(session
.get()));
334 serverCertificateHandled
= true;
336 // remember the server certificate for later use
337 if (Ssl::ServerBump
*serverBump
= csd
->serverBump()) {
338 serverBump
->serverCert
= std::move(serverCert
);
344 Ssl::PeekingPeerConnector::serverCertificateVerified()
346 if (ConnStateData
*csd
= request
->clientConnectionManager
.valid()) {
347 Security::CertPointer serverCert
;
348 if(Ssl::ServerBump
*serverBump
= csd
->serverBump())
349 serverCert
.resetAndLock(serverBump
->serverCert
.get());
351 const int fd
= serverConnection()->fd
;
352 Security::SessionPointer
session(fd_table
[fd
].ssl
);
353 serverCert
.resetWithoutLocking(SSL_get_peer_certificate(session
.get()));
356 csd
->resetSslCommonName(Ssl::CommonHostName(serverCert
.get()));
357 debugs(83, 5, "HTTPS server CN: " << csd
->sslCommonName() <<
358 " bumped: " << *serverConnection());
364 Ssl::PeekingPeerConnector::tunnelInsteadOfNegotiating()
366 Must(callback
!= NULL
);
367 CbDialer
*dialer
= dynamic_cast<CbDialer
*>(callback
->getDialer());
369 dialer
->answer().tunneled
= true;
370 debugs(83, 5, "The SSL negotiation with server aborted");