gpt4 book ai didi

c++ - 握手成功后 SSL_read() 不返回

转载 作者:行者123 更新时间:2023-11-28 04:08:59 24 4
gpt4 key购买 nike

我制作了一个服务器和一个客户端,它们在安全的 TLSv1.3、OpenSSL 3.0.0 channel 中进行通信。他们必须能够发送和接收,但在这个测试中,服务器只接收,客户端只定期发送应用程序数据。

握手成功后,客户端 select() 发出有数据可供读取的信号。当我尝试时,SSL_read() 没有返回。我检查了 wireshark 中的网络流量,并调试了 OpenSSL 库,发现服务器在握手后向客户端发送了 2 个 SESSION_TICKET,这就是消息 SSL_read() 处理失败。出于好奇,我在握手后立即向服务器发送了一条消息,以查看客户端对此有何 react 。令人惊讶的是,客户端离开了它的阻塞状态,之后通信工作正常。

由于观察到的行为,我唯一的猜测是我尝试读取用于 OpenSSL 的数据,当我调用 SSL_read() 时,它可能由其状态机处理。当库调用 read() 时,实际上没有可用的应用程序数据,因此它会阻塞线程。

下面是我用来读取“count”字节的成员函数。

int EventHandler::readByte(CommBuffer &buffer, ssize_t count, struct timeval &tmout){
fd_set rfds;
int retSelect, retRead;
int readByte=0;
int endRead=0;
int readSize=count;

buffer.setBufferSize(count+1);
do{
FD_ZERO(&rfds);
FD_SET(fd,&rfds);
retSelect=select(fd+1,&rfds,NULL,NULL,&tmout);
if(retSelect>0){
if (encryptionOn) {
retRead = SSL_read(ssl, (const_cast<char*>(&buffer.get()[readByte])), readSize); // Thread blocks here.
} else {
retRead = read(fd, (const_cast<char*>(&buffer.get()[readByte])), readSize);
}
if( retRead > 0 ){
readByte+=retRead;
allReadBytes+=retRead;
buffer.setDataSize(readByte);
if(readByte>=count) endRead=1;
readSize=count-readByte;
}
else{
if( retRead == -1 && errno == EINTR ){
continue;
}
if(fd>=0){
close(fd);
}
fd=CLOSED_FD;
return (CLOSED_FD);
}
}
else if(retSelect==0){
// handle timeout error
return(TIMEOUT_FD);
}
else{
return(retSelect);
}
}while(endRead!=1);
return(readByte);
}

请注意,此功能在没有加密的情况下也能正常工作。 (read() 而不是 SSL_read())

  • 我做错了什么?
  • 我应该如何读取数据?
  • 你会如何修改这个函数?

最佳答案

select 在 TCP 级别工作,而 SSL_read 在 TLS 级别工作。阻塞套接字上的 SSL_read 将(通常)仅在应用程序数据可用时返回,而 select 将在套接字上有任何类型的数据可用时发出信号,即也适用于非应用程序记录或不完整的 SSL 帧。

在您的特定情况下,这些数据是使用 TLS 1.3 的 session 票证,不再作为 TLS 握手的一部分发送,而是在握手之后发送。但是,对于较低的 TLS 版本,即使 select 返回数据可用,也可能发生 SSL_read 被阻止的情况:TLS 中的应用程序数据在 SSL 帧内发送,并且可能发生select 表示可用数据,即使只有部分 SSL 帧可用。在这种情况下,SSL_read 将阻塞,直到可以读取完整的 SSL 帧。此外,即使 select 发出可用数据信号,SSL_read 也会阻止 SSL 重新协商。

此外,select 可能不会发出可用数据的信号,但 SSL_read 会返回一些数据。当先前的 SSL_read 没有消耗已从 TCP 套接字读取的最后一个 SSL 帧中包含的所有数据时,就是这种情况。

换句话说:select 不应与 SSL 中的阻塞套接字一起使用。相反,套接字应该是非阻塞的,这样 SSL_read(和其他函数)可能会因 SSL_ERROR_WANT_READSSL_ERROR_WANT_WRITE 而失败,其中一个应该按照记录进行处理.此外,应调用 SSL_pending 来检查已从 TCP 套接字读取但尚未被 SSL_read 使用的数据。

关于c++ - 握手成功后 SSL_read() 不返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58218797/

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