2 * Copyright 2001-2007 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 "security/Credential.h"
28 #include "security/CredentialCriteria.h"
29 #include "security/CredentialResolver.h"
31 #include <xsec/enc/XSECCryptoException.hpp>
32 #include <xsec/framework/XSECException.hpp>
33 #include <xsec/framework/XSECAlgorithmMapper.hpp>
34 #include <xsec/framework/XSECAlgorithmHandler.hpp>
35 #include <xsec/utils/XSECBinTXFMInputStream.hpp>
36 #include <xsec/xenc/XENCEncryptedData.hpp>
37 #include <xsec/xenc/XENCEncryptedKey.hpp>
39 using namespace xmlencryption;
40 using namespace xmlsignature;
41 using namespace xmltooling;
42 using namespace xercesc;
45 Decrypter::~Decrypter()
48 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
51 DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, XSECCryptoKey* key)
53 if (encryptedData.getDOM()==NULL)
54 throw DecryptionException("The object must be marshalled before decryption.");
56 // We can reuse the cipher object if the document hasn't changed.
58 if (m_cipher && m_cipher->getDocument()!=encryptedData.getDOM()->getOwnerDocument()) {
59 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
64 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedData.getDOM()->getOwnerDocument());
67 m_cipher->setKey(key->clone());
68 DOMNode* ret=m_cipher->decryptElementDetached(encryptedData.getDOM());
69 if (ret->getNodeType()!=DOMNode::DOCUMENT_FRAGMENT_NODE) {
71 throw DecryptionException("Decryption operation did not result in DocumentFragment.");
73 return static_cast<DOMDocumentFragment*>(ret);
75 catch(XSECException& e) {
76 auto_ptr_char temp(e.getMsg());
77 throw DecryptionException(string("XMLSecurity exception while decrypting: ") + temp.get());
79 catch(XSECCryptoException& e) {
80 throw DecryptionException(string("XMLSecurity exception while decrypting: ") + e.getMsg());
84 DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, const XMLCh* recipient)
87 throw DecryptionException("No CredentialResolver supplied to provide decryption keys.");
89 // Resolve a decryption key directly.
90 vector<const Credential*> creds;
91 int types = CredentialCriteria::KEYINFO_EXTRACTION_KEY | CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES;
93 m_criteria->setUsage(Credential::ENCRYPTION_CREDENTIAL);
94 m_criteria->setKeyInfo(encryptedData.getKeyInfo(), types);
95 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
97 m_criteria->setXMLAlgorithm(meth->getAlgorithm());
98 m_credResolver->resolve(creds,m_criteria);
101 CredentialCriteria criteria;
102 criteria.setUsage(Credential::ENCRYPTION_CREDENTIAL);
103 criteria.setKeyInfo(encryptedData.getKeyInfo(), types);
104 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
106 criteria.setXMLAlgorithm(meth->getAlgorithm());
107 m_credResolver->resolve(creds,&criteria);
110 // Loop over them and try each one.
112 for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
114 key = (*cred)->getPrivateKey();
117 return decryptData(encryptedData, key);
119 catch(DecryptionException& ex) {
120 logging::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what());
124 // We need to find an encrypted decryption key somewhere. We'll need the underlying algorithm...
125 const XMLCh* algorithm=
126 encryptedData.getEncryptionMethod() ? encryptedData.getEncryptionMethod()->getAlgorithm() : NULL;
128 throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed.");
130 // Check for external resolver.
131 const EncryptedKey* encKey=NULL;
133 encKey = m_EKResolver->resolveKey(encryptedData, recipient);
135 EncryptedKeyResolver ekr;
136 encKey = ekr.resolveKey(encryptedData, recipient);
140 throw DecryptionException("Unable to locate an encrypted key.");
142 auto_ptr<XSECCryptoKey> keywrapper(decryptKey(*encKey, algorithm));
143 if (!keywrapper.get())
144 throw DecryptionException("Unable to decrypt the encrypted key.");
145 return decryptData(encryptedData, keywrapper.get());
148 void Decrypter::decryptData(ostream& out, const EncryptedData& encryptedData, XSECCryptoKey* key)
150 if (encryptedData.getDOM()==NULL)
151 throw DecryptionException("The object must be marshalled before decryption.");
153 // We can reuse the cipher object if the document hasn't changed.
155 if (m_cipher && m_cipher->getDocument()!=encryptedData.getDOM()->getOwnerDocument()) {
156 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
161 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedData.getDOM()->getOwnerDocument());
164 m_cipher->setKey(key->clone());
165 auto_ptr<XSECBinTXFMInputStream> in(m_cipher->decryptToBinInputStream(encryptedData.getDOM()));
168 xsecsize_t count = in->readBytes(buf, sizeof(buf));
170 out.write(reinterpret_cast<char*>(buf),count);
172 catch(XSECException& e) {
173 auto_ptr_char temp(e.getMsg());
174 throw DecryptionException(string("XMLSecurity exception while decrypting: ") + temp.get());
176 catch(XSECCryptoException& e) {
177 throw DecryptionException(string("XMLSecurity exception while decrypting: ") + e.getMsg());
181 void Decrypter::decryptData(ostream& out, const EncryptedData& encryptedData, const XMLCh* recipient)
184 throw DecryptionException("No CredentialResolver supplied to provide decryption keys.");
186 // Resolve a decryption key directly.
187 vector<const Credential*> creds;
188 int types = CredentialCriteria::KEYINFO_EXTRACTION_KEY | CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES;
190 m_criteria->setUsage(Credential::ENCRYPTION_CREDENTIAL);
191 m_criteria->setKeyInfo(encryptedData.getKeyInfo(), types);
192 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
194 m_criteria->setXMLAlgorithm(meth->getAlgorithm());
195 m_credResolver->resolve(creds,m_criteria);
198 CredentialCriteria criteria;
199 criteria.setUsage(Credential::ENCRYPTION_CREDENTIAL);
200 criteria.setKeyInfo(encryptedData.getKeyInfo(), types);
201 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
203 criteria.setXMLAlgorithm(meth->getAlgorithm());
204 m_credResolver->resolve(creds,&criteria);
207 // Loop over them and try each one.
209 for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
211 key = (*cred)->getPrivateKey();
214 return decryptData(out, encryptedData, key);
216 catch(DecryptionException& ex) {
217 logging::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what());
221 // We need to find an encrypted decryption key somewhere. We'll need the underlying algorithm...
222 const XMLCh* algorithm=
223 encryptedData.getEncryptionMethod() ? encryptedData.getEncryptionMethod()->getAlgorithm() : NULL;
225 throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed.");
227 // Check for external resolver.
228 const EncryptedKey* encKey=NULL;
230 encKey = m_EKResolver->resolveKey(encryptedData, recipient);
232 EncryptedKeyResolver ekr;
233 encKey = ekr.resolveKey(encryptedData, recipient);
237 throw DecryptionException("Unable to locate an encrypted key.");
239 auto_ptr<XSECCryptoKey> keywrapper(decryptKey(*encKey, algorithm));
240 if (!keywrapper.get())
241 throw DecryptionException("Unable to decrypt the encrypted key.");
242 decryptData(out, encryptedData, keywrapper.get());
245 XSECCryptoKey* Decrypter::decryptKey(const EncryptedKey& encryptedKey, const XMLCh* algorithm)
248 throw DecryptionException("No CredentialResolver supplied to provide decryption keys.");
250 if (encryptedKey.getDOM()==NULL)
251 throw DecryptionException("The object must be marshalled before decryption.");
253 XSECAlgorithmHandler* handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithm);
255 throw DecryptionException("Unrecognized algorithm, no way to build object around decrypted key.");
257 // We can reuse the cipher object if the document hasn't changed.
259 if (m_cipher && m_cipher->getDocument()!=encryptedKey.getDOM()->getOwnerDocument()) {
260 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
265 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedKey.getDOM()->getOwnerDocument());
267 // Resolve key decryption keys.
268 int types = CredentialCriteria::KEYINFO_EXTRACTION_KEY | CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES;
269 vector<const Credential*> creds;
271 m_criteria->setUsage(Credential::ENCRYPTION_CREDENTIAL);
272 m_criteria->setKeyInfo(encryptedKey.getKeyInfo(), types);
273 const EncryptionMethod* meth = encryptedKey.getEncryptionMethod();
275 m_criteria->setXMLAlgorithm(meth->getAlgorithm());
276 m_credResolver->resolve(creds, m_criteria);
279 CredentialCriteria criteria;
280 criteria.setUsage(Credential::ENCRYPTION_CREDENTIAL);
281 criteria.setKeyInfo(encryptedKey.getKeyInfo(), types);
282 const EncryptionMethod* meth = encryptedKey.getEncryptionMethod();
284 criteria.setXMLAlgorithm(meth->getAlgorithm());
285 m_credResolver->resolve(creds, &criteria);
288 throw DecryptionException("Unable to resolve any key decryption keys.");
290 XMLByte buffer[1024];
291 for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
293 if (!(*cred)->getPrivateKey())
294 throw DecryptionException("Credential did not contain a private key.");
295 memset(buffer,0,sizeof(buffer));
296 m_cipher->setKEK((*cred)->getPrivateKey()->clone());
299 int keySize = m_cipher->decryptKey(encryptedKey.getDOM(), buffer, 1024);
301 throw DecryptionException("Unable to decrypt key.");
303 // Try to wrap the key.
304 return handler->createKeyForURI(algorithm, buffer, keySize);
306 catch(XSECException& e) {
307 auto_ptr_char temp(e.getMsg());
308 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + temp.get());
310 catch(XSECCryptoException& e) {
311 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + e.getMsg());
314 catch(DecryptionException& ex) {
315 logging::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what());
319 throw DecryptionException("Unable to decrypt key.");