【问题标题】:SSL_accept() fails with return value -1SSL_accept() 失败,返回值 -1
【发布时间】:2017-10-30 18:39:51
【问题描述】:

为了理解SSL/TLS,我在Windows-7上下载了OpenSSL-1.0.2k,并用Cygwingcc64 bit编译器编译。我从OpenSSL server/client example in c 中获取了off-the-shelf 的服务器/客户端示例,并使用cygwin gcc 编译。第一次编译就成功了。我使用以下命令从cmd 执行服务器和客户端。

(Server)   D:\>ssl-server.exe 5000
(Client)   D:\>ssl-client.exe 127.0.0.1 5000

客户端没有任何响应就退出,但另一方面,服务器显示它已建立连接,例如;

Connection: 127.0.0.1:50475

并无限等待下一行。

然后我开始调试服务器端,发现​​过程void Servlet(SSL* ssl)中的SSL_accept()返回了-1的值,这是意料之外的。我从OpenSSLopenSSL DOC咨询了文档;

TLS/SSL 握手不成功,因为在协议级别发生了致命错误或发生了连接失败。关机不干净。也可能发生需要继续非阻塞 BIO 操作的操作。使用返回值 ret 调用 SSL_get_error() 以找出原因。

SSL_get_error() 返回SSL_ERROR_SYSCALL。我在这个电话之后检查了errno 的值,我看到了no errorServlet 方法的完整代码如下。其余代码与链接相同。

void Servlet(SSL* ssl) /* Serve the connection -- threadable */
{   char buf[1024];
    char reply[1024];
    int sd, bytes;
    const char* HTMLecho="<html><body><pre>%s</pre></body></html>\n\n";
    int ret;
    ret = SSL_accept(ssl);  /* do SSL-protocol accept */ 
    if ( ret == -1 )    
    {
        // printf(" SSL_accept() returned -1\n");
        switch(SSL_get_error(ssl, ret) )
        {
            case SSL_ERROR_SYSCALL:
                perror("errno");
                break;
            default:
                printf( "default" );
                break;
        }
        exit(-1);
    }
    else if ( ret == 0)
    {
        printf(" SSL_accept() returned 0\n");
        exit(-1);
    }
    else if ( ret == 1) // The TLS/SSL connection has been established. 
    {
        ShowCerts(ssl);        /* get any certificates */
        bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
        if ( bytes > 0 )
        {
            buf[bytes] = 0;
            printf("Client msg: \"%s\"\n", buf);
            sprintf(reply, HTMLecho, buf);   /* construct reply */
            SSL_write(ssl, reply, strlen(reply)); /* send reply */
        }
        else
            ERR_print_errors_fp(stderr);
    }
    sd = SSL_get_fd(ssl);       /* get socket connection */
    SSL_free(ssl);         /* release SSL state */
    close(sd);          /* close connection */
}

【问题讨论】:

  • 那么SSL_get_error()的值是多少?
  • switch-case 进入默认情况。 printf("default\n"); 从我的代码中执行。 printf("ret: %i\n", ret);switch 之前的行输出-1
  • 所以你得到了SSL_ERROR_SYCALL,现在你必须找到errno的值,或者调用perror()。这都是有据可查的。所有这些信息都应该已经包含在问题中了。
  • 你已经用你能想到的一切编辑了你的问题除了我现在问了三四次,从一个多小时前开始。现在是您停止猜测和胡闹的时候了,开始注意这里告诉您的内容以及要求您提供的内容。
  • 您正在运行您无休止且毫无意义地摆弄的代码,因此与原始代码相比,它可能无法识别。您需要为 SSL_ERROR_SYSCALL 添加一个案例并在其中调用perror("SSL_accept")。我认为这也是微不足道的。我注意到,两个小时后,我们仍然没有比两个小时前更接近解决实际问题。

标签: sockets tcp openssl


【解决方案1】:
  1. 当您没有遇到您列举的 SSL_ERROR_ 案例之一时,您应该跟踪 SSL_get_error() 的值,以便开始调试。而不是只是举手。
  2. 在这种情况下,值为SSL_ERROR_SYSCALL。你没有在你认为应该的地方抓住它,因为case (SSL_ERROR_SYSCALL || SSL_ERROR_SSL || SSL_ERROR_WANT_CONNECT || SSL_ERROR_WANT_ACCEPT): 没有按照你的想法做。由于|| 的语义,它将变成case 1。每个值都应该有单独的 case 语句。
  3. SSL_ERROR_SYSCALL 表示基础错误在 errno 中,根据您自己引用的文档,这意味着您应该跟踪 那个。而不是仅仅举手。请注意,您必须在调用任何其他系统调用之前这样做(例如通过printf() 调用write()),因此立即保存errno 可能会有所帮助。
  4. 您可以直接使用printf("errno=%d\n", errno) 打印errno,但打印错误消息 会更有用,您可以使用perror()printf("error=%s\n", strerror(errno)) 来执行此操作。
  5. SSL_get_error() 的值不是 errno 值,也不是您开始使用的原始 -1。 errno 值来自 errno 变量。
  6. 但是你不应该做任何这些事情除非SSL_accept()返回-1,这里没有实际证据。

所以这里完全有可能完全没有错误。

【讨论】:

  • SSL_accept() 返回-1,我确定了。我还用更多细节重新构建了我的问题并删除了额外的内容。
  • 那么perror()打印了什么? 最初的问题是昨天?
  • 第4项的函数应该是strerror(errno)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多