2 * Copyright 2001-2010 Internet2
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * XMLToolingConfig.cpp
20 * Library configuration.
24 #include "exceptions.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"
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"
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>
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 <xsec/framework/XSECAlgorithmMapper.hpp>
65 # include <xsec/framework/XSECException.hpp>
66 # include <xsec/framework/XSECProvider.hpp>
67 # include <xsec/transformers/TXFMBase.hpp>
70 using namespace soap11;
71 using namespace xmltooling::logging;
72 using namespace xmltooling;
73 using namespace xercesc;
77 DECL_XMLTOOLING_EXCEPTION_FACTORY(XMLParserException,xmltooling);
78 DECL_XMLTOOLING_EXCEPTION_FACTORY(XMLObjectException,xmltooling);
79 DECL_XMLTOOLING_EXCEPTION_FACTORY(MarshallingException,xmltooling);
80 DECL_XMLTOOLING_EXCEPTION_FACTORY(UnmarshallingException,xmltooling);
81 DECL_XMLTOOLING_EXCEPTION_FACTORY(UnknownElementException,xmltooling);
82 DECL_XMLTOOLING_EXCEPTION_FACTORY(UnknownAttributeException,xmltooling);
83 DECL_XMLTOOLING_EXCEPTION_FACTORY(UnknownExtensionException,xmltooling);
84 DECL_XMLTOOLING_EXCEPTION_FACTORY(ValidationException,xmltooling);
85 DECL_XMLTOOLING_EXCEPTION_FACTORY(IOException,xmltooling);
87 #ifndef XMLTOOLING_NO_XMLSEC
88 using namespace xmlencryption;
89 using namespace xmlsignature;
90 DECL_XMLTOOLING_EXCEPTION_FACTORY(XMLSecurityException,xmltooling);
91 DECL_XMLTOOLING_EXCEPTION_FACTORY(SignatureException,xmlsignature);
92 DECL_XMLTOOLING_EXCEPTION_FACTORY(EncryptionException,xmlencryption);
96 static XMLToolingInternalConfig g_config;
97 #ifndef XMLTOOLING_NO_XMLSEC
98 static vector<Mutex*> g_openssl_locks;
100 extern "C" void openssl_locking_callback(int mode,int n,const char *file,int line)
102 if (mode & CRYPTO_LOCK)
103 g_openssl_locks[n]->lock();
105 g_openssl_locks[n]->unlock();
109 extern "C" unsigned long openssl_thread_id(void)
111 return (unsigned long)(pthread_self());
115 # ifdef XMLTOOLING_XMLSEC_DEBUGLOGGING
116 class TXFMOutputLog : public TXFMBase {
119 TXFMOutputLog(DOMDocument* doc) : TXFMBase(doc), m_log(Category::getInstance(XMLTOOLING_LOGCAT".Signature.Debugger")) {
123 m_log.debug("\n----- END SIGNATURE DEBUG -----\n");
126 void setInput(TXFMBase *newInput) {
128 if (newInput->getOutputType() != TXFMBase::BYTE_STREAM)
129 throw XSECException(XSECException::TransformInputOutputFail, "OutputLog transform requires BYTE_STREAM input");
130 keepComments = input->getCommentsStatus();
131 m_log.debug("\n----- BEGIN SIGNATURE DEBUG -----\n");
134 TXFMBase::ioType getInputType() {
135 return TXFMBase::BYTE_STREAM;
137 TXFMBase::ioType getOutputType() {
138 return TXFMBase::BYTE_STREAM;
140 TXFMBase::nodeType getNodeType() {
141 return TXFMBase::DOM_NODE_NONE;
144 unsigned int readBytes(XMLByte * const toFill, const unsigned int maxToFill) {
145 unsigned int sz = input->readBytes(toFill, maxToFill);
146 m_log.debug(string(reinterpret_cast<char* const>(toFill), sz));
150 DOMDocument* getDocument() {
153 DOMNode* getFragmentNode() {
156 const XMLCh* getFragmentId() {
164 TXFMBase* TXFMOutputLogFactory(DOMDocument* doc) {
165 if (Category::getInstance(XMLTOOLING_LOGCAT".Signature.Debugger").isDebugEnabled())
166 return new TXFMOutputLog(doc);
175 LPCSTR lpUNCServerName,
181 LPCSTR messages[] = {message, nullptr};
183 HANDLE hElog = RegisterEventSource(lpUNCServerName, "OpenSAML XMLTooling Library");
184 BOOL res = ReportEvent(hElog, wType, 0, dwEventID, lpUserSid, 1, 0, messages, nullptr);
185 return (DeregisterEventSource(hElog) && res);
190 XMLToolingConfig& XMLToolingConfig::getConfig()
195 XMLToolingInternalConfig& XMLToolingInternalConfig::getInternalConfig()
200 #ifndef XMLTOOLING_NO_XMLSEC
201 XMLToolingConfig::XMLToolingConfig()
202 : m_keyInfoResolver(nullptr), m_replayCache(nullptr), m_pathResolver(nullptr), m_templateEngine(nullptr), m_urlEncoder(nullptr), clock_skew_secs(180)
204 XMLToolingConfig::XMLToolingConfig()
205 : m_pathResolver(nullptr), m_templateEngine(nullptr), m_urlEncoder(nullptr), clock_skew_secs(180)
210 XMLToolingConfig::~XMLToolingConfig()
214 bool XMLToolingInternalConfig::log_config(const char* config)
217 if (!config || !*config)
218 config=getenv("XMLTOOLING_LOG_CONFIG");
219 if (!config || !*config)
223 Category& root = Category::getRoot();
224 if (!strcmp(config,"DEBUG")) {
225 root.setPriority(Priority::DEBUG);
228 else if (!strcmp(config,"INFO")) {
229 root.setPriority(Priority::INFO);
232 else if (!strcmp(config,"NOTICE")) {
233 root.setPriority(Priority::NOTICE);
236 else if (!strcmp(config,"WARN")) {
237 root.setPriority(Priority::WARN);
240 else if (!strcmp(config,"ERROR")) {
241 root.setPriority(Priority::ERROR);
244 else if (!strcmp(config,"CRIT")) {
245 root.setPriority(Priority::CRIT);
248 else if (!strcmp(config,"ALERT")) {
249 root.setPriority(Priority::ALERT);
252 else if (!strcmp(config,"EMERG")) {
253 root.setPriority(Priority::EMERG);
256 else if (!strcmp(config,"FATAL")) {
257 root.setPriority(Priority::FATAL);
261 root.setAppender(new OstreamAppender("default",&cerr));
265 PropertyConfigurator::configure(m_pathResolver ? m_pathResolver->resolve(path, PathResolver::XMLTOOLING_CFG_FILE) : path);
268 catch (const ConfigureFailure& e) {
269 string msg = string("failed to configure logging: ") + e.what();
270 Category::getInstance(XMLTOOLING_LOGCAT".Logging").crit(msg);
272 LogEvent(nullptr, EVENTLOG_ERROR_TYPE, 2100, nullptr, msg.c_str());
280 #ifndef XMLTOOLING_LITE
281 const KeyInfoResolver* XMLToolingConfig::getKeyInfoResolver() const
283 return m_keyInfoResolver;
286 ReplayCache* XMLToolingConfig::getReplayCache() const
288 return m_replayCache;
291 void XMLToolingConfig::setKeyInfoResolver(xmltooling::KeyInfoResolver *keyInfoResolver)
293 delete m_keyInfoResolver;
294 m_keyInfoResolver = keyInfoResolver;
297 void XMLToolingConfig::setReplayCache(ReplayCache* replayCache)
299 delete m_replayCache;
300 m_replayCache = replayCache;
304 PathResolver* XMLToolingConfig::getPathResolver() const
306 return m_pathResolver;
309 TemplateEngine* XMLToolingConfig::getTemplateEngine() const
311 return m_templateEngine;
314 const URLEncoder* XMLToolingConfig::getURLEncoder() const
319 void XMLToolingConfig::setPathResolver(PathResolver* pathResolver)
321 delete m_pathResolver;
322 m_pathResolver = pathResolver;
325 void XMLToolingConfig::setTemplateEngine(TemplateEngine* templateEngine)
327 delete m_templateEngine;
328 m_templateEngine = templateEngine;
331 void XMLToolingConfig::setURLEncoder(URLEncoder* urlEncoder)
334 m_urlEncoder = urlEncoder;
337 bool XMLToolingInternalConfig::init()
340 xmltooling::NDC ndc("init");
342 Category& log=Category::getInstance(XMLTOOLING_LOGCAT".XMLToolingConfig");
344 log.debug("library initialization started");
346 #ifndef XMLTOOLING_NO_XMLSEC
347 if (curl_global_init(CURL_GLOBAL_ALL)) {
348 log.fatal("failed to initialize libcurl, OpenSSL, or Winsock");
351 log.debug("libcurl %s initialization complete", LIBCURL_VERSION);
354 XMLPlatformUtils::Initialize();
355 log.debug("Xerces %s initialization complete", XERCES_FULLVERSIONDOT);
357 #ifndef XMLTOOLING_NO_XMLSEC
358 XSECPlatformUtils::Initialise();
359 # ifdef XMLTOOLING_XMLSEC_DEBUGLOGGING
360 XSECPlatformUtils::SetReferenceLoggingSink(TXFMOutputLogFactory);
362 m_xsecProvider=new XSECProvider();
363 log.debug("XML-Security %s initialization complete", XSEC_FULLVERSIONDOT);
366 m_parserPool=new ParserPool();
367 m_validatingPool=new ParserPool(true,true);
368 m_lock=XMLPlatformUtils::makeMutex();
370 // Load catalogs from path.
371 if (!catalog_path.empty()) {
372 char* catpath=strdup(catalog_path.c_str());
375 while (start && *start) {
376 sep=strchr(start,PATH_SEPARATOR_CHAR);
379 auto_ptr_XMLCh temp(start);
380 m_validatingPool->loadCatalog(temp.get());
381 start = sep ? sep + 1 : nullptr;
386 // default registrations
387 XMLObjectBuilder::registerDefaultBuilder(new UnknownElementBuilder());
389 registerSOAPClasses();
391 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(XMLParserException,xmltooling);
392 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(XMLObjectException,xmltooling);
393 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(MarshallingException,xmltooling);
394 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(UnmarshallingException,xmltooling);
395 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(UnknownElementException,xmltooling);
396 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(UnknownAttributeException,xmltooling);
397 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(ValidationException,xmltooling);
398 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(IOException,xmltooling);
400 #ifndef XMLTOOLING_NO_XMLSEC
401 XMLObjectBuilder::registerBuilder(QName(xmlconstants::XMLSIG_NS,Signature::LOCAL_NAME),new SignatureBuilder());
402 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(XMLSecurityException,xmltooling);
403 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(SignatureException,xmlsignature);
404 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(EncryptionException,xmlencryption);
405 registerKeyInfoClasses();
406 registerEncryptionClasses();
407 registerKeyInfoResolvers();
408 registerCredentialResolvers();
409 registerTrustEngines();
410 registerXMLAlgorithms();
411 registerSOAPTransports();
412 initSOAPTransports();
413 registerStorageServices();
414 m_keyInfoResolver = KeyInfoResolverManager.newPlugin(INLINE_KEYINFO_RESOLVER,nullptr);
417 m_pathResolver = new PathResolver();
418 m_urlEncoder = new URLEncoder();
420 HTTPResponse::getAllowedSchemes().push_back("https");
421 HTTPResponse::getAllowedSchemes().push_back("http");
423 // Register xml:id as an ID attribute.
424 static const XMLCh xmlid[] = UNICODE_LITERAL_2(i,d);
425 AttributeExtensibleXMLObject::registerIDAttribute(QName(xmlconstants::XML_NS, xmlid));
427 catch (const xercesc::XMLException&) {
428 log.fatal("caught exception while initializing Xerces");
429 #ifndef XMLTOOLING_NO_XMLSEC
430 curl_global_cleanup();
435 #ifndef XMLTOOLING_NO_XMLSEC
436 // Set up OpenSSL locking.
437 for (int i=0; i<CRYPTO_num_locks(); i++)
438 g_openssl_locks.push_back(Mutex::create());
439 CRYPTO_set_locking_callback(openssl_locking_callback);
441 CRYPTO_set_id_callback(openssl_thread_id);
445 log.info("%s library initialization complete", PACKAGE_STRING);
449 void XMLToolingInternalConfig::term()
451 #ifndef XMLTOOLING_NO_XMLSEC
452 CRYPTO_set_locking_callback(nullptr);
453 for_each(g_openssl_locks.begin(), g_openssl_locks.end(), xmltooling::cleanup<Mutex>());
454 g_openssl_locks.clear();
457 SchemaValidators.destroyValidators();
458 XMLObjectBuilder::destroyBuilders();
459 XMLToolingException::deregisterFactories();
460 AttributeExtensibleXMLObject::deregisterIDAttributes();
462 #ifndef XMLTOOLING_NO_XMLSEC
463 StorageServiceManager.deregisterFactories();
464 termSOAPTransports();
465 SOAPTransportManager.deregisterFactories();
466 TrustEngineManager.deregisterFactories();
467 CredentialResolverManager.deregisterFactories();
468 KeyInfoResolverManager.deregisterFactories();
469 m_algorithmMap.clear();
471 delete m_keyInfoResolver;
472 m_keyInfoResolver = nullptr;
474 delete m_replayCache;
475 m_replayCache = nullptr;
478 delete m_pathResolver;
479 m_pathResolver = nullptr;
481 delete m_templateEngine;
482 m_templateEngine = nullptr;
485 m_urlEncoder = nullptr;
487 for (vector<void*>::reverse_iterator i=m_libhandles.rbegin(); i!=m_libhandles.rend(); i++) {
489 FARPROC fn=GetProcAddress(static_cast<HMODULE>(*i),"xmltooling_extension_term");
492 FreeLibrary(static_cast<HMODULE>(*i));
493 #elif defined(HAVE_DLFCN_H)
494 void (*fn)()=(void (*)())dlsym(*i,"xmltooling_extension_term");
499 # error "Don't know about dynamic loading on this platform!"
502 m_libhandles.clear();
505 m_parserPool=nullptr;
506 delete m_validatingPool;
507 m_validatingPool=nullptr;
509 #ifndef XMLTOOLING_NO_XMLSEC
510 delete m_xsecProvider;
511 m_xsecProvider=nullptr;
512 XSECPlatformUtils::Terminate();
515 XMLPlatformUtils::closeMutex(m_lock);
517 XMLPlatformUtils::Terminate();
519 #ifndef XMLTOOLING_NO_XMLSEC
520 curl_global_cleanup();
523 xmltooling::NDC ndc("term");
525 Category::getInstance(XMLTOOLING_LOGCAT".XMLToolingConfig").info("%s library shutdown complete", PACKAGE_STRING);
528 Lockable* XMLToolingInternalConfig::lock()
530 xercesc::XMLPlatformUtils::lockMutex(m_lock);
534 void XMLToolingInternalConfig::unlock()
536 xercesc::XMLPlatformUtils::unlockMutex(m_lock);
539 bool XMLToolingInternalConfig::load_library(const char* path, void* context)
542 xmltooling::NDC ndc("LoadLibrary");
544 Category& log=Category::getInstance(XMLTOOLING_LOGCAT".XMLToolingConfig");
545 log.info("loading extension: %s", path);
549 string resolved(path);
550 m_pathResolver->resolve(resolved, PathResolver::XMLTOOLING_LIB_FILE);
553 HMODULE handle=nullptr;
554 for (string::iterator i = resolved.begin(); i != resolved.end(); ++i)
558 UINT em=SetErrorMode(SEM_FAILCRITICALERRORS);
560 handle=LoadLibraryEx(resolved.c_str(),nullptr,LOAD_WITH_ALTERED_SEARCH_PATH);
562 handle=LoadLibraryEx(resolved.c_str(),nullptr,0);
564 throw runtime_error(string("unable to load extension library: ") + resolved);
565 FARPROC fn=GetProcAddress(handle,"xmltooling_extension_init");
567 throw runtime_error(string("unable to locate xmltooling_extension_init entry point: ") + resolved);
568 if (reinterpret_cast<int(*)(void*)>(fn)(context)!=0)
569 throw runtime_error(string("detected error in xmltooling_extension_init: ") + resolved);
579 #elif defined(HAVE_DLFCN_H)
580 void* handle=dlopen(resolved.c_str(),RTLD_LAZY);
582 throw runtime_error(string("unable to load extension library '") + resolved + "': " + dlerror());
583 int (*fn)(void*)=(int (*)(void*))(dlsym(handle,"xmltooling_extension_init"));
587 string("unable to locate xmltooling_extension_init entry point in '") + resolved + "': " +
588 (dlerror() ? dlerror() : "unknown error")
593 throw runtime_error(string("detected error in xmltooling_extension_init in ") + resolved);
601 # error "Don't know about dynamic loading on this platform!"
603 m_libhandles.push_back(handle);
604 log.info("loaded extension: %s", resolved.c_str());
608 #ifndef XMLTOOLING_NO_XMLSEC
610 void xmltooling::log_openssl()
616 unsigned long code=ERR_get_error_line_data(&file,&line,&data,&flags);
618 Category& log=Category::getInstance("OpenSSL");
619 log.errorStream() << "error code: " << code << " in " << file << ", line " << line << logging::eol;
620 if (data && (flags & ERR_TXT_STRING))
621 log.errorStream() << "error data: " << data << logging::eol;
622 code=ERR_get_error_line_data(&file,&line,&data,&flags);
626 XSECCryptoX509CRL* XMLToolingInternalConfig::X509CRL() const
628 return new OpenSSLCryptoX509CRL();
631 pair<const char*,unsigned int> XMLToolingInternalConfig::mapXMLAlgorithmToKeyAlgorithm(const XMLCh* xmlAlgorithm) const
633 algmap_t::const_iterator i = m_algorithmMap.find(xmlAlgorithm);
634 if (i == m_algorithmMap.end())
635 return pair<const char*,unsigned int>(nullptr, 0);
636 return make_pair(i->second.first.c_str(), i->second.second);
639 void XMLToolingInternalConfig::registerXMLAlgorithm(const XMLCh* xmlAlgorithm, const char* keyAlgorithm, unsigned int size)
641 m_algorithmMap[xmlAlgorithm] = pair<string,unsigned int>(keyAlgorithm, size);
644 bool XMLToolingInternalConfig::isXMLAlgorithmSupported(const XMLCh* xmlAlgorithm)
647 if (XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(xmlAlgorithm))
650 catch (XSECException&) {
655 void XMLToolingInternalConfig::registerXMLAlgorithms()
657 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_MD5, "RSA", 0);
658 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA1, "RSA", 0);
659 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA224, "RSA", 0);
660 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA256, "RSA", 0);
661 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA384, "RSA", 0);
662 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA512, "RSA", 0);
664 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_1_5, "RSA", 0);
665 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1, "RSA", 0);
667 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIDSA_SHA1, "DSA", 0);
669 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA1, "EC", 0);
670 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA256, "EC", 0);
671 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA384, "EC", 0);
672 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA512, "EC", 0);
674 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA1, "HMAC", 0);
675 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA224, "HMAC", 0);
676 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA256, "HMAC", 0);
677 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA384, "HMAC", 0);
678 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA512, "HMAC", 0);
680 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURI3DES_CBC, "DESede", 192);
681 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_3DES, "DESede", 192);
683 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIAES128_CBC, "AES", 128);
684 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_AES128, "AES", 128);
686 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIAES192_CBC, "AES", 192);
687 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_AES192, "AES", 192);
689 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIAES256_CBC, "AES", 256);
690 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_AES256, "AES", 256);
697 extern "C" __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID)
699 if (fdwReason == DLL_THREAD_DETACH || fdwReason == DLL_PROCESS_DETACH)
700 ThreadKey::onDetach();