XRootD
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. More...
 
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. More...
 
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.
Definition: XrdTlsSocket.hh:53
@ TLS_HS_NOBLK
Do not block during handshake.
Definition: XrdTlsSocket.hh:54

◆ 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 {
45  TLS_RNB_WNB,
46  TLS_RNB_WBL,
47  TLS_RBL_WNB,
49 };
@ TLS_RNB_WBL
Non-blocking read blocking write.
Definition: XrdTlsSocket.hh:46
@ TLS_RBL_WNB
blocking read non-blocking write
Definition: XrdTlsSocket.hh:47
@ TLS_RBL_WBL
blocking read blocking write
Definition: XrdTlsSocket.hh:48
@ TLS_RNB_WNB
Non-blocking read non-blocking write.
Definition: XrdTlsSocket.hh:45

◆ 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.
Definition: XrdTlsSocket.cc:56

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 //
181 do{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");
192  return XrdTls::TLS_VER_Error;
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;
237  return XrdTls::TLS_SYS_Error;
238 }
#define EPNAME(x)
Definition: XrdBwmTrace.hh:56
int fcntl(int fd, int cmd,...)
const char * XrdSysE2T(int errcode)
Definition: XrdSysE2T.cc:104
#define DBG_SOK(y)
Definition: XrdTlsTrace.hh:43
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.
Definition: XrdTlsSocket.cc:63
bool hsNoBlock
Handshake handling nonblocking if true.
Definition: XrdTlsSocket.cc:65
int sFD
Associated file descriptor (never closed)
Definition: XrdTlsSocket.cc:58
char cAttr
Connection attributes.
Definition: XrdTlsSocket.cc:64

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 //
275 do{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;
303  return XrdTls::TLS_SYS_Error;
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  }
324  return XrdTls::TLS_HNV_Error;
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)
Definition: XrdTlsNotary.cc:56
@ TLS_HNV_Error
A hostname validation error occuured.
Definition: XrdTls.hh:44
bool hsDone
True if the handshake has completed.
Definition: XrdTlsSocket.cc:60

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().

+ Here is the call 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.
Definition: XrdTlsSocket.cc:55

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.
Definition: XrdTlsSocket.cc:54
bool isSerial
True if calls must be serialized.
Definition: XrdTlsSocket.cc:66

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 }
if(Avsz)
static const uint64_t hsto
Mask to isolate the hsto.
void * Session()
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.
Definition: XrdTlsSocket.cc:62
char fatal
!0 if fatal error prevents shutdown call
Definition: XrdTlsSocket.cc:61
const char * traceID
Trace identifier.
Definition: XrdTlsSocket.cc:57
int hsWait
Maximum amount of time to wait for handshake.
Definition: XrdTlsSocket.cc:59

References XrdTlsSocketImpl::cAttr, XrdTlsSocketImpl::cOpts, XrdTlsContext::dnsok, XrdTlsSocketImpl::fatal, fcntl(), XrdTlsContext::GetParams(), XrdTlsSocketImpl::hsDone, XrdTlsSocketImpl::hsNoBlock, XrdTlsContext::hsto, XrdTlsSocketImpl::hsWait, if(), 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.

+ Here is the call 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  //
599  return XrdTls::TLS_SYS_Error;
600  }
#define DBG_SIO(y)
Definition: XrdTlsTrace.hh:47
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 
698  return XrdTls::TLS_SYS_Error;
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 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(), and XrdLinkXeq::setTLS().

+ 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 
846  return XrdTls::TLS_SYS_Error;
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 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: