Add security indicator to transport, set by SSL callback, maintain across CURL reuse.
authorcantor <cantor@de75baf8-a10c-0410-a50a-987c0e22f00f>
Wed, 22 Nov 2006 22:48:02 +0000 (22:48 +0000)
committercantor <cantor@de75baf8-a10c-0410-a50a-987c0e22f00f>
Wed, 22 Nov 2006 22:48:02 +0000 (22:48 +0000)
git-svn-id: https://svn.middleware.georgetown.edu/cpp-xmltooling/trunk@207 de75baf8-a10c-0410-a50a-987c0e22f00f

xmltooling/soap/OpenSSLSOAPTransport.h
xmltooling/soap/SOAPTransport.h
xmltooling/soap/impl/CURLSOAPTransport.cpp

index 5620d78..6e3182c 100644 (file)
  * Encapsulates OpenSSL-capable SOAP transport layer.
  */
 
-#if !defined(__xmltooling_opensslsoaptrans_h__) && !defined(XMLTOOLING_NO_XMLSEC)
+#ifndef __xmltooling_opensslsoaptrans_h__
 #define __xmltooling_opensslsoaptrans_h__
 
-#include <xmltooling/signature/CredentialResolver.h>
 #include <xmltooling/soap/SOAPTransport.h>
 
 #include <openssl/ssl.h>
@@ -41,7 +40,7 @@ namespace xmltooling {
         virtual ~OpenSSLSOAPTransport() {}
         
         /** OpenSSL context callback for manipulating credentials and validation behavior. */
-        typedef bool (*ssl_ctx_callback_fn)(SSL_CTX* ssl_ctx, void* userptr);
+        typedef bool (*ssl_ctx_callback_fn)(OpenSSLSOAPTransport* transport, SSL_CTX* ssl_ctx, void* userptr);
 
         /**
          * Sets a callback function to invoke against the SSL_CTX before the handshake.
@@ -51,6 +50,13 @@ namespace xmltooling {
          * @return true iff the callback was set
          */
         virtual bool setSSLCallback(ssl_ctx_callback_fn fn, void* userptr=NULL) const=0;
+        
+        /**
+         * Sets indicator that the transport peer has been authenticated.
+         * 
+         * @param secure    flag to set
+         */
+        virtual void setSecure(bool secure)=0;
     };
 
 };
index 395a327..0c42f02 100644 (file)
@@ -86,7 +86,7 @@ namespace xmltooling {
          */
         virtual bool setAuth(transport_auth_t authType, const char* username=NULL, const char* password=NULL) const=0;
 
-#ifndef XMLTOOLING_NO_XMLSEC 
+#ifndef XMLTOOLING_NO_XMLSEC
         /**
          * Provides a CredentialResolver to the transport to supply transport credentials.
          * The lifetime of the resolver must be longer than the lifetime of this object.
@@ -103,10 +103,16 @@ namespace xmltooling {
          * The lifetime of the engine must be longer than the lifetime of this object.
          * 
          * @param trustEngine   a TrustEngine instance, or NULL
+         * @param mandatory     flag controls whether message is sent at all if the
+         *                      transport isn't authenticated using the TrustEngine
          * @param keyResolver   optional externally supplied KeyResolver, or NULL
          * @return true iff the transport supports the use of a TrustEngine
          */
-        virtual bool setTrustEngine(const X509TrustEngine* trustEngine, const xmlsignature::KeyResolver* keyResolver=NULL) const=0;
+        virtual bool setTrustEngine(
+            const X509TrustEngine* trustEngine,
+            bool mandatory=true,
+            const xmlsignature::KeyResolver* keyResolver=NULL
+            ) const=0;
 #endif
 
         /**
@@ -126,6 +132,13 @@ namespace xmltooling {
         virtual std::istream& receive()=0;
         
         /**
+         * Returns result of authenticating transport peer.
+         * 
+         * @return true iff TrustEngine or other mechanism successfully authenticated the peer
+         */
+        virtual bool isSecure() const=0;
+
+        /**
          * Returns the MIME type of the response, if any.
          * 
          * @return  MIME type of response, or an empty string
index da8a3f5..1212602 100644 (file)
@@ -68,8 +68,10 @@ namespace xmltooling {
     public:
         CURLSOAPTransport(const KeyInfoSource& peer, const char* endpoint)
                 : m_peer(peer), m_endpoint(endpoint), m_handle(NULL), m_headers(NULL),
-                    m_credResolver(NULL), m_trustEngine(NULL), m_keyResolver(NULL),
-                    m_ssl_callback(NULL), m_ssl_userptr(NULL) {
+#ifndef XMLTOOLING_NO_XMLSEC
+                    m_credResolver(NULL), m_trustEngine(NULL), m_mandatory(false), m_keyResolver(NULL),
+#endif
+                    m_ssl_callback(NULL), m_ssl_userptr(NULL), m_secure(false) {
             m_handle = g_CURLPool->get(peer.getName(), endpoint);
             curl_easy_setopt(m_handle,CURLOPT_URL,endpoint);
             curl_easy_setopt(m_handle,CURLOPT_CONNECTTIMEOUT,15);
@@ -83,6 +85,7 @@ namespace xmltooling {
         virtual ~CURLSOAPTransport() {
             curl_slist_free_all(m_headers);
             curl_easy_setopt(m_handle,CURLOPT_ERRORBUFFER,NULL);
+            curl_easy_setopt(m_handle,CURLOPT_PRIVATE,m_secure ? "secure" : NULL); // Save off security "state".
             g_CURLPool->put(m_peer.getName(), m_endpoint.c_str(), m_handle);
         }
 
@@ -96,6 +99,7 @@ namespace xmltooling {
         
         bool setAuth(transport_auth_t authType, const char* username=NULL, const char* password=NULL) const;
         
+#ifndef XMLTOOLING_NO_XMLSEC
         bool setCredentialResolver(const CredentialResolver* credResolver) const {
             const OpenSSLCredentialResolver* down = dynamic_cast<const OpenSSLCredentialResolver*>(credResolver);
             if (!down) {
@@ -106,7 +110,7 @@ namespace xmltooling {
             return true;
         }
         
-        bool setTrustEngine(const X509TrustEngine* trustEngine, const KeyResolver* keyResolver=NULL) const {
+        bool setTrustEngine(const X509TrustEngine* trustEngine, bool mandatory=true, const KeyResolver* keyResolver=NULL) const {
             const OpenSSLTrustEngine* down = dynamic_cast<const OpenSSLTrustEngine*>(trustEngine);
             if (!down) {
                 m_trustEngine = NULL;
@@ -115,15 +119,26 @@ namespace xmltooling {
             }
             m_trustEngine = down;
             m_keyResolver = keyResolver;
+            m_mandatory = mandatory;
             return true;
         }
         
+#endif
+        
         void send(istream& in);
         
         istream& receive() {
             return m_stream;
         }
         
+        bool isSecure() const {
+            return m_secure;
+        }
+
+        void setSecure(bool secure) {
+            m_secure = secure;
+        }
+
         string getContentType() const;
         
         bool setRequestHeader(const char* name, const char* val) const {
@@ -149,11 +164,15 @@ namespace xmltooling {
         stringstream m_stream;
         mutable struct curl_slist* m_headers;
         map<string,vector<string> > m_response_headers;
+#ifndef XMLTOOLING_NO_XMLSEC
         mutable const OpenSSLCredentialResolver* m_credResolver;
         mutable const OpenSSLTrustEngine* m_trustEngine;
+        mutable bool m_mandatory;
         mutable const KeyResolver* m_keyResolver;
+#endif
         mutable ssl_ctx_callback_fn m_ssl_callback;
         mutable void* m_ssl_userptr;
+        bool m_secure;
         
         friend size_t XMLTOOL_DLLLOCAL curl_header_hook(void* ptr, size_t size, size_t nmemb, void* stream);
         friend CURLcode XMLTOOL_DLLLOCAL xml_ssl_ctx_callback(CURL* curl, SSL_CTX* ssl_ctx, void* userptr);
@@ -166,7 +185,9 @@ namespace xmltooling {
     size_t XMLTOOL_DLLLOCAL curl_read_hook( void *ptr, size_t size, size_t nmemb, void *stream);
     int XMLTOOL_DLLLOCAL curl_debug_hook(CURL* handle, curl_infotype type, char* data, size_t len, void* ptr);
     CURLcode XMLTOOL_DLLLOCAL xml_ssl_ctx_callback(CURL* curl, SSL_CTX* ssl_ctx, void* userptr);
+#ifndef XMLTOOLING_NO_XMLSEC
     int XMLTOOL_DLLLOCAL verify_callback(X509_STORE_CTX* x509_ctx, void* arg);
+#endif
 
     SOAPTransport* CURLSOAPTransportFactory(const pair<const KeyInfoSource*,const char*>& dest)
     {
@@ -360,6 +381,13 @@ void CURLSOAPTransport::send(istream& in)
     if (m_ssl_callback || m_credResolver || m_trustEngine) {
         curl_easy_setopt(m_handle,CURLOPT_SSL_CTX_FUNCTION,xml_ssl_ctx_callback);
         curl_easy_setopt(m_handle,CURLOPT_SSL_CTX_DATA,this);
+
+        // Restore security "state". Necessary because the callback only runs
+        // when handshakes occur. Even new TCP connections won't execute it.
+        char* priv=NULL;
+        curl_easy_getinfo(m_handle,CURLINFO_PRIVATE,&priv);
+        if (priv)
+            m_secure=true;
     }
     else {
         curl_easy_setopt(m_handle,CURLOPT_SSL_CTX_FUNCTION,NULL);
@@ -436,6 +464,7 @@ int xmltooling::curl_debug_hook(CURL* handle, curl_infotype type, char* data, si
     return 0;
 }
 
+#ifndef XMLTOOLING_NO_XMLSEC
 int xmltooling::verify_callback(X509_STORE_CTX* x509_ctx, void* arg)
 {
     Category::getInstance("OpenSSL").debug("invoking X509 verify callback");
@@ -456,17 +485,22 @@ int xmltooling::verify_callback(X509_STORE_CTX* x509_ctx, void* arg)
      // Bypass name check (handled for us by curl).
     if (!ctx->m_trustEngine->validate(x509_ctx->cert,x509_ctx->untrusted,ctx->m_peer,false,ctx->m_keyResolver)) {
         x509_ctx->error=X509_V_ERR_APPLICATION_VERIFICATION;     // generic error, check log for plugin specifics
-        return 0;
+        ctx->setSecure(false);
+        return ctx->m_mandatory ? 0 : 1;
     }
     
     // Signal success. Hopefully it doesn't matter what's actually in the structure now.
+    ctx->setSecure(true);
     return 1;
 }
+#endif
 
 // callback to invoke a caller-defined SSL callback
 CURLcode xmltooling::xml_ssl_ctx_callback(CURL* curl, SSL_CTX* ssl_ctx, void* userptr)
 {
     CURLSOAPTransport* conf = reinterpret_cast<CURLSOAPTransport*>(userptr);
+
+#ifndef XMLTOOLING_NO_XMLSEC
     if (conf->m_credResolver)
         conf->m_credResolver->attach(ssl_ctx);
 
@@ -483,8 +517,9 @@ CURLcode xmltooling::xml_ssl_ctx_callback(CURL* curl, SSL_CTX* ssl_ctx, void* us
         SSL_CTX_set_verify_depth(ssl_ctx,reinterpret_cast<int>(userptr));
 #endif
     }
+#endif
         
-    if (!conf->m_ssl_callback(ssl_ctx,conf->m_ssl_userptr))
+    if (!conf->m_ssl_callback(conf, ssl_ctx, conf->m_ssl_userptr))
         return CURLE_SSL_CERTPROBLEM;
         
     return CURLE_OK;