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