From 292a2ef8764a62f85c014e05db49a5e7c86d1542 Mon Sep 17 00:00:00 2001 From: cantor Date: Wed, 22 Nov 2006 22:48:02 +0000 Subject: [PATCH] Add security indicator to transport, set by SSL callback, maintain across CURL reuse. git-svn-id: https://svn.middleware.georgetown.edu/cpp-xmltooling/trunk@207 de75baf8-a10c-0410-a50a-987c0e22f00f --- xmltooling/soap/OpenSSLSOAPTransport.h | 12 ++++++-- xmltooling/soap/SOAPTransport.h | 17 +++++++++-- xmltooling/soap/impl/CURLSOAPTransport.cpp | 45 ++++++++++++++++++++++++++---- 3 files changed, 64 insertions(+), 10 deletions(-) diff --git a/xmltooling/soap/OpenSSLSOAPTransport.h b/xmltooling/soap/OpenSSLSOAPTransport.h index 5620d78..6e3182c 100644 --- a/xmltooling/soap/OpenSSLSOAPTransport.h +++ b/xmltooling/soap/OpenSSLSOAPTransport.h @@ -20,10 +20,9 @@ * Encapsulates OpenSSL-capable SOAP transport layer. */ -#if !defined(__xmltooling_opensslsoaptrans_h__) && !defined(XMLTOOLING_NO_XMLSEC) +#ifndef __xmltooling_opensslsoaptrans_h__ #define __xmltooling_opensslsoaptrans_h__ -#include #include #include @@ -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; }; }; diff --git a/xmltooling/soap/SOAPTransport.h b/xmltooling/soap/SOAPTransport.h index 395a327..0c42f02 100644 --- a/xmltooling/soap/SOAPTransport.h +++ b/xmltooling/soap/SOAPTransport.h @@ -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 diff --git a/xmltooling/soap/impl/CURLSOAPTransport.cpp b/xmltooling/soap/impl/CURLSOAPTransport.cpp index da8a3f5..1212602 100644 --- a/xmltooling/soap/impl/CURLSOAPTransport.cpp +++ b/xmltooling/soap/impl/CURLSOAPTransport.cpp @@ -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(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(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 > 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& 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(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(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; -- 2.1.4