1 /**
2  * Licensed to the University Corporation for Advanced Internet
3  * Development, Inc. (UCAID) under one or more contributor license
4  * agreements. See the NOTICE file distributed with this work for
5  * additional information regarding copyright ownership.
6  *
7  * UCAID licenses this file to you under the Apache License,
8  * Version 2.0 (the "License"); you may not use this file except
9  * in compliance with the License. You may obtain a copy of the
10  * License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17  * either express or implied. See the License for the specific
18  * language governing permissions and limitations under the License.
19  */
20 
21 /**
22  * ExplicitKeyTrustEngine.cpp
23  *
24  * TrustEngine based on explicit knowledge of peer key information.
25  */
26 
27 #include "internal.h"
28 #include "logging.h"
29 #include "security/Credential.h"
30 #include "security/CredentialCriteria.h"
31 #include "security/CredentialResolver.h"
32 #include "security/OpenSSLTrustEngine.h"
33 #include "security/SignatureTrustEngine.h"
34 #include "signature/Signature.h"
35 #include "signature/SignatureValidator.h"
36 #include "util/NDC.h"
37 #include "security/impl/OpenSSLSupport.h"
38 
39 #include <xercesc/util/XMLUniDefs.hpp>
40 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyDSA.hpp>
41 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>
42 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
43 
44 #include "security/OpenSSLSecurityHelper.h"
45 #ifdef XSEC_OPENSSL_HAVE_EC
46 # include <openssl/ec.h>
47 #endif
48 
49 using namespace xmlsignature;
50 using namespace xmltooling::logging;
51 using namespace xmltooling;
52 using namespace std;
53 
54 
55 using xercesc::DOMElement;
56 
57 namespace xmltooling {
58     class XMLTOOL_DLLLOCAL ExplicitKeyTrustEngine : public SignatureTrustEngine, public OpenSSLTrustEngine
59     {
60     public:
ExplicitKeyTrustEngine(const DOMElement * e)61         ExplicitKeyTrustEngine(const DOMElement* e) : TrustEngine(e) {}
~ExplicitKeyTrustEngine()62         virtual ~ExplicitKeyTrustEngine() {}
63 
64         virtual bool validate(
65             Signature& sig,
66             const CredentialResolver& credResolver,
67             CredentialCriteria* criteria=nullptr
68             ) const;
69         virtual bool validate(
70             const XMLCh* sigAlgorithm,
71             const char* sig,
72             KeyInfo* keyInfo,
73             const char* in,
74             unsigned int in_len,
75             const CredentialResolver& credResolver,
76             CredentialCriteria* criteria=nullptr
77             ) const;
78         virtual bool validate(
79             XSECCryptoX509* certEE,
80             const vector<XSECCryptoX509*>& certChain,
81             const CredentialResolver& credResolver,
82             CredentialCriteria* criteria=nullptr
83             ) const;
84         virtual bool validate(
85             X509* certEE,
86             STACK_OF(X509)* certChain,
87             const CredentialResolver& credResolver,
88             CredentialCriteria* criteria=nullptr
89             ) const;
90     };
91 
ExplicitKeyTrustEngineFactory(const DOMElement * const & e,bool deprecationSupport)92     TrustEngine* XMLTOOL_DLLLOCAL ExplicitKeyTrustEngineFactory(const DOMElement* const & e, bool deprecationSupport)
93     {
94         return new ExplicitKeyTrustEngine(e);
95     }
96 };
97 
validate(Signature & sig,const CredentialResolver & credResolver,CredentialCriteria * criteria) const98 bool ExplicitKeyTrustEngine::validate(
99     Signature& sig,
100     const CredentialResolver& credResolver,
101     CredentialCriteria* criteria
102     ) const
103 {
104 #ifdef _DEBUG
105     NDC ndc("validate");
106 #endif
107     Category& log=Category::getInstance(XMLTOOLING_LOGCAT ".TrustEngine." EXPLICIT_KEY_TRUSTENGINE);
108 
109     vector<const Credential*> credentials;
110     if (criteria) {
111         criteria->setUsage(Credential::SIGNING_CREDENTIAL);
112         criteria->setSignature(sig, CredentialCriteria::KEYINFO_EXTRACTION_KEY);
113         credResolver.resolve(credentials,criteria);
114     }
115     else {
116         CredentialCriteria cc;
117         cc.setUsage(Credential::SIGNING_CREDENTIAL);
118         cc.setSignature(sig, CredentialCriteria::KEYINFO_EXTRACTION_KEY);
119         credResolver.resolve(credentials,&cc);
120     }
121     if (credentials.empty()) {
122         log.debug("unable to validate signature, no credentials available from peer");
123         return false;
124     }
125 
126     log.debug("attempting to validate signature with the peer's credentials");
127     SignatureValidator sigValidator;
128     for (vector<const Credential*>::const_iterator c=credentials.begin(); c!=credentials.end(); ++c) {
129         sigValidator.setCredential(*c);
130         try {
131             sigValidator.validate(&sig);
132             log.debug("signature validated with credential");
133             return true;
134         }
135         catch (ValidationException& e) {
136             log.debug("public key did not validate signature: %s", e.what());
137         }
138     }
139 
140     log.debug("no peer credentials validated the signature");
141     return false;
142 }
143 
validate(const XMLCh * sigAlgorithm,const char * sig,KeyInfo * keyInfo,const char * in,unsigned int in_len,const CredentialResolver & credResolver,CredentialCriteria * criteria) const144 bool ExplicitKeyTrustEngine::validate(
145     const XMLCh* sigAlgorithm,
146     const char* sig,
147     KeyInfo* keyInfo,
148     const char* in,
149     unsigned int in_len,
150     const CredentialResolver& credResolver,
151     CredentialCriteria* criteria
152     ) const
153 {
154 #ifdef _DEBUG
155     NDC ndc("validate");
156 #endif
157     Category& log=Category::getInstance(XMLTOOLING_LOGCAT ".TrustEngine." EXPLICIT_KEY_TRUSTENGINE);
158 
159     vector<const Credential*> credentials;
160     if (criteria) {
161         criteria->setUsage(Credential::SIGNING_CREDENTIAL);
162         criteria->setKeyInfo(keyInfo, CredentialCriteria::KEYINFO_EXTRACTION_KEY);
163         criteria->setXMLAlgorithm(sigAlgorithm);
164         credResolver.resolve(credentials,criteria);
165     }
166     else {
167         CredentialCriteria cc;
168         cc.setUsage(Credential::SIGNING_CREDENTIAL);
169         cc.setKeyInfo(keyInfo, CredentialCriteria::KEYINFO_EXTRACTION_KEY);
170         cc.setXMLAlgorithm(sigAlgorithm);
171         credResolver.resolve(credentials,&cc);
172     }
173     if (credentials.empty()) {
174         log.debug("unable to validate signature, no credentials available from peer");
175         return false;
176     }
177 
178     log.debug("attempting to validate signature with the peer's credentials");
179     for (vector<const Credential*>::const_iterator c=credentials.begin(); c!=credentials.end(); ++c) {
180         if ((*c)->getPublicKey()) {
181             try {
182                 if (Signature::verifyRawSignature((*c)->getPublicKey(), sigAlgorithm, sig, in, in_len)) {
183                     log.debug("signature validated with public key");
184                     return true;
185                 }
186             }
187             catch (SignatureException& e) {
188                 if (log.isDebugEnabled()) {
189                     log.debug("public key did not validate signature: %s", e.what());
190                 }
191             }
192         }
193     }
194 
195     log.debug("no peer credentials validated the signature");
196     return false;
197 }
198 
validate(XSECCryptoX509 * certEE,const vector<XSECCryptoX509 * > & certChain,const CredentialResolver & credResolver,CredentialCriteria * criteria) const199 bool ExplicitKeyTrustEngine::validate(
200     XSECCryptoX509* certEE,
201     const vector<XSECCryptoX509*>& certChain,
202     const CredentialResolver& credResolver,
203     CredentialCriteria* criteria
204     ) const
205 {
206 #ifdef _DEBUG
207         NDC ndc("validate");
208 #endif
209     if (!certEE) {
210         Category::getInstance(XMLTOOLING_LOGCAT ".TrustEngine." EXPLICIT_KEY_TRUSTENGINE).error("unable to validate, end-entity certificate was null");
211         return false;
212     }
213     else if (certEE->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) {
214         Category::getInstance(XMLTOOLING_LOGCAT ".TrustEngine." EXPLICIT_KEY_TRUSTENGINE).error("only the OpenSSL XSEC provider is supported");
215         return false;
216     }
217 
218     return validate(static_cast<OpenSSLCryptoX509*>(certEE)->getOpenSSLX509(), nullptr, credResolver, criteria);
219 }
220 
validate(X509 * certEE,STACK_OF (X509)* certChain,const CredentialResolver & credResolver,CredentialCriteria * criteria) const221 bool ExplicitKeyTrustEngine::validate(
222     X509* certEE,
223     STACK_OF(X509)* certChain,
224     const CredentialResolver& credResolver,
225     CredentialCriteria* criteria
226     ) const
227 {
228 #ifdef _DEBUG
229     NDC ndc("validate");
230 #endif
231     Category& log=Category::getInstance(XMLTOOLING_LOGCAT ".TrustEngine." EXPLICIT_KEY_TRUSTENGINE);
232 
233     if (!certEE) {
234         log.error("unable to validate, end-entity certificate was null");
235         return false;
236     }
237 
238     vector<const Credential*> credentials;
239     if (criteria) {
240         if (criteria->getUsage()==Credential::UNSPECIFIED_CREDENTIAL)
241             criteria->setUsage(Credential::SIGNING_CREDENTIAL);
242         credResolver.resolve(credentials,criteria);
243     }
244     else {
245         CredentialCriteria cc;
246         cc.setUsage(Credential::SIGNING_CREDENTIAL);
247         credResolver.resolve(credentials,&cc);
248     }
249     if (credentials.empty()) {
250         log.debug("unable to validate certificate, no credentials available from peer");
251         return false;
252     }
253 
254     // The "explicit" trust implementation relies solely on keys living within the
255     // peer resolver to verify the EE certificate.
256 
257     log.debug("attempting to match credentials from peer with end-entity certificate");
258     bool found = false;
259     EVP_PKEY* evp = X509_PUBKEY_get(X509_get_X509_PUBKEY(certEE));
260     if (!evp)
261         return false;
262 
263     for (vector<const Credential*>::const_iterator c=credentials.begin(); c != credentials.end(); ++c) {
264         const XSECCryptoKey* key = (*c)->getPublicKey();
265         if (!key)
266             continue;
267         if (key->getProviderName() != DSIGConstants::s_unicodeStrPROVOpenSSL) {
268             log.error("only the OpenSSL XSEC provider is supported");
269             continue;
270         }
271 
272         if (EVP_PKEY_id(evp) == EVP_PKEY_RSA) {
273             found = OpenSSLSecurityHelper::matchesPublic(EVP_PKEY_get0_RSA(evp), *key);
274             if (found) {
275                 log.debug("end-entity certificate matches peer RSA key information");
276                 break;
277             }
278         }
279         else if (EVP_PKEY_id(evp) == EVP_PKEY_DSA) {
280             found = OpenSSLSecurityHelper::matchesPublic(EVP_PKEY_get0_DSA(evp), *key);
281             if (found) {
282                 log.debug("end-entity certificate matches peer RSA key information");
283                 break;
284             }
285         }
286 #ifdef XSEC_OPENSSL_HAVE_EC
287         else if (EVP_PKEY_id(evp) == EVP_PKEY_EC) {
288             found = OpenSSLSecurityHelper::matchesPublic(EVP_PKEY_get0_EC_KEY(evp), *key);
289             if (found) {
290                 log.debug("end-entity certificate matches peer EC key information");
291                 break;
292             }
293         }
294 #endif
295         else {
296             log.warn("unknown peer key type, skipping...");
297         }
298     }
299     EVP_PKEY_free(evp);
300     if (!found)
301         log.debug("no keys within this peer's key information matched the given end-entity certificate");
302     return found;
303 }
304