XRootD
Loading...
Searching...
No Matches
XrdTlsSocket.cc
Go to the documentation of this file.
1//------------------------------------------------------------------------------
2// Copyright (c) 2011-2012 by European Organization for Nuclear Research (CERN)
3// Author: Michal Simon <simonm@cern.ch>
4//------------------------------------------------------------------------------
5// XRootD is free software: you can redistribute it and/or modify
6// it under the terms of the GNU Lesser General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// XRootD is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU Lesser General Public License
16// along with XRootD. If not, see <http://www.gnu.org/licenses/>.
17//------------------------------------------------------------------------------
18
19#include <cstring>
20#include <cerrno>
21#include <fcntl.h>
22#include <iostream>
23#include <poll.h>
24#include <cstdio>
25#include <ctime>
26#include <openssl/ssl.h>
27#include <openssl/bio.h>
28#include <openssl/err.h>
29#include <sys/types.h>
30#include <sys/socket.h>
31
33#include "XrdSys/XrdSysE2T.hh"
35#include "XrdTls/XrdTls.hh"
40#include "XrdTls/XrdTlsTrace.hh"
41
42#include <stdexcept>
43
44/******************************************************************************/
45/* X r d T l s S o c k e t I m p l */
46/******************************************************************************/
47
49{
50 XrdTlsSocketImpl() : tlsctx(0), ssl(0), traceID(""), sFD(-1), hsWait(15),
51 hsDone(false), fatal(0), isClient(false),
52 cOpts(0), cAttr(0), hsNoBlock(false), isSerial(true) {}
53
56 SSL *ssl;
57 const char *traceID;
58 int sFD;
59 int hsWait;
60 bool hsDone;
61 char fatal;
62 bool isClient;
63 char cOpts;
64 char cAttr;
65 bool hsNoBlock;
66 bool isSerial;
67};
68
69/******************************************************************************/
70/* L o c a l C l a s s e s */
71/******************************************************************************/
72
73namespace
74{
75class undoImpl
76{
77public:
78
79 undoImpl(XrdTlsSocketImpl *pImpl) : theImpl(pImpl) {}
80 ~undoImpl() {if (theImpl && theImpl->ssl)
81 {SSL_free( theImpl->ssl );
82 theImpl->ssl = 0;
83 }
84 }
85
86 void KeepImpl() {theImpl = 0;}
87
88private:
89XrdTlsSocketImpl *theImpl;
90};
91}
92
93/******************************************************************************/
94/* G l o b a l s */
95/******************************************************************************/
96
97namespace XrdTlsGlobal
98{
100}
101
102/******************************************************************************/
103/* l o c a l s */
104/******************************************************************************/
105
106namespace
107{
108static const int xVerify = 0x01;
109static const int DNSok = 0x04;
110
111static const int isServer = 0x01;
112static const int rBlocking = 0x02;
113static const int wBlocking = 0x04;
114static const int acc2Block = 0x08;
115}
116
117/******************************************************************************/
118/* C o n s t r u c t o r */
119/******************************************************************************/
120
122{
123
124}
125
126/******************************************************************************/
127/* C o n s t r u c t o r */
128/******************************************************************************/
129
133 bool isClient, bool serial )
134 : pImpl( new XrdTlsSocketImpl() )
135{
136
137// Simply initialize this object and throw an exception if it fails
138//
139 const char *eMsg = Init(ctx, sfd, rwm, hsm, isClient, serial);
140 if (eMsg) throw std::invalid_argument( eMsg );
141}
142
143/******************************************************************************/
144/* D e s t r u c t o r */
145/******************************************************************************/
146
148{
149 if (pImpl->ssl) Shutdown(sdForce);
150 delete pImpl;
151}
152
153/******************************************************************************/
154/* A c c e p t */
155/******************************************************************************/
156
158{
159 EPNAME("Accept");
160 int rc, ssler;
161 bool wOK, aOK = true;
162
163// Make sure there is a context here
164//
165 if (pImpl->ssl == 0)
166 {AcceptEMsg(eWhy, "TLS socket has no context");
168 }
169 undoImpl ImplTracker(pImpl);
170
171// Do some tracing
172//
173 DBG_SOK("Accepting a TLS connection...");
174
175// An accept may require several tries, so we do that here.
176//
177do{if ((rc = SSL_accept( pImpl->ssl )) > 0)
178 {if (pImpl->cOpts & xVerify)
179 {X509 *theCert = SSL_get_peer_certificate(pImpl->ssl);
180 if (!theCert)
181 {AcceptEMsg(eWhy, "x509 certificate is missing");
183 }
184 X509_free(theCert);
185 rc = SSL_get_verify_result(pImpl->ssl);
186 if (rc != X509_V_OK)
187 {AcceptEMsg(eWhy, "x509 certificate verification failed");
189 }
190 }
191 ImplTracker.KeepImpl();
192
193// Reset the socket to blocking mode if we need to. Note that we have to brute
194// force this on the socket as setting a BIO after accept has no effect. We
195// also tell ssl that we want to block on a handshake from now on.
196//
197 if (pImpl->cAttr & acc2Block)
198// BIO_set_nbio(SSL_get_rbio(pImpl->ssl), 0); *Does not work after accept*
199 {int eNO = errno;
200 int flags = fcntl(pImpl->sFD, F_GETFL, 0);
201 flags &= ~O_NONBLOCK;
202 fcntl(pImpl->sFD, F_SETFL, flags);
203 SSL_set_mode(pImpl->ssl, SSL_MODE_AUTO_RETRY);
204 errno = eNO;
205 }
206 return XrdTls::TLS_AOK;
207 }
208
209 // Get the actual SSL error code.
210 //
211 ssler = Diagnose("TLS_Accept", rc, XrdTls::dbgSOK);
212
213 // Check why we did not succeed. We may be able to recover.
214 //
215 if (ssler != SSL_ERROR_WANT_READ && ssler != SSL_ERROR_WANT_WRITE) {
216 if(ssler == SSL_ERROR_SSL){
217 //In the case the accept does have an error related to OpenSSL,
218 //shutdown the TLSSocket in case the link associated to that connection
219 //is re-used
220 Shutdown();
221 }
222 aOK = false; break;
223 }
224
225 if (pImpl->hsNoBlock) return XrdTls::ssl2RC(ssler);
226
227 } while((wOK = Wait4OK(ssler == SSL_ERROR_WANT_READ)));
228
229// If we are here then we got an error
230//
231 AcceptEMsg(eWhy, (!aOK ? Err2Text(ssler).c_str() : XrdSysE2T(errno)));
232 errno = ECONNABORTED;
234}
235
236/******************************************************************************/
237/* Private: A c c e p t E M s g */
238/******************************************************************************/
239
240void XrdTlsSocket::AcceptEMsg(std::string *eWhy, const char *reason)
241{
242 if (eWhy)
243 {*eWhy = "TLS connection from ";
244 *eWhy += pImpl->traceID;
245 *eWhy += " failed; ";
246 *eWhy += reason;
247 }
248}
249
250/******************************************************************************/
251/* C o n n e c t */
252/******************************************************************************/
253
254XrdTls::RC XrdTlsSocket::Connect(const char *thehost, std::string *eWhy)
255{
256 EPNAME("Connect");
257 int ssler, rc;
258 bool wOK = true, aOK = true;
259
260// Setup host verification of a host has been specified. This is a to-do
261// when we move to new versions of SSL. For now, we use the notary object.
262//
263
264// Do some tracing
265//
266 DBG_SOK("Connecting to " <<(thehost ? thehost : "unverified host")
267 <<(thehost && pImpl->cOpts & DNSok ? " dnsok" : "" ));
268
269// Do the connect.
270//
271do{int rc = SSL_connect( pImpl->ssl );
272 if (rc == 1) break;
273
274 ssler = Diagnose("TLS_Connect", rc, XrdTls::dbgSOK);
275
276 if (ssler != SSL_ERROR_WANT_READ && ssler != SSL_ERROR_WANT_WRITE)
277 {aOK = false; break;}
278
279 if (pImpl->hsNoBlock) return XrdTls::ssl2RC(ssler);
280
281 } while((wOK = Wait4OK(ssler == SSL_ERROR_WANT_READ)));
282
283// Check if everything went well. Note that we need to save the errno as
284// we may be calling external methods that may generate other errors. We
285//
286 if (!aOK || !wOK)
287 {rc = errno;
288 DBG_SOK("Handshake failed; "<<(!aOK ? Err2Text(ssler) : XrdSysE2T(rc)));
289 if (eWhy)
290 {const char *hName = (thehost ? thehost : "host");
291 *eWhy = "Unable to connect to ";
292 *eWhy += hName;
293 *eWhy += "; ";
294 if (!aOK) *eWhy += Err2Text(ssler);
295 else *eWhy += XrdSysE2T(rc);
296 }
297 if (!aOK) return XrdTls::ssl2RC(ssler);
298 errno = rc;
300 }
301
302// Set the hsDone flag!
303//
304 pImpl->hsDone = bool( SSL_is_init_finished( pImpl->ssl ) );
305
306// Validate the host name if so desired. Note that cert verification is
307// checked by the notary since hostname validation requires it. We currently
308// do not support dnsOK but doing so just means we need to check the option
309// and if on, also pass a XrdNetAddrInfo object generated from the hostname.
310//
311 if (thehost)
312 {const char *eTxt = XrdTlsNotary::Validate(pImpl->ssl, thehost, 0);
313 if (eTxt)
314 {DBG_SOK(thehost << " verification failed; " <<eTxt);
315 if (eWhy)
316 {
317 *eWhy = "Unable to validate "; *eWhy += thehost;
318 *eWhy += "; "; *eWhy += eTxt;
319 }
321 }
322 }
323
324 DBG_SOK("Connect completed without error.");
325 return XrdTls::TLS_AOK;
326}
327
328/******************************************************************************/
329/* C o n t e x t */
330/******************************************************************************/
331
333{
334 return pImpl->tlsctx;
335}
336
337/******************************************************************************/
338/* Private: D i a g n o s e */
339/******************************************************************************/
340
341int XrdTlsSocket::Diagnose(const char *what, int sslrc, int tcode)
342{
343 int eCode = SSL_get_error( pImpl->ssl, sslrc );
344
345// We need to dispose of the error queue otherwise the next operation will
346// fail. We do this by either printing them or flushing them down the drain.
347// We avoid the tracing hangups indicated by SSL_ERROR_SYSCALL w/ errno == 0.
348//
349 if (TRACING(tcode)
350 || (eCode != SSL_ERROR_WANT_READ && eCode != SSL_ERROR_WANT_WRITE))
351 {int eNO = errno;
352 if (!eNO && eCode == SSL_ERROR_SYSCALL) ERR_clear_error();
353 else {char eBuff[256];
354 snprintf(eBuff, sizeof(eBuff),
355 "TLS error rc=%d ec=%d (%s) errno=%d.",
356 sslrc, eCode, XrdTls::ssl2Text(eCode), eNO);
357 XrdTls::Emsg(pImpl->traceID, eBuff, true);
358 errno = eNO;
359 }
360 } else ERR_clear_error();
361
362// Make sure we can shutdown
363//
364 if (eCode == SSL_ERROR_SYSCALL)
365 pImpl->fatal = (char)XrdTls::TLS_SYS_Error;
366 else if (eCode == SSL_ERROR_SSL)
367 pImpl->fatal = (char)XrdTls::TLS_SSL_Error;
368
369// Return the errors
370//
371 return eCode;
372}
373
374/******************************************************************************/
375/* Private: E r r 2 T e x t */
376/******************************************************************************/
377
378std::string XrdTlsSocket::Err2Text(int sslerr)
379{
380 const char *eP;
381 char eBuff[256];
382
383 if (sslerr == SSL_ERROR_SYSCALL)
384 {int rc = errno;
385 if (!rc) rc = EPIPE;
386 snprintf(eBuff, sizeof(eBuff), "%s", XrdSysE2T(rc));
387 *eBuff = tolower(*eBuff);
388 eP = eBuff;
389 } else eP = XrdTls::ssl2Text(sslerr,0);
390
391 return std::string(eP);
392}
393
394/******************************************************************************/
395/* g e t C e r t s */
396/******************************************************************************/
397
399{
400 XrdSysMutexHelper mHelper;
401
402// Serialize call if need be
403//
404 if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
405
406// If verified certs need to be returned, make sure the certs are verified
407//
408 if (ver && SSL_get_verify_result(pImpl->ssl) != X509_V_OK) return 0;
409
410// Get the certs and return
411//
412 X509 *pcert = SSL_get_peer_certificate(pImpl->ssl);
413 if (pcert == 0) return 0;
414 return new XrdTlsPeerCerts(pcert, SSL_get_peer_cert_chain(pImpl->ssl));
415}
416
417/******************************************************************************/
418/* I n i t */
419/******************************************************************************/
420
421const char *XrdTlsSocket::Init( XrdTlsContext &ctx, int sfd,
424 bool isClient, bool serial,
425 const char *tid )
426{
427 BIO *rbio, *wbio = 0;
428
429// Make sure this connection is not in use if this is a client. Servers are
430// allowed to throw away the previous setup as they reuse sockets.
431//
432 if ( pImpl->ssl )
433 {if (isClient) return "TLS I/O: connection is still in use.";
434 else {SSL_free( pImpl->ssl );
435 pImpl->ssl = 0;
436 }
437 }
438
439// Obtain the ssl object at this point.
440//
441 pImpl->ssl = static_cast<SSL *>(ctx.Session());
442 if (pImpl->ssl == 0) return "TLS I/O: failed to get ssl object.";
443
444// Initialze values from the context.
445//
446 pImpl->tlsctx = &ctx;
447 const XrdTlsContext::CTX_Params *parms = ctx.GetParams();
448 pImpl->hsWait = (parms->opts & XrdTlsContext::hsto) * 1000; // Poll timeout
449 if (ctx.x509Verify()) pImpl->cOpts = xVerify;
450 else pImpl->cOpts = 0;
451 if (parms->opts & XrdTlsContext::dnsok) pImpl->cOpts |= DNSok;
452 pImpl->traceID = tid;
453 pImpl->isClient= isClient;
454 pImpl->isSerial= serial;
455
456// Set the ssl object state to correspond to client or server type
457//
458 if (isClient)
459 {SSL_set_connect_state( pImpl->ssl );
460 pImpl->cAttr = 0;
461 } else {
462 SSL_set_accept_state( pImpl->ssl );
463 pImpl->cAttr = isServer;
464 }
465
466// Allocate right number of bio's and initialize them as requested. Note
467// that when the read and write bios have the same attribue, we use only one.
468//
469 switch( rwm )
470 {
471 case TLS_RNB_WNB:
472 rbio = BIO_new_socket( sfd, BIO_NOCLOSE );
473 BIO_set_nbio( rbio, 1 );
474 break;
475
476 case TLS_RNB_WBL:
477 rbio = BIO_new_socket( sfd, BIO_NOCLOSE );
478 BIO_set_nbio( rbio, 1 );
479 wbio = BIO_new_socket( sfd, BIO_NOCLOSE );
480 pImpl->cAttr |= wBlocking;
481 break;
482
483 case TLS_RBL_WNB:
484 rbio = BIO_new_socket( sfd, BIO_NOCLOSE );
485 wbio = BIO_new_socket( sfd, BIO_NOCLOSE );
486 BIO_set_nbio( wbio, 1 );
487 pImpl->cAttr |= rBlocking;
488 break;
489
490 case TLS_RBL_WBL:
491 rbio = BIO_new_socket( sfd, BIO_NOCLOSE );
492 pImpl->cAttr |= (rBlocking | wBlocking);
493 break;
494
495 default:
496 return "TLS I/O: invalid TLS rw mode."; break;
497 }
498
499// Set correct handshake mode
500//
501 if (hsm) pImpl->hsNoBlock = false;
502 else pImpl->hsNoBlock = true;
503
504// Reset the handshake and fatal error indicators
505//
506 pImpl->hsDone = false;
507 pImpl->fatal = 0;
508
509// The glories of OpenSSL require that we do some fancy footwork with the
510// handshake timeout. If there is one and this is a server and the server
511// wants blocking reads, we initially set the socket as non-blocking as the
512// bio's can handle it. Then after the accept we set it back to blocking mode.
513// Note: doing this via the bio causes the socket to remain nonblocking. yech!
514//
515 if (pImpl->hsWait && !hsm && pImpl->cAttr & rBlocking)
516 {int flags = fcntl(sfd, F_GETFL, 0);
517 flags |= O_NONBLOCK;
518 fcntl(sfd, F_SETFL, flags);
519 pImpl->cAttr |= acc2Block;
520 }
521
522// Finally attach the bios to the ssl object. When the ssl object is freed
523// the bios will be freed as well.
524//
525 pImpl->sFD = sfd;
526 if (wbio == 0) wbio = rbio;
527 SSL_set_bio( pImpl->ssl, rbio, wbio );
528
529// All done. The caller will do an Accept() or Connect() afterwards.
530//
531 return 0;
532}
533
534/******************************************************************************/
535/* P e e k */
536/******************************************************************************/
537
538XrdTls::RC XrdTlsSocket::Peek( char *buffer, size_t size, int &bytesPeek )
539 {
540 EPNAME("Peek");
541 XrdSysMutexHelper mHelper;
542 int ssler;
543
544 //------------------------------------------------------------------------
545 // Serialize call if need be
546 //------------------------------------------------------------------------
547
548 if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
549
550 //------------------------------------------------------------------------
551 // Return an error if this socket received a fatal error as OpenSSL will
552 // SEGV when called after such an error.
553 //------------------------------------------------------------------------
554
555 if (pImpl->fatal)
556 {DBG_SIO("Failing due to previous error, fatal=" << (int)pImpl->fatal);
557 return (XrdTls::RC)pImpl->fatal;
558 }
559
560 //------------------------------------------------------------------------
561 // If necessary, SSL_read() will negotiate a TLS/SSL session, so we don't
562 // have to explicitly call SSL_connect or SSL_do_handshake.
563 //------------------------------------------------------------------------
564
565 do{int rc = SSL_peek( pImpl->ssl, buffer, size );
566
567 // Note that according to SSL whenever rc > 0 then SSL_ERROR_NONE can be
568 // returned to the caller. So, we short-circuit all the error handling.
569 //
570 if( rc > 0 )
571 {bytesPeek = rc;
572 return XrdTls::TLS_AOK;
573 }
574
575 // We have a potential error. Get the SSL error code and whether or
576 // not the handshake actually is finished (semi-accurate)
577 //
578 pImpl->hsDone = bool( SSL_is_init_finished( pImpl->ssl ) );
579 ssler = Diagnose("TLS_Peek", rc, XrdTls::dbgSIO);
580
581 // If the error isn't due to blocking issues, we are done.
582 //
583 if (ssler != SSL_ERROR_WANT_READ && ssler != SSL_ERROR_WANT_WRITE)
584 return XrdTls::ssl2RC(ssler);
585
586 // If the caller is non-blocking, the return the issue. Otherwise, block.
587 //
588 if ((pImpl->hsNoBlock && NeedHS()) || !(pImpl->cAttr & rBlocking))
589 return XrdTls::ssl2RC(ssler);
590
591 } while(Wait4OK(ssler == SSL_ERROR_WANT_READ));
592
593 // Return failure as the Wait failed.
594 //
596 }
597
598/******************************************************************************/
599/* P e n d i n g */
600/******************************************************************************/
601
603{
604 XrdSysMutexHelper mHelper;
605
606 //------------------------------------------------------------------------
607 // Return an error if this socket received a fatal error as OpenSSL will
608 // SEGV when called after such an error. So, return something reasonable.
609 //------------------------------------------------------------------------
610
611 if (pImpl->fatal) return 0;
612
613 //------------------------------------------------------------------------
614 // Serialize call if need be
615 //------------------------------------------------------------------------
616
617 if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
618
619 if (!any) return SSL_pending(pImpl->ssl);
620#if OPENSSL_VERSION_NUMBER < 0x10100000L
621 return SSL_pending(pImpl->ssl) != 0;
622#else
623 return SSL_has_pending(pImpl->ssl);
624#endif
625}
626
627/******************************************************************************/
628/* R e a d */
629/******************************************************************************/
630
631XrdTls::RC XrdTlsSocket::Read( char *buffer, size_t size, int &bytesRead )
632{
633 EPNAME("Read");
634 XrdSysMutexHelper mHelper;
635 int ssler;
636
637 //------------------------------------------------------------------------
638 // Serialize call if need be
639 //------------------------------------------------------------------------
640
641 if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
642
643 //------------------------------------------------------------------------
644 // Return an error if this socket received a fatal error as OpenSSL will
645 // SEGV when called after such an error.
646 //------------------------------------------------------------------------
647
648 if (pImpl->fatal)
649 {DBG_SIO("Failing due to previous error, fatal=" << (int)pImpl->fatal);
650 return (XrdTls::RC)pImpl->fatal;
651 }
652
653 //------------------------------------------------------------------------
654 // If necessary, SSL_read() will negotiate a TLS/SSL session, so we don't
655 // have to explicitly call SSL_connect or SSL_do_handshake.
656 //------------------------------------------------------------------------
657
658 do{int rc = SSL_read( pImpl->ssl, buffer, size );
659
660 // Note that according to SSL whenever rc > 0 then SSL_ERROR_NONE can be
661 // returned to the caller. So, we short-circuit all the error handling.
662 //
663 if( rc > 0 )
664 {bytesRead = rc;
665 DBG_SIO(rc <<" out of " <<size <<" bytes.");
666 return XrdTls::TLS_AOK;
667 }
668
669 // We have a potential error. Get the SSL error code and whether or
670 // not the handshake actually is finished (semi-accurate)
671 //
672 ssler = Diagnose("TLS_Read", rc, XrdTls::dbgSIO);
673 if (ssler == SSL_ERROR_NONE)
674 {bytesRead = 0;
675 DBG_SIO("0 out of " <<size <<" bytes.");
676 return XrdTls::TLS_AOK;
677 }
678
679 // If the error isn't due to blocking issues, we are done.
680 //
681 if (ssler != SSL_ERROR_WANT_READ && ssler != SSL_ERROR_WANT_WRITE)
682 return XrdTls::ssl2RC(ssler);
683
684 // If the caller is non-blocking for reads, return the issue. Otherwise,
685 // block for the caller.
686 //
687 if ((pImpl->hsNoBlock && NeedHS()) || !(pImpl->cAttr & rBlocking))
688 return XrdTls::ssl2RC(ssler);
689
690 // Wait until we can read again.
691
692 } while(Wait4OK(ssler == SSL_ERROR_WANT_READ));
693
695 }
696
697/******************************************************************************/
698/* S e t T r a c e I D */
699/******************************************************************************/
700
701void XrdTlsSocket::SetTraceID(const char *tid)
702{
703 if (pImpl) pImpl->traceID = tid;
704}
705
706/******************************************************************************/
707/* S h u t d o w n */
708/******************************************************************************/
709
711{
712 EPNAME("Shutdown");
713 XrdSysMutexHelper mHelper;
714 const char *how;
715 int sdMode, rc;
716
717// Make sure we have an ssl object.
718//
719 if (pImpl->ssl == 0) return;
720
721// While we do not need to technically serialize here, we're being conservative
722//
723 if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
724
725// Perform shutdown as needed. This is required before freeing the ssl object.
726// If we previously encountered a SYSCALL or SSL error, shutdown is prohibited!
727// The following code is patterned after code in the public TomCat server.
728//
729 if (!pImpl->fatal)
730 {switch(sdType)
731 {case sdForce: // Forced shutdown which violate TLS standard!
732 sdMode = SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN;
733 how = "forced";
734 break;
735 case sdWait: // Wait for client acknowledgement
736 sdMode = 0;
737 how = "clean";
738 break;
739 default: // Fast shutdown, don't wait for ack (compliant)
740 sdMode = SSL_RECEIVED_SHUTDOWN;
741 how = "fast";
742 break;
743 }
744
745 DBG_SOK("Doing " <<how <<" shutdown.");
746 SSL_set_shutdown(pImpl->ssl, sdMode);
747
748 for (int i = 0; i < 4; i++)
749 {rc = SSL_shutdown( pImpl->ssl );
750 if (rc > 0) break;
751 if (rc < 0)
752 {rc = SSL_get_error( pImpl->ssl, rc );
753 if (rc == SSL_ERROR_WANT_READ || rc == SSL_ERROR_WANT_WRITE)
754 {if (Wait4OK(rc == SSL_ERROR_WANT_READ)) continue;
755 rc = SSL_ERROR_SYSCALL;
756 }
757 char msgBuff[512];
758 std::string eMsg = Err2Text(rc);
759 snprintf(msgBuff, sizeof(msgBuff),
760 "FD %d TLS shutdown failed; %s.\n",pImpl->sFD,eMsg.c_str());
761 XrdTls::Emsg(pImpl->traceID, msgBuff, true);
762 break;
763 }
764 }
765 }
766
767// Now free the ssl object which will free all the BIO's associated with it
768//
769 SSL_free( pImpl->ssl );
770 pImpl->ssl = 0;
771 pImpl->fatal = 0;
772}
773
774/******************************************************************************/
775/* W r i t e */
776/******************************************************************************/
777
778XrdTls::RC XrdTlsSocket::Write( const char *buffer, size_t size,
779 int &bytesWritten )
780{
781 EPNAME("Write");
782 XrdSysMutexHelper mHelper;
783 int ssler;
784
785 //------------------------------------------------------------------------
786 // Serialize call if need be
787 //------------------------------------------------------------------------
788
789 if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
790
791 //------------------------------------------------------------------------
792 // Return an error if this socket received a fatal error as OpenSSL will
793 // SEGV when called after such an error.
794 //------------------------------------------------------------------------
795
796 if (pImpl->fatal)
797 {DBG_SIO("Failing due to previous error, fatal=" << (int)pImpl->fatal);
798 return (XrdTls::RC)pImpl->fatal;
799 }
800
801 //------------------------------------------------------------------------
802 // If necessary, SSL_write() will negotiate a TLS/SSL session, so we don't
803 // have to explicitly call SSL_connect or SSL_do_handshake.
804 //------------------------------------------------------------------------
805
806 do{int rc = SSL_write( pImpl->ssl, buffer, size );
807
808 // Note that according to SSL whenever rc > 0 then SSL_ERROR_NONE can be
809 // returned to the caller. So, we short-circuit all the error handling.
810 //
811 if (rc > 0)
812 {bytesWritten = rc;
813 DBG_SIO(rc <<" out of " <<size <<" bytes.");
814 return XrdTls::TLS_AOK;
815 }
816
817 // We have a potential error. Get the SSL error code and whether or
818 // not the handshake actually is finished (semi-accurate)
819 //
820 ssler = Diagnose("TLS_Write", rc, XrdTls::dbgSIO);
821 if (ssler == SSL_ERROR_NONE)
822 {bytesWritten = 0;
823 DBG_SIO(rc <<" out of " <<size <<" bytes.");
824 return XrdTls::TLS_AOK;
825 }
826
827 // If the error isn't due to blocking issues, we are done.
828 //
829 if (ssler != SSL_ERROR_WANT_READ && ssler != SSL_ERROR_WANT_WRITE)
830 return XrdTls::ssl2RC(ssler);
831
832 // If the caller is non-blocking for reads, return the issue. Otherwise,
833 // block for the caller.
834 //
835 if ((pImpl->hsNoBlock && NeedHS()) || !(pImpl->cAttr & wBlocking))
836 return XrdTls::ssl2RC(ssler);
837
838 // Wait unil the write can get restarted
839
840 } while(Wait4OK(ssler == SSL_ERROR_WANT_READ));
841
843}
844
845/******************************************************************************/
846/* N e e d H a n d S h a k e */
847/******************************************************************************/
848
850 {
851 XrdSysMutexHelper mHelper;
852
853 //------------------------------------------------------------------------
854 // Return an error if this socket received a fatal error as OpenSSL will
855 // SEGV when called after such an error. So, return something reasonable.
856 // Technically, we don't need to serialize this because nothing get
857 // modified. We do so anyway out of abundance of caution.
858 //------------------------------------------------------------------------
859
860 if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
861 if (pImpl->fatal) return false;
862 pImpl->hsDone = bool( SSL_is_init_finished( pImpl->ssl ) );
863 return !pImpl->hsDone;
864 }
865
866/******************************************************************************/
867/* Private: N e e d H S */
868/******************************************************************************/
869
870 bool XrdTlsSocket::NeedHS()
871 {
872 //------------------------------------------------------------------------
873 // The following code is identical to NeedHandshake() except that it does
874 // serialize the call because the caller already has done so. While we
875 // could use a recursive mutex the overhead in doing so is not worth it
876 // and it is only used for internal purposes.
877 //------------------------------------------------------------------------
878
879 if (pImpl->fatal) return false;
880 pImpl->hsDone = bool( SSL_is_init_finished( pImpl->ssl ) );
881 return !pImpl->hsDone;
882 }
883
884/******************************************************************************/
885/* V e r s i o n */
886/******************************************************************************/
887
889 {
890 // This call modifies nothing nor does it depend on modified data once the
891 // connection is esablished and doesn't need serialization.
892 //
893 return SSL_get_version(pImpl->ssl);
894 }
895
896/******************************************************************************/
897/* Private: W a i t 4 O K */
898/******************************************************************************/
899
900bool XrdTlsSocket::Wait4OK(bool wantRead)
901{
902 static const short rdOK = POLLIN |POLLRDNORM;
903 static const short wrOK = POLLOUT|POLLWRNORM;
904 struct pollfd polltab = {pImpl->sFD, (wantRead ? rdOK : wrOK), 0};
905 int rc, timeout;
906
907 // Establish how long we will wait. This depends on hsDone being current!
908 //
909 if (pImpl->hsDone) timeout = -1;
910 else timeout = (pImpl->hsWait ? pImpl->hsWait : -1);
911
912 do {rc = poll(&polltab, 1, timeout);} while(rc < 0 && errno == EINTR);
913
914 // Make sure we have a clean state, otherwise indicate we failed. The
915 // caller will need to perform the correct action.
916 //
917 if (rc == 1)
918 {if (polltab.revents & (wantRead ? rdOK : wrOK)) return true;
919 if (polltab.revents & POLLERR) errno = EIO;
920 else if (polltab.revents & (POLLHUP|POLLNVAL)) errno = EPIPE;
921 else errno = EINVAL;
922 } else if (!rc) errno = ETIMEDOUT; // This is not possible
923 return false;
924}
#define EPNAME(x)
#define eMsg(x)
const char * XrdSysE2T(int errcode)
Definition XrdSysE2T.cc:104
#define DBG_SOK(y)
#define DBG_SIO(y)
#define TRACING(x)
Definition XrdTrace.hh:70
void Lock(XrdSysMutex *Mutex)
static const uint64_t hsto
Mask to isolate the hsto.
const CTX_Params * GetParams()
static const uint64_t dnsok
Trust DNS for host name.
static const char * Validate(const SSL *ssl, const char *hName, XrdNetAddrInfo *netInfo=0)
XrdTlsContext * Context()
XrdTls::RC Accept(std::string *eMsg=0)
void Shutdown(SDType=sdImmed)
~XrdTlsSocket()
Destructor.
@ TLS_RNB_WBL
Non-blocking read blocking write.
@ TLS_RBL_WNB
blocking read non-blocking write
@ TLS_RBL_WBL
blocking read blocking write
@ TLS_RNB_WNB
Non-blocking read non-blocking write.
bool NeedHandShake()
XrdTls::RC Write(const char *buffer, size_t size, int &bytesOut)
const char * Version()
XrdTls::RC Read(char *buffer, size_t size, int &bytesRead)
Read from the TLS connection. If necessary, a handshake will be done.
const char * Init(XrdTlsContext &ctx, int sfd, RW_Mode rwm, HS_Mode hsm, bool isClient, bool serial=true, const char *tid="")
XrdTls::RC Connect(const char *thehost=0, std::string *eWhy=0)
void SetTraceID(const char *tid)
int Pending(bool any=true)
XrdTls::RC Peek(char *buffer, size_t size, int &bytesPeek)
XrdTlsPeerCerts * getCerts(bool ver=true)
static RC ssl2RC(int sslrc)
Definition XrdTls.cc:205
static const int dbgSIO
Turn debugging in for socket I/O.
Definition XrdTls.hh:102
static const int dbgSOK
Turn debugging in for socket operations.
Definition XrdTls.hh:101
static void Emsg(const char *tid, const char *msg=0, bool flush=true)
Definition XrdTls.cc:104
static const char * ssl2Text(int sslrc, const char *dflt="unknown_error")
Definition XrdTls.cc:235
@ TLS_AOK
All went well, will always be zero.
Definition XrdTls.hh:40
@ TLS_HNV_Error
A hostname validation error occuured.
Definition XrdTls.hh:44
@ TLS_VER_Error
Certificate verification failed.
Definition XrdTls.hh:48
@ TLS_CRT_Missing
The x509 certificate missing.
Definition XrdTls.hh:42
@ TLS_SYS_Error
A system call error occurred.
Definition XrdTls.hh:46
@ TLS_SSL_Error
An SSL error occurred.
Definition XrdTls.hh:45
@ TLS_CTX_Missing
The TLS context is missing.
Definition XrdTls.hh:43
XrdSysTrace SysTrace("TLS", 0)
uint64_t opts
Options as passed to the constructor.
char cOpts
Connection options.
XrdSysMutex sslMutex
Mutex to serialize calls.
bool isClient
True if for client use.
bool hsDone
True if the handshake has completed.
char fatal
!0 if fatal error prevents shutdown call
bool hsNoBlock
Handshake handling nonblocking if true.
int sFD
Associated file descriptor (never closed)
char cAttr
Connection attributes.
bool isSerial
True if calls must be serialized.
XrdTlsContext * tlsctx
Associated context object.
const char * traceID
Trace identifier.
SSL * ssl
Associated SSL object.
int hsWait
Maximum amount of time to wait for handshake.