aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl6
-rw-r--r--lib/ssh/src/ssh_transport.erl71
-rw-r--r--lib/ssh/test/ssh_protocol_SUITE.erl43
-rw-r--r--lib/ssh/vsn.mk2
4 files changed, 88 insertions, 34 deletions
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index fcd66b80c0..5b4f6081c1 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -425,6 +425,12 @@ key_exchange(#ssh_msg_kex_dh_gex_request{} = Msg,
send_msg(GexGroup, State),
{next_state, key_exchange_dh_gex_init, next_packet(State#state{ssh_params = Ssh})};
+key_exchange(#ssh_msg_kex_dh_gex_request_old{} = Msg,
+ #state{ssh_params = #ssh{role = server} = Ssh0} = State) ->
+ {ok, GexGroup, Ssh} = ssh_transport:handle_kex_dh_gex_request(Msg, Ssh0),
+ send_msg(GexGroup, State),
+ {next_state, key_exchange_dh_gex_init, next_packet(State#state{ssh_params = Ssh})};
+
key_exchange(#ssh_msg_kex_dh_gex_group{} = Msg,
#state{ssh_params = #ssh{role = client} = Ssh0} = State) ->
{ok, KexGexInit, Ssh} = ssh_transport:handle_kex_dh_gex_group(Msg, Ssh0),
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 2b6f0a3cdc..e3ee399b8e 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -427,6 +427,32 @@ handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request{min = Min,
Ssh#ssh{keyex_key = {{Private, Public}, {G, P}},
keyex_info = {Min, Max, NBits}
}};
+
+handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request_old{n = NBits},
+ Ssh0=#ssh{opts=Opts}) ->
+ %% server
+ %%
+ %% This message was in the draft-00 of rfc4419
+ %% (https://tools.ietf.org/html/draft-ietf-secsh-dh-group-exchange-00)
+ %% In later drafts and the rfc is "is used for backward compatibility".
+ %% Unfortunatly the rfc does not specify how to treat the parameter n
+ %% if there is no group of that modulus length :(
+ %% The draft-00 however specifies that n is the "... number of bits
+ %% the subgroup should have at least".
+ %% Further, it says that "Servers and clients SHOULD support groups
+ %% with a modulus length of k bits, where 1024 <= k <= 8192."
+ %%
+ Min = NBits,
+ Max = 8192,
+ {G, P} = dh_gex_group(Min, NBits, Max, proplists:get_value(dh_gex_groups,Opts)),
+ {Public, Private} = generate_key(dh, [P,G]),
+ {SshPacket, Ssh} =
+ ssh_packet(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0),
+ {ok, SshPacket,
+ Ssh#ssh{keyex_key = {{Private, Public}, {G, P}},
+ keyex_info = {-1, -1, NBits} % flag for kex_h hash calc
+ }};
+
handle_kex_dh_gex_request(_, _) ->
throw({{error,bad_ssh_msg_kex_dh_gex_request},
#ssh_msg_disconnect{
@@ -1286,6 +1312,9 @@ kex_h(SSH, Curve, Key, Q_c, Q_s, K) ->
kex_h(SSH, Key, Min, NBits, Max, Prime, Gen, E, F, K) ->
L = if Min==-1; Max==-1 ->
+ %% flag from 'ssh_msg_kex_dh_gex_request_old'
+ %% It was like this before that message was supported,
+ %% why?
Ts = [string,string,binary,binary,binary,
uint32,
mpint,mpint,mpint,mpint,mpint],
@@ -1349,35 +1378,23 @@ dh_gex_default_groups() -> ?dh_default_groups.
dh_gex_group(Min, N, Max, undefined) ->
dh_gex_group(Min, N, Max, dh_gex_default_groups());
dh_gex_group(Min, N, Max, Groups) ->
- %% First try to find an exact match. If not an exact match, select the largest possible.
- {_,Group} =
- lists:foldl(
- fun(_, {I,G}) when I==N ->
- %% If we have an exact match already: use that one
- {I,G};
- ({I,G}, _) when I==N ->
- %% If we now found an exact match: use that very one
- {I,G};
- ({I,G}, {Imax,_Gmax}) when Min=<I,I=<Max, % a) {I,G} fullfills the requirements
- I>Imax -> % b) {I,G} is larger than current max
- %% A group within the limits and better than the one we have
- {I,G};
- (_, IGmax) ->
- %% Keep the one we have
- IGmax
- end, {-1,undefined}, Groups),
-
- case Group of
- undefined ->
- throw(#ssh_msg_disconnect{
- code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
- description = "No possible diffie-hellman-group-exchange group found",
- language = ""});
- _ ->
- Group
+ %% Try to find an exact match. If not an exact match, select the first found.
+ case lists:keyfind(N, 1, Groups) of
+ {N,Grp} ->
+ Grp;
+ false ->
+ case lists:dropwhile(fun({I,_}) -> I < Min-1 orelse I > Max+1 end,
+ Groups) of
+ [{_,Grp}|_] ->
+ Grp;
+ [] ->
+ throw(#ssh_msg_disconnect{
+ code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
+ description = "No possible diffie-hellman-group-exchange group found",
+ language = ""})
+ end
end.
-
generate_key(Algorithm, Args) ->
{Public,Private} = crypto:generate_key(Algorithm, Args),
{crypto:bytes_to_integer(Public), crypto:bytes_to_integer(Private)}.
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index d8e99799e2..dd0adda2dc 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -60,7 +60,9 @@ groups() ->
gex_client_init_default_noexact,
gex_client_init_default_exact,
gex_client_init_option_groups,
- gex_client_init_option_groups_file
+ gex_client_init_option_groups_file,
+ gex_client_old_request_exact,
+ gex_client_old_request_noexact
]}
].
@@ -79,7 +81,9 @@ init_per_testcase(no_common_alg_server_disconnects, Config) ->
init_per_testcase(TC, Config) when TC == gex_client_init_default_noexact ;
TC == gex_client_init_default_exact ;
TC == gex_client_init_option_groups ;
- TC == gex_client_init_option_groups_file ->
+ TC == gex_client_init_option_groups_file ;
+ TC == gex_client_old_request_exact ;
+ TC == gex_client_old_request_noexact ->
Opts = case TC of
gex_client_init_option_groups ->
[{dh_gex_groups, [{2345, 3, 41}]}];
@@ -101,7 +105,9 @@ end_per_testcase(no_common_alg_server_disconnects, Config) ->
end_per_testcase(TC, Config) when TC == gex_client_init_default_noexact ;
TC == gex_client_init_default_exact ;
TC == gex_client_init_option_groups ;
- TC == gex_client_init_option_groups_file ->
+ TC == gex_client_init_option_groups_file ;
+ TC == gex_client_old_request_exact ;
+ TC == gex_client_old_request_noexact ->
stop_std_daemon(Config);
end_per_testcase(_TestCase, Config) ->
check_std_daemon_works(Config, ?LINE).
@@ -333,13 +339,13 @@ no_common_alg_client_disconnects(Config) ->
gex_client_init_default_noexact(Config) ->
do_gex_client_init(Config, {2000, 3000, 4000},
%% Warning, app knowledege:
- ?dh_group15).
+ ?dh_group14).
gex_client_init_default_exact(Config) ->
- do_gex_client_init(Config, {2000, 2048, 4000},
+ do_gex_client_init(Config, {2000, 3072, 4000},
%% Warning, app knowledege:
- ?dh_group14).
+ ?dh_group15).
gex_client_init_option_groups(Config) ->
@@ -373,6 +379,31 @@ do_gex_client_init(Config, {Min,N,Max}, {_,{G,P}}) ->
]
).
+%%%--------------------------------------------------------------------
+gex_client_old_request_exact(Config) -> do_gex_client_init_old(Config, 2048, ?dh_group14).
+gex_client_old_request_noexact(Config) -> do_gex_client_init_old(Config, 1000, ?dh_group1).
+
+do_gex_client_init_old(Config, N, {_,{G,P}}) ->
+ {ok,_} =
+ ssh_trpt_test_lib:exec(
+ [{set_options, [print_ops, print_seqnums, print_messages]},
+ {connect,
+ server_host(Config),server_port(Config),
+ [{silently_accept_hosts, true},
+ {user_dir, user_dir(Config)},
+ {user_interaction, false},
+ {preferred_algorithms,[{kex,['diffie-hellman-group-exchange-sha1']}]}
+ ]},
+ receive_hello,
+ {send, hello},
+ {send, ssh_msg_kexinit},
+ {match, #ssh_msg_kexinit{_='_'}, receive_msg},
+ {send, #ssh_msg_kex_dh_gex_request_old{n = N}},
+ {match, #ssh_msg_kex_dh_gex_group{p=P, g=G, _='_'}, receive_msg}
+ ]
+ ).
+
+
%%%================================================================
%%%==== Internal functions ========================================
%%%================================================================
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 5bb18a656a..762bd9b208 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,4 +1,4 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.1.2
+SSH_VSN = 4.1.3
APP_VSN = "ssh-$(SSH_VSN)"