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