You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用OpenSSL BIOs?BIO_s_socket与BIO_f_ssl结合问题及进阶需求

基于OpenSSL的客户端BIO构建问题及自定义BIO开发疑问

问题描述

我正在开发一个基于OpenSSL的简单客户端,原本计划通过自定义BIO结合Linux的SO_TIMESTAMPING获取硬件套接字时间戳,但对BIO的正确构建逻辑存在认知缺失,先从基础问题排查。

我的核心思路是用两个BIO分别处理套接字连接和加密操作,以此复现SSL_write和SSL_read的基础行为,编写的BIO实例化及与SSL绑定的代码如下:

BIO *default_sck_bio = BIO_new(BIO_s_socket());
BIO *default_ssl_bio = BIO_new(BIO_f_ssl());
BIO *sock_bio = BIO_new(BIO_s_socket());
BIO *ssl_bio = BIO_new(BIO_f_ssl());
BIO_push(default_sck_bio, default_ssl_bio);
SSL_set_bio(ssl, default_sck_bio, default_sck_bio);

我预期SSL_read底层会先执行基于BIO的recv()再进行SSL解密,SSL_write则先执行SSL加密再进行基于BIO的send(),但SSL_connect一直返回SSL_ERROR_SSL错误,错误信息:

error:10000078:BIO routines::uninitialized

请问我遗漏了什么步骤?

解决上述问题后,回到自定义BIO开发需求,又产生新疑问:如何在通过BIO_meth_set_read设置的读写BIO回调中调用SSL加密函数?


问题解答

一、SSL_connect报错的解决

你的代码存在三个关键错误,直接导致BIO未初始化:

  1. BIO链方向完全搞反:BIO_push的逻辑是将底层BIO压入顶层BIO的链中,数据流向应为SSL过滤BIO → 套接字BIO(加密层在上,传输层在下),你当前把套接字BIO作为顶层,完全颠倒了数据处理顺序。
  2. SSL过滤BIO未绑定SSL对象:BIO_f_ssl()创建的是SSL过滤BIO,必须通过BIO_set_ssl()将其与你的ssl对象绑定,否则该BIO处于未初始化状态,这正是报错的直接原因。
  3. 存在冗余BIO实例:你创建了sock_bio和ssl_bio但未使用,属于无效代码。

修正后的代码示例:

// 先创建并连接套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
// 此处省略sockaddr配置及connect()调用代码

// 创建套接字BIO并关联已连接的套接字
BIO *sock_bio = BIO_new_socket(sockfd, BIO_NOCLOSE);

// 创建SSL过滤BIO并绑定SSL对象
BIO *ssl_bio = BIO_new(BIO_f_ssl());
BIO_set_ssl(ssl_bio, ssl, BIO_CLOSE);

// 构建正确的BIO链:SSL过滤BIO在上,套接字BIO在下
BIO_push(ssl_bio, sock_bio);

// 将BIO链绑定到SSL对象
SSL_set_bio(ssl, ssl_bio, ssl_bio);

额外注意:

  • 套接字BIO必须关联已完成连接的套接字,也可以用BIO_do_connect让BIO自行处理连接(需先配置主机端口信息)
  • BIO_CLOSE参数表示释放BIO时自动关闭关联的SSL对象和套接字,可根据需求调整为BIO_NOCLOSE

二、自定义BIO回调中调用SSL加密函数的正确方式

自定义BIO的读写回调负责底层数据传输逻辑,SSL加密解密属于上层处理逻辑,直接在回调中调用SSL加密函数会打破BIO链的分层设计,不推荐这么做。

正确的实现思路是:

  1. 自定义BIO仅替代默认的套接字BIO,专注于带SO_TIMESTAMPING时间戳的套接字读写操作
  2. 将自定义BIO作为底层,上层使用BIO_f_ssl()创建的SSL过滤BIO,构建SSL过滤BIO → 自定义套接字BIO的链
  3. SSL的加密解密会由上层的SSL过滤BIO自动处理,自定义BIO无需关心SSL加密细节,只负责传输层的读写和时间戳采集

如果非要在自定义BIO中介入SSL操作(不推荐,易破坏SSL状态机),可以:

  • 通过BIO_set_data在自定义BIO结构体中保存关联的SSL对象指针
  • 在读写回调中手动调用SSL底层函数(如SSL_do_write/SSL_do_read)处理加密解密,再执行传输操作,但这种方式需要手动维护SSL状态,出错概率极高。

内容的提问来源于stack exchange,提问作者Mattia Terenzi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 07:15:09