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 CredentialCriteria::KEYINFO_EXTRACTION_KEY |
91 CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES |
92 CredentialCriteria::KEYINFO_EXTRACTION_IMPLICIT_KEYNAMES;
94 m_criteria->setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
95 m_criteria->setKeyInfo(encryptedData.getKeyInfo(), types);
96 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
98 m_criteria->setXMLAlgorithm(meth->getAlgorithm());
99 m_credResolver->resolve(creds,m_criteria);
102 CredentialCriteria criteria;
103 criteria.setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
104 criteria.setKeyInfo(encryptedData.getKeyInfo(), types);
105 const EncryptionMethod* meth = encryptedData.getEncryptionMethod();
107 criteria.setXMLAlgorithm(meth->getAlgorithm());
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 keys.
173 CredentialCriteria::KEYINFO_EXTRACTION_KEY |
174 CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES |
175 CredentialCriteria::KEYINFO_EXTRACTION_IMPLICIT_KEYNAMES;
176 vector<const Credential*> creds;
178 m_criteria->setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
179 m_criteria->setKeyInfo(encryptedKey.getKeyInfo(), types);
180 const EncryptionMethod* meth = encryptedKey.getEncryptionMethod();
182 m_criteria->setXMLAlgorithm(meth->getAlgorithm());
183 m_credResolver->resolve(creds, m_criteria);
186 CredentialCriteria criteria;
187 criteria.setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL);
188 criteria.setKeyInfo(encryptedKey.getKeyInfo(), types);
189 const EncryptionMethod* meth = encryptedKey.getEncryptionMethod();
191 criteria.setXMLAlgorithm(meth->getAlgorithm());
192 m_credResolver->resolve(creds, &criteria);
195 throw DecryptionException("Unable to resolve any key decryption keys.");
197 XMLByte buffer[1024];
198 for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
200 if (!(*cred)->getPrivateKey())
201 throw DecryptionException("Credential did not contain a private key.");
202 memset(buffer,0,sizeof(buffer));
203 m_cipher->setKEK((*cred)->getPrivateKey()->clone());
206 int keySize = m_cipher->decryptKey(encryptedKey.getDOM(), buffer, 1024);
208 throw DecryptionException("Unable to decrypt key.");
210 // Try to wrap the key.
211 return handler->createKeyForURI(algorithm, buffer, keySize);
213 catch(XSECException& e) {
214 auto_ptr_char temp(e.getMsg());
215 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + temp.get());
217 catch(XSECCryptoException& e) {
218 throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + e.getMsg());
221 catch(DecryptionException& ex) {
222 log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what());
226 throw DecryptionException("Unable to decrypt key.");