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 130 of file XrdTlsSocket.cc.

134  : pImpl( new XrdTlsSocketImpl() )
135 {
136 
137 // Simply initialize this object and throw an exception if it fails
138 //
139  const char *eMsg = Init(ctx, sfd, rwm, hsm, isClient, serial);
140  if (eMsg) throw std::invalid_argument( eMsg );
141 }
#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 121 of file XrdTlsSocket.cc.

121  : pImpl( new XrdTlsSocketImpl() )
122 {
123 
124 }

◆ ~XrdTlsSocket()

XrdTlsSocket::~XrdTlsSocket ( )

Destructor.

Definition at line 147 of file XrdTlsSocket.cc.

148 {
149  if (pImpl->ssl) Shutdown(sdForce);
150  delete pImpl;
151 }
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 157 of file XrdTlsSocket.cc.

158 {
159  EPNAME("Accept");
160  int rc, ssler;
161  bool wOK, aOK = true;
162 
163 // Make sure there is a context here
164 //
165  if (pImpl->ssl == 0)
166  {AcceptEMsg(eWhy, "TLS socket has no context");
168  }
169  undoImpl ImplTracker(pImpl);
170 
171 // Do some tracing
172 //
173  DBG_SOK("Accepting a TLS connection...");
174 
175 // An accept may require several tries, so we do that here.
176 //
177 do{if ((rc = SSL_accept( pImpl->ssl )) > 0)
178  {if (pImpl->cOpts & xVerify)
179  {X509 *theCert = SSL_get_peer_certificate(pImpl->ssl);
180  if (!theCert)
181  {AcceptEMsg(eWhy, "x509 certificate is missing");
183  }
184  X509_free(theCert);
185  rc = SSL_get_verify_result(pImpl->ssl);
186  if (rc != X509_V_OK)
187  {AcceptEMsg(eWhy, "x509 certificate verification failed");
188  return XrdTls::TLS_VER_Error;
189  }
190  }
191  ImplTracker.KeepImpl();
192 
193 // Reset the socket to blocking mode if we need to. Note that we have to brute
194 // force this on the socket as setting a BIO after accept has no effect. We
195 // also tell ssl that we want to block on a handshake from now on.
196 //
197  if (pImpl->cAttr & acc2Block)
198 // BIO_set_nbio(SSL_get_rbio(pImpl->ssl), 0); *Does not work after accept*
199  {int eNO = errno;
200  int flags = fcntl(pImpl->sFD, F_GETFL, 0);
201  flags &= ~O_NONBLOCK;
202  fcntl(pImpl->sFD, F_SETFL, flags);
203  SSL_set_mode(pImpl->ssl, SSL_MODE_AUTO_RETRY);
204  errno = eNO;
205  }
206  return XrdTls::TLS_AOK;
207  }
208 
209  // Get the actual SSL error code.
210  //
211  ssler = Diagnose("TLS_Accept", rc, XrdTls::dbgSOK);
212 
213  // Check why we did not succeed. We may be able to recover.
214  //
215  if (ssler != SSL_ERROR_WANT_READ && ssler != SSL_ERROR_WANT_WRITE) {
216  if(ssler == SSL_ERROR_SSL){
217  //In the case the accept does have an error related to OpenSSL,
218  //shutdown the TLSSocket in case the link associated to that connection
219  //is re-used
220  Shutdown();
221  }
222  aOK = false; break;
223  }
224 
225  if (pImpl->hsNoBlock) return XrdTls::ssl2RC(ssler);
226 
227  } while((wOK = Wait4OK(ssler == SSL_ERROR_WANT_READ)));
228 
229 // If we are here then we got an error
230 //
231  AcceptEMsg(eWhy, (!aOK ? Err2Text(ssler).c_str() : XrdSysE2T(errno)));
232  errno = ECONNABORTED;
233  return XrdTls::TLS_SYS_Error;
234 }
#define EPNAME(x)
Definition: XrdBwmTrace.hh:56
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, 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 254 of file XrdTlsSocket.cc.

255 {
256  EPNAME("Connect");
257  int ssler, rc;
258  bool wOK = true, aOK = true;
259 
260 // Setup host verification of a host has been specified. This is a to-do
261 // when we move to new versions of SSL. For now, we use the notary object.
262 //
263 
264 // Do some tracing
265 //
266  DBG_SOK("Connecting to " <<(thehost ? thehost : "unverified host")
267  <<(thehost && pImpl->cOpts & DNSok ? " dnsok" : "" ));
268 
269 // Do the connect.
270 //
271 do{int rc = SSL_connect( pImpl->ssl );
272  if (rc == 1) break;
273 
274  ssler = Diagnose("TLS_Connect", rc, XrdTls::dbgSOK);
275 
276  if (ssler != SSL_ERROR_WANT_READ && ssler != SSL_ERROR_WANT_WRITE)
277  {aOK = false; break;}
278 
279  if (pImpl->hsNoBlock) return XrdTls::ssl2RC(ssler);
280 
281  } while((wOK = Wait4OK(ssler == SSL_ERROR_WANT_READ)));
282 
283 // Check if everything went well. Note that we need to save the errno as
284 // we may be calling external methods that may generate other errors. We
285 //
286  if (!aOK || !wOK)
287  {rc = errno;
288  DBG_SOK("Handshake failed; "<<(!aOK ? Err2Text(ssler) : XrdSysE2T(rc)));
289  if (eWhy)
290  {const char *hName = (thehost ? thehost : "host");
291  *eWhy = "Unable to connect to ";
292  *eWhy += hName;
293  *eWhy += "; ";
294  if (!aOK) *eWhy += Err2Text(ssler);
295  else *eWhy += XrdSysE2T(rc);
296  }
297  if (!aOK) return XrdTls::ssl2RC(ssler);
298  errno = rc;
299  return XrdTls::TLS_SYS_Error;
300  }
301 
302 // Set the hsDone flag!
303 //
304  pImpl->hsDone = bool( SSL_is_init_finished( pImpl->ssl ) );
305 
306 // Validate the host name if so desired. Note that cert verification is
307 // checked by the notary since hostname validation requires it. We currently
308 // do not support dnsOK but doing so just means we need to check the option
309 // and if on, also pass a XrdNetAddrInfo object generated from the hostname.
310 //
311  if (thehost)
312  {const char *eTxt = XrdTlsNotary::Validate(pImpl->ssl, thehost, 0);
313  if (eTxt)
314  {DBG_SOK(thehost << " verification failed; " <<eTxt);
315  if (eWhy)
316  {
317  *eWhy = "Unable to validate "; *eWhy += thehost;
318  *eWhy += "; "; *eWhy += eTxt;
319  }
320  return XrdTls::TLS_HNV_Error;
321  }
322  }
323 
324  DBG_SOK("Connect completed without error.");
325  return XrdTls::TLS_AOK;
326 }
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 332 of file XrdTlsSocket.cc.

333 {
334  return pImpl->tlsctx;
335 }
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 398 of file XrdTlsSocket.cc.

399 {
400  XrdSysMutexHelper mHelper;
401 
402 // Serialize call if need be
403 //
404  if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
405 
406 // If verified certs need to be returned, make sure the certs are verified
407 //
408  if (ver && SSL_get_verify_result(pImpl->ssl) != X509_V_OK) return 0;
409 
410 // Get the certs and return
411 //
412  X509 *pcert = SSL_get_peer_certificate(pImpl->ssl);
413  if (pcert == 0) return 0;
414  return new XrdTlsPeerCerts(pcert, SSL_get_peer_cert_chain(pImpl->ssl));
415 }
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 421 of file XrdTlsSocket.cc.

426 {
427  BIO *rbio, *wbio = 0;
428 
429 // Make sure this connection is not in use if this is a client. Servers are
430 // allowed to throw away the previous setup as they reuse sockets.
431 //
432  if ( pImpl->ssl )
433  {if (isClient) return "TLS I/O: connection is still in use.";
434  else {SSL_free( pImpl->ssl );
435  pImpl->ssl = 0;
436  }
437  }
438 
439 // Obtain the ssl object at this point.
440 //
441  pImpl->ssl = static_cast<SSL *>(ctx.Session());
442  if (pImpl->ssl == 0) return "TLS I/O: failed to get ssl object.";
443 
444 // Initialze values from the context.
445 //
446  pImpl->tlsctx = &ctx;
447  const XrdTlsContext::CTX_Params *parms = ctx.GetParams();
448  pImpl->hsWait = (parms->opts & XrdTlsContext::hsto) * 1000; // Poll timeout
449  if (ctx.x509Verify()) pImpl->cOpts = xVerify;
450  else pImpl->cOpts = 0;
451  if (parms->opts & XrdTlsContext::dnsok) pImpl->cOpts |= DNSok;
452  pImpl->traceID = tid;
453  pImpl->isClient= isClient;
454  pImpl->isSerial= serial;
455 
456 // Set the ssl object state to correspond to client or server type
457 //
458  if (isClient)
459  {SSL_set_connect_state( pImpl->ssl );
460  pImpl->cAttr = 0;
461  } else {
462  SSL_set_accept_state( pImpl->ssl );
463  pImpl->cAttr = isServer;
464  }
465 
466 // Allocate right number of bio's and initialize them as requested. Note
467 // that when the read and write bios have the same attribue, we use only one.
468 //
469  switch( rwm )
470  {
471  case TLS_RNB_WNB:
472  rbio = BIO_new_socket( sfd, BIO_NOCLOSE );
473  BIO_set_nbio( rbio, 1 );
474  break;
475 
476  case TLS_RNB_WBL:
477  rbio = BIO_new_socket( sfd, BIO_NOCLOSE );
478  BIO_set_nbio( rbio, 1 );
479  wbio = BIO_new_socket( sfd, BIO_NOCLOSE );
480  pImpl->cAttr |= wBlocking;
481  break;
482 
483  case TLS_RBL_WNB:
484  rbio = BIO_new_socket( sfd, BIO_NOCLOSE );
485  wbio = BIO_new_socket( sfd, BIO_NOCLOSE );
486  BIO_set_nbio( wbio, 1 );
487  pImpl->cAttr |= rBlocking;
488  break;
489 
490  case TLS_RBL_WBL:
491  rbio = BIO_new_socket( sfd, BIO_NOCLOSE );
492  pImpl->cAttr |= (rBlocking | wBlocking);
493  break;
494 
495  default:
496  return "TLS I/O: invalid TLS rw mode."; break;
497  }
498 
499 // Set correct handshake mode
500 //
501  if (hsm) pImpl->hsNoBlock = false;
502  else pImpl->hsNoBlock = true;
503 
504 // Reset the handshake and fatal error indicators
505 //
506  pImpl->hsDone = false;
507  pImpl->fatal = 0;
508 
509 // The glories of OpenSSL require that we do some fancy footwork with the
510 // handshake timeout. If there is one and this is a server and the server
511 // wants blocking reads, we initially set the socket as non-blocking as the
512 // bio's can handle it. Then after the accept we set it back to blocking mode.
513 // Note: doing this via the bio causes the socket to remain nonblocking. yech!
514 //
515  if (pImpl->hsWait && !hsm && pImpl->cAttr & rBlocking)
516  {int flags = fcntl(sfd, F_GETFL, 0);
517  flags |= O_NONBLOCK;
518  fcntl(sfd, F_SETFL, flags);
519  pImpl->cAttr |= acc2Block;
520  }
521 
522 // Finally attach the bios to the ssl object. When the ssl object is freed
523 // the bios will be freed as well.
524 //
525  pImpl->sFD = sfd;
526  if (wbio == 0) wbio = rbio;
527  SSL_set_bio( pImpl->ssl, rbio, wbio );
528 
529 // All done. The caller will do an Accept() or Connect() afterwards.
530 //
531  return 0;
532 }
if(Avsz)
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.
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, 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 844 of file XrdTlsSocket.cc.

845  {
846  XrdSysMutexHelper mHelper;
847 
848  //------------------------------------------------------------------------
849  // Return an error if this socket received a fatal error as OpenSSL will
850  // SEGV when called after such an error. So, return something reasonable.
851  // Technically, we don't need to serialize this because nothing get
852  // modified. We do so anyway out of abundance of caution.
853  //------------------------------------------------------------------------
854 
855  if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
856  if (pImpl->fatal) return false;
857  pImpl->hsDone = bool( SSL_is_init_finished( pImpl->ssl ) );
858  return !pImpl->hsDone;
859  }

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 538 of file XrdTlsSocket.cc.

539  {
540  EPNAME("Peek");
541  XrdSysMutexHelper mHelper;
542  int ssler;
543 
544  //------------------------------------------------------------------------
545  // Serialize call if need be
546  //------------------------------------------------------------------------
547 
548  if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
549 
550  //------------------------------------------------------------------------
551  // Return an error if this socket received a fatal error as OpenSSL will
552  // SEGV when called after such an error.
553  //------------------------------------------------------------------------
554 
555  if (pImpl->fatal)
556  {DBG_SIO("Failing due to previous error, fatal=" << (int)pImpl->fatal);
557  return (XrdTls::RC)pImpl->fatal;
558  }
559 
560  //------------------------------------------------------------------------
561  // If necessary, SSL_read() will negotiate a TLS/SSL session, so we don't
562  // have to explicitly call SSL_connect or SSL_do_handshake.
563  //------------------------------------------------------------------------
564 
565  do{int rc = SSL_peek( pImpl->ssl, buffer, size );
566 
567  // Note that according to SSL whenever rc > 0 then SSL_ERROR_NONE can be
568  // returned to the caller. So, we short-circuit all the error handling.
569  //
570  if( rc > 0 )
571  {bytesPeek = rc;
572  return XrdTls::TLS_AOK;
573  }
574 
575  // We have a potential error. Get the SSL error code and whether or
576  // not the handshake actually is finished (semi-accurate)
577  //
578  pImpl->hsDone = bool( SSL_is_init_finished( pImpl->ssl ) );
579  ssler = Diagnose("TLS_Peek", rc, XrdTls::dbgSIO);
580 
581  // If the error isn't due to blocking issues, we are done.
582  //
583  if (ssler != SSL_ERROR_WANT_READ && ssler != SSL_ERROR_WANT_WRITE)
584  return XrdTls::ssl2RC(ssler);
585 
586  // If the caller is non-blocking, the return the issue. Otherwise, block.
587  //
588  if ((pImpl->hsNoBlock && NeedHS()) || !(pImpl->cAttr & rBlocking))
589  return XrdTls::ssl2RC(ssler);
590 
591  } while(Wait4OK(ssler == SSL_ERROR_WANT_READ));
592 
593  // Return failure as the Wait failed.
594  //
595  return XrdTls::TLS_SYS_Error;
596  }
#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 602 of file XrdTlsSocket.cc.

603 {
604  XrdSysMutexHelper mHelper;
605 
606  //------------------------------------------------------------------------
607  // Return an error if this socket received a fatal error as OpenSSL will
608  // SEGV when called after such an error. So, return something reasonable.
609  //------------------------------------------------------------------------
610 
611  if (pImpl->fatal) return 0;
612 
613  //------------------------------------------------------------------------
614  // Serialize call if need be
615  //------------------------------------------------------------------------
616 
617  if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
618 
619  return any ? SSL_has_pending(pImpl->ssl) : SSL_pending(pImpl->ssl);
620 }

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 626 of file XrdTlsSocket.cc.

627 {
628  EPNAME("Read");
629  XrdSysMutexHelper mHelper;
630  int ssler;
631 
632  //------------------------------------------------------------------------
633  // Serialize call if need be
634  //------------------------------------------------------------------------
635 
636  if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
637 
638  //------------------------------------------------------------------------
639  // Return an error if this socket received a fatal error as OpenSSL will
640  // SEGV when called after such an error.
641  //------------------------------------------------------------------------
642 
643  if (pImpl->fatal)
644  {DBG_SIO("Failing due to previous error, fatal=" << (int)pImpl->fatal);
645  return (XrdTls::RC)pImpl->fatal;
646  }
647 
648  //------------------------------------------------------------------------
649  // If necessary, SSL_read() will negotiate a TLS/SSL session, so we don't
650  // have to explicitly call SSL_connect or SSL_do_handshake.
651  //------------------------------------------------------------------------
652 
653  do{int rc = SSL_read( pImpl->ssl, buffer, size );
654 
655  // Note that according to SSL whenever rc > 0 then SSL_ERROR_NONE can be
656  // returned to the caller. So, we short-circuit all the error handling.
657  //
658  if( rc > 0 )
659  {bytesRead = rc;
660  DBG_SIO(rc <<" out of " <<size <<" bytes.");
661  return XrdTls::TLS_AOK;
662  }
663 
664  // We have a potential error. Get the SSL error code and whether or
665  // not the handshake actually is finished (semi-accurate)
666  //
667  ssler = Diagnose("TLS_Read", rc, XrdTls::dbgSIO);
668  if (ssler == SSL_ERROR_NONE)
669  {bytesRead = 0;
670  DBG_SIO("0 out of " <<size <<" bytes.");
671  return XrdTls::TLS_AOK;
672  }
673 
674  // If the error isn't due to blocking issues, we are done.
675  //
676  if (ssler != SSL_ERROR_WANT_READ && ssler != SSL_ERROR_WANT_WRITE)
677  return XrdTls::ssl2RC(ssler);
678 
679  // If the caller is non-blocking for reads, return the issue. Otherwise,
680  // block for the caller.
681  //
682  if ((pImpl->hsNoBlock && NeedHS()) || !(pImpl->cAttr & rBlocking))
683  return XrdTls::ssl2RC(ssler);
684 
685  // Wait until we can read again.
686 
687  } while(Wait4OK(ssler == SSL_ERROR_WANT_READ));
688 
689  return XrdTls::TLS_SYS_Error;
690  }

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 696 of file XrdTlsSocket.cc.

697 {
698  if (pImpl) pImpl->traceID = tid;
699 }

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 705 of file XrdTlsSocket.cc.

706 {
707  EPNAME("Shutdown");
708  XrdSysMutexHelper mHelper;
709  const char *how;
710  int sdMode, rc;
711 
712 // Make sure we have an ssl object.
713 //
714  if (pImpl->ssl == 0) return;
715 
716 // While we do not need to technically serialize here, we're being conservative
717 //
718  if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
719 
720 // Perform shutdown as needed. This is required before freeing the ssl object.
721 // If we previously encountered a SYSCALL or SSL error, shutdown is prohibited!
722 // The following code is patterned after code in the public TomCat server.
723 //
724  if (!pImpl->fatal)
725  {switch(sdType)
726  {case sdForce: // Forced shutdown which violate TLS standard!
727  sdMode = SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN;
728  how = "forced";
729  break;
730  case sdWait: // Wait for client acknowledgement
731  sdMode = 0;
732  how = "clean";
733  break;
734  default: // Fast shutdown, don't wait for ack (compliant)
735  sdMode = SSL_RECEIVED_SHUTDOWN;
736  how = "fast";
737  break;
738  }
739 
740  DBG_SOK("Doing " <<how <<" shutdown.");
741  SSL_set_shutdown(pImpl->ssl, sdMode);
742 
743  for (int i = 0; i < 4; i++)
744  {rc = SSL_shutdown( pImpl->ssl );
745  if (rc > 0) break;
746  if (rc < 0)
747  {rc = SSL_get_error( pImpl->ssl, rc );
748  if (rc == SSL_ERROR_WANT_READ || rc == SSL_ERROR_WANT_WRITE)
749  {if (Wait4OK(rc == SSL_ERROR_WANT_READ)) continue;
750  rc = SSL_ERROR_SYSCALL;
751  }
752  char msgBuff[512];
753  std::string eMsg = Err2Text(rc);
754  snprintf(msgBuff, sizeof(msgBuff),
755  "FD %d TLS shutdown failed; %s.\n",pImpl->sFD,eMsg.c_str());
756  XrdTls::Emsg(pImpl->traceID, msgBuff, true);
757  break;
758  }
759  }
760  }
761 
762 // Now free the ssl object which will free all the BIO's associated with it
763 //
764  SSL_free( pImpl->ssl );
765  pImpl->ssl = 0;
766  pImpl->fatal = 0;
767 }
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 883 of file XrdTlsSocket.cc.

884  {
885  // This call modifies nothing nor does it depend on modified data once the
886  // connection is esablished and doesn't need serialization.
887  //
888  return SSL_get_version(pImpl->ssl);
889  }

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 773 of file XrdTlsSocket.cc.

775 {
776  EPNAME("Write");
777  XrdSysMutexHelper mHelper;
778  int ssler;
779 
780  //------------------------------------------------------------------------
781  // Serialize call if need be
782  //------------------------------------------------------------------------
783 
784  if (pImpl->isSerial) mHelper.Lock(&(pImpl->sslMutex));
785 
786  //------------------------------------------------------------------------
787  // Return an error if this socket received a fatal error as OpenSSL will
788  // SEGV when called after such an error.
789  //------------------------------------------------------------------------
790 
791  if (pImpl->fatal)
792  {DBG_SIO("Failing due to previous error, fatal=" << (int)pImpl->fatal);
793  return (XrdTls::RC)pImpl->fatal;
794  }
795 
796  //------------------------------------------------------------------------
797  // If necessary, SSL_write() will negotiate a TLS/SSL session, so we don't
798  // have to explicitly call SSL_connect or SSL_do_handshake.
799  //------------------------------------------------------------------------
800 
801  do{int rc = SSL_write( pImpl->ssl, buffer, size );
802 
803  // Note that according to SSL whenever rc > 0 then SSL_ERROR_NONE can be
804  // returned to the caller. So, we short-circuit all the error handling.
805  //
806  if (rc > 0)
807  {bytesWritten = rc;
808  DBG_SIO(rc <<" out of " <<size <<" bytes.");
809  return XrdTls::TLS_AOK;
810  }
811 
812  // We have a potential error. Get the SSL error code and whether or
813  // not the handshake actually is finished (semi-accurate)
814  //
815  ssler = Diagnose("TLS_Write", rc, XrdTls::dbgSIO);
816  if (ssler == SSL_ERROR_NONE)
817  {bytesWritten = 0;
818  DBG_SIO(rc <<" out of " <<size <<" bytes.");
819  return XrdTls::TLS_AOK;
820  }
821 
822  // If the error isn't due to blocking issues, we are done.
823  //
824  if (ssler != SSL_ERROR_WANT_READ && ssler != SSL_ERROR_WANT_WRITE)
825  return XrdTls::ssl2RC(ssler);
826 
827  // If the caller is non-blocking for reads, return the issue. Otherwise,
828  // block for the caller.
829  //
830  if ((pImpl->hsNoBlock && NeedHS()) || !(pImpl->cAttr & wBlocking))
831  return XrdTls::ssl2RC(ssler);
832 
833  // Wait unil the write can get restarted
834 
835  } while(Wait4OK(ssler == SSL_ERROR_WANT_READ));
836 
837  return XrdTls::TLS_SYS_Error;
838 }

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: