*/
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.
* 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
/**
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
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);
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);
}
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) {
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;
}
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 {
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);
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)
{
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);
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");
// 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);
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;