aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorHans Nilsson <[email protected]>2015-08-06 11:55:14 +0200
committerHans Nilsson <[email protected]>2015-08-06 11:55:14 +0200
commitfc2e067c61cf2afbf298f05c28a8c6112daa9d0f (patch)
treed1ec96947db4f1b94074e6778e7ff1f5376b58c8 /lib
parent7716e9b630b96d7f3b135c88a5be4b54967e8181 (diff)
parent277bbb049662cb0b15489097d066bdb09366e538 (diff)
downloadotp-fc2e067c61cf2afbf298f05c28a8c6112daa9d0f.tar.gz
otp-fc2e067c61cf2afbf298f05c28a8c6112daa9d0f.tar.bz2
otp-fc2e067c61cf2afbf298f05c28a8c6112daa9d0f.zip
Merge branch 'hans/ssh/diffie-hellman-group14-sha1/OTP-12671' into maint
* hans/ssh/diffie-hellman-group14-sha1/OTP-12671: ssh: diffie-hellman-group14-sha1
Diffstat (limited to 'lib')
-rw-r--r--lib/ssh/src/ssh_transport.erl32
-rw-r--r--lib/ssh/test/ssh_basic_SUITE.erl107
-rw-r--r--lib/ssh/test/ssh_to_openssh_SUITE.erl116
3 files changed, 200 insertions, 55 deletions
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 9be8e45aed..69ba797faf 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -79,9 +79,10 @@ supported_algorithms() -> [{K,supported_algorithms(K)} || K <- algo_classes()].
supported_algorithms(kex) ->
select_crypto_supported(
- [{'diffie-hellman-group1-sha1', [{hashs,sha}]},
- {'diffie-hellman-group-exchange-sha1', [{hashs,sha}]},
- {'diffie-hellman-group-exchange-sha256', [{hashs,sha256}]}
+ [{'diffie-hellman-group14-sha1', [{hashs,sha}]},
+ {'diffie-hellman-group1-sha1', [{hashs,sha}]},
+ {'diffie-hellman-group-exchange-sha256', [{hashs,sha256}]},
+ {'diffie-hellman-group-exchange-sha1', [{hashs,sha}]}
]);
supported_algorithms(public_key) ->
ssh_auth:default_public_key_algorithms();
@@ -297,6 +298,7 @@ verify_algorithm(#alg{compress = undefined}) -> false;
verify_algorithm(#alg{decompress = undefined}) -> false;
verify_algorithm(#alg{kex = 'diffie-hellman-group1-sha1'}) -> true;
+verify_algorithm(#alg{kex = 'diffie-hellman-group14-sha1'}) -> true;
verify_algorithm(#alg{kex = 'diffie-hellman-group-exchange-sha1'}) -> true;
verify_algorithm(#alg{kex = 'diffie-hellman-group-exchange-sha256'}) -> true;
verify_algorithm(_) -> false.
@@ -305,8 +307,9 @@ verify_algorithm(_) -> false.
%%%
%%% Key exchange initialization
%%%
-key_exchange_first_msg('diffie-hellman-group1-sha1', Ssh0) ->
- {G, P} = dh_group1(),
+key_exchange_first_msg(Kex, Ssh0) when Kex == 'diffie-hellman-group1-sha1' ;
+ Kex == 'diffie-hellman-group14-sha1' ->
+ {G, P} = dh_group(Kex),
{Private, Public} = dh_gen_key(G, P, 1024),
%% Public = G^Private mod P (def)
{SshPacket, Ssh1} = ssh_packet(#ssh_msg_kexdh_init{e = Public}, Ssh0),
@@ -329,10 +332,12 @@ key_exchange_first_msg(Kex, Ssh0) when Kex == 'diffie-hellman-group-exchange-sha
%%%----------------------------------------------------------------
%%%
%%% diffie-hellman-group1-sha1
+%%% diffie-hellman-group14-sha1
%%%
-handle_kexdh_init(#ssh_msg_kexdh_init{e = E}, Ssh0) ->
+handle_kexdh_init(#ssh_msg_kexdh_init{e = E},
+ Ssh0 = #ssh{algorithms = #alg{kex=Kex}}) ->
%% server
- {G, P} = dh_group1(),
+ {G, P} = dh_group(Kex),
if
1=<E, E=<(P-1) ->
{Private, Public} = dh_gen_key(G, P, 1024),
@@ -817,6 +822,7 @@ verify(PlainText, Hash, Sig, Key) ->
%% key exchange
%%
%% diffie-hellman-group1-sha1 REQUIRED
+%% diffie-hellman-group14-sha1 REQUIRED
%%
%%
@@ -1131,6 +1137,8 @@ hash(SSH, Char, Bits) ->
case SSH#ssh.kex of
'diffie-hellman-group1-sha1' ->
fun(Data) -> crypto:hash(sha, Data) end;
+ 'diffie-hellman-group14-sha1' ->
+ fun(Data) -> crypto:hash(sha, Data) end;
'diffie-hellman-group-exchange-sha1' ->
fun(Data) -> crypto:hash(sha, Data) end;
'diffie-hellman-group-exchange-sha256' ->
@@ -1229,6 +1237,10 @@ 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();
@@ -1250,7 +1262,11 @@ dh_compute_key(G, P, OthersPublic, MyPrivate) ->
crypto:compute_key(dh, OthersPublic, MyPrivate, [P,G])
).
-
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% Other utils
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
trim_tail(Str) ->
lists:reverse(trim_head(lists:reverse(Str))).
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index c71463db30..39ea2c9609 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -42,7 +42,7 @@ suite() ->
all() ->
[app_test,
appup_test,
- {group, 'diffie-hellman-group-exchange-sha1'},
+ {group, key_exchange},
{group, dsa_key},
{group, rsa_key},
{group, dsa_pass_key},
@@ -93,8 +93,11 @@ groups() ->
max_sessions_sftp_start_channel_parallel,
max_sessions_sftp_start_channel_sequential
]},
- {'diffie-hellman-group-exchange-sha1', [], ['diffie-hellman-group-exchange-sha1'
- ]},
+ {key_exchange, [], ['diffie-hellman-group-exchange-sha1',
+ 'diffie-hellman-group-exchange-sha256',
+ 'diffie-hellman-group1-sha1',
+ 'diffie-hellman-group14-sha1'
+ ]},
{dir_options, [], [user_dir_option,
system_dir_option]}
].
@@ -149,17 +152,11 @@ init_per_group(internal_error, Config) ->
ssh_test_lib:setup_dsa(DataDir, PrivDir),
file:delete(filename:join(PrivDir, "system/ssh_host_dsa_key")),
Config;
-init_per_group('diffie-hellman-group-exchange-sha1', Config) ->
- case lists:member('diffie-hellman-group-exchange-sha1',
- ssh_transport:supported_algorithms(kex)) of
- true ->
- DataDir = ?config(data_dir, Config),
- PrivDir = ?config(priv_dir, Config),
- ssh_test_lib:setup_rsa(DataDir, PrivDir),
- Config;
- false ->
- {skip,"diffie-hellman-group-exchange-sha1 is not supported"}
- end;
+init_per_group(key_exchange, Config) ->
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ ssh_test_lib:setup_rsa(DataDir, PrivDir),
+ Config;
init_per_group(dir_options, Config) ->
PrivDir = ?config(priv_dir, Config),
%% Make unreadable dir:
@@ -207,6 +204,8 @@ init_per_group(_, Config) ->
end_per_group(hardening_tests, Config) ->
end_per_group(dsa_key, Config);
+end_per_group(key_exchange, Config) ->
+ end_per_group(rsa_key, Config);
end_per_group(dsa_key, Config) ->
PrivDir = ?config(priv_dir, Config),
ssh_test_lib:clean_dsa(PrivDir),
@@ -833,40 +832,56 @@ ssh_msg_debug_fun_option_client(Config) ->
%%--------------------------------------------------------------------
'diffie-hellman-group-exchange-sha1'(Config) ->
- process_flag(trap_exit, true),
- SystemDir = filename:join(?config(priv_dir, Config), system),
- UserDir = ?config(priv_dir, Config),
+ kextest('diffie-hellman-group-exchange-sha1',Config).
- {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
- {user_dir, UserDir},
- {user_passwords, [{"foo", "bar"}]},
- {preferred_algorithms,
- [{kex, ['diffie-hellman-group-exchange-sha1']}]},
- {failfun, fun ssh_test_lib:failfun/2}]),
-
- ConnectionRef =
- ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
- {user, "foo"},
- {password, "bar"},
- {user_dir, UserDir},
- {preferred_algorithms,
- [{kex, ['diffie-hellman-group-exchange-sha1']}]},
- {user_interaction, false}]),
- check(ConnectionRef, Pid).
+'diffie-hellman-group-exchange-sha256'(Config) ->
+ kextest('diffie-hellman-group-exchange-sha256',Config).
-check(ConnectionRef, Pid) ->
- {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
- success = ssh_connection:exec(ConnectionRef, ChannelId,
- "1+1.", infinity),
- Data = {ssh_cm, ConnectionRef, {data, ChannelId, 0, <<"2\n">>}},
- case ssh_test_lib:receive_exec_result(Data) of
- expected ->
- ok;
- Other ->
- ct:fail(Other)
- end,
- ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId),
- ssh:stop_daemon(Pid).
+'diffie-hellman-group1-sha1'(Config) ->
+ kextest('diffie-hellman-group1-sha1',Config).
+
+'diffie-hellman-group14-sha1'(Config) ->
+ kextest('diffie-hellman-group14-sha1',Config).
+
+
+kextest(Kex, Config) ->
+ case lists:member(Kex, ssh_transport:supported_algorithms(kex)) of
+ true ->
+ process_flag(trap_exit, true),
+ SystemDir = filename:join(?config(priv_dir, Config), system),
+ UserDir = ?config(priv_dir, Config),
+
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {user_passwords, [{"foo", "bar"}]},
+ {preferred_algorithms,
+ [{kex, [Kex]}]},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+
+ ConnectionRef =
+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user, "foo"},
+ {password, "bar"},
+ {user_dir, UserDir},
+ {preferred_algorithms,
+ [{kex, [Kex]}]},
+ {user_interaction, false}]),
+
+ {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
+ success = ssh_connection:exec(ConnectionRef, ChannelId,
+ "1+1.", infinity),
+ Data = {ssh_cm, ConnectionRef, {data, ChannelId, 0, <<"2\n">>}},
+ case ssh_test_lib:receive_exec_result(Data) of
+ expected ->
+ ok;
+ Other ->
+ ct:fail(Other)
+ end,
+ ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId),
+ ssh:stop_daemon(Pid);
+ false ->
+ {skip, lists:concat([Kex, " is not supported"])}
+ end.
%%--------------------------------------------------------------------
connectfun_disconnectfun_server(Config) ->
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index b7283202a3..fb1c6a1b61 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -51,13 +51,15 @@ groups() ->
erlang_client_openssh_server_publickey_rsa,
erlang_client_openssh_server_publickey_dsa,
erlang_client_openssh_server_password,
+ erlang_client_openssh_server_kexs,
erlang_client_openssh_server_nonexistent_subsystem
]},
{erlang_server, [], [erlang_server_openssh_client_exec,
erlang_server_openssh_client_exec_compressed,
erlang_server_openssh_client_pulic_key_dsa,
erlang_server_openssh_client_cipher_suites,
- erlang_server_openssh_client_macs]}
+ erlang_server_openssh_client_macs,
+ erlang_server_openssh_client_kexs]}
].
init_per_suite(Config) ->
@@ -99,6 +101,12 @@ init_per_testcase(erlang_server_openssh_client_cipher_suites, Config) ->
init_per_testcase(erlang_server_openssh_client_macs, Config) ->
check_ssh_client_support(Config);
+init_per_testcase(erlang_server_openssh_client_kexs, Config) ->
+ check_ssh_client_support(Config);
+
+init_per_testcase(erlang_client_openssh_server_kexs, Config) ->
+ check_ssh_client_support(Config);
+
init_per_testcase(_TestCase, Config) ->
ssh:start(),
Config.
@@ -189,6 +197,48 @@ erlang_client_openssh_server_exec_compressed(Config) when is_list(Config) ->
end.
%%--------------------------------------------------------------------
+erlang_client_openssh_server_kexs() ->
+ [{doc, "Test that we can connect with different KEXs."}].
+
+erlang_client_openssh_server_kexs(Config) when is_list(Config) ->
+ Success =
+ lists:foldl(
+ fun(Kex, Acc) ->
+ ConnectionRef =
+ ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true},
+ {user_interaction, false},
+ {preferred_algorithms,
+ [{kex,[Kex]}]}]),
+
+ {ok, ChannelId} =
+ ssh_connection:session_channel(ConnectionRef, infinity),
+ success =
+ ssh_connection:exec(ConnectionRef, ChannelId,
+ "echo testing", infinity),
+
+ ExpectedData = {ssh_cm, ConnectionRef, {data, ChannelId, 0, <<"testing\n">>}},
+ case ssh_test_lib:receive_exec_result(ExpectedData) of
+ expected ->
+ ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId),
+ Acc;
+ {unexpected_msg,{ssh_cm, ConnectionRef,
+ {exit_status, ChannelId, 0}} = ExitStatus} ->
+ ct:pal("0: Collected data ~p", [ExitStatus]),
+ ssh_test_lib:receive_exec_result(ExpectedData, ConnectionRef, ChannelId),
+ Acc;
+ Other ->
+ ct:pal("~p failed: ~p",[Kex,Other]),
+ false
+ end
+ end, true, ssh_transport:supported_algorithms(kex)),
+ case Success of
+ true ->
+ ok;
+ false ->
+ {fail, "Kex failed for one or more algos"}
+ end.
+
+%%--------------------------------------------------------------------
erlang_server_openssh_client_exec() ->
[{doc, "Test that exec command works."}].
@@ -322,6 +372,70 @@ erlang_server_openssh_client_macs(Config) when is_list(Config) ->
ssh:stop_daemon(Pid).
%%--------------------------------------------------------------------
+erlang_server_openssh_client_kexs() ->
+ [{doc, "Test that we can connect with different KEXs."}].
+
+erlang_server_openssh_client_kexs(Config) when is_list(Config) ->
+ SystemDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ KnownHosts = filename:join(PrivDir, "known_hosts"),
+
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {failfun, fun ssh_test_lib:failfun/2},
+ {preferred_algorithms,
+ [{kex,ssh_transport:supported_algorithms(kex)}]}
+ ]),
+ ct:sleep(500),
+
+ ErlKexs = lists:map(fun erlang:atom_to_list/1,
+ ssh_transport:supported_algorithms(kex)),
+ OpenSshKexs = string:tokens(os:cmd("ssh -Q kex"), "\n"),
+
+ Kexs = [{OpenSshKex,lists:member(OpenSshKex,ErlKexs)}
+ || OpenSshKex <- OpenSshKexs],
+
+ Success =
+ lists:foldl(
+ fun({Kex, Expect}, Acc) ->
+ Cmd = "ssh -p " ++ integer_to_list(Port) ++
+ " -o UserKnownHostsFile=" ++ KnownHosts ++ " " ++ Host ++ " " ++
+ " -o KexAlgorithms=" ++ Kex ++ " 1+1.",
+
+ ct:pal("Cmd: ~p~n", [Cmd]),
+
+ SshPort = open_port({spawn, Cmd}, [binary, stderr_to_stdout]),
+
+ case Expect of
+ true ->
+ receive
+ {SshPort,{data, <<"2\n">>}} ->
+ Acc
+ after ?TIMEOUT ->
+ ct:pal("Did not receive answer for ~p",[Kex]),
+ false
+ end;
+ false ->
+ receive
+ {SshPort,{data, <<"Unable to negotiate a key exchange method", _/binary>>}} ->
+ Acc
+ after ?TIMEOUT ->
+ ct:pal("Did not receive no matching kex message for ~p",[Kex]),
+ false
+ end
+ end
+ end, true, Kexs),
+
+ ssh:stop_daemon(Pid),
+
+ case Success of
+ true ->
+ ok;
+ false ->
+ {fail, "Kex failed for one or more algos"}
+ end.
+
+
+%%--------------------------------------------------------------------
erlang_server_openssh_client_exec_compressed() ->
[{doc, "Test that exec command works."}].