C++将TCP套接字转换为BIO(OpenSSL)

C++ convert TCP Socket to BIO (OpenSSL)

本文关键字:BIO OpenSSL 转换 TCP 套接字 C++      更新时间:2023-10-16

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

我写了一个小型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;
}

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

好吧,我在这里阅读:链接 1 我应该使用BIO_new_socket()SSL_set_bio()我在这里找到了一个截取的代码:链接 2

所以这是我当前的代码截取,试图将 TCP 套接字转换为 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(( 将在错误时打印出 <0,否则字节发送。这是我的输出:

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

而不是"F",我应该在那里看到HTML源代码或HTTP响应。我很确定我在创建 BIO* 时做了一些错误的事情,但我说不出是什么。这里有人可以吗?

您所要求的与其他需要启动未加密然后稍后升级到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*上调用 BIO_do_handshake() 以启动 SSL/TLS 握手(将通过已连接的套接字BIO*(,然后在 SSL/TLS BIO*上使用BIO_read()BIO_write()根据需要执行加密的 I/O。

简短的回答:不要使用OpenSSL BIO而使用libcurl。