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

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

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  if (!any) return SSL_pending(pImpl->ssl);
620 #if OPENSSL_VERSION_NUMBER < 0x10100000L
621  return SSL_pending(pImpl->ssl) != 0;
622 #else
623  return SSL_has_pending(pImpl->ssl);
624 #endif
625 }

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

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

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

702 {
703  if (pImpl) pImpl->traceID = tid;
704 }

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

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

889  {
890  // This call modifies nothing nor does it depend on modified data once the
891  // connection is esablished and doesn't need serialization.
892  //
893  return SSL_get_version(pImpl->ssl);
894  }

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

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

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: