XRootD
Loading...
Searching...
No Matches
XrdTlsContext.cc
Go to the documentation of this file.
1//------------------------------------------------------------------------------
2// Copyright (c) 2011-2018 by European Organization for Nuclear Research (CERN)
3// Author: Michal Simon <simonm@cern.ch>
4//------------------------------------------------------------------------------
5// XRootD is free software: you can redistribute it and/or modify
6// it under the terms of the GNU Lesser General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// XRootD is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU Lesser General Public License
16// along with XRootD. If not, see <http://www.gnu.org/licenses/>.
17//------------------------------------------------------------------------------
18
19#include <cstdio>
20#include <openssl/bio.h>
21#include <openssl/crypto.h>
22#include <openssl/err.h>
23#include <openssl/ssl.h>
24#include <openssl/opensslv.h>
25#include <sys/stat.h>
26
27#include "XrdOuc/XrdOucUtils.hh"
29#include "XrdSys/XrdSysError.hh"
31#include "XrdSys/XrdSysTimer.hh"
32
33#include "XrdTls/XrdTls.hh"
35#include "XrdTls/XrdTlsTrace.hh"
36
37#if OPENSSL_VERSION_NUMBER >= 0x30400010
38#define SSL_CTX_flush_sessions SSL_CTX_flush_sessions_ex
39#endif
40
41/******************************************************************************/
42/* G l o b a l s */
43/******************************************************************************/
44
45namespace XrdTlsGlobal
46{
48};
49
50/******************************************************************************/
51/* X r d T l s C o n t e x t I m p l */
52/******************************************************************************/
53
55{
57 : ctx(0), ctxnew(0), owner(p), flsCVar(0),
58 flushT(0),
59 crlRunning(false), flsRunning(false) {}
60 ~XrdTlsContextImpl() {if (ctx) SSL_CTX_free(ctx);
61 if (ctxnew) delete ctxnew;
62 if (flsCVar) delete flsCVar;
63 }
64
65 SSL_CTX *ctx;
71 short flushT;
74 time_t lastCertModTime = 0;
76 std::string sessionCacheId;
77 uint64_t opts{0};
78};
79
80/******************************************************************************/
81/* C r l R e f r e s h S u p p o r t */
82/******************************************************************************/
83
84namespace XrdTlsCrl
85{
86// Inital entry for refreshing crls
87//
88void *Refresh(void *parg)
89{
90 EPNAME("Refresh");
91 int sleepTime;
92 bool doreplace;
93
94// Get the implementation details
95//
96 XrdTlsContextImpl *ctxImpl = static_cast<XrdTlsContextImpl*>(parg);
97
98// Indicate we have started in the trace record
99//
100 DBG_CTX("CRL refresh started.")
101
102// Do this forever but first get the sleep time
103//
104do{ctxImpl->crlMutex.ReadLock();
105 sleepTime = ctxImpl->Parm.crlRT;
106 ctxImpl->crlMutex.UnLock();
107
108// We may have been cancelled, in which case we just exit
109//
110 if (!sleepTime)
111 {ctxImpl->crlMutex.WriteLock();
112 ctxImpl->crlRunning = false;
113 ctxImpl->crlMutex.UnLock();
114 DBG_CTX("CRL refresh ending by request!");
115 return (void *)0;
116 }
117
118// Indicate we how long before a refresh
119//
120 DBG_CTX("CRL refresh will happen in " <<sleepTime <<" seconds.");
121
122// Now sleep the request amount of time
123//
124 XrdSysTimer::Snooze(sleepTime);
125
126 if (ctxImpl->owner->x509Verify() || ctxImpl->owner->newHostCertificateDetected()) {
127 // Check if this context is still alive. Generally, it never gets deleted.
128 //
129 ctxImpl->crlMutex.WriteLock();
130 if (!ctxImpl->owner) break;
131
132 // We clone the original, this will give us the latest crls (i.e. refreshed).
133 // We drop the lock while doing so as this may take a long time. This is
134 // completely safe to do because we implicitly own the implementation.
135 //
136 ctxImpl->crlMutex.UnLock();
137 XrdTlsContext *newctx = ctxImpl->owner->Clone();
138
139 // Verify that the context was properly built
140 //
141 if (!newctx || !newctx->isOK())
142 {XrdTls::Emsg("CrlRefresh:","Refresh of context failed!!!",false);
143 continue;
144 }
145
146 // OK, set the new context to be used next time Session() is called.
147 //
148 ctxImpl->crlMutex.WriteLock();
149 doreplace = (ctxImpl->ctxnew != 0);
150 if (doreplace) delete ctxImpl->ctxnew;
151 ctxImpl->ctxnew = newctx;
152 ctxImpl->crlMutex.UnLock();
153
154 // Do some debugging
155 //
156 if (doreplace) {DBG_CTX("CRL refresh created replacement x509 store.");}
157 else {DBG_CTX("CRL refresh created new x509 store.");}
158 }
159 } while(true);
160
161// If we are here the context that started us has gone away and we are done
162//
163 bool keepctx = ctxImpl->flsRunning;
164 ctxImpl->crlRunning = false;
165 ctxImpl->crlMutex.UnLock();
166 if (!keepctx) delete ctxImpl;
167 return (void *)0;
168}
169}
170
171/******************************************************************************/
172/* C a c h e F l u s h S u p p o r t */
173/******************************************************************************/
174
175namespace XrdTlsFlush
176{
177/******************************************************************************/
178/* F l u s h e r */
179/******************************************************************************/
180// Inital entry for refreshing crls
181//
182void *Flusher(void *parg)
183{
184 EPNAME("Flusher");
185 time_t tStart, tWaited;
186 int flushT, waitT, hits, miss, sesn, tmos;
187 long tNow;
188
189// Get the implementation details
190//
191 XrdTlsContextImpl *ctxImpl = static_cast<XrdTlsContextImpl*>(parg);
192
193// Get the interval as it may change as we are running
194//
195 ctxImpl->crlMutex.ReadLock();
196 waitT = flushT = ctxImpl->flushT;
197 ctxImpl->crlMutex.UnLock();
198
199// Indicate we have started in the trace record
200//
201 DBG_CTX("Cache flusher started; interval="<<flushT<<" seconds.");
202
203// Do this forever
204//
205do{tStart = time(0);
206 ctxImpl->flsCVar->Wait(waitT);
207 tWaited= time(0) - tStart;
208
209// Check if this context is still alive. Generally, it never gets deleted.
210//
211 ctxImpl->crlMutex.ReadLock();
212 if (!ctxImpl->owner) break;
213
214// If the interval changed, see if we should wait a bit longer
215//
216 if (flushT != ctxImpl->flushT && tWaited < ctxImpl->flushT-1)
217 {waitT = ctxImpl->flushT - tWaited;
218 ctxImpl->crlMutex.UnLock();
219 continue;
220 }
221
222// Get the new values and drop the lock
223//
224 waitT = flushT = ctxImpl->flushT;
225 ctxImpl->crlMutex.UnLock();
226
227// Get some relevant statistics
228//
229 sesn = SSL_CTX_sess_number(ctxImpl->ctx);
230 hits = SSL_CTX_sess_hits(ctxImpl->ctx);
231 miss = SSL_CTX_sess_misses(ctxImpl->ctx);
232 tmos = SSL_CTX_sess_timeouts(ctxImpl->ctx);
233
234// Flush the cache
235//
236 tNow = time(0);
237 SSL_CTX_flush_sessions(ctxImpl->ctx, tNow);
238
239// Print some stuff should debugging be on
240//
242 {char mBuff[512];
243 snprintf(mBuff, sizeof(mBuff), "sess=%d hits=%d miss=%d timeouts=%d",
244 sesn, hits, miss, tmos);
245 DBG_CTX("Cache flushed; " <<mBuff);
246 }
247 } while(true);
248
249// If we are here the context that started us has gone away and we are done
250//
251 bool keepctx = ctxImpl->crlRunning;
252 ctxImpl->flsRunning = false;
253 ctxImpl->crlMutex.UnLock();
254 if (!keepctx) delete ctxImpl;
255 return (void *)0;
256}
257
258/******************************************************************************/
259/* S e t u p _ F l u s h e r */
260/******************************************************************************/
261
262bool Setup_Flusher(XrdTlsContextImpl *pImpl, int flushT)
263{
264 pthread_t tid;
265 int rc;
266
267// Set the new flush interval
268//
269 pImpl->crlMutex.WriteLock();
270 pImpl->flushT = flushT;
271 pImpl->crlMutex.UnLock();
272
273// If the flush thread is already running, then wake it up to get the new value
274//
275 if (pImpl->flsRunning)
276 {pImpl->flsCVar->Signal();
277 return true;
278 }
279
280// Start the flusher thread
281//
282 pImpl->flsCVar = new XrdSysCondVar();
283 if ((rc = XrdSysThread::Run(&tid, XrdTlsFlush::Flusher, (void *)pImpl,
284 0, "Cache Flusher")))
285 {char eBuff[512];
286 snprintf(eBuff, sizeof(eBuff),
287 "Unable to start cache flusher thread; rc=%d", rc);
288 XrdTls::Emsg("SessCache:", eBuff, false);
289 return false;
290 }
291
292// Finish up
293//
294 pImpl->flsRunning = true;
295 SSL_CTX_set_session_cache_mode(pImpl->ctx, SSL_SESS_CACHE_NO_AUTO_CLEAR);
296 return true;
297}
298}
299
300/******************************************************************************/
301/* S S L T h r e a d i n g S u p p o r t */
302/******************************************************************************/
303
304// The following may confusing because SSL MT support is somewhat bizarre.
305// Versions < 1.0 require a numeric thread_id and lock callbasks.
306// Versions < 1.1 require a lock_callbacks but the thread_is callback is
307// optional. While the numeric thread_id callback can be used
308// it's deprecated and fancier pointer/numeric call should be
309// used. In our case, we use the deprecated version.
310// Versions >- 1.1 Do not need any callbacks as all threading functions are
311// internally defined to use native MT functions.
312
313#if OPENSSL_VERSION_NUMBER < 0x10100000L && defined(OPENSSL_THREADS)
314namespace
315{
316#define XRDTLS_SET_CALLBACKS 1
317#ifdef __solaris__
318extern "C" {
319#endif
320
321template<bool is32>
322struct tlsmix;
323
324template<>
325struct tlsmix<false> {
326 static unsigned long mixer(unsigned long x) {
327 // mixer based on splitmix64
328 x ^= x >> 30;
329 x *= 0xbf58476d1ce4e5b9UL;
330 x ^= x >> 27;
331 x *= 0x94d049bb133111ebUL;
332 x ^= x >> 31;
333 return x;
334 }
335};
336
337template<>
338struct tlsmix<true> {
339 static unsigned long mixer(unsigned long x) {
340 // mixer based on murmurhash3
341 x ^= x >> 16;
342 x *= 0x85ebca6bU;
343 x ^= x >> 13;
344 x *= 0xc2b2ae35U;
345 x ^= x >> 16;
346 return x;
347 }
348};
349
350unsigned long sslTLS_id_callback(void)
351{
352 // base thread-id on the id given by XrdSysThread;
353 // but openssl 1.0 uses thread-id as a key for looking
354 // up per thread crypto ERR structures in a hash-table.
355 // So mix bits so that the table's hash function gives
356 // better distribution.
357
358 unsigned long x = (unsigned long)XrdSysThread::ID();
359 return tlsmix<sizeof(unsigned long)==4>::mixer(x);
360}
361
362XrdSysMutex *MutexVector = 0;
363
364void sslTLS_lock(int mode, int n, const char *file, int line)
365{
366// Use exclusive locks. At some point, SSL categorizes these as read and
367// write locks but it's not clear when this actually occurs, sigh.
368//
369 if (mode & CRYPTO_LOCK) MutexVector[n].Lock();
370 else MutexVector[n].UnLock();
371}
372#ifdef __solaris__
373}
374#endif
375} // namespace
376#else
377#undef XRDTLS_SET_CALLBACKS
378#endif
379
380/******************************************************************************/
381/* F i l e L o c a l D e f i n i t i o n s */
382/******************************************************************************/
383
384namespace
385{
386// The following is the default cipher list. Note that for OpenSSL v1.0.2+ we
387// use the recommended cipher list from Mozilla. Otherwise, we use the dumber
388// less secure ciphers as older versions of openssl have issues with them. See
389// ssl-config.mozilla.org/#config=intermediate&openssl=1.0.2k&guideline=5.4
390//
391#if OPENSSL_VERSION_NUMBER >= 0x10002000L
392const char *sslCiphers = "ECDHE-ECDSA-AES128-GCM-SHA256:"
393 "ECDHE-RSA-AES128-GCM-SHA256:"
394 "ECDHE-ECDSA-AES256-GCM-SHA384:"
395 "ECDHE-RSA-AES256-GCM-SHA384:"
396 "ECDHE-ECDSA-CHACHA20-POLY1305:"
397 "ECDHE-RSA-CHACHA20-POLY1305:"
398 "DHE-RSA-AES128-GCM-SHA256:"
399 "DHE-RSA-AES256-GCM-SHA384";
400#else
401const char *sslCiphers = "ALL:!LOW:!EXP:!MD5:!MD2";
402#endif
403
404XrdSysMutex dbgMutex, tlsMutex;
405XrdSys::RAtomic<bool> initDbgDone{ false };
406bool initTlsDone{ false };
407
408/******************************************************************************/
409/* I n i t T L S */
410/******************************************************************************/
411
412void InitTLS() // This is strictly a one-time call!
413{
414 XrdSysMutexHelper tlsHelper(tlsMutex);
415
416// Make sure we are not trying to load the ssl library more than once. This can
417// happen when a server and a client instance happen to be both defined.
418//
419 if (initTlsDone) return;
420 initTlsDone = true;
421
422// SSL library initialisation
423//
424 SSL_library_init();
425 OpenSSL_add_all_algorithms();
426 SSL_load_error_strings();
427 OpenSSL_add_all_ciphers();
428#if OPENSSL_VERSION_NUMBER < 0x30000000L
429 ERR_load_BIO_strings();
430#endif
431 ERR_load_crypto_strings();
432
433// Set callbacks if we need to do this
434//
435#ifdef XRDTLS_SET_CALLBACKS
436
437 int n = CRYPTO_num_locks();
438 if (n > 0)
439 {MutexVector = new XrdSysMutex[n];
440 CRYPTO_set_locking_callback(sslTLS_lock);
441 }
442 CRYPTO_set_id_callback(sslTLS_id_callback);
443
444#endif
445}
446
447/******************************************************************************/
448/* F a t a l */
449/******************************************************************************/
450
451void Fatal(std::string *eMsg, const char *msg, bool sslmsg=false)
452{
453// If there is an outboard error string object, return the message there.
454//
455 if (eMsg) *eMsg = msg;
456
457// Now route the message to the message callback function. If this is an ssl
458// related error we also flush the ssl error queue to prevent suprises.
459//
460 XrdTls::Emsg("TLS_Context:", msg, sslmsg);
461}
462
463/******************************************************************************/
464/* G e t T l s M e t h o d */
465/******************************************************************************/
466
467const char *GetTlsMethod(const SSL_METHOD *&meth)
468{
469#if OPENSSL_VERSION_NUMBER > 0x1010000fL /* v1.1.0 */
470 meth = TLS_method();
471#else
472 meth = SSLv23_method();
473#endif
474 if (meth == 0) return "No negotiable TLS method available.";
475 return 0;
476}
477
478/******************************************************************************/
479/* V e r P a t h s */
480/******************************************************************************/
481
482bool VerPaths(const char *cert, const char *pkey,
483 const char *cadr, const char *cafl, std::string &eMsg)
484{
485 static const mode_t cert_mode = S_IRUSR | S_IWUSR | S_IRWXG | S_IROTH;
486 static const mode_t pkey_mode = S_IRUSR | S_IWUSR;
487 static const mode_t cadr_mode = S_IRWXU | S_IRGRP | S_IXGRP
488 | S_IROTH | S_IXOTH;
489 static const mode_t cafl_mode = S_IRUSR | S_IWUSR | S_IRWXG | S_IROTH;
490 const char *emsg;
491
492// If the ca cert directory is present make sure it's a directory and
493// only the ower can write to that directory (anyone can read from it).
494//
495 if (cadr && (emsg = XrdOucUtils::ValPath(cadr, cadr_mode, true)))
496 {eMsg = "Unable to use CA cert directory ";
497 eMsg += cadr; eMsg += "; "; eMsg += emsg;
498 return false;
499 }
500
501// If a ca cert file is present make sure it's a file and only the owner can
502// write it (anyone can read it).
503//
504 if (cafl && (emsg = XrdOucUtils::ValPath(cafl, cafl_mode, false)))
505 {eMsg = "Unable to use CA cert file ";
506 eMsg += cafl; eMsg += "; "; eMsg += emsg;
507 return false;
508 }
509
510// If a private key is present than make sure it's a file and only the
511// owner has access to it.
512//
513 if (pkey && (emsg = XrdOucUtils::ValPath(pkey, pkey_mode, false)))
514 {eMsg = "Unable to use key file ";
515 eMsg += pkey; eMsg += "; "; eMsg += emsg;
516 return false;
517 }
518
519// If a cert file is present then make sure it's a file. If a keyfile is
520// present then anyone can read it but only the owner can write it.
521// Otherwise, only the owner can gave access to it (it contains the key).
522//
523 if (cert)
524 {mode_t cmode = (pkey ? cert_mode : pkey_mode);
525 if ((emsg = XrdOucUtils::ValPath(cert, cmode, false)))
526 {if (pkey) eMsg = "Unable to use cert file ";
527 else eMsg = "Unable to use cert+key file ";
528 eMsg += cert; eMsg += "; "; eMsg += emsg;
529 return false;
530 }
531 }
532
533// All tests succeeded.
534//
535 return true;
536}
537
538/******************************************************************************/
539/* V e r C B */
540/******************************************************************************/
541
542extern "C"
543{
544int VerCB(int aOK, X509_STORE_CTX *x509P)
545{
546 if (!aOK)
547 {X509 *cert = X509_STORE_CTX_get_current_cert(x509P);
548 int depth = X509_STORE_CTX_get_error_depth(x509P);
549 int err = X509_STORE_CTX_get_error(x509P);
550 char name[512], info[1024];
551
552 X509_NAME_oneline(X509_get_subject_name(cert), name, sizeof(name));
553 snprintf(info,sizeof(info),"Cert verification failed for DN=%s",name);
554 XrdTls::Emsg("CertVerify:", info, false);
555
556 X509_NAME_oneline(X509_get_issuer_name(cert), name, sizeof(name));
557 snprintf(info,sizeof(info),"Failing cert issuer=%s", name);
558 XrdTls::Emsg("CertVerify:", info, false);
559
560 snprintf(info, sizeof(info), "Error %d at depth %d [%s]", err, depth,
561 X509_verify_cert_error_string(err));
562 XrdTls::Emsg("CertVerify:", info, true);
563 }
564
565 return aOK;
566}
567}
568
569} // Anonymous namespace end
570
571/******************************************************************************/
572/* C o n s t r u c t o r */
573/******************************************************************************/
574
575#define KILL_CTX(x) if (x) {SSL_CTX_free(x); x = 0;}
576
577#define FATAL(msg) {Fatal(eMsg, msg); KILL_CTX(pImpl->ctx); return;}
578
579#define FATAL_SSL(msg) {Fatal(eMsg, msg, true); KILL_CTX(pImpl->ctx); return;}
580
581XrdTlsContext::XrdTlsContext(const char *cert, const char *key,
582 const char *caDir, const char *caFile,
583 uint64_t opts, std::string *eMsg)
584 : pImpl( new XrdTlsContextImpl(this) )
585{
586 class ctx_helper
587 {public:
588
589 void Keep() {ctxLoc = 0;}
590
591 ctx_helper(SSL_CTX **ctxP) : ctxLoc(ctxP) {}
592 ~ctx_helper() {if (ctxLoc && *ctxLoc)
593 {SSL_CTX_free(*ctxLoc); *ctxLoc = 0;}
594 }
595 private:
596 SSL_CTX **ctxLoc;
597 } ctx_tracker(&pImpl->ctx);
598
599 pImpl->opts = opts;
600
601 static const uint64_t sslOpts = SSL_OP_ALL
602 | SSL_OP_NO_SSLv2
603 | SSL_OP_NO_SSLv3
604 | SSL_OP_NO_COMPRESSION
605#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF
606 | SSL_OP_IGNORE_UNEXPECTED_EOF
607#endif
608#if OPENSSL_VERSION_NUMBER >= 0x10101000L
609 | SSL_OP_NO_RENEGOTIATION
610#endif
611 ;
612
613 std::string certFN, eText;
614 const char *emsg;
615
616// Assume we will fail
617//
618 pImpl->ctx = 0;
619
620// Verify that initialzation has occurred. This is not heavy weight as
621// there will usually be no more than two instances of this object.
622//
623 if (!initDbgDone)
624 {XrdSysMutexHelper dbgHelper(dbgMutex);
625 if (!initDbgDone)
626 {const char *dbg;
627 if (!(opts & servr) && (dbg = getenv("XRDTLS_DEBUG")))
628 {int dbgOpts = 0;
629 if (strstr(dbg, "ctx")) dbgOpts |= XrdTls::dbgCTX;
630 if (strstr(dbg, "sok")) dbgOpts |= XrdTls::dbgSOK;
631 if (strstr(dbg, "sio")) dbgOpts |= XrdTls::dbgSIO;
632 if (!dbgOpts) dbgOpts = XrdTls::dbgALL;
634 }
635 if ((emsg = Init())) FATAL(emsg);
636 initDbgDone = true;
637 }
638 }
639
640// If no CA cert information is specified and this is not a server context,
641// then get the paths from the environment. They must exist as we need to
642// verify peer certs in order to verify target host names client-side. We
643// also use this setupt to see if we should use a specific cert and key.
644//
645 if (!(opts & servr))
646 {if (!caDir && !caFile)
647 {caDir = getenv("X509_CERT_DIR");
648 caFile = getenv("X509_CERT_FILE");
649 if (!caDir && !caFile)
650 FATAL("No CA cert specified; host identity cannot be verified.");
651 }
652 if (!key) key = getenv("X509_USER_KEY");
653 if (!cert) cert = getenv("X509_USER_PROXY");
654 if (!cert)
655 {struct stat Stat;
656 long long int uid = static_cast<long long int>(getuid());
657 certFN = std::string("/tmp/x509up_u") + std::to_string(uid);
658 if (!stat(certFN.c_str(), &Stat)) cert = certFN.c_str();
659 }
660 }
661
662// Before we try to use any specified files, make sure they exist, are of
663// the right type and do not have excessive access privileges.
664// .a
665 if (!VerPaths(cert, key, caDir, caFile, eText)) FATAL( eText.c_str());
666
667// Copy parameters to out parm structure.
668//
669 if (cert) {
670 pImpl->Parm.cert = cert;
671 //This call should not fail as a stat is already performed in the call of VerPaths() above
672 XrdOucUtils::getModificationTime(pImpl->Parm.cert.c_str(),pImpl->lastCertModTime);
673 }
674 if (key) pImpl->Parm.pkey = key;
675 if (caDir) pImpl->Parm.cadir = caDir;
676 if (caFile) pImpl->Parm.cafile = caFile;
677 pImpl->Parm.opts = opts;
678 if (opts & crlRF) {
679 // What we store in crlRF is the time in minutes, convert it back to seconds
680 pImpl->Parm.crlRT = static_cast<int>((opts & crlRF) >> crlRS) * 60;
681 }
682
683// Get the correct method to use for TLS and check if successful create a
684// server context that uses the method.
685//
686 const SSL_METHOD *meth;
687 emsg = GetTlsMethod(meth);
688 if (emsg) FATAL(emsg);
689
690 pImpl->ctx = SSL_CTX_new(meth);
691
692// Make sure we have a context here
693//
694 if (pImpl->ctx == 0) FATAL_SSL("Unable to allocate TLS context!");
695
696// Always prohibit SSLv2 & SSLv3 as these are not secure.
697//
698 SSL_CTX_set_options(pImpl->ctx, sslOpts);
699
700// Handle session re-negotiation automatically
701//
702// SSL_CTX_set_mode(pImpl->ctx, sslMode);
703
704// Turn off the session cache as it's useless with peer cert chains
705//
706 SSL_CTX_set_session_cache_mode(pImpl->ctx, SSL_SESS_CACHE_OFF);
707
708// Establish the CA cert locations, if specified. Then set the verification
709// depth and turn on peer cert validation. For now, we don't set a callback.
710// In the future we may to grab debugging information.
711//
712 if (caDir || caFile)
713 {if (!SSL_CTX_load_verify_locations(pImpl->ctx, caFile, caDir))
714 FATAL_SSL("Unable to load the CA cert file or directory.");
715
716 int vDepth = (opts & vdept) >> vdepS;
717 SSL_CTX_set_verify_depth(pImpl->ctx, (vDepth ? vDepth : 9));
718
719 bool LogVF = (opts & logVF) != 0;
720 SSL_CTX_set_verify(pImpl->ctx, SSL_VERIFY_PEER, (LogVF ? VerCB : 0));
721
722 unsigned long xFlags = (opts & nopxy ? 0 : X509_V_FLAG_ALLOW_PROXY_CERTS);
723 if (opts & crlON)
724 {xFlags |= X509_V_FLAG_CRL_CHECK;
725 if (opts & crlFC) xFlags |= X509_V_FLAG_CRL_CHECK_ALL;
726 }
727 if (opts) X509_STORE_set_flags(SSL_CTX_get_cert_store(pImpl->ctx),xFlags);
728 } else {
729 SSL_CTX_set_verify(pImpl->ctx, SSL_VERIFY_NONE, 0);
730 }
731
732// Set cipher list
733//
734 if (!SSL_CTX_set_cipher_list(pImpl->ctx, sslCiphers))
735 FATAL_SSL("Unable to set SSL cipher list; no supported ciphers.");
736
737// If we need to enable eliptic-curve support, do so now. Note that for
738// OpenSSL 1.1.0+ this is automatically done for us.
739//
740#if SSL_CTRL_SET_ECDH_AUTO
741 SSL_CTX_set_ecdh_auto(pImpl->ctx, 1);
742#endif
743
744// We normally handle renegotiation during reads and writes or selective
745// prohibit on a SSL socket basis. The calle may request this be applied
746// to all SSL's generated from this context. If so, do it here.
747//
748 if (opts & artON) SSL_CTX_set_mode(pImpl->ctx, SSL_MODE_AUTO_RETRY);
749
750// If there is no cert then assume this is a generic context for a client
751//
752 if (cert == 0)
753 {ctx_tracker.Keep();
754 return;
755 }
756
757// We have a cert. If the key is missing then we assume the key is in the
758// cert file (ssl will complain if it isn't).
759//
760 if (!key) key = cert;
761
762// Load certificate
763//
764 if (SSL_CTX_use_certificate_chain_file(pImpl->ctx, cert) != 1)
765 FATAL_SSL("Unable to create TLS context; invalid certificate.");
766
767// Load the private key
768//
769 if (SSL_CTX_use_PrivateKey_file(pImpl->ctx, key, SSL_FILETYPE_PEM) != 1 )
770 FATAL_SSL("Unable to create TLS context; invalid private key.");
771
772// Make sure the key and certificate file match.
773//
774 if (SSL_CTX_check_private_key(pImpl->ctx) != 1 )
775 FATAL_SSL("Unable to create TLS context; cert-key mismatch.");
776
777// All went well, start the CRL refresh thread and keep the context.
778//
779 if(opts & rfCRL) {
781 }
782 ctx_tracker.Keep();
783}
784
785/******************************************************************************/
786/* D e s t r u c t o r */
787/******************************************************************************/
788
790{
791// We can delet eour implementation of there is no refresh thread running. If
792// there is then the refresh thread has to delete the implementation.
793//
794 if (pImpl->crlRunning | pImpl->flsRunning)
795 {pImpl->crlMutex.WriteLock();
796 pImpl->owner = 0;
797 pImpl->crlMutex.UnLock();
798 } else delete pImpl;
799}
800
801/******************************************************************************/
802/* C l o n e */
803/******************************************************************************/
804
805XrdTlsContext *XrdTlsContext::Clone(bool full,bool startCRLRefresh)
806{
807 XrdTlsContext::CTX_Params &my = pImpl->Parm;
808 const char *cert = (my.cert.size() ? my.cert.c_str() : 0);
809 const char *pkey = (my.pkey.size() ? my.pkey.c_str() : 0);
810 const char *caD = (my.cadir.size() ? my.cadir.c_str() : 0);
811 const char *caF = (my.cafile.size() ? my.cafile.c_str() : 0);
812
813// If this is a non-full context, get rid of any verification
814//
815 if (!full) caD = caF = 0;
816
817// Cloning simply means getting a object with the old parameters.
818//
819 uint64_t myOpts = my.opts;
820 if(startCRLRefresh){
822 } else {
824 }
825 XrdTlsContext *xtc = new XrdTlsContext(cert, pkey, caD, caF, myOpts);
826
827// Verify that the context was built
828//
829 if (xtc->isOK()) {
830 if(pImpl->sessionCacheOpts != -1){
831 //A SessionCache() call was done for the current context, so apply it for this new cloned context
832 xtc->SessionCache(pImpl->sessionCacheOpts,pImpl->sessionCacheId.c_str(),pImpl->sessionCacheId.size());
833 }
834 return xtc;
835 }
836
837// We failed, cleanup.
838//
839 delete xtc;
840 return 0;
841}
842
843/******************************************************************************/
844/* C o n t e x t */
845/******************************************************************************/
846
848{
849 return pImpl->ctx;
850}
851
852/******************************************************************************/
853/* G e t P a r a m s */
854/******************************************************************************/
855
857{
858 return &pImpl->Parm;
859}
860
861/******************************************************************************/
862/* I n i t */
863/******************************************************************************/
864
866{
867
868// Disallow use if this object unless SSL provides thread-safety!
869//
870#ifndef OPENSSL_THREADS
871 return "Installed OpenSSL lacks the required thread support!";
872#endif
873
874// Initialize the library (one time call)
875//
876 InitTLS();
877 return 0;
878}
879
880/******************************************************************************/
881/* i s O K */
882/******************************************************************************/
883
885{
886 return pImpl->ctx != 0;
887}
888
889/******************************************************************************/
890/* S e s s i o n */
891/******************************************************************************/
892
893// Note: The reason we handle the x509 store update here is because allow the
894// SSL context to be exported and then have no lock control over it. This may
895// happen for transient purposes other than creating sessions. Once we
896// disallow direct access to the context, the exchange can happen in the
897// refresh thread which simplifies this whole process.
898
900{
901#if OPENSSL_VERSION_NUMBER >= 0x10002000L
902
903 EPNAME("Session");
904 SSL *ssl;
905
906// Check if we have a refreshed context. If so, we need to replace the X509
907// store in the current context with the new one before we create the session.
908//
909 pImpl->crlMutex.ReadLock();
910 if (!(pImpl->ctxnew))
911 {ssl = SSL_new(pImpl->ctx);
912 pImpl->crlMutex.UnLock();
913 return ssl;
914 }
915
916// Things have changed, so we need to take the long route here. We need to
917// replace the x509 cache with the current cache. Get a R/W lock now.
918//
919 pImpl->crlMutex.UnLock();
920 pImpl->crlMutex.WriteLock();
921
922// If some other thread beat us to the punch, just return what we have.
923//
924 if (!(pImpl->ctxnew))
925 {ssl = SSL_new(pImpl->ctx);
926 pImpl->crlMutex.UnLock();
927 return ssl;
928 }
929
930// Do some tracing
931//
932 DBG_CTX("Replacing x509 store with new contents.");
933
934// Get the new store and set it in our context. Setting the store is black
935// magic. For OpenSSL < 1.1, Two stores need to be set with the "set1" variant.
936// Newer version only require SSL_CTX_set1_cert_store() to be used.
937//
938 //We have a new context generated by Refresh, so we must use it.
939 XrdTlsContext * ctxnew = pImpl->ctxnew;
940
941 /*X509_STORE *newX509 = SSL_CTX_get_cert_store(ctxnew->pImpl->ctx);
942 SSL_CTX_set1_verify_cert_store(pImpl->ctx, newX509);
943 SSL_CTX_set1_chain_cert_store(pImpl->ctx, newX509);*/
944 //The above two macros actually do not replace the certificate that has
945 //to be used for that SSL session, so we will create the session with the SSL_CTX * of
946 //the TlsContext created by Refresh()
947 //First, free the current SSL_CTX, if it is used by any transfer, it will just decrease
948 //the reference counter of it. There is therefore no risk of double free...
949 SSL_CTX_free(pImpl->ctx);
950 pImpl->ctx = ctxnew->pImpl->ctx;
951 //In the destructor of XrdTlsContextImpl, SSL_CTX_Free() is
952 //called if ctx is != 0. As this new ctx is used by the session
953 //we just created, we don't want that to happen. We therefore set it to 0.
954 //The SSL_free called on the session will cleanup the context for us.
955 ctxnew->pImpl->ctx = 0;
956
957// Save the generated context and clear it's presence
958//
959 XrdTlsContext *ctxold = pImpl->ctxnew;
960 pImpl->ctxnew = 0;
961
962// Generate a new session (might as well to keep the lock we have)
963//
964 ssl = SSL_new(pImpl->ctx);
965
966// OK, now we can drop all the locks and get rid of the old context
967//
968 pImpl->crlMutex.UnLock();
969 delete ctxold;
970 return ssl;
971
972#else
973// If we did not compile crl refresh code, we can simply return the OpenSSL
974// session using our context. Otherwise, we need to see if we have a refreshed
975// context and if so, carry forward the X509_store to our original context.
976//
977 return SSL_new(pImpl->ctx);
978#endif
979}
980
981/******************************************************************************/
982/* S e s s i o n C a c h e */
983/******************************************************************************/
984
985int XrdTlsContext::SessionCache(int opts, const char *id, int idlen)
986{
987 static const int doSet = scSrvr | scClnt | scOff;
988 long sslopt = 0;
989 int flushT = opts & scFMax;
990
991 pImpl->sessionCacheOpts = opts;
992 pImpl->sessionCacheId = id;
993
994// If initialization failed there is nothing to do
995//
996 if (pImpl->ctx == 0) return 0;
997
998// Set options as appropriate
999//
1000 if (opts & doSet)
1001 {if (opts & scOff) sslopt = SSL_SESS_CACHE_OFF;
1002 else {if (opts & scSrvr) sslopt = SSL_SESS_CACHE_SERVER;
1003 if (opts & scClnt) sslopt |= SSL_SESS_CACHE_CLIENT;
1004 }
1005 }
1006
1007// Check if we should set any cache options or simply get them
1008//
1009 if (!(opts & doSet)) sslopt = SSL_CTX_get_session_cache_mode(pImpl->ctx);
1010 else {sslopt = SSL_CTX_set_session_cache_mode(pImpl->ctx, sslopt);
1011 if (opts & scOff) SSL_CTX_set_options(pImpl->ctx, SSL_OP_NO_TICKET);
1012 }
1013
1014// Compute what he previous cache options were
1015//
1016 opts = scNone;
1017 if (sslopt & SSL_SESS_CACHE_SERVER) opts |= scSrvr;
1018 if (sslopt & SSL_SESS_CACHE_CLIENT) opts |= scClnt;
1019 if (!opts) opts = scOff;
1020 if (sslopt & SSL_SESS_CACHE_NO_AUTO_CLEAR) opts |= scKeep;
1021 opts |= (static_cast<int>(pImpl->flushT) & scFMax);
1022
1023// Set the id is so wanted
1024//
1025 if (id && idlen > 0)
1026 {if (!SSL_CTX_set_session_id_context(pImpl->ctx,
1027 (unsigned const char *)id,
1028 (unsigned int)idlen)) opts |= scIdErr;
1029 }
1030
1031// If a flush interval was specified and it is different from what we have
1032// then reset the flush interval.
1033//
1034 if (flushT && flushT != pImpl->flushT)
1035 XrdTlsFlush::Setup_Flusher(pImpl, flushT);
1036
1037// All done
1038//
1039 return opts;
1040}
1041
1042/******************************************************************************/
1043/* S e t C o n t e x t C i p h e r s */
1044/******************************************************************************/
1045
1046bool XrdTlsContext::SetContextCiphers(const char *ciphers)
1047{
1048 if (pImpl->ctx && SSL_CTX_set_cipher_list(pImpl->ctx, ciphers)) return true;
1049
1050 char eBuff[2048];
1051 snprintf(eBuff,sizeof(eBuff),"Unable to set context ciphers '%s'",ciphers);
1052 Fatal(0, eBuff, true);
1053 return false;
1054}
1055
1056/******************************************************************************/
1057/* S e t D e f a u l t C i p h e r s */
1058/******************************************************************************/
1059
1060void XrdTlsContext::SetDefaultCiphers(const char *ciphers)
1061{
1062 sslCiphers = ciphers;
1063}
1064
1065/******************************************************************************/
1066/* S e t C r l R e f r e s h */
1067/******************************************************************************/
1068
1070{
1071#if OPENSSL_VERSION_NUMBER >= 0x10002000L
1072
1073 pthread_t tid;
1074 int rc;
1075
1076// If it's negative or equal to 0, use the current setting
1077//
1078 if (refsec <= 0)
1079 {pImpl->crlMutex.WriteLock();
1080 refsec = pImpl->Parm.crlRT;
1081 pImpl->crlMutex.UnLock();
1082 if (!refsec) refsec = XrdTlsContext::DEFAULT_CRL_REF_INT_SEC;
1083 }
1084
1085// Make sure this is at least 60 seconds between refreshes
1086//
1087// if (refsec < 60) refsec = 60;
1088
1089// We will set the new interval and start a refresh thread if not running.
1090//
1091 pImpl->crlMutex.WriteLock();
1092 pImpl->Parm.crlRT = refsec;
1093 if (!pImpl->crlRunning)
1094 {if ((rc = XrdSysThread::Run(&tid, XrdTlsCrl::Refresh, (void *)pImpl,
1095 0, "CRL Refresh")))
1096 {char eBuff[512];
1097 snprintf(eBuff, sizeof(eBuff),
1098 "Unable to start CRL refresh thread; rc=%d", rc);
1099 XrdTls::Emsg("CrlRefresh:", eBuff, false);
1100 pImpl->crlMutex.UnLock();
1101 return false;
1102 } else pImpl->crlRunning = true;
1103 pImpl->crlMutex.UnLock();
1104 }
1105
1106// All done
1107//
1108 return true;
1109
1110#else
1111// We use features present on OpenSSL 1.02 and above to implement crl refresh.
1112// Older version are too difficult to deal with. Issue a message if this
1113// feature is being enabled on an old version.
1114//
1115 XrdTls::Emsg("CrlRefresh:", "Refreshing CRLs only supported in "
1116 "OpenSSL version >= 1.02; CRL refresh disabled!", false);
1117 return false;
1118#endif
1119}
1120
1121/******************************************************************************/
1122/* x 5 0 9 V e r i f y */
1123/******************************************************************************/
1124
1126{
1127 return !(pImpl->Parm.cadir.empty()) || !(pImpl->Parm.cafile.empty());
1128}
1129
1131 const std::string certPath = pImpl->Parm.cert;
1132 if(certPath.empty()) {
1133 //No certificate provided, should not happen though
1134 return false;
1135 }
1136 time_t modificationTime;
1137 if(!XrdOucUtils::getModificationTime(certPath.c_str(),modificationTime)){
1138 if (pImpl->lastCertModTime != modificationTime) {
1139 //The certificate file has changed
1140 pImpl->lastCertModTime = modificationTime;
1141 return true;
1142 }
1143 }
1144 return false;
1145}
1146
1148
1149 bool LogVF = (pImpl->opts & logVF) != 0;
1150 switch (setting) {
1151 case kOn:
1152 SSL_CTX_set_verify(pImpl->ctx, SSL_VERIFY_PEER, (LogVF ? VerCB : 0));
1153 break;
1154 case kOff:
1155 SSL_CTX_set_verify(pImpl->ctx, SSL_VERIFY_NONE, 0);
1156 break;
1157 default:
1158 return false;
1159 }
1160 return true;
1161}
#define EPNAME(x)
struct stat Stat
Definition XrdCks.cc:49
void Fatal(const char *op, const char *target)
Definition XrdCrc32c.cc:58
#define stat(a, b)
Definition XrdPosix.hh:101
#define eMsg(x)
struct myOpts opts
int emsg(int rc, char *msg)
#define FATAL_SSL(msg)
#define FATAL(msg)
#define DBG_CTX(y)
#define TRACING(x)
Definition XrdTrace.hh:70
static int getModificationTime(const char *path, time_t &modificationTime)
static const char * ValPath(const char *path, mode_t allow, bool isdir)
static int Run(pthread_t *, void *(*proc)(void *), void *arg, int opts=0, const char *desc=0)
static pthread_t ID(void)
static void Snooze(int seconds)
static const int scIdErr
Info: Id not set, is too long.
XrdTlsContext * Clone(bool full=true, bool startCRLRefresh=false)
~XrdTlsContext()
Destructor.
static const uint64_t vdept
Mask to isolate vdept.
static const int crlRS
Bits to shift vdept.
int SessionCache(int opts=scNone, const char *id=0, int idlen=0)
static void SetDefaultCiphers(const char *ciphers)
XrdTlsContext(const char *cert=0, const char *key=0, const char *cadir=0, const char *cafile=0, uint64_t opts=0, std::string *eMsg=0)
static const int scClnt
Turn on cache client mode.
static const int DEFAULT_CRL_REF_INT_SEC
Default CRL refresh interval in seconds.
static const uint64_t servr
This is a server context.
static const uint64_t rfCRL
Turn on the CRL refresh thread.
static const int scKeep
Info: TLS-controlled flush disabled.
static const uint64_t nopxy
Do not allow proxy certs.
bool SetTlsClientAuth(ClientAuthSetting setting)
static const int scNone
Do not change any option settings.
static const uint64_t logVF
Log verify failures.
static const uint64_t crlFC
Full crl chain checking.
static const uint64_t crlON
Enables crl checking.
static const uint64_t artON
Auto retry Handshake.
static const int vdepS
Bits to shift vdept.
const CTX_Params * GetParams()
static const int scOff
Turn off cache.
static const char * Init()
bool newHostCertificateDetected()
bool SetContextCiphers(const char *ciphers)
static const int scFMax
bool SetCrlRefresh(int refsec=-1)
static const int scSrvr
Turn on cache server mode (default)
static const uint64_t crlRF
Mask to isolate crl refresh in min.
static const int dbgSIO
Turn debugging in for socket I/O.
Definition XrdTls.hh:102
static const int dbgSOK
Turn debugging in for socket operations.
Definition XrdTls.hh:101
static const int dbgOUT
Force msgs to stderr for easier client debug.
Definition XrdTls.hh:104
static void Emsg(const char *tid, const char *msg=0, bool flush=true)
Definition XrdTls.cc:104
static const int dbgALL
Turn debugging for everything.
Definition XrdTls.hh:103
static const int dbgCTX
Turn debugging in for context operations.
Definition XrdTls.hh:100
static void SetDebug(int opts, XrdSysLogger *logP=0)
Definition XrdTls.cc:177
bool InitTLS()
Definition XrdClTls.cc:96
void * Refresh(void *parg)
bool Setup_Flusher(XrdTlsContextImpl *pImpl, int flushT)
void * Flusher(void *parg)
XrdSysTrace SysTrace("TLS", 0)
XrdTlsContextImpl(XrdTlsContext *p)
std::string sessionCacheId
XrdTlsContext * owner
XrdTlsContext::CTX_Params Parm
XrdTlsContext * ctxnew
XrdSysCondVar * flsCVar
XrdSysRWLock crlMutex
std::string cafile
-> ca cert file.
uint64_t opts
Options as passed to the constructor.
std::string cadir
-> ca cert directory.
int crlRT
crl refresh interval time in seconds
std::string pkey
-> private key path.
std::string cert
-> certificate path.