Credential resolver plugin
authorScott Cantor <cantor.2@osu.edu>
Mon, 24 Jul 2006 04:05:07 +0000 (04:05 +0000)
committerScott Cantor <cantor.2@osu.edu>
Mon, 24 Jul 2006 04:05:07 +0000 (04:05 +0000)
18 files changed:
configure.ac
xmltooling/Makefile.am
xmltooling/PluginManager.h
xmltooling/XMLToolingConfig.cpp
xmltooling/XMLToolingConfig.h
xmltooling/internal.h
xmltooling/signature/CredentialResolver.h [new file with mode: 0644]
xmltooling/signature/KeyResolver.h
xmltooling/signature/OpenSSLCredentialResolver.h [new file with mode: 0644]
xmltooling/signature/impl/CredentialResolver.cpp [new file with mode: 0644]
xmltooling/signature/impl/FilesystemCredentialResolver.cpp [new file with mode: 0644]
xmltooling/util/XMLHelper.cpp
xmltooling/util/XMLHelper.h
xmltooling/xmltooling.vcproj
xmltoolingtest/FilesystemCredentialResolverTest.h [new file with mode: 0644]
xmltoolingtest/Makefile.am
xmltoolingtest/data/FilesystemCredentialResolver.xml [new file with mode: 0644]
xmltoolingtest/xmltoolingtest.vcproj

index d6c5eb2..8fdc692 100644 (file)
@@ -73,7 +73,7 @@ fi
 AC_ARG_WITH(openssl,
     AC_HELP_STRING([--with-openssl=PATH], [where openssl is installed]),
     [if test x_$with_openssl != x_/usr; then
-        SSLLIBS="-L${with_openssl}/lib -lcrypto"
+        SSLLIBS="-L${with_openssl}/lib -lcrypto -lssl"
         SSLFLAGS="-I${with_openssl}/include"
     fi])
 
@@ -90,7 +90,7 @@ if test "x$SSLLIBS" = "x" ; then
 fi
 
 if test "x$SSLLIBS" = "x" ; then
-    SSLLIBS="-lcrypto"
+    SSLLIBS="-lcrypto -lssl"
 fi
 
 AC_MSG_CHECKING(for OpenSSL libraries)
index 71dd110..cdcd8b6 100644 (file)
@@ -56,8 +56,10 @@ ioinclude_HEADERS = \
 
 siginclude_HEADERS = \
        signature/ContentReference.h \
+       signature/CredentialResolver.h \
        signature/KeyInfo.h \
        signature/KeyResolver.h \
+       signature/OpenSSLCredentialResolver.h \
        signature/Signature.h \
        signature/SignatureValidator.h
 
@@ -81,6 +83,8 @@ if BUILD_XMLSEC
 xmlsec_sources = \
        encryption/impl/Decrypter.cpp \
        encryption/impl/Encrypter.cpp \
+       signature/impl/CredentialResolver.cpp \
+       signature/impl/FilesystemCredentialResolver.cpp \
        signature/impl/SignatureValidator.cpp \
        signature/impl/XMLSecSignatureImpl.cpp
 else
index e1add0e..67323c8 100644 (file)
@@ -69,9 +69,15 @@ namespace xmltooling {
          * @param type  the name of the plugin type\r
          */\r
         void deregisterFactory(const char* type) {\r
-            if (type) {\r
+            if (type)\r
                 m_map.erase(type);\r
-            }\r
+        }\r
+\r
+        /**\r
+         * Unregisters all registered factories.\r
+         */\r
+        void deregisterFactories() {\r
+            m_map.clear();\r
         }\r
 \r
         /**\r
index b22b664..a5a4e3b 100644 (file)
@@ -25,6 +25,7 @@
 #include "XMLToolingConfig.h"
 #include "encryption/Encryption.h"
 #include "impl/UnknownElement.h"
+#include "signature/CredentialResolver.h"
 #include "signature/KeyInfo.h"
 #include "signature/Signature.h"
 #include "util/NDC.h"
 # include <dlfcn.h>
 #endif
 
+#include <stdexcept>
 #include <log4cpp/Category.hh>
 #include <log4cpp/PropertyConfigurator.hh>
 #include <log4cpp/OstreamAppender.hh>
 #include <xercesc/util/PlatformUtils.hpp>
 #ifndef XMLTOOLING_NO_XMLSEC
     #include <xsec/framework/XSECProvider.hpp>
+    #include <openssl/err.h>
 #endif
 
-#include <stdexcept>
-
 using namespace xmlencryption;
 using namespace xmlsignature;
 using namespace xmltooling;
@@ -176,6 +177,7 @@ bool XMLToolingInternalConfig::init()
 #ifndef XMLTOOLING_NO_XMLSEC
         XMLObjectBuilder::registerBuilder(QName(XMLConstants::XMLSIG_NS,Signature::LOCAL_NAME),new SignatureBuilder());
         REGISTER_EXCEPTION_FACTORY(SignatureException,xmlsignature);
+        registerCredentialResolvers();
 #endif
     }
     catch (const xercesc::XMLException&) {
@@ -194,6 +196,11 @@ void XMLToolingInternalConfig::term()
     EncryptionSchemaValidators.destroyValidators();
     XMLToolingException::deregisterFactories();
 
+#ifndef XMLTOOLING_NO_XMLSEC
+    CredentialResolverManager.deregisterFactories();
+    KeyResolverManager.deregisterFactories();
+#endif
+
     for (vector<void*>::reverse_iterator i=m_libhandles.rbegin(); i!=m_libhandles.rend(); i++) {
 #if defined(WIN32)
         FARPROC fn=GetProcAddress(static_cast<HMODULE>(*i),"xmltooling_extension_term");
@@ -318,3 +325,21 @@ bool XMLToolingInternalConfig::load_library(const char* path, void* context)
     log.info("loaded extension: %s", path);
     return true;
 }
+
+#ifndef XMLTOOLING_NO_XMLSEC
+void xmltooling::log_openssl()
+{
+    const char* file;
+    const char* data;
+    int flags,line;
+
+    unsigned long code=ERR_get_error_line_data(&file,&line,&data,&flags);
+    while (code) {
+        Category& log=Category::getInstance("OpenSSL");
+        log.errorStream() << "error code: " << code << " in " << file << ", line " << line << CategoryStream::ENDLINE;
+        if (data && (flags & ERR_TXT_STRING))
+            log.errorStream() << "error data: " << data << CategoryStream::ENDLINE;
+        code=ERR_get_error_line_data(&file,&line,&data,&flags);
+    }
+}
+#endif
index 5241fe4..e2845b8 100644 (file)
 #define __xmltooling_config_h__\r
 \r
 #include <xmltooling/Lockable.h>\r
+#include <xmltooling/PluginManager.h>\r
 #include <xmltooling/util/ParserPool.h>\r
 \r
+#ifndef XMLTOOLING_NO_XMLSEC\r
+namespace xmlsignature {\r
+    class XMLTOOL_API CredentialResolver;\r
+    class XMLTOOL_API KeyResolver;\r
+};\r
+#endif\r
+\r
+#if defined (_MSC_VER)\r
+    #pragma warning( push )\r
+    #pragma warning( disable : 4251 )\r
+#endif\r
+\r
 namespace xmltooling {\r
 \r
     /**\r
@@ -110,10 +123,26 @@ namespace xmltooling {
          */\r
         virtual ParserPool& getValidatingParser() const=0;\r
 \r
+#ifndef XMLTOOLING_NO_XMLSEC\r
+        /**\r
+         * Manages factories for KeyResolver plugins.\r
+         */\r
+        xmltooling::PluginManager<xmlsignature::KeyResolver,const DOMElement*> KeyResolverManager;\r
+\r
+        /**\r
+         * Manages factories for CredentialResolver plugins.\r
+         */\r
+        xmltooling::PluginManager<xmlsignature::CredentialResolver,const DOMElement*> CredentialResolverManager;\r
+#endif\r
+\r
     protected:\r
         XMLToolingConfig() {}\r
     };\r
 \r
 };\r
 \r
+#if defined (_MSC_VER)\r
+    #pragma warning( pop )\r
+#endif\r
+\r
 #endif /* __xmltooling_config_h__ */\r
index 49b1a35..1ddd193 100644 (file)
@@ -92,6 +92,11 @@ namespace xmltooling {
         ParserPool* m_parserPool;
         ParserPool* m_validatingPool;
     };
+    
+#ifndef XMLTOOLING_NO_XMLSEC
+    void log_openssl();
+#endif
+    
     /// @endcond
 
 };
diff --git a/xmltooling/signature/CredentialResolver.h b/xmltooling/signature/CredentialResolver.h
new file mode 100644 (file)
index 0000000..f955f37
--- /dev/null
@@ -0,0 +1,72 @@
+/*\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 xmltooling/signature/CredentialResolver.h\r
+ * \r
+ * Resolves keys and certificates "owned" by an entity \r
+ */\r
+\r
+#if !defined(__xmltooling_credres_h__) && !defined(XMLTOOLING_NO_XMLSEC)\r
+#define __xmltooling_credres_h__\r
+\r
+#include <xmltooling/Lockable.h>\r
+\r
+#include <vector>\r
+#include <xsec/enc/XSECCryptoKey.hpp>\r
+#include <xsec/enc/XSECCryptoX509.hpp>\r
+\r
+namespace xmlsignature {\r
+\r
+    /**\r
+     * An API for resolving local/owned keys and certificates\r
+     */\r
+    class XMLTOOL_API CredentialResolver : public xmltooling::Lockable\r
+    {\r
+        MAKE_NONCOPYABLE(CredentialResolver);\r
+    protected:\r
+        CredentialResolver() {}\r
+        \r
+    public:\r
+        virtual ~CredentialResolver() {}\r
+        \r
+        /**\r
+         * Returns a secret or private key to use for signing operations.\r
+         * The caller is responsible for deleting the key when finished with it.\r
+         * \r
+         * @return  a secret or private key\r
+         */\r
+        virtual XSECCryptoKey* getKey() const=0;\r
+        \r
+        /**\r
+         * Returns a set of certificates to publish during signing operations.\r
+         * The certificates must be cloned if kept beyond the scope of a lock.\r
+         * \r
+         * @return  a set of certificates\r
+         */\r
+        virtual const std::vector<XSECCryptoX509*>& getCertificates() const=0;\r
+    };\r
+\r
+    /**\r
+     * Registers CredentialResolver classes into the runtime.\r
+     */\r
+    void XMLTOOL_API registerCredentialResolvers();\r
+\r
+    /** CredentialResolver based on local files */\r
+    #define FILESYSTEM_CREDENTIAL_RESOLVER  "org.opensaml.xmlooling.FilesystemCredentialResolver"\r
+};\r
+\r
+#endif /* __xmltooling_credres_h__ */\r
index 7d060c6..2c88250 100644 (file)
@@ -34,6 +34,7 @@ namespace xmlsignature {
      * An API for resolving keys.\r
      */\r
     class XMLTOOL_API KeyResolver {\r
+        MAKE_NONCOPYABLE(KeyResolver);\r
     public:\r
         /**\r
          * Constructor based on a single externally supplied key.\r
@@ -69,15 +70,6 @@ namespace xmlsignature {
             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
diff --git a/xmltooling/signature/OpenSSLCredentialResolver.h b/xmltooling/signature/OpenSSLCredentialResolver.h
new file mode 100644 (file)
index 0000000..e119380
--- /dev/null
@@ -0,0 +1,54 @@
+/*\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 xmltooling/signature/OpenSSLCredentialResolver.h\r
+ * \r
+ * OpenSSL-specific credential resolver\r
+ */\r
+\r
+#if !defined(__xmltooling_opensslcredres_h__) && !defined(XMLTOOLING_NO_XMLSEC)\r
+#define __xmltooling_opensslcredres_h__\r
+\r
+#include <xmltooling/signature/CredentialResolver.h>\r
+\r
+#include <openssl/ssl.h>\r
+\r
+namespace xmlsignature {\r
+\r
+    /**\r
+     * An OpenSSL-specific API for resolving local/owned keys and certificates\r
+     */\r
+    class XMLTOOL_API OpenSSLCredentialResolver : public CredentialResolver\r
+    {\r
+    protected:\r
+        OpenSSLCredentialResolver() {}\r
+        \r
+    public:\r
+        virtual ~OpenSSLCredentialResolver() {}\r
+        \r
+        /**\r
+         * Attaches credentials to an OpenSSL SSL context object.\r
+         * The resolver is unlockable after attachment.\r
+         * \r
+         * @param ctx   an SSL context\r
+         */\r
+        virtual void attach(SSL_CTX* ctx) const=0;\r
+    };\r
+\r
+};\r
+\r
+#endif /* __xmltooling_opensslcredres_h__ */\r
diff --git a/xmltooling/signature/impl/CredentialResolver.cpp b/xmltooling/signature/impl/CredentialResolver.cpp
new file mode 100644 (file)
index 0000000..9da33d3
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *  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.
+ */
+
+/**
+ * CredentialResolver.cpp
+ * 
+ * Registration of factories for built-in resolvers
+ */
+
+#include "internal.h"
+#include "signature/CredentialResolver.h"
+
+using namespace xmlsignature;
+using namespace xmltooling;
+
+namespace xmlsignature {
+    XMLTOOL_DLLLOCAL PluginManager<CredentialResolver,const DOMElement*>::Factory FilesystemCredentialResolverFactory; 
+};
+
+void XMLTOOL_API xmlsignature::registerCredentialResolvers()
+{
+    XMLToolingConfig& conf=XMLToolingConfig::getConfig();
+    conf.CredentialResolverManager.registerFactory(FILESYSTEM_CREDENTIAL_RESOLVER, FilesystemCredentialResolverFactory);
+    conf.CredentialResolverManager.registerFactory("edu.internet2.middleware.shibboleth.common.Credentials.FileCredentialResolver", FilesystemCredentialResolverFactory);
+}
diff --git a/xmltooling/signature/impl/FilesystemCredentialResolver.cpp b/xmltooling/signature/impl/FilesystemCredentialResolver.cpp
new file mode 100644 (file)
index 0000000..86e70b1
--- /dev/null
@@ -0,0 +1,557 @@
+/*\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
+/**\r
+ * FilesystemCredentialResolver.cpp\r
+ * \r
+ * Supplies credentials from local files\r
+ */\r
+\r
+#include "internal.h"\r
+#include "signature/OpenSSLCredentialResolver.h"\r
+#include "util/NDC.h"\r
+#include "util/XMLHelper.h"\r
+\r
+using namespace xmlsignature;\r
+using namespace xmltooling;\r
+\r
+#include <sys/types.h>\r
+#include <sys/stat.h>\r
+#include <algorithm>\r
+#include <openssl/pkcs12.h>\r
+#include <log4cpp/Category.hh>\r
+#include <xercesc/util/XMLUniDefs.hpp>\r
+#include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>\r
+#include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>\r
+#include <xsec/enc/OpenSSL/OpenSSLCryptoKeyDSA.hpp>\r
+\r
+using namespace xmlsignature;\r
+using namespace xmltooling;\r
+using namespace log4cpp;\r
+using namespace std;\r
+\r
+// OpenSSL password callback...\r
+static int passwd_callback(char* buf, int len, int verify, void* passwd)\r
+{\r
+    if(!verify)\r
+    {\r
+        if(passwd && len > strlen(reinterpret_cast<char*>(passwd)))\r
+        {\r
+            strcpy(buf,reinterpret_cast<char*>(passwd));\r
+            return strlen(buf);\r
+        }\r
+    }  \r
+    return 0;\r
+}\r
+\r
+namespace xmlsignature {\r
+    class FilesystemCredentialResolver : public CredentialResolver\r
+    {\r
+    public:\r
+        FilesystemCredentialResolver(const DOMElement* e);\r
+        ~FilesystemCredentialResolver();\r
+\r
+        Lockable* lock() { return this; }\r
+        void unlock() {}\r
+        \r
+        XSECCryptoKey* loadKey();\r
+        \r
+        void attach(SSL_CTX* ctx) const;\r
+        XSECCryptoKey* getKey() const { return m_key->clone(); }\r
+        const vector<XSECCryptoX509*>& getCertificates() const { return m_xseccerts; }\r
+        \r
+    private:\r
+        enum format_t { PEM=SSL_FILETYPE_PEM, DER=SSL_FILETYPE_ASN1, _PKCS12, UNKNOWN };\r
+    \r
+        format_t getEncodingFormat(BIO* in) const;\r
+        string formatToString(format_t format) const;\r
+        format_t xmlFormatToFormat(const XMLCh* format_xml) const;\r
+    \r
+        format_t m_keyformat;\r
+        string m_keypath,m_keypass;\r
+        vector<X509*> m_certs;\r
+        vector<XSECCryptoX509*> m_xseccerts;\r
+        XSECCryptoKey* m_key;\r
+    };\r
+\r
+    CredentialResolver* XMLTOOL_DLLLOCAL FilesystemCredentialResolverFactory(const DOMElement* const & e)\r
+    {\r
+        return new FilesystemCredentialResolver(e);\r
+    }\r
+};\r
+\r
+static const XMLCh CAPath[] =           UNICODE_LITERAL_6(C,A,P,a,t,h);\r
+static const XMLCh Certificate[] =      UNICODE_LITERAL_11(C,e,r,t,i,f,i,c,a,t,e);\r
+static const XMLCh format[] =           UNICODE_LITERAL_6(f,o,r,m,a,t);\r
+static const XMLCh Key[] =              UNICODE_LITERAL_3(K,e,y);\r
+static const XMLCh password[] =         UNICODE_LITERAL_8(p,a,s,s,w,o,r,d);\r
+static const XMLCh Path[] =             UNICODE_LITERAL_4(P,a,t,h);\r
+\r
+FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e)\r
+{\r
+#ifdef _DEBUG\r
+    NDC ndc("FilesystemCredentialResolver");\r
+#endif\r
+    Category& log=Category::getInstance(XMLTOOLING_LOGCAT".CredentialResolver");\r
+\r
+    format_t fformat;\r
+    const XMLCh* format_xml=NULL;\r
+    BIO* in = NULL;\r
+    \r
+    // Move to Key\r
+    const DOMElement* root=e;\r
+    e=XMLHelper::getFirstChildElement(root,Key);\r
+    if (e) {\r
+\r
+        // Get raw format attrib value, but defer processing til later since may need to \r
+        // determine format dynamically, and we need the Path for that.\r
+        format_xml=e->getAttributeNS(NULL,format);\r
+            \r
+        const XMLCh* password_xml=e->getAttributeNS(NULL,password);\r
+        if (password_xml) {\r
+            auto_ptr_char kp(password_xml);\r
+            m_keypass=kp.get();\r
+        }\r
+        \r
+        e=XMLHelper::getFirstChildElement(e,Path);\r
+        if (e && e->hasChildNodes()) {\r
+            const XMLCh* s=e->getFirstChild()->getNodeValue();\r
+            auto_ptr_char kpath(s);\r
+#ifdef WIN32\r
+            struct _stat stat_buf;\r
+            if (_stat(kpath.get(), &stat_buf) != 0)\r
+#else\r
+            struct stat stat_buf;\r
+            if (stat(kpath.get(), &stat_buf) != 0)\r
+#endif\r
+            {\r
+                log.error("key file (%s) can't be opened", kpath.get());\r
+                throw XMLSecurityException("FilesystemCredentialResolver can't access key file ($1)",params(1,kpath.get()));\r
+            }\r
+            m_keypath=kpath.get();\r
+        }\r
+        else {\r
+            log.error("Path element missing inside Key element");\r
+            throw XMLSecurityException("FilesystemCredentialResolver can't access key file, no Path element specified.");\r
+        }\r
+\r
+        // Determine the key encoding format dynamically, if not explicitly specified\r
+        if (format_xml && *format_xml) {\r
+            fformat = xmlFormatToFormat(format_xml);\r
+            if (fformat != UNKNOWN) {\r
+                m_keyformat = fformat;\r
+            }\r
+            else {\r
+                auto_ptr_char unknown(format_xml);\r
+                log.error("configuration specifies unknown key encoding format (%s)", unknown.get());\r
+                throw XMLSecurityException("FilesystemCredentialResolver configuration contains unknown key encoding format ($1)",params(1,unknown.get()));\r
+            }\r
+        }\r
+        else {\r
+            in=BIO_new(BIO_s_file_internal());\r
+            if (in && BIO_read_filename(in,m_keypath.c_str())>0) {\r
+                m_keyformat = getEncodingFormat(in);\r
+                log.debug("key encoding format for (%s) dynamically resolved as (%s)", m_keypath.c_str(), formatToString(m_keyformat).c_str());\r
+            }\r
+            else {\r
+                log.error("key file (%s) can't be read to determine encoding format", m_keypath.c_str());\r
+                throw XMLSecurityException("FilesystemCredentialResolver can't read key file ($1) to determine encoding format",params(1,m_keypath.c_str()));\r
+            }\r
+            if (in)\r
+                BIO_free(in);\r
+            in = NULL;    \r
+        }\r
+        \r
+        // Load the key.\r
+        m_key = loadKey();\r
+    }\r
+        \r
+    // Check for Certificate\r
+    e=XMLHelper::getFirstChildElement(root,Certificate);\r
+    if (!e)\r
+        return;\r
+    auto_ptr_char certpass(e->getAttributeNS(NULL,password));\r
+    \r
+    DOMElement* ep=XMLHelper::getFirstChildElement(e,Path);\r
+    if (!ep || !ep->hasChildNodes()) {\r
+        log.error("Path element missing inside Certificate element or is empty");\r
+        throw XMLSecurityException("FilesystemCredentialResolver can't access certificate file, missing or empty Path element.");\r
+    }\r
+    \r
+    auto_ptr_char certpath(ep->getFirstChild()->getNodeValue());\r
+    format_xml=e->getAttributeNS(NULL,format);\r
+    if (format_xml && *format_xml) {\r
+        fformat = xmlFormatToFormat(format_xml);\r
+        if (fformat == UNKNOWN) {\r
+            auto_ptr_char unknown(format_xml);\r
+            log.error("configuration specifies unknown certificate encoding format (%s)", unknown.get());\r
+            throw XMLSecurityException("FilesystemCredentialResolver configuration contains unknown certificate encoding format ($1)",params(1,unknown.get()));\r
+        }\r
+    }\r
+    \r
+    try {\r
+        X509* x=NULL;\r
+        PKCS12* p12=NULL;\r
+        in=BIO_new(BIO_s_file_internal());\r
+        if (in && BIO_read_filename(in,certpath.get())>0) {\r
+            if (!format_xml || !*format_xml) {\r
+                // Determine the cert encoding format dynamically, if not explicitly specified\r
+                fformat = getEncodingFormat(in);\r
+                log.debug("certificate encoding format for (%s) dynamically resolved as (%s)", certpath.get(), formatToString(fformat).c_str());\r
+            }\r
+\r
+            switch(fformat) {\r
+                case PEM:\r
+                    while (x=PEM_read_bio_X509(in,NULL,passwd_callback,const_cast<char*>(certpass.get())))\r
+                        m_certs.push_back(x);\r
+                    break;\r
+                                \r
+                case DER:\r
+                    x=d2i_X509_bio(in,NULL);\r
+                    if (x)\r
+                        m_certs.push_back(x);\r
+                    else {\r
+                        log_openssl();\r
+                        BIO_free(in);\r
+                        throw XMLSecurityException("FilesystemCredentialResolver unable to load DER certificate from file ($1)",params(1,certpath.get()));\r
+                    }\r
+                    break;\r
+\r
+                case _PKCS12:\r
+                    p12=d2i_PKCS12_bio(in,NULL);\r
+                    if (p12) {\r
+                        PKCS12_parse(p12, certpass.get(), NULL, &x, NULL);\r
+                        PKCS12_free(p12);\r
+                    }\r
+                    if (x) {\r
+                        m_certs.push_back(x);\r
+                        x=NULL;\r
+                    } else {\r
+                        log_openssl();\r
+                        BIO_free(in);\r
+                        throw XMLSecurityException("FilesystemCredentialResolver unable to load PKCS12 certificate from file ($1)",params(1,certpath.get()));\r
+                    }\r
+                    break;\r
+            } // end switch\r
+\r
+        } else {\r
+            log_openssl();\r
+            if (in) {\r
+                BIO_free(in);\r
+                in=NULL;\r
+            }\r
+            throw XMLSecurityException("FilesystemCredentialResolver unable to load certificate(s) from file ($1)",params(1,certpath.get()));\r
+        }\r
+        if (in) {\r
+            BIO_free(in);\r
+            in=NULL;\r
+        }\r
+\r
+        if (m_certs.empty()) {\r
+            throw XMLSecurityException("FilesystemCredentialResolver unable to load any certificate(s)");\r
+        }\r
+\r
+        // Load any extra CA files.\r
+        DOMElement* extra=XMLHelper::getFirstChildElement(e,CAPath);\r
+        while (extra) {\r
+            if (!extra->hasChildNodes()) {\r
+                log.warn("skipping empty CAPath element");\r
+                extra = XMLHelper::getNextSiblingElement(extra,CAPath);\r
+                continue;\r
+            }\r
+            auto_ptr_char capath(extra->getFirstChild()->getNodeValue());\r
+            x=NULL;\r
+            p12=NULL;\r
+            in=BIO_new(BIO_s_file_internal());\r
+            if (in && BIO_read_filename(in,capath.get())>0) {\r
+                if (!format_xml || !*format_xml) {\r
+                    // Determine the cert encoding format dynamically, if not explicitly specified\r
+                    fformat = getEncodingFormat(in);\r
+                    log.debug("CA certificate encoding format for (%s) dynamically resolved as (%s)", certpath.get(), formatToString(fformat).c_str());\r
+                }\r
+\r
+                switch (fformat) {\r
+                    case PEM:\r
+                        while (x=PEM_read_bio_X509(in,NULL,passwd_callback,const_cast<char*>(certpass.get())))\r
+                            m_certs.push_back(x);\r
+                        break;\r
+\r
+                    case DER:\r
+                        x=d2i_X509_bio(in,NULL);\r
+                        if (x)\r
+                            m_certs.push_back(x);\r
+                        else {\r
+                            log_openssl();\r
+                            BIO_free(in);\r
+                            throw XMLSecurityException("FilesystemCredentialResolver unable to load DER CA certificate from file ($1)",params(1,capath.get()));\r
+                        }\r
+                        break;\r
+\r
+                    case _PKCS12:\r
+                        p12 = d2i_PKCS12_bio(in, NULL);\r
+                        if (p12) {\r
+                            PKCS12_parse(p12, certpass.get(), NULL, &x, NULL);\r
+                            PKCS12_free(p12);\r
+                        }\r
+                        if (x) {\r
+                            m_certs.push_back(x);\r
+                            x=NULL;\r
+                        }\r
+                        else {\r
+                            log_openssl();\r
+                            BIO_free(in);\r
+                            throw XMLSecurityException("FilesystemCredentialResolver unable to load PKCS12 CA certificate from file ($1)",params(1,capath.get()));\r
+                        }\r
+                        break;\r
+                } //end switch\r
+\r
+                BIO_free(in);\r
+            }\r
+            else {\r
+                if (in)\r
+                    BIO_free(in);\r
+                log_openssl();\r
+                log.error("CA file (%s) can't be opened", capath.get());\r
+                throw XMLSecurityException("FilesystemCredentialResolver can't open CA file ($1)",params(1,capath.get()));\r
+            }\r
+            \r
+            extra = XMLHelper::getNextSiblingElement(extra,CAPath);\r
+        }\r
+    }\r
+    catch (XMLToolingException&) {\r
+        for (vector<X509*>::iterator j=m_certs.begin(); j!=m_certs.end(); j++)\r
+            X509_free(*j);\r
+        throw;\r
+    }\r
+\r
+    // Reflect certs over to XSEC form.\r
+    for (vector<X509*>::iterator j=m_certs.begin(); j!=m_certs.end(); j++)\r
+        m_xseccerts.push_back(new OpenSSLCryptoX509(*j));\r
+}\r
+\r
+XSECCryptoKey* FilesystemCredentialResolver::loadKey()\r
+{\r
+#ifdef _DEBUG\r
+    NDC ndc("loadKey");\r
+#endif\r
+\r
+    // Get a EVP_PKEY.\r
+    EVP_PKEY* pkey=NULL;\r
+    BIO* in=BIO_new(BIO_s_file_internal());\r
+    if (in && BIO_read_filename(in,m_keypath.c_str())>0) {\r
+        switch (m_keyformat) {\r
+            case PEM:\r
+                pkey=PEM_read_bio_PrivateKey(in, NULL, passwd_callback, const_cast<char*>(m_keypass.c_str()));\r
+                break;\r
+            \r
+            case DER:\r
+                pkey=d2i_PrivateKey_bio(in, NULL);\r
+                break;\r
+                \r
+            default: {\r
+                PKCS12* p12 = d2i_PKCS12_bio(in, NULL);\r
+                if (p12) {\r
+                    PKCS12_parse(p12, const_cast<char*>(m_keypass.c_str()), &pkey, NULL, NULL);\r
+                    PKCS12_free(p12);\r
+                }\r
+            }\r
+        }\r
+    }\r
+    if (in)\r
+        BIO_free(in);\r
+    \r
+    // Now map it to an XSEC wrapper.\r
+    if (pkey) {\r
+        XSECCryptoKey* ret=NULL;\r
+        switch (pkey->type) {\r
+            case EVP_PKEY_RSA:\r
+                ret=new OpenSSLCryptoKeyRSA(pkey);\r
+                break;\r
+                \r
+            case EVP_PKEY_DSA:\r
+                ret=new OpenSSLCryptoKeyDSA(pkey);\r
+                break;\r
+            \r
+            default:\r
+                Category::getInstance(XMLTOOLING_LOGCAT".CredentialResolver").error("unsupported private key type");\r
+        }\r
+        EVP_PKEY_free(pkey);\r
+        if (ret)\r
+            return ret;\r
+    }\r
+\r
+    log_openssl();\r
+    throw XMLSecurityException("FilesystemCredentialResolver unable to load private key from file."); \r
+}\r
+\r
+FilesystemCredentialResolver::~FilesystemCredentialResolver()\r
+{\r
+    for_each(m_certs.begin(),m_certs.end(),X509_free);\r
+    for_each(m_xseccerts.begin(),m_xseccerts.end(),xmltooling::cleanup<XSECCryptoX509>());\r
+}\r
+\r
+void FilesystemCredentialResolver::attach(SSL_CTX* ctx) const\r
+{\r
+#ifdef _DEBUG\r
+    NDC ndc("attach");\r
+#endif\r
+    \r
+    // Attach key.\r
+    SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);\r
+    SSL_CTX_set_default_passwd_cb_userdata(ctx, const_cast<char*>(m_keypass.c_str()));\r
+\r
+    int ret=0;\r
+    switch (m_keyformat) {\r
+        case PEM:\r
+            ret=SSL_CTX_use_PrivateKey_file(ctx, m_keypath.c_str(), m_keyformat);\r
+            break;\r
+            \r
+        case DER:\r
+            ret=SSL_CTX_use_RSAPrivateKey_file(ctx, m_keypath.c_str(), m_keyformat);\r
+            break;\r
+            \r
+        default: {\r
+            BIO* in=BIO_new(BIO_s_file_internal());\r
+            if (in && BIO_read_filename(in,m_keypath.c_str())>0) {\r
+                EVP_PKEY* pkey=NULL;\r
+                PKCS12* p12 = d2i_PKCS12_bio(in, NULL);\r
+                if (p12) {\r
+                    PKCS12_parse(p12, const_cast<char*>(m_keypass.c_str()), &pkey, NULL, NULL);\r
+                    PKCS12_free(p12);\r
+                    if (pkey) {\r
+                        ret=SSL_CTX_use_PrivateKey(ctx, pkey);\r
+                        EVP_PKEY_free(pkey);\r
+                    }\r
+                }\r
+            }\r
+            if (in)\r
+                BIO_free(in);\r
+        }\r
+    }\r
+    \r
+    if (ret!=1) {\r
+        log_openssl();\r
+        throw XMLSecurityException("Unable to attach private key to SSL context.");\r
+    }\r
+\r
+    // Attach certs.\r
+    for (vector<X509*>::const_iterator i=m_certs.begin(); i!=m_certs.end(); i++) {\r
+        if (i==m_certs.begin()) {\r
+            if (SSL_CTX_use_certificate(ctx, *i) != 1) {\r
+                log_openssl();\r
+                throw XMLSecurityException("Unable to attach client certificate to SSL context.");\r
+            }\r
+        }\r
+        else {\r
+            // When we add certs, they don't get ref counted, so we need to duplicate them.\r
+            X509* dup = X509_dup(*i);\r
+            if (SSL_CTX_add_extra_chain_cert(ctx, dup) != 1) {\r
+                X509_free(dup);\r
+                log_openssl();\r
+                throw XMLSecurityException("Unable to attach CA certificate to SSL context.");\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+// Used to determine the encoding format of credentials files\r
+// dynamically. Supports: PEM, DER, PKCS12.\r
+FilesystemCredentialResolver::format_t FilesystemCredentialResolver::getEncodingFormat(BIO* in) const\r
+{\r
+    PKCS12* p12 = NULL;\r
+    format_t format;\r
+\r
+    const int READSIZE = 1;\r
+    char buf[READSIZE];\r
+    char b1;\r
+    int mark;\r
+\r
+    try {\r
+        if ( (mark = BIO_tell(in)) < 0 ) \r
+            throw XMLSecurityException("getEncodingFormat: BIO_tell() can't get the file position");\r
+        if ( BIO_read(in, buf, READSIZE) <= 0 ) \r
+            throw XMLSecurityException("getEncodingFormat: BIO_read() can't read from the stream");\r
+        if ( BIO_seek(in, mark) < 0 ) \r
+            throw XMLSecurityException("getEncodingFormat: BIO_seek() can't reset the file position");\r
+    }\r
+    catch (...) {\r
+        log_openssl();\r
+        throw;\r
+    }\r
+\r
+    b1 = buf[0];\r
+\r
+    // This is a slight variation of the Java code by Chad La Joie.\r
+    //\r
+    // Check the first byte of the file.  If it's some kind of\r
+    // DER-encoded structure (including PKCS12), it will begin with ASCII 048.\r
+    // Otherwise, assume it's PEM.\r
+    if (b1 !=  48) {\r
+        format = PEM;\r
+    } else {\r
+        // Here we know it's DER-encoded, now try to parse it as a PKCS12\r
+        // ASN.1 structure.  If it fails, must be another kind of DER-encoded\r
+        // key/cert structure.  A little inefficient...but it works.\r
+        if ( (p12=d2i_PKCS12_bio(in,NULL)) == NULL ) {\r
+            format = DER;\r
+        } else {\r
+            format = _PKCS12;\r
+        }\r
+        if (p12)\r
+            PKCS12_free(p12);    \r
+        if ( BIO_seek(in, mark) < 0 ) {\r
+            log_openssl();\r
+            throw XMLSecurityException("getEncodingFormat: BIO_seek() can't reset the file position");\r
+        }\r
+    }\r
+\r
+    return format;\r
+}\r
+\r
+// Convert key/cert format_t types to a human-meaningful string for debug output\r
+string FilesystemCredentialResolver::formatToString(format_t format) const\r
+{\r
+    switch(format) {\r
+        case PEM:\r
+            return "PEM";\r
+        case DER:\r
+            return "DER";\r
+        case _PKCS12:\r
+            return "PKCS12";\r
+        default:\r
+            return "UNKNOWN";\r
+    }\r
+}\r
+\r
+// Convert key/cert raw XML format attribute (XMLCh[]) to format_t type\r
+FilesystemCredentialResolver::format_t FilesystemCredentialResolver::xmlFormatToFormat(const XMLCh* format_xml) const\r
+{\r
+    static const XMLCh cPEM[] = UNICODE_LITERAL_3(P,E,M);\r
+    static const XMLCh cDER[] = UNICODE_LITERAL_3(D,E,R);\r
+    static const XMLCh cPKCS12[] = { chLatin_P, chLatin_K, chLatin_C, chLatin_S, chDigit_1, chDigit_2, chNull };\r
+    format_t format;\r
+\r
+    if (!XMLString::compareString(format_xml,cPEM))\r
+        format=PEM;\r
+    else if (!XMLString::compareString(format_xml,cDER))\r
+        format=DER;\r
+    else if (!XMLString::compareString(format_xml,cPKCS12))\r
+        format=_PKCS12;\r
+    else\r
+        format=UNKNOWN;\r
+\r
+    return format;\r
+}\r
index 7d61fdc..1bf8d5d 100644 (file)
@@ -133,75 +133,83 @@ const XMLCh* XMLHelper::getTextContent(const DOMElement* e)
     return NULL;\r
 }\r
 \r
-DOMElement* XMLHelper::getFirstChildElement(const DOMNode* n)\r
+DOMElement* XMLHelper::getFirstChildElement(const DOMNode* n, const XMLCh* localName)\r
 {\r
     DOMNode* child = n->getFirstChild();\r
     while (child && child->getNodeType() != DOMNode::ELEMENT_NODE)\r
         child = child->getNextSibling();\r
-    if (child)\r
-        return static_cast<DOMElement*>(child);\r
-    return NULL;\r
+    if (child && localName) {\r
+        if (!XMLString::equals(localName,child->getLocalName()))\r
+            return getNextSiblingElement(child, localName);\r
+    }\r
+    return static_cast<DOMElement*>(child);\r
 }    \r
 \r
-DOMElement* XMLHelper::getLastChildElement(const DOMNode* n)\r
+DOMElement* XMLHelper::getLastChildElement(const DOMNode* n, const XMLCh* localName)\r
 {\r
     DOMNode* child = n->getLastChild();\r
     while (child && child->getNodeType() != DOMNode::ELEMENT_NODE)\r
         child = child->getPreviousSibling();\r
-    if (child)\r
-        return static_cast<DOMElement*>(child);\r
-    return NULL;\r
+    if (child && localName) {\r
+        if (!XMLString::equals(localName,child->getLocalName()))\r
+            return getPreviousSiblingElement(child, localName);\r
+    }\r
+    return static_cast<DOMElement*>(child);\r
 }    \r
 \r
 DOMElement* XMLHelper::getFirstChildElement(const DOMNode* n, const XMLCh* ns, const XMLCh* localName)\r
 {\r
-    DOMElement* e = getFirstChildElement(n);\r
-    while (e && !isNodeNamed(e, ns, localName))\r
-        e = getNextSiblingElement(e);\r
+    DOMElement* e = getFirstChildElement(n, localName);\r
+    while (e && !XMLString::equals(e->getNamespaceURI(),ns))\r
+        e = getNextSiblingElement(e, localName);\r
     return e;\r
 }\r
 \r
 DOMElement* XMLHelper::getLastChildElement(const DOMNode* n, const XMLCh* ns, const XMLCh* localName)\r
 {\r
-    DOMElement* e = getLastChildElement(n);\r
-    while (e && !isNodeNamed(e, ns, localName))\r
-        e = getPreviousSiblingElement(e);\r
+    DOMElement* e = getLastChildElement(n, localName);\r
+    while (e && !XMLString::equals(e->getNamespaceURI(),ns))\r
+        e = getPreviousSiblingElement(e, localName);\r
     return e;\r
 }\r
 \r
-DOMElement* XMLHelper::getNextSiblingElement(const DOMNode* n)\r
+DOMElement* XMLHelper::getNextSiblingElement(const DOMNode* n, const XMLCh* localName)\r
 {\r
     DOMNode* sib = n->getNextSibling();\r
     while (sib && sib->getNodeType() != DOMNode::ELEMENT_NODE)\r
         sib = sib->getNextSibling();\r
-    if (sib)\r
-        return static_cast<DOMElement*>(sib);\r
-    return NULL;\r
+    if (sib && localName) {\r
+        if (!XMLString::equals(localName,sib->getLocalName()))\r
+            return getNextSiblingElement(sib, localName);\r
+    }   \r
+    return static_cast<DOMElement*>(sib);\r
 }\r
 \r
-DOMElement* XMLHelper::getPreviousSiblingElement(const DOMNode* n)\r
+DOMElement* XMLHelper::getPreviousSiblingElement(const DOMNode* n, const XMLCh* localName)\r
 {\r
     DOMNode* sib = n->getPreviousSibling();\r
     while (sib && sib->getNodeType() != DOMNode::ELEMENT_NODE)\r
         sib = sib->getPreviousSibling();\r
-    if (sib)\r
-        return static_cast<DOMElement*>(sib);\r
-    return NULL;\r
+    if (sib && localName) {\r
+        if (!XMLString::equals(localName,sib->getLocalName()))\r
+            return getPreviousSiblingElement(sib, localName);\r
+    }   \r
+    return static_cast<DOMElement*>(sib);\r
 }\r
 \r
 DOMElement* XMLHelper::getNextSiblingElement(const DOMNode* n, const XMLCh* ns, const XMLCh* localName)\r
 {\r
-    DOMElement* e = getNextSiblingElement(n);\r
-    while (e && !isNodeNamed(e, ns, localName))\r
-        e = getNextSiblingElement(e);\r
+    DOMElement* e = getNextSiblingElement(n, localName);\r
+    while (e && !XMLString::equals(e->getNamespaceURI(),ns))\r
+        e = getNextSiblingElement(e, localName);\r
     return e;\r
 }\r
 \r
 DOMElement* XMLHelper::getPreviousSiblingElement(const DOMNode* n, const XMLCh* ns, const XMLCh* localName)\r
 {\r
-    DOMElement* e = getPreviousSiblingElement(n);\r
-    while (e && !isNodeNamed(e, ns, localName))\r
-        e = getPreviousSiblingElement(e);\r
+    DOMElement* e = getPreviousSiblingElement(n, localName);\r
+    while (e && !XMLString::equals(e->getNamespaceURI(),ns))\r
+        e = getPreviousSiblingElement(e, localName);\r
     return e;\r
 }\r
 \r
index 912c208..777ce13 100644 (file)
@@ -20,7 +20,7 @@
  * A helper class for working with W3C DOM objects. \r
  */\r
 \r
-#if !defined(__xmltooling_xmlhelper_h__)\r
+#ifndef __xmltooling_xmlhelper_h__\r
 #define __xmltooling_xmlhelper_h__\r
 \r
 #include <xmltooling/QName.h>\r
@@ -126,36 +126,40 @@ namespace xmltooling {
         }\r
 \r
         /**\r
-         * Returns the first child element of the node if any.\r
+         * Returns the first matching child element of the node if any.\r
          * \r
-         * @param n     node to check\r
-         * @return  the first child node of type Element, or NULL\r
+         * @param n         node to check\r
+         * @param localName local name to compare with or NULL for any match\r
+         * @return  the first matching child node of type Element, or NULL\r
          */\r
-        static DOMElement* getFirstChildElement(const DOMNode* n);\r
+        static DOMElement* getFirstChildElement(const DOMNode* n, const XMLCh* localName=NULL);\r
         \r
         /**\r
-         * Returns the last child element of the node if any.\r
+         * Returns the last matching child element of the node if any.\r
          * \r
          * @param n     node to check\r
-         * @return  the last child node of type Element, or NULL\r
+         * @param localName local name to compare with or NULL for any match\r
+         * @return  the last matching child node of type Element, or NULL\r
          */\r
-        static DOMElement* getLastChildElement(const DOMNode* n);\r
+        static DOMElement* getLastChildElement(const DOMNode* n, const XMLCh* localName=NULL);\r
         \r
         /**\r
-         * Returns the next sibling element of the node if any.\r
+         * Returns the next matching sibling element of the node if any.\r
          * \r
          * @param n     node to check\r
-         * @return  the next sibling node of type Element, or NULL\r
+         * @param localName local name to compare with or NULL for any match\r
+         * @return  the next matching sibling node of type Element, or NULL\r
          */\r
-        static DOMElement* getNextSiblingElement(const DOMNode* n);\r
+        static DOMElement* getNextSiblingElement(const DOMNode* n, const XMLCh* localName=NULL);\r
         \r
         /**\r
-         * Returns the previous sibling element of the node if any.\r
+         * Returns the previous matching sibling element of the node if any.\r
          * \r
          * @param n     node to check\r
-         * @return  the previous sibling node of type Element, or NULL\r
+         * @param localName local name to compare with or NULL for any match\r
+         * @return  the previous matching sibling node of type Element, or NULL\r
          */\r
-        static DOMElement* getPreviousSiblingElement(const DOMNode* n);\r
+        static DOMElement* getPreviousSiblingElement(const DOMNode* n, const XMLCh* localName=NULL);\r
         \r
         /**\r
          * Returns the first matching child element of the node if any.\r
index dd64694..51492df 100644 (file)
@@ -62,7 +62,7 @@
                        />\r
                        <Tool\r
                                Name="VCLinkerTool"\r
-                               AdditionalDependencies="log4cppD.lib xerces-c_2D.lib xsec_1D.lib"\r
+                               AdditionalDependencies="log4cppD.lib xerces-c_2D.lib xsec_1D.lib libeay32_0_9_8D.lib ssleay32_0_9_8D.lib"\r
                                OutputFile="$(OutDir)\$(ProjectName)_1D.dll"\r
                                LinkIncremental="2"\r
                                GenerateDebugInformation="true"\r
                        />\r
                        <Tool\r
                                Name="VCLinkerTool"\r
-                               AdditionalDependencies="log4cpp.lib xerces-c_2.lib xsec_1.lib"\r
+                               AdditionalDependencies="log4cpp.lib xerces-c_2.lib xsec_1.lib libeay32_0_9_8.lib ssleay32_0_9_8.lib"\r
                                OutputFile="$(OutDir)\$(ProjectName)_1.dll"\r
                                LinkIncremental="2"\r
                                GenerateDebugInformation="true"\r
                                        Name="impl"\r
                                        >\r
                                        <File\r
+                                               RelativePath=".\signature\impl\CredentialResolver.cpp"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
+                                               RelativePath=".\signature\impl\FilesystemCredentialResolver.cpp"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
                                                RelativePath=".\signature\impl\KeyInfoImpl.cpp"\r
                                                >\r
                                        </File>\r
                                        >\r
                                </File>\r
                                <File\r
+                                       RelativePath=".\signature\CredentialResolver.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
                                        RelativePath=".\signature\KeyInfo.h"\r
                                        >\r
                                </File>\r
                                        >\r
                                </File>\r
                                <File\r
+                                       RelativePath=".\signature\OpenSSLCredentialResolver.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
                                        RelativePath=".\signature\Signature.h"\r
                                        >\r
                                </File>\r
diff --git a/xmltoolingtest/FilesystemCredentialResolverTest.h b/xmltoolingtest/FilesystemCredentialResolverTest.h
new file mode 100644 (file)
index 0000000..92e720a
--- /dev/null
@@ -0,0 +1,48 @@
+/*\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
+#include "XMLObjectBaseTestCase.h"\r
+\r
+#include <xmltooling/signature/CredentialResolver.h>\r
+\r
+#include <fstream>\r
+\r
+class FilesystemCredentialResolverTest : public CxxTest::TestSuite {\r
+public:\r
+    void setUp() {\r
+    }\r
+    \r
+    void tearDown() {\r
+    }\r
+\r
+    void testFilesystemProvider() {\r
+        string config = data_path + "FilesystemCredentialResolver.xml";\r
+        ifstream in(config.c_str());\r
+        DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in);\r
+        XercesJanitor<DOMDocument> janitor(doc);\r
+\r
+        auto_ptr<CredentialResolver> credResolver(\r
+            XMLToolingConfig::getConfig().CredentialResolverManager.newPlugin(\r
+                FILESYSTEM_CREDENTIAL_RESOLVER,doc->getDocumentElement()\r
+                )\r
+            );\r
+\r
+        Locker locker(credResolver.get());\r
+        auto_ptr<XSECCryptoKey> key(credResolver->getKey());\r
+        TSM_ASSERT("Retrieved key was null", key.get()!=NULL);\r
+        TSM_ASSERT_EQUALS("Unexpected number of certificates", 1, credResolver->getCertificates().size());\r
+    }\r
+};\r
index 69538ec..4525b08 100644 (file)
@@ -10,6 +10,7 @@ endif
 if BUILD_XMLSEC
 xmlsec_sources = \
     EncryptionTest.h \
+    FilesystemCredentialResolverTest.h \
     SignatureTest.h
 else
 xmlsec_sources =
diff --git a/xmltoolingtest/data/FilesystemCredentialResolver.xml b/xmltoolingtest/data/FilesystemCredentialResolver.xml
new file mode 100644 (file)
index 0000000..32be243
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<FilesystemCredentialResolver>
+    <Key>
+        <Path>../xmltoolingtest/data/key.pem</Path>
+    </Key>
+    <Certificate>
+        <Path>../xmltoolingtest/data/cert.pem</Path>
+    </Certificate>
+</FilesystemCredentialResolver>
index 5e838d9..4502fe7 100644 (file)
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath=".\FilesystemCredentialResolverTest.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath=".\KeyInfoTest.cpp"\r
                                >\r
                        </File>\r
                                </FileConfiguration>\r
                        </File>\r
                        <File\r
+                               RelativePath=".\FilesystemCredentialResolverTest.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=".\KeyInfoTest.h"\r
                                >\r
                                <FileConfiguration\r