C语言 SSL_CONNECT 因 SSL_ERROR_SYSCALL 错误而失败
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31183297/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
SSL_CONNECT fails with SSL_ERROR_SYSCALL error
提问by Ragav
Having strange connection failure with openssl SSLConnect with my SSLCLIENT.
我的 SSLCLIENT 与 openssl SSLConnect 发生奇怪的连接失败。
We are trying to establish ssl connection with a server. We notice that SSL_CONNECT is failing with error code "SSL_ERROR_SYSCALL".
我们正在尝试与服务器建立 ssl 连接。我们注意到 SSL_CONNECT 失败,错误代码为“SSL_ERROR_SYSCALL”。
For further depth we tried printing strerror(errno) which return "scuccess" "0".
为了进一步深入,我们尝试打印返回“scuccess”“0”的 strerror(errno)。
However i am just trying to understand what might be the exact cause for this issue
但是我只是想了解这个问题的确切原因可能是什么
Added code snippet for SSL init and connect::
添加了 SSL 初始化和连接的代码片段::
request some guidance:
请求一些指导:
int setupSSL(int server){
int retVal = 0;
int errorStatus = 0;
int retryMaxCount = 6;
static int sslInitContext=0;
if(sslInitContext == 0)
{
if(InitCTX() != 0)
{
return -1;
}
else
{
sslInitContext=1;
}
}
retVal = SSL_set_fd(ssl, server); /* attach the socket descriptor */
if ( retVal != 1 )
{
/* perform the connection */
sprintf(debugBuf,"SYSTEM:SOCKET:Could not set ssl FD: %d %s\n",retVal,strerror(retVal));
debug_log(debugBuf,TRACE_LOG);
CloseSocket(server);
return -1;
}
do
{
retVal = SSL_connect(ssl);
errorStatus = SSL_get_error (ssl, retVal);
switch (errorStatus)
{
case SSL_ERROR_NONE:
retVal = 0;
break;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
retVal = 1;
break;
default:
sprintf(debugBuf,"SYSTEM:SSL_SOCKET:Could not build SSL session(Other error): %d %s\n",errorStatus,strerror(errno));
debug_log(debugBuf,TRACE_LOG);
CloseSocket(server);
return -1;
}
sprintf(debugBuf,"SYSTEM:SSL_SOCKET:SSL CONNECTION Under PROGRESS: %d with remaining retries %d\n",errorStatus,retryMaxCount);
debug_log(debugBuf,TRACE_LOG);
if (retVal)
{
struct timeval tv;
fd_set sockReadSet;
tv.tv_sec = 2;
tv.tv_usec = 0;
FD_ZERO(&sockReadSet);
FD_CLR(server, &sockReadSet);
FD_SET(server,&sockReadSet);
retVal = select(server+1, &sockReadSet, NULL, NULL, &tv);
if (retVal >= 1)
{
retVal = 1;
}
else
{
retVal = -1;
}
retryMaxCount--;
if (retryMaxCount <= 0 )
break;
}
}while(!SSL_is_init_finished (ssl) && retVal == 1);
cert = SSL_get_peer_certificate(ssl);
if(cert == NULL)
{
debug_log("SYSTEM:SSL_SOCKET:Unable to retrive server certificate\n",TRACE_LOG);
CloseSocket(server);
return -1;
}
if(SSL_get_verify_result(ssl)!=X509_V_OK)
{
debug_log("SYSTEM:SSL_SOCKET:Certificate doesn't verify\n",TRACE_LOG);
CloseSocket(server);
return -1;
}
/*X509_NAME_get_text_by_NID (X509_get_subject_name (cert), NID_commonName, peer_CN, 256);
if(strcasecmp(peer_CN, cnName)){
debug_log("SYSTEM:SSL_SOCKET:Common name doesn't match host name\n",TRACE_LOG);
return -1;
}*/
return 0;
// LoadCertificates(ctx, CertFile, KeyFile);
}
int InitCTX(void)
{
int errorStatus = 0;
static int isSslInit = 1;
if(isSslInit)
{
OpenSSL_add_all_algorithms();/* Load cryptos, et.al. */
SSL_load_error_strings();/* Bring in and register error messages */
if(SSL_library_init() < 0)
{
debug_log("SYSTEM:SSL_SOCKET:Could not initialize the OpenSSL library\n",TRACE_LOG);
return -1;
}
method = TLSv1_client_method();
isSslInit=0;
}
ctx = SSL_CTX_new(method);/* Create new context */
if ( ctx == NULL)
{
debug_log("SYSTEM:SSL_SOCKET:Unable to create a new SSL context structure\n",TRACE_LOG);
//sprintf(debugBuf,"SYSTEM:SSL_SOCKET:Unable to create a new SSL context structure: %d %s\n",errorStatus,strerror(retVal));
//debug_log(debugBuf,TRACE_LOG);
return -1;
}
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
if (SSL_CTX_use_certificate_file(ctx,CertFile, SSL_FILETYPE_PEM) <= 0)
{
SSL_CTX_free(ctx);
ctx = NULL;
debug_log("SYSTEM:SSL_SOCKET:Error setting the certificate file.\n",TRACE_LOG);
return -1;
}
/* Set the list of trusted CAs based on the file and/or directory provided*/
if(SSL_CTX_load_verify_locations(ctx,CertFile,NULL)<1)
{
SSL_CTX_free(ctx);
ctx = NULL;
debug_log("SYSTEM:SSL_SOCKET:Error setting verify location.\n",TRACE_LOG);
return -1;
}
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);
SSL_CTX_set_timeout (ctx, 300);
ssl = SSL_new(ctx); /* create new SSL connection state */
if(ssl == NULL)
{
sprintf(debugBuf,"SYSTEM:SOCKET:SSL:Unable to create SSL_new context\n");
debug_log(debugBuf,DEBUG_LOG);
if(ctx != NULL)
SSL_CTX_free(ctx);
return -1;
}
return 0;
}
Also is it advised to maintain SSL context for new connections or should we destroy and re init the ssl context??
还建议为新连接维护 SSL 上下文还是应该销毁并重新初始化 ssl 上下文?
Added PCAP info:
添加了 PCAP 信息:
https://drive.google.com/file/d/0B60pejPe6yiSUk1MMmI1cERMaFU/view?usp=sharing
https://drive.google.com/file/d/0B60pejPe6yiSUk1MMmI1cERMaFU/view?usp=sharing
client: 198.168.51.10 (198.168.51.10), Server: 192.168.96.7 (192.168.96.7)
客户端:198.168.51.10 (198.168.51.10),服务器:192.168.96.7 (192.168.96.7)
回答by Steffen Ullrich
We are trying to establish ssl connection with a server. We notice that SSL_CONNECT is failing with error code "SSL_ERROR_SYSCALL".
我们正在尝试与服务器建立 ssl 连接。我们注意到 SSL_CONNECT 失败,错误代码为“SSL_ERROR_SYSCALL”。
This is usually the case if the other side is simply closing the connection. Microsoft SChannel does this on many kind of handshake problems instead of sending a TLS alert back. This can happen for problems like invalid protocol or no common ciphers etc. It also can happen if you try to do a TLS handshake with a server which does not speak TLS at all on this port. Look at logs at the server side for problems.
如果另一方只是关闭连接,通常就是这种情况。Microsoft SChannel 会针对多种握手问题执行此操作,而不是发送回 TLS 警报。这可能发生在无效协议或没有通用密码等问题上。如果您尝试与在此端口上根本不使用 TLS 的服务器进行 TLS 握手,也会发生这种情况。查看服务器端的日志是否有问题。
Of course it can also be something different so you might check the errno to get more details about the problem. It might also help if you do a packet capture to check what's going on on the wire. Best would be to do this capture on the client and server side to make sure that no middlebox like a firewall is tampering with the connection.
当然,它也可能有所不同,因此您可以检查 errno 以获取有关问题的更多详细信息。如果您进行数据包捕获以检查线路上发生了什么,这也可能会有所帮助。最好在客户端和服务器端进行此捕获,以确保没有像防火墙这样的中间件篡改连接。
Also is it advised to maintain SSL context for new connections or should we destroy and re init the ssl context??
还建议为新连接维护 SSL 上下文还是应该销毁并重新初始化 ssl 上下文?
The context is just a collection of settings, certificates etc and is not affected by the SSL connection itself. You can reuse it for other connection later or at the same time.
上下文只是设置、证书等的集合,不受 SSL 连接本身的影响。您可以稍后或同时将其重新用于其他连接。
EDIT, after the packet capture was attached:
编辑,在附加数据包捕获后:
There are multiple TCP connection in the file between client and server and only inside a single one the client tries to initiate a handshake, i.e. the ClientHello can be seen. The server closes the connection. A few things a interesting:
客户端和服务器之间的文件中有多个 TCP 连接,并且只有在一个内部客户端尝试发起握手,即可以看到 ClientHello。服务器关闭连接。一些有趣的事情:
- TCP handshake takes very long. The server only replies after 1.6 seconds after receiving the SYN with the SYN+ACK. Also the other replies take 800ms which is very long given that both addresses are in a private network (192.168.0.0). This might indicate a slow connection or VPN (this is about the latency of a satellite link), some middlebox (firewall) slowing everything down or a really slow server.
- Client sends TLS 1.0 request. It might be that the server will do only TLS 1.1+. Some TLS stacks (see above) simply close the connection on such errors instead of sending an unsupported protocol alert. But given that the server is slow it might also be old and only support SSL 3.0 or lower.
- Client does not use SNI extension. More and more servers need this and might simply close if they don't get the extension.
- TCP 握手需要很长时间。服务器仅在收到带有 SYN+ACK 的 SYN 后 1.6 秒后才回复。考虑到两个地址都在专用网络 (192.168.0.0) 中,其他回复也需要 800 毫秒,这很长。这可能表示连接或 VPN 速度较慢(这与卫星链接的延迟有关)、某些中间件(防火墙)使一切变慢或服务器速度非常慢。
- 客户端发送 TLS 1.0 请求。可能是服务器只会执行 TLS 1.1+。一些 TLS 堆栈(见上文)只是在出现此类错误时关闭连接,而不是发送不受支持的协议警报。但是考虑到服务器很慢,它也可能很旧并且只支持 SSL 3.0 或更低版本。
- 客户端不使用 SNI 扩展。越来越多的服务器需要这个,如果他们没有得到扩展,可能会直接关闭。
It is hard to know what really is going on without having access to the server. I recommend to look for error messages on the server side and use tools like SSLyzeto check the requirements of the server, i.e. supported TLS versions, ciphers etc.
如果无法访问服务器,就很难知道到底发生了什么。我建议在服务器端查找错误消息并使用SSLyze 等工具检查服务器的要求,即支持的 TLS 版本、密码等。
Apart from that client offers dangerously weak ciphers like various EXPORT ciphers. This looks for me like the defaults of a considerably old OpenSSL version.
除此之外,客户端还提供危险的弱密码,例如各种 EXPORT 密码。这在我看来就像一个相当旧的 OpenSSL 版本的默认值。

![C语言 C 中的 sizeof(char[])](/res/img/loading.gif)