如何使用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未初始化:
- BIO链方向完全搞反:
BIO_push的逻辑是将底层BIO压入顶层BIO的链中,数据流向应为SSL过滤BIO → 套接字BIO(加密层在上,传输层在下),你当前把套接字BIO作为顶层,完全颠倒了数据处理顺序。 - SSL过滤BIO未绑定SSL对象:
BIO_f_ssl()创建的是SSL过滤BIO,必须通过BIO_set_ssl()将其与你的ssl对象绑定,否则该BIO处于未初始化状态,这正是报错的直接原因。 - 存在冗余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链的分层设计,不推荐这么做。
正确的实现思路是:
- 自定义BIO仅替代默认的套接字BIO,专注于带
SO_TIMESTAMPING时间戳的套接字读写操作 - 将自定义BIO作为底层,上层使用
BIO_f_ssl()创建的SSL过滤BIO,构建SSL过滤BIO → 自定义套接字BIO的链 - 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
相关产品推荐
相关产品推荐

