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