f448e9538ede94a17d0934cd6336b79c0cdffd2c
[shibboleth/sp.git] / shib / BasicTrust.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 /* BasicTrust.cpp - a trust implementation that relies solely on standard SAML metadata
51
52    Scott Cantor
53    4/9/05
54
55    $History:$
56 */
57
58 #include "internal.h"
59
60 #include <openssl/x509.h>
61 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
62
63 using namespace shibboleth;
64 using namespace saml;
65 using namespace log4cpp;
66 using namespace std;
67
68 IPlugIn* BasicTrustFactory(const DOMElement* e)
69 {
70     return new BasicTrust(e);
71 }
72
73 static const XMLCh resolver[] =
74 { chLatin_K, chLatin_e, chLatin_y, chLatin_I, chLatin_n, chLatin_f, chLatin_o,
75   chLatin_R, chLatin_e, chLatin_s, chLatin_o, chLatin_l, chLatin_v, chLatin_e, chLatin_r, chNull
76 };
77 static const XMLCh type[] =
78 { chLatin_t, chLatin_y, chLatin_p, chLatin_e, chNull };
79
80 BasicTrust::BasicTrust(const DOMElement* e)
81 {
82     // Find any KeyResolver plugins.
83     e=saml::XML::getFirstChildElement(e);
84     while (e) {
85         if (!XMLString::compareString(resolver,e->getLocalName()) && e->hasAttributeNS(NULL,type)) {
86             try {
87                 auto_ptr_char temp(e->getAttributeNS(NULL,type));
88                 m_resolvers.push_back(KeyInfoResolver::getInstance(temp.get(),e));
89             }
90             catch (SAMLException& ex) {
91                 Category::getInstance(SHIB_LOGCAT".Trust.Basic").error(
92                     "caught SAML exception building KeyInfoResolver plugin: %s",ex.what()
93                     );
94             }
95 #ifndef _DEBUG
96             catch (...) {
97                 Category::getInstance(SHIB_LOGCAT".Trust.Basic").error("caught unknown exception building KeyInfoResolver plugin");
98             }
99 #endif
100         }
101         e=saml::XML::getNextSiblingElement(e);
102     }
103     m_resolvers.push_back(KeyInfoResolver::getInstance(e));
104 }
105
106 BasicTrust::~BasicTrust()
107 {
108     for (vector<KeyInfoResolver*>::iterator i=m_resolvers.begin(); i!=m_resolvers.end(); i++)
109         delete *i;
110 }
111
112 bool BasicTrust::validate(void* certEE, const Iterator<void*>& certChain, const IRoleDescriptor* role, bool checkName)
113 {
114 #ifdef _DEBUG
115     saml::NDC ndc("validate");
116 #endif
117     Category& log=Category::getInstance(SHIB_LOGCAT".Trust.Basic");
118
119     if (!certEE) {
120         log.error("no certificate provided for comparison");
121         return false;
122     }
123
124     // The new "basic" trust implementation relies solely on certificates living within the
125     // role interface to verify the EE certificate.
126
127     log.debug("comparing certificate to KeyDescriptors");
128     Iterator<const IKeyDescriptor*> kd_i=role->getKeyDescriptors();
129     while (kd_i.hasNext()) {
130         const IKeyDescriptor* kd=kd_i.next();
131         if (kd->getUse()==IKeyDescriptor::encryption)
132             continue;
133         DSIGKeyInfoList* KIL=kd->getKeyInfo();
134         if (!KIL)
135             continue;
136         Iterator<KeyInfoResolver*> resolvers(m_resolvers);
137         while (resolvers.hasNext()) {
138             XSECCryptoX509* cert=resolvers.next()->resolveCert(KIL);
139             if (cert) {
140                 log.debug("KeyDescriptor resolved into a certificate, comparing it...");
141                 if (cert->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) {
142                     log.warn("only the OpenSSL XSEC provider is supported");
143                     continue;
144                 }
145                 else if (!X509_cmp(reinterpret_cast<X509*>(certEE),static_cast<OpenSSLCryptoX509*>(cert)->getOpenSSLX509())) {
146                     log.info("certificate match found in KeyDescriptor");
147                     return true;
148                 }
149                 else
150                     log.debug("certificate did not match");
151             }
152         }
153     }
154     
155     log.debug("failed to find an exact match for certificate in KeyDescriptors");
156     return false;
157 }
158
159 bool BasicTrust::validate(const saml::SAMLSignedObject& token, const IRoleDescriptor* role, ITrust* certValidator)
160 {
161 #ifdef _DEBUG
162     saml::NDC ndc("validate");
163 #endif
164     Category& log=Category::getInstance(SHIB_LOGCAT".Trust.Basic");
165
166     // The new "basic" trust implementation relies solely on keys living within the
167     // role interface to verify the token. No indirection of any sort is allowed,
168     // unless an alternate key resolver is involved.
169  
170     log.debug("validating signature with KeyDescriptors");
171     Iterator<const IKeyDescriptor*> kd_i=role->getKeyDescriptors();
172     while (kd_i.hasNext()) {
173         const IKeyDescriptor* kd=kd_i.next();
174         if (kd->getUse()!=IKeyDescriptor::signing)
175             continue;
176         DSIGKeyInfoList* KIL=kd->getKeyInfo();
177         if (!KIL)
178             continue;
179         Iterator<KeyInfoResolver*> resolvers(m_resolvers);
180         while (resolvers.hasNext()) {
181             XSECCryptoKey* key=((XSECKeyInfoResolver*)*resolvers.next())->resolveKey(KIL);
182             if (key) {
183                 log.debug("KeyDescriptor resolved into a key, trying it...");
184                 try {
185                     token.verify(key);
186                     log.info("signature verified with KeyDescriptor");
187                     return true;
188                 }
189                 catch (SAMLException& e) {
190                     log.debug("verification with KeyDescriptor failed: %s", e.what());
191                 }
192             }
193         }
194     }
195     
196     log.debug("failed to validate signature with KeyDescriptors");
197     return false;
198 }