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