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.
24 #include "encryption/Decrypter.h"
25 #include "encryption/EncryptedKeyResolver.h"
26 #include "security/Credential.h"
27 #include "security/CredentialCriteria.h"
28 #include "security/CredentialResolver.h"
30 #include <log4cpp/Category.hh>
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;
91 CredentialCriteria::KEYINFO_EXTRACTION_KEY |
92 CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES |
93 CredentialCriteria::KEYINFO_EXTRACTION_IMPLICIT_KEYNAMES;
95 m_criteria->setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
96 m_criteria->setKeyInfo(encryptedData.getKeyInfo(), types);
97 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
99 m_criteria->setXMLAlgorithm(meth->getAlgorithm());
100 m_credResolver->resolve(creds,m_criteria);
103 CredentialCriteria criteria;
104 criteria.setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
105 criteria.setKeyInfo(encryptedData.getKeyInfo(), types);
106 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
108 criteria.setXMLAlgorithm(meth->getAlgorithm());
109 m_credResolver->resolve(creds,&criteria);
112 // Loop over them and try each one.
114 for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
116 key = (*cred)->getPrivateKey();
119 return decryptData(encryptedData, key);
121 catch(DecryptionException& ex) {
122 log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what());
126 // We need to find an encrypted decryption key somewhere. We'll need the underlying algorithm...
127 const XMLCh* algorithm=
128 encryptedData.getEncryptionMethod() ? encryptedData.getEncryptionMethod()->getAlgorithm() : NULL;
130 throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed.");
132 // Check for external resolver.
133 const EncryptedKey* encKey=NULL;
135 encKey = m_EKResolver->resolveKey(encryptedData, recipient);
137 EncryptedKeyResolver ekr;
138 encKey = ekr.resolveKey(encryptedData, recipient);
142 throw DecryptionException("Unable to locate an encrypted key.");
144 auto_ptr<XSECCryptoKey> keywrapper(decryptKey(*encKey, algorithm));
145 if (!keywrapper.get())
146 throw DecryptionException("Unable to decrypt the encrypted key.");
147 return decryptData(encryptedData, keywrapper.get());
150 void Decrypter::decryptData(ostream& out, const EncryptedData& encryptedData, XSECCryptoKey* key)
152 if (encryptedData.getDOM()==NULL)
153 throw DecryptionException("The object must be marshalled before decryption.");
155 // We can reuse the cipher object if the document hasn't changed.
157 if (m_cipher && m_cipher->getDocument()!=encryptedData.getDOM()->getOwnerDocument()) {
158 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
163 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedData.getDOM()->getOwnerDocument());
166 m_cipher->setKey(key->clone());
167 auto_ptr<XSECBinTXFMInputStream> in(m_cipher->decryptToBinInputStream(encryptedData.getDOM()));
170 unsigned int count = in->readBytes(buf, sizeof(buf));
172 out.write(reinterpret_cast<char*>(buf),count);
174 catch(XSECException& e) {
175 auto_ptr_char temp(e.getMsg());
176 throw DecryptionException(string("XMLSecurity exception while decrypting: ") + temp.get());
178 catch(XSECCryptoException& e) {
179 throw DecryptionException(string("XMLSecurity exception while decrypting: ") + e.getMsg());
183 void Decrypter::decryptData(ostream& out, const EncryptedData& encryptedData, const XMLCh* recipient)
186 throw DecryptionException("No CredentialResolver supplied to provide decryption keys.");
188 // Resolve a decryption key directly.
189 vector<const Credential*> creds;
191 CredentialCriteria::KEYINFO_EXTRACTION_KEY |
192 CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES |
193 CredentialCriteria::KEYINFO_EXTRACTION_IMPLICIT_KEYNAMES;
195 m_criteria->setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
196 m_criteria->setKeyInfo(encryptedData.getKeyInfo(), types);
197 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
199 m_criteria->setXMLAlgorithm(meth->getAlgorithm());
200 m_credResolver->resolve(creds,m_criteria);
203 CredentialCriteria criteria;
204 criteria.setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
205 criteria.setKeyInfo(encryptedData.getKeyInfo(), types);
206 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
208 criteria.setXMLAlgorithm(meth->getAlgorithm());
209 m_credResolver->resolve(creds,&criteria);
212 // Loop over them and try each one.
214 for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
216 key = (*cred)->getPrivateKey();
219 return decryptData(out, encryptedData, key);
221 catch(DecryptionException& ex) {
222 log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what());
226 // We need to find an encrypted decryption key somewhere. We'll need the underlying algorithm...
227 const XMLCh* algorithm=
228 encryptedData.getEncryptionMethod() ? encryptedData.getEncryptionMethod()->getAlgorithm() : NULL;
230 throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed.");
232 // Check for external resolver.
233 const EncryptedKey* encKey=NULL;
235 encKey = m_EKResolver->resolveKey(encryptedData, recipient);
237 EncryptedKeyResolver ekr;
238 encKey = ekr.resolveKey(encryptedData, recipient);
242 throw DecryptionException("Unable to locate an encrypted key.");
244 auto_ptr<XSECCryptoKey> keywrapper(decryptKey(*encKey, algorithm));
245 if (!keywrapper.get())
246 throw DecryptionException("Unable to decrypt the encrypted key.");
247 decryptData(out, encryptedData, keywrapper.get());
250 XSECCryptoKey* Decrypter::decryptKey(const EncryptedKey& encryptedKey, const XMLCh* algorithm)
253 throw DecryptionException("No CredentialResolver supplied to provide decryption keys.");
255 if (encryptedKey.getDOM()==NULL)
256 throw DecryptionException("The object must be marshalled before decryption.");
258 XSECAlgorithmHandler* handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithm);
260 throw DecryptionException("Unrecognized algorithm, no way to build object around decrypted key.");
262 // We can reuse the cipher object if the document hasn't changed.
264 if (m_cipher && m_cipher->getDocument()!=encryptedKey.getDOM()->getOwnerDocument()) {
265 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
270 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedKey.getDOM()->getOwnerDocument());
272 // Resolve key decryption keys.
274 CredentialCriteria::KEYINFO_EXTRACTION_KEY |
275 CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES |
276 CredentialCriteria::KEYINFO_EXTRACTION_IMPLICIT_KEYNAMES;
277 vector<const Credential*> creds;
279 m_criteria->setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
280 m_criteria->setKeyInfo(encryptedKey.getKeyInfo(), types);
281 const EncryptionMethod* meth = encryptedKey.getEncryptionMethod();
283 m_criteria->setXMLAlgorithm(meth->getAlgorithm());
284 m_credResolver->resolve(creds, m_criteria);
287 CredentialCriteria criteria;
288 criteria.setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
289 criteria.setKeyInfo(encryptedKey.getKeyInfo(), types);
290 const EncryptionMethod* meth = encryptedKey.getEncryptionMethod();
292 criteria.setXMLAlgorithm(meth->getAlgorithm());
293 m_credResolver->resolve(creds, &criteria);
296 throw DecryptionException("Unable to resolve any key decryption keys.");
298 XMLByte buffer[1024];
299 for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
301 if (!(*cred)->getPrivateKey())
302 throw DecryptionException("Credential did not contain a private key.");
303 memset(buffer,0,sizeof(buffer));
304 m_cipher->setKEK((*cred)->getPrivateKey()->clone());
307 int keySize = m_cipher->decryptKey(encryptedKey.getDOM(), buffer, 1024);
309 throw DecryptionException("Unable to decrypt key.");
311 // Try to wrap the key.
312 return handler->createKeyForURI(algorithm, buffer, keySize);
314 catch(XSECException& e) {
315 auto_ptr_char temp(e.getMsg());
316 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + temp.get());
318 catch(XSECCryptoException& e) {
319 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + e.getMsg());
322 catch(DecryptionException& ex) {
323 log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what());
327 throw DecryptionException("Unable to decrypt key.");