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 // 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 const Credential* cred=NULL;
171 m_criteria->setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
172 m_criteria->setKeyInfo(encryptedKey.getKeyInfo());
173 const EncryptionMethod* meth = encryptedKey.getEncryptionMethod();
175 auto_ptr_char alg(meth->getAlgorithm());
176 m_criteria->setKeyAlgorithm(alg.get());
178 cred = m_credResolver->resolve(m_criteria);
181 CredentialCriteria criteria;
182 criteria.setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
183 criteria.setKeyInfo(encryptedKey.getKeyInfo());
184 const EncryptionMethod* meth = encryptedKey.getEncryptionMethod();
186 auto_ptr_char alg(meth->getAlgorithm());
187 criteria.setKeyAlgorithm(alg.get());
189 cred = m_credResolver->resolve(&criteria);
191 if (!cred || !cred->getPrivateKey())
192 throw DecryptionException("Unable to resolve a key decryption key.");
195 m_cipher->setKEK(cred->getPrivateKey()->clone());
196 XMLByte buffer[1024];
197 memset(buffer,0,sizeof(buffer));
198 int keySize = m_cipher->decryptKey(encryptedKey.getDOM(), buffer, 1024);
200 throw DecryptionException("Unable to decrypt key.");
202 // Try to map the key.
203 XSECAlgorithmHandler* handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithm);
205 return handler->createKeyForURI(algorithm, buffer, keySize);
206 throw DecryptionException("Unrecognized algorithm, could not build object around decrypted key.");
208 catch(XSECException& e) {
209 auto_ptr_char temp(e.getMsg());
210 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + temp.get());
212 catch(XSECCryptoException& e) {
213 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + e.getMsg());