2 * Copyright 2001-2009 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.
17 /* XMLTrust.cpp - a trust implementation that uses an XML file
27 #include <sys/types.h>
30 #include <openssl/err.h>
31 #include <openssl/x509v3.h>
32 #include <openssl/x509_vfy.h>
34 #include <xercesc/framework/URLInputSource.hpp>
35 #include <xercesc/util/regx/RegularExpression.hpp>
36 #include <xsec/enc/XSECCryptoException.hpp>
37 #include <xsec/enc/XSECKeyInfoResolverDefault.hpp>
39 using namespace xmlproviders::logging;
40 using namespace shibboleth;
45 class XMLTrustImpl : public ReloadableXMLFileImpl
48 XMLTrustImpl(const char* pathname) : ReloadableXMLFileImpl(pathname), m_wildcard(NULL) { init(); }
49 XMLTrustImpl(const DOMElement* e) : ReloadableXMLFileImpl(e), m_wildcard(NULL) { init(); }
55 KeyAuthority() : m_depth(1) {}
57 X509_STORE* getX509Store();
60 vector<const XMLCh*> m_subjects;
62 vector<X509*> m_certs;
63 vector<X509_CRL*> m_crls;
64 unsigned short m_depth;
67 vector<DSIGKeyInfoList*> m_keybinds;
68 vector<KeyAuthority*> m_keyauths;
69 KeyAuthority* m_wildcard;
71 typedef map<xstring,KeyAuthority*> AuthMap;
72 typedef map<xstring,DSIGKeyInfoList*> BindMap;
78 class XMLTrust : public ITrust, public ReloadableXMLFile
81 XMLTrust(const DOMElement* e);
84 bool validate(void* certEE, const Iterator<void*>& certChain, const IRoleDescriptor* role, bool checkName=true);
85 bool validate(const saml::SAMLSignedObject& token, const IRoleDescriptor* role, ITrust* certValidator=NULL);
88 virtual ReloadableXMLFileImpl* newImplementation(const char* pathname, bool first=true) const;
89 virtual ReloadableXMLFileImpl* newImplementation(const DOMElement* e, bool first=true) const;
91 vector<KeyInfoResolver*> m_resolvers;
96 IPlugIn* XMLTrustFactory(const DOMElement* e)
98 auto_ptr<XMLTrust> t(new XMLTrust(e));
99 t->getImplementation();
104 ReloadableXMLFileImpl* XMLTrust::newImplementation(const char* pathname, bool first) const
106 return new XMLTrustImpl(pathname);
109 ReloadableXMLFileImpl* XMLTrust::newImplementation(const DOMElement* e, bool first) const
111 return new XMLTrustImpl(e);
114 X509_STORE* XMLTrustImpl::KeyAuthority::getX509Store()
117 NDC ndc("getX509Store");
119 Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Trust");
121 // Load the cert vector into a store.
122 X509_STORE* store=X509_STORE_new();
127 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
128 X509_STORE_set_flags(store,X509_V_FLAG_CRL_CHECK_ALL);
131 for (vector<X509*>::iterator j=m_certs.begin(); j!=m_certs.end(); j++) {
132 if (!X509_STORE_add_cert(store,*j)) {
134 log.warn("failed to add cert: %s", (*j)->name);
139 for (vector<X509_CRL*>::iterator k=m_crls.begin(); k!=m_crls.end(); k++) {
140 if (!X509_STORE_add_crl(store,*k)) {
142 log.warn("failed to add CRL");
150 XMLTrustImpl::KeyAuthority::~KeyAuthority()
152 for (vector<X509*>::iterator i=m_certs.begin(); i!=m_certs.end(); i++)
154 for (vector<X509_CRL*>::iterator j=m_crls.begin(); j!=m_crls.end(); j++)
158 class KeyInfoNodeFilter : public DOMNodeFilter
161 short acceptNode(const DOMNode* node) const
163 // Our filter just skips any trees not rooted by ds:KeyInfo.
164 if (node->getNodeType()==DOMNode::ELEMENT_NODE) {
165 if (saml::XML::isElementNamed(static_cast<const DOMElement*>(node),saml::XML::XMLSIG_NS,L(KeyInfo)))
166 return FILTER_ACCEPT;
168 return FILTER_REJECT;
172 void XMLTrustImpl::init()
175 saml::NDC ndc("init");
177 Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Trust");
180 if (!saml::XML::isElementNamed(m_root,::XML::TRUST_NS,SHIB_L(Trust))) {
181 log.error("Construction requires a valid trust file: (trust:Trust as root element)");
182 throw TrustException("Construction requires a valid trust file: (trust:Trust as root element)");
185 // Loop over the KeyAuthority elements.
186 DOMNodeList* nlist=m_root->getElementsByTagNameNS(::XML::TRUST_NS,SHIB_L(KeyAuthority));
187 for (XMLSize_t i=0; nlist && i<nlist->getLength(); i++) {
188 auto_ptr<KeyAuthority> ka(new KeyAuthority());
190 const DOMElement* e=static_cast<DOMElement*>(nlist->item(i));
191 const XMLCh* depth=e->getAttributeNS(NULL,SHIB_L(VerifyDepth));
193 ka->m_depth=XMLString::parseInt(depth);
195 const DOMElement* k_child=saml::XML::getLastChildElement(e,saml::XML::XMLSIG_NS,L(KeyInfo));
197 log.error("ignoring KeyAuthority element with no ds:KeyInfo");
200 const DOMElement* badkeyname=saml::XML::getFirstChildElement(k_child,saml::XML::XMLSIG_NS,SHIB_L(KeyName));
202 log.error("ignoring KeyAuthority element with embedded ds:KeyName, these must appear only outside of ds:KeyInfo");
206 // Very rudimentary, grab up all the in-band X509Certificate elements, and flatten into one list.
207 DOMNodeList* certlist=k_child->getElementsByTagNameNS(saml::XML::XMLSIG_NS,L(X509Certificate));
208 for (XMLSize_t j=0; certlist && j<certlist->getLength(); j++) {
209 auto_ptr_char blob(certlist->item(j)->getFirstChild()->getNodeValue());
210 X509* x=B64_to_X509(blob.get());
212 ka->m_certs.push_back(x);
214 log.error("unable to create certificate from inline X509Certificate data");
217 // Now look for externally referenced objects.
218 certlist=k_child->getElementsByTagNameNS(saml::XML::XMLSIG_NS,SHIB_L(RetrievalMethod));
219 for (XMLSize_t k=0; certlist && k<certlist->getLength(); k++) {
220 DOMElement* cert=static_cast<DOMElement*>(certlist->item(k));
221 if (!XMLString::compareString(cert->getAttributeNS(NULL,SHIB_L(Type)),::XML::XMLSIG_RETMETHOD_RAWX509)) {
223 auto_ptr_char fname(cert->getAttributeNS(NULL,SHIB_L(URI)));
224 FILE* f=fopen(fname.get(),"r");
229 ka->m_certs.push_back(x);
235 log.error("unable to create certificate from externally referenced file");
239 // Very rudimentary, grab up all the in-band X509CRL elements, and flatten into one list.
240 certlist=k_child->getElementsByTagNameNS(saml::XML::XMLSIG_NS,SHIB_L(X509CRL));
241 for (XMLSize_t r=0; certlist && r<certlist->getLength(); r++) {
242 auto_ptr_char blob(certlist->item(r)->getFirstChild()->getNodeValue());
243 X509_CRL* x=B64_to_CRL(blob.get());
245 ka->m_crls.push_back(x);
247 log.warn("unable to create CRL from inline X509CRL data");
250 KeyAuthority* ka2=ka.release();
251 m_keyauths.push_back(ka2);
253 // Now map the ds:KeyName values to the list of certs.
255 DOMElement* sub=saml::XML::getFirstChildElement(e,saml::XML::XMLSIG_NS,SHIB_L(KeyName));
257 const XMLCh* name=sub->getFirstChild()->getNodeValue();
263 ka2->m_subjects.push_back(name);
266 sub=saml::XML::getNextSiblingElement(sub,saml::XML::XMLSIG_NS,SHIB_L(KeyName));
269 // If no Subjects, this is a catch-all binding.
272 log.warn("found a wildcard KeyAuthority element, make sure this is what you intend");
276 log.warn("found multiple wildcard KeyAuthority elements, ignoring all but the first");
280 // Now traverse the outer ds:KeyInfo elements. Supposedly this cast just works...
282 KeyInfoNodeFilter filter;
283 XSECKeyInfoResolverDefault resolver;
284 DOMTreeWalker* walker=
285 static_cast<DOMDocumentTraversal*>(m_doc)->createTreeWalker(const_cast<DOMElement*>(m_root),DOMNodeFilter::SHOW_ELEMENT,&filter,false);
286 DOMElement* kidom=static_cast<DOMElement*>(walker->firstChild());
289 DSIGKeyInfoList* KIL = new DSIGKeyInfoList(NULL);
290 // We let XMLSec hack through anything it can. This should evolve over time, or we can
291 // plug in our own KeyResolver later...
293 if (!KIL->loadListFromXML(kidom))
294 log.error("skipping ds:KeyInfo element (%d) containing unsupported children",count);
296 catch (XSECCryptoException& xe) {
297 log.error("unable to process ds:KeyInfo element (%d): %s",count,xe.getMsg());
300 // Dry run...can we resolve to a key?
301 XSECCryptoKey* key=NULL;
303 key = resolver.resolveKey(KIL);
305 catch (XSECCryptoException& xe) {
306 log.error("unable to resolver key from ds:KeyInfo element (%d): %s", count, xe.getMsg());
309 // So far so good, now look for the name binding(s).
312 for (size_t index=0; index<KIL->getSize(); index++) {
313 DSIGKeyInfo* info=KIL->item(index);
314 const XMLCh* name=info->getKeyName();
317 m_keybinds.push_back(KIL);
325 log.warn("skipping ds:KeyInfo binding (%d) that does not contain a usable key name",count);
330 log.warn("skipping ds:KeyInfo binding (%d) that does not resolve to a key",count);
333 kidom=static_cast<DOMElement*>(walker->nextSibling());
335 walker->release(); // This just cleans up aggressively, but there's no leak if we don't.
337 catch (SAMLException& e) {
338 log.errorStream() << "Error while parsing trust configuration: " << e.what() << xmlproviders::logging::eol;
339 this->~XMLTrustImpl();
344 log.error("Unexpected error while parsing trust configuration");
345 this->~XMLTrustImpl();
351 XMLTrustImpl::~XMLTrustImpl()
353 for (vector<KeyAuthority*>::iterator i=m_keyauths.begin(); i!=m_keyauths.end(); i++)
355 for (vector<DSIGKeyInfoList*>::iterator j=m_keybinds.begin(); j!=m_keybinds.end(); j++)
359 XMLTrust::XMLTrust(const DOMElement* e) : ReloadableXMLFile(e), m_delegate(NULL)
361 static const XMLCh resolver[] =
362 { chLatin_K, chLatin_e, chLatin_y, chLatin_I, chLatin_n, chLatin_f, chLatin_o,
363 chLatin_R, chLatin_e, chLatin_s, chLatin_o, chLatin_l, chLatin_v, chLatin_e, chLatin_r, chNull
366 static const XMLCh _type[] =
367 { chLatin_t, chLatin_y, chLatin_p, chLatin_e, chNull };
369 Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Trust");
371 // Find any KeyResolver plugins.
372 DOMElement* child=saml::XML::getFirstChildElement(e);
374 if (!XMLString::compareString(resolver,child->getLocalName()) && child->hasAttributeNS(NULL,_type)) {
376 auto_ptr_char temp(child->getAttributeNS(NULL,_type));
377 m_resolvers.push_back(KeyInfoResolver::getInstance(temp.get(),child));
379 catch (SAMLException& ex) {
380 log.error("caught SAML exception building KeyInfoResolver plugin: %s",ex.what());
384 log.error("caught unknown exception building KeyInfoResolver plugin");
388 child=saml::XML::getNextSiblingElement(child);
390 m_resolvers.push_back(KeyInfoResolver::getInstance(e));
393 IPlugIn* plugin=SAMLConfig::getConfig().getPlugMgr().newPlugin(
394 "edu.internet2.middleware.shibboleth.common.provider.ShibbolethTrust",e
396 m_delegate=dynamic_cast<ITrust*>(plugin);
399 log.error("plugin was not a trust provider");
400 throw UnsupportedExtensionException("Legacy trust provider requires Shibboleth trust provider in order to function.");
403 catch (SAMLException& ex) {
404 log.error("caught SAML exception building embedded trust provider: %s", ex.what());
409 XMLTrust::~XMLTrust()
412 for (vector<KeyInfoResolver*>::iterator i=m_resolvers.begin(); i!=m_resolvers.end(); i++)
416 static int error_callback(int ok, X509_STORE_CTX* ctx)
419 Category::getInstance("OpenSSL").error("path validation failure: %s", X509_verify_cert_error_string(ctx->error));
423 bool XMLTrust::validate(void* certEE, const Iterator<void*>& certChain, const IRoleDescriptor* role, bool checkName)
425 // The delegated trust plugin handles path validation with metadata extensions.
426 // We only take over if the legacy format has to kick in.
427 if (m_delegate->validate(certEE,certChain,role,checkName))
431 saml::NDC ndc("validate");
433 Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Trust");
436 // Before we do the cryptogprahy, check that the EE certificate "name" matches
437 // one of the acceptable key "names" for the signer.
438 vector<string> keynames;
440 // Build a list of acceptable names. Transcode the possible key "names" to UTF-8.
441 // For some simple cases, this should handle UTF-8 encoded DNs in certificates.
442 Iterator<const IKeyDescriptor*> kd_i=role->getKeyDescriptors();
443 while (kd_i.hasNext()) {
444 const IKeyDescriptor* kd=kd_i.next();
445 if (kd->getUse()!=IKeyDescriptor::signing)
447 DSIGKeyInfoList* KIL=kd->getKeyInfo();
450 for (size_t s=0; s<KIL->getSize(); s++) {
451 const XMLCh* n=KIL->item(s)->getKeyName();
453 auto_ptr<char> kn(toUTF8(n));
454 keynames.push_back(kn.get());
458 auto_ptr<char> kn(toUTF8(role->getEntityDescriptor()->getId()));
459 keynames.push_back(kn.get());
461 X509* x=(X509*)certEE;
462 X509_NAME* subject=X509_get_subject_name(x);
464 // One way is a direct match to the subject DN.
465 // Seems that the way to do the compare is to write the X509_NAME into a BIO.
466 BIO* b = BIO_new(BIO_s_mem());
467 BIO* b2 = BIO_new(BIO_s_mem());
468 // The flags give us LDAP order instead of X.500, with a comma separator.
469 int len=X509_NAME_print_ex(b,subject,0,XN_FLAG_RFC2253);
471 // The flags give us LDAP order instead of X.500, with a comma plus space separator.
472 len=X509_NAME_print_ex(b2,subject,0,XN_FLAG_RFC2253 + XN_FLAG_SEP_CPLUS_SPC - XN_FLAG_SEP_COMMA_PLUS);
477 BIO_get_mem_ptr(b, &bptr);
478 BIO_get_mem_ptr(b2, &bptr2);
480 if (bptr && bptr->length > 0 && log.isDebugEnabled()) {
481 string subjectstr(bptr->data, bptr->length);
482 log.debug("certificate subject: %s", subjectstr.c_str());
485 // Check each keyname.
486 for (vector<string>::const_iterator n=keynames.begin(); n!=keynames.end(); n++) {
487 #ifdef HAVE_STRCASECMP
488 if ((n->length() == bptr->length && !strncasecmp(n->c_str(), bptr->data, bptr->length)) ||
489 (n->length() == bptr2->length && !strncasecmp(n->c_str(), bptr2->data, bptr2->length))) {
491 if ((n->length() == bptr->length && !strnicmp(n->c_str(), bptr->data, bptr->length)) ||
492 (n->length() == bptr2->length && !strnicmp(n->c_str(), bptr2->data, bptr2->length))) {
494 log.debug("matched full subject DN to a key name (%s)", n->c_str());
503 log.debug("unable to match DN, trying TLS subjectAltName match");
504 STACK_OF(GENERAL_NAME)* altnames=(STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
506 int numalts = sk_GENERAL_NAME_num(altnames);
507 for (int an=0; checkName && an<numalts; an++) {
508 const GENERAL_NAME* check = sk_GENERAL_NAME_value(altnames, an);
509 if (check->type==GEN_DNS || check->type==GEN_URI) {
510 const char* altptr = (char*)ASN1_STRING_data(check->d.ia5);
511 const int altlen = ASN1_STRING_length(check->d.ia5);
512 for (vector<string>::const_iterator n=keynames.begin(); n!=keynames.end(); n++) {
513 #ifdef HAVE_STRCASECMP
514 if ((check->type==GEN_DNS && n->length()==altlen && !strncasecmp(altptr,n->c_str(),altlen))
516 if ((check->type==GEN_DNS && n->length()==altlen && !strnicmp(altptr,n->c_str(),altlen))
518 || (check->type==GEN_URI && n->length()==altlen && !strncmp(altptr,n->c_str(),altlen))) {
519 log.debug("matched DNS/URI subjectAltName to a key name (%s)", n->c_str());
526 GENERAL_NAMES_free(altnames);
530 log.debug("unable to match subjectAltName, trying TLS CN match");
532 // Fetch the last CN RDN.
533 char* peer_CN = NULL;
535 while ((j=X509_NAME_get_index_by_NID(subject, NID_commonName, i)) >= 0)
538 ASN1_STRING* tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject, i));
539 // Copied in from libcurl.
540 /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input
541 is already UTF-8 encoded. We check for this case and copy the raw
542 string manually to avoid the problem. */
543 if(tmp && ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
544 j = ASN1_STRING_length(tmp);
546 peer_CN = (char*)OPENSSL_malloc(j + 1);
547 memcpy(peer_CN, ASN1_STRING_data(tmp), j);
551 else /* not a UTF8 name */ {
552 j = ASN1_STRING_to_UTF8(reinterpret_cast<unsigned char**>(&peer_CN), tmp);
555 for (vector<string>::const_iterator n=keynames.begin(); n!=keynames.end(); n++) {
556 #ifdef HAVE_STRCASECMP
557 if (n->length() == j && !strncasecmp(peer_CN, n->c_str(), j)) {
559 if (n->length() == j && !strnicmp(peer_CN, n->c_str(), j)) {
561 log.debug("matched subject CN to a key name (%s)", n->c_str());
567 OPENSSL_free(peer_CN);
570 log.warn("no common name in certificate subject");
576 log.error("certificate has no subject?!");
581 log.error("cannot match certificate subject against acceptable key names based on KeyDescriptors");
587 XMLTrustImpl* impl=dynamic_cast<XMLTrustImpl*>(getImplementation());
589 // Build a list of the names to match. We include any named KeyDescriptors, and the provider ID and its groups.
590 vector<const XMLCh*> names;
591 Iterator<const IKeyDescriptor*> kdlist=role->getKeyDescriptors();
592 while (kdlist.hasNext()) {
593 const IKeyDescriptor* kd=kdlist.next();
594 if (kd->getUse()==IKeyDescriptor::encryption)
596 DSIGKeyInfoList* kilist=kd->getKeyInfo();
597 for (size_t s=0; kilist && s<kilist->getSize(); s++) {
598 const XMLCh* n=kilist->item(s)->getKeyName();
603 names.push_back(role->getEntityDescriptor()->getId());
604 const IEntitiesDescriptor* group=role->getEntityDescriptor()->getEntitiesDescriptor();
606 if (group->getName())
607 names.push_back(group->getName());
608 group=group->getEntitiesDescriptor();
611 // Now check each name.
612 XMLTrustImpl::KeyAuthority* kauth=NULL;
613 for (vector<const XMLCh*>::const_iterator name=names.begin(); !kauth && name!=names.end(); name++) {
615 XMLTrustImpl::AuthMap::const_iterator c=impl->m_authMap.find(*name);
616 if (c!=impl->m_authMap.end()) {
618 if (log.isInfoEnabled()) {
619 auto_ptr_char temp(*name);
620 log.info("KeyAuthority match on %s",temp.get());
624 // Without a decent STL, we trade-off the transcoding by doing a linear search.
625 for (vector<XMLTrustImpl::KeyAuthority*>::const_iterator keyauths=impl->m_keyauths.begin(); !kauth && keyauths!=impl->m_keyauths.end(); keyauths++) {
626 for (vector<const XMLCh*>::const_iterator subs=(*keyauths)->m_subjects.begin(); !kauth && subs!=(*keyauths)->m_subjects.end(); subs++) {
627 if (!XMLString::compareString(*name,*subs)) {
629 if (log.isInfoEnabled()) {
630 auto_ptr_char temp(*name);
631 log.debug("KeyAuthority match on %s",temp.get());
640 if (impl->m_wildcard) {
641 log.warn("applying wildcard KeyAuthority, use with caution!");
642 kauth=impl->m_wildcard;
646 log.warn("no KeyAuthority found to validate SSL connection, leaving it alone");
651 log.debug("performing certificate path validation...");
653 // If we have a match, use the associated keyauth.
654 X509_STORE* store=kauth->getX509Store();
656 STACK_OF(X509)* untrusted=sk_X509_new_null();
658 while (certChain.hasNext())
659 sk_X509_push(untrusted,(X509*)certChain.next());
661 // This contains the state of the validate operation.
664 // AFAICT, EE and untrusted are passed in but not owned by the ctx.
665 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
666 if (X509_STORE_CTX_init(&ctx,store,(X509*)certEE,untrusted)!=1) {
668 log.error("unable to initialize X509_STORE_CTX");
669 X509_STORE_free(store);
670 sk_X509_free(untrusted);
675 X509_STORE_CTX_init(&ctx,store,(X509*)certEE,untrusted);
677 X509_STORE_CTX_set_depth(&ctx,100); // handle depth below
678 X509_STORE_CTX_set_verify_cb(&ctx,error_callback);
680 int ret=X509_verify_cert(&ctx);
682 // Now see if the depth was acceptable by counting the number of intermediates.
683 int depth=sk_X509_num(ctx.chain)-2;
684 if (kauth->m_depth < depth) {
686 "certificate chain was too long (%d intermediates, only %d allowed)",
687 (depth==-1) ? 0 : depth,
695 X509_STORE_CTX_cleanup(&ctx);
696 X509_STORE_free(store);
699 log.debug("successfully validated certificate chain");
713 bool XMLTrust::validate(const saml::SAMLSignedObject& token, const IRoleDescriptor* role, ITrust* certValidator)
715 // The delegated trust plugin handles metadata keys and use of metadata extensions.
716 // If it fails to find an inline key in metadata, then it will branch off to the
717 // extended version and verify the token using the certificates inside it. At that
718 // point, control will pass to the other virtual function above and we can handle
719 // legacy KeyAuthority rules that way.
720 if (m_delegate->validate(token,role,certValidator ? certValidator : this))
724 saml::NDC ndc("validate");
726 Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Trust");
730 XMLTrustImpl* impl=dynamic_cast<XMLTrustImpl*>(getImplementation());
732 // If we actually make it this far, the only case we're handling directly
733 // is an inline key in the old trust file format. Build a list of key names
734 // which will be used to find matching rules.
735 vector<const XMLCh*> names;
737 // Build a list of acceptable names. Transcode the possible key "names" to UTF-8.
738 // For some simple cases, this should handle UTF-8 encoded DNs in certificates.
739 Iterator<const IKeyDescriptor*> kd_i=role->getKeyDescriptors();
740 while (kd_i.hasNext()) {
741 const IKeyDescriptor* kd=kd_i.next();
742 if (kd->getUse()!=IKeyDescriptor::signing)
744 DSIGKeyInfoList* KIL=kd->getKeyInfo();
747 for (size_t s=0; s<KIL->getSize(); s++) {
748 const XMLCh* n=KIL->item(s)->getKeyName();
753 names.push_back(role->getEntityDescriptor()->getId());
755 log.debug("checking for keys in trust file");
756 DSIGKeyInfoList* KIL=NULL;
757 for (vector<const XMLCh*>::const_iterator name=names.begin(); !KIL && name!=names.end(); name++) {
759 XMLTrustImpl::BindMap::const_iterator c=impl->m_bindMap.find(*name);
760 if (c!=impl->m_bindMap.end()) {
762 if (log.isInfoEnabled()) {
763 auto_ptr_char temp(*name);
764 log.info("KeyInfo match on %s",temp.get());
768 // Without a decent STL, we trade-off the transcoding by doing a linear search.
769 for (vector<DSIGKeyInfoList*>::const_iterator keybinds=impl->m_keybinds.begin(); !KIL && keybinds!=impl->m_keybinds.end(); keybinds++) {
770 for (size_t s=0; !KIL && s<(*keybinds)->getSize(); s++) {
771 if (!XMLString::compareString(*name,(*keybinds)->item(s)->getKeyName())) {
773 if (log.isInfoEnabled()) {
774 auto_ptr_char temp(*name);
775 log.debug("KeyInfo match on %s",temp.get());
784 // Any inline KeyInfo should ostensibly resolve to a key we can try.
785 Iterator<KeyInfoResolver*> resolvers(m_resolvers);
786 while (resolvers.hasNext()) {
787 XSECCryptoKey* key=NULL;
789 key=((XSECKeyInfoResolver*)*resolvers.next())->resolveKey(KIL);
791 catch (XSECCryptoException& xe) {
792 log.error("unable to resolver ds:KeyInfo element into key: %s", xe.getMsg());
795 log.debug("resolved key, trying it...");
799 log.debug("token verified with KeyInfo, nothing more to verify");
802 catch (SAMLException& e) {
804 log.warn("verification with inline key failed: %s", e.what());
809 log.warn("KeyInfo in trust provider did not resolve to a key");