2 * Copyright 2001-2010 Internet2
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 * Methods for decrypting XMLObjects and other data.
25 #include "encryption/Decrypter.h"
26 #include "encryption/EncryptedKeyResolver.h"
27 #include "encryption/Encryption.h"
28 #include "security/Credential.h"
29 #include "security/CredentialCriteria.h"
30 #include "security/CredentialResolver.h"
32 #include <xsec/enc/XSECCryptoException.hpp>
33 #include <xsec/framework/XSECException.hpp>
34 #include <xsec/framework/XSECAlgorithmMapper.hpp>
35 #include <xsec/framework/XSECAlgorithmHandler.hpp>
36 #include <xsec/utils/XSECBinTXFMInputStream.hpp>
37 #include <xsec/xenc/XENCCipher.hpp>
38 #include <xsec/xenc/XENCEncryptedData.hpp>
39 #include <xsec/xenc/XENCEncryptedKey.hpp>
41 using namespace xmlencryption;
42 using namespace xmlsignature;
43 using namespace xmltooling;
44 using namespace xercesc;
47 Decrypter::Decrypter(const CredentialResolver* credResolver, CredentialCriteria* criteria, const EncryptedKeyResolver* EKResolver)
48 : m_cipher(nullptr), m_credResolver(credResolver), m_criteria(criteria), m_EKResolver(EKResolver)
52 Decrypter::~Decrypter()
55 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
58 void Decrypter::setEncryptedKeyResolver(const EncryptedKeyResolver* EKResolver)
60 m_EKResolver=EKResolver;
63 void Decrypter::setKEKResolver(const CredentialResolver* resolver, CredentialCriteria* criteria)
65 m_credResolver=resolver;
69 DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, XSECCryptoKey* key)
71 if (encryptedData.getDOM()==nullptr)
72 throw DecryptionException("The object must be marshalled before decryption.");
74 // We can reuse the cipher object if the document hasn't changed.
76 if (m_cipher && m_cipher->getDocument()!=encryptedData.getDOM()->getOwnerDocument()) {
77 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
82 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedData.getDOM()->getOwnerDocument());
85 m_cipher->setKey(key->clone());
86 DOMNode* ret=m_cipher->decryptElementDetached(encryptedData.getDOM());
87 if (ret->getNodeType()!=DOMNode::DOCUMENT_FRAGMENT_NODE) {
89 throw DecryptionException("Decryption operation did not result in DocumentFragment.");
91 return static_cast<DOMDocumentFragment*>(ret);
93 catch(XSECException& e) {
94 auto_ptr_char temp(e.getMsg());
95 throw DecryptionException(string("XMLSecurity exception while decrypting: ") + temp.get());
97 catch(XSECCryptoException& e) {
98 throw DecryptionException(string("XMLSecurity exception while decrypting: ") + e.getMsg());
102 DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, const XMLCh* recipient)
105 throw DecryptionException("No CredentialResolver supplied to provide decryption keys.");
107 // Resolve a decryption key directly.
108 vector<const Credential*> creds;
109 int types = CredentialCriteria::KEYINFO_EXTRACTION_KEY | CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES;
111 m_criteria->setUsage(Credential::ENCRYPTION_CREDENTIAL);
112 m_criteria->setKeyInfo(encryptedData.getKeyInfo(), types);
113 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
115 m_criteria->setXMLAlgorithm(meth->getAlgorithm());
116 m_credResolver->resolve(creds,m_criteria);
119 CredentialCriteria criteria;
120 criteria.setUsage(Credential::ENCRYPTION_CREDENTIAL);
121 criteria.setKeyInfo(encryptedData.getKeyInfo(), types);
122 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
124 criteria.setXMLAlgorithm(meth->getAlgorithm());
125 m_credResolver->resolve(creds,&criteria);
128 // Loop over them and try each one.
130 for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
132 key = (*cred)->getPrivateKey();
135 return decryptData(encryptedData, key);
137 catch(DecryptionException& ex) {
138 logging::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what());
142 // We need to find an encrypted decryption key somewhere. We'll need the underlying algorithm...
143 const XMLCh* algorithm=
144 encryptedData.getEncryptionMethod() ? encryptedData.getEncryptionMethod()->getAlgorithm() : nullptr;
146 throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed.");
148 // Check for external resolver.
149 const EncryptedKey* encKey=nullptr;
151 encKey = m_EKResolver->resolveKey(encryptedData, recipient);
153 EncryptedKeyResolver ekr;
154 encKey = ekr.resolveKey(encryptedData, recipient);
158 throw DecryptionException("Unable to locate an encrypted key.");
160 auto_ptr<XSECCryptoKey> keywrapper(decryptKey(*encKey, algorithm));
161 if (!keywrapper.get())
162 throw DecryptionException("Unable to decrypt the encrypted key.");
163 return decryptData(encryptedData, keywrapper.get());
166 void Decrypter::decryptData(ostream& out, const EncryptedData& encryptedData, XSECCryptoKey* key)
168 if (encryptedData.getDOM()==nullptr)
169 throw DecryptionException("The object must be marshalled before decryption.");
171 // We can reuse the cipher object if the document hasn't changed.
173 if (m_cipher && m_cipher->getDocument()!=encryptedData.getDOM()->getOwnerDocument()) {
174 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
179 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedData.getDOM()->getOwnerDocument());
182 m_cipher->setKey(key->clone());
183 auto_ptr<XSECBinTXFMInputStream> in(m_cipher->decryptToBinInputStream(encryptedData.getDOM()));
186 xsecsize_t count = in->readBytes(buf, sizeof(buf));
188 out.write(reinterpret_cast<char*>(buf),count);
190 catch(XSECException& e) {
191 auto_ptr_char temp(e.getMsg());
192 throw DecryptionException(string("XMLSecurity exception while decrypting: ") + temp.get());
194 catch(XSECCryptoException& e) {
195 throw DecryptionException(string("XMLSecurity exception while decrypting: ") + e.getMsg());
199 void Decrypter::decryptData(ostream& out, const EncryptedData& encryptedData, const XMLCh* recipient)
202 throw DecryptionException("No CredentialResolver supplied to provide decryption keys.");
204 // Resolve a decryption key directly.
205 vector<const Credential*> creds;
206 int types = CredentialCriteria::KEYINFO_EXTRACTION_KEY | CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES;
208 m_criteria->setUsage(Credential::ENCRYPTION_CREDENTIAL);
209 m_criteria->setKeyInfo(encryptedData.getKeyInfo(), types);
210 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
212 m_criteria->setXMLAlgorithm(meth->getAlgorithm());
213 m_credResolver->resolve(creds,m_criteria);
216 CredentialCriteria criteria;
217 criteria.setUsage(Credential::ENCRYPTION_CREDENTIAL);
218 criteria.setKeyInfo(encryptedData.getKeyInfo(), types);
219 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
221 criteria.setXMLAlgorithm(meth->getAlgorithm());
222 m_credResolver->resolve(creds,&criteria);
225 // Loop over them and try each one.
227 for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
229 key = (*cred)->getPrivateKey();
232 return decryptData(out, encryptedData, key);
234 catch(DecryptionException& ex) {
235 logging::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what());
239 // We need to find an encrypted decryption key somewhere. We'll need the underlying algorithm...
240 const XMLCh* algorithm=
241 encryptedData.getEncryptionMethod() ? encryptedData.getEncryptionMethod()->getAlgorithm() : nullptr;
243 throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed.");
245 // Check for external resolver.
246 const EncryptedKey* encKey=nullptr;
248 encKey = m_EKResolver->resolveKey(encryptedData, recipient);
250 EncryptedKeyResolver ekr;
251 encKey = ekr.resolveKey(encryptedData, recipient);
255 throw DecryptionException("Unable to locate an encrypted key.");
257 auto_ptr<XSECCryptoKey> keywrapper(decryptKey(*encKey, algorithm));
258 if (!keywrapper.get())
259 throw DecryptionException("Unable to decrypt the encrypted key.");
260 decryptData(out, encryptedData, keywrapper.get());
263 XSECCryptoKey* Decrypter::decryptKey(const EncryptedKey& encryptedKey, const XMLCh* algorithm)
266 throw DecryptionException("No CredentialResolver supplied to provide decryption keys.");
268 if (encryptedKey.getDOM()==nullptr)
269 throw DecryptionException("The object must be marshalled before decryption.");
271 XSECAlgorithmHandler* handler;
273 handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithm);
275 throw DecryptionException("Unrecognized algorithm, no way to build object around decrypted key.");
277 catch(XSECException& e) {
278 auto_ptr_char temp(e.getMsg());
279 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + temp.get());
281 catch(XSECCryptoException& e) {
282 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + e.getMsg());
285 // We can reuse the cipher object if the document hasn't changed.
287 if (m_cipher && m_cipher->getDocument()!=encryptedKey.getDOM()->getOwnerDocument()) {
288 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
293 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedKey.getDOM()->getOwnerDocument());
295 // Resolve key decryption keys.
296 int types = CredentialCriteria::KEYINFO_EXTRACTION_KEY | CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES;
297 vector<const Credential*> creds;
299 m_criteria->setUsage(Credential::ENCRYPTION_CREDENTIAL);
300 m_criteria->setKeyInfo(encryptedKey.getKeyInfo(), types);
301 const EncryptionMethod* meth = encryptedKey.getEncryptionMethod();
303 m_criteria->setXMLAlgorithm(meth->getAlgorithm());
304 m_credResolver->resolve(creds, m_criteria);
307 CredentialCriteria criteria;
308 criteria.setUsage(Credential::ENCRYPTION_CREDENTIAL);
309 criteria.setKeyInfo(encryptedKey.getKeyInfo(), types);
310 const EncryptionMethod* meth = encryptedKey.getEncryptionMethod();
312 criteria.setXMLAlgorithm(meth->getAlgorithm());
313 m_credResolver->resolve(creds, &criteria);
316 throw DecryptionException("Unable to resolve any key decryption keys.");
318 XMLByte buffer[1024];
319 for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
321 if (!(*cred)->getPrivateKey())
322 throw DecryptionException("Credential did not contain a private key.");
323 memset(buffer,0,sizeof(buffer));
324 m_cipher->setKEK((*cred)->getPrivateKey()->clone());
327 int keySize = m_cipher->decryptKey(encryptedKey.getDOM(), buffer, 1024);
329 throw DecryptionException("Unable to decrypt key.");
331 // Try to wrap the key.
332 return handler->createKeyForURI(algorithm, buffer, keySize);
334 catch(XSECException& e) {
335 auto_ptr_char temp(e.getMsg());
336 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + temp.get());
338 catch(XSECCryptoException& e) {
339 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + e.getMsg());
342 catch(DecryptionException& ex) {
343 logging::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what());
347 throw DecryptionException("Unable to decrypt key.");