将部分数据包写入SSL BIO

时间:2017-11-07 14:40:46

标签: sockets ssl encryption openssl

我有一个读写数据的套接字应用程序。我使用OpenSSL进行加密/解密。我的问题是" BIO_write"方法可以在内部缓冲数据,或者当我从套接字中读取更多内容时,我必须附加到不断增长的缓冲区。这就是我正在做的事情。

我从套接字读取并使用下面的类方法写入读取到BIO中的所有字节:

int CSslConnectionContext::Store(BYTE* pbData, DWORD dwDataLength)
{
    int bytes = 0;
    if (dwDataLength > 0)
    {
        bytes = BIO_write(bio[BIO_RECV], pbData, dwDataLength);
    }

    return bytes;
}

然后我立即调用SSL_read方法来获取解密数据:

int CSslConnectionContext::Read(BYTE* pbBuffer, DWORD dwBufferSize)
{
    int bytes = SSL_read(ssl, pbBuffer, dwBufferSize);
    return bytes;
}

如果SSL_read返回正数,那么我已经为我的应用程序提供了解密数据。

我不确定当我的套接字读取在单次读取中没有捕获解密所需的所有数据时会发生什么。

因此,如果我需要100个字节才能解密数据并且第一个只读取80,我可以用那些80调用BIO_write(),再读取另一个套接字以获得接下来的20个,然后调用BIO_write()只有那20个字节?

或者我是否需要编写代码,所以当我阅读80时,我会做这样的事情:

  1. 用80个字节调用BIO_write()。
  2. 如果返回失败指示符 - 保持该80字节。
  3. 从套接字读取接下来的20个字节,并将其附加到缓冲的80字节。
  4. 用100字节
  5. 调用BIO_write()

2 个答案:

答案 0 :(得分:1)

OpenSSL保存内部缓冲区 - 让我们称之为SSL堆栈 - 在TCP堆栈之上。 OpenSSL库处理SSL堆栈。 BIO_xxx()函数可以在不同的端点上运行:即内存,套接字。 它的行为会有所不同,具体取决于它所操作的实际项目。例如,如果BIO_write()使用内存(BIO_s_mem),除了内存不足外,BIO_write永远不会失败。但是如果它使用套接字,并且套接字是非阻塞的,它可以在失败时返回错误,或者它可以写入一些字节而不是所有请求的字节,其中套接字缓冲区已满。

因此,如何使用/处理缓冲区取决于许多因素,但最值得注意的是:

  • 阻止或阻止IO
  • 对(内存,套接字等)进行操作的BIO对象

例如,如果您正在使用BIO_s_mem和非阻塞套接字操作,则可以应用以下技术:

  1. 使用BIO_write写缓冲区,并检查它是否失败。如果它没有失败,您可以确定已将所有缓冲区写入SSL堆栈。
  2. 调用Read_SSL并检查错误,如果错误是WANT_READ,或者WANT_WRITE,则需要将更多数据写入SSL堆栈以便能够读取有效记录。
  3. 对于问题和示例:

    您可以部分写入(尽可能多地写入,甚至1个字节)。例如,如果从套接字读取80个字节,则使用BIO_write写入。然后调用SSL_read可能会失败(WANT_READ,WANT_WRITE或其他)。然后从套接字接收20个字节,然后使用BIO_write写入这些字节。然后再次调用SSL_read。每当SSL_read返回时没有错误,这意味着SSL堆栈解码了有效记录。

    但是理解使用select()等待非阻塞套接字处理SSL读/写非常麻烦非常重要。当您已经等待套接字的READ事件时,一个SSL_write可能导致多次写入套接字。

答案 1 :(得分:0)

请使用bio_pending ..来了解openssl ..可用的所有字节。使用bio_pending的返回值循环。应该在bio_read之前调用它。