WolfSSL 也很糟糕,现在怎么办?
WolfSSL Sucks Too, So Now What?

原始链接: https://blog.feld.me/posts/2026/02/wolfssl-sucks-too/

## WolfSSL 与 TLS 1.3:兼容性问题 最近的测试发现 WolfSSL 对 TLS 1.3 的实现存在一个显著缺陷,导致与 Erlang/OTP(以及 Elixir)等客户端的连接失败。TLS 1.3 旨在提高安全性,包含“中间盒兼容模式”,以便与不支持新标准的旧网络基础设施协同工作。该模式需要特定的行为——交换虚拟消息——以避免这些“中间盒”的干扰。 然而,WolfSSL *并未*完全按照 RFC 8446 标准实现此兼容模式。它采用一刀切的方式,要么始终启用该模式,要么完全禁用。这意味着期望符合 RFC 标准行为的客户端,例如默认启用该模式的 Erlang/OTP,将无法连接到使用 TLS 1.3 的 WolfSSL 服务器。 作者的经验强调了这个问题,源于希望利用 WolfSSL 的速度与 FreeBSD 上的 Haproxy 结合。解决方法涉及在客户端禁用中间盒兼容性,但这并非理想方案。作者建议关注 LibreSSL 作为更可靠的替代方案,呼应了 OpenBSD 一贯的立场,并警告不要以牺牲标准合规性为代价追求性能提升。

Hacker News 新闻 | 过去 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 WolfSSL 也很糟糕,那该怎么办? (feld.me) 24 分,thomasjb 发表于 40 分钟前 | 隐藏 | 过去 | 收藏 | 5 条评论 mythz 发表于 2 分钟前 | 下一个 [–] BearSSL 由 Thomas Pornin 开发,值得关注,不确定当前状态如何,但看起来去年收到过一次提交。[1] https://bearssl.org 回复 eptcyka 发表于 1 分钟前 | 上一个 | 下一个 [–] 还有 rustls。 ospray 发表于 17 分钟前 | 上一个 | 下一个 [–] 我们需要下一个名字中包含 TLS,这样人们就不会再感到困惑了。 magicalhippo 发表于 3 分钟前 | 父评论 | 下一个 [–] MbedTLS[1] 帮你搞定![1]: https://www.trustedfirmware.org/projects/mbed-tls/ 回复 MrBuddyCasino 发表于 4 分钟前 | 上一个 [–] 那该怎么办?BearSSL。 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
相关文章

原文

OpenSSL sucks. The BoringSSL and AWS-LC forks are Googled and Amazoned to death; they don't care about anyone but their own use cases. I can't remember ever having a good experience with software using GnuTLS. LibreSSL is incomplete...

What happened now?

Last year an article from Haproxy about how terribly slow OpenSSL has become was published. This made the rounds a few times, and I had an itch to scratch so I helped enable FreeBSD to package a variant of Haproxy built against WolfSSL. This seemed like an easy way to get people wider exposure to WolfSSL as it's unlikely we'll see this happen on most Linux distros, so in reality the only people who are experiencing a WolfSSL-backed Haproxy are people who know what they're getting into and custom built it themselves. I haven't actually checked if Arch, Gentoo, Nix, etc have done similar, but they'd be the easiest to produce a similar haproxy-wolfssl package.

So I did it, and I ran WolfSSL in a few places, and then I hit a bug. I reported the bug, forgot about it, and moved on. And then I hit it again and was motivated to actually figure it out. So I reopened the bug and fumbled my way through debugging the issue until the root cause was identified.

TLS 1.3 is defined in RFC 8446. It works quite a bit different from TLS 1.2 which caused them no end of issues, such that they documented "The design of TLS 1.3 was constrained by widely deployed non-compliant TLS middleboxes".

Ahh yes, the infamous middleboxes. Great. Those invisible pieces of garbage that can tamper with your traffic and you'll generally never know they exist until they cause you grief. And they will.

Middlebox Hell

Hell is definitely a place where middleboxes were invented and no amount of wishcasting will remove them from existence. Although maybe some Etsy witches could provide some guidance as they have incredible luck solving problems...

Anyway, so we have all these middleboxes and they suck and we want the network to have better security guarantees than TLS 1.2 but the boxes only understand TLS 1.2 and TLS 1.3 can't exist if the boxes break them so TLS 1.3 has to be able to pretend to be TLS 1.2. That's where we're at with this.

So the authors hemmed and hawwed about this and came up with a solution: Middlebox Compatibility Mode.

Essentially, clients can optionally set a non-empty session ID in the ClientHello to fool the middleboxes, and the client and server exchange dummy change_cipher_spec records. This is useless and just adds latency to establishing the TLS session, but it will work. Fair.

The Upside Down

The RFC is pretty clear about how this is all meant to play out.

This "compatibility mode" is partially negotiated: the client can opt to provide a session ID or not, and the server has to echo it.

and

if the client sends a non-empty session ID, the server MUST send the change_cipher_spec as described in this appendix.

But WolfSSL says "thanks but no thanks". The entire middlebox compatibility functionality is gated behind compiling the library with -DWOLFSSL_TLS13_MIDDLEBOX_COMPAT, which forces it to always be in this mode or not.

So the current state is that WolfSSL cannot be trusted to work correctly with TLS 1.3 clients. It all depends on how forgiving they are, and that's not exactly a driver of confidence. The GitHub issue comment left at the end leads me to believe that they aren't really interested in RFC compliance. There isn't a middleground here or a "different way" of implementing middlebox compatibility. It's either RFC compliant or not. And they're not.

The Plaintiff

Currently I've only identified one victim of this decision, but there's bound to be more out there. Erlang/OTP has its own ssl library implementation and you can rightfully assume that they've taken Joe's advice to heart when adding TLS 1.3 support:

Make it work, then make it beautiful, then if you really, really have to, make it fast. - Joe Armstrong

So to cover their butts, they opted to enable middlebox_comp_mode by default. (If you want it fast and you know it's safe to do so -- turn it off)

And now every Elixir/Erlang/etc HTTP client fails to be able to connect to a WolfSSL HTTPS server if TLS 1.3 is available.

Where Do We Go From Here?

OpenBSD was probably right. We just need to get people to focus on LibreSSL and forget about these other libraries. As Haproxy noted, it's not a victim of the OpenSSL 3.0 screwups because they forked earlier, but it's missing some optimizations. I think that's probably a fair trade-off and the gaps will be filled in due time.

So don't be like me. This was hubris I guess. Sure, I thought I could be clever and have faster TLS termination for my websites, but all it did was lead me to wasting a lot of time learning about something I really didn't care to know, and then writing this stupid blog post. You've been warned.

Elixir PoC

A PoC for Elixir 1.17.3 (compiled with Erlang/OTP 26) is as simple as below:

#!/usr/bin/env elixir

url = "https://some-wolfssl-endpoint"

url = String.to_charlist(url)

{:ok, _} = Application.ensure_all_started(:inets)
{:ok, _} = Application.ensure_all_started(:ssl)

:logger.set_application_level(:ssl, :debug)

http_options =
  [
    ssl: [
      verify: :verify_peer,
      cacerts: :public_key.cacerts_get(),
      depth: 2,
      customize_hostname_check: [
        match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
      ],
      versions: [:"tlsv1.2", :"tlsv1.3"],
      middlebox_comp_mode: true
    ]
  ]

options = [body_format: :binary]

:httpc.request(:get, {url, []}, http_options, options)

The error is going to look like this:

11:00:44.996 [warning] Description: ~c"Failed to assert middlebox server message"
     Reason: [missing: {:change_cipher_spec, 1}]

11:00:45.014 [notice] TLS :client: In state :hello_middlebox_assert at ssl_gen_statem.erl:821 generated CLIENT ALERT: Fatal - Unexpected Message
 - {:unexpected_msg,
 {:internal,
  {:encrypted_extensions,
   %{
     elliptic_curves: {:supported_groups,
      [:secp521r1, :secp384r1, :secp256r1, :x25519, :ffdhe2048]}
   }}}}

That's when you'll know you've been thrown to the wolves. 🤬 If you change those http_options to set middlebox_comp_mode to false it will work as expected.

联系我们 contact @ memedata.com