diff options
-rw-r--r-- | lib/ssh/src/ssh_connection_handler.erl | 6 | ||||
-rw-r--r-- | lib/ssh/src/ssh_transport.erl | 71 | ||||
-rw-r--r-- | lib/ssh/test/ssh_protocol_SUITE.erl | 43 | ||||
-rw-r--r-- | lib/ssh/vsn.mk | 2 |
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)" |