XRootD
Loading...
Searching...
No Matches
XrdTlsSocket Class Reference

Socket wrapper for TLS I/O. More...

#include <XrdTlsSocket.hh>

+ Collaboration diagram for XrdTlsSocket:

Public Types

enum  HS_Mode {
  TLS_HS_BLOCK = true ,
  TLS_HS_NOBLK = false
}
 
enum  RW_Mode {
  TLS_RNB_WNB ,
  TLS_RNB_WBL ,
  TLS_RBL_WNB ,
  TLS_RBL_WBL
}
 
enum  SDType {
  sdForce = 1 ,
  sdImmed = 2 ,
  sdWait = 3
}
 

Public Member Functions

 XrdTlsSocket ()
 
 XrdTlsSocket (XrdTlsContext &ctx, int sfd, RW_Mode rwm, HS_Mode hsm, bool isClient, bool serial=true)
 
 ~XrdTlsSocket ()
 Destructor.
 
XrdTls::RC Accept (std::string *eMsg=0)
 
XrdTls::RC Connect (const char *thehost=0, std::string *eWhy=0)
 
XrdTlsContextContext ()
 
XrdTlsPeerCertsgetCerts (bool ver=true)
 
const char * Init (XrdTlsContext &ctx, int sfd, RW_Mode rwm, HS_Mode hsm, bool isClient, bool serial=true, const char *tid="")
 
bool NeedHandShake ()
 
XrdTls::RC Peek (char *buffer, size_t size, int &bytesPeek)
 
int Pending (bool any=true)
 
XrdTls::RC Read (char *buffer, size_t size, int &bytesRead)
 Read from the TLS connection. If necessary, a handshake will be done.
 
void SetTraceID (const char *tid)
 
void Shutdown (SDType=sdImmed)
 
const char * Version ()
 
XrdTls::RC Write (const char *buffer, size_t size, int &bytesOut)
 

Detailed Description

Socket wrapper for TLS I/O.

Definition at line 39 of file XrdTlsSocket.hh.

Member Enumeration Documentation

◆ HS_Mode

Enumerator
TLS_HS_BLOCK 

Always block during handshake.

TLS_HS_NOBLK 

Do not block during handshake.

Definition at line 51 of file XrdTlsSocket.hh.

52{
53 TLS_HS_BLOCK = true,
54 TLS_HS_NOBLK = false,
55};
@ TLS_HS_BLOCK
Always block during handshake.
@ TLS_HS_NOBLK
Do not block during handshake.

◆ RW_Mode

Enumerator
TLS_RNB_WNB 

Non-blocking read non-blocking write.

TLS_RNB_WBL 

Non-blocking read blocking write.

TLS_RBL_WNB 

blocking read non-blocking write

TLS_RBL_WBL 

blocking read blocking write

Definition at line 43 of file XrdTlsSocket.hh.

44{
49};
@ 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.

◆ SDType

Tear down a TLS connection

Parameters
Oneof the following enums: sdForce - Forced shutdown (violates TLS standard). sdImmed - Immediate shutdown (don't wait for ack); the default. sdWait - Wait for peer acknowledgement (may be slow).
Enumerator
sdForce 
sdImmed 
sdWait 

Definition at line 225 of file XrdTlsSocket.hh.

Constructor & Destructor Documentation

◆ XrdTlsSocket() [1/2]

XrdTlsSocket::XrdTlsSocket ( XrdTlsContext & ctx,
int sfd,
XrdTlsSocket::RW_Mode rwm,
XrdTlsSocket::HS_Mode hsm,
bool isClient,
bool serial = true )

Constructor - creates specified mode TLS I/O wrapper for given socket file descriptor. Note this constructor throws an exception should any error be encountered. Use the parameterless constructor if you wish to avoid handling exceptions. When an exception is thrown, you should print all associated errors by calling GetErrs() or PrintErrs().

Parameters
ctx- the context for the connection. Be aware that a context can be associated wity multiple connections.
sfd- the file descriptor associated with the connection.
rwm- One of the above enums describing how connection I/O should be handled.
hsm- One of the above enums describing how handshakes during read/write calls should be handled.
isClient- When true initialize for client use. Otherwise, initialize for server use.
serial- When true, only allows one thread to use the socket at a time to prevent SSL errors (default). When false does not add this protection, assuming caller does so.

Definition at line 134 of file XrdTlsSocket.cc.

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}
#define eMsg(x)
const char * Init(XrdTlsContext &ctx, int sfd, RW_Mode rwm, HS_Mode hsm, bool isClient, bool serial=true, const char *tid="")

References eMsg, and Init().

+ Here is the call graph for this function:

◆ XrdTlsSocket() [2/2]

XrdTlsSocket::XrdTlsSocket ( )

Constructor - reserves space for a TLS I/O wrapper. Use the Init() method to fully initialize this object.

Definition at line 125 of file XrdTlsSocket.cc.

125 : pImpl( new XrdTlsSocketImpl() )
126{
127
128}

◆ ~XrdTlsSocket()

XrdTlsSocket::~XrdTlsSocket ( )

Destructor.

Definition at line 151 of file XrdTlsSocket.cc.

152{
153 if (pImpl->ssl) Shutdown(sdForce);
154 delete pImpl;
155}
void Shutdown(SDType=sdImmed)
SSL * ssl
Associated SSL object.

References sdForce, Shutdown(), and XrdTlsSocketImpl::ssl.

+ Here is the call graph for this function:

Member Function Documentation

◆ Accept()

XrdTls::RC XrdTlsSocket::Accept ( std::string * eMsg = 0)

Accept an incoming TLS connection

Parameters
eMsg- If not nil, receives the associated error message.
Returns
The appropriate TLS return code.

Definition at line 161 of file XrdTlsSocket.cc.

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}
#define EPNAME(x)
int fcntl(int fd, int cmd,...)
const char * XrdSysE2T(int errcode)
Definition XrdSysE2T.cc:99
#define DBG_SOK(y)
static RC ssl2RC(int sslrc)
Definition XrdTls.cc:205
static const int dbgSOK
Turn debugging in for socket operations.
Definition XrdTls.hh:101
@ TLS_AOK
All went well, will always be zero.
Definition XrdTls.hh:40
@ 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_CTX_Missing
The TLS context is missing.
Definition XrdTls.hh:43
char cOpts
Connection options.
bool hsNoBlock
Handshake handling nonblocking if true.
int sFD
Associated file descriptor (never closed)
char cAttr
Connection attributes.

References XrdTlsSocketImpl::cAttr, XrdTlsSocketImpl::cOpts, DBG_SOK, XrdTls::dbgSOK, EPNAME, fcntl(), XrdTlsSocketImpl::hsNoBlock, XrdTlsSocketImpl::sFD, Shutdown(), XrdTlsSocketImpl::ssl, XrdTls::ssl2RC(), XrdTls::TLS_AOK, XrdTls::TLS_CRT_Missing, XrdTls::TLS_CTX_Missing, XrdTls::TLS_SYS_Error, XrdTls::TLS_VER_Error, and XrdSysE2T().

Referenced by XrdLinkXeq::setTLS().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ Connect()

XrdTls::RC XrdTlsSocket::Connect ( const char * thehost = 0,
std::string * eWhy = 0 )

Establish a TLS connection

Parameters
thehost- The expected hostname. If nil the peername is not verified.
eWhy- If not nil, receives the associated error message.
Returns
TLS_AOK if the operation was successful; otherwise the appropraite return code indicating the problem with eWhy, not nil, containing a description of the error.

Definition at line 258 of file XrdTlsSocket.cc.

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}
static const char * Validate(const SSL *ssl, const char *hName, XrdNetAddrInfo *netInfo=0)
@ TLS_HNV_Error
A hostname validation error occuured.
Definition XrdTls.hh:44
bool hsDone
True if the handshake has completed.

References XrdTlsSocketImpl::cOpts, DBG_SOK, XrdTls::dbgSOK, EPNAME, XrdTlsSocketImpl::hsDone, XrdTlsSocketImpl::hsNoBlock, XrdTlsSocketImpl::ssl, XrdTls::ssl2RC(), XrdTls::TLS_AOK, XrdTls::TLS_HNV_Error, XrdTls::TLS_SYS_Error, XrdTlsNotary::Validate(), and XrdSysE2T().

Referenced by XrdCl::Tls::Connect().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ Context()

XrdTlsContext * XrdTlsSocket::Context ( )

Obtain context associated with this connection.

Returns
: Tls connection object

Definition at line 336 of file XrdTlsSocket.cc.

337{
338 return pImpl->tlsctx;
339}
XrdTlsContext * tlsctx
Associated context object.

References XrdTlsSocketImpl::tlsctx.

◆ getCerts()

XrdTlsPeerCerts * XrdTlsSocket::getCerts ( bool ver = true)

Get peer certificates associated with the socket.

Parameters
ver- When true, only return verified certificates.
Returns
A pointer to the object holding the peer certificate and the associated chain. Nill is returned if there are no certificates of if verification did not occur but ver was true. The caller is responsible for deleting the returned object.

Definition at line 402 of file XrdTlsSocket.cc.

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}
void Lock(XrdSysMutex *Mutex)
XrdSysMutex sslMutex
Mutex to serialize calls.
bool isSerial
True if calls must be serialized.

References XrdTlsSocketImpl::isSerial, XrdSysMutexHelper::Lock(), XrdTlsSocketImpl::ssl, and XrdTlsSocketImpl::sslMutex.

Referenced by XrdLinkXeq::getPeerCerts().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ Init()

const char * XrdTlsSocket::Init ( XrdTlsContext & ctx,
int sfd,
XrdTlsSocket::RW_Mode rwm,
XrdTlsSocket::HS_Mode hsm,
bool isClient,
bool serial = true,
const char * tid = "" )

Initialize this object to handle the specified TLS I/O mode for the given file descriptor. Should an error occur, messages are automatically routed to the context message callback before returning.

Parameters
ctx- the context for the connection. Be aware that a context can be associated wity multiple connections.
sfd- the file descriptor associated with the connection.
rwm- One of the above enums describing how connection I/O should be handled.
hsm- One of the above enums describing how handshakes during read/write calls should be handled.
isClient- When true initialize for client use. Otherwise, initialize for server use.
serial- When true, only allows one thread to use the socket at a time to prevent SSL errors (default). When false does not add this protection, assuming caller does so.
tid- Trace identifier to appear in messages. The value must have the same lifetime as this object.
Returns
=0 - object has been initialized.
!0 - an error occurred, the return value is a pointer to a message summarizing the error. This message is the same as would be thrown by the parameterized constructor.

Definition at line 425 of file XrdTlsSocket.cc.

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}
static const uint64_t hsto
Mask to isolate the hsto.
const CTX_Params * GetParams()
static const uint64_t dnsok
Trust DNS for host name.
uint64_t opts
Options as passed to the constructor.
bool isClient
True if for client use.
char fatal
!0 if fatal error prevents shutdown call
const char * traceID
Trace identifier.
int hsWait
Maximum amount of time to wait for handshake.

References XrdTlsSocketImpl::cAttr, XrdTlsSocketImpl::cOpts, XrdTlsContext::dnsok, XrdTlsSocketImpl::fatal, fcntl(), XrdTlsContext::GetParams(), XrdTlsSocketImpl::hsDone, XrdTlsSocketImpl::hsNoBlock, XrdTlsContext::hsto, XrdTlsSocketImpl::hsWait, XrdTlsSocketImpl::isClient, XrdTlsSocketImpl::isSerial, XrdTlsContext::CTX_Params::opts, XrdTlsContext::Session(), XrdTlsSocketImpl::sFD, XrdTlsSocketImpl::ssl, TLS_RBL_WBL, TLS_RBL_WNB, TLS_RNB_WBL, TLS_RNB_WNB, XrdTlsSocketImpl::tlsctx, XrdTlsSocketImpl::traceID, and XrdTlsContext::x509Verify().

Referenced by XrdTlsSocket(), and XrdLinkXeq::setTLS().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ NeedHandShake()

bool XrdTlsSocket::NeedHandShake ( )
Returns
: true if the TLS/SSL session is not established yet, false otherwise

Definition at line 853 of file XrdTlsSocket.cc.

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 }

References XrdTlsSocketImpl::fatal, XrdTlsSocketImpl::hsDone, XrdTlsSocketImpl::isSerial, XrdSysMutexHelper::Lock(), XrdTlsSocketImpl::ssl, and XrdTlsSocketImpl::sslMutex.

Referenced by XrdCl::Tls::Connect(), XrdCl::Tls::Read(), and XrdCl::Tls::Send().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ Peek()

XrdTls::RC XrdTlsSocket::Peek ( char * buffer,
size_t size,
int & bytesPeek )

Peek at the TLS connection data. If necessary, a handshake will be done.

Parameters
buffer- Pointer to buffer to hold the data.
size- The size of the buffer in bytes.
bytesPeek- Number of bytes placed in the buffer, if successful.
Returns
TLS_AOK if the operation was successful; otherwise the appropraite return code indicating the problem.

Definition at line 542 of file XrdTlsSocket.cc.

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 }
#define DBG_SIO(y)
static const int dbgSIO
Turn debugging in for socket I/O.
Definition XrdTls.hh:102

References XrdTlsSocketImpl::cAttr, DBG_SIO, XrdTls::dbgSIO, EPNAME, XrdTlsSocketImpl::fatal, XrdTlsSocketImpl::hsDone, XrdTlsSocketImpl::hsNoBlock, XrdTlsSocketImpl::isSerial, XrdSysMutexHelper::Lock(), XrdTlsSocketImpl::ssl, XrdTls::ssl2RC(), XrdTlsSocketImpl::sslMutex, XrdTls::TLS_AOK, and XrdTls::TLS_SYS_Error.

Referenced by XrdLinkXeq::TLS_Peek().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ Pending()

int XrdTlsSocket::Pending ( bool any = true)

Check if data is pending or readable.

Parameters
anyTrue to return in any data is in the queue. False to return the number of processed bytes.
Returns
any = true: 1 is returned if there is data in the queue (processed or not). 0 is returned o/w. any = false: the number of processed bytes that are available. These are not necesarily data bytes. A subsequent read may still return 0.

Definition at line 606 of file XrdTlsSocket.cc.

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}

References XrdTlsSocketImpl::fatal, XrdTlsSocketImpl::isSerial, XrdSysMutexHelper::Lock(), XrdTlsSocketImpl::ssl, and XrdTlsSocketImpl::sslMutex.

Referenced by XrdLinkXeq::TLS_Recv(), and XrdLinkXeq::TLS_RecvAll().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ Read()

XrdTls::RC XrdTlsSocket::Read ( char * buffer,
size_t size,
int & bytesRead )

Read from the TLS connection. If necessary, a handshake will be done.

Parameters
buffer- Pointer to buffer to hold the data.
size- The size of the buffer in bytes.
bytesRead- Number of bytes placed in the buffer, if successful.
Returns
TLS_AOK if the operation was successful; otherwise the appropraite return code indicating the problem.

Definition at line 635 of file XrdTlsSocket.cc.

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 }

References XrdTlsSocketImpl::cAttr, DBG_SIO, XrdTls::dbgSIO, EPNAME, XrdTlsSocketImpl::fatal, XrdTlsSocketImpl::hsNoBlock, XrdTlsSocketImpl::isSerial, XrdSysMutexHelper::Lock(), XrdTlsSocketImpl::ssl, XrdTls::ssl2RC(), XrdTlsSocketImpl::sslMutex, XrdTls::TLS_AOK, and XrdTls::TLS_SYS_Error.

Referenced by XrdCl::Tls::Read(), XrdLinkXeq::TLS_Recv(), and XrdLinkXeq::TLS_Recv().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ SetTraceID()

void XrdTlsSocket::SetTraceID ( const char * tid)

Set the trace identifier (used when it's updated).

Parameters
tid- Pointer to trace identifier.

Definition at line 705 of file XrdTlsSocket.cc.

706{
707 if (pImpl) pImpl->traceID = tid;
708}

References XrdTlsSocketImpl::traceID.

Referenced by XrdLinkXeq::setID().

+ Here is the caller graph for this function:

◆ Shutdown()

void XrdTlsSocket::Shutdown ( XrdTlsSocket::SDType sdType = sdImmed)

Definition at line 714 of file XrdTlsSocket.cc.

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}
static void Emsg(const char *tid, const char *msg=0, bool flush=true)
Definition XrdTls.cc:104

References DBG_SOK, XrdTls::Emsg(), eMsg, EPNAME, XrdTlsSocketImpl::fatal, XrdTlsSocketImpl::isSerial, XrdSysMutexHelper::Lock(), sdForce, sdWait, XrdTlsSocketImpl::sFD, XrdTlsSocketImpl::ssl, XrdTlsSocketImpl::sslMutex, and XrdTlsSocketImpl::traceID.

Referenced by ~XrdTlsSocket(), Accept(), XrdLinkXeq::Close(), XrdLinkXeq::setTLS(), and XrdCl::Tls::Shutdown().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ Version()

const char * XrdTlsSocket::Version ( )
Returns
The TLS version number being used.

Definition at line 892 of file XrdTlsSocket.cc.

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 }

References XrdTlsSocketImpl::ssl.

Referenced by XrdLinkXeq::verTLS().

+ Here is the caller graph for this function:

◆ Write()

XrdTls::RC XrdTlsSocket::Write ( const char * buffer,
size_t size,
int & bytesOut )

Write to the TLS connection. If necessary, a handshake will be done.

Parameters
buffer- Pointer to buffer holding the data.
size- The size of the data to write.
bytesOut- Number of bytes actually written, if successful.
Returns
TLS_AOK if the operation was successful; otherwise the appropraite return code indicating the problem.

Definition at line 782 of file XrdTlsSocket.cc.

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}

References XrdTlsSocketImpl::cAttr, DBG_SIO, XrdTls::dbgSIO, EPNAME, XrdTlsSocketImpl::fatal, XrdTlsSocketImpl::hsNoBlock, XrdTlsSocketImpl::isSerial, XrdSysMutexHelper::Lock(), XrdTlsSocketImpl::ssl, XrdTls::ssl2RC(), XrdTlsSocketImpl::sslMutex, XrdTls::TLS_AOK, and XrdTls::TLS_SYS_Error.

Referenced by XrdCl::Tls::Send(), XrdLinkXeq::TLS_Send(), XrdLinkXeq::TLS_Send(), and XrdLinkXeq::TLS_Write().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

The documentation for this class was generated from the following files: