Reputation: 41
I would like to build new version of Open Pegasus Client (2.14.1). Unfortunately I'm facing with some build issues. Does anybody know some workaround for these issues?
My environment is:
My scenario is quite easy:
After extraction of Pegasus source code I set my environment with these settings:
call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\vcvars32.bat"
set PEGASUS_ROOT=D:/Dev/pegasus-2.14.1/pegasus
set PEGASUS_HOME=%PEGASUS_ROOT%
set PEGASUS_PLATFORM=WIN32_IX86_MSVC
set path=%path%;%PEGASUS_HOME%\bin
set OPENSSL_HOME=D:/Dev/OpenSSL-Win32
set PEGASUS_HAS_SSL=true
Next step was building of mu.exe tool. So, I have executed "make buildmu" => successfully build and copied to "/bin" folder. I would like to build Pegasus so: "make build" => after some time I got this error:
Message.cpp(433) : error C2065: 'magic' : undeclared identifier
I tried to fix this problem. I found that magic constant is defined in \pegasus-2.14.1\pegasus\src\Pegasus\Common\Linkable.h file so I had two options: a) Switch build configuration to DEBUG (set PEGASUS_DEBUG=true) b) Remove DEBUG condition from lines 62 in Linkable.h file Then, I tried to build Pegasus again, unfortunately I got this error:
error LNK2005: _OPENSSL_Applink already defined in SSLContext.obj
At this point I have no clue how to fix this problem. I just tried to remove these lines:
# ifdef PEGASUS_OS_TYPE_WINDOWS
# include<openssl/applink.c>
# endif
from SSLContextRep.h file. After this modification I was able to get Pegasus clients binaries. But these binaries work just without SSL, when I want to use SSL communication I always got error: " Pegasus Exception: 'Cannot connect to 10.199.1.139:5989. Connection failed.'.", so I assume that is because my code modification in SSLContextRep.h.
Outputs from Pegasus Tracer:
SSL: Not connected 1 error:140740BF:SSL routines:SSL23_CLIENT_HELLO:no protocols available SSL: Deleted SSL socket
Does anybody know what can be wrong? Does somebody own some (better) environment configuration steps for Windows to build OpenPegasus?
Many thanks in advance for any kind of help.
Edit:
I need to be able work without certificates. Because I'm using SSL communication with various Storage Arrays and I don't have their certificates. Therefore I'm using this constructor of SSLContext:
SSLContext sslContext(String::EMPTY, NULL, String::EMPTY);
this approach works for me fine in the OpenPegasus 2.13 version.
Upvotes: 3
Views: 1234
Reputation: 41
I got response from Open Pegasus dev team. They created bug for the issue with "magic" constant. Also they recommending in my case to use sslBackwardCompatibility = true configuration for the build.
This setting helped me partially. For some Storage Arrays the SSL communication started work. But for some it still reporting "Cannot connect" exception.
Only workaround what I found is to replace code of _makeSSLContext() method with code from OpenPegasus 2.13 version. After this modification I'm able to use SSL communication with all my Storage Arrays + all features from new Pegasus version.
Upvotes: 1
Reputation: 102346
Outputs from Pegasus Tracer:
SSL: Not connected 1 error:140740BF:SSL routines:SSL23_CLIENT_HELLO:no protocols available SSL: Deleted SSL socket
Here's where the message is coming from:
$ grep -nR "Deleted SSL socket" *
src/Pegasus/Common/TLS.cpp:172: PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL3, "---> SSL: Deleted SSL socket");
And the code around line 172:
SSLSocket::~SSLSocket()
{
PEG_METHOD_ENTER(TRC_SSL, "SSLSocket::~SSLSocket()");
close();
delete static_cast<SharedPtr<X509_STORE, FreeX509STOREPtr>*>(_crlStore);
SSL_free(static_cast<SSL*>(_SSLConnection));
PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL3, "---> SSL: Deleted SSL socket");
PEG_METHOD_EXIT();
}
If you look in .../src/Pegasus/Common/SSLContext.cpp
, you will see:
SSL_CTX* SSLContextRep::_makeSSLContext()
{
PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::_makeSSLContext()");
//
// create SSL Context Area
//
SSL_CTX *sslContext = NULL;
if (!(sslContext = SSL_CTX_new(SSLv23_method())))
{
PEG_METHOD_EXIT();
MessageLoaderParms parms(
"Common.SSLContext.COULD_NOT_GET",
"Could not get SSL CTX");
throw SSLException(parms);
}
int options = SSL_OP_ALL;
SSL_CTX_set_options(sslContext, options);
if ( _sslCompatibility == false )
{
#ifdef TLS1_2_VERSION
// Enable only TLSv1.2 and disable all other protocol (SSL v2, SSL v3,
// TLS v1.0, TLSv1.1)
options = SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_SSLv3;
#else
PEG_METHOD_EXIT();
MessageLoaderParms parms(
" Common.SSLContext.TLS_1_2_PROTO_NOT_SUPPORTED",
"TLSv1.2 protocol support is not detected on this system. "
" To run in less secured mode, set sslBackwardCompatibility=true"
" in planned config file and start cimserver.");
throw SSLException(parms);
#endif
}
// sslv2 is off permanently even if sslCompatibility is true
options |= SSL_OP_NO_SSLv2;
SSL_CTX_set_options(sslContext, options);
#ifdef PEGASUS_SSL_WEAKENCRYPTION
if (!(SSL_CTX_set_cipher_list(sslContext, SSL_TXT_EXP40)))
{
SSL_CTX_free(sslContext);
sslContext = NULL;
MessageLoaderParms parms(
"Common.SSLContext.COULD_NOT_SET_CIPHER_LIST",
"Could not set the cipher list");
throw SSLException(parms);
}
#endif
if (_cipherSuite.size() != 0)
{
if (!(SSL_CTX_set_cipher_list(sslContext, _cipherSuite.getCString())))
{
SSL_CTX_free(sslContext);
sslContext = NULL;
PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL3,
"---> SSL: Cipher Suite could not be specified");
MessageLoaderParms parms(
"Common.SSLContext.COULD_NOT_SET_CIPHER_LIST",
"Could not set the cipher list");
throw SSLException(parms);
}
else
{
PEG_TRACE((TRC_SSL, Tracer::LEVEL3,
"---> SSL: Cipher suite set to %s",
(const char *)_cipherSuite.getCString()));
}
}
...
}
I would ditch that function for two reasons, and add something like the following instead.
First, its one of those amorphic routines written to be both client and server. What I have found from my experience with OpenSSL, is you have separate functions for SSL_CTX* GetClientContext()
and SSL_CTX* GetServerContext()
.
Second, from a Security Engineering perspective, you don't allow folks to get into a bad state with things like PEGASUS_SSL_WEAKENCRYPTION
or an empty cipher list. You take the gun away so they can't shoot themselves in the foot.
SSL_CTX* SSLContextRep::_makeSSLContext()
{
PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::_makeSSLContext()");
SSL_CTX *sslContext = NULL;
if (!(sslContext = SSL_CTX_new(SSLv23_method())))
{
PEG_METHOD_EXIT();
MessageLoaderParms parms(
"Common.SSLContext.COULD_NOT_GET",
"Could not get SSL CTX");
throw SSLException(parms);
}
// TLS 1.0 and above. No compression because it leaks information.
static const long options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION;
SSL_CTX_set_options(sslContext, options);
const char* const PREFERRED_CIPHERS = "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4";
int res = SSL_set_cipher_list(sslContext, PREFERRED_CIPHERS);
if(res != 1)
{
PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL3,
"---> SSL: Cipher Suite could not be specified");
MessageLoaderParms parms(
"Common.SSLContext.COULD_NOT_SET_CIPHER_LIST",
"Could not set the cipher list");
throw SSLException(parms);
}
// Keep this stuff
SSL_CTX_set_quiet_shutdown(sslContext, 1);
SSL_CTX_set_mode(sslContext, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_mode(sslContext, SSL_MODE_ENABLE_PARTIAL_WRITE);
SSL_CTX_set_session_cache_mode(sslContext, SSL_SESS_CACHE_OFF);
SSL_CTX_set_mode(sslContext, SSL_MODE_RELEASE_BUFFERS);
// Back to gutting. We don't allow VERIFY_PEER_NONE.
{
PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL4,
"---> SSL: certificate verification callback specified");
SSL_CTX_set_verify(sslContext,
SSL_VERIFY_PEER, prepareForCallback);
}
// Some more gutting. Certificates have to be verified.
if(_trustStore.size() == 0)
{
PEG_TRACE((TRC_SSL, Tracer::LEVEL1,
"---> SSL: Could not load certificates from the "
"trust store: %s",
(const char*)_trustStore.getCString()));
MessageLoaderParms parms(
"Common.SSLContext.COULD_NOT_LOAD_CERTIFICATES",
"Could not load certificates in to trust store.");
SSL_CTX_free(sslContext);
sslContext = NULL;
PEG_METHOD_EXIT();
throw SSLException(parms);
}
if ( !SSL_CTX_load_verify_locations(
sslContext, _trustStore.getCString(), NULL) )
{
PEG_TRACE((TRC_SSL, Tracer::LEVEL1,
"---> SSL: Could not load certificates from the "
"trust store: %s",
(const char*)_trustStore.getCString()));
MessageLoaderParms parms(
"Common.SSLContext.COULD_NOT_LOAD_CERTIFICATES",
"Could not load certificates in to trust store.");
SSL_CTX_free(sslContext);
sslContext = NULL;
PEG_METHOD_EXIT();
throw SSLException(parms);
}
// I'm not sure what to do with CRLs. They are usually a DoS waiting to happen....
if (_crlPath.size() != 0)
{
// need to save this -- can we make it static since there's only
// one CRL for cimserver?
X509_LOOKUP* pLookup;
_crlStore.reset(X509_STORE_new());
if (_crlStore.get() == NULL)
{
SSL_CTX_free(sslContext);
sslContext = NULL;
PEG_METHOD_EXIT();
throw PEGASUS_STD(bad_alloc)();
}
// the validity of the crlstore was checked in ConfigManager
// during server startup
if (FileSystem::isDirectory(_crlPath))
{
PEG_TRACE((TRC_SSL, Tracer::LEVEL4,
"---> SSL: CRL store is a directory in %s",
(const char*)_crlPath.getCString()));
if ((pLookup = X509_STORE_add_lookup(
_crlStore.get(), X509_LOOKUP_hash_dir())) == NULL)
{
MessageLoaderParms parms(
"Common.SSLContext.COULD_NOT_LOAD_CRLS",
"Could not load certificate revocation list.");
_crlStore.reset();
SSL_CTX_free(sslContext);
sslContext = NULL;
PEG_METHOD_EXIT();
throw SSLException(parms);
}
X509_LOOKUP_add_dir(
pLookup, (const char*)_crlPath.getCString(), X509_FILETYPE_PEM);
PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL3,
"---> SSL: Successfully configured CRL directory");
}
else
{
PEG_TRACE((TRC_SSL, Tracer::LEVEL4,
"---> SSL: CRL store is the file %s",
(const char*)_crlPath.getCString()));
if ((pLookup = X509_STORE_add_lookup(
_crlStore.get(), X509_LOOKUP_file())) == NULL)
{
MessageLoaderParms parms(
"Common.SSLContext.COULD_NOT_LOAD_CRLS",
"Could not load certificate revocation list.");
_crlStore.reset();
SSL_CTX_free(sslContext);
sslContext = NULL;
PEG_METHOD_EXIT();
throw SSLException(parms);
}
X509_LOOKUP_load_file(
pLookup, (const char*)_crlPath.getCString(), X509_FILETYPE_PEM);
PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL4,
"---> SSL: Successfully configured CRL file");
}
}
Boolean keyLoaded = false;
// Gut server specific certificate and key routines since this is a client.
PEG_METHOD_EXIT();
return sslContext;
}
TLS 1.2 and the AEAD cipher suites are a very good choice. However, for most intents and purposes, TLS 1.0 and above is fine.
I think this might be the cause of 0x140740BF
in the client. Its from line SSLContext.cpp
, 824:
SSL_CTX_set_verify(sslContext,
SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, prepareForCallback);
It looks like the server requires a certificate.
... but usually you get a different TLS alert.
And the sources does not call SSL_set_tlsext_host_name
, so SNI appears to be broken. You should probably file a bug report for this one...
$ grep -nR SSL_set_tlsext_host_name *
$
You will have to figure out where the client makes its connection, and set that as a SSL*
option:
SSL_set_tlsext_host_name(ssl, hostname);
Somewhere around SSLSocket::SSLSocket
might be a good choice because its constructor takes a string and the sslConnection
is available in the ctor.
SSLSocket::SSLSocket(
SocketHandle socket,
SSLContext * sslcontext,
ReadWriteSem * sslContextObjectLock,
const String& ipAddress)
But I'm pretty sure you need a DNS name and not an IP address because the multiplexing of different servers on the same IP is what caused the need for SNI in the first place.
But I could be wrong. const String& ipAddress
could actually be a DNS name.
Upvotes: 1