gpt4 book ai didi

c++ - 仅 OpenSSL BIO : single SSL_write broken in two SSL records with TLS 1. 0

转载 作者:可可西里 更新时间:2023-11-01 02:32:41 25 4
gpt4 key购买 nike

我想使用以下代码发送此消息“Hello world!\n Bye world!”。此代码以 2 条 SSL 记录发送消息,但我需要以 1 条 SSL 记录发送。

我读了一些关于 base64 的文章 herehere但我不知道如何在我的代码中使用它们!谁能帮我解决我的问题。

问题:我想发送消息的一部分,而不是用“\n”分隔的两部分!

更多说明: 我使用 OpenSSL s_client 连接它,我强制它使用 TLSv1 并使用 wireshark 嗅探网络。实际上这段代码是简化了一个更大的项目作为数据库代理。在主项目中,我们需要向不受我们控制的服务器发送一条消息,它只能处理 1 条 SSL 记录。

我的 OpenSSL 命令:

s_client -connect 127.0.0.1:9999 -tls1

消息的 Wireshark 结果:

17 03 01 00 24 db f3 59 37 98 78 3b b6 06 b0 c1 66 0c 78 04 4d 50 60 54 19 37 fe 
77 65 27 7f 4e e8 4e 9a d7 94 66 3f 0d 03 17 03 01 00 34 83 a8 39 b3 3e 9a 35 7b
a2 64 07 35 9b c5 d7 d0 c9 03 3c 43 ac d8 1c ad d5 0f 55 34 10 6c 99 3e 57 b1 51
d4 a5 36 6a 8e 23 08 e0 2d 33 c1 53 63 4e d2 bd bd

我的模拟代码:

#include <cstdlib>
#include <iostream>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <unistd.h>

using namespace std;

static void ssl_set_sys_error(int ssl_error)
{
int error = 0;

switch (ssl_error) {
case SSL_ERROR_ZERO_RETURN:
error = 0;
break;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
#ifdef SSL_ERROR_WANT_CONNECT
case SSL_ERROR_WANT_CONNECT:
#endif
#ifdef SSL_ERROR_WANT_ACCEPT
case SSL_ERROR_WANT_ACCEPT:
#endif
error = 1;
break;
case SSL_ERROR_SSL:
/* Protocol error. */
#ifdef EPROTO
error = EPROTO;
#else
error = SOCKET_ECONNRESET;
#endif
break;
case SSL_ERROR_SYSCALL:
case SSL_ERROR_NONE:
default:
break;
};
}

int main()
{
/*
------------------ START Initialize Server ------------------
*/

int serverfd, clientfd;
struct sockaddr_in vir_serv_addr, cli_addr;

serverfd = socket(AF_INET, SOCK_STREAM, 0);
bzero((char *) &vir_serv_addr, sizeof (vir_serv_addr));

vir_serv_addr.sin_family = AF_INET;
vir_serv_addr.sin_addr.s_addr = INADDR_ANY;
vir_serv_addr.sin_port = htons(9999);

bind(serverfd, (struct sockaddr *) &vir_serv_addr, sizeof (vir_serv_addr));
listen(serverfd, 5);
socklen_t client = sizeof (cli_addr);
clientfd = accept(serverfd, (struct sockaddr*) &cli_addr, (socklen_t*) & client);

/*
------------------- END Initialize Server -------------------
*/

/*
------------------ START SSL ------------------
*/
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();

SSL_CTX* context = SSL_CTX_new(TLS_server_method());
SSL_CTX_set_ecdh_auto(context, 1);
SSL_CTX_use_certificate_file(context, "server-cert.pem", SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(context, "server-key.pem", SSL_FILETYPE_PEM);
SSL_CTX_load_verify_locations(context, "ca-cert.pem", NULL);
SSL_CTX_check_private_key(context);

SSL* ssl = SSL_new(context);
BIO *rbio = BIO_new(BIO_s_mem());
BIO *wbio = BIO_new(BIO_s_mem());
SSL_set_bio(ssl, rbio, wbio);

char* buffer[8192];
int n;

SSL_set_accept_state(ssl);

while (!SSL_is_init_finished(ssl)) {
n = recv(clientfd, buffer, 8192, 0);
n = BIO_write(rbio, buffer, n);
int r = SSL_do_handshake(ssl);
n = BIO_read(wbio, buffer, 8192);
n = send(clientfd, buffer, n, 0);

bzero(buffer, 8192);
BIO_flush(rbio);
BIO_flush(wbio);

if (r != 1) {
ERR_print_errors_fp(stderr);
int err_SSL_get_error = SSL_get_error(ssl, r);
switch (err_SSL_get_error) {
case SSL_ERROR_NONE:
case SSL_ERROR_SSL:
return 0;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
continue;
default:
return 0;
}
}
}

string message = "Hello world! \n Bye world!";
n = SSL_write(ssl, message.c_str(), message.size());
n = BIO_read(wbio, buffer, 8192);
n = send(clientfd, buffer, n, 0);

/*
------------------- END SSL -------------------
*/

}

最佳答案

确实是个很有趣的问题。这里发生的是单个 SSL_write 导致两个应用程序数据 SSL 帧(类型 0x17)。而且这仅发生在 TLS 1.0 中,即不会发生在 TLS 1.1 或 TLS 1.2 中。

虽然它可能看起来像一个错误,但实际上是为了对抗 BEAST 而设计的。以及使用 SSL 3.0 和 TLS 1.0 中与 CBC 密码相关的协议(protocol)漏洞的类似攻击。这种保护是通过插入空数据片段来实现的,这会导致第一个 SSL 帧实际上不包含实际数据。像这种 0/n 拆分这样的类似保护以 1/n-1 拆分的形式存在于其他 TLS 堆栈中。

由于此攻击不影响 TLS 1.1 和 TLS 1.2,因此未在此处启用保护。有关此保护如何工作的更多详细信息,请参阅 Why does Firefox split HTTPS request?Is BEAST really fixed in all modern browsers? .

但是由于您背负着一些无法处理这种行为的错误应用程序,您需要找到一种方法来禁用它。这可以通过选择一个不是 CBC 的密码(但 TLS 1.0 中没有好的密码)或简单地禁用保护来完成:

SSL_CTX_set_options(context, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);

除了 SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS,您还可以使用 SSL_OP_ALL,其中包括针对有问题的 TLS 实现的所有解决方法,包括这个。

关于c++ - 仅 OpenSSL BIO : single SSL_write broken in two SSL records with TLS 1. 0,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39328143/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com