feat(tls-partial-chains): error handling for invalid cacertfile

This commit is contained in:
William Yang 2023-05-05 10:04:20 +02:00
parent 30cccab387
commit 6d0a76805a
2 changed files with 24 additions and 2 deletions

View File

@ -26,6 +26,8 @@
, opt_partial_chain/1 , opt_partial_chain/1
]). ]).
-include("logger.hrl").
%% non-empty string %% non-empty string
-define(IS_STRING(L), (is_list(L) andalso L =/= [] andalso is_integer(hd(L)))). -define(IS_STRING(L), (is_list(L) andalso L =/= [] andalso is_integer(hd(L)))).
%% non-empty list of strings %% non-empty list of strings
@ -189,14 +191,23 @@ opt_partial_chain(SslOpts) ->
false -> false ->
SslOpts; SslOpts;
V when V =:= cacert_from_cacertfile orelse V == true -> V when V =:= cacert_from_cacertfile orelse V == true ->
replace(SslOpts, partial_chain, cacert_from_cacertfile(SslOpts)) replace(SslOpts, partial_chain, rootfun_trusted_ca_from_cacertfile(SslOpts))
end. end.
replace(Opts, Key, Value) -> [{Key, Value} | proplists:delete(Key, Opts)]. replace(Opts, Key, Value) -> [{Key, Value} | proplists:delete(Key, Opts)].
%% @doc Helper, make TLS root_fun %% @doc Helper, make TLS root_fun
cacert_from_cacertfile(SslOpts) -> rootfun_trusted_ca_from_cacertfile(SslOpts) ->
Cacertfile = proplists:get_value(cacertfile, SslOpts, undefined), Cacertfile = proplists:get_value(cacertfile, SslOpts, undefined),
try do_rootfun_trusted_ca_from_cacertfile(Cacertfile)
catch _Error:_ ->
%% The cacertfile will be checked by OTP SSL as well and OTP choice to be silent on this.
%% We are touching security sutffs, don't leak extra info..
?LOG(error, "Failed to look for trusted cacert from cacertfile. loc: ~p:~p",
[?MODULE, ?FUNCTION_NAME]),
throw({error, ?FUNCTION_NAME})
end.
do_rootfun_trusted_ca_from_cacertfile(Cacertfile) ->
{ok, PemBin} = file:read_file(Cacertfile), {ok, PemBin} = file:read_file(Cacertfile),
%% The last one should be the top parent in the chain if it is a chain %% The last one should be the top parent in the chain if it is a chain
{'Certificate', CADer, _} = lists:last(public_key:pem_decode(PemBin)), {'Certificate', CADer, _} = lists:last(public_key:pem_decode(PemBin)),

View File

@ -281,6 +281,17 @@ t_conn_success_with_server_intermediate_and_client_root_chain(Config) ->
fail_when_ssl_error(Socket), fail_when_ssl_error(Socket),
ok = ssl:close(Socket). ok = ssl:close(Socket).
t_error_handling_invalid_cacertfile(Config) ->
Port = emqx_test_tls_certs_helper:select_free_port(ssl),
DataDir = ?config(data_dir, Config),
Options = [{ssl_options, [ {cacertfile, filename:join(DataDir, "server2.key")} %% trigger error
, {certfile, filename:join(DataDir, "server2.pem")}
, {keyfile, filename:join(DataDir, "server2.key")}
| ?config(ssl_config, Config)
]}],
?assertException(throw, {error, rootfun_trusted_ca_from_cacertfile}, emqx_listeners:start_listener(ssl, Port, Options)).
ssl_config_verify_partial_chain() -> ssl_config_verify_partial_chain() ->
[ {verify, verify_peer} [ {verify, verify_peer}
, {fail_if_no_peer_cert, true} , {fail_if_no_peer_cert, true}