Skip to content

Commit 74bfa90

Browse files
committed
Merge branch 'ingela/ssl/cache-refresh/OTP-19698' into maint
* ingela/ssl/cache-refresh/OTP-19698: ssl: files_to_certificates should return empty content if file ceased to exist
2 parents e17126c + 533f47c commit 74bfa90

3 files changed

Lines changed: 61 additions & 32 deletions

File tree

lib/ssl/src/ssl_certificate.erl

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,18 +186,24 @@ certificate_chain(#cert{} = Cert, CertDbHandle, CertsDbRef, Candidates, Type) ->
186186
%% Description: Return list of DER encoded certificates.
187187
%%--------------------------------------------------------------------
188188
file_to_certificats(File, DbHandle) ->
189-
{ok, List} = ssl_manager:cache_pem_file(File, DbHandle),
190-
[Bin || {'Certificate', Bin, not_encrypted} <- List].
191-
189+
case ssl_manager:cache_pem_file(File, DbHandle) of
190+
{ok, List} ->
191+
[Bin || {'Certificate', Bin, not_encrypted} <- List];
192+
_ ->
193+
[] % If file no longer exists return empty content
194+
end.
192195
%%--------------------------------------------------------------------
193196
-spec file_to_crls(binary(), term()) -> [public_key:der_encoded()].
194197
%%
195198
%% Description: Return list of DER encoded certificates.
196199
%%--------------------------------------------------------------------
197200
file_to_crls(File, DbHandle) ->
198-
{ok, List} = ssl_manager:cache_pem_file(File, DbHandle),
199-
[Bin || {'CertificateList', Bin, not_encrypted} <- List].
200-
201+
case ssl_manager:cache_pem_file(File, DbHandle) of
202+
{ok, List} ->
203+
[Bin || {'CertificateList', Bin, not_encrypted} <- List];
204+
_ ->
205+
[] % If file no longer exists return empty content
206+
end.
201207
%%--------------------------------------------------------------------
202208
-spec validate(term(), {extension, #'Extension'{}} | {bad_cert, atom()} | valid | valid_peer,
203209
term(), logger:level() | none | all) -> {valid, term()} | {fail, tuple()} | {unknown, term()}.

lib/ssl/src/ssl_config.erl

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ init(SslOpts, Role) ->
6060
init_manager_name(maps:get(erl_dist, SslOpts, false)),
6161
#{pem_cache := PemCache} = Config = init_cacerts(SslOpts, Role),
6262
DHParams = init_diffie_hellman(PemCache, SslOpts, Role),
63-
CertKeyAlts = init_certs_keys(SslOpts, Role, PemCache),
63+
CertKeyAlts = init_certs_keys(SslOpts, PemCache),
6464
{ok, Config#{cert_key_alts => CertKeyAlts, dh_params => DHParams}}.
6565

6666
new_emulated([], EmOpts) ->
@@ -142,24 +142,17 @@ get_internal_active_n(true) ->
142142
get_internal_active_n(false) ->
143143
application_int(internal_active_n, ?INTERNAL_ACTIVE_N).
144144

145-
%%====================================================================
146-
%% Internal functions
147-
%%====================================================================
148-
149145
%%====================================================================
150146
%% Certificate and Key configuration
151147
%%====================================================================
152-
init_certs_keys(#{certs_keys := CertsKeys} = Opts, Role, PemCache) ->
153-
Pairs = lists:map(fun(CertKey) ->
154-
init_cert_key_pair(CertKey, Role, PemCache)
155-
end, CertsKeys),
148+
init_certs_keys(#{certs_keys := CertsKeys} = Opts, PemCache) ->
149+
Pairs = lists:map(fun(CertKey) -> init_cert_key_pair(CertKey, PemCache) end, CertsKeys),
156150
CertKeyGroups = group_pairs(Pairs),
157151
prioritize_groups(CertKeyGroups, Opts).
158152

159-
init_cert_key_pair(CertKey, Role, PemCache) ->
160-
Certs = init_certificates(CertKey, PemCache, Role),
161-
PrivateKey = init_private_key(maps:get(key, CertKey, undefined),
162-
CertKey, PemCache),
153+
init_cert_key_pair(CertKey, PemCache) ->
154+
Certs = init_certificates(CertKey, PemCache),
155+
PrivateKey = init_private_key(maps:get(key, CertKey, undefined), CertKey, PemCache),
163156
#{private_key => PrivateKey, certs => Certs}.
164157

165158
group_pairs([#{certs := []}]) ->
@@ -304,26 +297,25 @@ init_cacerts(#{cacerts := CaCerts, crl_cache := CRLCache} = Opts, Role) ->
304297
end,
305298
Config.
306299

307-
init_certificates(CertKey, PemCache, Role) ->
300+
init_certificates(CertKey, PemCache) ->
308301
case maps:get(cert, CertKey, undefined) of
309302
undefined ->
310-
init_certificate_file(maps:get(certfile, CertKey, <<>>), PemCache, Role);
303+
init_certificate_file(maps:get(certfile, CertKey, <<>>), PemCache);
311304
Bin when is_binary(Bin) ->
312305
[Bin];
313306
Certs when is_list(Certs) ->
314307
Certs
315308
end.
316309

317-
init_certificate_file(<<>>, _PemCache, _Role) ->
310+
init_certificate_file(<<>>, _PemCache) ->
318311
[];
319-
init_certificate_file(CertFile, PemCache, Role) ->
320-
try %% OwnCert | [OwnCert | Chain]
321-
ssl_certificate:file_to_certificats(CertFile, PemCache)
322-
catch
323-
_Error:_Reason when Role =:= client ->
324-
[];
325-
_Error:Reason ->
326-
file_error(CertFile, {certfile, Reason})
312+
init_certificate_file(CertFile, PemCache) ->
313+
case ssl_certificate:file_to_certificats(CertFile, PemCache) of
314+
[] ->
315+
Reason = cert_file_error(CertFile),
316+
file_error(CertFile, Reason);
317+
Certs ->
318+
Certs
327319
end.
328320

329321
init_private_key(#{algorithm := _, sign_fun := _SignFun} = Key, _, _) ->
@@ -2040,6 +2032,21 @@ ciphers_for_version([AtomVersion | _], CurrentSuites, Record) ->
20402032
[Suite || Suite <- CurrentSuites, lists:member(Suite, Suites)]
20412033
end.
20422034

2035+
cert_file_error(CertFile) ->
2036+
%% ssl_certificate:file_to_certificats
2037+
%% ignores file errors to be efficient
2038+
%% and works correctly for most executed
2039+
%% code paths.
2040+
Reason =
2041+
case file:read_file_info(CertFile) of
2042+
{error, _} = Error ->
2043+
Error;
2044+
_ ->
2045+
%% A file existed but included no certs
2046+
no_certs
2047+
end,
2048+
{options, {certfile, binary_to_list(CertFile), Reason}}.
2049+
20432050
%%%--------------------------------------------------------------
20442051
%%% Tracing
20452052
%%%--------------------------------------------------------------------

lib/ssl/test/ssl_pem_cache_SUITE.erl

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,12 @@
6969
alternative_path_noabspath/1,
7070
alternative_path_symlink_relative/0,
7171
alternative_path_symlink_relative/1,
72-
check_cert/3
72+
cache_file_does_not_exist/0,
73+
cache_file_does_not_exist/1
7374
]).
7475

76+
-export([check_cert/3]).
77+
7578
-define(CLEANUP_INTERVAL, 5000).
7679
-define(BIG_CLEANUP_INTERVAL, 600000).
7780
-define(SLEEP_AMOUNT, 1000).
@@ -93,7 +96,8 @@ all() ->
9396
alternative_path_noabspath,
9497
alternative_path_hardlink,
9598
alternative_path_symlink,
96-
alternative_path_symlink_relative].
99+
alternative_path_symlink_relative,
100+
cache_file_does_not_exist].
97101

98102
groups() -> [].
99103

@@ -431,6 +435,18 @@ alternative_path_symlink_relative(Config) when is_list(Config) ->
431435
disconnected => [8, 0, 0, 0]},
432436
alternative_path_helper(Config, fun make_symlink_noabspath/1, Expected).
433437

438+
cache_file_does_not_exist() ->
439+
[{doc, "White box test, that a none existing file will provide an empty content. "
440+
"This will have the effect that the ssl manager process "
441+
"will not crash but previous content will be invalidated."}].
442+
443+
cache_file_does_not_exist(Config) when is_list(Config)->
444+
PrivDir = proplists:get_value(priv_dir, Config),
445+
Id = ets:new(dummy_test, []),
446+
NonExistingFile = filename:join(PrivDir, "foo.pem"),
447+
[] = ssl_certificate:file_to_certificats(NonExistingFile, Id),
448+
[] = ssl_certificate:file_to_crls(NonExistingFile, Id).
449+
434450
%%--------------------------------------------------------------------
435451
%% Internal functions
436452
%%--------------------------------------------------------------------

0 commit comments

Comments
 (0)