X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=xmltooling%2Fsoap%2Fimpl%2FCURLSOAPTransport.cpp;h=af06fbb8e29f1226594d465ea919c9b7f23c0972;hb=312607da1e82e7d1ac0c3093e5f9f2c094055cf7;hp=da8a3f54174d5e37dc9581864f2bb3e19b65ea06;hpb=c7288a45e5a581ea8253cf4c1d45e84281172584;p=shibboleth%2Fcpp-xmltooling.git diff --git a/xmltooling/soap/impl/CURLSOAPTransport.cpp b/xmltooling/soap/impl/CURLSOAPTransport.cpp index da8a3f5..af06fbb 100644 --- a/xmltooling/soap/impl/CURLSOAPTransport.cpp +++ b/xmltooling/soap/impl/CURLSOAPTransport.cpp @@ -1,6 +1,6 @@ /* - * Copyright 2001-2006 Internet2 - * + * Copyright 2001-2009 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 @@ -16,14 +16,16 @@ /** * CURLSOAPTransport.cpp - * + * * libcurl-based SOAPTransport implementation */ #include "internal.h" #include "exceptions.h" +#include "logging.h" +#include "security/CredentialCriteria.h" #include "security/OpenSSLTrustEngine.h" -#include "signature/OpenSSLCredentialResolver.h" +#include "security/OpenSSLCredential.h" #include "soap/HTTPSOAPTransport.h" #include "soap/OpenSSLSOAPTransport.h" #include "util/NDC.h" @@ -31,12 +33,10 @@ #include #include -#include #include -using namespace xmlsignature; +using namespace xmltooling::logging; using namespace xmltooling; -using namespace log4cpp; using namespace std; namespace xmltooling { @@ -45,14 +45,14 @@ namespace xmltooling { class XMLTOOL_DLLLOCAL CURLPool { public: - CURLPool() : m_size(256), m_lock(Mutex::create()), - m_log(Category::getInstance(XMLTOOLING_LOGCAT".SOAPTransport.CURLPool")) {} + CURLPool() : m_size(0), m_lock(Mutex::create()), + m_log(Category::getInstance(XMLTOOLING_LOGCAT".SOAPTransport.CURL")) {} ~CURLPool(); - - CURL* get(const string& to, const char* endpoint); - void put(const string& to, const char* endpoint, CURL* handle); - - private: + + CURL* get(const SOAPTransport::Address& addr); + void put(const char* from, const char* to, const char* endpoint, CURL* handle); + + private: typedef map > poolmap_t; poolmap_t m_bindingMap; list< vector* > m_pools; @@ -60,101 +60,178 @@ namespace xmltooling { Mutex* m_lock; Category& m_log; }; - + static XMLTOOL_DLLLOCAL CURLPool* g_CURLPool = NULL; - + class XMLTOOL_DLLLOCAL CURLSOAPTransport : public HTTPSOAPTransport, public OpenSSLSOAPTransport { 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) { - m_handle = g_CURLPool->get(peer.getName(), endpoint); - curl_easy_setopt(m_handle,CURLOPT_URL,endpoint); + CURLSOAPTransport(const Address& addr) + : m_sender(addr.m_from ? addr.m_from : ""), m_peerName(addr.m_to ? addr.m_to : ""), m_endpoint(addr.m_endpoint), + m_handle(NULL), m_headers(NULL), +#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_handle = g_CURLPool->get(addr); + curl_easy_setopt(m_handle,CURLOPT_URL,addr.m_endpoint); curl_easy_setopt(m_handle,CURLOPT_CONNECTTIMEOUT,15); curl_easy_setopt(m_handle,CURLOPT_TIMEOUT,30); curl_easy_setopt(m_handle,CURLOPT_HTTPAUTH,0); curl_easy_setopt(m_handle,CURLOPT_USERPWD,NULL); + curl_easy_setopt(m_handle,CURLOPT_SSL_VERIFYHOST,2); curl_easy_setopt(m_handle,CURLOPT_HEADERDATA,this); m_headers=curl_slist_append(m_headers,"Content-Type: text/xml"); } - + virtual ~CURLSOAPTransport() { curl_slist_free_all(m_headers); curl_easy_setopt(m_handle,CURLOPT_ERRORBUFFER,NULL); - g_CURLPool->put(m_peer.getName(), m_endpoint.c_str(), m_handle); + curl_easy_setopt(m_handle,CURLOPT_PRIVATE,m_authenticated ? "secure" : NULL); // Save off security "state". + g_CURLPool->put(m_sender.c_str(), m_peerName.c_str(), m_endpoint.c_str(), m_handle); } - bool setConnectTimeout(long timeout) const { + bool isConfidential() const { + return m_endpoint.find("https")==0; + } + + bool setConnectTimeout(long timeout) { return (curl_easy_setopt(m_handle,CURLOPT_CONNECTTIMEOUT,timeout)==CURLE_OK); } - - bool setTimeout(long timeout) const { + + bool setTimeout(long timeout) { return (curl_easy_setopt(m_handle,CURLOPT_TIMEOUT,timeout)==CURLE_OK); } - - bool setAuth(transport_auth_t authType, const char* username=NULL, const char* password=NULL) const; - - bool setCredentialResolver(const CredentialResolver* credResolver) const { - const OpenSSLCredentialResolver* down = dynamic_cast(credResolver); + + bool setAuth(transport_auth_t authType, const char* username=NULL, const char* password=NULL); + + bool setVerifyHost(bool verify) { + return (curl_easy_setopt(m_handle,CURLOPT_SSL_VERIFYHOST,verify ? 2 : 0)==CURLE_OK); + } + +#ifndef XMLTOOLING_NO_XMLSEC + bool setCredential(const Credential* cred=NULL) { + const OpenSSLCredential* down = dynamic_cast(cred); if (!down) { - m_credResolver = NULL; - return (credResolver==NULL); + m_cred = NULL; + return (cred==NULL); } - m_credResolver = down; + m_cred = down; return true; } - - bool setTrustEngine(const X509TrustEngine* trustEngine, const KeyResolver* keyResolver=NULL) const { + + bool setTrustEngine( + const X509TrustEngine* trustEngine=NULL, + const CredentialResolver* peerResolver=NULL, + CredentialCriteria* criteria=NULL, + bool mandatory=true + ) { const OpenSSLTrustEngine* down = dynamic_cast(trustEngine); if (!down) { m_trustEngine = NULL; - m_keyResolver = NULL; + m_peerResolver = NULL; + m_criteria = NULL; return (trustEngine==NULL); } m_trustEngine = down; - m_keyResolver = keyResolver; + m_peerResolver = peerResolver; + m_criteria = criteria; + m_mandatory = mandatory; return true; } - - void send(istream& in); - + +#endif + + bool useChunkedEncoding(bool chunked=true) { + m_chunked = chunked; + 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(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 + } + + void send(istream& in) { + send(&in); + } + + void send(istream* in=NULL); + istream& receive() { return m_stream; } - + + bool isAuthenticated() const { + return m_authenticated; + } + + void setAuthenticated(bool auth) { + m_authenticated = auth; + } + string getContentType() const; - - bool setRequestHeader(const char* name, const char* val) const { + + bool setRequestHeader(const char* name, const char* val) { string temp(name); temp=temp + ": " + val; m_headers=curl_slist_append(m_headers,temp.c_str()); return true; } - + const vector& getResponseHeader(const char* val) const; - - bool setSSLCallback(ssl_ctx_callback_fn fn, void* userptr=NULL) const { + + bool setSSLCallback(ssl_ctx_callback_fn fn, void* userptr=NULL) { m_ssl_callback=fn; m_ssl_userptr=userptr; return true; } - private: + private: // per-call state - const KeyInfoSource& m_peer; - string m_endpoint; + string m_sender,m_peerName,m_endpoint,m_simplecreds; CURL* m_handle; stringstream m_stream; - mutable struct curl_slist* m_headers; + struct curl_slist* m_headers; map > m_response_headers; - mutable const OpenSSLCredentialResolver* m_credResolver; - mutable const OpenSSLTrustEngine* m_trustEngine; - mutable const KeyResolver* m_keyResolver; - mutable ssl_ctx_callback_fn m_ssl_callback; - mutable void* m_ssl_userptr; - + vector m_saved_options; +#ifndef XMLTOOLING_NO_XMLSEC + const OpenSSLCredential* m_cred; + const OpenSSLTrustEngine* m_trustEngine; + const CredentialResolver* m_peerResolver; + CredentialCriteria* m_criteria; + bool m_mandatory; +#endif + ssl_ctx_callback_fn m_ssl_callback; + void* m_ssl_userptr; + bool m_chunked; + bool m_authenticated; + 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); friend int XMLTOOL_DLLLOCAL verify_callback(X509_STORE_CTX* x509_ctx, void* arg); @@ -166,11 +243,13 @@ 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& dest) + SOAPTransport* CURLSOAPTransportFactory(const SOAPTransport::Address& addr) { - return new CURLSOAPTransport(*dest.first, dest.second); + return new CURLSOAPTransport(addr); } }; @@ -192,6 +271,14 @@ void xmltooling::termSOAPTransports() g_CURLPool = NULL; } +OpenSSLSOAPTransport::OpenSSLSOAPTransport() +{ +} + +OpenSSLSOAPTransport::~OpenSSLSOAPTransport() +{ +} + CURLPool::~CURLPool() { for (poolmap_t::iterator i=m_bindingMap.begin(); i!=m_bindingMap.end(); i++) { @@ -201,20 +288,25 @@ CURLPool::~CURLPool() delete m_lock; } -CURL* CURLPool::get(const string& to, const char* endpoint) +CURL* CURLPool::get(const SOAPTransport::Address& addr) { #ifdef _DEBUG xmltooling::NDC("get"); #endif - m_log.debug("getting connection handle to %s", endpoint); + m_log.debug("getting connection handle to %s", addr.m_endpoint); + string key(addr.m_endpoint); + if (addr.m_from) + key = key + '|' + addr.m_from; + if (addr.m_to) + key = key + '|' + addr.m_to; m_lock->lock(); - poolmap_t::iterator i=m_bindingMap.find(to + "|" + endpoint); - + poolmap_t::iterator i=m_bindingMap.find(key); + if (i!=m_bindingMap.end()) { // Move this pool to the front of the list. m_pools.remove(&(i->second)); m_pools.push_front(&(i->second)); - + // If a free connection exists, return it. if (!(i->second.empty())) { CURL* handle=i->second.back(); @@ -225,10 +317,10 @@ CURL* CURLPool::get(const string& to, const char* endpoint) return handle; } } - + m_lock->unlock(); m_log.debug("nothing free in pool, returning new connection handle"); - + // Create a new connection and set non-varying options. CURL* handle=curl_easy_init(); if (!handle) @@ -236,26 +328,31 @@ CURL* CURLPool::get(const string& to, const char* endpoint) curl_easy_setopt(handle,CURLOPT_NOPROGRESS,1); curl_easy_setopt(handle,CURLOPT_NOSIGNAL,1); curl_easy_setopt(handle,CURLOPT_FAILONERROR,1); - curl_easy_setopt(handle,CURLOPT_SSLVERSION,3); - curl_easy_setopt(handle,CURLOPT_SSL_VERIFYHOST,2); + curl_easy_setopt(handle,CURLOPT_SSL_CIPHER_LIST,"ALL:!aNULL:!LOW:!EXPORT:!SSLv2"); + // Verification of the peer is via TrustEngine only. + curl_easy_setopt(handle,CURLOPT_SSL_VERIFYPEER,0); + curl_easy_setopt(handle,CURLOPT_CAINFO,NULL); curl_easy_setopt(handle,CURLOPT_HEADERFUNCTION,&curl_header_hook); - curl_easy_setopt(handle,CURLOPT_READFUNCTION,&curl_read_hook); curl_easy_setopt(handle,CURLOPT_WRITEFUNCTION,&curl_write_hook); curl_easy_setopt(handle,CURLOPT_DEBUGFUNCTION,&curl_debug_hook); return handle; } -void CURLPool::put(const string& to, const char* endpoint, CURL* handle) +void CURLPool::put(const char* from, const char* to, const char* endpoint, CURL* handle) { - string key = to + "|" + endpoint; + string key(endpoint); + if (from) + key = key + '|' + from; + if (to) + key = key + '|' + to; m_lock->lock(); poolmap_t::iterator i=m_bindingMap.find(key); if (i==m_bindingMap.end()) m_pools.push_front(&(m_bindingMap.insert(poolmap_t::value_type(key,vector(1,handle))).first->second)); else i->second.push_back(handle); - + CURL* killit=NULL; if (++m_size > 256) { // Kick a handle out from the back of the bus. @@ -267,7 +364,7 @@ void CURLPool::put(const string& to, const char* endpoint, CURL* handle) m_size--; break; } - + // Move an empty pool up to the front so we don't keep hitting it. m_pools.pop_back(); m_pools.push_front(corpse); @@ -283,7 +380,7 @@ void CURLPool::put(const string& to, const char* endpoint, CURL* handle) } } -bool CURLSOAPTransport::setAuth(transport_auth_t authType, const char* username, const char* password) const +bool CURLSOAPTransport::setAuth(transport_auth_t authType, const char* username, const char* password) { if (authType==transport_auth_none) { if (curl_easy_setopt(m_handle,CURLOPT_HTTPAUTH,0)!=CURLE_OK) @@ -300,8 +397,8 @@ bool CURLSOAPTransport::setAuth(transport_auth_t authType, const char* username, } if (curl_easy_setopt(m_handle,CURLOPT_HTTPAUTH,flag)!=CURLE_OK) return false; - string creds = string(username ? username : "") + ':' + (password ? password : ""); - return (curl_easy_setopt(m_handle,CURLOPT_USERPWD,creds.c_str())==CURLE_OK); + m_simplecreds = string(username ? username : "") + ':' + (password ? password : ""); + return (curl_easy_setopt(m_handle,CURLOPT_USERPWD,m_simplecreds.c_str())==CURLE_OK); } const vector& CURLSOAPTransport::getResponseHeader(const char* name) const @@ -311,7 +408,7 @@ const vector& CURLSOAPTransport::getResponseHeader(const char* name) con map >::const_iterator i=m_response_headers.find(name); if (i!=m_response_headers.end()) return i->second; - + for (map >::const_iterator j=m_response_headers.begin(); j!=m_response_headers.end(); j++) { #ifdef HAVE_STRCASECMP if (!strcasecmp(j->first.c_str(), name)) @@ -320,7 +417,7 @@ const vector& CURLSOAPTransport::getResponseHeader(const char* name) con #endif return j->second; } - + return emptyVector; } @@ -331,22 +428,46 @@ string CURLSOAPTransport::getContentType() const return content_type ? content_type : ""; } -void CURLSOAPTransport::send(istream& in) +void CURLSOAPTransport::send(istream* in) { #ifdef _DEBUG xmltooling::NDC ndc("send"); #endif - Category& log=Category::getInstance(XMLTOOLING_LOGCAT".SOAPTransport"); + Category& log=Category::getInstance(XMLTOOLING_LOGCAT".SOAPTransport.CURL"); Category& log_curl=Category::getInstance(XMLTOOLING_LOGCAT".libcurl"); + // For this implementation, it's sufficient to check for https as a sign of transport security. + if (m_mandatory && !isConfidential()) + throw IOException("Blocking unprotected HTTP request, transport authentication by server required."); + + string msg; + // By this time, the handle has been prepared with the URL to use and the // caller should have executed any set functions to manipulate it. // Setup standard per-call curl properties. - curl_easy_setopt(m_handle,CURLOPT_POST,1); - curl_easy_setopt(m_handle,CURLOPT_READDATA,&in); - curl_easy_setopt(m_handle,CURLOPT_FILE,&m_stream); curl_easy_setopt(m_handle,CURLOPT_DEBUGDATA,&log_curl); + curl_easy_setopt(m_handle,CURLOPT_FILE,&m_stream); + if (m_chunked && in) { + curl_easy_setopt(m_handle,CURLOPT_POST,1); + m_headers=curl_slist_append(m_headers,"Transfer-Encoding: chunked"); + curl_easy_setopt(m_handle,CURLOPT_READFUNCTION,&curl_read_hook); + curl_easy_setopt(m_handle,CURLOPT_READDATA,in); + } + else if (in) { + char buf[1024]; + while (*in) { + in->read(buf,1024); + msg.append(buf,in->gcount()); + } + curl_easy_setopt(m_handle,CURLOPT_POST,1); + curl_easy_setopt(m_handle,CURLOPT_READFUNCTION,NULL); + curl_easy_setopt(m_handle,CURLOPT_POSTFIELDS,msg.c_str()); + curl_easy_setopt(m_handle,CURLOPT_POSTFIELDSIZE,msg.length()); + } + else { + curl_easy_setopt(m_handle,CURLOPT_HTTPGET,1); + } char curl_errorbuf[CURL_ERROR_SIZE]; curl_errorbuf[0]=0; @@ -354,28 +475,34 @@ void CURLSOAPTransport::send(istream& in) if (log_curl.isDebugEnabled()) curl_easy_setopt(m_handle,CURLOPT_VERBOSE,1); - // Set request headers (possibly appended by hooks). + // Set request headers. curl_easy_setopt(m_handle,CURLOPT_HTTPHEADER,m_headers); - if (m_ssl_callback || m_credResolver || m_trustEngine) { +#ifndef XMLTOOLING_NO_XMLSEC + if (m_ssl_callback || m_cred || m_trustEngine) { +#else + if (m_ssl_callback) { +#endif 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_authenticated=true; } else { curl_easy_setopt(m_handle,CURLOPT_SSL_CTX_FUNCTION,NULL); curl_easy_setopt(m_handle,CURLOPT_SSL_CTX_DATA,NULL); } - - // Verification of the peer is via TrustEngine only. - curl_easy_setopt(m_handle,CURLOPT_SSL_VERIFYPEER,0); // Make the call. - log.info("sending SOAP message to %s", m_endpoint.c_str()); + log.debug("sending SOAP message to %s", m_endpoint.c_str()); if (curl_easy_perform(m_handle) != CURLE_OK) { - log.error("failed communicating with SOAP endpoint: %s", - (curl_errorbuf[0] ? curl_errorbuf : "no further information available")); throw IOException( - string("CURLSOAPTransport::send() failed while contacting SOAP responder: ") + + string("CURLSOAPTransport failed while contacting SOAP endpoint (") + m_endpoint + "): " + (curl_errorbuf[0] ? curl_errorbuf : "no further information available")); } } @@ -410,10 +537,10 @@ size_t xmltooling::curl_header_hook(void* ptr, size_t size, size_t nmemb, void* // callback to send data to server size_t xmltooling::curl_read_hook(void* ptr, size_t size, size_t nmemb, void* stream) { - // *stream is actually an istream object - istream& buf=*(reinterpret_cast(stream)); - buf.read(reinterpret_cast(ptr),size*nmemb); - return buf.gcount(); + // stream is actually an istream pointer + istream* buf=reinterpret_cast(stream); + buf->read(reinterpret_cast(ptr),size*nmemb); + return buf->gcount(); } // callback to buffer data from server @@ -430,15 +557,16 @@ int xmltooling::curl_debug_hook(CURL* handle, curl_infotype type, char* data, si // *ptr is actually a logging object if (!ptr) return 0; CategoryStream log=reinterpret_cast(ptr)->debugStream(); - for (char* ch=data; len && (isprint(*ch) || isspace(*ch)); len--) + for (unsigned char* ch=(unsigned char*)data; len && (isprint(*ch) || isspace(*ch)); len--) log << *ch++; - log << CategoryStream::ENDLINE; 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"); + Category& log=Category::getInstance(XMLTOOLING_LOGCAT".SOAPTransport.CURL"); + log.debug("invoking custom X.509 verify callback"); #if (OPENSSL_VERSION_NUMBER >= 0x00907000L) CURLSOAPTransport* ctx = reinterpret_cast(arg); #else @@ -453,22 +581,50 @@ int xmltooling::verify_callback(X509_STORE_CTX* x509_ctx, void* arg) ); #endif - // 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)) { + bool success=false; + if (ctx->m_criteria) { + ctx->m_criteria->setUsage(Credential::TLS_CREDENTIAL); + // Bypass name check (handled for us by curl). + ctx->m_criteria->setPeerName(NULL); + success = ctx->m_trustEngine->validate(x509_ctx->cert,x509_ctx->untrusted,*(ctx->m_peerResolver),ctx->m_criteria); + } + else { + // Bypass name check (handled for us by curl). + CredentialCriteria cc; + cc.setUsage(Credential::TLS_CREDENTIAL); + success = ctx->m_trustEngine->validate(x509_ctx->cert,x509_ctx->untrusted,*(ctx->m_peerResolver),&cc); + } + + if (!success) { + log.error("supplied TrustEngine failed to validate SSL/TLS server certificate"); x509_ctx->error=X509_V_ERR_APPLICATION_VERIFICATION; // generic error, check log for plugin specifics - return 0; + ctx->setAuthenticated(false); + return ctx->m_mandatory ? 0 : 1; } - + // Signal success. Hopefully it doesn't matter what's actually in the structure now. + ctx->setAuthenticated(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(userptr); - if (conf->m_credResolver) - conf->m_credResolver->attach(ssl_ctx); + + // 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); +#else + SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2); +#endif + +#ifndef XMLTOOLING_NO_XMLSEC + if (conf->m_cred) + conf->m_cred->attach(ssl_ctx); if (conf->m_trustEngine) { SSL_CTX_set_verify(ssl_ctx,SSL_VERIFY_PEER,NULL); @@ -483,9 +639,10 @@ CURLcode xmltooling::xml_ssl_ctx_callback(CURL* curl, SSL_CTX* ssl_ctx, void* us SSL_CTX_set_verify_depth(ssl_ctx,reinterpret_cast(userptr)); #endif } - - if (!conf->m_ssl_callback(ssl_ctx,conf->m_ssl_userptr)) +#endif + + if (conf->m_ssl_callback && !conf->m_ssl_callback(conf, ssl_ctx, conf->m_ssl_userptr)) return CURLE_SSL_CERTPROBLEM; - + return CURLE_OK; }