【问题标题】:C++ convert TCP Socket to BIO (OpenSSL)C++ 将 TCP 套接字转换为 BIO (OpenSSL)
【发布时间】:2016-05-14 13:57:00
【问题描述】:

首先我确实搜索了我的问题,但要找到这个主题的确切答案并不容易。

我编写了一个小型 C++ 程序,它通过 SOCKS5 代理连接到 HTTP 网站。这一切都很好。现在我想连接到一个 HTTPS 网站,这造成了一些麻烦..

问题是我不能直接创建 BIO* 并连接到 SOCKS5 代理,我需要先使用未加密的套接字执行 SOCKS5 协议,然后将其转换为 BIO*。我说得对吗?

所以我为正常的 TCP->SOCKS5->网站内容截取了这段代码:

SOCKS5_Greeting_Response socks_gresp;
SOCKS5_Command_Response socks_cresp;
int sock = createSocket();

socketConnect(sock, "127.0.0.1", 9050);

socks_gresp = socketWriteSOCKS5Greeting_TOR(sock);

if(socks_gresp.Version == 5){

    std::cout << "[i] Version match!" << std::endl;

}

socks_cresp = SOCKS5_Connect(sock, get_IPv4("www.google.de"), 80);

if(socks_cresp.Reply == 0){

    std::cout << "[i] Connection success!" << std::endl;

}
else if(socks_cresp.Reply == 1){

    std::cout << "[i] General server error" << std::endl;

}
else if(socks_cresp.Reply == 3){

    std::cout << "[i] Network not reachable" << std::endl;

}
else if(socks_cresp.Reply == 5){

    std::cout << "[i] Connection refused!" << std::endl;

}

之后我可以从 sock 读取/写入,我不想发布所有子功能,因为它会太多......

我在这里读到:Link 1 我应该使用 BIO_new_socket()SSL_set_bio() 我在这里找到了一段代码:Link 2

所以这是我当前的代码片段,试图将 TCP Socket 转换为 BIO*(没有所有错误处理的东西,当一切正常时我将其包括在内):

SSL_library_init();

SOCKS5_Greeting_Response socks_gresp;
SOCKS5_Command_Response socks_cresp;
int sock = createSocket();

socketConnect(sock, "127.0.0.1", 9050);

socks_gresp = socketWriteSOCKS5Greeting_TOR(sock);

if(socks_gresp.Version == 5){

    std::cout << "[i] Version match!" << std::endl;

}

socks_cresp = SOCKS5_Connect(sock, get_IPv4("www.google.de"), 443);

if(socks_cresp.Reply == 0){

    std::cout << "[i] Connection success!" << std::endl;

}
else if(socks_cresp.Reply == 1){

    std::cout << "[i] General server error" << std::endl;

}
else if(socks_cresp.Reply == 3){

    std::cout << "[i] Network not reachable" << std::endl;

}
else if(socks_cresp.Reply == 5){

    std::cout << "[i] Connection refused!" << std::endl;

}

//--

BIO* sslsock = BIO_new_socket(sock, BIO_NOCLOSE);
SSL_CTX * ctx = SSL_CTX_new(SSLv23_client_method());
SSL_CTX_load_verify_locations(ctx, "/path/to/cacert.pem", NULL);
SSL* ssl = SSL_new(ctx);

SSL_set_bio(ssl, sslsock, sslsock);

std::cout << "[i] SSL Write: " << SSL_write(sslsock, generate_basic_GET_request("www.google.de","Mozilla","")) << std::endl;

std::cout << SSL_read(sslsock) << std::endl;

SSL_Close_Connection(sslsock);

//--

closeSocket(sock);

我的 SSL_write() 将在错误时打印出

[i] Version match!
[i] Connection success!
[i] SSL Write: 191
F

我应该在那里看到 HTML 源或 HTTP 响应,而不是“F”。我很确定我在创建 BIO* 时做错了什么,但我不知道是什么。这里有人可以吗?

【问题讨论】:

    标签: c++ sockets ssl openssl


    【解决方案1】:

    您所要求的与其他需要开始未加密然后升级到 SSL/TLS 的情况没有什么不同,例如 SMTP 上的STARTTLS。所以是的,有一些方法可以通过 OpenSSL 的 BIO API 来实现。

    OpenSSL 有自己的 SSL_write()SSL_read() 函数,它们需要 SSL* 作为输入。您正在调用 SSL_write()SSL_read() 函数,它们将 BIO* 作为输入,并直接读取/写入 std::string 值。因此,您显然已经用自定义函数重载了本机函数。而您传递BIO* 的事实让我认为您可能在这些函数中调用BIO_write()BIO_read()。使用SSL_set_bio()时,需要使用原生的SSL_write()SSL_read()函数直接与SSL*进行读写。在内部,他们将根据需要将关联的BIO* 用于较低级别的套接字 I/O。

    话虽如此,虽然上述方法可行,但它也不是在这种情况下使用 BIO API 的唯一方法。另一种方法是使用BIO_new_ssl_connect() 创建一个BIO 链,该链由链接在一起的SSL/TLS BIO 和套接字连接BIO 组成。调用BIO_do_connect() 连接到SOCKS 代理,然后使用BIO_find_type(BIO_TYPE_SOCKET) 从链中检索套接字BIO* 并在其上使用BIO_read()BIO_write() 根据需要执行未加密的SOCKS I/O。准备就绪后,在 SSL/TLS 上调用 BIO_do_handshake() BIO* 以启动 SSL/TLS 握手(将通过已连接的套接字 BIO*),然后在 SSL 上使用 BIO_read()BIO_write() /TLS BIO* 根据需要执行加密 I/O。

    【讨论】:

      【解决方案2】:

      简答:不要使用 OpenSSL BIO,而是使用 libcurl

      【讨论】:

      • OpenSSL BIO 可以很好地满足 OP 的要求。你必须知道如何使用它。
      • 当你似乎知道的时候,为什么不告诉我?
      • 嗯,是的,但是 curl 文档更加详尽,并且您必须随身携带以执行 SSL 连接的神秘废话*t,所以无论如何我都会使用 libcurl。并不是说 OpenSSL 的安全历史还有很多不足之处。
      猜你喜欢
      • 2013-04-18
      • 2019-06-12
      • 2019-07-14
      • 2021-10-26
      • 2020-03-11
      • 2013-02-08
      • 1970-01-01
      • 1970-01-01
      • 2011-11-22
      相关资源
      最近更新 更多