Update copyright.
[shibboleth/cpp-xmltooling.git] / xmltooling / security / impl / ExplicitKeyTrustEngine.cpp
1 /*
2  *  Copyright 2001-2007 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  * ExplicitKeyTrustEngine.cpp
19  * 
20  * TrustEngine based on explicit knowledge of peer key information.
21  */
22
23 #include "internal.h"
24 #include "security/OpenSSLTrustEngine.h"
25 #include "signature/SignatureValidator.h"
26 #include "util/NDC.h"
27
28 #include <log4cpp/Category.hh>
29 #include <xercesc/util/XMLUniDefs.hpp>
30 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyDSA.hpp>
31 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>
32 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
33
34 using namespace xmlsignature;
35 using namespace xmltooling;
36 using namespace log4cpp;
37 using namespace std;
38
39 namespace xmltooling {
40     class XMLTOOL_DLLLOCAL ExplicitKeyTrustEngine : public OpenSSLTrustEngine
41     {
42     public:
43         ExplicitKeyTrustEngine(const DOMElement* e) : OpenSSLTrustEngine(e) {}
44         virtual ~ExplicitKeyTrustEngine() {}
45
46         virtual bool validate(
47             Signature& sig,
48             const KeyInfoSource& keyInfoSource,
49             const KeyResolver* keyResolver=NULL
50             ) const;
51         virtual bool validate(
52             const XMLCh* sigAlgorithm,
53             const char* sig,
54             KeyInfo* keyInfo,
55             const char* in,
56             unsigned int in_len,
57             const KeyInfoSource& keyInfoSource,
58             const KeyResolver* keyResolver=NULL
59             ) const;
60         virtual bool validate(
61             XSECCryptoX509* certEE,
62             const vector<XSECCryptoX509*>& certChain,
63             const KeyInfoSource& keyInfoSource,
64             bool checkName=true,
65             const KeyResolver* keyResolver=NULL
66             ) const;
67         virtual bool validate(
68             X509* certEE,
69             STACK_OF(X509)* certChain,
70             const KeyInfoSource& keyInfoSource,
71             bool checkName=true,
72             const KeyResolver* keyResolver=NULL
73             ) const;
74     };
75
76     TrustEngine* XMLTOOL_DLLLOCAL ExplicitKeyTrustEngineFactory(const DOMElement* const & e)
77     {
78         return new ExplicitKeyTrustEngine(e);
79     }
80 };
81
82 bool ExplicitKeyTrustEngine::validate(
83     Signature& sig,
84     const KeyInfoSource& keyInfoSource,
85     const KeyResolver* keyResolver
86     ) const
87 {
88 #ifdef _DEBUG
89     NDC ndc("validate");
90 #endif
91     Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine");
92     
93     auto_ptr<KeyInfoIterator> keyInfoIter(keyInfoSource.getKeyInfoIterator());
94     if (!keyInfoIter->hasNext()) {
95         log.warn("unable to validate signature, no key information available for peer");
96         return false;
97     }
98     
99     log.debug("attempting to validate signature with the key information for peer");
100     SignatureValidator sigValidator;
101     while (keyInfoIter->hasNext()) {
102         XSECCryptoKey* key = (keyResolver ? keyResolver : m_keyResolver)->resolveKey(keyInfoIter->next());
103         if (key) {
104             log.debug("attempting to validate signature with public key...");
105             try {
106                 sigValidator.setKey(key);   // key now owned by validator
107                 sigValidator.validate(&sig);
108                 log.info("signature validated with public key");
109                 return true;
110             }
111             catch (ValidationException& e) {
112                 if (log.isDebugEnabled()) {
113                     log.debug("public key did not validate signature: %s", e.what());
114                 }
115             }
116         }
117         else {
118             log.debug("key information does not resolve to a public key, skipping it");
119         }
120     }
121
122     log.error("no peer key information validated the signature");
123     return false;
124 }
125
126 bool ExplicitKeyTrustEngine::validate(
127     const XMLCh* sigAlgorithm,
128     const char* sig,
129     KeyInfo* keyInfo,
130     const char* in,
131     unsigned int in_len,
132     const KeyInfoSource& keyInfoSource,
133     const KeyResolver* keyResolver
134     ) const
135 {
136 #ifdef _DEBUG
137     NDC ndc("validate");
138 #endif
139     Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine");
140     
141     auto_ptr<KeyInfoIterator> keyInfoIter(keyInfoSource.getKeyInfoIterator());
142     if (!keyInfoIter->hasNext()) {
143         log.warn("unable to validate signature, no key information available for peer");
144         return false;
145     }
146     
147     log.debug("attempting to validate signature with the key information for peer");
148     while (keyInfoIter->hasNext()) {
149         auto_ptr<XSECCryptoKey> key((keyResolver ? keyResolver : m_keyResolver)->resolveKey(keyInfoIter->next()));
150         if (key.get()) {
151             log.debug("attempting to validate signature with public key...");
152             try {
153                 if (Signature::verifyRawSignature(key.get(), sigAlgorithm, sig, in, in_len)) {
154                     log.info("signature validated with public key");
155                     return true;
156                 }
157             }
158             catch (SignatureException& e) {
159                 if (log.isDebugEnabled()) {
160                     log.debug("public key did not validate signature: %s", e.what());
161                 }
162             }
163         }
164         else {
165             log.debug("key information does not resolve to a public key, skipping it");
166         }
167     }
168
169     log.error("no peer key information validated the signature");
170     return false;
171 }
172
173 bool ExplicitKeyTrustEngine::validate(
174     XSECCryptoX509* certEE,
175     const vector<XSECCryptoX509*>& certChain,
176     const KeyInfoSource& keyInfoSource,
177     bool checkName,
178     const KeyResolver* keyResolver
179     ) const
180 {
181     if (!certEE) {
182 #ifdef _DEBUG
183         NDC ndc("validate");
184 #endif
185         Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine").error("unable to validate, end-entity certificate was null");
186         return false;
187     }
188     else if (certEE->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) {
189 #ifdef _DEBUG
190         NDC ndc("validate");
191 #endif
192         Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine").error("only the OpenSSL XSEC provider is supported");
193         return false;
194     }
195
196     return validate(static_cast<OpenSSLCryptoX509*>(certEE)->getOpenSSLX509(), NULL, keyInfoSource, checkName, keyResolver);
197 }
198
199 bool ExplicitKeyTrustEngine::validate(
200     X509* certEE,
201     STACK_OF(X509)* certChain,
202     const KeyInfoSource& keyInfoSource,
203     bool checkName,
204     const KeyResolver* keyResolver
205     ) const
206 {
207 #ifdef _DEBUG
208     NDC ndc("validate");
209 #endif
210     Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine");
211     
212     if (!certEE) {
213         log.error("unable to validate, end-entity certificate was null");
214         return false;
215     }
216
217     auto_ptr<KeyInfoIterator> keyInfoIter(keyInfoSource.getKeyInfoIterator());
218     if (!keyInfoIter->hasNext()) {
219         log.warn("unable to validate, no key information available for peer");
220         return false;
221     }
222
223     // The "explicit" trust implementation relies solely on keys living within the
224     // peer interface to verify the EE certificate.
225
226     log.debug("attempting to match key information from peer with end-entity certificate");
227     while (keyInfoIter->hasNext()) {
228         auto_ptr<XSECCryptoKey> key((keyResolver ? keyResolver : m_keyResolver)->resolveKey(keyInfoIter->next()));
229         if (key.get()) {
230             log.debug("checking if peer key matches end-entity certificate");
231             if (key->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) {
232                 log.error("only the OpenSSL XSEC provider is supported");
233                 continue;
234             }
235             switch (key->getKeyType()) {
236                 case XSECCryptoKey::KEY_RSA_PUBLIC:
237                 {
238                     RSA* rsa = static_cast<OpenSSLCryptoKeyRSA*>(key.get())->getOpenSSLRSA();
239                     EVP_PKEY* evp = certEE->cert_info->key->pkey;
240                     if (rsa && evp && evp->type == EVP_PKEY_RSA &&
241                             BN_cmp(rsa->n,evp->pkey.rsa->n) == 0 && BN_cmp(rsa->e,evp->pkey.rsa->e) != 0) {
242                         log.info("end-entity certificate matches peer RSA key information");
243                         return true;
244                     }
245                     break;
246                 }
247                 
248                 case XSECCryptoKey::KEY_DSA_PUBLIC:
249                 {
250                     DSA* dsa = static_cast<OpenSSLCryptoKeyDSA*>(key.get())->getOpenSSLDSA();
251                     EVP_PKEY* evp = certEE->cert_info->key->pkey;
252                     if (dsa && evp && evp->type == EVP_PKEY_DSA && BN_cmp(dsa->pub_key,evp->pkey.dsa->pub_key) == 0) {
253                         log.info("end-entity certificate matches peer DSA key information");
254                         return true;
255                     }
256                     break;
257                 }
258
259                 default:
260                     log.warn("unknown peer key type, skipping...");
261             }
262         }
263         else {
264             log.debug("key information does not resolve to a public key, skipping it");
265         }
266     }
267
268     log.debug("no keys within this peer's key information matched the given end-entity certificate");
269     return false;
270 }