带有 TCP 流的 TLS/SSL 中的 ssl_read() 不返回 BIO_write() 写入的整个缓冲区

Ami*_*yaG 4 c sockets openssl tcp polling

以下代码部分的目的是轮询套接字 fd-set,如果数据(ssl 加密)可用,则读取它并通过 openssl 库解密。底层传输层是 TCP Stream,因此数据以流的形式出现(而不是数据包)。

现在,如果从对等方快速连续发送了多个数据包(假设有 2 个长度为 85 字节的数据包),那么 TCP 接收将返回同一缓冲区中的两个数据包,接收的字节数为 170。因此,我们有一个携带 2 个 ssl 加密数据包(或 n 个数据包)的缓冲区。对于 ssl 解密,我们需要调用 BIO_write() 将缓冲区写入 ssl_bio,然后调用 ssl_read() 来检索解密的缓冲区。但是,尽管 BIO_write() 正在向 bio 中写入 170 个字节,但 ssl_read() 似乎只返回一个解密的数据包(43 个字节)。没有返回错误。如何知道 bio 中是否还有未处理的字节。有什么出路吗或者代码中有什么错误?

当在 tcp recv() 中接收到单个数据包时,代码工作正常。

int iReadyFds = poll( PollFdSet, iFdCount, iTimeout);

for(iFdIndx = 0; iFdIndx < (iFdCount) && (iReadyFds>0); ++iFdIndx)
{
    if((PollFdSet[iFdIndx].events == 0) ||
       (PollFdSet[iFdIndx].fd == 0) ||
       (PollFdSet[iFdIndx].revents != POLLIN)
       )
    {
        continue;
    }

    /* we have data to read */
    int iMsgLen = 0;
    int iFd = PollFdSet[iFdIndx].fd;


    /*This is TCP Receive. Returns 170 bytes*/
    iRcvdBytes = recv( iSocketId, ( void* )pcInBuffer, PN_TCP_STREAM_MAX_RX_BUFF_SIZE, 0 );
    
    /*Writing into SSL BIO, this will be retrieved by ssl_read*/
    /*iNoOFBytes  = 170*/
    iNoOFBytes = BIO_write(m_pRead_bio, pcInBuffer, iRcvdBytes);

    if(iNoOFBytes <= 0)
    {
        printf("Error");
        return -1;
    }
    
    char* pcDecodedBuff = (char*)malloc(1024);
    
    /*here it returns 43 bytes of decrypted buffer(1 packet). the other packet vanishes*/
    iReadData = SSL_read(m_psSSL, pcDecodedBuff, 1024);

    if ((iReadData == -1) || (iReadData == 0))
    {
        error = SSL_get_error(psPskTls->m_psSSL, iReadData);

        if(error == SSL_ERROR_ZERO_RETURN
        || error == SSL_ERROR_NONE
        || error == SSL_ERROR_WANT_READ)
        {
            printf("Error");
        }
    }

    iReadyFds--;
}
Run Code Online (Sandbox Code Playgroud)

Mat*_*ell 5

OpenSSL 通常一次只读取和解密一条记录。再次调用 SSL_read 将为您提供下一条记录。如果您不知道是否有另一条记录要读取,您可以询问底层传输它当前是否“可读”——或者只是调用 SSL_read() 并处理错误(如果使用非阻塞 IO)。

在某些情况下(例如,如果您使用“read_ahead”功能),OpenSSL 可能会在内部缓冲一些数据。您可以使用 SSL_has_pending()(对于 OpenSSL 1.1.0)或 SSL_pending()(对于 OpenSSL 1.0.2+)来查明是否有缓冲的内部数据。请参阅https://www.openssl.org/docs/man1.1.0/ssl/SSL_has_pending.html