/******************************************************************************/
/* */
/* X r d S e c P r o t o c o l g s i . h h */
/* */
/* (c) 2005 G. Ganis / CERN */
/* */
/* This file is part of the XRootD software suite. */
/* */
/* XRootD is free software: you can redistribute it and/or modify it under */
/* the terms of the GNU Lesser General Public License as published by the */
/* Free Software Foundation, either version 3 of the License, or (at your */
/* option) any later version. */
/* */
/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public License */
/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
/* COPYING (GPL license). If not, see . */
/* */
/* The copyright holder's institutional names and contributor's names may not */
/* be used to endorse or promote products derived from this software without */
/* specific prior written permission of the institution or contributor. */
/* */
/******************************************************************************/
#include
#include "XrdNet/XrdNetAddrInfo.hh"
#include "XrdOuc/XrdOucErrInfo.hh"
#include "XrdOuc/XrdOucGMap.hh"
#include "XrdOuc/XrdOucHash.hh"
#include "XrdOuc/XrdOucString.hh"
#include "XrdOuc/XrdOucTokenizer.hh"
#include "XrdSys/XrdSysPthread.hh"
#include "XrdSec/XrdSecInterface.hh"
#include "XrdSecgsi/XrdSecgsiTrace.hh"
#include "XrdSut/XrdSutCache.hh"
#include "XrdSut/XrdSutPFEntry.hh"
#include "XrdSut/XrdSutPFile.hh"
#include "XrdSut/XrdSutBuffer.hh"
#include "XrdSut/XrdSutRndm.hh"
#include "XrdCrypto/XrdCryptoAux.hh"
#include "XrdCrypto/XrdCryptoCipher.hh"
#include "XrdCrypto/XrdCryptoFactory.hh"
#include "XrdCrypto/XrdCryptoX509Crl.hh"
#include "XrdCrypto/XrdCryptogsiX509Chain.hh"
/******************************************************************************/
/* D e f i n e s */
/******************************************************************************/
typedef XrdOucString String;
typedef XrdCryptogsiX509Chain X509Chain;
#define XrdSecPROTOIDENT "gsi"
#define XrdSecPROTOIDLEN sizeof(XrdSecPROTOIDENT)
#define XrdSecgsiVERSION 10400
#define XrdSecNOIPCHK 0x0001
#define XrdSecDEBUG 0x1000
#define XrdCryptoMax 10
#define kMAXBUFLEN 1024
#define XrdSecgsiVersDHsigned 10400 // Version at which started signing
// of server DH parameters
//
// Message codes either returned by server or included in buffers
enum kgsiStatus {
kgST_error = -1, // error occured
kgST_ok = 0, // ok
kgST_more = 1 // need more info
};
// Client steps
enum kgsiClientSteps {
kXGC_none = 0,
kXGC_certreq = 1000, // 1000: request server certificate
kXGC_cert, // 1001: packet with (proxy) certificate
kXGC_sigpxy, // 1002: packet with signed proxy certificate
kXGC_reserved //
};
// Server steps
enum kgsiServerSteps {
kXGS_none = 0,
kXGS_init = 2000, // 2000: fake code used the first time
kXGS_cert, // 2001: packet with certificate
kXGS_pxyreq, // 2002: packet with proxy req to be signed
kXGS_reserved //
};
// Handshake options
enum kgsiHandshakeOpts {
kOptsDlgPxy = 1, // 0x0001: Ask for a delegated proxy
kOptsFwdPxy = 2, // 0x0002: Forward local proxy
kOptsSigReq = 4, // 0x0004: Accept to sign delegated proxy
kOptsSrvReq = 8, // 0x0008: Server request for delegated proxy
kOptsPxFile = 16, // 0x0010: Save delegated proxies in file
kOptsDelChn = 32, // 0x0020: Delete chain
kOptsPxCred = 64 // 0x0040: Save delegated proxies as credentials
};
// Error codes
enum kgsiErrors {
kGSErrParseBuffer = 10000, // 10000
kGSErrDecodeBuffer, // 10001
kGSErrLoadCrypto, // 10002
kGSErrBadProtocol, // 10003
kGSErrCreateBucket, // 10004
kGSErrDuplicateBucket, // 10005
kGSErrCreateBuffer, // 10006
kGSErrSerialBuffer, // 10007
kGSErrGenCipher, // 10008
kGSErrExportPuK, // 10009
kGSErrEncRndmTag, // 10010
kGSErrBadRndmTag, // 10011
kGSErrNoRndmTag, // 10012
kGSErrNoCipher, // 10013
kGSErrNoCreds, // 10014
kGSErrBadOpt, // 10015
kGSErrMarshal, // 10016
kGSErrUnmarshal, // 10017
kGSErrSaveCreds, // 10018
kGSErrNoBuffer, // 10019
kGSErrRefCipher, // 10020
kGSErrNoPublic, // 10021
kGSErrAddBucket, // 10022
kGSErrFinCipher, // 10023
kGSErrInit, // 10024
kGSErrBadCreds, // 10025
kGSErrError // 10026
};
#define REL1(x) { if (x) delete x; }
#define REL2(x,y) { if (x) delete x; if (y) delete y; }
#define REL3(x,y,z) { if (x) delete x; if (y) delete y; if (z) delete z; }
#define SafeDelete(x) { if (x) {delete x ; x = 0;} }
#define SafeDelArray(x) { if (x) {delete [] x ; x = 0;} }
#define SafeFree(x) { if (x) {free(x) ; x = 0;} }
// External functions for generic mapping
typedef char *(*XrdSecgsiGMAP_t)(const char *, int);
typedef int (*XrdSecgsiAuthz_t)(XrdSecEntity &);
typedef int (*XrdSecgsiAuthzInit_t)(const char *);
typedef int (*XrdSecgsiAuthzKey_t)(XrdSecEntity &, char **);
// VOMS extraction
typedef XrdSecgsiAuthz_t XrdSecgsiVOMS_t;
typedef XrdSecgsiAuthzInit_t XrdSecgsiVOMSInit_t;
//
// This a small class to set the relevant options in one go
//
class XrdOucGMap;
class XrdOucTrace;
class gsiOptions {
public:
short debug; // [cs] debug flag
char mode; // [cs] 'c' or 's'
char *clist; // [s] list of crypto modules ["ssl" ]
char *certdir;// [cs] dir with CA info [/etc/grid-security/certificates]
char *crldir; // [cs] dir with CRL info [/etc/grid-security/certificates]
char *crlext; // [cs] extension of CRL files [.r0]
char *cert; // [s] server certificate [/etc/grid-security/root/rootcert.pem]
// [c] user certificate [$HOME/.globus/usercert.pem]
char *key; // [s] server private key [/etc/grid-security/root/rootkey.pem]
// [c] user private key [$HOME/.globus/userkey.pem]
char *cipher; // [s] list of ciphers [aes-128-cbc:bf-cbc:des-ede3-cbc]
char *md; // [s] list of MDs [sha256:md5]
int crl; // [cs] check level of CRL's [1]
int ca; // [cs] verification level of CA's [1]
int crlrefresh; // [cs] CRL refresh or expiration period in secs [1 day]
char *proxy; // [c] user proxy [/tmp/x509up_u]
char *valid; // [c] proxy validity [12:00]
int deplen; // [c] depth of signature path for proxies [0]
int bits; // [c] bits in PKI for proxies [512]
char *gridmap;// [s] gridmap file [/etc/grid-security/gridmap]
int gmapto; // [s] validity in secs of grid-map cache entries [600 s]
char *gmapfun;// [s] file with the function to map DN to usernames [0]
char *gmapfunparms;// [s] parameters for the function to map DN to usernames [0]
char *authzfun;// [s] file with the function to fill entities [0]
char *authzfunparms;// [s] parameters for the function to fill entities [0]
int authzto; // [s] validity in secs of authz cache entries [-1 => unlimited]
int ogmap; // [s] gridmap file checking option
int dlgpxy; // [c] explicitely ask the creation of a delegated proxy; default 0
// [s] ask client for proxies; default: do not accept delegated proxies
int sigpxy; // [c] accept delegated proxy requests
char *srvnames;// [c] '|' separated list of allowed server names
char *exppxy; // [s] template for the exported file with proxies
int authzpxy; // [s] if 1 make proxy available in exported form in the 'endorsement'
// field of the XrdSecEntity object for use in XrdAcc
int vomsat; // [s] 0 do not look for; 1 extract if any
char *vomsfun;// [s] file with the function to fill VOMS [0]
char *vomsfunparms;// [s] parameters for the function to fill VOMS [0]
int moninfo; // [s] 0 do not look for; 1 use DN as default
int hashcomp; // [cs] 1 send hash names with both algorithms; 0 send only the default [1]
bool trustdns; // [cs] 'true' if DNS is trusted [true]
gsiOptions() { debug = -1; mode = 's'; clist = 0;
certdir = 0; crldir = 0; crlext = 0; cert = 0; key = 0;
cipher = 0; md = 0; ca = 1 ; crl = 1; crlrefresh = 86400;
proxy = 0; valid = 0; deplen = 0; bits = 512;
gridmap = 0; gmapto = 600;
gmapfun = 0; gmapfunparms = 0; authzfun = 0; authzfunparms = 0; authzto = -1;
ogmap = 1; dlgpxy = 0; sigpxy = 1; srvnames = 0;
exppxy = 0; authzpxy = 0;
vomsat = 1; vomsfun = 0; vomsfunparms = 0; moninfo = 0; hashcomp = 1; trustdns = true; }
virtual ~gsiOptions() { } // Cleanup inside XrdSecProtocolgsiInit
void Print(XrdOucTrace *t); // Print summary of gsi option status
};
class XrdSecProtocolgsi;
class gsiHSVars;
// From a proxy query
typedef struct {
X509Chain *chain;
XrdCryptoRSA *ksig;
XrdSutBucket *cbck;
} ProxyOut_t;
// To query proxies
typedef struct {
const char *cert;
const char *key;
const char *certdir;
const char *out;
const char *valid;
int deplen;
int bits;
} ProxyIn_t;
template
class GSIStack {
public:
void Add(T *t) {
char k[40]; snprintf(k, 40, "%p", t);
mtx.Lock();
if (!stack.Find(k)) stack.Add(k, t, 0, Hash_count); // We need an additional count
stack.Add(k, t, 0, Hash_count);
mtx.UnLock();
}
void Del(T *t) {
char k[40]; snprintf(k, 40, "%p", t);
mtx.Lock();
if (stack.Find(k)) stack.Del(k, Hash_count);
mtx.UnLock();
}
private:
XrdSysMutex mtx;
XrdOucHash stack;
};
/******************************************************************************/
/* X r d S e c P r o t o c o l g s i C l a s s */
/******************************************************************************/
class XrdSecProtocolgsi : public XrdSecProtocol
{
friend class gsiOptions;
friend class gsiHSVars;
public:
int Authenticate (XrdSecCredentials *cred,
XrdSecParameters **parms,
XrdOucErrInfo *einfo=0);
XrdSecCredentials *getCredentials(XrdSecParameters *parm=0,
XrdOucErrInfo *einfo=0);
XrdSecProtocolgsi(int opts, const char *hname, XrdNetAddrInfo &endPoint,
const char *parms = 0);
virtual ~XrdSecProtocolgsi() {} // Delete() does it all
// Initialization methods
static char *Init(gsiOptions o, XrdOucErrInfo *erp);
void Delete();
// Encrypt / Decrypt methods
int Encrypt(const char *inbuf, int inlen,
XrdSecBuffer **outbuf);
int Decrypt(const char *inbuf, int inlen,
XrdSecBuffer **outbuf);
// Sign / Verify methods
int Sign(const char *inbuf, int inlen,
XrdSecBuffer **outbuf);
int Verify(const char *inbuf, int inlen,
const char *sigbuf, int siglen);
// Export session key
int getKey(char *kbuf=0, int klen=0);
// Import a key
int setKey(char *kbuf, int klen);
// Enable tracing
static XrdOucTrace *EnableTracing();
private:
XrdNetAddrInfo epAddr;
// Static members initialized at startup
static XrdSysMutex gsiContext;
static String CAdir;
static String CRLdir;
static String DefCRLext;
static String SrvCert;
static String SrvKey;
static String UsrProxy;
static String UsrCert;
static String UsrKey;
static String PxyValid;
static int DepLength;
static int DefBits;
static int CACheck;
static int CRLCheck;
static int CRLDownload;
static int CRLRefresh;
static String DefCrypto;
static String DefCipher;
static String DefMD;
static String DefError;
static String GMAPFile;
static int GMAPOpt;
static bool GMAPuseDNname;
static int GMAPCacheTimeOut;
static XrdSecgsiGMAP_t GMAPFun;
static XrdSecgsiAuthz_t AuthzFun;
static XrdSecgsiAuthzKey_t AuthzKey;
static int AuthzCertFmt;
static int AuthzCacheTimeOut;
static int PxyReqOpts;
static int AuthzPxyWhat;
static int AuthzPxyWhere;
static String SrvAllowedNames;
static int VOMSAttrOpt;
static XrdSecgsiVOMS_t VOMSFun;
static int VOMSCertFmt;
static int MonInfoOpt;
static bool HashCompatibility;
static bool TrustDNS;
//
// Crypto related info
static int ncrypt; // Number of factories
static XrdCryptoFactory *cryptF[XrdCryptoMax]; // their hooks
static int cryptID[XrdCryptoMax]; // their IDs
static String cryptName[XrdCryptoMax]; // their names
static XrdCryptoCipher *refcip[XrdCryptoMax]; // ref for session ciphers
//
// Caches
static XrdSutCache cacheCA; // Info about trusted CA's
static XrdSutCache cacheCert; // Server certificates info cache
static XrdSutCache cachePxy; // Client proxies cache;
static XrdSutCache cacheGMAPFun; // Cache for entries mapped by GMAPFun
static XrdSutCache cacheAuthzFun; // Cache for entities filled by AuthzFun
//
// Services
static XrdOucGMap *servGMap; // Grid mapping service
//
// CA and CRL stacks
static GSIStack stackCA; // Stack of CA in use
static GSIStack stackCRL; // Stack of CRL in use
//
// GMAP control vars
static time_t lastGMAPCheck; // time of last check on GMAP
static XrdSysMutex mutexGMAP; // mutex to control GMAP reloads
//
// Running options / settings
static int Debug; // [CS] Debug level
static bool Server; // [CS] If server mode
static int TimeSkew; // [CS] Allowed skew in secs for time stamps
//
// for error logging and tracing
static XrdSysLogger Logger;
static XrdSysError eDest;
static XrdOucTrace *GSITrace;
// Information local to this instance
int options;
XrdCryptoFactory *sessionCF; // Chosen crypto factory
XrdCryptoCipher *sessionKey; // Session Key (result of the handshake)
XrdSutBucket *bucketKey; // Bucket with the key in export form
XrdCryptoMsgDigest *sessionMD; // Message Digest instance
XrdCryptoRSA *sessionKsig; // RSA key to sign
XrdCryptoRSA *sessionKver; // RSA key to verify
X509Chain *proxyChain; // Chain with the delegated proxy on servers
bool srvMode; // TRUE if server mode
char *expectedHost; // Expected hostname if TrustDNS is enabled.
bool useIV; // Use a non-zeroed unique IV in cipher enc/dec operations
// Temporary Handshake local info
gsiHSVars *hs;
// Parsing received buffers: client
int ParseClientInput(XrdSutBuffer *br, XrdSutBuffer **bm,
String &emsg);
int ClientDoInit(XrdSutBuffer *br, XrdSutBuffer **bm,
String &cmsg);
int ClientDoCert(XrdSutBuffer *br, XrdSutBuffer **bm,
String &cmsg);
int ClientDoPxyreq(XrdSutBuffer *br, XrdSutBuffer **bm,
String &cmsg);
// Parsing received buffers: server
int ParseServerInput(XrdSutBuffer *br, XrdSutBuffer **bm,
String &cmsg);
int ServerDoCertreq(XrdSutBuffer *br, XrdSutBuffer **bm,
String &cmsg);
int ServerDoCert(XrdSutBuffer *br, XrdSutBuffer **bm,
String &cmsg);
int ServerDoSigpxy(XrdSutBuffer *br, XrdSutBuffer **bm,
String &cmsg);
// Auxilliary functions
int ParseCrypto(String cryptlist);
int ParseCAlist(String calist);
// Load CA certificates
static int GetCA(const char *cahash,
XrdCryptoFactory *cryptof, gsiHSVars *hs = 0);
static String GetCApath(const char *cahash);
static bool VerifyCA(int opt, X509Chain *cca, XrdCryptoFactory *cf);
static int VerifyCRL(XrdCryptoX509Crl *crl, XrdCryptoX509 *xca, XrdOucString crldir,
XrdCryptoFactory *CF, int hashalg);
bool ServerCertNameOK(const char *subject, const char *hname, String &e);
static XrdSutCacheEntry *GetSrvCertEnt(XrdSutCERef &gcref,
XrdCryptoFactory *cf,
time_t timestamp, String &cal);
// Load CRLs
static XrdCryptoX509Crl *LoadCRL(XrdCryptoX509 *xca, const char *sjhash,
XrdCryptoFactory *CF, int dwld, int &err);
// Updating proxies
static int QueryProxy(bool checkcache, XrdSutCache *cache, const char *tag,
XrdCryptoFactory *cf, time_t timestamp,
ProxyIn_t *pi, ProxyOut_t *po);
static int InitProxy(ProxyIn_t *pi, XrdCryptoFactory *cf,
X509Chain *ch = 0, XrdCryptoRSA **key = 0);
// Error functions
static void ErrF(XrdOucErrInfo *einfo, kXR_int32 ecode,
const char *msg1, const char *msg2 = 0,
const char *msg3 = 0);
XrdSecCredentials *ErrC(XrdOucErrInfo *einfo, XrdSutBuffer *b1,
XrdSutBuffer *b2,XrdSutBuffer *b3,
kXR_int32 ecode, const char *msg1 = 0,
const char *msg2 = 0, const char *msg3 = 0);
int ErrS(String ID, XrdOucErrInfo *einfo, XrdSutBuffer *b1,
XrdSutBuffer *b2, XrdSutBuffer *b3,
kXR_int32 ecode, const char *msg1 = 0,
const char *msg2 = 0, const char *msg3 = 0);
// Check Time stamp
bool CheckTimeStamp(XrdSutBuffer *b, int skew, String &emsg);
// Check random challenge
bool CheckRtag(XrdSutBuffer *bm, String &emsg);
// Auxilliary methods
int AddSerialized(char opt, kXR_int32 step, String ID,
XrdSutBuffer *bls, XrdSutBuffer *buf,
kXR_int32 type, XrdCryptoCipher *cip);
// Grid map cache handling
static XrdSecgsiGMAP_t // Load alternative function for mapping
LoadGMAPFun(const char *plugin, const char *parms);
static XrdSecgsiAuthz_t // Load alternative function to fill XrdSecEntity
LoadAuthzFun(const char *plugin, const char *parms, int &fmt);
static XrdSecgsiVOMS_t // Load alternative function to extract VOMS
LoadVOMSFun(const char *plugin, const char *parms, int &fmt);
static void QueryGMAP(XrdCryptoX509Chain* chain, int now, String &name); //Lookup info for DN
// Entity handling
void CopyEntity(XrdSecEntity *in, XrdSecEntity *out, int *lout = 0);
void FreeEntity(XrdSecEntity *in);
// VOMS parsing
int ExtractVOMS(X509Chain *c, XrdSecEntity &ent);
};
class gsiHSVars {
public:
int Iter; // Iteration number
time_t TimeStamp; // Time of last call
String CryptoMod; // Crypto module in use
int RemVers; // Version run by remote counterpart
XrdCryptoCipher *Rcip; // Reference cipher
bool HasPad; // Whether padding is supported
XrdSutBucket *Cbck; // Bucket with the certificate in export form
String ID; // Handshake ID (dummy for clients)
XrdSutPFEntry *Cref; // Cache reference
XrdSutPFEntry *Pent; // Pointer to relevant file entry
X509Chain *Chain; // Chain to be eventually verified
XrdCryptoX509Crl *Crl; // Pointer to CRL, if required
X509Chain *PxyChain; // Proxy Chain on clients
bool RtagOK; // Rndm tag checked / not checked
bool Tty; // Terminal attached / not attached
int LastStep; // Step required at previous iteration
int Options; // Handshake options;
int HashAlg; // Hash algorithm of peer hash name;
XrdSutBuffer *Parms; // Buffer with server parms on first iteration
gsiHSVars() { Iter = 0; TimeStamp = -1; CryptoMod = "";
RemVers = -1; Rcip = 0; HasPad = 0;
Cbck = 0;
ID = ""; Cref = 0; Pent = 0; Chain = 0; Crl = 0; PxyChain = 0;
RtagOK = 0; Tty = 0; LastStep = 0; Options = 0; HashAlg = 0; Parms = 0;}
~gsiHSVars() { SafeDelete(Cref);
if (Options & kOptsDelChn) {
// Do not delete the CA certificate in the cached reference
if (Chain) Chain->Cleanup(1);
SafeDelete(Chain);
}
if (Crl) {
// This decreases the counter and actually deletes the object only
// when no instance is using it
XrdSecProtocolgsi::stackCRL.Del(Crl);
Crl = 0;
}
// The proxy chain is owned by the proxy cache; invalid proxies are
// detected (and eventually removed) by QueryProxy
PxyChain = 0;
SafeDelete(Parms); }
void Dump(XrdSecProtocolgsi *p = 0);
};