New KeyResolver/Validator/Encrypter/Decrypter classes.
authorScott Cantor <cantor.2@osu.edu>
Sun, 11 Jun 2006 19:25:17 +0000 (19:25 +0000)
committerScott Cantor <cantor.2@osu.edu>
Sun, 11 Jun 2006 19:25:17 +0000 (19:25 +0000)
14 files changed:
xmltooling/Makefile.am
xmltooling/encryption/Decrypter.h [new file with mode: 0644]
xmltooling/encryption/Encrypter.h
xmltooling/encryption/impl/Decrypter.cpp [new file with mode: 0644]
xmltooling/encryption/impl/Encrypter.cpp
xmltooling/signature/KeyResolver.h [new file with mode: 0644]
xmltooling/signature/SignatureValidator.h
xmltooling/signature/impl/SignatureValidator.cpp
xmltooling/xmltooling.vcproj
xmltoolingtest/EncryptionTest.h [new file with mode: 0644]
xmltoolingtest/Makefile.am
xmltoolingtest/SignatureTest.h
xmltoolingtest/data/ComplexXMLObject.xml
xmltoolingtest/xmltoolingtest.vcproj

index 35c6017..64543ae 100644 (file)
@@ -41,6 +41,7 @@ libxmltoolinginclude_HEADERS = \
     XMLToolingConfig.h
 
 encinclude_HEADERS = \
     XMLToolingConfig.h
 
 encinclude_HEADERS = \
+       encryption/Decrypter.h \
        encryption/Encrypter.h \
     encryption/Encryption.h
 
        encryption/Encrypter.h \
     encryption/Encryption.h
 
@@ -55,6 +56,7 @@ ioinclude_HEADERS = \
 siginclude_HEADERS = \
     signature/ContentReference.h \
     signature/KeyInfo.h \
 siginclude_HEADERS = \
     signature/ContentReference.h \
     signature/KeyInfo.h \
+    signature/KeyResolver.h \
     signature/Signature.h \
     signature/SignatureValidator.h
 
     signature/Signature.h \
     signature/SignatureValidator.h
 
@@ -76,6 +78,7 @@ noinst_HEADERS = \
 
 if BUILD_XMLSEC
 xmlsec_sources = \
 
 if BUILD_XMLSEC
 xmlsec_sources = \
+    encryption/impl/Decrypter.cpp \
     encryption/impl/Encrypter.cpp \
        signature/impl/SignatureValidator.cpp \
     signature/impl/XMLSecSignatureImpl.cpp
     encryption/impl/Encrypter.cpp \
        signature/impl/SignatureValidator.cpp \
     signature/impl/XMLSecSignatureImpl.cpp
diff --git a/xmltooling/encryption/Decrypter.h b/xmltooling/encryption/Decrypter.h
new file mode 100644 (file)
index 0000000..19a245b
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ *  Copyright 2001-2006 Internet2
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Encrypter.h
+ * 
+ * Methods for encrypting XMLObjects and other data.
+ */
+
+#if !defined(__xmltooling_decrypter_h__) && !defined(XMLTOOLING_NO_XMLSEC)
+#define __xmltooling_decrypter_h__
+
+#include <xmltooling/encryption/Encryption.h>
+#include <xmltooling/signature/KeyResolver.h>
+
+#include <xsec/enc/XSECCryptoKey.hpp>
+#include <xsec/xenc/XENCCipher.hpp>
+
+namespace xmlencryption {
+
+    /**
+     * Wrapper API for XML Decryption functionality.
+     */
+    class XMLTOOL_API Decrypter
+    {
+    public:
+        /**
+         * Constructor.
+         * Resolvers will be deleted when Decrypter is.
+         * 
+         * @param KEKresolver   resolves key decryption key based on KeyInfo information 
+         * @param resolver      resolves data decryption key based on KeyInfo information 
+         */
+        Decrypter(xmlsignature::KeyResolver* KEKresolver=NULL, xmlsignature::KeyResolver* resolver=NULL)
+            : m_cipher(NULL), m_resolver(resolver), m_KEKresolver(KEKresolver) {
+        }
+
+        ~Decrypter();
+        
+        /**
+         * Replace the current KeyResolver interface, if any, with a new one.
+         * 
+         * @param resolver  the KeyResolver to attach 
+         */
+        void setKeyResolver(xmlsignature::KeyResolver* resolver) {
+            delete m_resolver;
+            m_resolver=resolver;
+        }
+
+        /**
+         * Replace the current key encryption KeyResolver interface, if any, with a new one.
+         * 
+         * @param resolver  the KeyResolver to attach 
+         */
+        void setKEKResolver(xmlsignature::KeyResolver* resolver) {
+            delete m_KEKresolver;
+            m_KEKresolver=resolver;
+        }
+
+        /**
+         * Decrypts the supplied information and returns the resulting as a DOM
+         * fragment owned by the document associated with the marshalled EncryptedData
+         * object.
+         * 
+         * Note that the DOM nodes will be invalidated once that document
+         * is released. The caller should therefore process the DOM fragment as
+         * required and drop all references to it before that happens. The usual
+         * approach should be to unmarshall the DOM and then release it, or the
+         * DOM can also be imported into a separately owned document.
+         * 
+         * @param encryptedData the encrypted data to decrypt
+         * @return  the decrypted DOM fragment
+         */
+        DOMDocumentFragment* decryptData(EncryptedData* encryptedData);
+        
+        /**
+         * Decrypts the supplied information and returns the resulting key.
+         * The caller is responsible for deleting the key. The algorithm of the
+         * key must be supplied by the caller based on knowledge of the associated
+         * EncryptedData information.
+         * 
+         * @param encryptedKey  the encrypted/wrapped key to decrypt
+         * @param algorithm     the algorithm associated with the decrypted key
+         * @return  the decrypted key
+         */
+        XSECCryptoKey* decryptKey(EncryptedKey* encryptedKey, const XMLCh* algorithm);
+        
+    private:
+        XENCCipher* m_cipher;
+        xmlsignature::KeyResolver* m_resolver;
+        xmlsignature::KeyResolver* m_KEKresolver;
+    };
+
+    DECL_XMLTOOLING_EXCEPTION(DecryptionException,XMLTOOL_EXCEPTIONAPI(XMLTOOL_API),xmlencryption,xmltooling::XMLToolingException,Exceptions in decryption processing);
+
+};
+
+#endif /* __xmltooling_decrypter_h__ */
index bb00268..63d2be7 100644 (file)
@@ -129,55 +129,61 @@ namespace xmlencryption {
         
         /**
          * Encrypts the supplied element and returns the resulting object.
         
         /**
          * Encrypts the supplied element and returns the resulting object.
-         * The returned object will be unmarshalled around a DOM tree created
-         * using the encrypted element's owning document.
          * 
          * If an encryption algorithm is set, but no key, a random key will be
          * 
          * If an encryption algorithm is set, but no key, a random key will be
-         * generated iff keParams is non-NULL and the algorithm is known.
+         * generated iff kencParams is non-NULL and the algorithm is known.
          * 
          * If key encryption parameters are supplied, then the encryption key
          * is wrapped and the result placed into an EncryptedKey object in the
          * KeyInfo of the returned EncryptedData.
          * 
          * 
          * If key encryption parameters are supplied, then the encryption key
          * is wrapped and the result placed into an EncryptedKey object in the
          * KeyInfo of the returned EncryptedData.
          * 
-         * @param element   the DOM element to encrypt
-         * @param keParams  key encryption settings, or NULL
+         * @param element       the DOM element to encrypt
+         * @param encParams     primary encryption settings
+         * @param kencParams    key encryption settings, or NULL
          */
         EncryptedData* encryptElement(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams=NULL);
 
         /**
          * Encrypts the supplied element's children and returns the resulting object.
          */
         EncryptedData* encryptElement(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams=NULL);
 
         /**
          * Encrypts the supplied element's children and returns the resulting object.
-         * The returned object will be unmarshalled around a DOM tree created
-         * using the encrypted content's owning document.
          * 
          * If an encryption algorithm is set, but no key, a random key will be
          * 
          * If an encryption algorithm is set, but no key, a random key will be
-         * generated iff keParams is non-NULL and the algorithm is known.
+         * generated iff kencParams is non-NULL and the algorithm is known.
 
          * If key encryption parameters are supplied, then the encryption key
          * is wrapped and the result placed into an EncryptedKey object in the
          * KeyInfo of the returned EncryptedData.
          * 
 
          * If key encryption parameters are supplied, then the encryption key
          * is wrapped and the result placed into an EncryptedKey object in the
          * KeyInfo of the returned EncryptedData.
          * 
-         * @param element   parent element of children to encrypt
-         * @param keParams  key encryption settings, or NULL
+         * @param element       parent element of children to encrypt
+         * @param encParams     primary encryption settings
+         * @param kencParams    key encryption settings, or NULL
          */
         EncryptedData* encryptElementContent(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams=NULL);
 
         /**
          * Encrypts the supplied input stream and returns the resulting object.
          */
         EncryptedData* encryptElementContent(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams=NULL);
 
         /**
          * Encrypts the supplied input stream and returns the resulting object.
-         * The returned object will be unmarshalled around a DOM tree created
-         * using the encrypted element's owning document.
          * 
          * If an encryption algorithm is set, but no key, a random key will be
          * 
          * If an encryption algorithm is set, but no key, a random key will be
-         * generated iff keParams is non-NULL and the algorithm is known.
+         * generated iff kencParams is non-NULL and the algorithm is known.
 
          * If key encryption parameters are supplied, then the encryption key
          * is wrapped and the result placed into an EncryptedKey object in the
          * KeyInfo of the returned EncryptedData.
          * 
 
          * If key encryption parameters are supplied, then the encryption key
          * is wrapped and the result placed into an EncryptedKey object in the
          * KeyInfo of the returned EncryptedData.
          * 
-         * @param input   the stream to encrypt
-         * @param keParams  key encryption settings, or NULL
+         * @param input         the stream to encrypt
+         * @param encParams     primary encryption settings
+         * @param kencParams    key encryption settings, or NULL
          */
         EncryptedData* encryptStream(std::istream& input, EncryptionParams& encParams, KeyEncryptionParams* kencParams=NULL);
         
          */
         EncryptedData* encryptStream(std::istream& input, EncryptionParams& encParams, KeyEncryptionParams* kencParams=NULL);
         
+        /**
+         * Encrypts the supplied key and returns the resulting object.
+         * 
+         * @param keyBuffer     raw key material to encrypt
+         * @param keyBufferSize size in bytes of raw key material
+         * @param kencParams    key encryption settings
+         */
+        EncryptedKey* encryptKey(const unsigned char* keyBuffer, unsigned int keyBufferSize, KeyEncryptionParams& kencParams);
+        
     private:
         void checkParams(EncryptionParams& encParams, KeyEncryptionParams* kencParams);
         EncryptedData* decorateAndUnmarshall(EncryptionParams& encParams, KeyEncryptionParams* kencParams);
     private:
         void checkParams(EncryptionParams& encParams, KeyEncryptionParams* kencParams);
         EncryptedData* decorateAndUnmarshall(EncryptionParams& encParams, KeyEncryptionParams* kencParams);
diff --git a/xmltooling/encryption/impl/Decrypter.cpp b/xmltooling/encryption/impl/Decrypter.cpp
new file mode 100644 (file)
index 0000000..0788761
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ *  Copyright 2001-2006 Internet2
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Encrypter.cpp
+ * 
+ * Methods for encrypting XMLObjects and other data.
+ */
+
+#include "internal.h"
+#include "encryption/Decrypter.h"
+
+#include <log4cpp/Category.hh>
+#include <xsec/enc/XSECCryptoException.hpp>
+#include <xsec/framework/XSECException.hpp>
+#include <xsec/framework/XSECAlgorithmMapper.hpp>
+#include <xsec/framework/XSECAlgorithmHandler.hpp>
+#include <xsec/xenc/XENCEncryptedData.hpp>
+#include <xsec/xenc/XENCEncryptedKey.hpp>
+
+using namespace xmlencryption;
+using namespace xmlsignature;
+using namespace xmltooling;
+using namespace std;
+
+Decrypter::~Decrypter()
+{
+    XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
+    delete m_resolver;
+    delete m_KEKresolver;
+}
+
+DOMDocumentFragment* Decrypter::decryptData(EncryptedData* encryptedData)
+{
+    if (encryptedData->getDOM()==NULL)
+        throw DecryptionException("The object must be marshalled before decryption.");
+    
+    // We can reuse the cipher object if the document hasn't changed.
+
+    if (m_cipher && m_cipher->getDocument()!=encryptedData->getDOM()->getOwnerDocument()) {
+        XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
+        m_cipher=NULL;
+    }
+    
+    if (!m_cipher)
+        m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedData->getDOM()->getOwnerDocument());
+    
+    try {
+        // Resolve decryption key.
+        XSECCryptoKey* key=NULL;
+        if (m_resolver)
+            key=m_resolver->resolveKey(encryptedData->getKeyInfo());
+        if (!key) {
+            // See if there's an encrypted key present. We'll need the algorithm...
+            const XMLCh* algorithm=
+                encryptedData->getEncryptionMethod() ? encryptedData->getEncryptionMethod()->getAlgorithm() : NULL;
+            if (!algorithm)
+                throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed.");
+            
+            if (encryptedData->getKeyInfo()) {
+                const vector<XMLObject*>& others=const_cast<const KeyInfo*>(encryptedData->getKeyInfo())->getOthers();
+                for (vector<XMLObject*>::const_iterator i=others.begin(); i!=others.end(); i++) {
+                    EncryptedKey* encKey=dynamic_cast<EncryptedKey*>(*i);
+                    if (encKey) {
+                        try {
+                            key=decryptKey(encKey, algorithm);
+                        }
+                        catch (DecryptionException& e) {
+                            log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(e.what());
+                        }
+                    }
+                }
+            }
+            
+            if (!key)
+                throw DecryptionException("Unable to resolve a decryption key.");
+        }
+        
+        m_cipher->setKey(key);
+        DOMNode* ret=m_cipher->decryptElementDetached(encryptedData->getDOM());
+        if (ret->getNodeType()!=DOMNode::DOCUMENT_FRAGMENT_NODE) {
+            ret->release();
+            throw DecryptionException("Decryption operation did not result in DocumentFragment.");
+        }
+        return static_cast<DOMDocumentFragment*>(ret);
+    }
+    catch(XSECException& e) {
+        auto_ptr_char temp(e.getMsg());
+        throw DecryptionException(string("XMLSecurity exception while decrypting: ") + temp.get());
+    }
+    catch(XSECCryptoException& e) {
+        throw DecryptionException(string("XMLSecurity exception while decrypting: ") + e.getMsg());
+    }
+}
+
+XSECCryptoKey* Decrypter::decryptKey(EncryptedKey* encryptedKey, const XMLCh* algorithm)
+{
+    if (encryptedKey->getDOM()==NULL)
+        throw DecryptionException("The object must be marshalled before decryption.");
+    
+    // We can reuse the cipher object if the document hasn't changed.
+
+    if (m_cipher && m_cipher->getDocument()!=encryptedKey->getDOM()->getOwnerDocument()) {
+        XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
+        m_cipher=NULL;
+    }
+    
+    if (!m_cipher)
+        m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedKey->getDOM()->getOwnerDocument());
+    
+    try {
+        // Resolve key decryption key.
+        XSECCryptoKey* key=NULL;
+        if (m_KEKresolver)
+            key=m_KEKresolver->resolveKey(encryptedKey->getKeyInfo());
+        if (!key)
+            throw DecryptionException("Unable to resolve a key decryption key.");
+        m_cipher->setKEK(key);
+        
+        XMLByte buffer[1024];
+        int keySize = m_cipher->decryptKey(encryptedKey->getDOM(), buffer, 1024);
+        if (keySize > 0) {
+            // Try to map the key.
+            XSECAlgorithmHandler* handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithm);
+            if (handler != NULL)
+                return handler->createKeyForURI(algorithm, buffer, keySize);
+            throw DecryptionException("Unrecognized algorithm, could not build object around decrypted key.");
+        }
+        throw DecryptionException("Unable to decrypt key.");
+    }
+    catch(XSECException& e) {
+        auto_ptr_char temp(e.getMsg());
+        throw DecryptionException(string("XMLSecurity exception while decrypting: ") + temp.get());
+    }
+    catch(XSECCryptoException& e) {
+        throw DecryptionException(string("XMLSecurity exception while decrypting: ") + e.getMsg());
+    }
+}
index 4f5b354..d4830cc 100644 (file)
 #include "internal.h"
 #include "encryption/Encrypter.h"
 
 #include "internal.h"
 #include "encryption/Encrypter.h"
 
-#include <xsec/enc/openssl/OpenSSLCryptoSymmetricKey.hpp>
 #include <xsec/enc/XSECCryptoException.hpp>
 #include <xsec/framework/XSECException.hpp>
 #include <xsec/enc/XSECCryptoException.hpp>
 #include <xsec/framework/XSECException.hpp>
+#include <xsec/framework/XSECAlgorithmMapper.hpp>
+#include <xsec/framework/XSECAlgorithmHandler.hpp>
 #include <xsec/xenc/XENCEncryptedData.hpp>
 #include <xsec/xenc/XENCEncryptedKey.hpp>
 
 #include <xsec/xenc/XENCEncryptedData.hpp>
 #include <xsec/xenc/XENCEncryptedKey.hpp>
 
@@ -61,22 +62,14 @@ void Encrypter::checkParams(EncryptionParams& encParams, KeyEncryptionParams* ke
     
     if (!encParams.m_key) {
         // We have to have a raw key now, so we need to build a wrapper around it.
     
     if (!encParams.m_key) {
         // We have to have a raw key now, so we need to build a wrapper around it.
-        if (XMLString::equals(encParams.m_algorithm,DSIGConstants::s_unicodeStrURI3DES_CBC)) {
-            encParams.m_key=new OpenSSLCryptoSymmetricKey(XSECCryptoSymmetricKey::KEY_3DES_192);
-        }
-        else if (XMLString::equals(encParams.m_algorithm,DSIGConstants::s_unicodeStrURIAES128_CBC)) {
-            encParams.m_key=new OpenSSLCryptoSymmetricKey(XSECCryptoSymmetricKey::KEY_AES_128);
-        }
-        else if (XMLString::equals(encParams.m_algorithm,DSIGConstants::s_unicodeStrURIAES192_CBC)) {
-            encParams.m_key=new OpenSSLCryptoSymmetricKey(XSECCryptoSymmetricKey::KEY_AES_192);
-        }
-        else if (XMLString::equals(encParams.m_algorithm,DSIGConstants::s_unicodeStrURIAES256_CBC)) {
-            encParams.m_key=new OpenSSLCryptoSymmetricKey(XSECCryptoSymmetricKey::KEY_AES_256);
-        }
-        else {
-            throw EncryptionException("Unrecognized encryption algorithm, unable to build key wrapper.");
-        }
-        static_cast<OpenSSLCryptoSymmetricKey*>(encParams.m_key)->setKey(encParams.m_keyBuffer, encParams.m_keyBufferSize);
+        XSECAlgorithmHandler* handler =XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(encParams.m_algorithm);
+        if (handler != NULL)
+            encParams.m_key = handler->createKeyForURI(
+                encParams.m_algorithm,const_cast<unsigned char*>(encParams.m_keyBuffer),encParams.m_keyBufferSize
+                );
+
+        if (!encParams.m_key)
+            throw EncryptionException("Unable to build wrapper for key, unknown algorithm?");
     }
     
     // Set the encryption key.
     }
     
     // Set the encryption key.
@@ -222,3 +215,51 @@ EncryptedData* Encrypter::decorateAndUnmarshall(EncryptionParams& encParams, Key
     xmlObject.release();
     return xmlEncData;
 }
     xmlObject.release();
     return xmlEncData;
 }
+
+EncryptedKey* Encrypter::encryptKey(const unsigned char* keyBuffer, unsigned int keyBufferSize, KeyEncryptionParams& kencParams)
+{
+    // Get a fresh cipher object and document.
+
+    if (m_cipher) {
+        XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
+        m_cipher=NULL;
+    }
+    
+    DOMDocument* doc=NULL;
+    try {
+        doc=XMLToolingConfig::getConfig().getParser().newDocument();
+        m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(doc);
+        m_cipher->setKEK(kencParams.m_key->clone());
+        auto_ptr<XENCEncryptedKey> encKey(m_cipher->encryptKey(keyBuffer, keyBufferSize, ENCRYPT_NONE, kencParams.m_algorithm));
+        
+        EncryptedKey* xmlEncKey=NULL;
+        auto_ptr<XMLObject> xmlObjectKey(XMLObjectBuilder::buildOneFromElement(encKey->getElement()));
+        if (!(xmlObjectKey.get()) || !(xmlEncKey=dynamic_cast<EncryptedKey*>(xmlObjectKey.get())))
+            throw EncryptionException("Unable to unmarshall into EncryptedKey object.");
+        
+        xmlEncKey->releaseThisAndChildrenDOM();
+        
+        // KeyInfo?
+        if (kencParams.m_keyInfo) {
+            xmlEncKey->setKeyInfo(kencParams.m_keyInfo);
+            kencParams.m_keyInfo=NULL;   // transfer ownership
+        }
+
+        doc->release();
+        xmlObjectKey.release();
+        return xmlEncKey;
+    }
+    catch(XSECException& e) {
+        doc->release();
+        auto_ptr_char temp(e.getMsg());
+        throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
+    }
+    catch(XSECCryptoException& e) {
+        doc->release();
+        throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
+    }
+    catch (...) {
+        doc->release();
+        throw;
+    }
+}
diff --git a/xmltooling/signature/KeyResolver.h b/xmltooling/signature/KeyResolver.h
new file mode 100644 (file)
index 0000000..cf318be
--- /dev/null
@@ -0,0 +1,88 @@
+/*\r
+ *  Copyright 2001-2006 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/**\r
+ * @file KeyResolver.h\r
+ * \r
+ * Resolves keys based on KeyInfo information or other external factors. \r
+ */\r
+\r
+#if !defined(__xmltooling_keyres_h__) && !defined(XMLTOOLING_NO_XMLSEC)\r
+#define __xmltooling_keyres_h__\r
+\r
+#include <xmltooling/signature/KeyInfo.h>\r
+\r
+#include <xsec/dsig/DSIGKeyInfoList.hpp>\r
+#include <xsec/enc/XSECCryptoKey.hpp>\r
+\r
+namespace xmlsignature {\r
+\r
+    /**\r
+     * An API for resolving decryption keys.\r
+     * Can be used during both data and key decryption.\r
+     */\r
+    class XMLTOOL_API KeyResolver {\r
+    public:\r
+        /**\r
+         * Constructor based on a single externally supplied decryption key.\r
+         * The key will be destroyed when the resolver is. \r
+         * \r
+         * @param key   external decryption key\r
+         */\r
+        KeyResolver(XSECCryptoKey* key=NULL) : m_key(key) {}\r
+        \r
+        virtual ~KeyResolver() {\r
+            delete m_key;\r
+        }\r
+        \r
+        /**\r
+         * Returns a key based on the supplied KeyInfo information.\r
+         * The caller must delete the key when done with it.\r
+         * \r
+         * @param keyInfo   the key information\r
+         * @return  the resolved key\r
+         */\r
+        virtual XSECCryptoKey* resolveKey(KeyInfo* keyInfo) {\r
+            return m_key ? m_key->clone() : NULL;\r
+        }\r
+\r
+        /**\r
+         * Returns a key based on the supplied KeyInfo information.\r
+         * The caller must delete the key when done with it.\r
+         * \r
+         * @param keyInfo   the key information\r
+         * @return  the resolved key\r
+         */\r
+        virtual XSECCryptoKey* resolveKey(DSIGKeyInfoList* keyInfo=NULL) {\r
+            return m_key ? m_key->clone() : NULL;\r
+        }\r
+        \r
+        /**\r
+         * Creates a copy of the resolver.\r
+         * \r
+         * @return the cloned resolver\r
+         */\r
+        virtual KeyResolver* clone() const {\r
+            return new KeyResolver(m_key ? m_key->clone() : NULL);\r
+        }\r
+        \r
+    protected:\r
+        XSECCryptoKey* m_key;\r
+    };\r
+\r
+};\r
+\r
+#endif /* __xmltooling_keyres_h__ */\r
index 6a09ef4..4dc362a 100644 (file)
 #if !defined(__xmltooling_sigval_h__) && !defined(XMLTOOLING_NO_XMLSEC)\r
 #define __xmltooling_sigval_h__\r
 \r
 #if !defined(__xmltooling_sigval_h__) && !defined(XMLTOOLING_NO_XMLSEC)\r
 #define __xmltooling_sigval_h__\r
 \r
+#include <xmltooling/signature/KeyResolver.h>\r
 #include <xmltooling/signature/Signature.h>\r
 #include <xmltooling/validation/Validator.h>\r
 \r
 namespace xmlsignature {\r
 \r
     /**\r
 #include <xmltooling/signature/Signature.h>\r
 #include <xmltooling/validation/Validator.h>\r
 \r
 namespace xmlsignature {\r
 \r
     /**\r
-     * Validator for signatures based on an externally-supplied key.\r
+     * Validator for signatures based on a KeyResolver\r
      */\r
     class XMLTOOL_API SignatureValidator : public virtual xmltooling::Validator\r
     {\r
      */\r
     class XMLTOOL_API SignatureValidator : public virtual xmltooling::Validator\r
     {\r
@@ -37,15 +38,13 @@ namespace xmlsignature {
         /**\r
          * Constructor\r
          * \r
         /**\r
          * Constructor\r
          * \r
-         * @param key   the verification key to use, will be freed by Validator\r
+         * @param resolver   the key resolver to use, will be freed by Validator\r
          */\r
          */\r
-        SignatureValidator(XSECCryptoKey* key) : m_key(key) {\r
-            if (!key)\r
-                throw xmltooling::ValidationException("Verification key cannot be NULL.");\r
+        SignatureValidator(KeyResolver* resolver) : m_resolver(resolver) {\r
         }\r
         \r
         virtual ~SignatureValidator() {\r
         }\r
         \r
         virtual ~SignatureValidator() {\r
-            delete m_key;\r
+            delete m_resolver;\r
         }\r
 \r
         void validate(const xmltooling::XMLObject* xmlObject) const;\r
         }\r
 \r
         void validate(const xmltooling::XMLObject* xmlObject) const;\r
@@ -55,14 +54,23 @@ namespace xmlsignature {
         SignatureValidator* clone() const {\r
             return new SignatureValidator(*this);\r
         }\r
         SignatureValidator* clone() const {\r
             return new SignatureValidator(*this);\r
         }\r
+\r
+        /**\r
+         * Replace the current KeyResolver, if any, with a new one.\r
+         * \r
+         * @param resolver  the KeyResolver to attach \r
+         */\r
+        void setKeyResolver(KeyResolver* resolver) {\r
+            delete m_resolver;\r
+            m_resolver=resolver;\r
+        }\r
     \r
     protected:\r
         SignatureValidator(const SignatureValidator& src) {\r
     \r
     protected:\r
         SignatureValidator(const SignatureValidator& src) {\r
-            m_key=src.m_key->clone();\r
+            m_resolver=src.m_resolver ? src.m_resolver->clone() : NULL;\r
         }\r
 \r
         }\r
 \r
-    private:\r
-        XSECCryptoKey* m_key;\r
+        KeyResolver* m_resolver;\r
     };\r
 \r
 };\r
     };\r
 \r
 };\r
index e6b1cec..ab41546 100644 (file)
@@ -43,9 +43,14 @@ void SignatureValidator::validate(const Signature* sigObj) const
     DSIGSignature* sig=sigObj->getXMLSignature();\r
     if (!sig)\r
         throw ValidationException("Signature does not exist yet.");\r
     DSIGSignature* sig=sigObj->getXMLSignature();\r
     if (!sig)\r
         throw ValidationException("Signature does not exist yet.");\r
+    else if (!m_resolver)\r
+        throw ValidationException("No KeyResolver set on Validator.");\r
 \r
     try {\r
 \r
     try {\r
-        sig->setSigningKey(m_key->clone());\r
+        XSECCryptoKey* key=m_resolver->resolveKey(sig->getKeyInfoList());\r
+        if (!key)\r
+            throw ValidationException("Unable to resolve signing key.");\r
+        sig->setSigningKey(key);\r
         if (!sig->verify())\r
             throw ValidationException("Digital signature does not validate with the given key.");\r
     }\r
         if (!sig->verify())\r
             throw ValidationException("Digital signature does not validate with the given key.");\r
     }\r
index b6d71f5..54a48c3 100644 (file)
                                        Name="impl"\r
                                        >\r
                                        <File\r
                                        Name="impl"\r
                                        >\r
                                        <File\r
+                                               RelativePath=".\encryption\impl\Decrypter.cpp"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
                                                RelativePath=".\encryption\impl\Encrypter.cpp"\r
                                                >\r
                                        </File>\r
                                                RelativePath=".\encryption\impl\Encrypter.cpp"\r
                                                >\r
                                        </File>\r
                                        >\r
                                </File>\r
                                <File\r
                                        >\r
                                </File>\r
                                <File\r
+                                       RelativePath=".\signature\KeyResolver.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
                                        RelativePath=".\signature\Signature.h"\r
                                        >\r
                                </File>\r
                                        RelativePath=".\signature\Signature.h"\r
                                        >\r
                                </File>\r
                                Name="encryption"\r
                                >\r
                                <File\r
                                Name="encryption"\r
                                >\r
                                <File\r
+                                       RelativePath=".\encryption\Decrypter.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
                                        RelativePath=".\encryption\Encrypter.h"\r
                                        >\r
                                </File>\r
                                        RelativePath=".\encryption\Encrypter.h"\r
                                        >\r
                                </File>\r
diff --git a/xmltoolingtest/EncryptionTest.h b/xmltoolingtest/EncryptionTest.h
new file mode 100644 (file)
index 0000000..cff6670
--- /dev/null
@@ -0,0 +1,117 @@
+/*\r
+ *  Copyright 2001-2005 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#include "XMLObjectBaseTestCase.h"\r
+\r
+#include <xmltooling/encryption/Decrypter.h>\r
+#include <xmltooling/encryption/Encrypter.h>\r
+\r
+#include <fstream>\r
+#include <openssl/pem.h>\r
+#include <xercesc/util/XMLUniDefs.hpp>\r
+#include <xsec/dsig/DSIGReference.hpp>\r
+#include <xsec/enc/XSECKeyInfoResolverDefault.hpp>\r
+#include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>\r
+#include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>\r
+#include <xsec/enc/XSECCryptoException.hpp>\r
+#include <xsec/framework/XSECException.hpp>\r
+\r
+using namespace xmlencryption;\r
+\r
+class _addcert : public std::binary_function<X509Data*,XSECCryptoX509*,void> {\r
+public:\r
+    void operator()(X509Data* bag, XSECCryptoX509* cert) const {\r
+        safeBuffer& buf=cert->getDEREncodingSB();\r
+        X509Certificate* x=X509CertificateBuilder::buildX509Certificate();\r
+        x->setValue(buf.sbStrToXMLCh());\r
+        bag->getX509Certificates().push_back(x);\r
+    }\r
+};\r
+\r
+class EncryptionTest : public CxxTest::TestSuite {\r
+    XSECCryptoKey* m_key;\r
+    vector<XSECCryptoX509*> m_certs;\r
+public:\r
+    void setUp() {\r
+        string keypath=data_path + "key.pem";\r
+        BIO* in=BIO_new(BIO_s_file_internal());\r
+        if (in && BIO_read_filename(in,keypath.c_str())>0) {\r
+            EVP_PKEY* pkey=PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);\r
+            if (pkey) {\r
+                m_key=new OpenSSLCryptoKeyRSA(pkey);\r
+                EVP_PKEY_free(pkey);\r
+            }\r
+        }\r
+        if (in) BIO_free(in);\r
+        TS_ASSERT(m_key!=NULL);\r
+\r
+        string certpath=data_path + "cert.pem";\r
+        in=BIO_new(BIO_s_file_internal());\r
+        if (in && BIO_read_filename(in,certpath.c_str())>0) {\r
+            X509* x=NULL;\r
+            while (x=PEM_read_bio_X509(in,NULL,NULL,NULL)) {\r
+                m_certs.push_back(new OpenSSLCryptoX509(x));\r
+                X509_free(x);\r
+            }\r
+        }\r
+        if (in) BIO_free(in);\r
+        TS_ASSERT(m_certs.size()>0);\r
+        \r
+    }\r
+\r
+    void tearDown() {\r
+        delete m_key;\r
+        for_each(m_certs.begin(),m_certs.end(),xmltooling::cleanup<XSECCryptoX509>());\r
+    }\r
+\r
+    void testBasic() {\r
+        TS_TRACE("testBasic");\r
+\r
+        string path=data_path + "ComplexXMLObject.xml";\r
+        ifstream fs(path.c_str());\r
+        DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(fs);\r
+        TS_ASSERT(doc!=NULL);\r
+\r
+        try {\r
+            Encrypter encrypter;\r
+            Encrypter::EncryptionParams ep;\r
+            Encrypter::KeyEncryptionParams kep(DSIGConstants::s_unicodeStrURIRSA_1_5,m_key->clone());\r
+            auto_ptr<EncryptedData> encData(encrypter.encryptElement(doc->getDocumentElement(),ep,&kep));\r
+\r
+            string buf;\r
+            XMLHelper::serialize(encData->marshall(), buf);\r
+            istringstream is(buf);\r
+            DOMDocument* doc2=XMLToolingConfig::getConfig().getValidatingParser().parse(is);\r
+            auto_ptr<EncryptedData> encData2(\r
+                dynamic_cast<EncryptedData*>(XMLObjectBuilder::buildOneFromElement(doc2->getDocumentElement(),true))\r
+                );\r
+\r
+            Decrypter decrypter(new KeyResolver(m_key->clone()));\r
+            DOMDocumentFragment* frag = decrypter.decryptData(encData2.get());\r
+            XMLHelper::serialize(static_cast<DOMElement*>(frag->getFirstChild()), buf);\r
+            TS_TRACE(buf.c_str());\r
+            TS_ASSERT(doc->getDocumentElement()->isEqualNode(frag->getFirstChild()));\r
+            frag->release();\r
+            doc->release();\r
+        }\r
+        catch (XMLToolingException& e) {\r
+            TS_TRACE(e.what());\r
+            doc->release();\r
+            throw;\r
+        }\r
+    }\r
+\r
+};\r
index d8cd904..69538ec 100644 (file)
@@ -9,6 +9,7 @@ endif
 
 if BUILD_XMLSEC
 xmlsec_sources = \
 
 if BUILD_XMLSEC
 xmlsec_sources = \
+    EncryptionTest.h \
     SignatureTest.h
 else
 xmlsec_sources =
     SignatureTest.h
 else
 xmlsec_sources =
index c3cd9bb..458fa7e 100644 (file)
@@ -57,7 +57,7 @@ class TestValidator : public SignatureValidator
     }\r
 \r
 public:\r
     }\r
 \r
 public:\r
-    TestValidator(const XMLCh* uri, XSECCryptoKey* key) : SignatureValidator(key) {\r
+    TestValidator(const XMLCh* uri, XSECCryptoKey* key) : SignatureValidator(new KeyResolver(key)) {\r
         m_uri=XMLString::replicate(uri);\r
     }\r
     \r
         m_uri=XMLString::replicate(uri);\r
     }\r
     \r
index 4cb5799..3951644 100644 (file)
@@ -1,27 +1,21 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <products>
 <?xml version="1.0" encoding="UTF-8"?>
 <products>
-    <product id="1144"
-        xmlns="http://example.com/product-info"
-        xmlns:html="http://www.w3.org/1999/xhtml"
-        >
+    <product id="1144" xmlns="http://example.com/product-info">
         <name xml:lang="en">Python Perfect IDE</name>
         <description>
             Uses mind-reading technology to anticipate and accommodate
             all user needs in Python development.  Implements all
         <name xml:lang="en">Python Perfect IDE</name>
         <description>
             Uses mind-reading technology to anticipate and accommodate
             all user needs in Python development.  Implements all
-            <html:code>from __future__ import</html:code> features though
+            <html:code xmlns:html="http://www.w3.org/1999/xhtml">from __future__ import</html:code> features though
             the year 3000.  Works well with <code>1166</code>.
         </description>
     </product>
     <p:product id="1166" xmlns:p="http://example.com/product-info">
         <p:name>XSLT Perfect IDE</p:name>
             the year 3000.  Works well with <code>1166</code>.
         </description>
     </product>
     <p:product id="1166" xmlns:p="http://example.com/product-info">
         <p:name>XSLT Perfect IDE</p:name>
-        <p:description
-            xmlns:html="http://www.w3.org/1999/xhtml"
-            xmlns:xl="http://www.w3.org/1999/xlink"
-            >
+        <p:description>
             <p:code>red</p:code>
             <p:code>red</p:code>
-            <html:code>blue</html:code>
-            <html:div>
-                <ref xl:type="simple" xl:href="index.xml">A link</ref>
+            <html:code xmlns:html="http://www.w3.org/1999/xhtml">blue</html:code>
+            <html:div xmlns:html="http://www.w3.org/1999/xhtml">
+                <ref xmlns:xl="http://www.w3.org/1999/xlink" xl:type="simple" xl:href="index.xml">A link</ref>
             </html:div>
         </p:description>
     </p:product>
             </html:div>
         </p:description>
     </p:product>
index 5b5b146..02de35a 100644 (file)
                                >\r
                        </File>\r
                        <File\r
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath=".\EncryptionTest.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath=".\ExceptionTest.cpp"\r
                                >\r
                        </File>\r
                                RelativePath=".\ExceptionTest.cpp"\r
                                >\r
                        </File>\r
                                </FileConfiguration>\r
                        </File>\r
                        <File\r
                                </FileConfiguration>\r
                        </File>\r
                        <File\r
+                               RelativePath=".\EncryptionTest.h"\r
+                               >\r
+                               <FileConfiguration\r
+                                       Name="Debug|Win32"\r
+                                       >\r
+                                       <Tool\r
+                                               Name="VCCustomBuildTool"\r
+                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;"\r
+                                               Outputs="&quot;$(InputName)&quot;.cpp"\r
+                                       />\r
+                               </FileConfiguration>\r
+                               <FileConfiguration\r
+                                       Name="Release|Win32"\r
+                                       >\r
+                                       <Tool\r
+                                               Name="VCCustomBuildTool"\r
+                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;"\r
+                                               Outputs="&quot;$(InputName)&quot;.cpp"\r
+                                       />\r
+                               </FileConfiguration>\r
+                       </File>\r
+                       <File\r
                                RelativePath=".\ExceptionTest.h"\r
                                >\r
                                <FileConfiguration\r
                                RelativePath=".\ExceptionTest.h"\r
                                >\r
                                <FileConfiguration\r