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