PKIX trust engine using metadata exts.
[shibboleth/sp.git] / shibsp / PKIXTrustEngine.cpp
1 /*
2  *  Copyright 2001-2006 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 /**
18  * PKIXTrustEngine.cpp
19  * 
20  * Shibboleth-specific PKIX-validation TrustEngine
21  */
22
23 #include "internal.h"
24 #include "MetadataExt.h"
25 #include "PKIXTrustEngine.h"
26
27 #include <saml/saml2/metadata/Metadata.h>
28 #include <xmltooling/XMLToolingConfig.h>
29 #include <xmltooling/security/AbstractPKIXTrustEngine.h>
30
31 using namespace shibsp;
32 using namespace opensaml::saml2md;
33 using namespace xmlsignature;
34 using namespace xmltooling;
35 using namespace std;
36
37 namespace shibsp {
38     /**
39      * Adapter between shibmd:KeyAuthority extension and the PKIXValidationInfoIterator interface. 
40      */
41     class SHIBSP_API MetadataPKIXIterator : public AbstractPKIXTrustEngine::PKIXValidationInfoIterator
42     {
43         const XMLObject* m_obj;
44         const Extensions* m_extBlock;
45         const KeyAuthority* m_current;
46         vector<XMLObject*>::const_iterator m_iter;
47         
48         bool m_certsOwned;
49         vector<XSECCryptoX509*> m_certs;
50         vector<XSECCryptoX509CRL*> m_crls;
51         
52     public:
53         MetadataPKIXIterator(const RoleDescriptor& role, const KeyResolver& keyResolver)
54             : PKIXValidationInfoIterator(keyResolver), m_obj(role.getParent()), m_extBlock(NULL), m_current(NULL), m_certsOwned(false) {
55         }
56
57         virtual ~MetadataPKIXIterator() {
58             clear();
59         }
60
61         bool next();
62
63         int getVerificationDepth() const {
64             pair<bool,int> vd = m_current->getVerifyDepth();
65             return vd.first ? vd.second : 1;
66         }
67         
68         const vector<XSECCryptoX509*>& getTrustAnchors() const {
69             return m_certs;
70         }
71
72         const vector<XSECCryptoX509CRL*>& getCRLs() const {
73             return m_crls;
74         }
75     
76     private:
77         void populate();
78
79         void clear() {
80             if (m_certsOwned)
81                 for_each(m_certs.begin(), m_certs.end(), xmltooling::cleanup<XSECCryptoX509>());
82             m_certs.clear();
83             for_each(m_crls.begin(), m_crls.end(), xmltooling::cleanup<XSECCryptoX509CRL>());
84             m_crls.clear();
85         }
86     };
87
88     class SHIBSP_DLLLOCAL PKIXTrustEngine : public xmltooling::AbstractPKIXTrustEngine
89     {
90     public:
91         PKIXTrustEngine(const DOMElement* e=NULL) : AbstractPKIXTrustEngine(e) {}
92         virtual ~PKIXTrustEngine() {}
93         
94         xmltooling::AbstractPKIXTrustEngine::PKIXValidationInfoIterator* getPKIXValidationInfoIterator(
95             const xmltooling::KeyInfoSource& pkixSource, const xmlsignature::KeyResolver& keyResolver
96             ) const;
97     };
98     
99     SHIBSP_DLLLOCAL PluginManager<TrustEngine,const DOMElement*>::Factory PKIXTrustEngineFactory;
100
101     TrustEngine* SHIBSP_DLLLOCAL PKIXTrustEngineFactory(const DOMElement* const & e)\r
102     {\r
103         return new PKIXTrustEngine(e);\r
104     }\r
105 };
106
107 void shibsp::registerPKIXTrustEngine()
108 {
109     XMLToolingConfig::getConfig().TrustEngineManager.registerFactory(SHIBBOLETH_PKIX_TRUSTENGINE, PKIXTrustEngineFactory);
110 }
111
112 AbstractPKIXTrustEngine::PKIXValidationInfoIterator* PKIXTrustEngine::getPKIXValidationInfoIterator(
113     const KeyInfoSource& pkixSource, const KeyResolver& keyResolver
114     ) const
115 {
116     return new MetadataPKIXIterator(dynamic_cast<const RoleDescriptor&>(pkixSource),keyResolver);
117 }
118
119 bool MetadataPKIXIterator::next()
120 {
121     // If we had a KeyAuthority, look for another in the same block.
122     if (m_current) {
123         // Keep going until we hit the end of the Extensions.
124         vector<XMLObject*>::const_iterator end = m_extBlock->getUnknownXMLObjects().end();
125         while (++m_iter != end) {
126             // If we hit another KeyAuthority, remember it and signal.
127             if (m_current=dynamic_cast<KeyAuthority*>(*m_iter)) {
128                 populate();
129                 return true;
130             }
131         }
132
133         // If we get here, we hit the end of this Extensions block.
134         // Climb a level, if possible.
135         m_obj = m_extBlock->getParent()->getParent();
136         m_current = NULL;
137         m_extBlock = NULL;
138     }
139
140     // If we get here, we try and find an Extensions block.
141     if (m_obj) {
142         const EntityDescriptor* entity = dynamic_cast<const EntityDescriptor*>(m_obj);
143         if (entity) {
144             m_extBlock = entity->getExtensions();
145         }
146         else {
147             const EntitiesDescriptor* entities = dynamic_cast<const EntitiesDescriptor*>(m_obj);
148             if (entities) {
149                 m_extBlock = entities->getExtensions();
150             }
151             else {
152                 // Jump a level and try again.
153                 m_obj = m_obj->getParent();
154                 return next();
155             }
156         }
157     }
158
159     if (m_extBlock) {
160         // We're starting over at a new block.
161         const vector<XMLObject*>& exts = m_extBlock->getUnknownXMLObjects();
162         for (m_iter=exts.begin(); m_iter!=exts.end(); ++m_iter) {
163             // If we hit a KeyAuthority, remember it and signal.
164             if (m_current=dynamic_cast<KeyAuthority*>(*m_iter)) {
165                 populate();
166                 return true;
167             }
168         }
169
170         // Jump a level and try again.
171         m_obj = m_obj->getParent();
172         return next();
173     }
174     
175     return false;
176 }
177
178 void MetadataPKIXIterator::populate()
179 {
180     // Dump anything old.
181     clear();
182
183     // We have to aggregate the resolution results.
184     KeyResolver::ResolvedCertificates certs;
185     XSECCryptoX509CRL* crl;
186     const vector<KeyInfo*>& keyInfos = m_current->getKeyInfos();
187     for (vector<KeyInfo*>::const_iterator k = keyInfos.begin(); k!=keyInfos.end(); ++k) {
188         vector<XSECCryptoX509*>::size_type count = m_keyResolver.resolveCertificates(*k,certs); 
189         if (count > 0) {
190             // Transfer certificates out of wrapper. 
191             bool own = certs.release(m_certs);
192             if (!m_certs.empty() && own != m_certsOwned) {
193                 // Ugh. We have a mashup of "owned" and "unowned".
194                 // The ones we just added need to be removed and perhaps freed.
195                 do {
196                     if (own)
197                         delete m_certs.back();
198                     m_certs.pop_back();
199                 } while (--count > 0);
200             }
201             m_certsOwned = own;
202         }
203
204         crl = m_keyResolver.resolveCRL(*k);
205         if (crl)
206             m_crls.push_back(crl);
207     }
208 }