为了使用 OpenSSL 进行加密,但做你自己的套接字 IO,你基本上要做的是创建一个内存 BIO,你可以读取和写入套接字数据,然后将其附加到 SSL 上下文。
每次执行 SSL_write 调用时,都会调用内存 BIO 以查看其读取缓冲区中是否有数据,将其读出并发送。
相反,当数据通过您的 io 完成端口机制到达套接字时,您将其写入 BIO 并调用 SSL_read 以读取数据。 SSL_read 可能会返回一个错误代码,表明它处于握手状态,这通常意味着它生成了更多要写入的数据 - 您可以通过再次读取内存 BIO 来处理这些数据。
为了创建我的 SSL 会话,我这样做:
// This creates a SSL session, and an in, and an out, memory bio and
// attaches them to the ssl session.
SSL* conn = SSL_new(ctx);
BIO* bioIn = BIO_new(BIO_s_mem());
BIO* bioOut = BIO_new(BIO_s_mem());
SSL_set_bio(conn,bioIn,bioOut);
// This tells the ssl session to start the negotiation.
SSL_set_connect_state(conn);
当我从网络层接收数据时:
// buf contains len bytes read from the socket.
BIO_write(bioIn,buf,len);
SendPendingHandshakeData();
TryResendBufferedData(); // see below
int cbPlainText;
while( cbPlainText = SSL_read(ssl,&plaintext,sizeof(plaintext)) >0)
{
// Send the decoded data to the application
ProcessPlaintext(plaintext,cbPlaintext);
}
当我从应用程序接收到要发送的数据时,您需要为 SSL_write 失败做好准备,因为握手正在进行中,在这种情况下,您可以缓冲数据,并在未来收到一些数据后尝试再次发送.
if( SSL_write(conn,buf,len) < 0)
{
StoreDataForSendingLater(buf,len);
}
SendPendingHandshakeData();
SendPendingHandshakeData 发送 SSL 需要发送的任何数据(握手或密文)。
while(cbPending = BIO_ctrl_pending(bioOut))
{
int len = BIO_read(bioOut,buf,sizeof(buf));
SendDataViaSocket(buf,len); // you fill this in here.
}
简而言之就是这个过程。代码示例并不完整,因为我必须从一个更大的库中提取它们,但我相信它们足以开始使用 SSL。在实际代码中,当 SSL_read/write / BIO_read/write 失败时,最好调用 SSL_get_error 并根据结果决定要做什么: SSL_ERROR_WANT_READ 是重要的,意味着你不能再 SSL_write 任何数据,因为它需要你首先读取并发送 bioOut BIO 中的待处理数据。