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