Correct MAX limit constant.
[shibboleth/cpp-xmltooling.git] / xmltooling / XMLToolingConfig.cpp
1 /*
2  *  Copyright 2001-2010 Internet2
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * XMLToolingConfig.cpp
19  *
20  * Library configuration.
21  */
22
23 #include "internal.h"
24 #include "exceptions.h"
25 #include "logging.h"
26 #include "XMLToolingConfig.h"
27 #include "encryption/Encryption.h"
28 #include "encryption/Encrypter.h"
29 #include "impl/UnknownElement.h"
30 #include "io/HTTPResponse.h"
31 #include "security/TrustEngine.h"
32 #include "security/OpenSSLCryptoX509CRL.h"
33 #include "security/CredentialResolver.h"
34 #include "security/KeyInfoResolver.h"
35 #include "signature/KeyInfo.h"
36 #include "signature/Signature.h"
37 #include "soap/SOAP.h"
38 #include "util/NDC.h"
39 #include "util/PathResolver.h"
40 #include "util/ReplayCache.h"
41 #include "util/StorageService.h"
42 #include "util/TemplateEngine.h"
43 #include "util/Threads.h"
44 #include "util/URLEncoder.h"
45 #include "validation/ValidatorSuite.h"
46
47 #ifdef HAVE_DLFCN_H
48 # include <dlfcn.h>
49 #endif
50
51 #include <stdexcept>
52 #if defined(XMLTOOLING_LOG4SHIB)
53 # include <log4shib/PropertyConfigurator.hh>
54 # include <log4shib/OstreamAppender.hh>
55 #elif defined(XMLTOOLING_LOG4CPP)
56 # include <log4cpp/PropertyConfigurator.hh>
57 # include <log4cpp/OstreamAppender.hh>
58 #endif
59 #include <xercesc/util/PlatformUtils.hpp>
60 #include <xercesc/util/XMLUniDefs.hpp>
61 #ifndef XMLTOOLING_NO_XMLSEC
62 # include <curl/curl.h>
63 # include <openssl/err.h>
64 # include <openssl/evp.h>
65 # include <xsec/framework/XSECAlgorithmMapper.hpp>
66 # include <xsec/framework/XSECException.hpp>
67 # include <xsec/framework/XSECProvider.hpp>
68 # include <xsec/transformers/TXFMBase.hpp>
69 #endif
70
71 using namespace soap11;
72 using namespace xmltooling::logging;
73 using namespace xmltooling;
74 using namespace xercesc;
75 using namespace std;
76
77 #ifdef WIN32
78 # if (OPENSSL_VERSION_NUMBER >= 0x00908000)
79 #  define XMLTOOLING_OPENSSL_HAVE_SHA2 1
80 # endif
81 #endif
82
83
84 DECL_XMLTOOLING_EXCEPTION_FACTORY(XMLParserException,xmltooling);
85 DECL_XMLTOOLING_EXCEPTION_FACTORY(XMLObjectException,xmltooling);
86 DECL_XMLTOOLING_EXCEPTION_FACTORY(MarshallingException,xmltooling);
87 DECL_XMLTOOLING_EXCEPTION_FACTORY(UnmarshallingException,xmltooling);
88 DECL_XMLTOOLING_EXCEPTION_FACTORY(UnknownElementException,xmltooling);
89 DECL_XMLTOOLING_EXCEPTION_FACTORY(UnknownAttributeException,xmltooling);
90 DECL_XMLTOOLING_EXCEPTION_FACTORY(UnknownExtensionException,xmltooling);
91 DECL_XMLTOOLING_EXCEPTION_FACTORY(ValidationException,xmltooling);
92 DECL_XMLTOOLING_EXCEPTION_FACTORY(IOException,xmltooling);
93
94 #ifndef XMLTOOLING_NO_XMLSEC
95 using namespace xmlencryption;
96 using namespace xmlsignature;
97     DECL_XMLTOOLING_EXCEPTION_FACTORY(XMLSecurityException,xmltooling);
98     DECL_XMLTOOLING_EXCEPTION_FACTORY(SignatureException,xmlsignature);
99     DECL_XMLTOOLING_EXCEPTION_FACTORY(EncryptionException,xmlencryption);
100 #endif
101
102 namespace {
103     static XMLToolingInternalConfig g_config;
104 #ifndef XMLTOOLING_NO_XMLSEC
105     static vector<Mutex*> g_openssl_locks;
106
107     extern "C" void openssl_locking_callback(int mode,int n,const char *file,int line)
108     {
109         if (mode & CRYPTO_LOCK)
110             g_openssl_locks[n]->lock();
111         else
112             g_openssl_locks[n]->unlock();
113     }
114
115 # ifndef WIN32
116     extern "C" unsigned long openssl_thread_id(void)
117     {
118         return (unsigned long)(pthread_self());
119     }
120 # endif
121
122 # ifdef XMLTOOLING_XMLSEC_DEBUGLOGGING
123     class TXFMOutputLog : public TXFMBase {
124             TXFMOutputLog();
125     public:
126         TXFMOutputLog(DOMDocument* doc) : TXFMBase(doc), m_log(Category::getInstance(XMLTOOLING_LOGCAT".Signature.Debugger")) {
127             input = nullptr;
128         }
129         ~TXFMOutputLog() {
130             m_log.debug("\n----- END SIGNATURE DEBUG -----\n");
131         }
132
133             void setInput(TXFMBase *newInput) {
134                 input = newInput;
135                 if (newInput->getOutputType() != TXFMBase::BYTE_STREAM)
136                         throw XSECException(XSECException::TransformInputOutputFail, "OutputLog transform requires BYTE_STREAM input");
137                 keepComments = input->getCommentsStatus();
138             m_log.debug("\n----- BEGIN SIGNATURE DEBUG -----\n");
139         }
140
141             TXFMBase::ioType getInputType() {
142             return TXFMBase::BYTE_STREAM;
143         }
144             TXFMBase::ioType getOutputType() {
145             return TXFMBase::BYTE_STREAM;
146         }
147             TXFMBase::nodeType getNodeType() {
148             return TXFMBase::DOM_NODE_NONE;
149         }
150
151             unsigned int readBytes(XMLByte * const toFill, const unsigned int maxToFill) {
152                 unsigned int sz = input->readBytes(toFill, maxToFill);
153             m_log.debug(string(reinterpret_cast<char* const>(toFill), sz));
154                 return sz;
155         }
156
157             DOMDocument* getDocument() {
158             return nullptr;
159         }
160             DOMNode* getFragmentNode() {
161             return nullptr;
162         }
163             const XMLCh* getFragmentId() {
164             return nullptr;
165         }
166         
167     private:
168         Category& m_log;
169     };
170
171     TXFMBase* TXFMOutputLogFactory(DOMDocument* doc) {
172         if (Category::getInstance(XMLTOOLING_LOGCAT".Signature.Debugger").isDebugEnabled())
173             return new TXFMOutputLog(doc);
174         return nullptr;
175     }
176 # endif
177
178 #endif
179
180 #ifdef WIN32
181     BOOL LogEvent(
182         LPCSTR  lpUNCServerName,
183         WORD  wType,
184         DWORD  dwEventID,
185         PSID  lpUserSid,
186         LPCSTR  message)
187     {
188         LPCSTR  messages[] = {message, nullptr};
189
190         HANDLE hElog = RegisterEventSource(lpUNCServerName, "OpenSAML XMLTooling Library");
191         BOOL res = ReportEvent(hElog, wType, 0, dwEventID, lpUserSid, 1, 0, messages, nullptr);
192         return (DeregisterEventSource(hElog) && res);
193     }
194 #endif
195 }
196
197 XMLToolingConfig& XMLToolingConfig::getConfig()
198 {
199     return g_config;
200 }
201
202 XMLToolingInternalConfig& XMLToolingInternalConfig::getInternalConfig()
203 {
204     return g_config;
205 }
206
207 #ifndef XMLTOOLING_NO_XMLSEC
208 XMLToolingConfig::XMLToolingConfig()
209     : m_keyInfoResolver(nullptr), m_replayCache(nullptr), m_pathResolver(nullptr), m_templateEngine(nullptr), m_urlEncoder(nullptr), clock_skew_secs(180)
210 #else
211 XMLToolingConfig::XMLToolingConfig()
212     : m_pathResolver(nullptr), m_templateEngine(nullptr), m_urlEncoder(nullptr), clock_skew_secs(180)
213 #endif
214 {
215 }
216
217 XMLToolingConfig::~XMLToolingConfig()
218 {
219 }
220
221 #ifndef XMLTOOLING_LITE
222 const KeyInfoResolver* XMLToolingConfig::getKeyInfoResolver() const
223 {
224     return m_keyInfoResolver;
225 }
226
227 ReplayCache* XMLToolingConfig::getReplayCache() const
228 {
229     return m_replayCache;
230 }
231
232 void XMLToolingConfig::setKeyInfoResolver(xmltooling::KeyInfoResolver *keyInfoResolver)
233 {
234     delete m_keyInfoResolver;
235     m_keyInfoResolver = keyInfoResolver;
236 }
237
238 void XMLToolingConfig::setReplayCache(ReplayCache* replayCache)
239 {
240     delete m_replayCache;
241     m_replayCache = replayCache;
242 }
243 #endif
244
245 PathResolver* XMLToolingConfig::getPathResolver() const
246 {
247     return m_pathResolver;
248 }
249
250 TemplateEngine* XMLToolingConfig::getTemplateEngine() const
251 {
252     return m_templateEngine;
253 }
254
255 const URLEncoder* XMLToolingConfig::getURLEncoder() const
256 {
257     return m_urlEncoder;
258 }
259
260 void XMLToolingConfig::setPathResolver(PathResolver* pathResolver)
261 {
262     delete m_pathResolver;
263     m_pathResolver = pathResolver;
264 }
265
266 void XMLToolingConfig::setTemplateEngine(TemplateEngine* templateEngine)
267 {
268     delete m_templateEngine;
269     m_templateEngine = templateEngine;
270 }
271
272 void XMLToolingConfig::setURLEncoder(URLEncoder* urlEncoder)
273 {
274     delete m_urlEncoder;
275     m_urlEncoder = urlEncoder;
276 }
277
278 XMLToolingInternalConfig::XMLToolingInternalConfig() :
279 #ifndef XMLTOOLING_NO_XMLSEC
280     m_xsecProvider(nullptr),
281 #endif
282     m_initCount(0), m_lock(Mutex::create()), m_parserPool(nullptr), m_validatingPool(nullptr)
283 {
284 }
285
286 XMLToolingInternalConfig::~XMLToolingInternalConfig()
287 {
288     delete m_lock;
289 }
290
291 bool XMLToolingInternalConfig::log_config(const char* config)
292 {
293     try {
294         if (!config || !*config)
295             config=getenv("XMLTOOLING_LOG_CONFIG");
296         if (!config || !*config)
297             config="WARN";
298
299         bool level=false;
300         Category& root = Category::getRoot();
301         if (!strcmp(config,"DEBUG")) {
302             root.setPriority(Priority::DEBUG);
303             level=true;
304         }
305         else if (!strcmp(config,"INFO")) {
306             root.setPriority(Priority::INFO);
307             level=true;
308         }
309         else if (!strcmp(config,"NOTICE")) {
310             root.setPriority(Priority::NOTICE);
311             level=true;
312         }
313         else if (!strcmp(config,"WARN")) {
314             root.setPriority(Priority::WARN);
315             level=true;
316         }
317         else if (!strcmp(config,"ERROR")) {
318             root.setPriority(Priority::ERROR);
319             level=true;
320         }
321         else if (!strcmp(config,"CRIT")) {
322             root.setPriority(Priority::CRIT);
323             level=true;
324         }
325         else if (!strcmp(config,"ALERT")) {
326             root.setPriority(Priority::ALERT);
327             level=true;
328         }
329         else if (!strcmp(config,"EMERG")) {
330             root.setPriority(Priority::EMERG);
331             level=true;
332         }
333         else if (!strcmp(config,"FATAL")) {
334             root.setPriority(Priority::FATAL);
335             level=true;
336         }
337         if (level) {
338             root.setAppender(new OstreamAppender("default",&cerr));
339         }
340         else {
341             string path(config);
342             PropertyConfigurator::configure(m_pathResolver ? m_pathResolver->resolve(path, PathResolver::XMLTOOLING_CFG_FILE) : path);
343         }
344
345 #ifndef XMLTOOLING_NO_XMLSEC
346         Category::getInstance(XMLTOOLING_LOGCAT".Signature.Debugger").setAdditivity(false);
347 #endif
348         }
349     catch (const ConfigureFailure& e) {
350         string msg = string("failed to configure logging: ") + e.what();
351         Category::getInstance(XMLTOOLING_LOGCAT".Logging").crit(msg);
352 #ifdef WIN32
353         LogEvent(nullptr, EVENTLOG_ERROR_TYPE, 2100, nullptr, msg.c_str());
354 #endif
355         return false;
356     }
357
358     return true;
359 }
360
361 bool XMLToolingInternalConfig::init()
362 {
363 #ifdef _DEBUG
364     xmltooling::NDC ndc("init");
365 #endif
366     Category& log=Category::getInstance(XMLTOOLING_LOGCAT".Config");
367
368     Lock initLock(m_lock);
369
370     if (m_initCount == INT_MAX) {
371         log.crit("library initialized too many times");
372         return false;
373     }
374
375     if (m_initCount >= 1) {
376         ++m_initCount;
377         return true;
378     }
379
380     try {
381         log.debug("library initialization started");
382
383 #ifndef XMLTOOLING_NO_XMLSEC
384         if (curl_global_init(CURL_GLOBAL_ALL)) {
385             log.fatal("failed to initialize libcurl, OpenSSL, or Winsock");
386             return false;
387         }
388         curl_version_info_data* curlver = curl_version_info(CURLVERSION_NOW);
389         if (curlver) {
390             log.debug("libcurl %s initialization complete", curlver->version);
391             if (!(curlver->features & CURL_VERSION_SSL)) {
392                 log.warn("libcurl lacks TLS/SSL support, this will greatly limit functionality");
393             }
394         }
395         else {
396             log.debug("libcurl %s initialization complete", LIBCURL_VERSION);
397         }
398 #endif
399
400         XMLPlatformUtils::Initialize();
401         log.debug("Xerces %s initialization complete", XERCES_FULLVERSIONDOT);
402
403 #ifndef XMLTOOLING_NO_XMLSEC
404         XSECPlatformUtils::Initialise();
405 # ifdef XMLTOOLING_XMLSEC_DEBUGLOGGING
406         XSECPlatformUtils::SetReferenceLoggingSink(TXFMOutputLogFactory);
407 # endif
408         m_xsecProvider=new XSECProvider();
409         log.debug("XML-Security %s initialization complete", XSEC_FULLVERSIONDOT);
410 #endif
411
412         m_parserPool=new ParserPool();
413         m_validatingPool=new ParserPool(true,true);
414
415         // Load catalogs from path.
416         if (!catalog_path.empty()) {
417             char* catpath=strdup(catalog_path.c_str());
418             char* sep=nullptr;
419             char* start=catpath;
420             while (start && *start) {
421                 sep=strchr(start,PATH_SEPARATOR_CHAR);
422                 if (sep)
423                     *sep=0;
424                 auto_ptr_XMLCh temp(start);
425                 m_validatingPool->loadCatalog(temp.get());
426                 start = sep ? sep + 1 : nullptr;
427             }
428             free(catpath);
429         }
430
431         // default registrations
432         XMLObjectBuilder::registerDefaultBuilder(new UnknownElementBuilder());
433
434         registerSOAPClasses();
435
436         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(XMLParserException,xmltooling);
437         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(XMLObjectException,xmltooling);
438         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(MarshallingException,xmltooling);
439         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(UnmarshallingException,xmltooling);
440         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(UnknownElementException,xmltooling);
441         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(UnknownAttributeException,xmltooling);
442         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(ValidationException,xmltooling);
443         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(IOException,xmltooling);
444
445 #ifndef XMLTOOLING_NO_XMLSEC
446         XMLObjectBuilder::registerBuilder(QName(xmlconstants::XMLSIG_NS,Signature::LOCAL_NAME),new SignatureBuilder());
447         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(XMLSecurityException,xmltooling);
448         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(SignatureException,xmlsignature);
449         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(EncryptionException,xmlencryption);
450         registerKeyInfoClasses();
451         registerEncryptionClasses();
452         registerKeyInfoResolvers();
453         registerCredentialResolvers();
454         registerTrustEngines();
455         registerXMLAlgorithms();
456         registerSOAPTransports();
457         initSOAPTransports();
458         registerStorageServices();
459         m_keyInfoResolver = KeyInfoResolverManager.newPlugin(INLINE_KEYINFO_RESOLVER,nullptr);
460 #endif
461
462         m_pathResolver = new PathResolver();
463         m_urlEncoder = new URLEncoder();
464
465         HTTPResponse::getAllowedSchemes().push_back("https");
466         HTTPResponse::getAllowedSchemes().push_back("http");
467
468         // Register xml:id as an ID attribute.
469         static const XMLCh xmlid[] = UNICODE_LITERAL_2(i,d);
470         AttributeExtensibleXMLObject::registerIDAttribute(QName(xmlconstants::XML_NS, xmlid));
471     }
472     catch (const xercesc::XMLException&) {
473         log.fatal("caught exception while initializing Xerces");
474 #ifndef XMLTOOLING_NO_XMLSEC
475         curl_global_cleanup();
476 #endif
477         return false;
478     }
479
480 #ifndef XMLTOOLING_NO_XMLSEC
481     // Set up OpenSSL locking.
482     for (int i=0; i<CRYPTO_num_locks(); i++)
483         g_openssl_locks.push_back(Mutex::create());
484     CRYPTO_set_locking_callback(openssl_locking_callback);
485 # ifndef WIN32
486     CRYPTO_set_id_callback(openssl_thread_id);
487 # endif
488 #endif
489
490     log.info("%s library initialization complete", PACKAGE_STRING);
491     ++m_initCount;
492     return true;
493 }
494
495 void XMLToolingInternalConfig::term()
496 {
497 #ifdef _DEBUG
498     xmltooling::NDC ndc("term");
499 #endif
500
501     Lock initLock(m_lock);
502     if (m_initCount == 0) {
503         Category::getInstance(XMLTOOLING_LOGCAT".Config").crit("term without corresponding init");
504         return;
505     }
506     else if (--m_initCount > 0) {
507         return;
508     }
509
510 #ifndef XMLTOOLING_NO_XMLSEC
511     CRYPTO_set_locking_callback(nullptr);
512     for_each(g_openssl_locks.begin(), g_openssl_locks.end(), xmltooling::cleanup<Mutex>());
513     g_openssl_locks.clear();
514 #endif
515
516     SchemaValidators.destroyValidators();
517     XMLObjectBuilder::destroyBuilders();
518     XMLToolingException::deregisterFactories();
519     AttributeExtensibleXMLObject::deregisterIDAttributes();
520
521 #ifndef XMLTOOLING_NO_XMLSEC
522     StorageServiceManager.deregisterFactories();
523     termSOAPTransports();
524     SOAPTransportManager.deregisterFactories();
525     TrustEngineManager.deregisterFactories();
526     CredentialResolverManager.deregisterFactories();
527     KeyInfoResolverManager.deregisterFactories();
528     m_algorithmMap.clear();
529
530     delete m_keyInfoResolver;
531     m_keyInfoResolver = nullptr;
532
533     delete m_replayCache;
534     m_replayCache = nullptr;
535 #endif
536
537     delete m_pathResolver;
538     m_pathResolver = nullptr;
539
540     delete m_templateEngine;
541     m_templateEngine = nullptr;
542
543     delete m_urlEncoder;
544     m_urlEncoder = nullptr;
545
546     for (vector<void*>::reverse_iterator i=m_libhandles.rbegin(); i!=m_libhandles.rend(); i++) {
547 #if defined(WIN32)
548         FARPROC fn=GetProcAddress(static_cast<HMODULE>(*i),"xmltooling_extension_term");
549         if (fn)
550             fn();
551         FreeLibrary(static_cast<HMODULE>(*i));
552 #elif defined(HAVE_DLFCN_H)
553         void (*fn)()=(void (*)())dlsym(*i,"xmltooling_extension_term");
554         if (fn)
555             fn();
556         dlclose(*i);
557 #else
558 # error "Don't know about dynamic loading on this platform!"
559 #endif
560     }
561     m_libhandles.clear();
562
563     delete m_parserPool;
564     m_parserPool=nullptr;
565     delete m_validatingPool;
566     m_validatingPool=nullptr;
567
568 #ifndef XMLTOOLING_NO_XMLSEC
569     delete m_xsecProvider;
570     m_xsecProvider=nullptr;
571     XSECPlatformUtils::Terminate();
572 #endif
573
574     XMLPlatformUtils::Terminate();
575
576 #ifndef XMLTOOLING_NO_XMLSEC
577     curl_global_cleanup();
578 #endif
579    Category::getInstance(XMLTOOLING_LOGCAT".Config").info("%s library shutdown complete", PACKAGE_STRING);
580 }
581
582 Lockable* XMLToolingInternalConfig::lock()
583 {
584     m_lock->lock();
585     return this;
586 }
587
588 void XMLToolingInternalConfig::unlock()
589 {
590     m_lock->unlock();
591 }
592
593 bool XMLToolingInternalConfig::load_library(const char* path, void* context)
594 {
595 #ifdef _DEBUG
596     xmltooling::NDC ndc("LoadLibrary");
597 #endif
598     Category& log=Category::getInstance(XMLTOOLING_LOGCAT".Config");
599     log.info("loading extension: %s", path);
600
601     Locker locker(this);
602
603     string resolved(path);
604     m_pathResolver->resolve(resolved, PathResolver::XMLTOOLING_LIB_FILE);
605
606 #if defined(WIN32)
607     HMODULE handle=nullptr;
608     for (string::iterator i = resolved.begin(); i != resolved.end(); ++i)
609         if (*i == '/')
610             *i = '\\';
611
612     UINT em=SetErrorMode(SEM_FAILCRITICALERRORS);
613     try {
614         handle=LoadLibraryEx(resolved.c_str(),nullptr,LOAD_WITH_ALTERED_SEARCH_PATH);
615         if (!handle)
616              handle=LoadLibraryEx(resolved.c_str(),nullptr,0);
617         if (!handle)
618             throw runtime_error(string("unable to load extension library: ") + resolved);
619         FARPROC fn=GetProcAddress(handle,"xmltooling_extension_init");
620         if (!fn)
621             throw runtime_error(string("unable to locate xmltooling_extension_init entry point: ") + resolved);
622         if (reinterpret_cast<int(*)(void*)>(fn)(context)!=0)
623             throw runtime_error(string("detected error in xmltooling_extension_init: ") + resolved);
624         SetErrorMode(em);
625     }
626     catch(exception&) {
627         if (handle)
628             FreeLibrary(handle);
629         SetErrorMode(em);
630         throw;
631     }
632
633 #elif defined(HAVE_DLFCN_H)
634     void* handle=dlopen(resolved.c_str(),RTLD_LAZY);
635     if (!handle)
636         throw runtime_error(string("unable to load extension library '") + resolved + "': " + dlerror());
637     int (*fn)(void*)=(int (*)(void*))(dlsym(handle,"xmltooling_extension_init"));
638     if (!fn) {
639         dlclose(handle);
640         throw runtime_error(
641             string("unable to locate xmltooling_extension_init entry point in '") + resolved + "': " +
642                 (dlerror() ? dlerror() : "unknown error")
643             );
644     }
645     try {
646         if (fn(context)!=0)
647             throw runtime_error(string("detected error in xmltooling_extension_init in ") + resolved);
648     }
649     catch(exception&) {
650         if (handle)
651             dlclose(handle);
652         throw;
653     }
654 #else
655 # error "Don't know about dynamic loading on this platform!"
656 #endif
657     m_libhandles.push_back(handle);
658     log.info("loaded extension: %s", resolved.c_str());
659     return true;
660 }
661
662 #ifndef XMLTOOLING_NO_XMLSEC
663
664 void xmltooling::log_openssl()
665 {
666     const char* file;
667     const char* data;
668     int flags,line;
669
670     unsigned long code=ERR_get_error_line_data(&file,&line,&data,&flags);
671     while (code) {
672         Category& log=Category::getInstance("OpenSSL");
673         log.errorStream() << "error code: " << code << " in " << file << ", line " << line << logging::eol;
674         if (data && (flags & ERR_TXT_STRING))
675             log.errorStream() << "error data: " << data << logging::eol;
676         code=ERR_get_error_line_data(&file,&line,&data,&flags);
677     }
678 }
679
680 XSECCryptoX509CRL* XMLToolingInternalConfig::X509CRL() const
681 {
682     return new OpenSSLCryptoX509CRL();
683 }
684
685 pair<const char*,unsigned int> XMLToolingInternalConfig::mapXMLAlgorithmToKeyAlgorithm(const XMLCh* xmlAlgorithm) const
686 {
687     for (algmap_t::const_iterator i = m_algorithmMap.begin(); i != m_algorithmMap.end(); ++i) {
688         algmap_t::value_type::second_type::const_iterator j = i->second.find(xmlAlgorithm);
689         if (j != i->second.end())
690             return pair<const char*,unsigned int>(j->second.first.c_str(), j->second.second);
691     }
692     return pair<const char*,unsigned int>(nullptr, 0);
693 }
694
695 void XMLToolingInternalConfig::registerXMLAlgorithm(
696     const XMLCh* xmlAlgorithm, const char* keyAlgorithm, unsigned int size, XMLSecurityAlgorithmType type
697     )
698 {
699     m_algorithmMap[type][xmlAlgorithm] = pair<string,unsigned int>((keyAlgorithm ? keyAlgorithm : ""), size);
700 }
701
702 bool XMLToolingInternalConfig::isXMLAlgorithmSupported(const XMLCh* xmlAlgorithm, XMLSecurityAlgorithmType type)
703 {
704     try {
705         // First check for basic support from the xmlsec layer.
706         if (XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(xmlAlgorithm)) {
707             // Make sure the algorithm is registered.
708             algmap_t::const_iterator i = m_algorithmMap.find(type);
709             if (i != m_algorithmMap.end()) {
710                 algmap_t::value_type::second_type::const_iterator j = i->second.find(xmlAlgorithm);
711                 if (j != i->second.end())
712                     return true;
713             }
714         }
715     }
716     catch (XSECException&) {
717     }
718     return false;
719 }
720
721 void XMLToolingInternalConfig::registerXMLAlgorithms()
722 {
723     // The deal with all the macros is to try and figure out with no false positives whether
724     // the OpenSSL version *and* the XML-Security version support the algorithms.
725
726     // With ECDSA, XML-Security exports a public macro for OpenSSL's support, and any
727     // versions of XML-Security that didn't provide the macro don't handle ECDSA anyway.
728
729     // With AES, all supported XML-Security versions export a macro for OpenSSL's support.
730
731     // With SHA2, only the very latest XML-Security exports a macro, but all the versions
732     // will handle SHA2 *if* OpenSSL does. So we use our own macro to check OpenSSL's
733     // support, and then add checks to see if specific versions are compiled out.
734
735     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIMD5, nullptr, 0, ALGTYPE_DIGEST);
736     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURISHA1, nullptr, 0, ALGTYPE_DIGEST);
737 #if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA256)
738     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURISHA224, nullptr, 0, ALGTYPE_DIGEST);
739     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURISHA256, nullptr, 0, ALGTYPE_DIGEST);
740 #endif
741 #if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA512)
742     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURISHA384, nullptr, 0, ALGTYPE_DIGEST);
743     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURISHA512, nullptr, 0, ALGTYPE_DIGEST);
744 #endif
745
746     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIDSA_SHA1, "DSA", 0, ALGTYPE_SIGN);
747     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_MD5, "RSA", 0, ALGTYPE_SIGN);
748     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA1, "RSA", 0, ALGTYPE_SIGN);
749 #if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA256)
750     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA224, "RSA", 0, ALGTYPE_SIGN);
751     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA256, "RSA", 0, ALGTYPE_SIGN);
752 #endif
753 #if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA512)
754     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA384, "RSA", 0, ALGTYPE_SIGN);
755     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA512, "RSA", 0, ALGTYPE_SIGN);
756 #endif
757
758 #ifdef XSEC_OPENSSL_HAVE_EC
759     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA1, "EC", 0, ALGTYPE_SIGN);
760 #if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA256)
761     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA256, "EC", 0, ALGTYPE_SIGN);
762 # endif
763 #if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA512)
764     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA384, "EC", 0, ALGTYPE_SIGN);
765     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA512, "EC", 0, ALGTYPE_SIGN);
766 # endif
767 #endif
768
769     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA1, "HMAC", 0, ALGTYPE_SIGN);
770 #if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA256)
771     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA224, "HMAC", 0, ALGTYPE_SIGN);
772     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA256, "HMAC", 0, ALGTYPE_SIGN);
773 #endif
774 #if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA512)
775     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA384, "HMAC", 0, ALGTYPE_SIGN);
776     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA512, "HMAC", 0, ALGTYPE_SIGN);
777 #endif
778
779     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_1_5, "RSA", 0, ALGTYPE_KEYENCRYPT);
780     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1, "RSA", 0, ALGTYPE_KEYENCRYPT);
781
782     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURI3DES_CBC, "DESede", 192, ALGTYPE_ENCRYPT);
783     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_3DES, "DESede", 192, ALGTYPE_KEYENCRYPT);
784
785 #ifdef XSEC_OPENSSL_HAVE_AES
786     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIAES128_CBC, "AES", 128, ALGTYPE_ENCRYPT);
787     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_AES128, "AES", 128, ALGTYPE_KEYENCRYPT);
788
789     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIAES192_CBC, "AES", 192, ALGTYPE_ENCRYPT);
790     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_AES192, "AES", 192, ALGTYPE_KEYENCRYPT);
791
792     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIAES256_CBC, "AES", 256, ALGTYPE_ENCRYPT);
793     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_AES256, "AES", 256, ALGTYPE_KEYENCRYPT);
794 #endif
795 }
796
797 #endif
798
799 #ifdef WIN32
800
801 extern "C" __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID)
802 {
803     if (fdwReason == DLL_THREAD_DETACH || fdwReason == DLL_PROCESS_DETACH)
804         ThreadKey::onDetach();
805     return TRUE;
806 }
807
808 #endif