OpenSSL解密失败或记录MAC失败 boost::asio

4
我正在使用boost::asio + openSSL编写一个透明的拦截HTTPS代理。我有一个默认的服务器上下文,指定服务器是TLSv1.2服务器。当客户端连接时,我从hello中提取主机并使用SSL_set_SSL_CTX设置上下文(它可能已经存在,或者我刚刚在欺骗上游证书后创建了它),然后启动服务器(下行)读/写往返以及上游。
在存储和共享上下文之前,这是有效的。对于每个新的传入连接,我都会创建一个新的客户端套接字和上下文,加载ca-bundle作为验证文件,然后创建一个新的服务器上下文,并获取伪造的证书。虽然它可以正常运行,但我开始遇到EC_KEY对象被双重释放等问题。我从我的另一个问题中了解到,我走错了路,并开始重构以重复使用和共享CTX对象。具体来说,我正在全面使用一个单一的客户端CTX,该CTX在程序启动时加载用于验证的CA-Bundle。
然而,自从进行了这次重构后,无论是客户端还是服务器,我都得到了以下内容:
 decryption failed or bad record mac

与无数“短读”混杂的内容。如果我尝试强制使用TLSv1.2,就会出现...

block cipher pad is wrong

在读写失败后,当我调用上游或下游套接字的async_shutdown时,会出现这些错误,在回调中,设置了错误(因此关闭失败)。

我仔细查找了互联网上的Jira帖子,例如来自Apache httpd和Nginx等地方,在这些地方,通过不同的方式修复了这个错误(将读缓冲区大小调整更大,进行openSSL补丁,强制使用SSLv3等等)。

我认为可能存在多线程问题(我的io-service使用线程池),但我可以在代码中看到,boost do_init为openSSL设置了锁定机制,并且所有的IO都包装在一个单一的strand中。

我完全不知所措,想知道可能发生了什么。我意识到我没有发布任何代码,这是因为我有成百上千行的代码,不想以巨大的代码转储来打击人们的热情。不过,我也意识到这是一个相当复杂的程序,因此也是一个复杂的问题,所以请随便问,我会提供我所能提供的一切。

编辑
我想我应该提到,我在openssl 1.0.2和1.0.2a、Win 8.1 x64上都遇到了这些错误,我使用WinDivert拦截和路由http/https流量通过我的代理。

编辑2
将整个程序减少到1个线程,效果相同。为每个客户端连接创建新的客户端CTX,问题仍然存在。尝试禁用AES-NI,问题仍然存在。尝试不同的计算机,效果相同。重新编译openssl源代码(之前使用的是预编译二进制文件),问题仍然存在。尝试设置相关的OP_ workaround标志,以便与降级检测、填充漏洞等有关的当前文档描述相匹配,问题仍然存在。我想我很快就会开始随机地敲键盘和编译按钮了。


单线程可能存在并发问题,特别是在使用协程时。线程检查某些内容,执行隐式或间接的yield操作,允许另一个线程运行,然后执行假设之前检查过的内容没有改变的操作。每个SSL连接是否都有关联的strand?所有可以触发组合操作的异步操作是否都正确地分派到strand上? - David Schwartz
@DavidSchwartz 是的先生,它们确实有关联的链,并且所有访问连接的异步操作也被包装了。 - user562566
@DavidSchwartz 我解决了,问题非常荒谬,openSSL的错误代码掩盖了真正的问题。当我忽略它们并检查控制流时,发现是解析初始请求失败,由于没有异步IO操作来继续会话,导致会话过早关闭,从而导致boost错误代码聚合了神秘而又(几乎)完全不相关的“解密失败或...”。感谢您的帮助。不确定是否应该取消这个问题。 - user562566
你可以自己回答这个问题,我猜。 - David Schwartz
2个回答

18

我本来想删除这个问题,但考虑到网络上没有一个地方(至少我找不到)指向正确的解决方案,所以我决定回答它。我阅读了每一篇关于这个错误的报告,每一个人都用不同的方法“解决”或“减少”了这个错误。每个人都有不同的解决方案。这就是为什么这个问题如此难以理解的原因,因为每个人都有不同的根本原因解释。

很复杂,准备好了吗?如果您取消/中止挂起的异步SSL操作,将出现此错误。Mind->boom()。如果按照文档所说使用async_shutdown来执行此操作,那么即使回调到async_shutdown也会失败(错误代码已设置),您的错误消息也会随机变成一些愚蠢的东西,例如“解密失败或坏记录mac”、“块密码填充错误”或“SSLv3警报!”等等。当看到这样的错误时,请忽略错误并分析您的IO操作的控制流程,您可能要么过早地结束它们,要么按顺序获取它们。

在我的情况下,过早的结束有点故意,因为在这个愚蠢的大规模重构期间,我决定改变问题范围之外的事情,比如我的HTTPHeader解析器,我把它搞砸了,导致连接几乎100%失败并中止。:)错误字符串掩盖了真正的原因,告诉我加密失败了,或者由于某种原因而失败了。我知道这是一个愚蠢的错误,但我很欣慰自己是第一个(显然)认识到它的人。 :)

我知道这已经很老了,但是当我执行ssl_do_handshake时,它会出现SSL_ERROR(1)的问题,和这个确切的问题一样。使用的版本是1.0.2l。 - Mike5050

-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接