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.
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
24 * Methods for decrypting XMLObjects and other data.
29 #include "encryption/Decrypter.h"
30 #include "encryption/EncryptedKeyResolver.h"
31 #include "encryption/Encryption.h"
32 #include "security/Credential.h"
33 #include "security/CredentialCriteria.h"
34 #include "security/CredentialResolver.h"
36 #include <xsec/enc/XSECCryptoException.hpp>
37 #include <xsec/framework/XSECException.hpp>
38 #include <xsec/framework/XSECAlgorithmMapper.hpp>
39 #include <xsec/framework/XSECAlgorithmHandler.hpp>
40 #include <xsec/utils/XSECBinTXFMInputStream.hpp>
41 #include <xsec/xenc/XENCCipher.hpp>
42 #include <xsec/xenc/XENCEncryptedData.hpp>
43 #include <xsec/xenc/XENCEncryptedKey.hpp>
45 using namespace xmlencryption;
46 using namespace xmlsignature;
47 using namespace xmltooling;
48 using namespace xercesc;
51 Decrypter::Decrypter(const CredentialResolver* credResolver, CredentialCriteria* criteria, const EncryptedKeyResolver* EKResolver)
52 : m_cipher(nullptr), m_credResolver(credResolver), m_criteria(criteria), m_EKResolver(EKResolver)
56 Decrypter::~Decrypter()
59 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
62 void Decrypter::setEncryptedKeyResolver(const EncryptedKeyResolver* EKResolver)
64 m_EKResolver=EKResolver;
67 void Decrypter::setKEKResolver(const CredentialResolver* resolver, CredentialCriteria* criteria)
69 m_credResolver=resolver;
73 DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, XSECCryptoKey* key)
75 if (encryptedData.getDOM()==nullptr)
76 throw DecryptionException("The object must be marshalled before decryption.");
78 // We can reuse the cipher object if the document hasn't changed.
80 if (m_cipher && m_cipher->getDocument()!=encryptedData.getDOM()->getOwnerDocument()) {
81 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
86 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedData.getDOM()->getOwnerDocument());
89 m_cipher->setKey(key->clone());
90 DOMNode* ret=m_cipher->decryptElementDetached(encryptedData.getDOM());
91 if (ret->getNodeType()!=DOMNode::DOCUMENT_FRAGMENT_NODE) {
93 throw DecryptionException("Decryption operation did not result in DocumentFragment.");
95 return static_cast<DOMDocumentFragment*>(ret);
97 catch(XSECException& e) {
98 auto_ptr_char temp(e.getMsg());
99 throw DecryptionException(string("XMLSecurity exception while decrypting: ") + temp.get());
101 catch(XSECCryptoException& e) {
102 throw DecryptionException(string("XMLSecurity exception while decrypting: ") + e.getMsg());
106 DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, const XMLCh* recipient)
109 throw DecryptionException("No CredentialResolver supplied to provide decryption keys.");
111 // Resolve a decryption key directly.
112 vector<const Credential*> creds;
113 int types = CredentialCriteria::KEYINFO_EXTRACTION_KEY | CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES;
115 m_criteria->setUsage(Credential::ENCRYPTION_CREDENTIAL);
116 m_criteria->setKeyInfo(encryptedData.getKeyInfo(), types);
117 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
119 m_criteria->setXMLAlgorithm(meth->getAlgorithm());
120 m_credResolver->resolve(creds,m_criteria);
123 CredentialCriteria criteria;
124 criteria.setUsage(Credential::ENCRYPTION_CREDENTIAL);
125 criteria.setKeyInfo(encryptedData.getKeyInfo(), types);
126 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
128 criteria.setXMLAlgorithm(meth->getAlgorithm());
129 m_credResolver->resolve(creds,&criteria);
132 // Loop over them and try each one.
134 for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
136 key = (*cred)->getPrivateKey();
139 return decryptData(encryptedData, key);
141 catch(DecryptionException& ex) {
142 logging::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what());
146 // We need to find an encrypted decryption key somewhere. We'll need the underlying algorithm...
147 const XMLCh* algorithm=
148 encryptedData.getEncryptionMethod() ? encryptedData.getEncryptionMethod()->getAlgorithm() : nullptr;
150 throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed.");
152 // Check for external resolver.
153 const EncryptedKey* encKey=nullptr;
155 encKey = m_EKResolver->resolveKey(encryptedData, recipient);
157 EncryptedKeyResolver ekr;
158 encKey = ekr.resolveKey(encryptedData, recipient);
162 throw DecryptionException("Unable to locate an encrypted key.");
164 auto_ptr<XSECCryptoKey> keywrapper(decryptKey(*encKey, algorithm));
165 if (!keywrapper.get())
166 throw DecryptionException("Unable to decrypt the encrypted key.");
167 return decryptData(encryptedData, keywrapper.get());
170 void Decrypter::decryptData(ostream& out, const EncryptedData& encryptedData, XSECCryptoKey* key)
172 if (encryptedData.getDOM()==nullptr)
173 throw DecryptionException("The object must be marshalled before decryption.");
175 // We can reuse the cipher object if the document hasn't changed.
177 if (m_cipher && m_cipher->getDocument()!=encryptedData.getDOM()->getOwnerDocument()) {
178 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
183 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedData.getDOM()->getOwnerDocument());
186 m_cipher->setKey(key->clone());
187 auto_ptr<XSECBinTXFMInputStream> in(m_cipher->decryptToBinInputStream(encryptedData.getDOM()));
190 xsecsize_t count = in->readBytes(buf, sizeof(buf));
192 out.write(reinterpret_cast<char*>(buf),count);
194 catch(XSECException& e) {
195 auto_ptr_char temp(e.getMsg());
196 throw DecryptionException(string("XMLSecurity exception while decrypting: ") + temp.get());
198 catch(XSECCryptoException& e) {
199 throw DecryptionException(string("XMLSecurity exception while decrypting: ") + e.getMsg());
203 void Decrypter::decryptData(ostream& out, const EncryptedData& encryptedData, const XMLCh* recipient)
206 throw DecryptionException("No CredentialResolver supplied to provide decryption keys.");
208 // Resolve a decryption key directly.
209 vector<const Credential*> creds;
210 int types = CredentialCriteria::KEYINFO_EXTRACTION_KEY | CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES;
212 m_criteria->setUsage(Credential::ENCRYPTION_CREDENTIAL);
213 m_criteria->setKeyInfo(encryptedData.getKeyInfo(), types);
214 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
216 m_criteria->setXMLAlgorithm(meth->getAlgorithm());
217 m_credResolver->resolve(creds,m_criteria);
220 CredentialCriteria criteria;
221 criteria.setUsage(Credential::ENCRYPTION_CREDENTIAL);
222 criteria.setKeyInfo(encryptedData.getKeyInfo(), types);
223 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
225 criteria.setXMLAlgorithm(meth->getAlgorithm());
226 m_credResolver->resolve(creds,&criteria);
229 // Loop over them and try each one.
231 for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
233 key = (*cred)->getPrivateKey();
236 return decryptData(out, encryptedData, key);
238 catch(DecryptionException& ex) {
239 logging::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what());
243 // We need to find an encrypted decryption key somewhere. We'll need the underlying algorithm...
244 const XMLCh* algorithm=
245 encryptedData.getEncryptionMethod() ? encryptedData.getEncryptionMethod()->getAlgorithm() : nullptr;
247 throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed.");
249 // Check for external resolver.
250 const EncryptedKey* encKey=nullptr;
252 encKey = m_EKResolver->resolveKey(encryptedData, recipient);
254 EncryptedKeyResolver ekr;
255 encKey = ekr.resolveKey(encryptedData, recipient);
259 throw DecryptionException("Unable to locate an encrypted key.");
261 auto_ptr<XSECCryptoKey> keywrapper(decryptKey(*encKey, algorithm));
262 if (!keywrapper.get())
263 throw DecryptionException("Unable to decrypt the encrypted key.");
264 decryptData(out, encryptedData, keywrapper.get());
267 XSECCryptoKey* Decrypter::decryptKey(const EncryptedKey& encryptedKey, const XMLCh* algorithm)
270 throw DecryptionException("No CredentialResolver supplied to provide decryption keys.");
272 if (encryptedKey.getDOM()==nullptr)
273 throw DecryptionException("The object must be marshalled before decryption.");
275 XSECAlgorithmHandler* handler;
277 handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithm);
279 throw DecryptionException("Unrecognized algorithm, no way to build object around decrypted key.");
281 catch(XSECException& e) {
282 auto_ptr_char temp(e.getMsg());
283 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + temp.get());
285 catch(XSECCryptoException& e) {
286 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + e.getMsg());
289 // We can reuse the cipher object if the document hasn't changed.
291 if (m_cipher && m_cipher->getDocument()!=encryptedKey.getDOM()->getOwnerDocument()) {
292 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
297 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedKey.getDOM()->getOwnerDocument());
299 // Resolve key decryption keys.
300 int types = CredentialCriteria::KEYINFO_EXTRACTION_KEY | CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES;
301 vector<const Credential*> creds;
303 m_criteria->setUsage(Credential::ENCRYPTION_CREDENTIAL);
304 m_criteria->setKeyInfo(encryptedKey.getKeyInfo(), types);
305 const EncryptionMethod* meth = encryptedKey.getEncryptionMethod();
307 m_criteria->setXMLAlgorithm(meth->getAlgorithm());
308 m_credResolver->resolve(creds, m_criteria);
311 CredentialCriteria criteria;
312 criteria.setUsage(Credential::ENCRYPTION_CREDENTIAL);
313 criteria.setKeyInfo(encryptedKey.getKeyInfo(), types);
314 const EncryptionMethod* meth = encryptedKey.getEncryptionMethod();
316 criteria.setXMLAlgorithm(meth->getAlgorithm());
317 m_credResolver->resolve(creds, &criteria);
320 throw DecryptionException("Unable to resolve any key decryption keys.");
322 XMLByte buffer[1024];
323 for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
325 if (!(*cred)->getPrivateKey())
326 throw DecryptionException("Credential did not contain a private key.");
327 memset(buffer,0,sizeof(buffer));
328 m_cipher->setKEK((*cred)->getPrivateKey()->clone());
331 int keySize = m_cipher->decryptKey(encryptedKey.getDOM(), buffer, 1024);
333 throw DecryptionException("Unable to decrypt key.");
335 // Try to wrap the key.
336 return handler->createKeyForURI(algorithm, buffer, keySize);
338 catch(XSECException& e) {
339 auto_ptr_char temp(e.getMsg());
340 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + temp.get());
342 catch(XSECCryptoException& e) {
343 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + e.getMsg());
346 catch(DecryptionException& ex) {
347 logging::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what());
351 throw DecryptionException("Unable to decrypt key.");