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;
44 Decrypter::~Decrypter()
47 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
50 DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, XSECCryptoKey* key)
52 if (encryptedData.getDOM()==NULL)
53 throw DecryptionException("The object must be marshalled before decryption.");
55 // We can reuse the cipher object if the document hasn't changed.
57 if (m_cipher && m_cipher->getDocument()!=encryptedData.getDOM()->getOwnerDocument()) {
58 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
63 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedData.getDOM()->getOwnerDocument());
66 m_cipher->setKey(key->clone());
67 DOMNode* ret=m_cipher->decryptElementDetached(encryptedData.getDOM());
68 if (ret->getNodeType()!=DOMNode::DOCUMENT_FRAGMENT_NODE) {
70 throw DecryptionException("Decryption operation did not result in DocumentFragment.");
72 return static_cast<DOMDocumentFragment*>(ret);
74 catch(XSECException& e) {
75 auto_ptr_char temp(e.getMsg());
76 throw DecryptionException(string("XMLSecurity exception while decrypting: ") + temp.get());
78 catch(XSECCryptoException& e) {
79 throw DecryptionException(string("XMLSecurity exception while decrypting: ") + e.getMsg());
83 DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, const XMLCh* recipient)
86 throw DecryptionException("No CredentialResolver supplied to provide decryption keys.");
88 // Resolve a decryption key directly.
89 vector<const Credential*> creds;
90 int types = CredentialCriteria::KEYINFO_EXTRACTION_KEY | CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES;
92 m_criteria->setUsage(Credential::ENCRYPTION_CREDENTIAL);
93 m_criteria->setKeyInfo(encryptedData.getKeyInfo(), types);
94 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
96 m_criteria->setXMLAlgorithm(meth->getAlgorithm());
97 m_credResolver->resolve(creds,m_criteria);
100 CredentialCriteria criteria;
101 criteria.setUsage(Credential::ENCRYPTION_CREDENTIAL);
102 criteria.setKeyInfo(encryptedData.getKeyInfo(), types);
103 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
105 criteria.setXMLAlgorithm(meth->getAlgorithm());
106 m_credResolver->resolve(creds,&criteria);
109 // Loop over them and try each one.
111 for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
113 key = (*cred)->getPrivateKey();
116 return decryptData(encryptedData, key);
118 catch(DecryptionException& ex) {
119 logging::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what());
123 // We need to find an encrypted decryption key somewhere. We'll need the underlying algorithm...
124 const XMLCh* algorithm=
125 encryptedData.getEncryptionMethod() ? encryptedData.getEncryptionMethod()->getAlgorithm() : NULL;
127 throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed.");
129 // Check for external resolver.
130 const EncryptedKey* encKey=NULL;
132 encKey = m_EKResolver->resolveKey(encryptedData, recipient);
134 EncryptedKeyResolver ekr;
135 encKey = ekr.resolveKey(encryptedData, recipient);
139 throw DecryptionException("Unable to locate an encrypted key.");
141 auto_ptr<XSECCryptoKey> keywrapper(decryptKey(*encKey, algorithm));
142 if (!keywrapper.get())
143 throw DecryptionException("Unable to decrypt the encrypted key.");
144 return decryptData(encryptedData, keywrapper.get());
147 void Decrypter::decryptData(ostream& out, const EncryptedData& encryptedData, XSECCryptoKey* key)
149 if (encryptedData.getDOM()==NULL)
150 throw DecryptionException("The object must be marshalled before decryption.");
152 // We can reuse the cipher object if the document hasn't changed.
154 if (m_cipher && m_cipher->getDocument()!=encryptedData.getDOM()->getOwnerDocument()) {
155 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
160 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedData.getDOM()->getOwnerDocument());
163 m_cipher->setKey(key->clone());
164 auto_ptr<XSECBinTXFMInputStream> in(m_cipher->decryptToBinInputStream(encryptedData.getDOM()));
167 unsigned int count = in->readBytes(buf, sizeof(buf));
169 out.write(reinterpret_cast<char*>(buf),count);
171 catch(XSECException& e) {
172 auto_ptr_char temp(e.getMsg());
173 throw DecryptionException(string("XMLSecurity exception while decrypting: ") + temp.get());
175 catch(XSECCryptoException& e) {
176 throw DecryptionException(string("XMLSecurity exception while decrypting: ") + e.getMsg());
180 void Decrypter::decryptData(ostream& out, const EncryptedData& encryptedData, const XMLCh* recipient)
183 throw DecryptionException("No CredentialResolver supplied to provide decryption keys.");
185 // Resolve a decryption key directly.
186 vector<const Credential*> creds;
187 int types = CredentialCriteria::KEYINFO_EXTRACTION_KEY | CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES;
189 m_criteria->setUsage(Credential::ENCRYPTION_CREDENTIAL);
190 m_criteria->setKeyInfo(encryptedData.getKeyInfo(), types);
191 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
193 m_criteria->setXMLAlgorithm(meth->getAlgorithm());
194 m_credResolver->resolve(creds,m_criteria);
197 CredentialCriteria criteria;
198 criteria.setUsage(Credential::ENCRYPTION_CREDENTIAL);
199 criteria.setKeyInfo(encryptedData.getKeyInfo(), types);
200 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
202 criteria.setXMLAlgorithm(meth->getAlgorithm());
203 m_credResolver->resolve(creds,&criteria);
206 // Loop over them and try each one.
208 for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
210 key = (*cred)->getPrivateKey();
213 return decryptData(out, encryptedData, key);
215 catch(DecryptionException& ex) {
216 logging::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what());
220 // We need to find an encrypted decryption key somewhere. We'll need the underlying algorithm...
221 const XMLCh* algorithm=
222 encryptedData.getEncryptionMethod() ? encryptedData.getEncryptionMethod()->getAlgorithm() : NULL;
224 throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed.");
226 // Check for external resolver.
227 const EncryptedKey* encKey=NULL;
229 encKey = m_EKResolver->resolveKey(encryptedData, recipient);
231 EncryptedKeyResolver ekr;
232 encKey = ekr.resolveKey(encryptedData, recipient);
236 throw DecryptionException("Unable to locate an encrypted key.");
238 auto_ptr<XSECCryptoKey> keywrapper(decryptKey(*encKey, algorithm));
239 if (!keywrapper.get())
240 throw DecryptionException("Unable to decrypt the encrypted key.");
241 decryptData(out, encryptedData, keywrapper.get());
244 XSECCryptoKey* Decrypter::decryptKey(const EncryptedKey& encryptedKey, const XMLCh* algorithm)
247 throw DecryptionException("No CredentialResolver supplied to provide decryption keys.");
249 if (encryptedKey.getDOM()==NULL)
250 throw DecryptionException("The object must be marshalled before decryption.");
252 XSECAlgorithmHandler* handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithm);
254 throw DecryptionException("Unrecognized algorithm, no way to build object around decrypted key.");
256 // We can reuse the cipher object if the document hasn't changed.
258 if (m_cipher && m_cipher->getDocument()!=encryptedKey.getDOM()->getOwnerDocument()) {
259 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
264 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedKey.getDOM()->getOwnerDocument());
266 // Resolve key decryption keys.
267 int types = CredentialCriteria::KEYINFO_EXTRACTION_KEY | CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES;
268 vector<const Credential*> creds;
270 m_criteria->setUsage(Credential::ENCRYPTION_CREDENTIAL);
271 m_criteria->setKeyInfo(encryptedKey.getKeyInfo(), types);
272 const EncryptionMethod* meth = encryptedKey.getEncryptionMethod();
274 m_criteria->setXMLAlgorithm(meth->getAlgorithm());
275 m_credResolver->resolve(creds, m_criteria);
278 CredentialCriteria criteria;
279 criteria.setUsage(Credential::ENCRYPTION_CREDENTIAL);
280 criteria.setKeyInfo(encryptedKey.getKeyInfo(), types);
281 const EncryptionMethod* meth = encryptedKey.getEncryptionMethod();
283 criteria.setXMLAlgorithm(meth->getAlgorithm());
284 m_credResolver->resolve(creds, &criteria);
287 throw DecryptionException("Unable to resolve any key decryption keys.");
289 XMLByte buffer[1024];
290 for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
292 if (!(*cred)->getPrivateKey())
293 throw DecryptionException("Credential did not contain a private key.");
294 memset(buffer,0,sizeof(buffer));
295 m_cipher->setKEK((*cred)->getPrivateKey()->clone());
298 int keySize = m_cipher->decryptKey(encryptedKey.getDOM(), buffer, 1024);
300 throw DecryptionException("Unable to decrypt key.");
302 // Try to wrap the key.
303 return handler->createKeyForURI(algorithm, buffer, keySize);
305 catch(XSECException& e) {
306 auto_ptr_char temp(e.getMsg());
307 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + temp.get());
309 catch(XSECCryptoException& e) {
310 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + e.getMsg());
313 catch(DecryptionException& ex) {
314 logging::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what());
318 throw DecryptionException("Unable to decrypt key.");