Backport fixes from main branch and rev patch version.
[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 bool XMLToolingInternalConfig::log_config(const char* config)
222 {
223     try {
224         if (!config || !*config)
225             config=getenv("XMLTOOLING_LOG_CONFIG");
226         if (!config || !*config)
227             config="WARN";
228
229         bool level=false;
230         Category& root = Category::getRoot();
231         if (!strcmp(config,"DEBUG")) {
232             root.setPriority(Priority::DEBUG);
233             level=true;
234         }
235         else if (!strcmp(config,"INFO")) {
236             root.setPriority(Priority::INFO);
237             level=true;
238         }
239         else if (!strcmp(config,"NOTICE")) {
240             root.setPriority(Priority::NOTICE);
241             level=true;
242         }
243         else if (!strcmp(config,"WARN")) {
244             root.setPriority(Priority::WARN);
245             level=true;
246         }
247         else if (!strcmp(config,"ERROR")) {
248             root.setPriority(Priority::ERROR);
249             level=true;
250         }
251         else if (!strcmp(config,"CRIT")) {
252             root.setPriority(Priority::CRIT);
253             level=true;
254         }
255         else if (!strcmp(config,"ALERT")) {
256             root.setPriority(Priority::ALERT);
257             level=true;
258         }
259         else if (!strcmp(config,"EMERG")) {
260             root.setPriority(Priority::EMERG);
261             level=true;
262         }
263         else if (!strcmp(config,"FATAL")) {
264             root.setPriority(Priority::FATAL);
265             level=true;
266         }
267         if (level) {
268             root.setAppender(new OstreamAppender("default",&cerr));
269         }
270         else {
271             string path(config);
272             PropertyConfigurator::configure(m_pathResolver ? m_pathResolver->resolve(path, PathResolver::XMLTOOLING_CFG_FILE) : path);
273         }
274
275 #ifndef XMLTOOLING_NO_XMLSEC
276         Category::getInstance(XMLTOOLING_LOGCAT".Signature.Debugger").setAdditivity(false);
277 #endif
278         }
279     catch (const ConfigureFailure& e) {
280         string msg = string("failed to configure logging: ") + e.what();
281         Category::getInstance(XMLTOOLING_LOGCAT".Logging").crit(msg);
282 #ifdef WIN32
283         LogEvent(nullptr, EVENTLOG_ERROR_TYPE, 2100, nullptr, msg.c_str());
284 #endif
285         return false;
286     }
287
288     return true;
289 }
290
291 #ifndef XMLTOOLING_LITE
292 const KeyInfoResolver* XMLToolingConfig::getKeyInfoResolver() const
293 {
294     return m_keyInfoResolver;
295 }
296
297 ReplayCache* XMLToolingConfig::getReplayCache() const
298 {
299     return m_replayCache;
300 }
301
302 void XMLToolingConfig::setKeyInfoResolver(xmltooling::KeyInfoResolver *keyInfoResolver)
303 {
304     delete m_keyInfoResolver;
305     m_keyInfoResolver = keyInfoResolver;
306 }
307
308 void XMLToolingConfig::setReplayCache(ReplayCache* replayCache)
309 {
310     delete m_replayCache;
311     m_replayCache = replayCache;
312 }
313 #endif
314
315 PathResolver* XMLToolingConfig::getPathResolver() const
316 {
317     return m_pathResolver;
318 }
319
320 TemplateEngine* XMLToolingConfig::getTemplateEngine() const
321 {
322     return m_templateEngine;
323 }
324
325 const URLEncoder* XMLToolingConfig::getURLEncoder() const
326 {
327     return m_urlEncoder;
328 }
329
330 void XMLToolingConfig::setPathResolver(PathResolver* pathResolver)
331 {
332     delete m_pathResolver;
333     m_pathResolver = pathResolver;
334 }
335
336 void XMLToolingConfig::setTemplateEngine(TemplateEngine* templateEngine)
337 {
338     delete m_templateEngine;
339     m_templateEngine = templateEngine;
340 }
341
342 void XMLToolingConfig::setURLEncoder(URLEncoder* urlEncoder)
343 {
344     delete m_urlEncoder;
345     m_urlEncoder = urlEncoder;
346 }
347
348 bool XMLToolingInternalConfig::init()
349 {
350 #ifdef _DEBUG
351     xmltooling::NDC ndc("init");
352 #endif
353     Category& log=Category::getInstance(XMLTOOLING_LOGCAT".XMLToolingConfig");
354     try {
355         log.debug("library initialization started");
356
357 #ifndef XMLTOOLING_NO_XMLSEC
358         if (curl_global_init(CURL_GLOBAL_ALL)) {
359             log.fatal("failed to initialize libcurl, OpenSSL, or Winsock");
360             return false;
361         }
362         curl_version_info_data* curlver = curl_version_info(CURLVERSION_NOW);
363         if (curlver) {
364             log.debug("libcurl %s initialization complete", curlver->version);
365             if (!(curlver->features & CURL_VERSION_SSL)) {
366                 log.warn("libcurl lacks TLS/SSL support, this will greatly limit functionality");
367             }
368         }
369         else {
370             log.debug("libcurl %s initialization complete", LIBCURL_VERSION);
371         }
372 #endif
373
374         XMLPlatformUtils::Initialize();
375         log.debug("Xerces %s initialization complete", XERCES_FULLVERSIONDOT);
376
377 #ifndef XMLTOOLING_NO_XMLSEC
378         XSECPlatformUtils::Initialise();
379 # ifdef XMLTOOLING_XMLSEC_DEBUGLOGGING
380         XSECPlatformUtils::SetReferenceLoggingSink(TXFMOutputLogFactory);
381 # endif
382         m_xsecProvider=new XSECProvider();
383         log.debug("XML-Security %s initialization complete", XSEC_FULLVERSIONDOT);
384 #endif
385
386         m_parserPool=new ParserPool();
387         m_validatingPool=new ParserPool(true,true);
388         m_lock=XMLPlatformUtils::makeMutex();
389
390         // Load catalogs from path.
391         if (!catalog_path.empty()) {
392             char* catpath=strdup(catalog_path.c_str());
393             char* sep=nullptr;
394             char* start=catpath;
395             while (start && *start) {
396                 sep=strchr(start,PATH_SEPARATOR_CHAR);
397                 if (sep)
398                     *sep=0;
399                 auto_ptr_XMLCh temp(start);
400                 m_validatingPool->loadCatalog(temp.get());
401                 start = sep ? sep + 1 : nullptr;
402             }
403             free(catpath);
404         }
405
406         // default registrations
407         XMLObjectBuilder::registerDefaultBuilder(new UnknownElementBuilder());
408
409         registerSOAPClasses();
410
411         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(XMLParserException,xmltooling);
412         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(XMLObjectException,xmltooling);
413         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(MarshallingException,xmltooling);
414         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(UnmarshallingException,xmltooling);
415         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(UnknownElementException,xmltooling);
416         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(UnknownAttributeException,xmltooling);
417         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(ValidationException,xmltooling);
418         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(IOException,xmltooling);
419
420 #ifndef XMLTOOLING_NO_XMLSEC
421         XMLObjectBuilder::registerBuilder(QName(xmlconstants::XMLSIG_NS,Signature::LOCAL_NAME),new SignatureBuilder());
422         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(XMLSecurityException,xmltooling);
423         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(SignatureException,xmlsignature);
424         REGISTER_XMLTOOLING_EXCEPTION_FACTORY(EncryptionException,xmlencryption);
425         registerKeyInfoClasses();
426         registerEncryptionClasses();
427         registerKeyInfoResolvers();
428         registerCredentialResolvers();
429         registerTrustEngines();
430         registerXMLAlgorithms();
431         registerSOAPTransports();
432         initSOAPTransports();
433         registerStorageServices();
434         m_keyInfoResolver = KeyInfoResolverManager.newPlugin(INLINE_KEYINFO_RESOLVER,nullptr);
435 #endif
436
437         m_pathResolver = new PathResolver();
438         m_urlEncoder = new URLEncoder();
439
440         HTTPResponse::getAllowedSchemes().push_back("https");
441         HTTPResponse::getAllowedSchemes().push_back("http");
442
443         // Register xml:id as an ID attribute.
444         static const XMLCh xmlid[] = UNICODE_LITERAL_2(i,d);
445         AttributeExtensibleXMLObject::registerIDAttribute(QName(xmlconstants::XML_NS, xmlid));
446     }
447     catch (const xercesc::XMLException&) {
448         log.fatal("caught exception while initializing Xerces");
449 #ifndef XMLTOOLING_NO_XMLSEC
450         curl_global_cleanup();
451 #endif
452         return false;
453     }
454
455 #ifndef XMLTOOLING_NO_XMLSEC
456     // Set up OpenSSL locking.
457     for (int i=0; i<CRYPTO_num_locks(); i++)
458         g_openssl_locks.push_back(Mutex::create());
459     CRYPTO_set_locking_callback(openssl_locking_callback);
460 # ifndef WIN32
461     CRYPTO_set_id_callback(openssl_thread_id);
462 # endif
463 #endif
464
465     log.info("%s library initialization complete", PACKAGE_STRING);
466     return true;
467 }
468
469 void XMLToolingInternalConfig::term()
470 {
471 #ifndef XMLTOOLING_NO_XMLSEC
472     CRYPTO_set_locking_callback(nullptr);
473     for_each(g_openssl_locks.begin(), g_openssl_locks.end(), xmltooling::cleanup<Mutex>());
474     g_openssl_locks.clear();
475 #endif
476
477     SchemaValidators.destroyValidators();
478     XMLObjectBuilder::destroyBuilders();
479     XMLToolingException::deregisterFactories();
480     AttributeExtensibleXMLObject::deregisterIDAttributes();
481
482 #ifndef XMLTOOLING_NO_XMLSEC
483     StorageServiceManager.deregisterFactories();
484     termSOAPTransports();
485     SOAPTransportManager.deregisterFactories();
486     TrustEngineManager.deregisterFactories();
487     CredentialResolverManager.deregisterFactories();
488     KeyInfoResolverManager.deregisterFactories();
489     m_algorithmMap.clear();
490
491     delete m_keyInfoResolver;
492     m_keyInfoResolver = nullptr;
493
494     delete m_replayCache;
495     m_replayCache = nullptr;
496 #endif
497
498     delete m_pathResolver;
499     m_pathResolver = nullptr;
500
501     delete m_templateEngine;
502     m_templateEngine = nullptr;
503
504     delete m_urlEncoder;
505     m_urlEncoder = nullptr;
506
507     for (vector<void*>::reverse_iterator i=m_libhandles.rbegin(); i!=m_libhandles.rend(); i++) {
508 #if defined(WIN32)
509         FARPROC fn=GetProcAddress(static_cast<HMODULE>(*i),"xmltooling_extension_term");
510         if (fn)
511             fn();
512         FreeLibrary(static_cast<HMODULE>(*i));
513 #elif defined(HAVE_DLFCN_H)
514         void (*fn)()=(void (*)())dlsym(*i,"xmltooling_extension_term");
515         if (fn)
516             fn();
517         dlclose(*i);
518 #else
519 # error "Don't know about dynamic loading on this platform!"
520 #endif
521     }
522     m_libhandles.clear();
523
524     delete m_parserPool;
525     m_parserPool=nullptr;
526     delete m_validatingPool;
527     m_validatingPool=nullptr;
528
529 #ifndef XMLTOOLING_NO_XMLSEC
530     delete m_xsecProvider;
531     m_xsecProvider=nullptr;
532     XSECPlatformUtils::Terminate();
533 #endif
534
535     XMLPlatformUtils::closeMutex(m_lock);
536     m_lock=nullptr;
537     XMLPlatformUtils::Terminate();
538
539 #ifndef XMLTOOLING_NO_XMLSEC
540     curl_global_cleanup();
541 #endif
542 #ifdef _DEBUG
543     xmltooling::NDC ndc("term");
544 #endif
545    Category::getInstance(XMLTOOLING_LOGCAT".XMLToolingConfig").info("%s library shutdown complete", PACKAGE_STRING);
546 }
547
548 Lockable* XMLToolingInternalConfig::lock()
549 {
550     xercesc::XMLPlatformUtils::lockMutex(m_lock);
551     return this;
552 }
553
554 void XMLToolingInternalConfig::unlock()
555 {
556     xercesc::XMLPlatformUtils::unlockMutex(m_lock);
557 }
558
559 bool XMLToolingInternalConfig::load_library(const char* path, void* context)
560 {
561 #ifdef _DEBUG
562     xmltooling::NDC ndc("LoadLibrary");
563 #endif
564     Category& log=Category::getInstance(XMLTOOLING_LOGCAT".XMLToolingConfig");
565     log.info("loading extension: %s", path);
566
567     Locker locker(this);
568
569     string resolved(path);
570     m_pathResolver->resolve(resolved, PathResolver::XMLTOOLING_LIB_FILE);
571
572 #if defined(WIN32)
573     HMODULE handle=nullptr;
574     for (string::iterator i = resolved.begin(); i != resolved.end(); ++i)
575         if (*i == '/')
576             *i = '\\';
577
578     UINT em=SetErrorMode(SEM_FAILCRITICALERRORS);
579     try {
580         handle=LoadLibraryEx(resolved.c_str(),nullptr,LOAD_WITH_ALTERED_SEARCH_PATH);
581         if (!handle)
582              handle=LoadLibraryEx(resolved.c_str(),nullptr,0);
583         if (!handle)
584             throw runtime_error(string("unable to load extension library: ") + resolved);
585         FARPROC fn=GetProcAddress(handle,"xmltooling_extension_init");
586         if (!fn)
587             throw runtime_error(string("unable to locate xmltooling_extension_init entry point: ") + resolved);
588         if (reinterpret_cast<int(*)(void*)>(fn)(context)!=0)
589             throw runtime_error(string("detected error in xmltooling_extension_init: ") + resolved);
590         SetErrorMode(em);
591     }
592     catch(exception&) {
593         if (handle)
594             FreeLibrary(handle);
595         SetErrorMode(em);
596         throw;
597     }
598
599 #elif defined(HAVE_DLFCN_H)
600     void* handle=dlopen(resolved.c_str(),RTLD_LAZY);
601     if (!handle)
602         throw runtime_error(string("unable to load extension library '") + resolved + "': " + dlerror());
603     int (*fn)(void*)=(int (*)(void*))(dlsym(handle,"xmltooling_extension_init"));
604     if (!fn) {
605         dlclose(handle);
606         throw runtime_error(
607             string("unable to locate xmltooling_extension_init entry point in '") + resolved + "': " +
608                 (dlerror() ? dlerror() : "unknown error")
609             );
610     }
611     try {
612         if (fn(context)!=0)
613             throw runtime_error(string("detected error in xmltooling_extension_init in ") + resolved);
614     }
615     catch(exception&) {
616         if (handle)
617             dlclose(handle);
618         throw;
619     }
620 #else
621 # error "Don't know about dynamic loading on this platform!"
622 #endif
623     m_libhandles.push_back(handle);
624     log.info("loaded extension: %s", resolved.c_str());
625     return true;
626 }
627
628 #ifndef XMLTOOLING_NO_XMLSEC
629
630 void xmltooling::log_openssl()
631 {
632     const char* file;
633     const char* data;
634     int flags,line;
635
636     unsigned long code=ERR_get_error_line_data(&file,&line,&data,&flags);
637     while (code) {
638         Category& log=Category::getInstance("OpenSSL");
639         log.errorStream() << "error code: " << code << " in " << file << ", line " << line << logging::eol;
640         if (data && (flags & ERR_TXT_STRING))
641             log.errorStream() << "error data: " << data << logging::eol;
642         code=ERR_get_error_line_data(&file,&line,&data,&flags);
643     }
644 }
645
646 XSECCryptoX509CRL* XMLToolingInternalConfig::X509CRL() const
647 {
648     return new OpenSSLCryptoX509CRL();
649 }
650
651 pair<const char*,unsigned int> XMLToolingInternalConfig::mapXMLAlgorithmToKeyAlgorithm(const XMLCh* xmlAlgorithm) const
652 {
653     for (algmap_t::const_iterator i = m_algorithmMap.begin(); i != m_algorithmMap.end(); ++i) {
654         algmap_t::value_type::second_type::const_iterator j = i->second.find(xmlAlgorithm);
655         if (j != i->second.end())
656             return pair<const char*,unsigned int>(j->second.first.c_str(), j->second.second);
657     }
658     return pair<const char*,unsigned int>(nullptr, 0);
659 }
660
661 void XMLToolingInternalConfig::registerXMLAlgorithm(
662     const XMLCh* xmlAlgorithm, const char* keyAlgorithm, unsigned int size, XMLSecurityAlgorithmType type
663     )
664 {
665     m_algorithmMap[type][xmlAlgorithm] = pair<string,unsigned int>((keyAlgorithm ? keyAlgorithm : ""), size);
666 }
667
668 bool XMLToolingInternalConfig::isXMLAlgorithmSupported(const XMLCh* xmlAlgorithm, XMLSecurityAlgorithmType type)
669 {
670     try {
671         // First check for basic support from the xmlsec layer.
672         if (XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(xmlAlgorithm)) {
673             // Make sure the algorithm is registered.
674             algmap_t::const_iterator i = m_algorithmMap.find(type);
675             if (i != m_algorithmMap.end()) {
676                 algmap_t::value_type::second_type::const_iterator j = i->second.find(xmlAlgorithm);
677                 if (j != i->second.end())
678                     return true;
679             }
680         }
681     }
682     catch (XSECException&) {
683     }
684     return false;
685 }
686
687 void XMLToolingInternalConfig::registerXMLAlgorithms()
688 {
689     // The deal with all the macros is to try and figure out with no false positives whether
690     // the OpenSSL version *and* the XML-Security version support the algorithms.
691
692     // With ECDSA, XML-Security exports a public macro for OpenSSL's support, and any
693     // versions of XML-Security that didn't provide the macro don't handle ECDSA anyway.
694
695     // With AES, all supported XML-Security versions export a macro for OpenSSL's support.
696
697     // With SHA2, only the very latest XML-Security exports a macro, but all the versions
698     // will handle SHA2 *if* OpenSSL does. So we use our own macro to check OpenSSL's
699     // support, and then add checks to see if specific versions are compiled out.
700
701     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIMD5, nullptr, 0, ALGTYPE_DIGEST);
702     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURISHA1, nullptr, 0, ALGTYPE_DIGEST);
703 #if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA256)
704     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURISHA224, nullptr, 0, ALGTYPE_DIGEST);
705     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURISHA256, nullptr, 0, ALGTYPE_DIGEST);
706 #endif
707 #if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA512)
708     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURISHA384, nullptr, 0, ALGTYPE_DIGEST);
709     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURISHA512, nullptr, 0, ALGTYPE_DIGEST);
710 #endif
711
712     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIDSA_SHA1, "DSA", 0, ALGTYPE_SIGN);
713     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_MD5, "RSA", 0, ALGTYPE_SIGN);
714     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA1, "RSA", 0, ALGTYPE_SIGN);
715 #if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA256)
716     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA224, "RSA", 0, ALGTYPE_SIGN);
717     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA256, "RSA", 0, ALGTYPE_SIGN);
718 #endif
719 #if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA512)
720     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA384, "RSA", 0, ALGTYPE_SIGN);
721     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA512, "RSA", 0, ALGTYPE_SIGN);
722 #endif
723
724 #ifdef XSEC_OPENSSL_HAVE_EC
725     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA1, "EC", 0, ALGTYPE_SIGN);
726 #if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA256)
727     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA256, "EC", 0, ALGTYPE_SIGN);
728 # endif
729 #if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA512)
730     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA384, "EC", 0, ALGTYPE_SIGN);
731     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA512, "EC", 0, ALGTYPE_SIGN);
732 # endif
733 #endif
734
735     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA1, "HMAC", 0, ALGTYPE_SIGN);
736 #if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA256)
737     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA224, "HMAC", 0, ALGTYPE_SIGN);
738     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA256, "HMAC", 0, ALGTYPE_SIGN);
739 #endif
740 #if defined(XMLTOOLING_OPENSSL_HAVE_SHA2) && !defined(OPENSSL_NO_SHA512)
741     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA384, "HMAC", 0, ALGTYPE_SIGN);
742     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA512, "HMAC", 0, ALGTYPE_SIGN);
743 #endif
744
745     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_1_5, "RSA", 0, ALGTYPE_KEYENCRYPT);
746     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1, "RSA", 0, ALGTYPE_KEYENCRYPT);
747
748     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURI3DES_CBC, "DESede", 192, ALGTYPE_ENCRYPT);
749     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_3DES, "DESede", 192, ALGTYPE_KEYENCRYPT);
750
751 #ifdef XSEC_OPENSSL_HAVE_AES
752     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIAES128_CBC, "AES", 128, ALGTYPE_ENCRYPT);
753     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_AES128, "AES", 128, ALGTYPE_KEYENCRYPT);
754
755     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIAES192_CBC, "AES", 192, ALGTYPE_ENCRYPT);
756     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_AES192, "AES", 192, ALGTYPE_KEYENCRYPT);
757
758     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIAES256_CBC, "AES", 256, ALGTYPE_ENCRYPT);
759     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_AES256, "AES", 256, ALGTYPE_KEYENCRYPT);
760 #endif
761 }
762
763 #endif
764
765 #ifdef WIN32
766
767 extern "C" __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID)
768 {
769     if (fdwReason == DLL_THREAD_DETACH || fdwReason == DLL_PROCESS_DETACH)
770         ThreadKey::onDetach();
771     return TRUE;
772 }
773
774 #endif