OpenSSL 1.0.1 SSL_read()函数在某些https网站上返回0字节
我正试图通过OpenSSL 1.0.1 SSL_read()函数在某些https网站上返回0字节,ssl,https,openssl,httpclient,Ssl,Https,Openssl,Httpclient,我正试图通过openssl1.0.1u创建一个https客户端,它可以访问使用ssl协议的网站。 当访问大多数https网站(如google.com、yahoo.com、facebook.com等)时,它运行良好,并且返回主页内容。但是,有些网站(相对较小的网站),服务器返回0字节,以下是一些详细信息: 我使用SSLv23\u method()创建我的openssl上下文: this->_sslContext = SSL_CTX_new(SSLv23_method()); // SSLv2
openssl1.0.1u
创建一个https客户端,它可以访问使用ssl协议的网站。
当访问大多数https网站(如google.com、yahoo.com、facebook.com等)时,它运行良好,并且返回主页内容。但是,有些网站(相对较小的网站),服务器返回0字节,以下是一些详细信息:
我使用SSLv23\u method()
创建我的openssl上下文:
this->_sslContext = SSL_CTX_new(SSLv23_method()); // SSLv23_method: Negotiate highest available SSL/TLS version
然后我发现在以下调用序列中(向前列出):
对于某些网站(失败的情况),函数SSL\u read()
返回0字节,因为在函数ssl3\u read\u bytes()
中,我将警报描述设置为SSL\u AD\u CLOSE\u NOTIFY
,然后函数只返回0,以下是源代码:
...
if (alert_level == SSL3_AL_WARNING)
{
s->s3->warn_alert = alert_descr;
if (alert_descr == SSL_AD_CLOSE_NOTIFY) {
s->shutdown |= SSL_RECEIVED_SHUTDOWN;
return (0);
}
有人能给我一些提示来解决这个问题吗?谢谢
==更新===
根据他的建议,我发布了发送请求/获取响应的源代码。我的小型实验性https客户端由Socket
和SSLSocket
类和一个助手WebpageFetcher
类组成。函数WebpageFetcher::fetchPage
用于发送https请求并从私有函数WebpageFetcher::\u getResponse()
:
调用工厂函数时,我将参数usesl
与true
一起传递,因此我得到的套接字是一个SSLSocket实例,它覆盖默认函数connect()
,\u send()
和\u recv()
,以让openssl执行实际工作。下面是我的SSLSocket类的构造函数,它派生自类Socket:
SSLSocket::SSLSocket(bool isServerSocket, int port, int socketType, int socketProtocol, int uOptions, wchar_t * strBindingAddress, wchar_t * cerPath, wchar_t * keyPath, wchar_t * keyPass) :
Socket(isServerSocket, port, socketType, socketProtocol, uOptions, strBindingAddress)
{
// Register the error strings
SSL_load_error_strings();
// Register the available ciphers and digests
SSL_library_init();
// Create an SSL_CTX structure by choosing a SSL/TLS protocol version
this->_sslContext = SSL_CTX_new(SSLv23_method()); // Use SSL 2 or SSL 3
// Create an SSL struct (client only, server does not need one)
this->_sslHandle = (this->_isServer ? NULL : SSL_new(this->_sslContext));
bool success = false;
if (!this->_isServer) // is Client socket
{
success = (this->_sslHandle != NULL);
}
else if (cerPath != NULL && keyPath != NULL) // is Server socket
{
success = ......
}
if (!success)
this->close();
}
下面是函数覆盖父类套接字中的虚拟函数,它允许openssl执行相关工作:
bool SSLSocket::connect(wchar_t * strDestination, int port, int timeout)
{
SocketAddress socketAddress(strDestination, port);
return this->connect(&socketAddress, timeout);
}
bool SSLSocket::connect(SocketAddress * sockAddress, int timeout)
{
bool success =
(this->_sslHandle != NULL &&
Socket::connect(sockAddress, timeout) && // Regular TCP connection
SSL_set_fd(this->_sslHandle, (int)this->_hSocket) == 1 && // Connect the SSL struct to our connection
SSL_connect(this->_sslHandle) == 1); // Initiate SSL handshake
if (!success)
this->close();
return success;
}
int SSLSocket::_recv(void * lpBuffer, int size, int flags)
{
MonitorLock cs(&_mutex);
return SSL_read(this->_sslHandle, lpBuffer, size);
}
int SSLSocket::_send(const void * lpBuffer, int size, int flags)
{
return SSL_write(this->_sslHandle, lpBuffer, size);
}
1.0.1u是一个非常旧的OpenSSL版本(当前版本为1.1.1k,3.0目前正在进行alpha测试)。OpenSSL开发团队在2016年底放弃了对1.0.1系列的支持ssl\u read()
返回0表示服务器关闭了TCP连接,可能是因为您使用的是如此旧的版本。例如,1.0.1是支持TLS1.2的第一个版本,但您的代码没有使用SNI,而大多数现代web服务器在使用TLS1.2时都需要SNI。你需要升级你的OpenSSL。嗨,雷米,我高度相信你的预测是正确的,因为所有失败的案例都是当我尝试访问托管在共享web服务器上的https网站并使用某种虚拟域时。我对TLS/SSL握手和SNI非常陌生,只是想知道您是否可以提供一个指向好教程的链接?这可能会让我得到最终的答案。嗨,雷米,我采纳了你的建议,找到了SNI的教程,然后我在连接之前添加了“SSL\u set\u tlsext\u host\u name(SSL,domainName)”,效果很好!如果你能再发一次,我可以接受你的建议。
SSLSocket::SSLSocket(bool isServerSocket, int port, int socketType, int socketProtocol, int uOptions, wchar_t * strBindingAddress, wchar_t * cerPath, wchar_t * keyPath, wchar_t * keyPass) :
Socket(isServerSocket, port, socketType, socketProtocol, uOptions, strBindingAddress)
{
// Register the error strings
SSL_load_error_strings();
// Register the available ciphers and digests
SSL_library_init();
// Create an SSL_CTX structure by choosing a SSL/TLS protocol version
this->_sslContext = SSL_CTX_new(SSLv23_method()); // Use SSL 2 or SSL 3
// Create an SSL struct (client only, server does not need one)
this->_sslHandle = (this->_isServer ? NULL : SSL_new(this->_sslContext));
bool success = false;
if (!this->_isServer) // is Client socket
{
success = (this->_sslHandle != NULL);
}
else if (cerPath != NULL && keyPath != NULL) // is Server socket
{
success = ......
}
if (!success)
this->close();
}
bool SSLSocket::connect(wchar_t * strDestination, int port, int timeout)
{
SocketAddress socketAddress(strDestination, port);
return this->connect(&socketAddress, timeout);
}
bool SSLSocket::connect(SocketAddress * sockAddress, int timeout)
{
bool success =
(this->_sslHandle != NULL &&
Socket::connect(sockAddress, timeout) && // Regular TCP connection
SSL_set_fd(this->_sslHandle, (int)this->_hSocket) == 1 && // Connect the SSL struct to our connection
SSL_connect(this->_sslHandle) == 1); // Initiate SSL handshake
if (!success)
this->close();
return success;
}
int SSLSocket::_recv(void * lpBuffer, int size, int flags)
{
MonitorLock cs(&_mutex);
return SSL_read(this->_sslHandle, lpBuffer, size);
}
int SSLSocket::_send(const void * lpBuffer, int size, int flags)
{
return SSL_write(this->_sslHandle, lpBuffer, size);
}