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/XSECException.hpp>
65 # include <xsec/framework/XSECProvider.hpp>
66 # include <xsec/transformers/TXFMBase.hpp>
69 using namespace soap11;
70 using namespace xmltooling::logging;
71 using namespace xmltooling;
72 using namespace xercesc;
76 DECL_XMLTOOLING_EXCEPTION_FACTORY(XMLParserException,xmltooling);
77 DECL_XMLTOOLING_EXCEPTION_FACTORY(XMLObjectException,xmltooling);
78 DECL_XMLTOOLING_EXCEPTION_FACTORY(MarshallingException,xmltooling);
79 DECL_XMLTOOLING_EXCEPTION_FACTORY(UnmarshallingException,xmltooling);
80 DECL_XMLTOOLING_EXCEPTION_FACTORY(UnknownElementException,xmltooling);
81 DECL_XMLTOOLING_EXCEPTION_FACTORY(UnknownAttributeException,xmltooling);
82 DECL_XMLTOOLING_EXCEPTION_FACTORY(UnknownExtensionException,xmltooling);
83 DECL_XMLTOOLING_EXCEPTION_FACTORY(ValidationException,xmltooling);
84 DECL_XMLTOOLING_EXCEPTION_FACTORY(IOException,xmltooling);
86 #ifndef XMLTOOLING_NO_XMLSEC
87 using namespace xmlencryption;
88 using namespace xmlsignature;
89 DECL_XMLTOOLING_EXCEPTION_FACTORY(XMLSecurityException,xmltooling);
90 DECL_XMLTOOLING_EXCEPTION_FACTORY(SignatureException,xmlsignature);
91 DECL_XMLTOOLING_EXCEPTION_FACTORY(EncryptionException,xmlencryption);
95 static XMLToolingInternalConfig g_config;
96 #ifndef XMLTOOLING_NO_XMLSEC
97 static vector<Mutex*> g_openssl_locks;
99 extern "C" void openssl_locking_callback(int mode,int n,const char *file,int line)
101 if (mode & CRYPTO_LOCK)
102 g_openssl_locks[n]->lock();
104 g_openssl_locks[n]->unlock();
108 extern "C" unsigned long openssl_thread_id(void)
110 return (unsigned long)(pthread_self());
114 # ifdef XMLTOOLING_XMLSEC_DEBUGLOGGING
115 class TXFMOutputLog : public TXFMBase {
118 TXFMOutputLog(DOMDocument* doc) : TXFMBase(doc), m_log(Category::getInstance(XMLTOOLING_LOGCAT".Signature.Debugger")) {
122 m_log.debug("\n----- END SIGNATURE DEBUG -----\n");
125 void setInput(TXFMBase *newInput) {
127 if (newInput->getOutputType() != TXFMBase::BYTE_STREAM)
128 throw XSECException(XSECException::TransformInputOutputFail, "OutputLog transform requires BYTE_STREAM input");
129 keepComments = input->getCommentsStatus();
130 m_log.debug("\n----- BEGIN SIGNATURE DEBUG -----\n");
133 TXFMBase::ioType getInputType() {
134 return TXFMBase::BYTE_STREAM;
136 TXFMBase::ioType getOutputType() {
137 return TXFMBase::BYTE_STREAM;
139 TXFMBase::nodeType getNodeType() {
140 return TXFMBase::DOM_NODE_NONE;
143 unsigned int readBytes(XMLByte * const toFill, const unsigned int maxToFill) {
144 unsigned int sz = input->readBytes(toFill, maxToFill);
145 m_log.debug(string(reinterpret_cast<char* const>(toFill), sz));
149 DOMDocument* getDocument() {
152 DOMNode* getFragmentNode() {
155 const XMLCh* getFragmentId() {
163 TXFMBase* TXFMOutputLogFactory(DOMDocument* doc) {
164 if (Category::getInstance(XMLTOOLING_LOGCAT".Signature.Debugger").isDebugEnabled())
165 return new TXFMOutputLog(doc);
174 LPCSTR lpUNCServerName,
180 LPCSTR messages[] = {message, nullptr};
182 HANDLE hElog = RegisterEventSource(lpUNCServerName, "OpenSAML XMLTooling Library");
183 BOOL res = ReportEvent(hElog, wType, 0, dwEventID, lpUserSid, 1, 0, messages, nullptr);
184 return (DeregisterEventSource(hElog) && res);
189 XMLToolingConfig& XMLToolingConfig::getConfig()
194 XMLToolingInternalConfig& XMLToolingInternalConfig::getInternalConfig()
199 #ifndef XMLTOOLING_NO_XMLSEC
200 XMLToolingConfig::XMLToolingConfig()
201 : m_keyInfoResolver(nullptr), m_replayCache(nullptr), m_pathResolver(nullptr), m_templateEngine(nullptr), m_urlEncoder(nullptr), clock_skew_secs(180)
203 XMLToolingConfig::XMLToolingConfig()
204 : m_pathResolver(nullptr), m_templateEngine(nullptr), m_urlEncoder(nullptr), clock_skew_secs(180)
209 XMLToolingConfig::~XMLToolingConfig()
213 bool XMLToolingInternalConfig::log_config(const char* config)
216 if (!config || !*config)
217 config=getenv("XMLTOOLING_LOG_CONFIG");
218 if (!config || !*config)
222 Category& root = Category::getRoot();
223 if (!strcmp(config,"DEBUG")) {
224 root.setPriority(Priority::DEBUG);
227 else if (!strcmp(config,"INFO")) {
228 root.setPriority(Priority::INFO);
231 else if (!strcmp(config,"NOTICE")) {
232 root.setPriority(Priority::NOTICE);
235 else if (!strcmp(config,"WARN")) {
236 root.setPriority(Priority::WARN);
239 else if (!strcmp(config,"ERROR")) {
240 root.setPriority(Priority::ERROR);
243 else if (!strcmp(config,"CRIT")) {
244 root.setPriority(Priority::CRIT);
247 else if (!strcmp(config,"ALERT")) {
248 root.setPriority(Priority::ALERT);
251 else if (!strcmp(config,"EMERG")) {
252 root.setPriority(Priority::EMERG);
255 else if (!strcmp(config,"FATAL")) {
256 root.setPriority(Priority::FATAL);
260 root.setAppender(new OstreamAppender("default",&cerr));
264 PropertyConfigurator::configure(m_pathResolver ? m_pathResolver->resolve(path, PathResolver::XMLTOOLING_CFG_FILE) : path);
267 catch (const ConfigureFailure& e) {
268 string msg = string("failed to configure logging: ") + e.what();
269 Category::getInstance(XMLTOOLING_LOGCAT".Logging").crit(msg);
271 LogEvent(nullptr, EVENTLOG_ERROR_TYPE, 2100, nullptr, msg.c_str());
279 #ifndef XMLTOOLING_LITE
280 const KeyInfoResolver* XMLToolingConfig::getKeyInfoResolver() const
282 return m_keyInfoResolver;
285 ReplayCache* XMLToolingConfig::getReplayCache() const
287 return m_replayCache;
290 void XMLToolingConfig::setKeyInfoResolver(xmltooling::KeyInfoResolver *keyInfoResolver)
292 delete m_keyInfoResolver;
293 m_keyInfoResolver = keyInfoResolver;
296 void XMLToolingConfig::setReplayCache(ReplayCache* replayCache)
298 delete m_replayCache;
299 m_replayCache = replayCache;
303 PathResolver* XMLToolingConfig::getPathResolver() const
305 return m_pathResolver;
308 TemplateEngine* XMLToolingConfig::getTemplateEngine() const
310 return m_templateEngine;
313 const URLEncoder* XMLToolingConfig::getURLEncoder() const
318 void XMLToolingConfig::setPathResolver(PathResolver* pathResolver)
320 delete m_pathResolver;
321 m_pathResolver = pathResolver;
324 void XMLToolingConfig::setTemplateEngine(TemplateEngine* templateEngine)
326 delete m_templateEngine;
327 m_templateEngine = templateEngine;
330 void XMLToolingConfig::setURLEncoder(URLEncoder* urlEncoder)
333 m_urlEncoder = urlEncoder;
336 bool XMLToolingInternalConfig::init()
339 xmltooling::NDC ndc("init");
341 Category& log=Category::getInstance(XMLTOOLING_LOGCAT".XMLToolingConfig");
343 log.debug("library initialization started");
345 #ifndef XMLTOOLING_NO_XMLSEC
346 if (curl_global_init(CURL_GLOBAL_ALL)) {
347 log.fatal("failed to initialize libcurl, OpenSSL, or Winsock");
350 log.debug("libcurl %s initialization complete", LIBCURL_VERSION);
353 XMLPlatformUtils::Initialize();
354 log.debug("Xerces %s initialization complete", XERCES_FULLVERSIONDOT);
356 #ifndef XMLTOOLING_NO_XMLSEC
357 XSECPlatformUtils::Initialise();
358 # ifdef XMLTOOLING_XMLSEC_DEBUGLOGGING
359 XSECPlatformUtils::SetReferenceLoggingSink(TXFMOutputLogFactory);
361 m_xsecProvider=new XSECProvider();
362 log.debug("XML-Security %s initialization complete", XSEC_FULLVERSIONDOT);
365 m_parserPool=new ParserPool();
366 m_validatingPool=new ParserPool(true,true);
367 m_lock=XMLPlatformUtils::makeMutex();
369 // Load catalogs from path.
370 if (!catalog_path.empty()) {
371 char* catpath=strdup(catalog_path.c_str());
374 while (start && *start) {
375 sep=strchr(start,PATH_SEPARATOR_CHAR);
378 auto_ptr_XMLCh temp(start);
379 m_validatingPool->loadCatalog(temp.get());
380 start = sep ? sep + 1 : nullptr;
385 // default registrations
386 XMLObjectBuilder::registerDefaultBuilder(new UnknownElementBuilder());
388 registerSOAPClasses();
390 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(XMLParserException,xmltooling);
391 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(XMLObjectException,xmltooling);
392 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(MarshallingException,xmltooling);
393 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(UnmarshallingException,xmltooling);
394 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(UnknownElementException,xmltooling);
395 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(UnknownAttributeException,xmltooling);
396 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(ValidationException,xmltooling);
397 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(IOException,xmltooling);
399 #ifndef XMLTOOLING_NO_XMLSEC
400 XMLObjectBuilder::registerBuilder(QName(xmlconstants::XMLSIG_NS,Signature::LOCAL_NAME),new SignatureBuilder());
401 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(XMLSecurityException,xmltooling);
402 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(SignatureException,xmlsignature);
403 REGISTER_XMLTOOLING_EXCEPTION_FACTORY(EncryptionException,xmlencryption);
404 registerKeyInfoClasses();
405 registerEncryptionClasses();
406 registerKeyInfoResolvers();
407 registerCredentialResolvers();
408 registerTrustEngines();
409 registerXMLAlgorithms();
410 registerSOAPTransports();
411 initSOAPTransports();
412 registerStorageServices();
413 m_keyInfoResolver = KeyInfoResolverManager.newPlugin(INLINE_KEYINFO_RESOLVER,nullptr);
416 m_pathResolver = new PathResolver();
417 m_urlEncoder = new URLEncoder();
419 HTTPResponse::getAllowedSchemes().push_back("https");
420 HTTPResponse::getAllowedSchemes().push_back("http");
422 // Register xml:id as an ID attribute.
423 static const XMLCh xmlid[] = UNICODE_LITERAL_2(i,d);
424 AttributeExtensibleXMLObject::registerIDAttribute(QName(xmlconstants::XML_NS, xmlid));
426 catch (const xercesc::XMLException&) {
427 log.fatal("caught exception while initializing Xerces");
428 #ifndef XMLTOOLING_NO_XMLSEC
429 curl_global_cleanup();
434 #ifndef XMLTOOLING_NO_XMLSEC
435 // Set up OpenSSL locking.
436 for (int i=0; i<CRYPTO_num_locks(); i++)
437 g_openssl_locks.push_back(Mutex::create());
438 CRYPTO_set_locking_callback(openssl_locking_callback);
440 CRYPTO_set_id_callback(openssl_thread_id);
444 log.info("%s library initialization complete", PACKAGE_STRING);
448 void XMLToolingInternalConfig::term()
450 #ifndef XMLTOOLING_NO_XMLSEC
451 CRYPTO_set_locking_callback(nullptr);
452 for_each(g_openssl_locks.begin(), g_openssl_locks.end(), xmltooling::cleanup<Mutex>());
453 g_openssl_locks.clear();
456 SchemaValidators.destroyValidators();
457 XMLObjectBuilder::destroyBuilders();
458 XMLToolingException::deregisterFactories();
459 AttributeExtensibleXMLObject::deregisterIDAttributes();
461 #ifndef XMLTOOLING_NO_XMLSEC
462 StorageServiceManager.deregisterFactories();
463 termSOAPTransports();
464 SOAPTransportManager.deregisterFactories();
465 TrustEngineManager.deregisterFactories();
466 CredentialResolverManager.deregisterFactories();
467 KeyInfoResolverManager.deregisterFactories();
468 m_algorithmMap.clear();
470 delete m_keyInfoResolver;
471 m_keyInfoResolver = nullptr;
473 delete m_replayCache;
474 m_replayCache = nullptr;
477 delete m_pathResolver;
478 m_pathResolver = nullptr;
480 delete m_templateEngine;
481 m_templateEngine = nullptr;
484 m_urlEncoder = nullptr;
486 for (vector<void*>::reverse_iterator i=m_libhandles.rbegin(); i!=m_libhandles.rend(); i++) {
488 FARPROC fn=GetProcAddress(static_cast<HMODULE>(*i),"xmltooling_extension_term");
491 FreeLibrary(static_cast<HMODULE>(*i));
492 #elif defined(HAVE_DLFCN_H)
493 void (*fn)()=(void (*)())dlsym(*i,"xmltooling_extension_term");
498 # error "Don't know about dynamic loading on this platform!"
501 m_libhandles.clear();
504 m_parserPool=nullptr;
505 delete m_validatingPool;
506 m_validatingPool=nullptr;
508 #ifndef XMLTOOLING_NO_XMLSEC
509 delete m_xsecProvider;
510 m_xsecProvider=nullptr;
511 XSECPlatformUtils::Terminate();
514 XMLPlatformUtils::closeMutex(m_lock);
516 XMLPlatformUtils::Terminate();
518 #ifndef XMLTOOLING_NO_XMLSEC
519 curl_global_cleanup();
522 xmltooling::NDC ndc("term");
524 Category::getInstance(XMLTOOLING_LOGCAT".XMLToolingConfig").info("%s library shutdown complete", PACKAGE_STRING);
527 Lockable* XMLToolingInternalConfig::lock()
529 xercesc::XMLPlatformUtils::lockMutex(m_lock);
533 void XMLToolingInternalConfig::unlock()
535 xercesc::XMLPlatformUtils::unlockMutex(m_lock);
538 bool XMLToolingInternalConfig::load_library(const char* path, void* context)
541 xmltooling::NDC ndc("LoadLibrary");
543 Category& log=Category::getInstance(XMLTOOLING_LOGCAT".XMLToolingConfig");
544 log.info("loading extension: %s", path);
548 string resolved(path);
549 m_pathResolver->resolve(resolved, PathResolver::XMLTOOLING_LIB_FILE);
552 HMODULE handle=nullptr;
553 for (string::iterator i = resolved.begin(); i != resolved.end(); ++i)
557 UINT em=SetErrorMode(SEM_FAILCRITICALERRORS);
559 handle=LoadLibraryEx(resolved.c_str(),nullptr,LOAD_WITH_ALTERED_SEARCH_PATH);
561 handle=LoadLibraryEx(resolved.c_str(),nullptr,0);
563 throw runtime_error(string("unable to load extension library: ") + resolved);
564 FARPROC fn=GetProcAddress(handle,"xmltooling_extension_init");
566 throw runtime_error(string("unable to locate xmltooling_extension_init entry point: ") + resolved);
567 if (reinterpret_cast<int(*)(void*)>(fn)(context)!=0)
568 throw runtime_error(string("detected error in xmltooling_extension_init: ") + resolved);
578 #elif defined(HAVE_DLFCN_H)
579 void* handle=dlopen(resolved.c_str(),RTLD_LAZY);
581 throw runtime_error(string("unable to load extension library '") + resolved + "': " + dlerror());
582 int (*fn)(void*)=(int (*)(void*))(dlsym(handle,"xmltooling_extension_init"));
586 string("unable to locate xmltooling_extension_init entry point in '") + resolved + "': " +
587 (dlerror() ? dlerror() : "unknown error")
592 throw runtime_error(string("detected error in xmltooling_extension_init in ") + resolved);
600 # error "Don't know about dynamic loading on this platform!"
602 m_libhandles.push_back(handle);
603 log.info("loaded extension: %s", resolved.c_str());
607 #ifndef XMLTOOLING_NO_XMLSEC
608 void xmltooling::log_openssl()
614 unsigned long code=ERR_get_error_line_data(&file,&line,&data,&flags);
616 Category& log=Category::getInstance("OpenSSL");
617 log.errorStream() << "error code: " << code << " in " << file << ", line " << line << logging::eol;
618 if (data && (flags & ERR_TXT_STRING))
619 log.errorStream() << "error data: " << data << logging::eol;
620 code=ERR_get_error_line_data(&file,&line,&data,&flags);
624 XSECCryptoX509CRL* XMLToolingInternalConfig::X509CRL() const
626 return new OpenSSLCryptoX509CRL();
629 void XMLToolingInternalConfig::registerXMLAlgorithms()
631 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_MD5, "RSA", 0);
632 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA1, "RSA", 0);
633 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA224, "RSA", 0);
634 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA256, "RSA", 0);
635 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA384, "RSA", 0);
636 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_SHA512, "RSA", 0);
638 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_1_5, "RSA", 0);
639 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1, "RSA", 0);
641 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIDSA_SHA1, "DSA", 0);
643 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA1, "EC", 0);
644 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA256, "EC", 0);
645 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA384, "EC", 0);
646 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIECDSA_SHA512, "EC", 0);
648 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA1, "HMAC", 0);
649 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA224, "HMAC", 0);
650 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA256, "HMAC", 0);
651 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA384, "HMAC", 0);
652 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIHMAC_SHA512, "HMAC", 0);
654 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURI3DES_CBC, "DESede", 192);
655 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_3DES, "DESede", 192);
657 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIAES128_CBC, "AES", 128);
658 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_AES128, "AES", 128);
660 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIAES192_CBC, "AES", 192);
661 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_AES192, "AES", 192);
663 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIAES256_CBC, "AES", 256);
664 registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_AES256, "AES", 256);
670 extern "C" __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID)
672 if (fdwReason == DLL_THREAD_DETACH || fdwReason == DLL_PROCESS_DETACH)
673 ThreadKey::onDetach();