Outputs from Pegasus Tracer:
SSL: Not connected 1 error:140740BF:SSL routines:SSL23_CLIENT_HELLO:no protocols available SSL: Deleted SSL socket
这是消息的来源:
$ grep -nR "Deleted SSL socket" *
src/Pegasus/Common/TLS.cpp:172: PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL3, "---> SSL: Deleted SSL socket");
第 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();
}
如果您查看.../src/Pegasus/Common/SSLContext.cpp
,您将看到:
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()));
}
}
...
}
我会出于两个原因放弃该功能,并添加类似以下内容。
首先,它是编写为既是客户端又是服务器的非晶例程之一。我从使用 OpenSSL 的经验中发现,你有单独的函数SSL_CTX* GetClientContext()
和SSL_CTX* GetServerContext()
.
其次,从安全工程的角度来看,你不允许人们进入一个糟糕的状态,比如PEGASUS_SSL_WEAKENCRYPTION
一个空的密码列表。你把枪拿走,这样他们就不会在脚上开枪了。
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 和 AEAD 密码套件是一个很好的选择。但是,对于大多数意图和目的而言,TLS 1.0 及更高版本都可以。
我认为这可能是0x140740BF
在客户端的原因。它来自第SSLContext.cpp
824 行:
SSL_CTX_set_verify(sslContext,
SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, prepareForCallback);
看起来服务器需要证书。
...但通常您会收到不同的 TLS 警报。
并且消息来源没有调用SSL_set_tlsext_host_name
,因此 SNI 似乎已损坏。您可能应该为此提交一份错误报告...
$ grep -nR SSL_set_tlsext_host_name *
$
您必须弄清楚客户端在哪里建立连接,并将其设置为SSL*
选项:
SSL_set_tlsext_host_name(ssl, hostname);
某个地方SSLSocket::SSLSocket
可能是一个不错的选择,因为它的构造函数接受一个字符串,并且sslConnection
在 ctor 中可用。
SSLSocket::SSLSocket(
SocketHandle socket,
SSLContext * sslcontext,
ReadWriteSem * sslContextObjectLock,
const String& ipAddress)
但我很确定你需要一个 DNS 名称而不是 IP 地址,因为在同一个 IP 上多路复用不同服务器是首先需要 SNI 的原因。
但我可能是错的。const String& ipAddress
实际上可能是 DNS 名称。