aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssh
diff options
context:
space:
mode:
authorHans Nilsson <[email protected]>2015-06-30 15:40:16 +0200
committerHans Nilsson <[email protected]>2015-07-02 12:18:28 +0200
commita9bedfb5b9a469642c0e8bf315f41a2505444cd6 (patch)
tree52027f492745d79e1eb717e406e51766289c5ba7 /lib/ssh
parent941ddfbeab3357177ce6eac709456fd881ac2429 (diff)
downloadotp-a9bedfb5b9a469642c0e8bf315f41a2505444cd6.tar.gz
otp-a9bedfb5b9a469642c0e8bf315f41a2505444cd6.tar.bz2
otp-a9bedfb5b9a469642c0e8bf315f41a2505444cd6.zip
ssh: testcases for no common algorithms in key exchange
Diffstat (limited to 'lib/ssh')
-rw-r--r--lib/ssh/src/ssh_transport.erl33
-rw-r--r--lib/ssh/test/ssh_basic_SUITE.erl2
-rw-r--r--lib/ssh/test/ssh_protocol_SUITE.erl93
-rw-r--r--lib/ssh/test/ssh_trpt_test_lib.erl4
4 files changed, 120 insertions, 12 deletions
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index f4e6a23a1e..2e7391e1f8 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -246,26 +246,41 @@ handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own,
Ssh0#ssh{algorithms = Algoritms});
_ ->
%% TODO: Correct code?
- throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
+ throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
description = "Selection of key exchange"
" algorithm failed",
- language = "en"})
+ language = ""})
end;
handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own,
#ssh{role = server} = Ssh) ->
{ok, Algoritms} = select_algorithm(server, CounterPart, Own),
- {ok, Ssh#ssh{algorithms = Algoritms}}.
+ case verify_algorithm(Algoritms) of
+ true ->
+ {ok, Ssh#ssh{algorithms = Algoritms}};
+ _ ->
+ throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ description = "Selection of key exchange"
+ " algorithm failed",
+ language = ""})
+ end.
%% TODO: diffie-hellman-group14-sha1 should also be supported.
%% Maybe check more things ...
-verify_algorithm(#alg{kex = 'diffie-hellman-group1-sha1'}) ->
- true;
-verify_algorithm(#alg{kex = 'diffie-hellman-group-exchange-sha1'}) ->
- true;
-verify_algorithm(_) ->
- false.
+
+verify_algorithm(#alg{kex = undefined}) -> false;
+verify_algorithm(#alg{hkey = undefined}) -> false;
+verify_algorithm(#alg{send_mac = undefined}) -> false;
+verify_algorithm(#alg{recv_mac = undefined}) -> false;
+verify_algorithm(#alg{encrypt = undefined}) -> false;
+verify_algorithm(#alg{decrypt = undefined}) -> false;
+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-group-exchange-sha1'}) -> true;
+verify_algorithm(_) -> false.
key_exchange_first_msg('diffie-hellman-group1-sha1', Ssh0) ->
{G, P} = dh_group1(),
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 9ff3eb8d0b..bf9fe54c57 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -1838,6 +1838,8 @@ check_error("Invalid state") ->
ok;
check_error("Connection closed") ->
ok;
+check_error("Selection of key exchange algorithm failed") ->
+ ok;
check_error(Error) ->
ct:fail(Error).
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index 3fb2840a19..58c8306c31 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -45,7 +45,8 @@ suite() ->
[{ct_hooks,[ts_install_cth]}].
all() ->
- [{group,tool_tests}
+ [{group,tool_tests},
+ {group,kex}
].
groups() ->
@@ -53,7 +54,10 @@ groups() ->
lib_works_as_server,
lib_match,
lib_no_match
- ]}
+ ]},
+ {kex, [], [no_common_alg_server_disconnects,
+ no_common_alg_client_disconnects
+ ]}
].
@@ -203,6 +207,91 @@ lib_no_match(_Config) ->
{error, {_Op,{expected,a,b},_State}} -> ok
end.
+%%--------------------------------------------------------------------
+%%% Algo negotiation fail. This should result in a ssh_msg_disconnect
+%%% being sent from the server.
+no_common_alg_server_disconnects(Config) ->
+ {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,[{public_key,['ssh-dss']}]}
+ ]},
+ receive_hello,
+ {send, hello},
+ {match, #ssh_msg_kexinit{_='_'}, receive_msg},
+ {send, ssh_msg_kexinit},
+ {match,
+ #ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, _='_'},
+ receive_msg}
+ ]
+ ).
+
+%%--------------------------------------------------------------------
+%%% Algo negotiation fail. This should result in a ssh_msg_disconnect
+%%% being sent from the client.
+no_common_alg_client_disconnects(Config) ->
+ %% Create a listening socket as server socket:
+ {ok,InitialState} = ssh_trpt_test_lib:exec(listen),
+ HostPort = ssh_trpt_test_lib:server_host_port(InitialState),
+ Parent = self(),
+
+ %% Start a process handling one connection on the server side:
+ Pid =
+ spawn_link(
+ fun() ->
+ Parent !
+ {result,self(),
+ ssh_trpt_test_lib:exec(
+ [{set_options, [print_ops, print_messages]},
+ {accept, [{system_dir, system_dir(Config)},
+ {user_dir, user_dir(Config)}]},
+ receive_hello,
+ {send, hello},
+
+ {match, #ssh_msg_kexinit{_='_'}, receive_msg},
+ {send, #ssh_msg_kexinit{
+ cookie = 247381486335508958743193106082599558706,
+ kex_algorithms = ["diffie-hellman-group1-sha1"],
+ server_host_key_algorithms = ["some-unknown"],
+ encryption_algorithms_client_to_server = ["aes128-ctr"],
+ encryption_algorithms_server_to_client = ["aes128-ctr"],
+ mac_algorithms_client_to_server = ["hmac-sha2-256"],
+ mac_algorithms_server_to_client = ["hmac-sha2-256"],
+ compression_algorithms_client_to_server = ["none"],
+ compression_algorithms_server_to_client = ["none"],
+ languages_client_to_server = [],
+ languages_server_to_client = [],
+ first_kex_packet_follows = false,
+ reserved = 0
+ }},
+
+ {match,
+ #ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, _='_'},
+ receive_msg}
+ ],
+ InitialState)
+ }
+ end),
+
+ %% and finally connect to it with a regular Erlang SSH client:
+ Result = std_connect(HostPort, Config, [{preferred_algorithms,[{public_key,['ssh-dss']}]}]),
+ ct:log("Result of connect is ~p",[Result]),
+
+ receive
+ {result,Pid,{ok,_}} ->
+ ok;
+ {result,Pid,{error,{Op,ExecResult,S}}} ->
+ ct:pal("ERROR!~nOp = ~p~nExecResult = ~p~nState =~n~s",
+ [Op,ExecResult,ssh_trpt_test_lib:format_msg(S)]),
+ {fail, ExecResult};
+ X -> ct:fail(X)
+ end.
+
%%%================================================================
%%%==== Internal functions ========================================
%%%================================================================
diff --git a/lib/ssh/test/ssh_trpt_test_lib.erl b/lib/ssh/test/ssh_trpt_test_lib.erl
index 8623020a31..a604fca1ac 100644
--- a/lib/ssh/test/ssh_trpt_test_lib.erl
+++ b/lib/ssh/test/ssh_trpt_test_lib.erl
@@ -200,7 +200,9 @@ op_val(E, S0) ->
{'EXIT',{function_clause,[{ssh_trpt_test_lib,op,[E,S0],_}|_]}} ->
{instantiate(E,S0), S0};
S=#s{} ->
- {S#s.return_value, S}
+ {S#s.return_value, S};
+ F={fail,receive_timeout,_St} ->
+ throw(F)
end.