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 auto_ptr_char alg(meth->getAlgorithm());
95 m_criteria->setKeyAlgorithm(alg.get());
97 m_credResolver->resolve(creds,m_criteria);
100 CredentialCriteria criteria;
101 criteria.setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
102 criteria.setKeyInfo(encryptedData.getKeyInfo());
103 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
105 auto_ptr_char alg(meth->getAlgorithm());
106 criteria.setKeyAlgorithm(alg.get());
108 m_credResolver->resolve(creds,&criteria);
111 // Loop over them and try each one.
113 for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
115 key = (*cred)->getPrivateKey();
118 return decryptData(encryptedData, key);
120 catch(DecryptionException& ex) {
121 log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what());
125 // We need to find an encrypted decryption key somewhere. We'll need the underlying algorithm...
126 const XMLCh* algorithm=
127 encryptedData.getEncryptionMethod() ? encryptedData.getEncryptionMethod()->getAlgorithm() : NULL;
129 throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed.");
131 // Check for external resolver.
132 const EncryptedKey* encKey=NULL;
134 encKey = m_EKResolver->resolveKey(encryptedData, recipient);
136 EncryptedKeyResolver ekr;
137 encKey = ekr.resolveKey(encryptedData, recipient);
141 throw DecryptionException("Unable to locate an encrypted key.");
143 auto_ptr<XSECCryptoKey> keywrapper(decryptKey(*encKey, algorithm));
144 if (!keywrapper.get())
145 throw DecryptionException("Unable to decrypt the encrypted key.");
146 return decryptData(encryptedData, keywrapper.get());
149 XSECCryptoKey* Decrypter::decryptKey(const EncryptedKey& encryptedKey, const XMLCh* algorithm)
152 throw DecryptionException("No CredentialResolver supplied to provide decryption keys.");
154 if (encryptedKey.getDOM()==NULL)
155 throw DecryptionException("The object must be marshalled before decryption.");
157 XSECAlgorithmHandler* handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithm);
159 throw DecryptionException("Unrecognized algorithm, no way to build object around decrypted key.");
161 // We can reuse the cipher object if the document hasn't changed.
163 if (m_cipher && m_cipher->getDocument()!=encryptedKey.getDOM()->getOwnerDocument()) {
164 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
169 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedKey.getDOM()->getOwnerDocument());
171 // Resolve key decryption key. We can't loop over possible credentials because
172 // we can't tell a valid decrypt from an invalid one.
173 vector<const Credential*> creds;
175 m_criteria->setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
176 m_criteria->setKeyInfo(encryptedKey.getKeyInfo());
177 const EncryptionMethod* meth = encryptedKey.getEncryptionMethod();
179 auto_ptr_char alg(meth->getAlgorithm());
180 m_criteria->setKeyAlgorithm(alg.get());
182 m_credResolver->resolve(creds, m_criteria);
185 CredentialCriteria criteria;
186 criteria.setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
187 criteria.setKeyInfo(encryptedKey.getKeyInfo());
188 const EncryptionMethod* meth = encryptedKey.getEncryptionMethod();
190 auto_ptr_char alg(meth->getAlgorithm());
191 criteria.setKeyAlgorithm(alg.get());
193 m_credResolver->resolve(creds, &criteria);
196 throw DecryptionException("Unable to resolve any key decryption keys.");
198 XMLByte buffer[1024];
199 for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
201 if (!(*cred)->getPrivateKey())
202 throw DecryptionException("Credential did not contain a private key.");
203 memset(buffer,0,sizeof(buffer));
204 m_cipher->setKEK((*cred)->getPrivateKey()->clone());
207 int keySize = m_cipher->decryptKey(encryptedKey.getDOM(), buffer, 1024);
209 throw DecryptionException("Unable to decrypt key.");
211 // Try to wrap the key.
212 return handler->createKeyForURI(algorithm, buffer, keySize);
214 catch(XSECException& e) {
215 auto_ptr_char temp(e.getMsg());
216 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + temp.get());
218 catch(XSECCryptoException& e) {
219 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + e.getMsg());
222 catch(DecryptionException& ex) {
223 log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what());
227 throw DecryptionException("Unable to decrypt key.");