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