Fixed "cast" of key resolver.
[shibboleth/cpp-sp.git] / xmlproviders / XMLTrust.cpp
1 /* 
2  * The Shibboleth License, Version 1. 
3  * Copyright (c) 2002 
4  * University Corporation for Advanced Internet Development, Inc. 
5  * All rights reserved
6  * 
7  * 
8  * Redistribution and use in source and binary forms, with or without 
9  * modification, are permitted provided that the following conditions are met:
10  * 
11  * Redistributions of source code must retain the above copyright notice, this 
12  * list of conditions and the following disclaimer.
13  * 
14  * Redistributions in binary form must reproduce the above copyright notice, 
15  * this list of conditions and the following disclaimer in the documentation 
16  * and/or other materials provided with the distribution, if any, must include 
17  * the following acknowledgment: "This product includes software developed by 
18  * the University Corporation for Advanced Internet Development 
19  * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement 
20  * may appear in the software itself, if and wherever such third-party 
21  * acknowledgments normally appear.
22  * 
23  * Neither the name of Shibboleth nor the names of its contributors, nor 
24  * Internet2, nor the University Corporation for Advanced Internet Development, 
25  * Inc., nor UCAID may be used to endorse or promote products derived from this 
26  * software without specific prior written permission. For written permission, 
27  * please contact shibboleth@shibboleth.org
28  * 
29  * Products derived from this software may not be called Shibboleth, Internet2, 
30  * UCAID, or the University Corporation for Advanced Internet Development, nor 
31  * may Shibboleth appear in their name, without prior written permission of the 
32  * University Corporation for Advanced Internet Development.
33  * 
34  * 
35  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
36  * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
37  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
38  * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK 
39  * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE. 
40  * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY 
41  * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, 
42  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
43  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
44  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
46  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
47  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  */
49
50 /* XMLTrust.cpp - a trust implementation that uses an XML file
51
52    Scott Cantor
53    9/27/02
54
55    $History:$
56 */
57
58 #include "internal.h"
59
60 #include <sys/types.h>
61 #include <sys/stat.h>
62
63 #include <openssl/err.h>
64 #include <openssl/x509v3.h>
65 #include <openssl/x509_vfy.h>
66
67 #include <log4cpp/Category.hh>
68 #include <xercesc/framework/URLInputSource.hpp>
69 #include <xercesc/util/regx/RegularExpression.hpp>
70 #include <xsec/enc/XSECCryptoException.hpp>
71 #include <xsec/enc/XSECKeyInfoResolverDefault.hpp>
72
73 using namespace shibboleth;
74 using namespace saml;
75 using namespace log4cpp;
76 using namespace std;
77
78 namespace {
79     class XMLTrustImpl : public ReloadableXMLFileImpl
80     {
81     public:
82         XMLTrustImpl(const char* pathname) : ReloadableXMLFileImpl(pathname), m_wildcard(NULL) { init(); }
83         XMLTrustImpl(const DOMElement* e) : ReloadableXMLFileImpl(e), m_wildcard(NULL) { init(); }
84         void init();
85         ~XMLTrustImpl();
86         
87         struct KeyAuthority
88         {
89             KeyAuthority() : m_depth(1) {}
90             ~KeyAuthority();
91             X509_STORE* getX509Store();
92             
93 #ifndef HAVE_GOOD_STL
94             vector<const XMLCh*> m_subjects;
95 #endif
96             vector<X509*> m_certs;
97             vector<X509_CRL*> m_crls;
98             unsigned short m_depth;
99         };
100         
101         vector<DSIGKeyInfoList*> m_keybinds;
102         vector<KeyAuthority*> m_keyauths;
103         KeyAuthority* m_wildcard;
104 #ifdef HAVE_GOOD_STL
105         typedef map<xstring,KeyAuthority*> AuthMap;
106         typedef map<xstring,DSIGKeyInfoList*> BindMap;
107         AuthMap m_authMap;
108         BindMap m_bindMap;
109 #endif
110     };
111
112     class XMLTrust : public ITrust, public ReloadableXMLFile
113     {
114     public:
115         XMLTrust(const DOMElement* e);
116         ~XMLTrust();
117
118     bool validate(void* certEE, const Iterator<void*>& certChain, const IRoleDescriptor* role, bool checkName=true);
119     bool validate(const saml::SAMLSignedObject& token, const IRoleDescriptor* role);
120
121     protected:
122         virtual ReloadableXMLFileImpl* newImplementation(const char* pathname, bool first=true) const;
123         virtual ReloadableXMLFileImpl* newImplementation(const DOMElement* e, bool first=true) const;
124
125         vector<KeyInfoResolver*> m_resolvers;
126         ITrust* m_delegate;
127     };
128 }
129
130 IPlugIn* XMLTrustFactory(const DOMElement* e)
131 {
132     auto_ptr<XMLTrust> t(new XMLTrust(e));
133     t->getImplementation();
134     return t.release();
135 }
136
137
138 ReloadableXMLFileImpl* XMLTrust::newImplementation(const char* pathname, bool first) const
139 {
140     return new XMLTrustImpl(pathname);
141 }
142
143 ReloadableXMLFileImpl* XMLTrust::newImplementation(const DOMElement* e, bool first) const
144 {
145     return new XMLTrustImpl(e);
146 }
147
148 X509_STORE* XMLTrustImpl::KeyAuthority::getX509Store()
149 {
150 #ifdef _DEBUG
151     NDC ndc("getX509Store");
152 #endif
153     Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Trust");
154
155     // Load the cert vector into a store.
156     X509_STORE* store=X509_STORE_new();
157     if (!store) {
158         log_openssl();
159         return NULL;
160     }
161     X509_STORE_set_flags(store,X509_V_FLAG_CRL_CHECK_ALL);
162     
163     for (vector<X509*>::iterator j=m_certs.begin(); j!=m_certs.end(); j++) {
164         if (!X509_STORE_add_cert(store,*j)) {
165             log_openssl();
166             log.warn("failed to add cert: %s", (*j)->name);
167             continue;
168         }
169     }
170
171     for (vector<X509_CRL*>::iterator k=m_crls.begin(); k!=m_crls.end(); k++) {
172         if (!X509_STORE_add_crl(store,*k)) {
173             log_openssl();
174             log.warn("failed to add CRL");
175             continue;
176         }
177     }
178
179     return store;
180 }
181
182 XMLTrustImpl::KeyAuthority::~KeyAuthority()
183 {
184     for (vector<X509*>::iterator i=m_certs.begin(); i!=m_certs.end(); i++)
185         X509_free(*i);
186     for (vector<X509_CRL*>::iterator j=m_crls.begin(); j!=m_crls.end(); j++)
187         X509_CRL_free(*j);
188 }
189
190 class KeyInfoNodeFilter : public DOMNodeFilter
191 {
192 public:
193     short acceptNode(const DOMNode* node) const
194     {
195         // Our filter just skips any trees not rooted by ds:KeyInfo.
196         if (node->getNodeType()==DOMNode::ELEMENT_NODE) {
197             if (saml::XML::isElementNamed(static_cast<const DOMElement*>(node),saml::XML::XMLSIG_NS,L(KeyInfo)))
198                 return FILTER_ACCEPT;
199         }
200         return FILTER_REJECT;
201     }
202 };
203
204 void XMLTrustImpl::init()
205 {
206 #ifdef _DEBUG
207     saml::NDC ndc("init");
208 #endif
209     Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Trust");
210
211     try {
212         if (!saml::XML::isElementNamed(m_root,::XML::TRUST_NS,SHIB_L(Trust))) {
213             log.error("Construction requires a valid trust file: (trust:Trust as root element)");
214             throw TrustException("Construction requires a valid trust file: (trust:Trust as root element)");
215         }
216
217         // Loop over the KeyAuthority elements.
218         DOMNodeList* nlist=m_root->getElementsByTagNameNS(::XML::TRUST_NS,SHIB_L(KeyAuthority));
219         for (int i=0; nlist && i<nlist->getLength(); i++) {
220             auto_ptr<KeyAuthority> ka(new KeyAuthority());
221             
222             const DOMElement* e=static_cast<DOMElement*>(nlist->item(i));
223             const XMLCh* depth=e->getAttributeNS(NULL,SHIB_L(VerifyDepth));
224             if (depth && *depth)
225                 ka->m_depth=XMLString::parseInt(depth);
226             
227             const DOMElement* k_child=saml::XML::getLastChildElement(e,saml::XML::XMLSIG_NS,L(KeyInfo));
228             if (!k_child) {
229                 log.error("ignoring KeyAuthority element with no ds:KeyInfo");
230                 continue;
231             }
232             const DOMElement* badkeyname=saml::XML::getFirstChildElement(k_child,saml::XML::XMLSIG_NS,SHIB_L(KeyName));
233             if (badkeyname) {
234                 log.error("ignoring KeyAuthority element with embedded ds:KeyName, these must appear only outside of ds:KeyInfo");
235                 continue;
236             }
237             
238             // Very rudimentary, grab up all the in-band X509Certificate elements, and flatten into one list.
239             DOMNodeList* certlist=k_child->getElementsByTagNameNS(saml::XML::XMLSIG_NS,L(X509Certificate));
240             for (int j=0; certlist && j<certlist->getLength(); j++) {
241                 auto_ptr_char blob(certlist->item(j)->getFirstChild()->getNodeValue());
242                 X509* x=B64_to_X509(blob.get());
243                 if (x)
244                     ka->m_certs.push_back(x);
245                 else
246                     log.error("unable to create certificate from inline X509Certificate data");
247             }
248
249             // Now look for externally referenced objects.
250             certlist=k_child->getElementsByTagNameNS(saml::XML::XMLSIG_NS,SHIB_L(RetrievalMethod));
251             for (int k=0; certlist && k<certlist->getLength(); k++) {
252                 DOMElement* cert=static_cast<DOMElement*>(certlist->item(k));
253                 if (!XMLString::compareString(cert->getAttributeNS(NULL,SHIB_L(Type)),::XML::XMLSIG_RETMETHOD_RAWX509)) {
254                     // DER format
255                     auto_ptr_char fname(cert->getAttributeNS(NULL,SHIB_L(URI)));
256                     FILE* f=fopen(fname.get(),"r");
257                     if (f) {
258                         X509* x=NULL;
259                         d2i_X509_fp(f,&x);
260                         if (x) {
261                             ka->m_certs.push_back(x);
262                             continue;
263                         }
264                         else
265                             log_openssl();
266                     }
267                     log.error("unable to create certificate from externally referenced file");
268                 }
269             }
270
271             // Very rudimentary, grab up all the in-band X509CRL elements, and flatten into one list.
272             certlist=k_child->getElementsByTagNameNS(saml::XML::XMLSIG_NS,SHIB_L(X509CRL));
273             for (int r=0; certlist && r<certlist->getLength(); r++) {
274                 auto_ptr_char blob(certlist->item(r)->getFirstChild()->getNodeValue());
275                 X509_CRL* x=B64_to_CRL(blob.get());
276                 if (x)
277                     ka->m_crls.push_back(x);
278                 else
279                     log.warn("unable to create CRL from inline X509CRL data");
280             }
281
282             KeyAuthority* ka2=ka.release();
283             m_keyauths.push_back(ka2);
284             
285             // Now map the ds:KeyName values to the list of certs.
286             bool wildcard=true;
287             DOMElement* sub=saml::XML::getFirstChildElement(e,saml::XML::XMLSIG_NS,SHIB_L(KeyName));
288             while (sub) {
289                 const XMLCh* name=sub->getFirstChild()->getNodeValue();
290                 if (name && *name) {
291                     wildcard=false;
292 #ifdef HAVE_GOOD_STL
293                     m_authMap[name]=ka2;
294 #else
295                     ka2->m_subjects.push_back(name);
296 #endif
297                 }
298                 sub=saml::XML::getNextSiblingElement(sub,saml::XML::XMLSIG_NS,SHIB_L(KeyName));
299             }
300             
301             // If no Subjects, this is a catch-all binding.
302             if (wildcard) {
303                 if (!m_wildcard) {
304                     log.warn("found a wildcard KeyAuthority element, make sure this is what you intend");
305                     m_wildcard=ka2;
306                 }
307                 else
308                     log.warn("found multiple wildcard KeyAuthority elements, ignoring all but the first");
309             }
310         }
311
312         // Now traverse the outer ds:KeyInfo elements. Supposedly this cast just works...
313         int count=0;
314         KeyInfoNodeFilter filter;
315         XSECKeyInfoResolverDefault resolver;
316         DOMTreeWalker* walker=
317             static_cast<DOMDocumentTraversal*>(m_doc)->createTreeWalker(const_cast<DOMElement*>(m_root),DOMNodeFilter::SHOW_ELEMENT,&filter,false);
318         DOMElement* kidom=static_cast<DOMElement*>(walker->firstChild());
319         while (kidom) {
320             count++;
321             DSIGKeyInfoList* KIL = new DSIGKeyInfoList(NULL);
322             // We let XMLSec hack through anything it can. This should evolve over time, or we can
323             // plug in our own KeyResolver later...
324             try {
325                 if (!KIL->loadListFromXML(kidom))
326                     log.error("skipping ds:KeyInfo element (%d) containing unsupported children",count);
327             }
328             catch (XSECCryptoException& xe) {
329                 log.error("unable to process ds:KeyInfo element (%d): %s",count,xe.getMsg());
330             }
331             
332             // Dry run...can we resolve to a key?
333             XSECCryptoKey* key=resolver.resolveKey(KIL);
334             if (key) {
335                 // So far so good, now look for the name binding(s).
336                 delete key;
337                 bool named=false;
338                 for (size_t index=0; index<KIL->getSize(); index++) {
339                     DSIGKeyInfo* info=KIL->item(index);
340                     const XMLCh* name=info->getKeyName();
341                     if (name && *name) {
342                         if (!named)
343                             m_keybinds.push_back(KIL);
344                         named=true;
345 #ifdef HAVE_GOOD_STL
346                         m_bindMap[name]=KIL;
347 #endif
348                     }
349                 }
350                 if (!named) {
351                     log.warn("skipping ds:KeyInfo binding (%d) that does not contain a usable key name",count);
352                     delete KIL;
353                 }
354             }
355             else {
356                 log.warn("skipping ds:KeyInfo binding (%d) that does not resolve to a key",count);
357                 delete KIL;
358             }
359             kidom=static_cast<DOMElement*>(walker->nextSibling());
360         }
361         walker->release();    // This just cleans up aggressively, but there's no leak if we don't.
362     }
363     catch (SAMLException& e) {
364         log.errorStream() << "Error while parsing trust configuration: " << e.what() << CategoryStream::ENDLINE;
365         this->~XMLTrustImpl();
366         throw;
367     }
368 #ifndef _DEBUG
369     catch (...) {
370         log.error("Unexpected error while parsing trust configuration");
371         this->~XMLTrustImpl();
372         throw;
373     }
374 #endif
375 }
376
377 XMLTrustImpl::~XMLTrustImpl()
378 {
379     for (vector<KeyAuthority*>::iterator i=m_keyauths.begin(); i!=m_keyauths.end(); i++)
380         delete (*i);
381     for (vector<DSIGKeyInfoList*>::iterator j=m_keybinds.begin(); j!=m_keybinds.end(); j++)
382         delete (*j);
383 }
384
385 XMLTrust::XMLTrust(const DOMElement* e) : ReloadableXMLFile(e), m_delegate(NULL)
386 {
387     static const XMLCh resolver[] =
388     { chLatin_K, chLatin_e, chLatin_y, chLatin_I, chLatin_n, chLatin_f, chLatin_o,
389       chLatin_R, chLatin_e, chLatin_s, chLatin_o, chLatin_l, chLatin_v, chLatin_e, chLatin_r, chNull
390     };
391
392     static const XMLCh _type[] =
393     { chLatin_t, chLatin_y, chLatin_p, chLatin_e, chNull };
394
395     Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Trust");
396
397     // Find any KeyResolver plugins.
398     DOMElement* child=saml::XML::getFirstChildElement(e);
399     while (child) {
400         if (!XMLString::compareString(resolver,child->getLocalName()) && child->hasAttributeNS(NULL,_type)) {
401             try {
402                 auto_ptr_char temp(child->getAttributeNS(NULL,_type));
403                 m_resolvers.push_back(KeyInfoResolver::getInstance(temp.get(),child));
404             }
405             catch (SAMLException& ex) {
406                 log.error("caught SAML exception building KeyInfoResolver plugin: %s",ex.what());
407             }
408 #ifndef _DEBUG
409             catch (...) {
410                 log.error("caught unknown exception building KeyInfoResolver plugin");
411             }
412 #endif
413         }
414         child=saml::XML::getNextSiblingElement(child);
415     }
416     m_resolvers.push_back(KeyInfoResolver::getInstance(e));
417
418     try {
419         IPlugIn* plugin=SAMLConfig::getConfig().getPlugMgr().newPlugin(
420             "edu.internet2.middleware.shibboleth.common.provider.ShibbolethTrust",e
421             );
422         m_delegate=dynamic_cast<ITrust*>(plugin);
423         if (!m_delegate) {
424             delete plugin;
425             log.error("plugin was not a trust provider");
426             throw UnsupportedExtensionException("Legacy trust provider requires Shibboleth trust provider in order to function.");
427         }
428     }
429     catch (SAMLException& ex) {
430         log.error("caught SAML exception building embedded trust provider: %s", ex.what());
431         throw;
432     }
433 }
434
435 XMLTrust::~XMLTrust()
436 {
437     delete m_delegate;
438     for (vector<KeyInfoResolver*>::iterator i=m_resolvers.begin(); i!=m_resolvers.end(); i++)
439         delete *i;
440 }
441
442 extern "C" int error_callback(int ok, X509_STORE_CTX* ctx)
443 {
444     if (!ok)
445         Category::getInstance("OpenSSL").error("path validation failure: %s", X509_verify_cert_error_string(ctx->error));
446     return ok;
447 }
448
449 bool XMLTrust::validate(void* certEE, const Iterator<void*>& certChain, const IRoleDescriptor* role, bool checkName)
450 {
451     // The delegated trust plugin handles path validation with metadata extensions.
452     // We only take over if the legacy format has to kick in.
453     if (m_delegate->validate(certEE,certChain,role,checkName))
454         return true;
455
456 #ifdef _DEBUG
457     saml::NDC ndc("validate");
458 #endif
459     Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Trust");
460     
461     lock();
462     try {
463         XMLTrustImpl* impl=dynamic_cast<XMLTrustImpl*>(getImplementation());
464     
465         // Build a list of the names to match. We include any named KeyDescriptors, and the provider ID and its groups.
466         vector<const XMLCh*> names;
467         Iterator<const IKeyDescriptor*> kdlist=role->getKeyDescriptors();
468         while (kdlist.hasNext()) {
469             const IKeyDescriptor* kd=kdlist.next();
470             if (kd->getUse()==IKeyDescriptor::encryption)
471                 continue;
472             DSIGKeyInfoList* kilist=kd->getKeyInfo();
473             for (size_t s=0; kilist && s<kilist->getSize(); s++) {
474                 const XMLCh* n=kilist->item(s)->getKeyName();
475                 if (n)
476                     names.push_back(n);
477             }
478         }
479         names.push_back(role->getEntityDescriptor()->getId());
480         const IEntitiesDescriptor* group=role->getEntityDescriptor()->getEntitiesDescriptor();
481         while (group) {
482             names.push_back(group->getName());
483             group=group->getEntitiesDescriptor();
484         }
485     
486         // Now check each name.
487         XMLTrustImpl::KeyAuthority* kauth=NULL;
488         for (vector<const XMLCh*>::const_iterator name=names.begin(); !kauth && name!=names.end(); name++) {
489 #ifdef HAVE_GOOD_STL
490             XMLTrustImpl::AuthMap::const_iterator c=impl->m_authMap.find(*name);
491             if (c!=impl->m_authMap.end()) {
492                 kauth=c->second;
493                 if (log.isInfoEnabled()) {
494                     auto_ptr_char temp(*name);
495                     log.info("KeyAuthority match on %s",temp.get());
496                 }
497             }
498 #else
499             // Without a decent STL, we trade-off the transcoding by doing a linear search.
500             for (vector<XMLTrustImpl::KeyAuthority*>::const_iterator keyauths=impl->m_keyauths.begin(); !kauth && keyauths!=impl->m_keyauths.end(); keyauths++) {
501                 for (vector<const XMLCh*>::const_iterator subs=(*keyauths)->m_subjects.begin(); !kauth && subs!=(*keyauths)->m_subjects.end(); subs++) {
502                     if (!XMLString::compareString(*name,*subs)) {
503                         kauth=*keyauths;
504                         if (log.isInfoEnabled()) {
505                             auto_ptr_char temp(*name);
506                             log.info("KeyAuthority match on %s",temp.get());
507                         }
508                     }
509                 }
510             }
511 #endif
512         }
513     
514         if (!kauth) {
515             if (impl->m_wildcard) {
516                log.warn("applying wildcard KeyAuthority, use with caution!");
517                 kauth=impl->m_wildcard;
518             }
519             else {
520                 unlock();
521                 log.warn("no KeyAuthority found to validate SSL connection, leaving it alone");
522                 return false;
523             }
524         }
525     
526         log.debug("performing certificate path validation...");
527
528         // If we have a match, use the associated keyauth.
529         X509_STORE* store=kauth->getX509Store();
530         if (store) {
531             STACK_OF(X509)* untrusted=sk_X509_new(NULL);
532             certChain.reset();
533             while (certChain.hasNext())
534                 sk_X509_push(untrusted,(X509*)certChain.next());
535
536             // This contains the state of the validate operation.
537             X509_STORE_CTX ctx;
538
539             // AFAICT, EE and untrusted are passed in but not owned by the ctx.
540 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
541             if (X509_STORE_CTX_init(&ctx,store,(X509*)certEE,untrusted)!=1) {
542                 log_openssl();
543                 log.error("unable to initialize X509_STORE_CTX");
544                 X509_STORE_free(store);
545                 sk_X509_free(untrusted);
546                 unlock();
547                 return false;
548             }
549 #else
550             X509_STORE_CTX_init(&ctx,store,certEE,untrusted);
551 #endif
552             X509_STORE_CTX_set_depth(&ctx,kauth->m_depth+1);    // correct yet another OpenSSL/PXIX bug
553             X509_STORE_CTX_set_verify_cb(&ctx,error_callback);
554             
555             int ret=X509_verify_cert(&ctx);
556             
557             // Clean up...
558             X509_STORE_CTX_cleanup(&ctx);
559             X509_STORE_free(store);
560
561             if (ret==1) {
562                 log.info("successfully validated certificate chain");
563                 unlock();
564                 return true;
565             }
566         }
567     }
568     catch (...) {
569         unlock();
570         throw;
571     }
572     unlock();
573     return false;
574 }
575
576 bool XMLTrust::validate(const saml::SAMLSignedObject& token, const IRoleDescriptor* role)
577 {
578     // The delegated trust plugin handles metadata keys and use of metadata extensions.
579     // If it fails to find an inline key in metadata, then it will branch off to the
580     // extended version and verify the token using the certificates inside it. At that
581     // point, control will pass to the other virtual function above and we can handle
582     // legacy KeyAuthority rules that way.
583     if (m_delegate->validate(token,role))
584         return true;
585
586 #ifdef _DEBUG
587     saml::NDC ndc("validate");
588 #endif
589     Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Trust");
590
591     lock();
592     try {
593         XMLTrustImpl* impl=dynamic_cast<XMLTrustImpl*>(getImplementation());
594
595         // If we actually make it this far, the only case we're handling directly
596         // is an inline key in the old trust file format. Build a list of key names
597         // which will be used to find matching rules.
598         vector<const XMLCh*> names;
599         
600         // Build a list of acceptable names. Transcode the possible key "names" to UTF-8.
601         // For some simple cases, this should handle UTF-8 encoded DNs in certificates.
602         Iterator<const IKeyDescriptor*> kd_i=role->getKeyDescriptors();
603         while (kd_i.hasNext()) {
604             const IKeyDescriptor* kd=kd_i.next();
605             if (kd->getUse()!=IKeyDescriptor::signing)
606                 continue;
607             DSIGKeyInfoList* KIL=kd->getKeyInfo();
608             if (!KIL)
609                 continue;
610             for (size_t s=0; s<KIL->getSize(); s++) {
611                 const XMLCh* n=KIL->item(s)->getKeyName();
612                 if (n)
613                     names.push_back(n);
614             }
615         }
616         names.push_back(role->getEntityDescriptor()->getId());
617
618         log.debug("checking for keys in trust file");
619         DSIGKeyInfoList* KIL=NULL;
620         for (vector<const XMLCh*>::const_iterator name=names.begin(); !KIL && name!=names.end(); name++) {
621 #ifdef HAVE_GOOD_STL
622             XMLTrustImpl::BindMap::const_iterator c=impl->m_bindMap.find(*name);
623             if (c!=impl->m_bindMap.end()) {
624                 KIL=c->second;
625                 if (log.isInfoEnabled()) {
626                     auto_ptr_char temp(*name);
627                     log.info("KeyInfo match on %s",temp.get());
628                 }
629             }
630 #else
631             // Without a decent STL, we trade-off the transcoding by doing a linear search.
632             for (vector<DSIGKeyInfoList*>::const_iterator keybinds=impl->m_keybinds.begin(); !KIL && keybinds!=impl->m_keybinds.end(); keybinds++) {
633                 for (size_t s=0; !KIL && s<(*keybinds)->getSize(); s++) {
634                     if (!XMLString::compareString(*name,(*keybinds)->item(s)->getKeyName())) {
635                         KIL=*keybinds;
636                         if (log.isInfoEnabled()) {
637                             auto_ptr_char temp(*name);
638                             log.info("KeyInfo match on %s",temp.get());
639                         }
640                     }
641                 }
642             }
643 #endif
644         }
645         
646         if (KIL) {
647             // Any inline KeyInfo should ostensibly resolve to a key we can try.
648             Iterator<KeyInfoResolver*> resolvers(m_resolvers);
649             while (resolvers.hasNext()) {
650                 XSECCryptoKey* key=((XSECKeyInfoResolver*)*resolvers.next())->resolveKey(KIL);
651                 if (key) {
652                     log.debug("resolved key, trying it...");
653                     try {
654                         token.verify(key);
655                         unlock();
656                         log.info("token verified with KeyInfo, nothing more to verify");
657                         return true;
658                     }
659                     catch (SAMLException& e) {
660                         unlock();
661                         log.warn("verification with inline key failed: %s", e.what());
662                         return false;
663                     }
664                 }
665             }
666             log.warn("KeyInfo in trust provider did not resolve to a key");
667         }
668     }
669     catch (...) {
670         unlock();
671         throw;
672     }       
673
674     unlock();
675     return false;
676 }