OpenSSL RSA私钥解密触发vio_ssl_write断言失败崩溃问题
问题根因
该崩溃与解密返回值的判断分支无直接关系,核心触发原因是OpenSSL线程本地错误队列残留未清理的错误条目,触发了依赖组件的强制断言。
具体触发逻辑如下:
- OpenSSL所有接口执行失败时,都会将错误信息压入当前线程专属的错误队列,你现有代码中所有错误处理逻辑都没有主动清空该队列:
- 当
PEM_read_RSAPrivateKey读取私钥失败时,仅调用ERR_print_errors_fp向stderr打印错误,该函数只会输出错误文本,不会移除队列中的错误条目 - 当
RSA_private_decrypt解密失败返回-1时,对应的填充校验失败、密文非法、密钥不匹配等错误会直接残留在队列中,无任何清理操作
- 当
- 报错提到的
viossl.cc是MySQL网络SSL交互层的实现,该模块在执行vio_ssl_write发送数据前有强制校验逻辑:断言当前线程OpenSSL错误队列为空(即ERR_peek_error() == 0)。只要你前面的OpenSSL调用残留了错误,无论是否判断解密返回值,只要后续流程走到SSL写操作,就会直接触发断言崩溃。
现有代码的其他隐藏问题
这些问题会直接导致解密失败,持续往错误队列写入错误:
- 缺失十六进制转字节数组逻辑:代码仅为
encrypted_data_byte分配了内存,未将输入的十六进制字符串转换为对应字节值,传入解密函数的是未初始化的野内存,解密必然失败 - 私钥读取失败无兜底逻辑:如果
PEM_read_RSAPrivateKey返回NULL,打印错误后仍会继续执行后续解密逻辑,将空RSA指针传入解密接口,必然触发OpenSSL错误 - 无文件打开校验:如果
mykey.pem不存在、权限不足导致fopen返回NULL,直接传入私钥读取接口也会触发错误 - 输出缓冲区长度风险:使用
RSA_PKCS1_PADDING模式时,解密输出缓冲区长度至少要等于RSA密钥的字节长度,若预先分配的DATA_SIZE小于密钥长度,会出现内存溢出。
修复方法
- 所有OpenSSL接口的错误处理分支、解密函数返回前,主动清空当前线程的OpenSSL错误队列:
ERR_clear_error();注意:
ERR_print_errors_fp仅负责打印错误栈内容,不会消费或清除错误栈条目,这是OpenSSL开发的常见误区。 - 补全十六进制字符串转字节数组的逻辑,禁止传入未初始化的内存到解密接口
- 补全全链路返回值校验:文件打开失败直接返回错误、私钥读取失败直接终止流程返回错误码,不要执行后续无效逻辑
- 校验输出缓冲区长度,保证缓冲区大小不低于RSA密钥对应的字节长度,避免内存溢出。
内容的提问来源于stack exchange,提问作者sama
相关产品推荐
相关产品推荐

