Skip to content

Commit

Permalink
[TLS] Add peer certificate verification.
Browse files Browse the repository at this point in the history
[TLS] Note in login message the connection type and track upgrades.
[TLS] General code cleanup.
  • Loading branch information
abh3 authored and osschar committed Oct 10, 2019
1 parent 1e7f0a4 commit 3cc7ab7
Show file tree
Hide file tree
Showing 19 changed files with 848 additions and 273 deletions.
2 changes: 1 addition & 1 deletion src/XProtocol/XProtocol.hh
Expand Up @@ -97,7 +97,7 @@
#define kXR_gotoTLS 0x40000000
#define kXR_tlsAny 0x1f000000
#define kXR_tlsData 0x01000000
#define kXR_tlsGPFile 0x02000000
#define kXR_tlsGPF 0x02000000
#define kXR_tlsLogin 0x04000000
#define kXR_tlsSess 0x08000000
#define kXR_tlsTPC 0x10000000
Expand Down
132 changes: 116 additions & 16 deletions src/Xrd/XrdConfig.cc
Expand Up @@ -116,6 +116,10 @@ extern int ka_Icnt;
namespace
{
XrdOucEnv theEnv;
bool SSLmsgs = false;

void TlsError(const char *tid, const char *msg, bool sslmsg)
{if (!sslmsg || SSLmsgs) XrdGlobal::Log.Emsg("TLS", tid, msg);}
};

/******************************************************************************/
Expand Down Expand Up @@ -182,6 +186,8 @@ XrdConfig::XrdConfig()
HomePath = 0;
tlsCert = 0;
tlsKey = 0;
caDir = 0;
caFile = 0;
AdminMode= 0700;
HomeMode = 0700;
Police = 0;
Expand All @@ -193,11 +199,11 @@ XrdConfig::XrdConfig()
repInt = 600;
repOpts = 0;
ppNet = 0;
tlsHSTO =10;
tlsOpts = 0x0000000a | XrdTlsContext::servr;
tlsNoVer = false;
NetTCPlep = -1;
NetADM = 0;
coreV = 1;
tlsSSL = false;
memset(NetTCP, 0, sizeof(NetTCP));

Firstcp = Lastcp = 0;
Expand Down Expand Up @@ -650,6 +656,7 @@ int XrdConfig::ConfigXeq(char *var, XrdOucStream &Config, XrdSysError *eDest)
TS_Xeq("sitename", xsit);
TS_Xeq("timeout", xtmo);
TS_Xeq("tls", xtls);
TS_Xeq("tlsca", xtlsca);
}

// No match found, complain.
Expand Down Expand Up @@ -1131,19 +1138,29 @@ int XrdConfig::Setup(char *dfltp, char *libProt)

bool XrdConfig::SetupTLS()
{
XrdTlsContext::Protocol prot = (tlsSSL ? XrdTlsContext::doSSL
: XrdTlsContext::doTLS);

// Check if we should issue a verification error
//
if (!caDir && !caFile && !tlsNoVer)
{Log.Say("Config failure: the tlsca directive was not specified!");
return false;
}

// Set the message callback before doing anything else
//
XrdTlsContext::SetMsgCB(TlsError);

// Set debug option if need be.
//
if (TRACING((TRACE_DEBUG|TRACE_TLS))) tlsOpts |= XrdTlsContext::debug;

// Create a context
//
static XrdTlsContext xrdTLS(tlsCert, tlsKey, prot);
static XrdTlsContext xrdTLS(tlsCert, tlsKey, caDir, caFile, tlsOpts);

// Check if all went well
//
if (xrdTLS.Context() == 0)
{xrdTLS.PrintErrs("Config failure", &Log);
return false;
}
if (xrdTLS.Context() == 0) return false;

// Set address of out TLS object in the global area
//
Expand Down Expand Up @@ -1898,7 +1915,6 @@ int XrdConfig::xsit(XrdSysError *eDest, XrdOucStream &Config)
<cpath> is the the certificate file to be used.
<kpath> is the the private key file to be used.
<opts> options:
[no]ssl allow ssl protocols (default: nossl)
hsto <sec> handshake timeout interval (default 10).
Output: 0 upon success or 1 upon failure.
Expand All @@ -1907,15 +1923,18 @@ int XrdConfig::xsit(XrdSysError *eDest, XrdOucStream &Config)
int XrdConfig::xtls(XrdSysError *eDest, XrdOucStream &Config)
{
char *val;
int num;

if (!(val = Config.GetWord()))
{eDest->Emsg("Config", "tls cert path not specified"); return 1;}

if (*val != '/')
{eDest->Emsg("Config", "tls cert path not absolute"); return 1;}

if (tlsCert) free(tlsCert);
tlsCert = strdup(val);
if (tlsKey) free(tlsKey);
tlsKey = tlsCert;
tlsSSL = false;
tlsKey = 0;

if (!(val = Config.GetWord())) return 0;

Expand All @@ -1924,22 +1943,102 @@ int XrdConfig::xtls(XrdSysError *eDest, XrdOucStream &Config)
if (!(val = Config.GetWord())) return 0;
}

do { if (!strcmp(val, "ssl")) tlsSSL = true;
else if (!strcmp(val, "nossl")) tlsSSL = false;
do { if (!strcmp(val, "dump")) SSLmsgs = true;
else if (!strcmp(val, "nodump")) SSLmsgs = false;
else if (!strcmp(val, "hsto" ))
{if (!(val = Config.GetWord()))
{eDest->Emsg("Config", "tls hsto value not specified");
return 1;
}
if (XrdOuca2x::a2tm(*eDest,"tls hsto",val,&tlsHSTO,1))
if (XrdOuca2x::a2tm(*eDest,"tls hsto",val,&num,1,255))
return 1;
tlsOpts &= ~XrdTlsContext::hsto;
tlsOpts |= (XrdTlsContext::hsto & num);
}
else {eDest->Emsg("Config", "invalid tls option -",val); return 1;}
} while ((val = Config.GetWord()));

return 0;
}

/******************************************************************************/
/* x t l s c a */
/******************************************************************************/

/* Function: xtlsca
Purpose: To parse directive: tlsca noverify | <parms> [<opts>]
parms: {certdir | certfile} <path>
opts: [log {all | failure | none}] [verdepth <n>]
noverify client's cert need not be verified.
<path> is the the certificate path or file to be used.
Both a file and a directory path can be specified.
<n> the maximum certificate depth to be check.
log logs verification attempts. The default is 'none' (i.e.
no logging). The 'all' option logs all verifications.
The 'failure' option logs only verification failures.
Output: 0 upon success or 1 upon failure.
*/

int XrdConfig::xtlsca(XrdSysError *eDest, XrdOucStream &Config)
{
char *val, **cadest, kword[16];
int vd;
bool isdir;

if (!(val = Config.GetWord()))
{eDest->Emsg("Config", "tlsca parameter not specified"); return 1;}

if (!strcmp(val, "noverify"))
{tlsNoVer = true;
if (caDir) {free(caDir); caDir = 0;}
if (caFile) {free(caFile); caFile = 0;}
return 0;
}

do {if (strlen(val) >= (int)sizeof(kword))
{eDest->Emsg("Config", "Invalid tlsca parameter -", val);
return 1;
}
strcpy(kword, val);
if (!(val = Config.GetWord()))
{eDest->Emsg("Config", "tlsca parameter value not specified");
return 1;
}
if ((isdir = !strcmp(kword, "certdir"))
|| !strcmp(kword, "certfile"))
{if (*val != '/')
{eDest->Emsg("Config","tlsca",kword,"path is not absolute.");
return 1;
}
cadest = (isdir ? &caDir : &caFile);
if (*cadest) free(*cadest);
*cadest = strdup(val);
}
else if (!strcmp(kword, "log"))
{ if (!strcmp(val, "off"))
tlsOpts &= ~XrdTlsContext::logVF;
else if (!strcmp(val, "failure"))
tlsOpts |= XrdTlsContext::logVF;
else {eDest->Emsg("Config","Invalid tlsca log argument -",val);
return 1;
}
}
else if (!strcmp(kword, "verdepth"))
{if (XrdOuca2x::a2i(*eDest,"tlsca verdepth",val,&vd,1,255))
return 1;
tlsOpts &= ~XrdTlsContext::vdept;
tlsOpts |= ~XrdTlsContext::vdept & (vd << XrdTlsContext::vdepS);
}
} while((val = Config.GetWord()));

return 0;
}

/******************************************************************************/
/* x t m o */
/******************************************************************************/
Expand Down Expand Up @@ -2040,7 +2139,8 @@ int XrdConfig::xtrace(XrdSysError *eDest, XrdOucStream &Config)
{"net", TRACE_NET},
{"poll", TRACE_POLL},
{"protocol", TRACE_PROT},
{"sched", TRACE_SCHED}
{"sched", TRACE_SCHED},
{"tls", TRACE_TLS}
};
int i, neg, trval = 0, numopts = sizeof(tropts)/sizeof(struct traceopts);

Expand Down
7 changes: 5 additions & 2 deletions src/Xrd/XrdConfig.hh
Expand Up @@ -83,6 +83,7 @@ int xrep(XrdSysError *edest, XrdOucStream &Config);
int xsched(XrdSysError *edest, XrdOucStream &Config);
int xsit(XrdSysError *edest, XrdOucStream &Config);
int xtls(XrdSysError *edest, XrdOucStream &Config);
int xtlsca(XrdSysError *edest, XrdOucStream &Config);
int xtrace(XrdSysError *edest, XrdOucStream &Config);
int xtmo(XrdSysError *edest, XrdOucStream &Config);
int yport(XrdSysError *edest, const char *ptyp, const char *pval);
Expand All @@ -99,6 +100,8 @@ char *AdminPath;
char *HomePath;
char *tlsCert;
char *tlsKey;
char *caDir;
char *caFile;
char *ConfigFN;
char *repDest[2];
XrdConfigProt *Firstcp;
Expand All @@ -115,10 +118,10 @@ int NetTCPlep;
int AdminMode;
int HomeMode;
int repInt;
int tlsHSTO;
int tlsOpts;
bool tlsNoVer;
char repOpts;
char ppNet;
signed char coreV;
bool tlsSSL;
};
#endif
9 changes: 9 additions & 0 deletions src/Xrd/XrdLink.cc
Expand Up @@ -543,6 +543,15 @@ int XrdLink::Terminate(const char *owner, int fdnum, unsigned int inst)
return wTime;
}

/******************************************************************************/
/* v e r T L S */
/******************************************************************************/

const char *XrdLink::verTLS()
{
return (isTLS ? linkXQ.verTLS() : "");
}

/******************************************************************************/
/* W a i t 4 D a t a */
/******************************************************************************/
Expand Down
12 changes: 12 additions & 0 deletions src/Xrd/XrdLink.hh
Expand Up @@ -524,12 +524,24 @@ inline bool hasBridge() const {return isBridged;}
//-----------------------------------------------------------------------------
//! Determine if this link is using TLS.
//!
//! @param vprot if not nil, the TLS protocol version number if returned.
//! If the link is not using TLS the version is a null string.
//!
//! @return true this link is using TLS.
//! @return false this link not using TLS.
//-----------------------------------------------------------------------------

inline bool hasTLS() const {return isTLS;}

//-----------------------------------------------------------------------------
//! Return TLS protocol version being used.
//!
//! @return The TLS protocol version number. If the link is not using TLS,
//! a null string is returned;
//-----------------------------------------------------------------------------

const char *verTLS();

//-----------------------------------------------------------------------------
//! Constructor
//!
Expand Down
49 changes: 35 additions & 14 deletions src/Xrd/XrdLinkXeq.cc
Expand Up @@ -171,7 +171,7 @@ int XrdLinkXeq::Close(bool defer)

// Cleanup TLS if it is active
//
if (isTLS) tlsIO.Shutdown(!defer);
if (isTLS) tlsIO.Shutdown();

// If a defer close is requested, we can close the descriptor but we must
// keep the slot number to prevent a new client getting the same fd number.
Expand Down Expand Up @@ -768,37 +768,49 @@ XrdProtocol *XrdLinkXeq::setProtocol(XrdProtocol *pp, bool push)
/******************************************************************************/

bool XrdLinkXeq::setTLS(bool enable)
{
static const XrdTlsConnection::RW_Mode rwMode=XrdTlsConnection::TLS_RNB_WBL;
{ //???
// static const XrdTlsConnection::RW_Mode rwMode=XrdTlsConnection::TLS_RNB_WBL;
static const XrdTlsConnection::RW_Mode rwMode=XrdTlsConnection::TLS_RBL_WBL;
static const XrdTlsConnection::HS_Mode hsMode=XrdTlsConnection::TLS_HS_BLOCK;
const char *eNote;
int rc;

// If we are already in a compatible mode, we are done
//
if (isTLS == enable) return true;

// Either enable TLS or shut it down.
// If this is a shutdown, then do it now.
//
if (enable) eNote = tlsIO.Init(*tlsCtx, FD, rwMode, hsMode, false);
else {tlsIO.Shutdown();
eNote = 0;
}
if (!enable)
{tlsIO.Shutdown();
isTLS = enable;
Addr.SetTLS(enable);
return true;
}
// We want to initialize TLS, do so now.
//
eNote = tlsIO.Init(*tlsCtx, FD, rwMode, hsMode, false);

// Check for errors
//
if (eNote)
{char buff[1024];
snprintf(buff, sizeof(buff), "Unable to %s tls for %s;",
(enable ? "enable" : "disable"), ID);
snprintf(buff, sizeof(buff), "Unable to enable tls for %s;", ID);
Log.Emsg("LinkXeq", buff, eNote);
return false;
}

// All set. Record our TLS state.
// Now we need to accept this TLS connection
//
isTLS = enable;
Addr.SetTLS(enable);
return true;
rc = tlsIO.Accept();

// Diagnose return state
//
if (rc == 0)
{isTLS = enable;
Addr.SetTLS(enable);
}
return rc == 0;
}

/******************************************************************************/
Expand Down Expand Up @@ -1198,3 +1210,12 @@ bool XrdLinkXeq::TLS_Write(const char *Buff, int Blen)
//
return true;
}

/******************************************************************************/
/* v e r T L S */
/******************************************************************************/

const char *XrdLinkXeq::verTLS()
{
return tlsIO.Version();
}
2 changes: 2 additions & 0 deletions src/Xrd/XrdLinkXeq.hh
Expand Up @@ -125,6 +125,8 @@ int TLS_Send(const struct iovec *iov, int iocnt, int bytes);

int TLS_Send(const sfVec *sfP, int sfN);

const char *verTLS();

XrdLinkXeq();
~XrdLinkXeq() {} // Is never deleted!

Expand Down

0 comments on commit 3cc7ab7

Please sign in to comment.