https://bugs.internet2.edu/jira/browse/CPPXT-56
authorcantor <cantor@de75baf8-a10c-0410-a50a-987c0e22f00f>
Sat, 13 Mar 2010 20:42:04 +0000 (20:42 +0000)
committercantor <cantor@de75baf8-a10c-0410-a50a-987c0e22f00f>
Sat, 13 Mar 2010 20:42:04 +0000 (20:42 +0000)
git-svn-id: https://svn.middleware.georgetown.edu/cpp-xmltooling/branches/REL_1@723 de75baf8-a10c-0410-a50a-987c0e22f00f

xmltooling/soap/impl/CURLSOAPTransport.cpp
xmltooling/util/CurlURLInputStream.cpp
xmltooling/util/CurlURLInputStream.h

index e7a1b1e..de49f99 100644 (file)
@@ -72,7 +72,8 @@ namespace xmltooling {
 #ifndef XMLTOOLING_NO_XMLSEC
                     m_cred(NULL), m_trustEngine(NULL), m_peerResolver(NULL), m_mandatory(false),
 #endif
-                    m_ssl_callback(NULL), m_ssl_userptr(NULL), m_chunked(true), m_authenticated(false), m_cacheTag(NULL) {
+                    m_openssl_ops(SSL_OP_ALL|SSL_OP_NO_SSLv2), m_ssl_callback(NULL), m_ssl_userptr(NULL),
+                    m_chunked(true), m_authenticated(false), m_cacheTag(NULL) {
             m_handle = g_CURLPool->get(addr);
             curl_easy_setopt(m_handle,CURLOPT_URL,addr.m_endpoint);
             curl_easy_setopt(m_handle,CURLOPT_CONNECTTIMEOUT,15);
@@ -152,35 +153,7 @@ namespace xmltooling {
             return true;
         }
 
-        bool setProviderOption(const char* provider, const char* option, const char* value) {
-            if (!provider || strcmp(provider, "CURL"))
-                return false;
-            // For libcurl, the option is an enum and the value type depends on the option.
-            CURLoption opt = static_cast<CURLoption>(strtol(option, NULL, 10));
-            if (opt < CURLOPTTYPE_OBJECTPOINT)
-                return (curl_easy_setopt(m_handle, opt, strtol(value, NULL, 10)) == CURLE_OK);
-#ifdef CURLOPTTYPE_OFF_T
-            else if (opt < CURLOPTTYPE_OFF_T) {
-                if (value)
-                    m_saved_options.push_back(value);
-                return (curl_easy_setopt(m_handle, opt, value ? m_saved_options.back().c_str() : NULL) == CURLE_OK);
-            }
-# ifdef HAVE_CURL_OFF_T
-            else if (sizeof(curl_off_t) == sizeof(long))
-                return (curl_easy_setopt(m_handle, opt, strtol(value, NULL, 10)) == CURLE_OK);
-# else
-            else if (sizeof(off_t) == sizeof(long))
-                return (curl_easy_setopt(m_handle, opt, strtol(value, NULL, 10)) == CURLE_OK);
-# endif
-            return false;
-#else
-            else {
-                if (value)
-                    m_saved_options.push_back(value);
-                return (curl_easy_setopt(m_handle, opt, value ? m_saved_options.back().c_str() : NULL) == CURLE_OK);
-            }
-#endif
-        }
+        bool setProviderOption(const char* provider, const char* option, const char* value);
 
         void send(istream& in) {
             send(&in);
@@ -233,6 +206,7 @@ namespace xmltooling {
         CredentialCriteria* m_criteria;
         bool m_mandatory;
 #endif
+        int m_openssl_ops;
         ssl_ctx_callback_fn m_ssl_callback;
         void* m_ssl_userptr;
         bool m_chunked;
@@ -408,6 +382,60 @@ bool CURLSOAPTransport::setAuth(transport_auth_t authType, const char* username,
     return (curl_easy_setopt(m_handle,CURLOPT_USERPWD,m_simplecreds.c_str())==CURLE_OK);
 }
 
+bool CURLSOAPTransport::setProviderOption(const char* provider, const char* option, const char* value)
+{
+    if (!provider || !option || !value) {
+        return false;
+    }
+    else if (!strcmp(provider, "OpenSSL")) {
+        if (!strcmp(option, "SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION") && (*value=='1' || *value=='t')) {
+            // If the new option to enable buggy rengotiation is available, set it.
+            // Otherwise, signal false if this is newer than 0.9.8k, because that
+            // means it's 0.9.8l, which blocks renegotiation, and therefore will
+            // not honor this request. Older versions are buggy, so behave as though
+            // the flag was set anyway, so we signal true.
+#if defined(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)
+            m_openssl_ops |= SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
+            return true;
+#elif (OPENSSL_VERSION_NUMBER > 0x009080bfL)
+            return false;
+#else
+            return true;
+#endif
+        }
+        return false;
+    }
+    else if (strcmp(provider, "CURL")) {
+        return false;
+    }
+
+    // For libcurl, the option is an enum and the value type depends on the option.
+    CURLoption opt = static_cast<CURLoption>(strtol(option, NULL, 10));
+    if (opt < CURLOPTTYPE_OBJECTPOINT)
+        return (curl_easy_setopt(m_handle, opt, strtol(value, NULL, 10)) == CURLE_OK);
+#ifdef CURLOPTTYPE_OFF_T
+    else if (opt < CURLOPTTYPE_OFF_T) {
+        if (value)
+            m_saved_options.push_back(value);
+        return (curl_easy_setopt(m_handle, opt, value ? m_saved_options.back().c_str() : NULL) == CURLE_OK);
+    }
+# ifdef HAVE_CURL_OFF_T
+    else if (sizeof(curl_off_t) == sizeof(long))
+        return (curl_easy_setopt(m_handle, opt, strtol(value, NULL, 10)) == CURLE_OK);
+# else
+    else if (sizeof(off_t) == sizeof(long))
+        return (curl_easy_setopt(m_handle, opt, strtol(value, NULL, 10)) == CURLE_OK);
+# endif
+    return false;
+#else
+    else {
+        if (value)
+            m_saved_options.push_back(value);
+        return (curl_easy_setopt(m_handle, opt, value ? m_saved_options.back().c_str() : NULL) == CURLE_OK);
+    }
+#endif
+}
+
 const vector<string>& CURLSOAPTransport::getResponseHeader(const char* name) const
 {
     static vector<string> emptyVector;
@@ -642,13 +670,13 @@ CURLcode xmltooling::xml_ssl_ctx_callback(CURL* curl, SSL_CTX* ssl_ctx, void* us
 {
     CURLSOAPTransport* conf = reinterpret_cast<CURLSOAPTransport*>(userptr);
 
-    // Manually disable SSLv2 so we're not dependent on libcurl to do it.
+    // Default flags manually disable SSLv2 so we're not dependent on libcurl to do it.
     // Also disable the ticket option where implemented, since this breaks a variety
     // of servers. Newer libcurl also does this for us.
 #ifdef SSL_OP_NO_TICKET
-    SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_TICKET);
+    SSL_CTX_set_options(ssl_ctx, conf->m_openssl_ops|SSL_OP_NO_TICKET);
 #else
-    SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
+    SSL_CTX_set_options(ssl_ctx, conf->m_openssl_ops);
 #endif
 
 #ifndef XMLTOOLING_NO_XMLSEC
index e2d44c9..92ac8b1 100644 (file)
@@ -43,7 +43,8 @@ using namespace xercesc;
 using namespace std;
 
 namespace {
-    static const XMLCh  _CURL[] =           UNICODE_LITERAL_4(C,U,R,L);
+    static const XMLCh _CURL[] =            UNICODE_LITERAL_4(C,U,R,L);
+    static const XMLCh _OpenSSL[] =         UNICODE_LITERAL_7(O,p,e,n,S,S,L);
     static const XMLCh _option[] =          UNICODE_LITERAL_6(o,p,t,i,o,n);
     static const XMLCh _provider[] =        UNICODE_LITERAL_8(p,r,o,v,i,d,e,r);
     static const XMLCh TransportOption[] =  UNICODE_LITERAL_15(T,r,a,n,s,p,o,r,t,O,p,t,i,o,n);
@@ -54,13 +55,15 @@ namespace {
     // callback to invoke a caller-defined SSL callback
     CURLcode ssl_ctx_callback(CURL* curl, SSL_CTX* ssl_ctx, void* userptr)
     {
-        // Manually disable SSLv2 so we're not dependent on libcurl to do it.
+        CurlURLInputStream* str = reinterpret_cast<CurlURLInputStream*>(userptr);
+
+        // Default flags manually disable SSLv2 so we're not dependent on libcurl to do it.
         // Also disable the ticket option where implemented, since this breaks a variety
         // of servers. Newer libcurl also does this for us.
 #ifdef SSL_OP_NO_TICKET
-        SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_TICKET);
+        SSL_CTX_set_options(ssl_ctx, str->getOpenSSLOps()|SSL_OP_NO_TICKET);
 #else
-        SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
+        SSL_CTX_set_options(ssl_ctx, str->getOpenSSLOps());
 #endif
 
         return CURLE_OK;
@@ -103,6 +106,7 @@ namespace {
 CurlURLInputStream::CurlURLInputStream(const char* url, string* cacheTag)
     : fLog(logging::Category::getInstance(XMLTOOLING_LOGCAT".libcurl.InputStream"))
     , fCacheTag(cacheTag)
+    , fOpenSSLOps(SSL_OP_ALL|SSL_OP_NO_SSLv2)
     , fURL(url ? url : "")
     , fMulti(0)
     , fEasy(0)
@@ -125,6 +129,7 @@ CurlURLInputStream::CurlURLInputStream(const char* url, string* cacheTag)
 CurlURLInputStream::CurlURLInputStream(const XMLCh* url, string* cacheTag)
     : fLog(logging::Category::getInstance(XMLTOOLING_LOGCAT".libcurl.InputStream"))
     , fCacheTag(cacheTag)
+    , fOpenSSLOps(SSL_OP_ALL|SSL_OP_NO_SSLv2)
     , fMulti(0)
     , fEasy(0)
     , fHeaders(0)
@@ -150,6 +155,7 @@ CurlURLInputStream::CurlURLInputStream(const XMLCh* url, string* cacheTag)
 CurlURLInputStream::CurlURLInputStream(const DOMElement* e, string* cacheTag)
     : fLog(logging::Category::getInstance(XMLTOOLING_LOGCAT".libcurl.InputStream"))
     , fCacheTag(cacheTag)
+    , fOpenSSLOps(SSL_OP_ALL|SSL_OP_NO_SSLv2)
     , fMulti(0)
     , fEasy(0)
     , fHeaders(0)
@@ -233,6 +239,7 @@ void CurlURLInputStream::init(const DOMElement* e)
 
     // Install SSL callback.
     curl_easy_setopt(fEasy, CURLOPT_SSL_CTX_FUNCTION, ssl_ctx_callback);
+    curl_easy_setopt(fEasy, CURLOPT_SSL_CTX_DATA, this);
 
     fError[0] = 0;
     curl_easy_setopt(fEasy, CURLOPT_ERRORBUFFER, fError);
@@ -260,7 +267,32 @@ void CurlURLInputStream::init(const DOMElement* e)
         bool success;
         DOMElement* child = XMLHelper::getLastChildElement(e, TransportOption);
         while (child) {
-            if (child->hasChildNodes() && XMLString::equals(child->getAttributeNS(NULL,_provider), _CURL)) {
+            if (child->hasChildNodes() && XMLString::equals(child->getAttributeNS(NULL,_provider), _OpenSSL)) {
+                auto_ptr_char option(child->getAttributeNS(NULL,_option));
+                auto_ptr_char value(child->getFirstChild()->getNodeValue());
+                if (option.get() && value.get() && !strcmp(option.get(), "SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION") &&
+                    (*value.get()=='1' || *value.get()=='t')) {
+                    // If the new option to enable buggy rengotiation is available, set it.
+                    // Otherwise, signal false if this is newer than 0.9.8k, because that
+                    // means it's 0.9.8l, which blocks renegotiation, and therefore will
+                    // not honor this request. Older versions are buggy, so behave as though
+                    // the flag was set anyway, so we signal true.
+#if defined(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)
+                    fOpenSSLOps |= SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
+                    success = true;
+#elif (OPENSSL_VERSION_NUMBER > 0x009080bfL)
+                    success = false;
+#else
+                    success = true;
+#endif
+                }
+                else {
+                    success = false;
+                }
+                if (!success)
+                    fLog.error("failed to set OpenSSL transport option (%s)", option.get());
+            }
+            else if (child->hasChildNodes() && XMLString::equals(child->getAttributeNS(NULL,_provider), _CURL)) {
                 auto_ptr_char option(child->getAttributeNS(NULL,_option));
                 auto_ptr_char value(child->getFirstChild()->getNodeValue());
                 if (option.get() && *option.get() && value.get() && *value.get()) {
@@ -289,7 +321,7 @@ void CurlURLInputStream::init(const DOMElement* e)
                     }
 #endif
                     if (!success)
-                        fLog.error("failed to set transport option (%s)", option.get());
+                        fLog.error("failed to set CURL transport option (%s)", option.get());
                 }
             }
             child = XMLHelper::getPreviousSiblingElement(child, TransportOption);
index a2be81e..3adf169 100644 (file)
@@ -92,6 +92,15 @@ namespace xmltooling {
 
         xsecsize_t readBytes(XMLByte* const toFill, const xsecsize_t maxToRead);
 
+        /**
+         * Access the OpenSSL context options in place for this object.
+         *
+         * @return bitmask suitable for use with SSL_CTX_set_options
+         */
+        int getOpenSSLOps() const {
+            return fOpenSSLOps;
+        }
+
     private :
         CurlURLInputStream(const CurlURLInputStream&);
         CurlURLInputStream& operator=(const CurlURLInputStream&);
@@ -107,6 +116,7 @@ namespace xmltooling {
         std::string*        fCacheTag;
         std::string         fURL;
         std::vector<std::string>    fSavedOptions;
+        int                 fOpenSSLOps;
 
         CURLM*              fMulti;
         CURL*               fEasy;