C ++将TCP Socket转换为BIO(OpenSSL)

时间:2016-02-04 19:22:41

标签: c++ sockets ssl openssl

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

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

}

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

我在这里读到: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()将打印出来&lt;错误时为0,否则发送字节。这是我的输出:

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

而不是'F'我应该在那里看到HTML源代码或HTTP响应。我很确定我在创建BIO *时做了一些虚假的事情,但我不知道是什么。这里的任何人都可以吗?

2 个答案:

答案 0 :(得分: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*),然后使用{{1}并且SSL / TLS BIO_read()上的BIO_write()BIO*可以根据需要执行加密I / O.

答案 1 :(得分:-2)

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