SSL_CONNECT因SSL_ERROR_SYSCALL错误而失败

时间:2015-07-02 11:26:18

标签: c ssl openssl

使用我的SSLCLIENT与openssl SSLConnect发生奇怪的连接失败。

我们正在尝试与服务器建立ssl连接。我们注意到SSL_CONNECT失败,错误代码为“SSL_ERROR_SYSCALL”。

为了进一步深入,我们尝试打印strerror(errno),返回“scuccess”“0”。

但我只是想了解这个问题的确切原因

为SSL init和connect ::

添加了代码段

请求一些指导:

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; 
} 

还建议为新连接维护SSL上下文,还是应该销毁并重新启动ssl上下文?

添加了PCAP信息:

https://drive.google.com/file/d/0B60pejPe6yiSUk1MMmI1cERMaFU/view?usp=sharing

客户:198.168.51.10(198.168.51.10),服务器:192.168.96.7(192.168.96.7)

1 个答案:

答案 0 :(得分:5)

  

我们正在尝试与服务器建立ssl连接。我们注意到SSL_CONNECT失败并显示错误代码&#34; SSL_ERROR_SYSCALL&#34;。

如果另一方只是关闭连接,通常就是这种情况。 Microsoft SChannel在许多类型的握手问题上执行此操作,而不是发回TLS警报。对于无效协议或没有通用密码等问题,可能会发生这种情况。如果您尝试与此端口上根本不说TLS的服务器进行TLS握手,也会发生这种情况。查看服务器端的日志以查找问题。

当然它也可以是不同的东西,所以你可以检查errno以获得有关问题的更多细节。如果您进行数据包捕获以检查线路上发生了什么,这也可能有所帮助。最好是在客户端和服务器端进行此捕获,以确保没有像防火墙这样的中间件篡改连接。

  

还建议为新连接维护SSL上下文,还是应该销毁并重新启动ssl上下文?

上下文只是设置,证书等的集合,不受SSL连接本身的影响。您可以稍后或同时将其重新用于其他连接。

在附加数据包捕获后编辑:

客户端和服务器之间的文件中有多个TCP连接,并且只有一个客户端尝试启动握手,即可以看到ClientHello。服务器关闭连接。一些有趣的事情:

  • TCP握手需要很长时间。服务器仅在收到SYN + ACK的SYN后1.6秒后回复。另外,其他回复需要800毫秒,这是非常长的,因为两个地址都在专用网络(192.168.0.0)中。这可能表示连接速度较慢或VPN(这与卫星链路的延迟有关),某些中间盒(防火墙)会降低所有速度,或者服务器速度很慢。
  • 客户端发送TLS 1.0请求。可能是服务器只会执行TLS 1.1+。某些TLS堆栈(参见上文)只是关闭此类错误的连接,而不是发送不受支持的协议警报。但鉴于服务器速度很慢,它可能也很旧,只支持SSL 3.0或更低版本。
  • 客户端不使用SNI扩展。越来越多的服务器需要这个,如果他们没有获得扩展,可能会关闭。

如果没有访问服务器,很难知道到底发生了什么。我建议在服务器端查找错误消息,并使用SSLyze等工具检查服务器的要求,即支持的TLS版本,密码等。

除了客户端提供危险的弱密码,如各种EXPORT密码。这看起来像是一个相当古老的OpenSSL版本的默认值。