XRootD
XrdSecProtect Class Reference

#include <XrdSecProtect.hh>

+ Collaboration diagram for XrdSecProtect:

Public Member Functions

virtual ~XrdSecProtect ()
 Destructor. More...
 
virtual void Delete ()
 Delete this object. Use this method as opposed to operator delete. More...
 
virtual int Secure (SecurityRequest *&newreq, ClientRequest &thereq, const char *thedata)
 
virtual const char * Verify (SecurityRequest &secreq, ClientRequest &thereq, const char *thedata)
 

Public Attributes

bool(XrdSecProtect::* Need2Secure )(ClientRequest &thereq)
 

Protected Member Functions

 XrdSecProtect (XrdSecProtocol *aprot, XrdSecProtect &pRef, bool edok=true)
 
 XrdSecProtect (XrdSecProtocol *aprot=0, bool edok=true)
 
void SetProtection (const ServerResponseReqs_Protocol &inReqs)
 

Friends

class XrdSecProtector
 

Detailed Description

Definition at line 55 of file XrdSecProtect.hh.

Constructor & Destructor Documentation

◆ ~XrdSecProtect()

virtual XrdSecProtect::~XrdSecProtect ( )
inlinevirtual

Destructor.

Definition at line 132 of file XrdSecProtect.hh.

132 {}

◆ XrdSecProtect() [1/2]

XrdSecProtect::XrdSecProtect ( XrdSecProtocol aprot = 0,
bool  edok = true 
)
inlineprotected

Definition at line 136 of file XrdSecProtect.hh.

137  : Need2Secure(&XrdSecProtect::Screen),
138  authProt(aprot), secVec(0), lastSeqno(1),
139  edOK(edok), secVerData(false)
140  {}
bool(XrdSecProtect::* Need2Secure)(ClientRequest &thereq)

◆ XrdSecProtect() [2/2]

XrdSecProtect::XrdSecProtect ( XrdSecProtocol aprot,
XrdSecProtect pRef,
bool  edok = true 
)
inlineprotected

Definition at line 142 of file XrdSecProtect.hh.

144  : Need2Secure(&XrdSecProtect::Screen),
145  authProt(aprot), secVec(pRef.secVec),
146  lastSeqno(0), edOK(edok),
147  secVerData(pRef.secVerData) {}

Member Function Documentation

◆ Delete()

virtual void XrdSecProtect::Delete ( )
inlinevirtual

Delete this object. Use this method as opposed to operator delete.

Definition at line 64 of file XrdSecProtect.hh.

64 {delete this;}

◆ Secure()

int XrdSecProtect::Secure ( SecurityRequest *&  newreq,
ClientRequest thereq,
const char *  thedata 
)
virtual

Secure a request.

Request securement is optional and this call should be gaurded by an if statement to avoid securing requests that need not be secured as follows:

if (NEED2SECURE(<protP>)(thereq)) result = <protP>->Secure(....); else result = 0;

Modify the above to your particuar needs but gaurd the call!

Parameters
newreqA reference to a pointer where the new request, if needed, will be placed. The new request will consist of a kXR_sigver request followed by hash. The request buffer must be freed using free() when it is no longer needed.
thereqReference to the client request header/body that needs to be secured. The request must be in network byte order.
thedataThe request data whose length resides in theReq.dlen. If thedata is nil but thereq.dlen is not zero then the request data must follow the request header in the thereq buffer.
Returns
<0 An error occurred and the return value is -errno.
>0 The length of the new request whose pointer is in newreq. This is the nuber of bytes that must be sent.

Definition at line 239 of file XrdSecProtect.cc.

242 {
243  static const ClientSigverRequest initSigVer = {{0,0}, htons(kXR_sigver),
244  0, kXR_secver_0, 0, 0,
245  kXR_SHA256, {0, 0, 0}, 0
246  };
247  struct buffHold {XrdSecReq *P;
248  XrdSecBuffer *bP;
249  buffHold() : P(0), bP(0) {}
250  ~buffHold() {if (P) free(P); if (bP) delete bP;}
251  };
252  static const int iovNum = 3;
253  struct iovec iov[iovNum];
254  buffHold myReq;
255  kXR_unt64 mySeq;
256  const char *sigBuff, *payload = thedata;
257  unsigned char secHash[SHA256_DIGEST_LENGTH];
258  int sigSize, n, newSize, rc, paysize = 0;
259  bool nodata = false;
260 
261 // Generate a new sequence number
262 //
263  mySeq = nextSeqno++;
264  mySeq = htonll(mySeq);
265 
266 // Determine if we are going to sign the payload and its location
267 //
268  if (thereq.header.dlen)
269  {kXR_unt16 reqid = htons(thereq.header.requestid);
270  paysize = ntohl(thereq.header.dlen);
271  if (!payload) payload = ((char *)&thereq) + sizeof(ClientRequest);
272  if (reqid == kXR_write || reqid == kXR_pgwrite) n = (secVerData ? 3 : 2);
273  else n = 3;
274  } else n = 2;
275 
276 // Fill out the iovec
277 //
278  iov[0].iov_base = (char *)&mySeq;
279  iov[0].iov_len = sizeof(mySeq);
280  iov[1].iov_base = (char *)&thereq;
281  iov[1].iov_len = sizeof(ClientRequest);
282  if (n < 3) nodata = true;
283  else {iov[2].iov_base = (char *)payload;
284  iov[2].iov_len = paysize;
285  }
286 
287 // Compute the hash
288 //
289  if (!GetSHA2(secHash, iov, n)) return -EDOM;
290 
291 // Now encrypt the hash
292 //
293  if (edOK)
294  {rc = authProt->Encrypt((const char *)secHash,sizeof(secHash),&myReq.bP);
295  if (rc < 0) return rc;
296  sigSize = myReq.bP->size;
297  sigBuff = myReq.bP->buffer;
298  } else {
299  sigSize = sizeof(secHash);
300  sigBuff = (char *)secHash;
301  }
302 
303 // Allocate a new request object
304 //
305  newSize = sizeof(SecurityRequest) + sigSize;
306  myReq.P = (XrdSecReq *)malloc(newSize);
307  if (!myReq.P) return -ENOMEM;
308 
309 // Setup the security request (we only support signing)
310 //
311  memcpy(&(myReq.P->secReq), &initSigVer, sizeof(ClientSigverRequest));
312  memcpy(&(myReq.P->secReq.header.streamid ), thereq.header.streamid,
313  sizeof(myReq.P->secReq.header.streamid));
314  memcpy(&(myReq.P->secReq.sigver.expectrid),&thereq.header.requestid,
315  sizeof(myReq.P->secReq.sigver.expectrid));
316  myReq.P->secReq.sigver.seqno = mySeq;
317  if (nodata) myReq.P->secReq.sigver.flags |= kXR_nodata;
318  myReq.P->secReq.sigver.dlen = htonl(sigSize);
319 
320 // Append the signature to the request
321 //
322  memcpy(&(myReq.P->secSig), sigBuff, sigSize);
323 
324 // Return pointer to he security request and its size
325 //
326  newreq = &(myReq.P->secReq); myReq.P = 0;
327  return newSize;
328 }
kXR_char streamid[2]
Definition: XProtocol.hh:158
struct ClientRequestHdr header
Definition: XProtocol.hh:887
kXR_unt16 requestid
Definition: XProtocol.hh:159
@ kXR_sigver
Definition: XProtocol.hh:142
@ kXR_write
Definition: XProtocol.hh:132
@ kXR_pgwrite
Definition: XProtocol.hh:139
@ kXR_nodata
Definition: XProtocol.hh:774
#define kXR_secver_0
Definition: XProtocol.hh:1188
kXR_int32 dlen
Definition: XProtocol.hh:161
@ kXR_SHA256
Definition: XProtocol.hh:767
unsigned long long kXR_unt64
Definition: XPtypes.hh:99
unsigned short kXR_unt16
Definition: XPtypes.hh:67
virtual int Encrypt(const char *inbuff, int inlen, XrdSecBuffer **outbuff)
Generic structure to pass security information back and forth.

References ClientRequestHdr::dlen, ClientRequest::header, kXR_nodata, kXR_pgwrite, kXR_secver_0, kXR_SHA256, kXR_sigver, kXR_write, ClientRequestHdr::requestid, XrdOucIOVec::size, and ClientRequestHdr::streamid.

Referenced by XrdCl::XRootDTransport::GetSignature().

+ Here is the caller graph for this function:

◆ SetProtection()

void XrdSecProtect::SetProtection ( const ServerResponseReqs_Protocol inReqs)
protected

Definition at line 334 of file XrdSecProtect.cc.

335 {
336  unsigned int lvl, vsz;
337 
338 // Check for no security, the simlplest case
339 //
340  if (inReqs.secvsz == 0 && inReqs.seclvl == 0)
341  {memset(&myReqs, 0, sizeof(myReqs));
342  secVec = 0;
343  secVerData = false;
344  return;
345  }
346 
347 // Precheck the security level
348 //
349  lvl = inReqs.seclvl;
350  if (lvl > kXR_secPedantic) lvl = kXR_secPedantic;
351 
352 // Perform the default setup (the usual case)
353 //
354  secVec = secTable.Vec[lvl-1];
355  myReqs.seclvl = lvl;
356  myReqs.secvsz = 0;
357  myReqs.secver = kXR_secver_0;
358  myReqs.secopt = inReqs.secopt;
359 
360 // Set options
361 //
362  secVerData = (inReqs.secopt & kXR_secOData) != 0;
363 
364 // Create a modified vectr if there are overrides
365 //
366  if (inReqs.secvsz != 0)
367  {const ServerResponseSVec_Protocol *urVec = &inReqs.secvec;
368  memcpy(myVec, secVec, maxRIX);
369  vsz = inReqs.secvsz;
370  for (unsigned int i = 0; i < vsz; i++, urVec++)
371  {if (urVec->reqindx < maxRIX)
372  {if (urVec->reqsreq > kXR_signNeeded)
373  myVec[urVec->reqindx] = kXR_signNeeded;
374  else myVec[urVec->reqindx] = urVec->reqsreq;
375  }
376  }
377  secVec = myVec;
378  }
379 }
ServerResponseSVec_Protocol secvec
Definition: XProtocol.hh:1156
#define kXR_secOData
Definition: XProtocol.hh:1168
#define kXR_secPedantic
Definition: XProtocol.hh:1177
#define kXR_signNeeded
Definition: XProtocol.hh:1183

References kXR_secOData, kXR_secPedantic, kXR_secver_0, kXR_signNeeded, ServerResponseSVec_Protocol::reqindx, ServerResponseSVec_Protocol::reqsreq, ServerResponseReqs_Protocol::seclvl, ServerResponseReqs_Protocol::secopt, ServerResponseReqs_Protocol::secvec, and ServerResponseReqs_Protocol::secvsz.

Referenced by XrdSecProtector::Config(), and XrdSecProtector::New4Client().

+ Here is the caller graph for this function:

◆ Verify()

const char * XrdSecProtect::Verify ( SecurityRequest secreq,
ClientRequest thereq,
const char *  thedata 
)
virtual

Verify that a request was properly secured.

Parameters
secreqA reference to the kXR_sigver request followed by whatever data was sent (normally an encrypted verification hash). All but the request code must be in network byte order.
thereqReference to the client request header/body that needs to be verified. The request must be in network byte order.
thedataThe request data whose length resides in theReq.dlen.
Returns
Upon success zero is returned. Otherwise a pointer to a null delimited string describing the problem is returned.

Definition at line 385 of file XrdSecProtect.cc.

389 {
390  struct buffHold {XrdSecBuffer *bP;
391  buffHold() : bP(0) {}
392  ~buffHold() {if (bP) delete bP;}
393  };
394  static const int iovNum = 3;
395  struct iovec iov[iovNum];
396  buffHold myReq;
397  unsigned char *inHash, secHash[SHA256_DIGEST_LENGTH];
398  int dlen, n, rc;
399 
400 // First check for replay attacks. The incoming sequence number must be greater
401 // the previous one we have seen. Since it is in network byte order we can use
402 // a simple byte for byte compare (no need for byte swapping).
403 //
404  if (memcmp(&lastSeqno, &secreq.sigver.seqno, sizeof(lastSeqno)) >= 0)
405  return "Incorrect signature sequence";
406 
407 // Do basic verification for this request
408 //
409  if (memcmp(secreq.header.streamid, thereq.header.streamid,
410  sizeof(secreq.header.streamid)))
411  return "Signature streamid mismatch";
412  if (secreq.sigver.expectrid != thereq.header.requestid)
413  return "Signature requestid mismatch";
414  if (secreq.sigver.version != kXR_secver_0)
415  return "Unsupported signature version";
416  if ((secreq.sigver.crypto & kXR_HashMask) != kXR_SHA256)
417  return "Unsupported signature hash";
418  if (secreq.sigver.crypto & kXR_rsaKey)
419  return "Unsupported signature key";
420 
421 // Now get the hash information
422 //
423  dlen = ntohl(secreq.header.dlen);
424  inHash = ((unsigned char *)&secreq)+sizeof(SecurityRequest);
425 
426 // Now decrypt the hash
427 //
428  if (edOK)
429  {rc = authProt->Decrypt((const char *)inHash, dlen, &myReq.bP);
430  if (rc < 0) return XrdSysE2T(-rc);
431  if (myReq.bP->size != (int)sizeof(secHash))
432  return "Invalid signature hash length";
433  inHash = (unsigned char *)myReq.bP->buffer;
434  } else {
435  if (dlen != (int)sizeof(secHash))
436  return "Invalid signature hash length";
437  }
438 
439 // Fill out the iovec to recompute the hash
440 //
441  iov[0].iov_base = (char *)&secreq.sigver.seqno;
442  iov[0].iov_len = sizeof(secreq.sigver.seqno);
443  iov[1].iov_base = (char *)&thereq;
444  iov[1].iov_len = sizeof(ClientRequest);
445  if (thereq.header.dlen == 0 || secreq.sigver.flags & kXR_nodata) n = 2;
446  else {iov[2].iov_base = (char *)thedata;
447  iov[2].iov_len = ntohl(thereq.header.dlen);
448  n = 3;
449  }
450 
451 // Compute the hash
452 //
453  if (!GetSHA2(secHash, iov, n))
454  return "Signature hash computation failed";
455 
456 // Compare this hash with the hash we were given
457 //
458  if (memcmp(secHash, inHash, sizeof(secHash)))
459  return "Signature hash mismatch";
460 
461 // This request has been verified (update the seqno)
462 //
463  lastSeqno = secreq.sigver.seqno;
464  return 0;
465 }
struct ClientRequestHdr header
Definition: XProtocol.hh:923
struct ClientSigverRequest sigver
Definition: XProtocol.hh:924
kXR_unt16 expectrid
Definition: XProtocol.hh:785
@ kXR_HashMask
Definition: XProtocol.hh:768
@ kXR_rsaKey
Definition: XProtocol.hh:769
const char * XrdSysE2T(int errcode)
Definition: XrdSysE2T.cc:104
virtual int Decrypt(const char *inbuff, int inlen, XrdSecBuffer **outbuff)

References ClientSigverRequest::crypto, ClientRequestHdr::dlen, ClientSigverRequest::expectrid, ClientSigverRequest::flags, SecurityRequest::header, ClientRequest::header, kXR_HashMask, kXR_nodata, kXR_rsaKey, kXR_secver_0, kXR_SHA256, ClientRequestHdr::requestid, ClientSigverRequest::seqno, SecurityRequest::sigver, ClientRequestHdr::streamid, ClientSigverRequest::version, and XrdSysE2T().

Referenced by XrdXrootdProtocol::Process2().

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

Friends And Related Function Documentation

◆ XrdSecProtector

friend class XrdSecProtector
friend

Definition at line 58 of file XrdSecProtect.hh.

Member Data Documentation

◆ Need2Secure

bool(XrdSecProtect::* XrdSecProtect::Need2Secure) (ClientRequest &thereq)

Test whether or not a request needs to be secured. This method pointer should only be invoked via the NEED2SECURE macro (see above).

Parameters
thereqReference to the request header/body in network byte order.
Returns
false - request need not be secured (equals false).
true - request needs to be secured.

Definition at line 76 of file XrdSecProtect.hh.


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