|
@@ -32,7 +32,8 @@
|
|
|
ensure_ssl_files/2,
|
|
ensure_ssl_files/2,
|
|
|
delete_ssl_files/3,
|
|
delete_ssl_files/3,
|
|
|
drop_invalid_certs/1,
|
|
drop_invalid_certs/1,
|
|
|
- is_valid_pem_file/1
|
|
|
|
|
|
|
+ is_valid_pem_file/1,
|
|
|
|
|
+ is_pem/1
|
|
|
]).
|
|
]).
|
|
|
|
|
|
|
|
-export([
|
|
-export([
|
|
@@ -281,8 +282,10 @@ ensure_ssl_files(_Dir, undefined, _DryRun) ->
|
|
|
{ok, undefined};
|
|
{ok, undefined};
|
|
|
ensure_ssl_files(_Dir, #{<<"enable">> := False} = Opts, _DryRun) when ?IS_FALSE(False) ->
|
|
ensure_ssl_files(_Dir, #{<<"enable">> := False} = Opts, _DryRun) when ?IS_FALSE(False) ->
|
|
|
{ok, Opts};
|
|
{ok, Opts};
|
|
|
|
|
+ensure_ssl_files(_Dir, #{enable := False} = Opts, _DryRun) when ?IS_FALSE(False) ->
|
|
|
|
|
+ {ok, Opts};
|
|
|
ensure_ssl_files(Dir, Opts, DryRun) ->
|
|
ensure_ssl_files(Dir, Opts, DryRun) ->
|
|
|
- ensure_ssl_files(Dir, Opts, ?SSL_FILE_OPT_NAMES, DryRun).
|
|
|
|
|
|
|
+ ensure_ssl_files(Dir, Opts, ?SSL_FILE_OPT_NAMES ++ ?SSL_FILE_OPT_NAMES_A, DryRun).
|
|
|
|
|
|
|
|
ensure_ssl_files(_Dir, Opts, [], _DryRun) ->
|
|
ensure_ssl_files(_Dir, Opts, [], _DryRun) ->
|
|
|
{ok, Opts};
|
|
{ok, Opts};
|
|
@@ -306,18 +309,20 @@ delete_ssl_files(Dir, NewOpts0, OldOpts0) ->
|
|
|
end,
|
|
end,
|
|
|
lists:foreach(
|
|
lists:foreach(
|
|
|
fun(Key) -> delete_old_file(Get(Key, NewOpts), Get(Key, OldOpts)) end,
|
|
fun(Key) -> delete_old_file(Get(Key, NewOpts), Get(Key, OldOpts)) end,
|
|
|
- ?SSL_FILE_OPT_NAMES
|
|
|
|
|
- ).
|
|
|
|
|
|
|
+ ?SSL_FILE_OPT_NAMES ++ ?SSL_FILE_OPT_NAMES_A
|
|
|
|
|
+ ),
|
|
|
|
|
+ %% try to delete the dir if it is empty
|
|
|
|
|
+ _ = file:del_dir(pem_dir(Dir)),
|
|
|
|
|
+ ok.
|
|
|
|
|
|
|
|
delete_old_file(New, Old) when New =:= Old -> ok;
|
|
delete_old_file(New, Old) when New =:= Old -> ok;
|
|
|
delete_old_file(_New, _Old = undefined) ->
|
|
delete_old_file(_New, _Old = undefined) ->
|
|
|
ok;
|
|
ok;
|
|
|
delete_old_file(_New, Old) ->
|
|
delete_old_file(_New, Old) ->
|
|
|
- case filelib:is_regular(Old) andalso file:delete(Old) of
|
|
|
|
|
|
|
+ case is_generated_file(Old) andalso filelib:is_regular(Old) andalso file:delete(Old) of
|
|
|
ok ->
|
|
ok ->
|
|
|
ok;
|
|
ok;
|
|
|
- %% already deleted
|
|
|
|
|
- false ->
|
|
|
|
|
|
|
+ false -> %% the file is not generated by us, or it is already deleted
|
|
|
ok;
|
|
ok;
|
|
|
{error, Reason} ->
|
|
{error, Reason} ->
|
|
|
?SLOG(error, #{msg => "failed_to_delete_ssl_file", file_path => Old, reason => Reason})
|
|
?SLOG(error, #{msg => "failed_to_delete_ssl_file", file_path => Old, reason => Reason})
|
|
@@ -391,11 +396,33 @@ save_pem_file(Dir, Key, Pem, DryRun) ->
|
|
|
%% the filename is prefixed by the option name without the 'file' part
|
|
%% the filename is prefixed by the option name without the 'file' part
|
|
|
%% and suffixed with the first 8 byets the PEM content's md5 checksum.
|
|
%% and suffixed with the first 8 byets the PEM content's md5 checksum.
|
|
|
%% e.g. key-1234567890abcdef, cert-1234567890abcdef, and cacert-1234567890abcdef
|
|
%% e.g. key-1234567890abcdef, cert-1234567890abcdef, and cacert-1234567890abcdef
|
|
|
|
|
+is_generated_file(Filename) ->
|
|
|
|
|
+ case string:split(filename:basename(Filename), "-") of
|
|
|
|
|
+ [_Name, Suffix] -> is_hex_str(Suffix);
|
|
|
|
|
+ _ -> false
|
|
|
|
|
+ end.
|
|
|
|
|
+
|
|
|
pem_file_name(Dir, Key, Pem) ->
|
|
pem_file_name(Dir, Key, Pem) ->
|
|
|
<<CK:8/binary, _/binary>> = crypto:hash(md5, Pem),
|
|
<<CK:8/binary, _/binary>> = crypto:hash(md5, Pem),
|
|
|
Suffix = hex_str(CK),
|
|
Suffix = hex_str(CK),
|
|
|
- FileName = binary:replace(Key, <<"file">>, <<"-", Suffix/binary>>),
|
|
|
|
|
- filename:join([emqx:mutable_certs_dir(), Dir, FileName]).
|
|
|
|
|
|
|
+ FileName = binary:replace(ensure_bin(Key), <<"file">>, <<"-", Suffix/binary>>),
|
|
|
|
|
+ filename:join([pem_dir(Dir), FileName]).
|
|
|
|
|
+
|
|
|
|
|
+pem_dir(Dir) ->
|
|
|
|
|
+ filename:join([emqx:mutable_certs_dir(), Dir]).
|
|
|
|
|
+
|
|
|
|
|
+is_hex_str(HexStr) ->
|
|
|
|
|
+ try is_hex_str2(ensure_str(HexStr))
|
|
|
|
|
+ catch throw: not_hex -> false
|
|
|
|
|
+ end.
|
|
|
|
|
+
|
|
|
|
|
+is_hex_str2(HexStr) ->
|
|
|
|
|
+ _ = [case S of
|
|
|
|
|
+ S when S >= $0, S =< $9 -> S;
|
|
|
|
|
+ S when S >= $a, S =< $f -> S;
|
|
|
|
|
+ _ -> throw(not_hex)
|
|
|
|
|
+ end || S <- HexStr],
|
|
|
|
|
+ true.
|
|
|
|
|
|
|
|
hex_str(Bin) ->
|
|
hex_str(Bin) ->
|
|
|
iolist_to_binary([io_lib:format("~2.16.0b", [X]) || <<X:8>> <= Bin]).
|
|
iolist_to_binary([io_lib:format("~2.16.0b", [X]) || <<X:8>> <= Bin]).
|
|
@@ -417,20 +444,21 @@ drop_invalid_certs(#{enable := False} = SSL) when ?IS_FALSE(False) ->
|
|
|
drop_invalid_certs(#{<<"enable">> := False} = SSL) when ?IS_FALSE(False) ->
|
|
drop_invalid_certs(#{<<"enable">> := False} = SSL) when ?IS_FALSE(False) ->
|
|
|
maps:without(?SSL_FILE_OPT_NAMES, SSL);
|
|
maps:without(?SSL_FILE_OPT_NAMES, SSL);
|
|
|
drop_invalid_certs(#{enable := True} = SSL) when ?IS_TRUE(True) ->
|
|
drop_invalid_certs(#{enable := True} = SSL) when ?IS_TRUE(True) ->
|
|
|
- drop_invalid_certs(?SSL_FILE_OPT_NAMES_A, SSL);
|
|
|
|
|
|
|
+ do_drop_invalid_certs(?SSL_FILE_OPT_NAMES_A, SSL);
|
|
|
drop_invalid_certs(#{<<"enable">> := True} = SSL) when ?IS_TRUE(True) ->
|
|
drop_invalid_certs(#{<<"enable">> := True} = SSL) when ?IS_TRUE(True) ->
|
|
|
- drop_invalid_certs(?SSL_FILE_OPT_NAMES, SSL).
|
|
|
|
|
|
|
+ do_drop_invalid_certs(?SSL_FILE_OPT_NAMES, SSL).
|
|
|
|
|
|
|
|
-drop_invalid_certs([], SSL) ->
|
|
|
|
|
|
|
+do_drop_invalid_certs([], SSL) ->
|
|
|
SSL;
|
|
SSL;
|
|
|
-drop_invalid_certs([Key | Keys], SSL) ->
|
|
|
|
|
|
|
+do_drop_invalid_certs([Key | Keys], SSL) ->
|
|
|
case maps:get(Key, SSL, undefined) of
|
|
case maps:get(Key, SSL, undefined) of
|
|
|
undefined ->
|
|
undefined ->
|
|
|
- drop_invalid_certs(Keys, SSL);
|
|
|
|
|
- Path ->
|
|
|
|
|
- case is_valid_pem_file(Path) of
|
|
|
|
|
- true -> SSL;
|
|
|
|
|
- {error, _} -> maps:without([Key], SSL)
|
|
|
|
|
|
|
+ do_drop_invalid_certs(Keys, SSL);
|
|
|
|
|
+ PemOrPath ->
|
|
|
|
|
+ case is_pem(PemOrPath) orelse is_valid_pem_file(PemOrPath) of
|
|
|
|
|
+ true -> do_drop_invalid_certs(Keys, SSL);
|
|
|
|
|
+ {error, _} ->
|
|
|
|
|
+ do_drop_invalid_certs(Keys, maps:without([Key], SSL))
|
|
|
end
|
|
end
|
|
|
end.
|
|
end.
|
|
|
|
|
|
|
@@ -476,6 +504,9 @@ ensure_str(undefined) -> undefined;
|
|
|
ensure_str(L) when is_list(L) -> L;
|
|
ensure_str(L) when is_list(L) -> L;
|
|
|
ensure_str(B) when is_binary(B) -> unicode:characters_to_list(B, utf8).
|
|
ensure_str(B) when is_binary(B) -> unicode:characters_to_list(B, utf8).
|
|
|
|
|
|
|
|
|
|
+ensure_bin(B) when is_binary(B) -> B;
|
|
|
|
|
+ensure_bin(A) when is_atom(A) -> atom_to_binary(A, utf8).
|
|
|
|
|
+
|
|
|
-if(?OTP_RELEASE > 22).
|
|
-if(?OTP_RELEASE > 22).
|
|
|
-ifdef(TEST).
|
|
-ifdef(TEST).
|
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
-include_lib("eunit/include/eunit.hrl").
|