aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/ssh/src/ssh.erl31
-rw-r--r--lib/ssh/src/ssh_transport.erl54
2 files changed, 71 insertions, 14 deletions
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 370f086600..cc2c591735 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -373,6 +373,10 @@ handle_option([{auth_method_kb_interactive_data, _} = Opt | Rest], SocketOptions
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([{preferred_algorithms,_} = Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
+handle_option([{dh_gex_groups,_} = Opt | Rest], SocketOptions, SshOptions) ->
+ handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
+handle_option([{dh_gex_limits,_} = Opt | Rest], SocketOptions, SshOptions) ->
+ handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([{quiet_mode, _} = Opt|Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([{idle_time, _} = Opt | Rest], SocketOptions, SshOptions) ->
@@ -411,6 +415,33 @@ handle_ssh_option({user_interaction, Value} = Opt) when is_boolean(Value) ->
Opt;
handle_ssh_option({preferred_algorithms,[_|_]} = Opt) ->
handle_pref_algs(Opt);
+handle_ssh_option({dh_gex_groups,L=[{I1,I2,I3}|_]}) when is_integer(I1), I1>0,
+ is_integer(I2), I2>0,
+ is_integer(I3), I3>0 ->
+ {dh_gex_groups, [{N,{G,P}} || {N,P,G} <- L]};
+handle_ssh_option({dh_gex_groups,{file,File=[C|_]}}=Opt) when is_integer(C), C>0 ->
+ %% A string, (file name)
+ case file:consult(File) of
+ {ok, List} ->
+ case lists:all(fun({I1,I2,I3}) when is_integer(I1), I1>0,
+ is_integer(I2), I2>0,
+ is_integer(I3), I3>0 ->
+ true;
+ (_) ->
+ false
+ end, List) of
+ true ->
+ handle_ssh_option({dh_gex_groups,List});
+ false ->
+ throw({error, {{eoptions, Opt}, "Bad format in file "++File}})
+ end;
+ Error ->
+ throw({error, {{eoptions, Opt},{"Error reading file",Error}}})
+ end;
+handle_ssh_option({dh_gex_limits,{Min,I,Max}} = Opt) when is_integer(Min), Min>0,
+ is_integer(I), I>0,
+ is_integer(Max), Max>0 ->
+ Opt;
handle_ssh_option({connect_timeout, Value} = Opt) when is_integer(Value); Value == infinity ->
Opt;
handle_ssh_option({max_sessions, Value} = Opt) when is_integer(Value), Value>0 ->
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 69ba797faf..dda9192284 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -404,9 +404,10 @@ handle_kexdh_reply(#ssh_msg_kexdh_reply{public_host_key = HostKey,
%%%
handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request{min = Min,
n = NBits,
- max = Max}, Ssh0) when Min=<NBits, NBits=<Max ->
+ max = Max},
+ Ssh0=#ssh{opts=Opts}) when Min=<NBits, NBits=<Max ->
%% server
- {G, P} = dh_gex_group(Min, NBits, Max),
+ {G, P} = dh_gex_group(Min, NBits, Max, proplists:get_value(dh_gex_groups,Opts)),
{Private, Public} = dh_gen_key(G, P, 1024),
{SshPacket, Ssh} =
ssh_packet(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0),
@@ -1236,21 +1237,46 @@ dh_group15() ->
dh_group16() ->
{2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF}.
-
dh_group('diffie-hellman-group1-sha1') -> dh_group1();
dh_group('diffie-hellman-group14-sha1') -> dh_group14().
-
-%%% First try exact match:
-dh_gex_group(_Min, N, _Max) when N==1024 -> dh_group1();
-dh_gex_group(_Min, N, _Max) when N==2048 -> dh_group14();
-dh_gex_group(_Min, N, _Max) when N==3072 -> dh_group15();
-dh_gex_group(_Min, N, _Max) when N==4096 -> dh_group16();
-%%% If not an exact match, select the largest possible:
-dh_gex_group(Min, _N, Max) when Min=<4096, 4096=<Max -> dh_group16();
-dh_gex_group(Min, _N, Max) when Min=<3072, 3072=<Max -> dh_group15();
-dh_gex_group(Min, _N, Max) when Min=<2048, 2048=<Max -> dh_group14();
-dh_gex_group(Min, _N, Max) when Min=<1024, 1024=<Max -> dh_group1().
+dh_gex_default_groups() ->
+ [{1024, dh_group1() },
+ {2048, dh_group14()},
+ {3072, dh_group15()},
+ {4096, dh_group16()}].
+
+
+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
+ end.
dh_gen_key(G, P, _) ->