XRootD
Loading...
Searching...
No Matches
XrdSecProtect Class Reference

#include <XrdSecProtect.hh>

+ Collaboration diagram for XrdSecProtect:

Public Member Functions

virtual ~XrdSecProtect ()
 Destructor.
 
virtual void Delete ()
 Delete this object. Use this method as opposed to operator delete.
 
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
@ 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, XrdSecProtocol::Encrypt(), ClientRequest::header, kXR_nodata, kXR_pgwrite, kXR_secver_0, kXR_SHA256, kXR_sigver, kXR_write, ClientRequestHdr::requestid, and ClientRequestHdr::streamid.

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

+ Here is the call graph for this function:
+ 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
#define kXR_secOData
#define kXR_secPedantic
#define kXR_signNeeded

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, ServerResponseReqs_Protocol::secver, 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_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, XrdSecProtocol::Decrypt(), ClientRequestHdr::dlen, ClientSigverRequest::expectrid, ClientSigverRequest::flags, ClientRequest::header, SecurityRequest::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 Symbol 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: