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 254 of file XrdSecProtect.cc.

257 {
258  static const ClientSigverRequest initSigVer = {{0,0}, htons(kXR_sigver),
259  0, kXR_secver_0, 0, 0,
260  kXR_SHA256, {0, 0, 0}, 0
261  };
262  struct buffHold {XrdSecReq *P;
263  XrdSecBuffer *bP;
264  buffHold() : P(0), bP(0) {}
265  ~buffHold() {if (P) free(P); if (bP) delete bP;}
266  };
267  static const int iovNum = 3;
268  struct iovec iov[iovNum];
269  buffHold myReq;
270  kXR_unt64 mySeq;
271  const char *sigBuff, *payload = thedata;
272  unsigned char secHash[SHA256_DIGEST_LENGTH];
273  int sigSize, n, newSize, rc, paysize = 0;
274  bool nodata = false;
275 
276 // Generate a new sequence number
277 //
278  mySeq = nextSeqno++;
279  mySeq = htonll(mySeq);
280 
281 // Determine if we are going to sign the payload and its location
282 //
283  if (thereq.header.dlen)
284  {kXR_unt16 reqid = htons(thereq.header.requestid);
285  paysize = ntohl(thereq.header.dlen);
286  if (!payload) payload = ((char *)&thereq) + sizeof(ClientRequest);
287  if (reqid == kXR_write || reqid == kXR_pgwrite) n = (secVerData ? 3 : 2);
288  else n = 3;
289  } else n = 2;
290 
291 // Fill out the iovec
292 //
293  iov[0].iov_base = (char *)&mySeq;
294  iov[0].iov_len = sizeof(mySeq);
295  iov[1].iov_base = (char *)&thereq;
296  iov[1].iov_len = sizeof(ClientRequest);
297  if (n < 3) nodata = true;
298  else {iov[2].iov_base = (char *)payload;
299  iov[2].iov_len = paysize;
300  }
301 
302 // Compute the hash
303 //
304  if (!GetSHA2(secHash, iov, n)) return -EDOM;
305 
306 // Now encrypt the hash
307 //
308  if (edOK)
309  {rc = authProt->Encrypt((const char *)secHash,sizeof(secHash),&myReq.bP);
310  if (rc < 0) return rc;
311  sigSize = myReq.bP->size;
312  sigBuff = myReq.bP->buffer;
313  } else {
314  sigSize = sizeof(secHash);
315  sigBuff = (char *)secHash;
316  }
317 
318 // Allocate a new request object
319 //
320  newSize = sizeof(SecurityRequest) + sigSize;
321  myReq.P = (XrdSecReq *)malloc(newSize);
322  if (!myReq.P) return -ENOMEM;
323 
324 // Setup the security request (we only support signing)
325 //
326  memcpy(&(myReq.P->secReq), &initSigVer, sizeof(ClientSigverRequest));
327  memcpy(&(myReq.P->secReq.header.streamid ), thereq.header.streamid,
328  sizeof(myReq.P->secReq.header.streamid));
329  memcpy(&(myReq.P->secReq.sigver.expectrid),&thereq.header.requestid,
330  sizeof(myReq.P->secReq.sigver.expectrid));
331  myReq.P->secReq.sigver.seqno = mySeq;
332  if (nodata) myReq.P->secReq.sigver.flags |= kXR_nodata;
333  myReq.P->secReq.sigver.dlen = htonl(sigSize);
334 
335 // Append the signature to the request
336 //
337  memcpy(&(myReq.P->secSig), sigBuff, sigSize);
338 
339 // Return pointer to he security request and its size
340 //
341  newreq = &(myReq.P->secReq); myReq.P = 0;
342  return newSize;
343 }
kXR_char streamid[2]
Definition: XProtocol.hh:156
struct ClientRequestHdr header
Definition: XProtocol.hh:846
kXR_unt16 requestid
Definition: XProtocol.hh:157
@ kXR_sigver
Definition: XProtocol.hh:141
@ kXR_write
Definition: XProtocol.hh:131
@ kXR_pgwrite
Definition: XProtocol.hh:138
@ kXR_nodata
Definition: XProtocol.hh:738
#define kXR_secver_0
Definition: XProtocol.hh:1146
kXR_int32 dlen
Definition: XProtocol.hh:159
@ kXR_SHA256
Definition: XProtocol.hh:731
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 349 of file XrdSecProtect.cc.

350 {
351  unsigned int lvl, vsz;
352 
353 // Check for no security, the simlplest case
354 //
355  if (inReqs.secvsz == 0 && inReqs.seclvl == 0)
356  {memset(&myReqs, 0, sizeof(myReqs));
357  secVec = 0;
358  secVerData = false;
359  return;
360  }
361 
362 // Precheck the security level
363 //
364  lvl = inReqs.seclvl;
365  if (lvl > kXR_secPedantic) lvl = kXR_secPedantic;
366 
367 // Perform the default setup (the usual case)
368 //
369  secVec = secTable.Vec[lvl-1];
370  myReqs.seclvl = lvl;
371  myReqs.secvsz = 0;
372  myReqs.secver = kXR_secver_0;
373  myReqs.secopt = inReqs.secopt;
374 
375 // Set options
376 //
377  secVerData = (inReqs.secopt & kXR_secOData) != 0;
378 
379 // Create a modified vectr if there are overrides
380 //
381  if (inReqs.secvsz != 0)
382  {const ServerResponseSVec_Protocol *urVec = &inReqs.secvec;
383  memcpy(myVec, secVec, maxRIX);
384  vsz = inReqs.secvsz;
385  for (unsigned int i = 0; i < vsz; i++, urVec++)
386  {if (urVec->reqindx < maxRIX)
387  {if (urVec->reqsreq > kXR_signNeeded)
388  myVec[urVec->reqindx] = kXR_signNeeded;
389  else myVec[urVec->reqindx] = urVec->reqsreq;
390  }
391  }
392  secVec = myVec;
393  }
394 }
ServerResponseSVec_Protocol secvec
Definition: XProtocol.hh:1114
#define kXR_secOData
Definition: XProtocol.hh:1126
#define kXR_secPedantic
Definition: XProtocol.hh:1135
#define kXR_signNeeded
Definition: XProtocol.hh:1141

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 400 of file XrdSecProtect.cc.

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