【问题标题】:OpenSSL Bio_gets in client客户端中的 OpenSSL Bio_gets
【发布时间】:2019-06-08 15:52:07
【问题描述】:

我正在尝试使用 OpenSSL 实现一个简单的 SSL 客户端,但我只想读取带有 BIO_gets() 的一行。我在这里得到了一个基于客户端示例的工作测试程序:
https://linux.die.net/man/3/bio_new_ssl_connect。 但在这段代码中,使用了函数BIO.read()。我只是用 BIO_gets 替换 BIO.read 来尝试它,但在这种情况下返回 -2 并且根据文档,此操作未在特定 BIO 类型中实现。我知道示例中的 BIO 是 SSL BIO,而在服务器示例(使用 BIO_gets)中,缓冲 BIO 位于 SSL BIO 之上:

bbio = BIO_new(BIO_f_buffer());
sbio = BIO_push(bbio, sbio);

我尝试将以上两行代码放入我的客户端代码中,但随后程序冻结。所以我的问题是:如何在客户端程序中使用 BIO_gets 一次读取一行?

完整代码:

    SSL_load_error_strings();
    ERR_load_BIO_strings();
    SSL_library_init();

    context = SSL_CTX_new(SSLv23_client_method());

    if(SSL_CTX_set_default_verify_paths(context) == 0){
        fprintf(stderr, "Error: Error: Can't load default verify paths!\n");
        printf("Reason: %s\n", ERR_reason_error_string(ERR_get_error()));
        return -1;
    }

    bio = BIO_new_ssl_connect(context);
    BIO_get_ssl(bio, &ssl);

    if(!ssl){
        fprintf(stderr, "Error: Can't locate SSL pointer\n");
        return -1;
    }

    //Don't want any retries
    SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);


    BIO_set_conn_hostname(bio, connection);

    if(BIO_do_connect(bio) <= 0){
        fprintf(stderr, "Error: Error: Can't load default verify paths!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }

    if(SSL_get_verify_result(ssl) != X509_V_OK)
    {
        fprintf(stderr, "No valid certificate!\n");
        return -1;
    }

    static char recv_buffer[1024]; 

    // Read line
    int len = BIO_gets(bio, recv_buffer, 1024);
    printf("Received: %d, %s", len, recv_buffer);

    return 0;

【问题讨论】:

  • 你能提供你的完整代码吗?
  • 我编辑了问题。

标签: c sockets openssl


【解决方案1】:

你需要这样做:

这将创建新的缓冲 BIO

BIO *bbio = BIO_new(BIO_f_buffer());

现在您必须将其链接到您现有的 SSL BIO

BIO_push(bbio, bio);

然后您可以在此致电BIO_gets()

int len = BIO_gets(bbio, recv_buffer, 1024);

它从文件流中读取类似于fgets() 的单个换行符终止的字符串。

这应该可以如您所愿。

【讨论】:

  • 我已经试过了。当我这样做时,程序冻结在int len = BIO_gets(bio, recv_buffer, 1024);
  • @Quentin 你在哪里连接?你的同龄人是什么?
  • @Quentin 顺便说一句。你上面写的和我在这里提出的不同。你有没有在我写的时候完全尝试过?
  • 我现在明白了。奇怪的是,当我用缓冲区覆盖 ssl bio 时,它不起作用bio = BIO_push(bbio, bio); BIO_gets(bio, recv_buffer, 1024);
【解决方案2】:

我也遇到了同样的问题,只有回想起来,修复才很明显。

TL;DR:BIO_gets 挂起,因为服务器没有发送任何数据。它没有发送数据,因为在初始 BIO_write 中发送的数据仍位于缓冲区 BIO 中。在写入后调用 BIO_flush 以将其从缓冲区中取出,进入套接字并通过线路。

警告 - 我强烈怀疑您的代码示例不完整,特别是它缺少 BIO_write 或 BIO_puts。如果不是,并且您的服务器确实在套接字打开后立即发送数据,那么这个答案可能不适用。

也许你的代码和我的一样进化。我有一些工作,决定我想使用 BIO_gets,并在没有做太多阅读或思考的情况下在那里拍了一个缓冲区。缓冲区自然是双向的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-06
    • 2011-07-08
    • 2014-10-20
    • 2019-10-13
    • 1970-01-01
    • 2017-01-29
    • 1970-01-01
    相关资源
    最近更新 更多