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/xenc/XENCEncryptedData.hpp>
36 #include <xsec/xenc/XENCEncryptedKey.hpp>
38 using namespace xmlencryption;
39 using namespace xmlsignature;
40 using namespace xmltooling;
43 Decrypter::~Decrypter()
46 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
49 DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, XSECCryptoKey* key)
51 if (encryptedData.getDOM()==NULL)
52 throw DecryptionException("The object must be marshalled before decryption.");
54 // We can reuse the cipher object if the document hasn't changed.
56 if (m_cipher && m_cipher->getDocument()!=encryptedData.getDOM()->getOwnerDocument()) {
57 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
62 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedData.getDOM()->getOwnerDocument());
65 m_cipher->setKey(key->clone());
66 DOMNode* ret=m_cipher->decryptElementDetached(encryptedData.getDOM());
67 if (ret->getNodeType()!=DOMNode::DOCUMENT_FRAGMENT_NODE) {
69 throw DecryptionException("Decryption operation did not result in DocumentFragment.");
71 return static_cast<DOMDocumentFragment*>(ret);
73 catch(XSECException& e) {
74 auto_ptr_char temp(e.getMsg());
75 throw DecryptionException(string("XMLSecurity exception while decrypting: ") + temp.get());
77 catch(XSECCryptoException& e) {
78 throw DecryptionException(string("XMLSecurity exception while decrypting: ") + e.getMsg());
82 DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, const XMLCh* recipient)
85 throw DecryptionException("No CredentialResolver supplied to provide decryption keys.");
87 // Resolve a decryption key directly.
88 vector<const Credential*> creds;
90 m_criteria->setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
91 m_criteria->setKeyInfo(encryptedData.getKeyInfo());
92 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
94 m_criteria->setXMLAlgorithm(meth->getAlgorithm());
95 m_credResolver->resolve(creds,m_criteria);
98 CredentialCriteria criteria;
99 criteria.setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
100 criteria.setKeyInfo(encryptedData.getKeyInfo());
101 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
103 criteria.setXMLAlgorithm(meth->getAlgorithm());
104 m_credResolver->resolve(creds,&criteria);
107 // Loop over them and try each one.
109 for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
111 key = (*cred)->getPrivateKey();
114 return decryptData(encryptedData, key);
116 catch(DecryptionException& ex) {
117 log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what());
121 // We need to find an encrypted decryption key somewhere. We'll need the underlying algorithm...
122 const XMLCh* algorithm=
123 encryptedData.getEncryptionMethod() ? encryptedData.getEncryptionMethod()->getAlgorithm() : NULL;
125 throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed.");
127 // Check for external resolver.
128 const EncryptedKey* encKey=NULL;
130 encKey = m_EKResolver->resolveKey(encryptedData, recipient);
132 EncryptedKeyResolver ekr;
133 encKey = ekr.resolveKey(encryptedData, recipient);
137 throw DecryptionException("Unable to locate an encrypted key.");
139 auto_ptr<XSECCryptoKey> keywrapper(decryptKey(*encKey, algorithm));
140 if (!keywrapper.get())
141 throw DecryptionException("Unable to decrypt the encrypted key.");
142 return decryptData(encryptedData, keywrapper.get());
145 XSECCryptoKey* Decrypter::decryptKey(const EncryptedKey& encryptedKey, const XMLCh* algorithm)
148 throw DecryptionException("No CredentialResolver supplied to provide decryption keys.");
150 if (encryptedKey.getDOM()==NULL)
151 throw DecryptionException("The object must be marshalled before decryption.");
153 XSECAlgorithmHandler* handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithm);
155 throw DecryptionException("Unrecognized algorithm, no way to build object around decrypted key.");
157 // We can reuse the cipher object if the document hasn't changed.
159 if (m_cipher && m_cipher->getDocument()!=encryptedKey.getDOM()->getOwnerDocument()) {
160 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
165 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedKey.getDOM()->getOwnerDocument());
167 // Resolve key decryption key. We can't loop over possible credentials because
168 // we can't tell a valid decrypt from an invalid one.
169 vector<const Credential*> creds;
171 m_criteria->setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
172 m_criteria->setKeyInfo(encryptedKey.getKeyInfo());
173 const EncryptionMethod* meth = encryptedKey.getEncryptionMethod();
175 m_criteria->setXMLAlgorithm(meth->getAlgorithm());
176 m_credResolver->resolve(creds, m_criteria);
179 CredentialCriteria criteria;
180 criteria.setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
181 criteria.setKeyInfo(encryptedKey.getKeyInfo());
182 const EncryptionMethod* meth = encryptedKey.getEncryptionMethod();
184 criteria.setXMLAlgorithm(meth->getAlgorithm());
185 m_credResolver->resolve(creds, &criteria);
188 throw DecryptionException("Unable to resolve any key decryption keys.");
190 XMLByte buffer[1024];
191 for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
193 if (!(*cred)->getPrivateKey())
194 throw DecryptionException("Credential did not contain a private key.");
195 memset(buffer,0,sizeof(buffer));
196 m_cipher->setKEK((*cred)->getPrivateKey()->clone());
199 int keySize = m_cipher->decryptKey(encryptedKey.getDOM(), buffer, 1024);
201 throw DecryptionException("Unable to decrypt key.");
203 // Try to wrap the key.
204 return handler->createKeyForURI(algorithm, buffer, keySize);
206 catch(XSECException& e) {
207 auto_ptr_char temp(e.getMsg());
208 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + temp.get());
210 catch(XSECCryptoException& e) {
211 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + e.getMsg());
214 catch(DecryptionException& ex) {
215 log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what());
219 throw DecryptionException("Unable to decrypt key.");