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.