Update copyright.
[shibboleth/cpp-xmltooling.git] / xmltooling / encryption / impl / Decrypter.cpp
1 /*
2  *  Copyright 2001-2007 Internet2
3  * 
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 /**
18  * Decrypter.cpp
19  * 
20  * Methods for decrypting XMLObjects and other data.
21  */
22
23 #include "internal.h"
24 #include "encryption/Decrypter.h"
25 #include "encryption/EncryptedKeyResolver.h"
26
27 #include <log4cpp/Category.hh>
28 #include <xsec/enc/XSECCryptoException.hpp>
29 #include <xsec/framework/XSECException.hpp>
30 #include <xsec/framework/XSECAlgorithmMapper.hpp>
31 #include <xsec/framework/XSECAlgorithmHandler.hpp>
32 #include <xsec/xenc/XENCEncryptedData.hpp>
33 #include <xsec/xenc/XENCEncryptedKey.hpp>
34
35 using namespace xmlencryption;
36 using namespace xmlsignature;
37 using namespace xmltooling;
38 using namespace std;
39
40 Decrypter::~Decrypter()
41 {
42     if (m_cipher)
43         XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
44     delete m_resolver;
45     delete m_KEKresolver;
46 }
47
48 DOMDocumentFragment* Decrypter::decryptData(EncryptedData* encryptedData)
49 {
50     if (encryptedData->getDOM()==NULL)
51         throw DecryptionException("The object must be marshalled before decryption.");
52     
53     // We can reuse the cipher object if the document hasn't changed.
54
55     if (m_cipher && m_cipher->getDocument()!=encryptedData->getDOM()->getOwnerDocument()) {
56         XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
57         m_cipher=NULL;
58     }
59     
60     if (!m_cipher)
61         m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedData->getDOM()->getOwnerDocument());
62     
63     try {
64         // Resolve decryption key.
65         XSECCryptoKey* key=NULL;
66         if (m_resolver)
67             key=m_resolver->resolveKey(encryptedData->getKeyInfo());
68
69         if (!key && m_KEKresolver) {
70             // See if there's an encrypted key available. We'll need the algorithm...
71             const XMLCh* algorithm=
72                 encryptedData->getEncryptionMethod() ? encryptedData->getEncryptionMethod()->getAlgorithm() : NULL;
73             if (!algorithm)
74                 throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed.");
75             
76             if (encryptedData->getKeyInfo()) {
77                 const vector<XMLObject*>& others=const_cast<const KeyInfo*>(encryptedData->getKeyInfo())->getUnknownXMLObjects();
78                 for (vector<XMLObject*>::const_iterator i=others.begin(); i!=others.end(); i++) {
79                     EncryptedKey* encKey=dynamic_cast<EncryptedKey*>(*i);
80                     if (encKey) {
81                         try {
82                             key=decryptKey(encKey, algorithm);
83                         }
84                         catch (DecryptionException& e) {
85                             log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(e.what());
86                         }
87                     }
88                 }
89             }
90             
91             if (!key) {
92                 // Check for a non-trivial resolver.
93                 EncryptedKeyResolver* ekr=dynamic_cast<EncryptedKeyResolver*>(m_resolver);
94                 if (ekr) {
95                     EncryptedKey* encKey=ekr->resolveKey(encryptedData);
96                     if (encKey) {
97                         try {
98                             key=decryptKey(encKey, algorithm);
99                         }
100                         catch (DecryptionException& e) {
101                             log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(e.what());
102                         }
103                     }
104                 }
105             }
106         }
107
108         if (!key)
109             throw DecryptionException("Unable to resolve a decryption key.");
110         
111         m_cipher->setKey(key);
112         DOMNode* ret=m_cipher->decryptElementDetached(encryptedData->getDOM());
113         if (ret->getNodeType()!=DOMNode::DOCUMENT_FRAGMENT_NODE) {
114             ret->release();
115             throw DecryptionException("Decryption operation did not result in DocumentFragment.");
116         }
117         return static_cast<DOMDocumentFragment*>(ret);
118     }
119     catch(XSECException& e) {
120         auto_ptr_char temp(e.getMsg());
121         throw DecryptionException(string("XMLSecurity exception while decrypting: ") + temp.get());
122     }
123     catch(XSECCryptoException& e) {
124         throw DecryptionException(string("XMLSecurity exception while decrypting: ") + e.getMsg());
125     }
126 }
127
128 XSECCryptoKey* Decrypter::decryptKey(EncryptedKey* encryptedKey, const XMLCh* algorithm)
129 {
130     if (encryptedKey->getDOM()==NULL)
131         throw DecryptionException("The object must be marshalled before decryption.");
132     
133     // We can reuse the cipher object if the document hasn't changed.
134
135     if (m_cipher && m_cipher->getDocument()!=encryptedKey->getDOM()->getOwnerDocument()) {
136         XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
137         m_cipher=NULL;
138     }
139     
140     if (!m_cipher)
141         m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedKey->getDOM()->getOwnerDocument());
142     
143     try {
144         // Resolve key decryption key.
145         XSECCryptoKey* key=NULL;
146         if (m_KEKresolver)
147             key=m_KEKresolver->resolveKey(encryptedKey->getKeyInfo());
148         if (!key)
149             throw DecryptionException("Unable to resolve a key decryption key.");
150         m_cipher->setKEK(key);
151         
152         XMLByte buffer[1024];
153         int keySize = m_cipher->decryptKey(encryptedKey->getDOM(), buffer, 1024);
154         if (keySize > 0) {
155             // Try to map the key.
156             XSECAlgorithmHandler* handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithm);
157             if (handler != NULL)
158                 return handler->createKeyForURI(algorithm, buffer, keySize);
159             throw DecryptionException("Unrecognized algorithm, could not build object around decrypted key.");
160         }
161         throw DecryptionException("Unable to decrypt key.");
162     }
163     catch(XSECException& e) {
164         auto_ptr_char temp(e.getMsg());
165         throw DecryptionException(string("XMLSecurity exception while decrypting: ") + temp.get());
166     }
167     catch(XSECCryptoException& e) {
168         throw DecryptionException(string("XMLSecurity exception while decrypting: ") + e.getMsg());
169     }
170 }