2 * Licensed to the University Corporation for Advanced Internet
3 * Development, Inc. (UCAID) under one or more contributor license
4 * agreements. See the NOTICE file distributed with this work for
5 * additional information regarding copyright ownership.
7 * UCAID licenses this file to you under the Apache License,
8 * Version 2.0 (the "License"); you may not use this file except
9 * in compliance with the License. You may obtain a copy of the
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17 * either express or implied. See the License for the specific
18 * language governing permissions and limitations under the License.
22 * FilesystemCredentialResolver.cpp
24 * Supplies credentials from local files.
29 #include "io/HTTPResponse.h"
30 #include "security/BasicX509Credential.h"
31 #include "security/CredentialCriteria.h"
32 #include "security/CredentialResolver.h"
33 #include "security/KeyInfoResolver.h"
34 #include "security/OpenSSLCredential.h"
35 #include "security/SecurityHelper.h"
36 #include "security/XSECCryptoX509CRL.h"
38 #include "util/PathResolver.h"
39 #include "util/Threads.h"
40 #include "util/XMLHelper.h"
44 #include <sys/types.h>
46 #include <openssl/pkcs12.h>
47 #include <xercesc/util/XMLUniDefs.hpp>
48 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
50 using namespace xmlsignature;
51 using namespace xmltooling::logging;
52 using namespace xmltooling;
55 using xercesc::DOMElement;
56 using xercesc::chLatin_f;
57 using xercesc::chDigit_0;
59 namespace xmltooling {
61 // The ManagedResource classes handle memory management, loading of the files
62 // and staleness detection. A copy of the active objects is always stored in
65 class XMLTOOL_DLLLOCAL ManagedResource {
67 ManagedResource() : local(true), reloadChanges(true), filestamp(0), reloadInterval(0) {}
70 SOAPTransport* getTransport() {
71 SOAPTransport::Address addr("FilesystemCredentialResolver", source.c_str(), source.c_str());
72 string scheme(addr.m_endpoint, strchr(addr.m_endpoint,':') - addr.m_endpoint);
73 SOAPTransport* ret = XMLToolingConfig::getConfig().SOAPTransportManager.newPlugin(scheme.c_str(), addr);
75 ret->setCacheTag(&cacheTag);
80 bool stale(Category& log, RWLock* lock=nullptr) {
83 struct _stat stat_buf;
84 if (_stat(source.c_str(), &stat_buf) != 0)
88 if (stat(source.c_str(), &stat_buf) != 0)
91 if (filestamp >= stat_buf.st_mtime)
94 // If necessary, elevate lock and recheck.
96 log.debug("timestamp of local resource changed, elevating to a write lock");
99 if (filestamp >= stat_buf.st_mtime) {
100 // Somebody else handled it, just downgrade.
101 log.debug("update of local resource handled by another thread, downgrading lock");
108 // Update the timestamp regardless. No point in repeatedly trying.
109 filestamp = stat_buf.st_mtime;
110 log.info("change detected, reloading local resource...");
113 time_t now = time(nullptr);
116 if (now - filestamp < reloadInterval)
119 // If necessary, elevate lock and recheck.
121 log.debug("reload interval for remote resource elapsed, elevating to a write lock");
124 if (now - filestamp < reloadInterval) {
125 // Somebody else handled it, just downgrade.
126 log.debug("update of remote resource handled by another thread, downgrading lock");
134 log.info("reloading remote resource...");
139 bool local,reloadChanges;
140 string format,source,backing,cacheTag;
141 time_t filestamp,reloadInterval;
144 class XMLTOOL_DLLLOCAL ManagedKey : public ManagedResource {
146 ManagedKey() : key(nullptr) {}
147 ~ManagedKey() { delete key; }
148 void load(Category& log, const char* password) {
151 XSECCryptoKey* nkey=nullptr;
153 nkey = SecurityHelper::loadKeyFromFile(source.c_str(), format.c_str(), password);
156 auto_ptr<SOAPTransport> t(getTransport());
157 log.info("loading private key from URL (%s)", source.c_str());
158 nkey = SecurityHelper::loadKeyFromURL(*t.get(), backing.c_str(), format.c_str(), password);
163 format = SecurityHelper::guessEncodingFormat(local ? source.c_str() : backing.c_str());
169 class XMLTOOL_DLLLOCAL ManagedCert : public ManagedResource {
172 ~ManagedCert() { for_each(certs.begin(), certs.end(), xmltooling::cleanup<XSECCryptoX509>()); }
173 void load(Category& log, const char* password) {
176 vector<XSECCryptoX509*> ncerts;
178 SecurityHelper::loadCertificatesFromFile(ncerts, source.c_str(), format.c_str(), password);
181 auto_ptr<SOAPTransport> t(getTransport());
182 log.info("loading certificate(s) from URL (%s)", source.c_str());
183 SecurityHelper::loadCertificatesFromURL(ncerts, *t.get(), backing.c_str(), format.c_str(), password);
185 for_each(certs.begin(), certs.end(), xmltooling::cleanup<XSECCryptoX509>());
188 format = SecurityHelper::guessEncodingFormat(local ? source.c_str() : backing.c_str());
190 vector<XSECCryptoX509*> certs;
193 class XMLTOOL_DLLLOCAL ManagedCRL : public ManagedResource {
196 ~ManagedCRL() { for_each(crls.begin(), crls.end(), xmltooling::cleanup<XSECCryptoX509CRL>()); }
197 void load(Category& log) {
200 vector<XSECCryptoX509CRL*> ncrls;
202 SecurityHelper::loadCRLsFromFile(ncrls, source.c_str(), format.c_str());
205 auto_ptr<SOAPTransport> t(getTransport());
206 log.info("loading CRL(s) from URL (%s)", source.c_str());
207 SecurityHelper::loadCRLsFromURL(ncrls, *t.get(), backing.c_str(), format.c_str());
209 for_each(crls.begin(), crls.end(), xmltooling::cleanup<XSECCryptoX509CRL>());
212 format = SecurityHelper::guessEncodingFormat(local ? source.c_str() : backing.c_str());
214 vector<XSECCryptoX509CRL*> crls;
217 class XMLTOOL_DLLLOCAL FilesystemCredential;
218 class XMLTOOL_DLLLOCAL FilesystemCredentialResolver : public CredentialResolver
221 FilesystemCredentialResolver(const DOMElement* e);
222 virtual ~FilesystemCredentialResolver();
229 const Credential* resolve(const CredentialCriteria* criteria=nullptr) const;
231 virtual vector<const Credential*>::size_type resolve(
232 vector<const Credential*>& results, const CredentialCriteria* criteria=nullptr
236 Credential* getCredential();
239 Credential* m_credential;
240 string m_keypass,m_certpass;
241 unsigned int m_keyinfomask,m_usage;
243 vector<string> m_keynames;
246 vector<ManagedCert> m_certs;
247 vector<ManagedCRL> m_crls;
249 friend class XMLTOOL_DLLLOCAL FilesystemCredential;
252 #if defined (_MSC_VER)
253 #pragma warning( push )
254 #pragma warning( disable : 4250 )
257 class XMLTOOL_DLLLOCAL FilesystemCredential : public OpenSSLCredential, public BasicX509Credential
260 FilesystemCredential(
261 FilesystemCredentialResolver* resolver,
263 const vector<XSECCryptoX509*>& xseccerts,
264 const vector<XSECCryptoX509CRL*>& crls
265 ) : BasicX509Credential(key ? key : (xseccerts.empty() ? nullptr : xseccerts.front()->clonePublicKey()), xseccerts, crls), m_resolver(resolver) {
266 if (m_resolver->m_extractNames)
268 m_keyNames.insert(m_resolver->m_keynames.begin(), m_resolver->m_keynames.end());
271 virtual ~FilesystemCredential() {
274 unsigned int getUsage() const {
275 return m_resolver->m_usage;
278 void initKeyInfo(unsigned int types=0) {
279 BasicX509Credential::initKeyInfo(types);
282 void attach(SSL_CTX* ctx) const;
285 FilesystemCredentialResolver* m_resolver;
288 #if defined (_MSC_VER)
289 #pragma warning( pop )
292 CredentialResolver* XMLTOOL_DLLLOCAL FilesystemCredentialResolverFactory(const DOMElement* const & e)
294 return new FilesystemCredentialResolver(e);
297 static const XMLCh backingFilePath[] = UNICODE_LITERAL_15(b,a,c,k,i,n,g,F,i,l,e,P,a,t,h);
298 static const XMLCh _CredentialResolver[] = UNICODE_LITERAL_18(C,r,e,d,e,n,t,i,a,l,R,e,s,o,l,v,e,r);
299 static const XMLCh CAPath[] = UNICODE_LITERAL_6(C,A,P,a,t,h);
300 static const XMLCh Certificate[] = UNICODE_LITERAL_11(C,e,r,t,i,f,i,c,a,t,e);
301 static const XMLCh _certificate[] = UNICODE_LITERAL_11(c,e,r,t,i,f,i,c,a,t,e);
302 static const XMLCh CRL[] = UNICODE_LITERAL_3(C,R,L);
303 static const XMLCh extractNames[] = UNICODE_LITERAL_12(e,x,t,r,a,c,t,N,a,m,e,s);
304 static const XMLCh _format[] = UNICODE_LITERAL_6(f,o,r,m,a,t);
305 static const XMLCh Key[] = UNICODE_LITERAL_3(K,e,y);
306 static const XMLCh _key[] = UNICODE_LITERAL_3(k,e,y);
307 static const XMLCh keyInfoMask[] = UNICODE_LITERAL_11(k,e,y,I,n,f,o,M,a,s,k);
308 static const XMLCh keyName[] = UNICODE_LITERAL_7(k,e,y,N,a,m,e);
309 static const XMLCh Name[] = UNICODE_LITERAL_4(N,a,m,e);
310 static const XMLCh password[] = UNICODE_LITERAL_8(p,a,s,s,w,o,r,d);
311 static const XMLCh Path[] = UNICODE_LITERAL_4(P,a,t,h);
312 static const XMLCh _reloadChanges[] = UNICODE_LITERAL_13(r,e,l,o,a,d,C,h,a,n,g,e,s);
313 static const XMLCh _reloadInterval[] = UNICODE_LITERAL_14(r,e,l,o,a,d,I,n,t,e,r,v,a,l);
314 static const XMLCh _URL[] = UNICODE_LITERAL_3(U,R,L);
315 static const XMLCh _use[] = UNICODE_LITERAL_3(u,s,e);
318 FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e)
319 : m_lock(nullptr), m_credential(nullptr), m_keyinfomask(XMLHelper::getAttrInt(e, 0, keyInfoMask)),
320 m_usage(Credential::UNSPECIFIED_CREDENTIAL), m_extractNames(true)
323 NDC ndc("FilesystemCredentialResolver");
325 Category& log=Category::getInstance(XMLTOOLING_LOGCAT".CredentialResolver."FILESYSTEM_CREDENTIAL_RESOLVER);
327 if (e && (e->hasAttributeNS(nullptr,_certificate) || e->hasAttributeNS(nullptr,_key))) {
328 // Dummy up a simple file resolver config using these attributes.
329 DOMElement* dummy = e->getOwnerDocument()->createElementNS(nullptr,_CredentialResolver);
332 if (e->hasAttributeNS(nullptr,_key)) {
333 child = e->getOwnerDocument()->createElementNS(nullptr,Key);
334 dummy->appendChild(child);
335 path = e->getOwnerDocument()->createElementNS(nullptr,Path);
336 child->appendChild(path);
337 path->appendChild(e->getOwnerDocument()->createTextNode(e->getAttributeNS(nullptr,_key)));
338 if (e->hasAttributeNS(nullptr,password))
339 child->setAttributeNS(nullptr,password,e->getAttributeNS(nullptr,password));
340 if (e->hasAttributeNS(nullptr,keyName)) {
341 path = e->getOwnerDocument()->createElementNS(nullptr,Name);
342 child->appendChild(path);
343 path->appendChild(e->getOwnerDocument()->createTextNode(e->getAttributeNS(nullptr,keyName)));
346 if (e->hasAttributeNS(nullptr,_certificate)) {
347 child = e->getOwnerDocument()->createElementNS(nullptr,Certificate);
348 dummy->appendChild(child);
349 path = e->getOwnerDocument()->createElementNS(nullptr,Path);
350 child->appendChild(path);
351 path->appendChild(e->getOwnerDocument()->createTextNode(e->getAttributeNS(nullptr,_certificate)));
352 if (e->hasAttributeNS(nullptr, extractNames))
353 child->setAttributeNS(nullptr, extractNames, e->getAttributeNS(nullptr, extractNames));
355 if (e->hasAttributeNS(nullptr, _use)) {
356 dummy->setAttributeNS(nullptr, _use, e->getAttributeNS(nullptr, _use));
359 e = dummy; // reset "root" to the dummy config element
363 const DOMElement* root = e;
365 // Save off usage bits.
366 string usage = XMLHelper::getAttrString(root, nullptr, _use);
367 if (usage == "signing")
368 m_usage = Credential::SIGNING_CREDENTIAL | Credential::TLS_CREDENTIAL;
369 else if (usage == "TLS")
370 m_usage = Credential::TLS_CREDENTIAL;
371 else if (usage == "encryption")
372 m_usage = Credential::ENCRYPTION_CREDENTIAL;
375 const DOMElement* keynode = XMLHelper::getFirstChildElement(root,Key);
377 m_key.format = XMLHelper::getAttrString(keynode, nullptr, _format);
378 m_keypass = XMLHelper::getAttrString(keynode, nullptr, password);
380 if ((e=XMLHelper::getFirstChildElement(keynode,Path)) && e->hasChildNodes()) {
381 prop = e->getFirstChild()->getNodeValue();
382 auto_ptr_char kpath(prop);
383 m_key.source = kpath.get();
384 XMLToolingConfig::getConfig().getPathResolver()->resolve(m_key.source, PathResolver::XMLTOOLING_CFG_FILE);
386 m_key.reloadChanges = XMLHelper::getAttrBool(e, true, _reloadChanges);
388 else if ((e=XMLHelper::getFirstChildElement(keynode,_URL)) && e->hasChildNodes()) {
389 prop = e->getFirstChild()->getNodeValue();
390 auto_ptr_char kpath(prop);
391 m_key.source = kpath.get();
393 m_key.backing = XMLHelper::getAttrString(e, nullptr, backingFilePath);
394 if (m_key.backing.empty())
395 throw XMLSecurityException("FilesystemCredentialResolver can't access key, backingFilePath missing from URL element.");
396 XMLToolingConfig::getConfig().getPathResolver()->resolve(m_key.backing, PathResolver::XMLTOOLING_CACHE_FILE);
397 m_key.reloadInterval = XMLHelper::getAttrInt(e, 0, _reloadInterval);
400 log.error("Path/URL element missing inside Key element");
401 throw XMLSecurityException("FilesystemCredentialResolver can't access key, no Path or URL element specified.");
404 e = XMLHelper::getFirstChildElement(keynode, Name);
406 if (e->hasChildNodes()) {
407 auto_ptr_char n(e->getFirstChild()->getNodeValue());
408 if (n.get() && *n.get())
409 m_keynames.push_back(n.get());
411 e = XMLHelper::getNextSiblingElement(e, Name);
416 const DOMElement* crlnode = XMLHelper::getFirstChildElement(root, CRL);
418 string crlformat = XMLHelper::getAttrString(crlnode, nullptr, _format);
419 e = XMLHelper::getFirstChildElement(crlnode, Path);
421 if (e->hasChildNodes()) {
422 m_crls.push_back(ManagedCRL());
423 ManagedResource& crl = m_crls.back();
424 crl.format = crlformat;
425 prop = e->getFirstChild()->getNodeValue();
426 auto_ptr_char crlpath(prop);
427 crl.source = crlpath.get();
428 XMLToolingConfig::getConfig().getPathResolver()->resolve(crl.source, PathResolver::XMLTOOLING_CFG_FILE);
430 crl.reloadChanges = XMLHelper::getAttrBool(e, true, _reloadChanges);
432 e = XMLHelper::getNextSiblingElement(e, Path);
435 e = XMLHelper::getFirstChildElement(crlnode, _URL);
437 if (e->hasChildNodes()) {
438 m_crls.push_back(ManagedCRL());
439 ManagedResource& crl = m_crls.back();
440 crl.format = crlformat;
441 prop = e->getFirstChild()->getNodeValue();
442 auto_ptr_char crlpath(prop);
443 crl.source = crlpath.get();
445 crl.backing = XMLHelper::getAttrString(e, nullptr, backingFilePath);
446 if (crl.backing.empty())
447 throw XMLSecurityException("FilesystemCredentialResolver can't access CRL, backingFilePath missing from URL element.");
448 XMLToolingConfig::getConfig().getPathResolver()->resolve(crl.backing, PathResolver::XMLTOOLING_CACHE_FILE);
449 crl.reloadInterval = XMLHelper::getAttrInt(e, 0, _reloadInterval);
451 e = XMLHelper::getNextSiblingElement(e, _URL);
453 if (m_crls.empty()) {
454 log.error("Path/URL element missing inside CRL element");
455 throw XMLSecurityException("FilesystemCredentialResolver can't access CRL, no Path or URL element specified.");
459 // Check for Certificate
460 DOMElement* certnode = XMLHelper::getFirstChildElement(root,Certificate);
462 m_certpass = XMLHelper::getAttrString(certnode, nullptr, password);
463 string certformat = XMLHelper::getAttrString(certnode, nullptr, _format);
464 m_extractNames = XMLHelper::getAttrBool(certnode, true, extractNames);
466 e = XMLHelper::getFirstChildElement(certnode);
468 if (e->hasChildNodes() && (XMLString::equals(e->getLocalName(), Path) || XMLString::equals(e->getLocalName(), CAPath))) {
469 m_certs.push_back(ManagedCert());
470 ManagedResource& cert = m_certs.back();
471 cert.format = certformat;
472 prop = e->getFirstChild()->getNodeValue();
473 auto_ptr_char certpath(prop);
474 cert.source = certpath.get();
475 XMLToolingConfig::getConfig().getPathResolver()->resolve(cert.source, PathResolver::XMLTOOLING_CFG_FILE);
477 cert.reloadChanges = XMLHelper::getAttrBool(e, true, _reloadChanges);
479 else if (e->hasChildNodes() && XMLString::equals(e->getLocalName(), _URL)) {
480 m_certs.push_back(ManagedCert());
481 ManagedResource& cert = m_certs.back();
482 cert.format = certformat;
483 prop = e->getFirstChild()->getNodeValue();
484 auto_ptr_char certpath(prop);
485 cert.source = certpath.get();
487 cert.backing = XMLHelper::getAttrString(e, nullptr, backingFilePath);
488 if (cert.backing.empty())
489 throw XMLSecurityException("FilesystemCredentialResolver can't access certificate, backingFilePath missing from URL element.");
490 XMLToolingConfig::getConfig().getPathResolver()->resolve(cert.backing, PathResolver::XMLTOOLING_CACHE_FILE);
491 cert.reloadInterval = XMLHelper::getAttrInt(e, 0, _reloadInterval);
493 e = XMLHelper::getNextSiblingElement(e);
495 if (m_certs.empty()) {
496 log.error("Path/URL element missing inside Certificate element");
497 throw XMLSecurityException("FilesystemCredentialResolver can't access certificate, no Path or URL element specified.");
501 // Do an initial load of all the objects. If anything blows up here, whatever's
502 // been loaded should be freed during teardown of the embedded objects.
503 time_t now = time(nullptr);
504 m_key.filestamp = now;
505 m_key.load(log, m_keypass.c_str());
506 for (vector<ManagedCert>::iterator i = m_certs.begin(); i != m_certs.end(); ++i) {
507 i->load(log, (i==m_certs.begin()) ? m_certpass.c_str() : nullptr);
510 for (vector<ManagedCRL>::iterator j = m_crls.begin(); j != m_crls.end(); ++j) {
515 // Load it all into a credential object and then create the lock.
516 auto_ptr<Credential> credential(getCredential());
517 m_lock = RWLock::create();
518 m_credential = credential.release();
519 if (m_credential->getPrivateKey() == nullptr) {
520 log.info("no private key resolved, usable for verification/trust only");
524 FilesystemCredentialResolver::~FilesystemCredentialResolver()
530 Credential* FilesystemCredentialResolver::getCredential()
532 // First, verify that the key and certificate match.
533 if (m_key.key && !m_certs.empty()) {
534 auto_ptr<XSECCryptoKey> temp(m_certs.front().certs.front()->clonePublicKey());
535 if (!SecurityHelper::matches(*m_key.key, *temp.get()))
536 throw XMLSecurityException("FilesystemCredentialResolver given mismatched key/certificate, check for consistency.");
539 // We (unfortunately) need to duplicate all the objects and put them in one set of arrays
540 // in order to create the credential wrapper.
541 FilesystemCredential* credential=nullptr;
542 auto_ptr<XSECCryptoKey> xseckey(m_key.key ? m_key.key->clone() : nullptr);
543 vector<XSECCryptoX509*> xseccerts;
544 vector<XSECCryptoX509CRL*> xseccrls;
546 for (vector<ManagedCert>::iterator i = m_certs.begin(); i != m_certs.end(); ++i) {
547 for (vector<XSECCryptoX509*>::const_iterator y = i->certs.begin(); y != i->certs.end(); ++y)
548 xseccerts.push_back(new OpenSSLCryptoX509(static_cast<OpenSSLCryptoX509*>(*y)->getOpenSSLX509()));
550 for (vector<ManagedCRL>::iterator j = m_crls.begin(); j != m_crls.end(); ++j) {
551 for (vector<XSECCryptoX509CRL*>::const_iterator z = j->crls.begin(); z != j->crls.end(); ++z)
552 xseccrls.push_back((*z)->clone());
554 credential = new FilesystemCredential(this, xseckey.get(), xseccerts, xseccrls);
558 for_each(xseccerts.begin(), xseccerts.end(), xmltooling::cleanup<XSECCryptoX509>());
559 for_each(xseccrls.begin(), xseccrls.end(), xmltooling::cleanup<XSECCryptoX509CRL>());
563 // At this point the copies are owned by the credential.
565 credential->initKeyInfo(m_keyinfomask);
575 Lockable* FilesystemCredentialResolver::lock()
580 Category& log=Category::getInstance(XMLTOOLING_LOGCAT".CredentialResolver."FILESYSTEM_CREDENTIAL_RESOLVER);
584 // Check each managed resource while holding a read lock for staleness.
585 // If it comes back false, the lock is left as is, and the resource was stable.
586 // If it comes back true, the lock was elevated to a write lock, and the resource
587 // needs to be reloaded, and the credential replaced.
588 // Once a stale check comes back true, further checks leave the lock alone.
590 bool writelock = false, updated = false;
592 if (m_key.stale(log, m_lock)) {
595 m_key.load(log, m_keypass.c_str());
599 if (ex == HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED) {
600 log.info("remote key (%s) unchanged from cached version", m_key.source.c_str());
603 // Shouldn't happen, we should only get codes intended to be gracefully handled.
604 log.crit("maintaining existing key, remote fetch returned atypical status code (%d)", ex);
607 catch (exception& ex) {
608 log.crit("maintaining existing key: %s", ex.what());
612 for (vector<ManagedCert>::iterator i = m_certs.begin(); i != m_certs.end(); ++i) {
613 if (i->stale(log, writelock ? nullptr : m_lock)) {
616 i->load(log, (i==m_certs.begin()) ? m_certpass.c_str() : nullptr);
620 if (ex == HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED) {
621 log.info("remote certificate(s) (%s) unchanged from cached version", i->source.c_str());
624 // Shouldn't happen, we should only get codes intended to be gracefully handled.
625 log.crit("maintaining existing certificate(s), remote fetch returned atypical status code (%d)", ex);
628 catch (exception& ex) {
629 log.crit("maintaining existing certificate(s): %s", ex.what());
634 for (vector<ManagedCRL>::iterator j = m_crls.begin(); j != m_crls.end(); ++j) {
635 if (j->stale(log, writelock ? nullptr : m_lock)) {
642 if (ex == HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED) {
643 log.info("remote CRL(s) (%s) unchanged from cached version", j->source.c_str());
646 // Shouldn't happen, we should only get codes intended to be gracefully handled.
647 log.crit("maintaining existing CRL(s), remote fetch returned atypical status code (%d)", ex);
650 catch (exception& ex) {
651 log.crit("maintaining existing CRL(s): %s", ex.what());
658 auto_ptr<Credential> credential(getCredential());
660 m_credential = credential.release();
662 catch (exception& ex) {
663 log.crit("maintaining existing credentials, error reloading: %s", ex.what());
674 const Credential* FilesystemCredentialResolver::resolve(const CredentialCriteria* criteria) const
676 return (criteria ? (criteria->matches(*m_credential) ? m_credential : nullptr) : m_credential);
679 vector<const Credential*>::size_type FilesystemCredentialResolver::resolve(
680 vector<const Credential*>& results, const CredentialCriteria* criteria
683 if (!criteria || criteria->matches(*m_credential)) {
684 results.push_back(m_credential);
690 // OpenSSL password callback...
691 static int passwd_callback(char* buf, int len, int verify, void* passwd)
695 if(passwd && len > strlen(reinterpret_cast<char*>(passwd)))
697 strcpy(buf,reinterpret_cast<char*>(passwd));
704 void FilesystemCredential::attach(SSL_CTX* ctx) const
711 const char* path = m_resolver->m_key.local ? m_resolver->m_key.source.c_str() : m_resolver->m_key.backing.c_str();
713 throw XMLSecurityException("No key available, unable to attach private key to SSL context.");
715 if (!m_resolver->m_keypass.empty()) {
716 SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
717 SSL_CTX_set_default_passwd_cb_userdata(ctx, const_cast<char*>(m_resolver->m_keypass.c_str()));
720 if (m_resolver->m_key.format == "PEM") {
721 ret=SSL_CTX_use_PrivateKey_file(ctx, path, SSL_FILETYPE_PEM);
723 else if (m_resolver->m_key.format == "DER") {
724 ret=SSL_CTX_use_RSAPrivateKey_file(ctx, path, SSL_FILETYPE_ASN1);
726 else if (m_resolver->m_key.format == "PKCS12") {
727 BIO* in=BIO_new(BIO_s_file_internal());
728 if (in && BIO_read_filename(in,path)>0) {
729 PKCS12* p12 = d2i_PKCS12_bio(in, nullptr);
731 EVP_PKEY* pkey=nullptr;
733 PKCS12_parse(p12, const_cast<char*>(m_resolver->m_keypass.c_str()), &pkey, &x, nullptr);
738 ret=SSL_CTX_use_PrivateKey(ctx, pkey);
749 throw XMLSecurityException("Unable to attach private key to SSL context.");
753 for (vector<XSECCryptoX509*>::const_iterator i=m_xseccerts.begin(); i!=m_xseccerts.end(); i++) {
754 if (i==m_xseccerts.begin()) {
755 if (SSL_CTX_use_certificate(ctx, static_cast<OpenSSLCryptoX509*>(*i)->getOpenSSLX509()) != 1) {
757 throw XMLSecurityException("Unable to attach client certificate to SSL context.");
761 // When we add certs, they don't get ref counted, so we need to duplicate them.
762 X509* dup = X509_dup(static_cast<OpenSSLCryptoX509*>(*i)->getOpenSSLX509());
763 if (SSL_CTX_add_extra_chain_cert(ctx, dup) != 1) {
766 throw XMLSecurityException("Unable to attach CA certificate to SSL context.");