【发布时间】:2015-06-13 17:14:13
【问题描述】:
我正在使用 boost::asio + openSSL 编写一个具有 HTTPS 能力的透明拦截代理。我有一个默认的服务器上下文,我指定服务器是 TLSv1.2 服务器,当客户端连接时,我从 hello 中提取主机并使用 SSL_set_SSL_CTX 设置上下文(它已经存在或者我刚刚在欺骗上游证书后创建它)并启动服务器(下游)读/写齐射以及上游。
这在我开始存储和共享上下文之前就已经奏效了。在每个新的传入连接上,我都创建了一个新的客户端套接字和上下文,加载 ca-bundle 作为验证文件,然后创建一个新的服务器上下文,获取欺骗证书。它正在运行,但我开始开发 EC_KEY 对象被双重释放等问题。 I learned from another question of mine 我的做法是错误的,并开始重构以回收和共享 CTX 对象。具体来说,我使用的是一个单一的客户端 CTX,它在程序启动时加载 CA-Bundle 以进行验证。
但是,自从这次重构以来,我在客户端和服务器上都得到了这个:
decryption failed or bad record mac
.. 混合了无数的“短读”。如果我尝试强制使用 TLSv1.2,我会得到
block cipher pad is wrong
在读/写失败后给我这些错误,我在上游或下游套接字上调用 async_shutdown,在回调中设置错误(因此关闭失败)。
我搜索了互联网,从 apache httpd 和 nginx 等地方找到了 jira 帖子,这些地方以不同的方式修复了此错误(将读取缓冲区的大小调整为更大、openSSL 补丁、强制 SSLv3 等等)。
我认为多线程可能存在问题(我的 io 服务使用线程池),但我可以在代码中看到 boost do_init 为 openSSL 设置了锁定机制,并且我的所有 IO 都被包装成一条链。
我完全不知所措,想知道是否有人可以阐明可能发生的事情。我意识到我没有发布任何代码,那是因为我有成百上千行代码,并且不想通过大量代码转储来关闭人们。但是我意识到这是一个相当复杂的程序,因此是一个复杂的问题,所以请询问,我会尽我所能提供。
编辑
为了完整起见,我想我应该提到我在 openssl 1.0.2 和 1.0.2a、Win 8.1 x64 上都遇到了这些错误,并且我正在使用 WinDivert 通过我的代理拦截和路由 http/https 流量。
编辑 2
将整个程序减少到 1 个线程,效果相同。为每个客户端连接创建了新的客户端 CTX,同样的问题。尝试禁用 AES-NI,问题仍然存在。试过不同的电脑,效果一样。从源代码重新编译 openssl(使用预编译的二进制文件),问题仍然存在。尝试设置当前文档中描述的与降级检测、填充错误等相关的其他 OP_ 解决方法标志,问题仍然存在。我想我很快就会开始随机捣碎键盘和编译按钮。
【问题讨论】:
-
单线程可能存在并发问题,尤其是在使用协同例程时。线程检查一些东西,做一些隐含或间接产生并允许另一个线程运行的东西,然后假设它之前检查的东西没有改变,然后做一些事情。每个 SSL 连接是否都有关联的链?是否所有可以触发组合操作的异步操作都在链上正确分派?
-
@DavidSchwartz yessir,他们确实有一个关联的链,并且所有访问连接的异步操作也都被包装了。
-
@DavidSchwartz 我修复了它,这是最荒谬的事情,来自 openSSL 的错误代码掩盖了真正的问题,当我忽略它们的控制流时,原来是解析初始请求失败,由于没有触发 async_io 操作来进行会话,导致会话过早关闭,从而导致 boost 错误代码聚合神秘但(几乎)完全不相关的“解密失败或。 ……”。谢谢你的帮助。不知道我是否应该回答这个问题。
-
我猜你可以自己回答。
标签: c++ ssl boost openssl boost-asio