OpenSSL 解密失败或记录错误 mac boost::asio
OpenSSL decryption failed or bad record mac boost::asio
我正在使用 boost::asio + openSSL 编写一个透明的拦截 HTTPS 代理。我有一个默认的服务器上下文,我在其中指定服务器是 TLSv1.2 服务器,当客户端连接时,我从 hello 中提取主机并使用 SSL_set_SSL_CTX
设置上下文(已经存在或者我'我们刚刚在欺骗上游证书后创建了它)并启动服务器(下游)read/write volley 以及上游。
在我开始存储和共享上下文之前,这是有效的。在每个新的传入连接上,我都在创建一个新的客户端套接字和上下文,加载 ca-bundle 作为验证文件,然后创建一个新的服务器上下文,获取欺骗证书。它正在运行,但我开始出现 EC_KEY 对象被双重释放等问题。 我以错误的方式解决这个问题并开始重构以回收和共享 CTX 对象。具体来说,我使用的是在整个板上共享的单个客户端 CTX,它在程序启动时加载 CA-Bundle 以进行验证。
但是,由于这次重构,我在客户端和服务器上都得到了这个:
decryption failed or bad record mac
..混合了无数的“短读”。如果我尝试强制执行所有 TLSv1.2,我会得到
block cipher pad is wrong
这些错误是在 read/write 失败后给我的,我在上游或下游套接字上调用 async_shutdown
,在回调中设置了错误(因此关闭失败)。
我搜索了 interwebs,从 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_ 解决方法标志,问题仍然存在。我想我很快就会开始随机混合键盘和编译按钮。
我本来打算删除这个问题,但我决定回答这个问题是因为网上(我能找到的)没有任何地方真正指出了这个问题的正确解决方案。我已经阅读了人们可以找到的关于此错误的每一份报告,以及这些报告中的每一份,人们 "solved" 或 "reduced" 以不同的方式处理此错误。每一个,一个不同的解决方案。这就是导致这个问题如此难以推理的原因,因为每个地方的每个人都有不同的潜在因果解释。
这很复杂,准备好了吗?如果您 cancel/abort 一个挂起的异步 SSL 操作,这个错误就会出现。心灵->繁荣()。如果你按照文档所说的去做并使用 async_shutdown 这样做会更加混乱,因为即使回调 async_shutdown 也会失败(错误代码已设置)并且你的错误消息会随机像 "decryption failed or bad record mac" 或 "block cipher pad is wrong" 或 "SSLv3 alert!" 等等愚蠢的东西。 当看到这样的错误时,请忽略这些错误并分析您的 IO 操作的控制流,在某个地方您要么过早地结束它们,要么让它们乱序。
在我的例子中,过早结束是(某种程度上)故意的,因为在这个愚蠢的重重构过程中,我决定改变问题范围之外的东西,比如我的 HTTPHeader 解析器,我发现它并最终导致它几乎 100% 失败并因此中止连接。 :) 错误字符串通过告诉我由于某种原因加密失败来掩盖真正的原因。我知道愚蠢的错误,但我很高兴成为第一个(显然)认识到它的人。 :)
打开一个 powershell 并输入这个
(Invoke-WebRequest -Uri status.dev.azure.com).StatusDescription
我正在使用 boost::asio + openSSL 编写一个透明的拦截 HTTPS 代理。我有一个默认的服务器上下文,我在其中指定服务器是 TLSv1.2 服务器,当客户端连接时,我从 hello 中提取主机并使用 SSL_set_SSL_CTX
设置上下文(已经存在或者我'我们刚刚在欺骗上游证书后创建了它)并启动服务器(下游)read/write volley 以及上游。
在我开始存储和共享上下文之前,这是有效的。在每个新的传入连接上,我都在创建一个新的客户端套接字和上下文,加载 ca-bundle 作为验证文件,然后创建一个新的服务器上下文,获取欺骗证书。它正在运行,但我开始出现 EC_KEY 对象被双重释放等问题。
但是,由于这次重构,我在客户端和服务器上都得到了这个:
decryption failed or bad record mac
..混合了无数的“短读”。如果我尝试强制执行所有 TLSv1.2,我会得到
block cipher pad is wrong
这些错误是在 read/write 失败后给我的,我在上游或下游套接字上调用 async_shutdown
,在回调中设置了错误(因此关闭失败)。
我搜索了 interwebs,从 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_ 解决方法标志,问题仍然存在。我想我很快就会开始随机混合键盘和编译按钮。
我本来打算删除这个问题,但我决定回答这个问题是因为网上(我能找到的)没有任何地方真正指出了这个问题的正确解决方案。我已经阅读了人们可以找到的关于此错误的每一份报告,以及这些报告中的每一份,人们 "solved" 或 "reduced" 以不同的方式处理此错误。每一个,一个不同的解决方案。这就是导致这个问题如此难以推理的原因,因为每个地方的每个人都有不同的潜在因果解释。
这很复杂,准备好了吗?如果您 cancel/abort 一个挂起的异步 SSL 操作,这个错误就会出现。心灵->繁荣()。如果你按照文档所说的去做并使用 async_shutdown 这样做会更加混乱,因为即使回调 async_shutdown 也会失败(错误代码已设置)并且你的错误消息会随机像 "decryption failed or bad record mac" 或 "block cipher pad is wrong" 或 "SSLv3 alert!" 等等愚蠢的东西。 当看到这样的错误时,请忽略这些错误并分析您的 IO 操作的控制流,在某个地方您要么过早地结束它们,要么让它们乱序。
在我的例子中,过早结束是(某种程度上)故意的,因为在这个愚蠢的重重构过程中,我决定改变问题范围之外的东西,比如我的 HTTPHeader 解析器,我发现它并最终导致它几乎 100% 失败并因此中止连接。 :) 错误字符串通过告诉我由于某种原因加密失败来掩盖真正的原因。我知道愚蠢的错误,但我很高兴成为第一个(显然)认识到它的人。 :)
打开一个 powershell 并输入这个
(Invoke-WebRequest -Uri status.dev.azure.com).StatusDescription