c588a42c57806707d8c6cfe286e3ddaa9be43bef
[shibboleth/cpp-sp.git] / shib / BasicTrust.cpp
1 /*
2  *  Copyright 2001-2005 Internet2
3  * 
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 /* BasicTrust.cpp - a trust implementation that relies solely on standard SAML metadata
18
19    Scott Cantor
20    4/9/05
21
22    $History:$
23 */
24
25 #include "internal.h"
26
27 #include <openssl/x509.h>
28 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyDSA.hpp>
29 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>
30 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
31
32 using namespace shibboleth::logging;
33 using namespace shibboleth;
34 using namespace saml;
35 using namespace std;
36
37 IPlugIn* BasicTrustFactory(const DOMElement* e)
38 {
39     return new BasicTrust(e);
40 }
41
42 static const XMLCh resolver[] =
43 { chLatin_K, chLatin_e, chLatin_y, chLatin_I, chLatin_n, chLatin_f, chLatin_o,
44   chLatin_R, chLatin_e, chLatin_s, chLatin_o, chLatin_l, chLatin_v, chLatin_e, chLatin_r, chNull
45 };
46 static const XMLCh type[] =
47 { chLatin_t, chLatin_y, chLatin_p, chLatin_e, chNull };
48
49 static const XMLCh debug[] =
50 { chLatin_d, chLatin_e, chLatin_b, chLatin_u, chLatin_g, chNull };
51
52 BasicTrust::BasicTrust(const DOMElement* e) : m_debug(false)
53 {
54     // Debug mode?
55     const XMLCh* flag=e->getAttributeNS(NULL,debug);
56     if (flag && (*flag==chLatin_t || *flag==chDigit_1))
57         m_debug=true;
58     
59     // Find any KeyResolver plugins.
60     e=saml::XML::getFirstChildElement(e);
61     while (e) {
62         if (!XMLString::compareString(resolver,e->getLocalName()) && e->hasAttributeNS(NULL,type)) {
63             try {
64                 auto_ptr_char temp(e->getAttributeNS(NULL,type));
65                 m_resolvers.push_back(KeyInfoResolver::getInstance(temp.get(),e));
66             }
67             catch (SAMLException& ex) {
68                 Category::getInstance(SHIB_LOGCAT".Trust.Basic").error(
69                     "caught SAML exception building KeyInfoResolver plugin: %s",ex.what()
70                     );
71             }
72 #ifndef _DEBUG
73             catch (...) {
74                 Category::getInstance(SHIB_LOGCAT".Trust.Basic").error("caught unknown exception building KeyInfoResolver plugin");
75             }
76 #endif
77         }
78         e=saml::XML::getNextSiblingElement(e);
79     }
80     m_resolvers.push_back(KeyInfoResolver::getInstance(e));
81 }
82
83 BasicTrust::~BasicTrust()
84 {
85     for (vector<KeyInfoResolver*>::iterator i=m_resolvers.begin(); i!=m_resolvers.end(); i++)
86         delete *i;
87 }
88
89 bool BasicTrust::validate(void* certEE, const Iterator<void*>& certChain, const IRoleDescriptor* role, bool checkName)
90 {
91 #ifdef _DEBUG
92     saml::NDC ndc("validate");
93 #endif
94     Category& log=Category::getInstance(SHIB_LOGCAT".Trust.Basic");
95
96     if (!certEE) {
97         log.error("no certificate provided for comparison");
98         return false;
99     }
100
101     if (m_debug) {
102         log.warn("running in debug mode, we accept anything!");
103         return true;
104     }
105
106     // The new "basic" trust implementation relies solely on certificates living within the
107     // role interface to verify the EE certificate.
108
109     log.debug("comparing key inside certificate to KeyDescriptors");
110     Iterator<const IKeyDescriptor*> kd_i=role->getKeyDescriptors();
111     while (kd_i.hasNext()) {
112         const IKeyDescriptor* kd=kd_i.next();
113         if (kd->getUse()==IKeyDescriptor::encryption)
114             continue;
115         DSIGKeyInfoList* KIL=kd->getKeyInfo();
116         if (!KIL)
117             continue;
118         Iterator<KeyInfoResolver*> resolvers(m_resolvers);
119         while (resolvers.hasNext()) {
120             XSECCryptoKey* key=((XSECKeyInfoResolver*)*resolvers.next())->resolveKey(KIL);
121             if (key) {
122                 log.debug("KeyDescriptor resolved into a key, comparing it...");
123                 if (key->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) {
124                     log.error("only the OpenSSL XSEC provider is supported");
125                     continue;
126                 }
127
128                 switch (key->getKeyType()) {
129                     case XSECCryptoKey::KEY_RSA_PUBLIC:
130                     case XSECCryptoKey::KEY_RSA_PAIR:
131                     {
132                         RSA* rsa = static_cast<OpenSSLCryptoKeyRSA*>(key)->getOpenSSLRSA();
133                         EVP_PKEY* evp = X509_PUBKEY_get(X509_get_X509_PUBKEY(reinterpret_cast<X509*>(certEE)));
134                         if (rsa && evp && evp->type == EVP_PKEY_RSA &&
135                                 BN_cmp(rsa->n,evp->pkey.rsa->n) == 0 && BN_cmp(rsa->e,evp->pkey.rsa->e) == 0) {
136                             if (evp)
137                                 EVP_PKEY_free(evp);
138                             log.debug("matching key found in KeyDescriptor");
139                             return true;
140                         }
141                         if (evp)
142                             EVP_PKEY_free(evp);
143                         break;
144                     }
145                 
146                     case XSECCryptoKey::KEY_DSA_PUBLIC:
147                     case XSECCryptoKey::KEY_DSA_PAIR:
148                     {
149                         DSA* dsa = static_cast<OpenSSLCryptoKeyDSA*>(key)->getOpenSSLDSA();
150                         EVP_PKEY* evp = X509_PUBKEY_get(X509_get_X509_PUBKEY(reinterpret_cast<X509*>(certEE)));
151                         if (dsa && evp && evp->type == EVP_PKEY_DSA && BN_cmp(dsa->pub_key,evp->pkey.dsa->pub_key) == 0) {
152                             if (evp)
153                                 EVP_PKEY_free(evp);
154                             log.debug("matching key found in KeyDescriptor");
155                             return true;
156                         }
157                         if (evp)
158                             EVP_PKEY_free(evp);
159                         break;
160                     }
161
162                     default:
163                         log.warn("unknown key type in KeyDescriptor, skipping...");
164                 }
165             }
166         }
167     }
168     
169     log.debug("failed to find a matching key for certificate in KeyDescriptors");
170     return false;
171 }
172
173 bool BasicTrust::validate(const saml::SAMLSignedObject& token, const IRoleDescriptor* role, ITrust* certValidator)
174 {
175 #ifdef _DEBUG
176     saml::NDC ndc("validate");
177 #endif
178     Category& log=Category::getInstance(SHIB_LOGCAT".Trust.Basic");
179
180     if (m_debug) {
181         log.warn("running in debug mode, we accept anything!");
182         return true;
183     }
184
185     // The new "basic" trust implementation relies solely on keys living within the
186     // role interface to verify the token. No indirection of any sort is allowed,
187     // unless an alternate key resolver is involved.
188  
189     log.debug("validating signature with KeyDescriptors");
190     Iterator<const IKeyDescriptor*> kd_i=role->getKeyDescriptors();
191     while (kd_i.hasNext()) {
192         const IKeyDescriptor* kd=kd_i.next();
193         if (kd->getUse()==IKeyDescriptor::encryption)
194             continue;
195         DSIGKeyInfoList* KIL=kd->getKeyInfo();
196         if (!KIL)
197             continue;
198         Iterator<KeyInfoResolver*> resolvers(m_resolvers);
199         while (resolvers.hasNext()) {
200             XSECCryptoKey* key=((XSECKeyInfoResolver*)*resolvers.next())->resolveKey(KIL);
201             if (key) {
202                 log.debug("KeyDescriptor resolved into a key, trying it...");
203                 try {
204                     token.verify(key);
205                     log.info("signature verified with KeyDescriptor");
206                     return true;
207                 }
208                 catch (SAMLException& e) {
209                     log.debug("verification with KeyDescriptor failed: %s", e.what());
210                 }
211             }
212         }
213     }
214     
215     log.debug("failed to validate signature with KeyDescriptors");
216     return false;
217 }