Skip to content

Commit

Permalink
ssl: Reject unsupoorted previous version with protocol alert
Browse files Browse the repository at this point in the history
  • Loading branch information
IngelaAndin committed Jun 1, 2022
1 parent 5619b35 commit c5a8e8c
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 46 deletions.
86 changes: 57 additions & 29 deletions lib/ssl/src/tls_connection_1_3.erl
Original file line number Diff line number Diff line change
Expand Up @@ -257,41 +257,69 @@ user_hello(_, _, _) ->

start(internal, #change_cipher_spec{}, State) ->
tls_gen_connection:next_event(?FUNCTION_NAME, no_record, State);
start(internal, #client_hello{extensions = Extensions} = Hello,
#state{ssl_options = #{handshake := hello},
start(internal, #client_hello{extensions = #{client_hello_versions :=
#client_hello_versions{versions = ClientVersions}} = Extensions} = Hello,
#state{ssl_options = #{handshake := hello},
start_or_recv_from = From,
handshake_env = HsEnv} = State) ->
{next_state, user_hello,
State#state{start_or_recv_from = undefined,
handshake_env = HsEnv#handshake_env{
hello = Hello}}, [{reply, From, {ok, Extensions}}]};
start(internal, #client_hello{} = Hello, State0) ->
case tls_handshake_1_3:do_start(Hello, State0) of
#alert{} = Alert ->
ssl_gen_statem:handle_own_alert(Alert, start, State0);
{State, start} ->
{next_state, start, State, []};
{State, negotiated} ->
{next_state, negotiated, State, [{next_event, internal, {start_handshake, undefined}}]};
{State, negotiated, PSK} -> %% Session Resumption with PSK
{next_state, negotiated, State, [{next_event, internal, {start_handshake, PSK}}]}
case tls_record:is_acceptable_version({3,4}, ClientVersions) of
true ->
{next_state, user_hello,
State#state{start_or_recv_from = undefined,
handshake_env = HsEnv#handshake_env{
hello = Hello}}, [{reply, From, {ok, Extensions}}]};
false ->
ssl_gen_statem:handle_own_alert(?ALERT_REC(?FATAL, ?PROTOCOL_VERSION), start, State)
end;
start(internal, #server_hello{extensions = Extensions} = ServerHello,
#state{ssl_options = #{handshake := hello},
start(internal, #client_hello{extensions = #{client_hello_versions :=
#client_hello_versions{versions = ClientVersions}
}} = Hello, State0) ->
case tls_record:is_acceptable_version({3,4}, ClientVersions) of
true ->
case tls_handshake_1_3:do_start(Hello, State0) of
#alert{} = Alert ->
ssl_gen_statem:handle_own_alert(Alert, start, State0);
{State, start} ->
{next_state, start, State, []};
{State, negotiated} ->
{next_state, negotiated, State, [{next_event, internal, {start_handshake, undefined}}]};
{State, negotiated, PSK} -> %% Session Resumption with PSK
{next_state, negotiated, State, [{next_event, internal, {start_handshake, PSK}}]}
end;
false ->
ssl_gen_statem:handle_own_alert(?ALERT_REC(?FATAL, ?PROTOCOL_VERSION), start, State0)
end;
start(internal, #client_hello{}, State0) ->
ssl_gen_statem:handle_own_alert(?ALERT_REC(?FATAL, ?PROTOCOL_VERSION), start, State0);
start(internal, #server_hello{extensions = Extensions, server_version = Version} = ServerHello,
#state{ssl_options = #{handshake := hello,
versions := SupportedVersions
},
handshake_env = HsEnv,
start_or_recv_from = From}
= State) ->
{next_state, user_hello,
State#state{start_or_recv_from = undefined,
handshake_env = HsEnv#handshake_env{
hello = ServerHello}}, [{reply, From, {ok, Extensions}}]};
start(internal, #server_hello{} = ServerHello, State0) ->
case tls_handshake_1_3:do_start(ServerHello, State0) of
#alert{} = Alert ->
ssl_gen_statem:handle_own_alert(Alert, start, State0);
{State, NextState} ->
{next_state, NextState, State, []}
end;
case tls_record:is_acceptable_version(Version, SupportedVersions) of
true ->
{next_state, user_hello,
State#state{start_or_recv_from = undefined,
handshake_env = HsEnv#handshake_env{
hello = ServerHello}}, [{reply, From, {ok, Extensions}}]};
false ->
ssl_gen_statem:handle_own_alert(?ALERT_REC(?FATAL, ?PROTOCOL_VERSION), start, State)
end;
start(internal, #server_hello{server_version = Version} = ServerHello,
#state{ssl_options = #{versions := SupportedVersions}} = State0) ->
case tls_record:is_acceptable_version(Version, SupportedVersions) of
true ->
case tls_handshake_1_3:do_start(ServerHello, State0) of
#alert{} = Alert ->
ssl_gen_statem:handle_own_alert(Alert, start, State0);
{State, NextState} ->
{next_state, NextState, State, []}
end;
false ->
ssl_gen_statem:handle_own_alert(?ALERT_REC(?FATAL, ?PROTOCOL_VERSION), start, State0)
end;
start(info, Msg, State) ->
tls_gen_connection:handle_info(Msg, ?FUNCTION_NAME, State);
start(Type, Msg, State) ->
Expand Down
68 changes: 51 additions & 17 deletions lib/ssl/test/ssl_reject_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@
]).

%% Test cases
-export([reject_sslv2/0,
-export([reject_prev/0,
reject_prev/1,
reject_sslv2/0,
reject_sslv2/1,
reject_sslv3/0,
reject_sslv3/1,
Expand All @@ -65,17 +67,19 @@ all() ->
{group, 'tlsv1.3'},
{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'}
].
{group, 'tlsv1'},
{group, 'dtlsv1.2'}
].

groups() ->
[{'tlsv1.3', [], all_versions_tests()},
{'tlsv1.2', [], all_versions_tests()},
{'tlsv1.1', [], all_versions_tests()},
{'tlsv1', [], all_versions_tests()}
[{'tlsv1.3', [], [reject_prev] ++ all_tls_version_tests()},
{'tlsv1.2', [], [reject_prev] ++ all_tls_version_tests()},
{'tlsv1.1', [], [reject_prev] ++ all_tls_version_tests()},
{'tlsv1', [], all_tls_version_tests()},
{'dtlsv1.2', [], [reject_prev]}
].

all_versions_tests() ->
all_tls_version_tests() ->
[
reject_sslv2,
reject_sslv3,
Expand Down Expand Up @@ -145,7 +149,6 @@ reject_sslv3() ->
[{doc,"Test that SSL v3 clients are rejected"}].

reject_sslv3(Config) when is_list(Config) ->
Version = proplists:get_value(version, Config),
ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
{_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),

Expand All @@ -168,14 +171,8 @@ reject_sslv3(Config) when is_list(Config) ->
{ok, Socket} = gen_tcp:connect(Hostname, Port, [{active, false}]),
gen_tcp:send(Socket, ClientHello),
%% v3 is not a supported protocol version (but hello record could have 3.0 for legacy interop)
case Version of
'tlsv1.3' ->
ssl_test_lib:check_server_alert(Server, illegal_parameter),
client_rejected(Socket, illegal_parameter);
_ ->
ssl_test_lib:check_server_alert(Server, protocol_version),
client_rejected(Socket, protocol_version)
end.
ssl_test_lib:check_server_alert(Server, protocol_version),
client_rejected(Socket, protocol_version).

accept_sslv3_record_hello() ->
[{doc,"Test that ssl v3 record in clients hellos are ignored when higher version are advertised"}].
Expand Down Expand Up @@ -205,6 +202,34 @@ accept_sslv3_record_hello(Config) when is_list(Config) ->
{error, timeout} ->
ct:fail(ssl3_record_not_accepted)
end.


reject_prev() ->
[{doc,"Test that prev version is rejected, for all version where there exists possible support a previous version, that is not configured"}].

reject_prev(Config) when is_list(Config) ->
ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),

{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Version = proplists:get_value(version, Config),
PrevVersion = prev_version(Version),

Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {ssl_test_lib,
no_result, []}},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),

Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
{mfa, {ssl_test_lib,
no_result, []}},
{options,[{versions, [PrevVersion]} | ClientOpts]}]),
ssl_test_lib:check_client_alert(Server, Client, protocol_version).

%%--------------------------------------------------------------------
%% Internal functions -----------------------------------
%%--------------------------------------------------------------------
Expand Down Expand Up @@ -273,3 +298,12 @@ hello_with_3_0_record('tlsv1.3') ->
42,42,32,73,84,134,110,74,110,163,140,111,177,126,133,118,141,2,153,
156,157,205,101,69,0,10,0,10,0,8,0,29,0,30,0,23,0,24,0,11,0,2,1,0,0,
?SUPPORTED_VERSIONS_EXT,0,3,2,?TLS_MAJOR, ?TLS_1_3_MINOR>>.

prev_version('tlsv1.3') ->
'tlsv1.2';
prev_version('tlsv1.2') ->
'tlsv1.1';
prev_version('tlsv1.1') ->
'tlsv1';
prev_version('dtlsv1.2') ->
'dtlsv1'.

0 comments on commit c5a8e8c

Please sign in to comment.