diff --git a/lib/pleroma/http/tls.ex b/lib/pleroma/http/tls.ex index 22718835b..e1fbc7caa 100644 --- a/lib/pleroma/http/tls.ex +++ b/lib/pleroma/http/tls.ex @@ -6,9 +6,11 @@ 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 + Hackney otherwise trusts its own certifi bundle. Hackney 1 drops all of its default TLS options, including certificate checks, as soon as any - `ssl_options` are given. + `ssl_options` are given. Hackney 4 merges them, so `partial_chain` must be + set too: Hackney's own one trusts any certificate in the peer chain that is + in certifi. """ @spec ssl_options(keyword()) :: keyword() @@ -18,12 +20,16 @@ defmodule Pleroma.HTTP.TLS do verify: :verify_peer, cacertfile: CAStore.file_path(), depth: 20, - customize_hostname_check: [match_fun: :public_key.pkix_verify_hostname_match_fun(:https)] + customize_hostname_check: [match_fun: :public_key.pkix_verify_hostname_match_fun(:https)], + partial_chain: &__MODULE__.reject_partial_chain/1 ], overrides ) end + @doc false + def reject_partial_chain(_certs), do: :unknown_ca + @spec put_hackney_ssl_options(keyword()) :: keyword() def put_hackney_ssl_options(opts) do if opts[:insecure] do diff --git a/test/pleroma/http/tls_test.exs b/test/pleroma/http/tls_test.exs index 7e9a85edd..490950b50 100644 --- a/test/pleroma/http/tls_test.exs +++ b/test/pleroma/http/tls_test.exs @@ -17,6 +17,12 @@ defmodule Pleroma.HTTP.TLSTest do assert is_function(match_fun, 2) end + test "does not accept certificates from the peer chain as trust anchors" do + partial_chain = TLS.ssl_options()[:partial_chain] + + assert partial_chain.([:certificate]) == :unknown_ca + end + test "keeps the CA bundle when other options are given" do opts = TLS.ssl_options(versions: [:"tlsv1.2"])