]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ssl/PeerConnector.cc
Fix printf format for size_t and mb_size_t
[thirdparty/squid.git] / src / ssl / PeerConnector.cc
CommitLineData
a23223bf 1/*
bde978a6 2 * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
a23223bf 3 *
bbc27441
AJ
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.
a23223bf
CT
7 */
8
bbc27441
AJ
9/* DEBUG: section 17 Request Forwarding */
10
a23223bf
CT
11#include "squid.h"
12#include "acl/FilledChecklist.h"
13#include "base/AsyncCbdataCalls.h"
14#include "CachePeer.h"
15#include "client_side.h"
16#include "comm/Loops.h"
17#include "errorpage.h"
18#include "fde.h"
19#include "globals.h"
24438ec5 20#include "helper/ResultCode.h"
a23223bf
CT
21#include "HttpRequest.h"
22#include "neighbors.h"
7f4e9b73 23#include "SquidConfig.h"
31855516 24#include "ssl/bio.h"
a23223bf
CT
25#include "ssl/cert_validate_message.h"
26#include "ssl/Config.h"
27#include "ssl/ErrorDetail.h"
28#include "ssl/helper.h"
29#include "ssl/PeerConnector.h"
30#include "ssl/ServerBump.h"
31#include "ssl/support.h"
a23223bf
CT
32
33CBDATA_NAMESPACED_CLASS_INIT(Ssl, PeerConnector);
34
35Ssl::PeerConnector::PeerConnector(
36 HttpRequestPointer &aRequest,
37 const Comm::ConnectionPointer &aServerConn,
93ead3fd 38 const Comm::ConnectionPointer &aClientConn,
8aec3e1b
CT
39 AsyncCall::Pointer &aCallback,
40 const time_t timeout):
f53969cc
SM
41 AsyncJob("Ssl::PeerConnector"),
42 request(aRequest),
43 serverConn(aServerConn),
44 clientConn(aClientConn),
45 callback(aCallback),
46 negotiationTimeout(timeout),
47 startTime(squid_curtime),
69f69080 48 splice(false),
89c5ca0f 49 resumingSession(false),
69f69080 50 serverCertificateHandled(false)
a23223bf
CT
51{
52 // if this throws, the caller's cb dialer is not our CbDialer
53 Must(dynamic_cast<CbDialer*>(callback->getDialer()));
54}
55
56Ssl::PeerConnector::~PeerConnector()
57{
58 debugs(83, 5, "Peer connector " << this << " gone");
59}
60
61bool Ssl::PeerConnector::doneAll() const
62{
63 return (!callback || callback->canceled()) && AsyncJob::doneAll();
64}
65
66/// Preps connection and SSL state. Calls negotiate().
67void
68Ssl::PeerConnector::start()
69{
70 AsyncJob::start();
71
72 if (prepareSocket()) {
73 initializeSsl();
74 negotiateSsl();
75 }
76}
77
78void
79Ssl::PeerConnector::commCloseHandler(const CommCloseCbParams &params)
80{
81 debugs(83, 5, "FD " << params.fd << ", Ssl::PeerConnector=" << params.data);
82 connectionClosed("Ssl::PeerConnector::commCloseHandler");
83}
84
85void
86Ssl::PeerConnector::connectionClosed(const char *reason)
87{
88 mustStop(reason);
89 callback = NULL;
90}
91
92bool
93Ssl::PeerConnector::prepareSocket()
94{
95 const int fd = serverConnection()->fd;
96 if (!Comm::IsConnOpen(serverConn) || fd_table[serverConn->fd].closing()) {
97 connectionClosed("Ssl::PeerConnector::prepareSocket");
98 return false;
99 }
100
101 // watch for external connection closures
102 typedef CommCbMemFunT<Ssl::PeerConnector, CommCloseCbParams> Dialer;
103 closeHandler = JobCallback(9, 5, Dialer, this, Ssl::PeerConnector::commCloseHandler);
104 comm_add_close_handler(fd, closeHandler);
105 return true;
106}
107
108void
109Ssl::PeerConnector::initializeSsl()
110{
a23223bf
CT
111 SSL_CTX *sslContext = NULL;
112 const CachePeer *peer = serverConnection()->getPeer();
113 const int fd = serverConnection()->fd;
114
115 if (peer) {
1f1f29e8 116 assert(peer->secure.encryptTransport);
a23223bf
CT
117 sslContext = peer->sslContext;
118 } else {
52655c4f 119 // XXX: locate a per-server context in Security:: instead
a23223bf
CT
120 sslContext = ::Config.ssl_client.sslContext;
121 }
122
123 assert(sslContext);
124
31855516
CT
125 SSL *ssl = Ssl::CreateClient(sslContext, fd, "server https start");
126 if (!ssl) {
a23223bf
CT
127 ErrorState *anErr = new ErrorState(ERR_SOCKET_FAILURE, Http::scInternalServerError, request.getRaw());
128 anErr->xerrno = errno;
129 debugs(83, DBG_IMPORTANT, "Error allocating SSL handle: " << ERR_error_string(ERR_get_error(), NULL));
130 bail(anErr);
131 return;
132 }
133
a23223bf 134 if (peer) {
1f1f29e8
AJ
135 // NP: domain may be a raw-IP but it is now always set
136 assert(!peer->secure.sslDomain.isEmpty());
137
138 // const loss is okay here, ssl_ex_index_server is only read and not assigned a destructor
68920ad8
CT
139 SBuf *host = new SBuf(peer->secure.sslDomain);
140 SSL_set_ex_data(ssl, ssl_ex_index_server, host);
a23223bf
CT
141
142 if (peer->sslSession)
143 SSL_set_session(ssl, peer->sslSession);
f233022a 144 } else if (ConnStateData *csd = request->clientConnectionManager.valid()) {
76b64c80 145 // client connection is required in the case we need to splice
20b79af2
CT
146 // or terminate client and server connections
147 assert(clientConn != NULL);
68920ad8 148 SBuf *hostName = NULL;
76b64c80
CT
149 Ssl::ClientBio *cltBio = NULL;
150
89c5ca0f
CT
151 //Enable Status_request tls extension, required to bump some clients
152 SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp);
153
76b64c80
CT
154 // In server-first bumping mode, clientSsl is NULL.
155 if (SSL *clientSsl = fd_table[clientConn->fd].ssl) {
156 BIO *b = SSL_get_rbio(clientSsl);
157 cltBio = static_cast<Ssl::ClientBio *>(b->ptr);
158 const Ssl::Bio::sslFeatures &features = cltBio->getFeatures();
159 if (!features.serverName.isEmpty())
68920ad8 160 hostName = new SBuf(features.serverName);
76b64c80 161 }
9db3fdb3 162
76b64c80
CT
163 if (!hostName) {
164 // While we are peeking at the certificate, we may not know the server
165 // name that the client will request (after interception or CONNECT)
166 // unless it was the CONNECT request with a user-typed address.
167 const bool isConnectRequest = !csd->port->flags.isIntercepted();
168 if (!request->flags.sslPeek || isConnectRequest)
68920ad8 169 hostName = new SBuf(request->GetHost());
76b64c80
CT
170 }
171
172 if (hostName)
173 SSL_set_ex_data(ssl, ssl_ex_index_server, (void*)hostName);
174
f233022a 175 Must(!csd->serverBump() || csd->serverBump()->step <= Ssl::bumpStep2);
76b64c80
CT
176 if (csd->sslBumpMode == Ssl::bumpPeek || csd->sslBumpMode == Ssl::bumpStare) {
177 assert(cltBio);
178 const Ssl::Bio::sslFeatures &features = cltBio->getFeatures();
179 if (features.sslVersion != -1) {
89c5ca0f 180 features.applyToSSL(ssl, csd->sslBumpMode);
76b64c80
CT
181 // Should we allow it for all protocols?
182 if (features.sslVersion >= 3) {
183 BIO *b = SSL_get_rbio(ssl);
184 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
185 // Inherite client features, like SSL version, SNI and other
186 srvBio->setClientFeatures(features);
187 srvBio->recordInput(true);
188 srvBio->mode(csd->sslBumpMode);
189 }
190 }
191 } else {
f233022a 192 // Set client SSL options
36092741 193 SSL_set_options(ssl, ::Security::ProxyOutgoingConfig.parsedOptions);
f233022a 194
76b64c80
CT
195 // Use SNI TLS extension only when we connect directly
196 // to the origin server and we know the server host name.
68920ad8 197 const char *sniServer = hostName ? hostName->c_str() :
76b64c80
CT
198 (!request->GetHostIsNumeric() ? request->GetHost() : NULL);
199 if (sniServer)
200 Ssl::setClientSNI(ssl, sniServer);
31855516 201 }
a23223bf
CT
202 }
203
204 // If CertValidation Helper used do not lookup checklist for errors,
205 // but keep a list of errors to send it to CertValidator
206 if (!Ssl::TheConfig.ssl_crt_validator) {
207 // Create the ACL check list now, while we have access to more info.
208 // The list is used in ssl_verify_cb() and is freed in ssl_free().
209 if (acl_access *acl = ::Config.ssl_client.cert_error) {
210 ACLFilledChecklist *check = new ACLFilledChecklist(acl, request.getRaw(), dash_str);
211 // check->fd(fd); XXX: need client FD here
212 SSL_set_ex_data(ssl, ssl_ex_index_cert_error_check, check);
213 }
214 }
215
216 // store peeked cert to check SQUID_X509_V_ERR_CERT_CHANGE
217 X509 *peeked_cert;
218 if (request->clientConnectionManager.valid() &&
219 request->clientConnectionManager->serverBump() &&
220 (peeked_cert = request->clientConnectionManager->serverBump()->serverCert.get())) {
221 CRYPTO_add(&(peeked_cert->references),1,CRYPTO_LOCK_X509);
222 SSL_set_ex_data(ssl, ssl_ex_index_ssl_peeked_cert, peeked_cert);
223 }
a23223bf
CT
224}
225
8aec3e1b
CT
226void
227Ssl::PeerConnector::setReadTimeout()
228{
229 int timeToRead;
230 if (negotiationTimeout) {
231 const int timeUsed = squid_curtime - startTime;
232 const int timeLeft = max(0, static_cast<int>(negotiationTimeout - timeUsed));
233 timeToRead = min(static_cast<int>(::Config.Timeout.read), timeLeft);
234 } else
235 timeToRead = ::Config.Timeout.read;
236 AsyncCall::Pointer nil;
237 commSetConnTimeout(serverConnection(), timeToRead, nil);
238}
239
a23223bf
CT
240void
241Ssl::PeerConnector::negotiateSsl()
242{
243 if (!Comm::IsConnOpen(serverConnection()) || fd_table[serverConnection()->fd].closing())
244 return;
245
246 const int fd = serverConnection()->fd;
247 SSL *ssl = fd_table[fd].ssl;
248 const int result = SSL_connect(ssl);
249 if (result <= 0) {
250 handleNegotiateError(result);
251 return; // we might be gone by now
252 }
253
c91d4d4e
CT
254 if (serverConnection()->getPeer() && !SSL_session_reused(ssl)) {
255 if (serverConnection()->getPeer()->sslSession)
256 SSL_SESSION_free(serverConnection()->getPeer()->sslSession);
257
258 serverConnection()->getPeer()->sslSession = SSL_get1_session(ssl);
259 }
260
261 if (!sslFinalized())
262 return;
263
264 callBack();
265}
266
69f69080
CT
267void
268Ssl::PeerConnector::handleServerCertificate()
269{
270 if (serverCertificateHandled)
271 return;
272
273 if (ConnStateData *csd = request->clientConnectionManager.valid()) {
274 const int fd = serverConnection()->fd;
275 SSL *ssl = fd_table[fd].ssl;
276 Ssl::X509_Pointer serverCert(SSL_get_peer_certificate(ssl));
277 if (!serverCert.get())
278 return;
279
280 serverCertificateHandled = true;
281
282 csd->resetSslCommonName(Ssl::CommonHostName(serverCert.get()));
283 debugs(83, 5, "HTTPS server CN: " << csd->sslCommonName() <<
284 " bumped: " << *serverConnection());
285
286 // remember the server certificate for later use
287 if (Ssl::ServerBump *serverBump = csd->serverBump()) {
8823b1c9 288 serverBump->serverCert.reset(serverCert.release());
69f69080
CT
289 }
290 }
291}
292
c91d4d4e
CT
293bool
294Ssl::PeerConnector::sslFinalized()
295{
296 const int fd = serverConnection()->fd;
297 SSL *ssl = fd_table[fd].ssl;
298
89c5ca0f
CT
299 // In the case the session is resuming, the certificates does not exist and
300 // we did not do any cert validation
301 if (resumingSession)
302 return true;
303
69f69080 304 handleServerCertificate();
a23223bf 305
69f69080
CT
306 if (ConnStateData *csd = request->clientConnectionManager.valid()) {
307 if (Ssl::ServerBump *serverBump = csd->serverBump()) {
a23223bf
CT
308 // remember validation errors, if any
309 if (Ssl::CertErrors *errs = static_cast<Ssl::CertErrors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors)))
310 serverBump->sslErrors = cbdataReference(errs);
311 }
312 }
313
a23223bf
CT
314 if (Ssl::TheConfig.ssl_crt_validator) {
315 Ssl::CertValidationRequest validationRequest;
316 // WARNING: Currently we do not use any locking for any of the
317 // members of the Ssl::CertValidationRequest class. In this code the
318 // Ssl::CertValidationRequest object used only to pass data to
319 // Ssl::CertValidationHelper::submit method.
320 validationRequest.ssl = ssl;
321 validationRequest.domainName = request->GetHost();
322 if (Ssl::CertErrors *errs = static_cast<Ssl::CertErrors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors)))
323 // validationRequest disappears on return so no need to cbdataReference
324 validationRequest.errors = errs;
325 else
326 validationRequest.errors = NULL;
327 try {
328 debugs(83, 5, "Sending SSL certificate for validation to ssl_crtvd.");
329 Ssl::CertValidationHelper::GetInstance()->sslSubmit(validationRequest, sslCrtvdHandleReplyWrapper, this);
c91d4d4e 330 return false;
a23223bf
CT
331 } catch (const std::exception &e) {
332 debugs(83, DBG_IMPORTANT, "ERROR: Failed to compose ssl_crtvd " <<
333 "request for " << validationRequest.domainName <<
334 " certificate: " << e.what() << "; will now block to " <<
335 "validate that certificate.");
336 // fall through to do blocking in-process generation.
337 ErrorState *anErr = new ErrorState(ERR_GATEWAY_FAILURE, Http::scInternalServerError, request.getRaw());
338 bail(anErr);
339 if (serverConnection()->getPeer()) {
340 peerConnectFailed(serverConnection()->getPeer());
341 }
342 serverConn->close();
c91d4d4e 343 return true;
a23223bf
CT
344 }
345 }
c91d4d4e 346 return true;
a23223bf
CT
347}
348
c91d4d4e 349void switchToTunnel(HttpRequest *request, Comm::ConnectionPointer & clientConn, Comm::ConnectionPointer &srvConn);
7f4e9b73 350
31855516 351void
a9c2dd2f 352Ssl::PeerConnector::cbCheckForPeekAndSpliceDone(allow_t answer, void *data)
7f4e9b73
CT
353{
354 Ssl::PeerConnector *peerConnect = (Ssl::PeerConnector *) data;
a9c2dd2f 355 peerConnect->checkForPeekAndSpliceDone((Ssl::BumpMode)answer.kind);
7f4e9b73
CT
356}
357
a9c2dd2f
CT
358void
359Ssl::PeerConnector::checkForPeekAndSplice()
31855516 360{
5d65362c
CT
361 // Mark Step3 of bumping
362 if (request->clientConnectionManager.valid()) {
363 if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
364 serverBump->step = Ssl::bumpStep3;
365 }
366 }
367
69f69080
CT
368 handleServerCertificate();
369
a9c2dd2f
CT
370 ACLFilledChecklist *acl_checklist = new ACLFilledChecklist(
371 ::Config.accessList.ssl_bump,
372 request.getRaw(), NULL);
373 acl_checklist->nonBlockingCheck(Ssl::PeerConnector::cbCheckForPeekAndSpliceDone, this);
374}
789dda8d 375
a9c2dd2f
CT
376void
377Ssl::PeerConnector::checkForPeekAndSpliceDone(Ssl::BumpMode const action)
378{
379 SSL *ssl = fd_table[serverConn->fd].ssl;
31855516
CT
380 BIO *b = SSL_get_rbio(ssl);
381 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
8693472e 382 debugs(83,5, "Will check for peek and splice on FD " << serverConn->fd);
7f4e9b73 383
a9c2dd2f
CT
384 Ssl::BumpMode finalAction = action;
385 // adjust the final bumping mode if needed
386 if (finalAction < Ssl::bumpSplice)
387 finalAction = Ssl::bumpBump;
5d65362c 388
a9c2dd2f
CT
389 if (finalAction == Ssl::bumpSplice && !srvBio->canSplice())
390 finalAction = Ssl::bumpBump;
391 else if (finalAction == Ssl::bumpBump && !srvBio->canBump())
392 finalAction = Ssl::bumpSplice;
5d65362c 393
a9c2dd2f 394 // Record final decision
68bd0182 395 if (request->clientConnectionManager.valid()) {
a9c2dd2f 396 request->clientConnectionManager->sslBumpMode = finalAction;
68bd0182
CT
397 request->clientConnectionManager->serverBump()->act.step3 = finalAction;
398 }
a9c2dd2f
CT
399
400 if (finalAction == Ssl::bumpTerminate) {
5d65362c
CT
401 comm_close(serverConn->fd);
402 comm_close(clientConn->fd);
a9c2dd2f 403 } else if (finalAction != Ssl::bumpSplice) {
31855516
CT
404 //Allow write, proceed with the connection
405 srvBio->holdWrite(false);
406 srvBio->recordInput(false);
407 Comm::SetSelect(serverConn->fd, COMM_SELECT_WRITE, &NegotiateSsl, this, 0);
8693472e 408 debugs(83,5, "Retry the fwdNegotiateSSL on FD " << serverConn->fd);
93ead3fd 409 } else {
c91d4d4e 410 splice = true;
f53969cc 411 // Ssl Negotiation stops here. Last SSL checks for valid certificates
c91d4d4e
CT
412 // and if done, switch to tunnel mode
413 if (sslFinalized())
414 switchToTunnel(request.getRaw(), clientConn, serverConn);
31855516
CT
415 }
416}
417
a23223bf
CT
418void
419Ssl::PeerConnector::sslCrtvdHandleReplyWrapper(void *data, Ssl::CertValidationResponse const &validationResponse)
420{
421 Ssl::PeerConnector *connector = (Ssl::PeerConnector *)(data);
422 connector->sslCrtvdHandleReply(validationResponse);
423}
424
425void
426Ssl::PeerConnector::sslCrtvdHandleReply(Ssl::CertValidationResponse const &validationResponse)
427{
428 Ssl::CertErrors *errs = NULL;
429 Ssl::ErrorDetail *errDetails = NULL;
430 bool validatorFailed = false;
431 if (!Comm::IsConnOpen(serverConnection())) {
432 return;
433 }
434
435 debugs(83,5, request->GetHost() << " cert validation result: " << validationResponse.resultCode);
436
2428ce02 437 if (validationResponse.resultCode == ::Helper::Error)
a23223bf 438 errs = sslCrtvdCheckForErrors(validationResponse, errDetails);
2428ce02 439 else if (validationResponse.resultCode != ::Helper::Okay)
a23223bf
CT
440 validatorFailed = true;
441
442 if (!errDetails && !validatorFailed) {
c91d4d4e
CT
443 if (splice)
444 switchToTunnel(request.getRaw(), clientConn, serverConn);
445 else
446 callBack();
a23223bf
CT
447 return;
448 }
449
450 ErrorState *anErr = NULL;
451 if (validatorFailed) {
452 anErr = new ErrorState(ERR_GATEWAY_FAILURE, Http::scInternalServerError, request.getRaw());
453 } else {
454
455 // Check the list error with
456 if (errDetails && request->clientConnectionManager.valid()) {
457 // remember the server certificate from the ErrorDetail object
458 if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
459 // remember validation errors, if any
460 if (errs) {
461 if (serverBump->sslErrors)
462 cbdataReferenceDone(serverBump->sslErrors);
463 serverBump->sslErrors = cbdataReference(errs);
464 }
465 }
466 }
467
468 anErr = new ErrorState(ERR_SECURE_CONNECT_FAIL, Http::scServiceUnavailable, request.getRaw());
469 anErr->detail = errDetails;
470 /*anErr->xerrno= Should preserved*/
471 }
472
473 bail(anErr);
474 if (serverConnection()->getPeer()) {
475 peerConnectFailed(serverConnection()->getPeer());
476 }
477 serverConn->close();
478 return;
479}
480
481/// Checks errors in the cert. validator response against sslproxy_cert_error.
482/// The first honored error, if any, is returned via errDetails parameter.
483/// The method returns all seen errors except SSL_ERROR_NONE as Ssl::CertErrors.
484Ssl::CertErrors *
485Ssl::PeerConnector::sslCrtvdCheckForErrors(Ssl::CertValidationResponse const &resp, Ssl::ErrorDetail *& errDetails)
486{
487 Ssl::CertErrors *errs = NULL;
488
489 ACLFilledChecklist *check = NULL;
490 if (acl_access *acl = ::Config.ssl_client.cert_error)
491 check = new ACLFilledChecklist(acl, request.getRaw(), dash_str);
492
493 SSL *ssl = fd_table[serverConnection()->fd].ssl;
494 typedef Ssl::CertValidationResponse::RecvdErrors::const_iterator SVCRECI;
495 for (SVCRECI i = resp.errors.begin(); i != resp.errors.end(); ++i) {
496 debugs(83, 7, "Error item: " << i->error_no << " " << i->error_reason);
497
498 assert(i->error_no != SSL_ERROR_NONE);
499
500 if (!errDetails) {
501 bool allowed = false;
502 if (check) {
503 check->sslErrors = new Ssl::CertErrors(Ssl::CertError(i->error_no, i->cert.get()));
504 if (check->fastCheck() == ACCESS_ALLOWED)
505 allowed = true;
506 }
507 // else the Config.ssl_client.cert_error access list is not defined
508 // and the first error will cause the error page
509
510 if (allowed) {
511 debugs(83, 3, "bypassing SSL error " << i->error_no << " in " << "buffer");
512 } else {
513 debugs(83, 5, "confirming SSL error " << i->error_no);
514 X509 *brokenCert = i->cert.get();
515 Ssl::X509_Pointer peerCert(SSL_get_peer_certificate(ssl));
516 const char *aReason = i->error_reason.empty() ? NULL : i->error_reason.c_str();
517 errDetails = new Ssl::ErrorDetail(i->error_no, peerCert.get(), brokenCert, aReason);
518 }
519 if (check) {
520 delete check->sslErrors;
521 check->sslErrors = NULL;
522 }
523 }
524
525 if (!errs)
526 errs = new Ssl::CertErrors(Ssl::CertError(i->error_no, i->cert.get()));
527 else
528 errs->push_back_unique(Ssl::CertError(i->error_no, i->cert.get()));
529 }
530 if (check)
531 delete check;
532
533 return errs;
534}
535
536/// A wrapper for Comm::SetSelect() notifications.
537void
538Ssl::PeerConnector::NegotiateSsl(int, void *data)
539{
540 PeerConnector *pc = static_cast<PeerConnector*>(data);
541 // Use job calls to add done() checks and other job logic/protections.
542 CallJobHere(83, 7, pc, Ssl::PeerConnector, negotiateSsl);
543}
544
545void
546Ssl::PeerConnector::handleNegotiateError(const int ret)
547{
548 const int fd = serverConnection()->fd;
549 unsigned long ssl_lib_error = SSL_ERROR_NONE;
550 SSL *ssl = fd_table[fd].ssl;
551 int ssl_error = SSL_get_error(ssl, ret);
31855516
CT
552 BIO *b = SSL_get_rbio(ssl);
553 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
a23223bf
CT
554
555#ifdef EPROTO
e2849af8 556 int sysErrNo = EPROTO;
a23223bf 557#else
e2849af8 558 int sysErrNo = EACCES;
a23223bf
CT
559#endif
560
e2849af8 561 switch (ssl_error) {
a23223bf 562
e2849af8 563 case SSL_ERROR_WANT_READ:
8aec3e1b 564 setReadTimeout();
e2849af8
A
565 Comm::SetSelect(fd, COMM_SELECT_READ, &NegotiateSsl, this, 0);
566 return;
a23223bf 567
e2849af8 568 case SSL_ERROR_WANT_WRITE:
92d867c5 569 if ((srvBio->bumpMode() == Ssl::bumpPeek || srvBio->bumpMode() == Ssl::bumpStare) && srvBio->holdWrite()) {
20b79af2 570 debugs(81, DBG_IMPORTANT, "hold write on SSL connection on FD " << fd);
a9c2dd2f 571 checkForPeekAndSplice();
a23223bf 572 return;
20b79af2 573 }
e2849af8
A
574 Comm::SetSelect(fd, COMM_SELECT_WRITE, &NegotiateSsl, this, 0);
575 return;
a23223bf 576
e2849af8
A
577 case SSL_ERROR_SSL:
578 case SSL_ERROR_SYSCALL:
579 ssl_lib_error = ERR_get_error();
a23223bf 580
89c5ca0f
CT
581 // In Peek mode, the ClientHello message sent to the server. If the
582 // server resuming a previous (spliced) SSL session with the client,
583 // then probably we are here because local SSL object does not know
584 // anything about the session being resumed.
de47229e 585 //
89c5ca0f
CT
586 if (srvBio->bumpMode() == Ssl::bumpPeek && (resumingSession = srvBio->resumingSession())) {
587 // we currently splice all resumed sessions unconditionally
588 if (const bool spliceResumed = true) {
589 checkForPeekAndSpliceDone(Ssl::bumpSplice);
590 return;
591 } // else fall through to find a matching ssl_bump action (with limited info)
592 }
593
20b79af2
CT
594 // If we are in peek-and-splice mode and still we did not write to
595 // server yet, try to see if we should splice.
596 // In this case the connection can be saved.
597 // If the checklist decision is do not splice a new error will
598 // occure in the next SSL_connect call, and we will fail again.
de97c33d
CT
599 // Abort on certificate validation errors to avoid splicing and
600 // thus hiding them.
601 // Abort if no certificate found probably because of malformed or
602 // unsupported server Hello message (TODO: make configurable).
7f4e9b73 603#if 1
de97c33d 604 if (!SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_detail) &&
92d867c5 605 (srvBio->bumpMode() == Ssl::bumpPeek || srvBio->bumpMode() == Ssl::bumpStare) && srvBio->holdWrite()) {
fa17b7f5
CT
606 Ssl::X509_Pointer serverCert(SSL_get_peer_certificate(ssl));
607 if (serverCert.get()) {
608 debugs(81, 3, "Error (" << ERR_error_string(ssl_lib_error, NULL) << ") but, hold write on SSL connection on FD " << fd);
609 checkForPeekAndSplice();
610 return;
611 }
20b79af2 612 }
7f4e9b73
CT
613#endif
614
e2849af8
A
615 // store/report errno when ssl_error is SSL_ERROR_SYSCALL, ssl_lib_error is 0, and ret is -1
616 if (ssl_error == SSL_ERROR_SYSCALL && ret == -1 && ssl_lib_error == 0)
617 sysErrNo = errno;
a23223bf 618
e2849af8
A
619 debugs(83, DBG_IMPORTANT, "Error negotiating SSL on FD " << fd <<
620 ": " << ERR_error_string(ssl_lib_error, NULL) << " (" <<
621 ssl_error << "/" << ret << "/" << errno << ")");
a23223bf 622
e2849af8 623 break; // proceed to the general error handling code
a23223bf 624
e2849af8
A
625 default:
626 break; // no special error handling for all other errors
627 }
a23223bf
CT
628
629 ErrorState *const anErr = ErrorState::NewForwarding(ERR_SECURE_CONNECT_FAIL, request.getRaw());
630 anErr->xerrno = sysErrNo;
631
632 Ssl::ErrorDetail *errFromFailure = (Ssl::ErrorDetail *)SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_detail);
633 if (errFromFailure != NULL) {
634 // The errFromFailure is attached to the ssl object
635 // and will be released when ssl object destroyed.
636 // Copy errFromFailure to a new Ssl::ErrorDetail object
637 anErr->detail = new Ssl::ErrorDetail(*errFromFailure);
638 } else {
639 // server_cert can be NULL here
640 X509 *server_cert = SSL_get_peer_certificate(ssl);
641 anErr->detail = new Ssl::ErrorDetail(SQUID_ERR_SSL_HANDSHAKE, server_cert, NULL);
642 X509_free(server_cert);
643 }
644
645 if (ssl_lib_error != SSL_ERROR_NONE)
646 anErr->detail->setLibError(ssl_lib_error);
647
648 if (request->clientConnectionManager.valid()) {
649 // remember the server certificate from the ErrorDetail object
650 if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
651 serverBump->serverCert.resetAndLock(anErr->detail->peerCert());
652
653 // remember validation errors, if any
654 if (Ssl::CertErrors *errs = static_cast<Ssl::CertErrors*>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors)))
655 serverBump->sslErrors = cbdataReference(errs);
656 }
657
658 // For intercepted connections, set the host name to the server
659 // certificate CN. Otherwise, we just hope that CONNECT is using
660 // a user-entered address (a host name or a user-entered IP).
661 const bool isConnectRequest = !request->clientConnectionManager->port->flags.isIntercepted();
662 if (request->flags.sslPeek && !isConnectRequest) {
663 if (X509 *srvX509 = anErr->detail->peerCert()) {
664 if (const char *name = Ssl::CommonHostName(srvX509)) {
665 request->SetHost(name);
666 debugs(83, 3, HERE << "reset request host: " << name);
667 }
668 }
669 }
670 }
671
672 bail(anErr);
673}
674
675void
676Ssl::PeerConnector::bail(ErrorState *error)
677{
678 Must(error); // or the recepient will not know there was a problem
679
680 // XXX: forward.cc calls peerConnectSucceeded() after an OK TCP connect but
681 // we call peerConnectFailed() if SSL failed afterwards. Is that OK?
682 // It is not clear whether we should call peerConnectSucceeded/Failed()
683 // based on TCP results, SSL results, or both. And the code is probably not
684 // consistent in this aspect across tunnelling and forwarding modules.
685 if (CachePeer *p = serverConnection()->getPeer())
686 peerConnectFailed(p);
687
688 Must(callback != NULL);
689 CbDialer *dialer = dynamic_cast<CbDialer*>(callback->getDialer());
690 Must(dialer);
691 dialer->answer().error = error;
692
693 callBack();
694 // Our job is done. The callabck recepient will probably close the failed
695 // peer connection and try another peer or go direct (if possible). We
696 // can close the connection ourselves (our error notification would reach
697 // the recepient before the fd-closure notification), but we would rather
698 // minimize the number of fd-closure notifications and let the recepient
699 // manage the TCP state of the connection.
700}
701
702void
703Ssl::PeerConnector::callBack()
704{
705 AsyncCall::Pointer cb = callback;
706 // Do this now so that if we throw below, swanSong() assert that we _tried_
707 // to call back holds.
708 callback = NULL; // this should make done() true
709
710 // remove close handler
711 comm_remove_close_handler(serverConnection()->fd, closeHandler);
712
713 CbDialer *dialer = dynamic_cast<CbDialer*>(cb->getDialer());
714 Must(dialer);
715 dialer->answer().conn = serverConnection();
716 ScheduleCallHere(cb);
717}
718
a23223bf
CT
719void
720Ssl::PeerConnector::swanSong()
721{
722 // XXX: unregister fd-closure monitoring and CommSetSelect interest, if any
723 AsyncJob::swanSong();
724 assert(!callback); // paranoid: we have not left the caller waiting
725}
726
727const char *
728Ssl::PeerConnector::status() const
729{
730 static MemBuf buf;
731 buf.reset();
732
733 // TODO: redesign AsyncJob::status() API to avoid this
734 // id and stop reason reporting duplication.
735 buf.append(" [", 2);
736 if (stopReason != NULL) {
737 buf.Printf("Stopped, reason:");
738 buf.Printf("%s",stopReason);
739 }
740 if (serverConn != NULL)
741 buf.Printf(" FD %d", serverConn->fd);
742 buf.Printf(" %s%u]", id.Prefix, id.value);
743 buf.terminate();
744
745 return buf.content();
746}
747