diff --git a/lib/rustler_precompiled.ex b/lib/rustler_precompiled.ex index 7392360..ab171d0 100644 --- a/lib/rustler_precompiled.ex +++ b/lib/rustler_precompiled.ex @@ -110,7 +110,8 @@ defmodule RustlerPrecompiled do * `HTTPS_PROXY` or `https_proxy` - Sets the HTTPS proxy configuration. * `HEX_CACERTS_PATH` - Sets the path for a custom CA certificates file. - If unset, defaults to `CAStore.file_path/0`. + If unset, defaults to `:public.cacerts_get/0` (OTP >= 25) if available. + In case it's running on an old OTP version, a warning is emitted. * `MIX_XDG` - If present, sets the OS as `:linux` for the `:filename.basedir/3` when getting an user cache dir. @@ -926,21 +927,17 @@ defmodule RustlerPrecompiled do :httpc.set_options([{:https_proxy, {{String.to_charlist(host), port}, []}}]) end - # https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/inets - # respects the user provided ca certs via Hex env var - cacertfile = System.get_env("HEX_CACERTS_PATH", CAStore.file_path()) - http_options = [ - ssl: [ - verify: :verify_peer, - cacertfile: cacertfile |> String.to_charlist(), - # We need to increase depth because the default value is 1. - # See: https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/ssl - depth: 3, - customize_hostname_check: [ - match_fun: :public_key.pkix_verify_hostname_match_fun(:https) - ] - ] + ssl: + [ + verify: :verify_peer, + # We need to increase depth because the default value is 1. + # See: https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/ssl + depth: 3, + customize_hostname_check: [ + match_fun: :public_key.pkix_verify_hostname_match_fun(:https) + ] + ] ++ cacerts_options() ] options = [body_format: :binary] @@ -957,6 +954,52 @@ defmodule RustlerPrecompiled do end end + # https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/inets + defp cacerts_options do + cond do + path = System.get_env("HEX_CACERTS_PATH") -> + [cacertfile: path] + + certs = otp_cacerts() -> + [cacerts: certs] + + true -> + warn_no_cacerts() + [] + end + end + + defp otp_cacerts do + if System.otp_release() >= "25" do + # cacerts_get/0 raises if no certs found + try do + :public_key.cacerts_get() + rescue + _ -> nil + end + end + end + + defp warn_no_cacerts do + Logger.warning(""" + No certificate trust store was found. + + A certificate trust store is required in + order to download locales for your configuration. + Since rustler_precompiled could not detect a system + installed certificate trust store one of the + following actions may be taken: + + 1. Specify the location of a certificate trust store + by configuring it in environment variable: + + export HEX_CACERTS_PATH="/path/to/cacerts.pem" + + 2. Use OTP 25+ on an OS that has built-in certificate + trust store. + """) + end + # Download a list of files from URLs and calculate its checksum. # Returns a list with details of the download and the checksum of each file. @doc false diff --git a/mix.exs b/mix.exs index 2278004..13f6684 100644 --- a/mix.exs +++ b/mix.exs @@ -35,7 +35,7 @@ defmodule RustlerPrecompiled.MixProject do defp deps do [ {:rustler, "~> 0.23", optional: true}, - {:castore, "~> 0.1 or ~> 1.0"}, + {:castore, "~> 0.1 or ~> 1.0", optional: true}, {:ex_doc, "~> 0.27", only: :dev}, {:bypass, "~> 2.1", only: :test} ] diff --git a/mix.lock b/mix.lock index d285bca..aecedca 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "bypass": {:hex, :bypass, "2.1.0", "909782781bf8e20ee86a9cabde36b259d44af8b9f38756173e8f5e2e1fabb9b1", [:mix], [{:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: false]}, {:ranch, "~> 1.3", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "d9b5df8fa5b7a6efa08384e9bbecfe4ce61c77d28a4282f79e02f1ef78d96b80"}, - "castore": {:hex, :castore, "1.0.8", "dedcf20ea746694647f883590b82d9e96014057aff1d44d03ec90f36a5c0dc6e", [:mix], [], "hexpm", "0b2b66d2ee742cb1d9cb8c8be3b43c3a70ee8651f37b75a8b982e036752983f1"}, + "castore": {:hex, :castore, "1.0.9", "5cc77474afadf02c7c017823f460a17daa7908e991b0cc917febc90e466a375c", [:mix], [], "hexpm", "5ea956504f1ba6f2b4eb707061d8e17870de2bee95fb59d512872c2ef06925e7"}, "cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, "cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"},