fix(http): make Hackney trust the CAStore bundle

Hackney trusts its own certifi bundle, which still has the roots of the
compromised eMudhra intermediate CAs. Pass explicit ssl_options with the
CAStore bundle. Hackney drops all its TLS defaults when ssl_options are
given, so keep peer and hostname checks in the options.
This commit is contained in:
Lain Soykaf 2026-10-21 08:21:43 +04:00
commit d8c880e494
No known key found for this signature in database
6 changed files with 102 additions and 3 deletions

View file

@ -28,6 +28,7 @@ defmodule Pleroma.HTTP.AdapterHelper.Hackney do
|> add_scheme_opts(uri)
|> maybe_add_with_body()
|> Pleroma.HTTP.AdapterHelper.maybe_add_proxy(proxy)
|> Pleroma.HTTP.TLS.put_hackney_ssl_options()
end
defp add_scheme_opts(opts, _), do: opts

35
lib/pleroma/http/tls.ex Normal file
View file

@ -0,0 +1,35 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.HTTP.TLS do
@moduledoc """
TLS client options that trust the CAStore bundle.
Hackney otherwise trusts its own certifi bundle, and it drops all of its
default TLS options, including certificate checks, as soon as any
`ssl_options` are given.
"""
@spec ssl_options(keyword()) :: keyword()
def ssl_options(overrides \\ []) do
Keyword.merge(
[
verify: :verify_peer,
cacertfile: CAStore.file_path(),
depth: 20,
customize_hostname_check: [match_fun: :public_key.pkix_verify_hostname_match_fun(:https)]
],
overrides
)
end
@spec put_hackney_ssl_options(keyword()) :: keyword()
def put_hackney_ssl_options(opts) do
if opts[:insecure] do
opts
else
Keyword.put(opts, :ssl_options, ssl_options(Keyword.get(opts, :ssl_options, [])))
end
end
end

View file

@ -28,9 +28,9 @@ defmodule Pleroma.ReverseProxy.Client.Hackney do
@impl true
def request(method, url, headers, body, opts \\ []) do
opts =
Keyword.put_new(opts, :path_encode_fun, fn path ->
path
end)
opts
|> Keyword.put_new(:path_encode_fun, fn path -> path end)
|> Pleroma.HTTP.TLS.put_hackney_ssl_options()
if opts[:follow_redirect] != false do
{_state, req_opts} = Access.get_and_update(opts, :follow_redirect, fn a -> {a, false} end)