aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssh/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssh/src')
-rw-r--r--lib/ssh/src/Makefile75
-rw-r--r--lib/ssh/src/ssh.erl5
-rw-r--r--lib/ssh/src/ssh.hrl1
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl54
-rw-r--r--lib/ssh/src/ssh_message.erl49
-rw-r--r--lib/ssh/src/ssh_transport.erl231
-rw-r--r--lib/ssh/src/ssh_transport.hrl80
7 files changed, 414 insertions, 81 deletions
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile
index 98fb90d7c4..b44c8eef35 100644
--- a/lib/ssh/src/Makefile
+++ b/lib/ssh/src/Makefile
@@ -144,3 +144,78 @@ release_spec: opt
release_docs_spec:
+
+deps:
+ erlc -M $(ERL_FILES) \
+ | sed 's@$(ERL_TOP)/lib@../..@g' \
+ | sed 's/\.$(EMULATOR)/\.$$\(EMULATOR\)/' \
+ | sed 's@^ssh_@$$(EBIN)/ssh_@'
+
+ssh.$(EMULATOR): ssh.erl ssh.hrl ssh_connect.hrl \
+ ../../public_key/include/public_key.hrl \
+ ../../public_key/include/OTP-PUB-KEY.hrl \
+ ../../public_key/include/PKCS-FRAME.hrl \
+ ../../kernel/include/file.hrl
+$(EBIN)/ssh_sup.$(EMULATOR): ssh_sup.erl
+sshc_sup.$(EMULATOR): sshc_sup.erl
+sshd_sup.$(EMULATOR): sshd_sup.erl ssh.hrl
+$(EBIN)/ssh_connection_sup.$(EMULATOR): ssh_connection_sup.erl
+$(EBIN)/ssh_connection.$(EMULATOR): ssh_connection.erl ssh.hrl ssh_connect.hrl \
+ ssh_transport.hrl
+$(EBIN)/ssh_connection_handler.$(EMULATOR): ssh_connection_handler.erl ssh.hrl \
+ ssh_transport.hrl ssh_auth.hrl ssh_connect.hrl
+$(EBIN)/ssh_shell.$(EMULATOR): ssh_shell.erl ssh_connect.hrl
+$(EBIN)/ssh_system_sup.$(EMULATOR): ssh_system_sup.erl ssh.hrl
+$(EBIN)/ssh_subsystem_sup.$(EMULATOR): ssh_subsystem_sup.erl
+$(EBIN)/ssh_channel_sup.$(EMULATOR): ssh_channel_sup.erl
+$(EBIN)/ssh_acceptor_sup.$(EMULATOR): ssh_acceptor_sup.erl ssh.hrl
+$(EBIN)/ssh_acceptor.$(EMULATOR): ssh_acceptor.erl ssh.hrl
+$(EBIN)/ssh_app.$(EMULATOR): ssh_app.erl
+$(EBIN)/ssh_auth.$(EMULATOR): ssh_auth.erl \
+ ../../public_key/include/public_key.hrl \
+ ../../public_key/include/OTP-PUB-KEY.hrl \
+ ../../public_key/include/PKCS-FRAME.hrl \
+ ssh.hrl ssh_auth.hrl ssh_transport.hrl
+$(EBIN)/ssh_bits.$(EMULATOR): ssh_bits.erl ssh.hrl
+$(EBIN)/ssh_cli.$(EMULATOR): ssh_cli.erl ssh.hrl ssh_connect.hrl
+$(EBIN)/ssh_file.$(EMULATOR): ssh_file.erl \
+ ../../public_key/include/public_key.hrl \
+ ../../public_key/include/OTP-PUB-KEY.hrl \
+ ../../public_key/include/PKCS-FRAME.hrl \
+ ../../kernel/include/file.hrl ssh.hrl
+$(EBIN)/ssh_io.$(EMULATOR): ssh_io.erl ssh.hrl
+$(EBIN)/ssh_info.$(EMULATOR): ssh_info.erl
+$(EBIN)/ssh_message.$(EMULATOR): ssh_message.erl \
+ ../../public_key/include/public_key.hrl \
+ ../../public_key/include/OTP-PUB-KEY.hrl \
+ ../../public_key/include/PKCS-FRAME.hrl \
+ ssh.hrl ssh_connect.hrl ssh_auth.hrl ssh_transport.hrl
+$(EBIN)/ssh_no_io.$(EMULATOR): ssh_no_io.erl ssh_transport.hrl
+$(EBIN)/ssh_sftp.$(EMULATOR): ssh_sftp.erl \
+ ../../kernel/include/file.hrl ssh.hrl \
+ ssh_xfer.hrl
+$(EBIN)/ssh_sftpd.$(EMULATOR): ssh_sftpd.erl \
+ ../../kernel/include/file.hrl ssh.hrl \
+ ssh_xfer.hrl
+$(EBIN)/ssh_sftpd_file.$(EMULATOR): ssh_sftpd_file.erl
+$(EBIN)/ssh_transport.$(EMULATOR): ssh_transport.erl \
+ ../../public_key/include/public_key.hrl \
+ ../../public_key/include/OTP-PUB-KEY.hrl \
+ ../../public_key/include/PKCS-FRAME.hrl \
+ ../../kernel/include/inet.hrl \
+ ssh_transport.hrl ssh.hrl
+$(EBIN)/ssh_xfer.$(EMULATOR): ssh_xfer.erl ssh.hrl ssh_xfer.hrl
+$(EBIN)/ssh_sftpd_file_api.$(EMULATOR): ssh_sftpd_file_api.erl
+$(EBIN)/ssh_channel.$(EMULATOR): ssh_channel.erl ssh_connect.hrl
+$(EBIN)/ssh_daemon_channel.$(EMULATOR): ssh_daemon_channel.erl
+$(EBIN)/ssh_client_key_api.$(EMULATOR): ssh_client_key_api.erl \
+ ../../public_key/include/public_key.hrl \
+ ../../public_key/include/OTP-PUB-KEY.hrl \
+ ../../public_key/include/PKCS-FRAME.hrl \
+ ssh.hrl
+$(EBIN)/ssh_server_key_api.$(EMULATOR): ssh_server_key_api.erl \
+ ../../public_key/include/public_key.hrl \
+ ../../public_key/include/OTP-PUB-KEY.hrl \
+ ../../public_key/include/PKCS-FRAME.hrl \
+ ssh.hrl
+
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 5b2e0a988c..132de71aed 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -397,6 +397,8 @@ handle_option([{id_string, _ID} = Opt|Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([{profile, _ID} = Opt|Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
+handle_option([{max_random_length_padding, _Bool} = Opt|Rest], SocketOptions, SshOptions) ->
+ handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, [handle_inet_option(Opt) | SocketOptions], SshOptions).
@@ -515,6 +517,9 @@ handle_ssh_option({id_string, random}) ->
{id_string, {random,2,5}}; %% 2 - 5 random characters
handle_ssh_option({id_string, ID} = Opt) when is_list(ID) ->
Opt;
+handle_ssh_option({max_random_length_padding, Value} = Opt) when is_integer(Value),
+ Value =< 255 ->
+ Opt;
handle_ssh_option({profile, Value} = Opt) when is_atom(Value) ->
Opt;
handle_ssh_option(Opt) ->
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index 8df5ee820c..462c98f503 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -124,6 +124,7 @@
recv_sequence = 0,
keyex_key,
keyex_info,
+ random_length_padding = 255, % From RFC 4253 section 6.
%% User auth
user,
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index c059834b27..fcd66b80c0 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -429,7 +429,21 @@ 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),
send_msg(KexGexInit, State),
- {next_state, key_exchange_dh_gex_reply, next_packet(State#state{ssh_params = Ssh})}.
+ {next_state, key_exchange_dh_gex_reply, next_packet(State#state{ssh_params = Ssh})};
+
+key_exchange(#ssh_msg_kex_ecdh_init{} = Msg,
+ #state{ssh_params = #ssh{role = server} = Ssh0} = State) ->
+ {ok, KexEcdhReply, Ssh1} = ssh_transport:handle_kex_ecdh_init(Msg, Ssh0),
+ send_msg(KexEcdhReply, State),
+ {ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
+ send_msg(NewKeys, State),
+ {next_state, new_keys, next_packet(State#state{ssh_params = Ssh})};
+
+key_exchange(#ssh_msg_kex_ecdh_reply{} = Msg,
+ #state{ssh_params = #ssh{role = client} = Ssh0} = State) ->
+ {ok, NewKeys, Ssh} = ssh_transport:handle_kex_ecdh_reply(Msg, Ssh0),
+ send_msg(NewKeys, State),
+ {next_state, new_keys, next_packet(State#state{ssh_params = Ssh})}.
%%--------------------------------------------------------------------
-spec key_exchange_dh_gex_init(#ssh_msg_kex_dh_gex_init{}, #state{}) -> gen_fsm_state_return().
@@ -1187,7 +1201,10 @@ init_ssh(client = Role, Vsn, Version, Options, Socket) ->
opts = Options,
userauth_supported_methods = AuthMethods,
peer = {PeerName, PeerAddr},
- available_host_keys = supported_host_keys(Role, KeyCb, Options)
+ available_host_keys = supported_host_keys(Role, KeyCb, Options),
+ random_length_padding = proplists:get_value(max_random_length_padding,
+ Options,
+ (#ssh{})#ssh.random_length_padding)
};
init_ssh(server = Role, Vsn, Version, Options, Socket) ->
@@ -1207,7 +1224,10 @@ init_ssh(server = Role, Vsn, Version, Options, Socket) ->
userauth_methods = AuthMethodsAsList,
kb_tries_left = 3,
peer = {undefined, PeerAddr},
- available_host_keys = supported_host_keys(Role, KeyCb, Options)
+ available_host_keys = supported_host_keys(Role, KeyCb, Options),
+ random_length_padding = proplists:get_value(max_random_length_padding,
+ Options,
+ (#ssh{})#ssh.random_length_padding)
}.
supported_host_keys(client, _, Options) ->
@@ -1301,7 +1321,7 @@ event(Event, StateName, State) ->
handle_disconnect(DisconnectMsg, State);
throw:{ErrorToDisplay, #ssh_msg_disconnect{} = DisconnectMsg} ->
handle_disconnect(DisconnectMsg, State, ErrorToDisplay);
- _:_ ->
+ _C:_Error ->
handle_disconnect(#ssh_msg_disconnect{code = error_code(StateName),
description = "Invalid state",
language = "en"}, State)
@@ -1370,9 +1390,10 @@ generate_event(<<?BYTE(Byte), _/binary>> = Msg, StateName,
{stop, {shutdown, Error}, State#state{connection_state = Connection}}
end;
+
generate_event(Msg, StateName, State0, EncData) ->
try
- Event = ssh_message:decode(Msg),
+ Event = ssh_message:decode(set_prefix_if_trouble(Msg,State0)),
State = generate_event_new_state(State0, EncData),
case Event of
#ssh_msg_kexinit{} ->
@@ -1382,7 +1403,7 @@ generate_event(Msg, StateName, State0, EncData) ->
event(Event, StateName, State)
end
catch
- _:_ ->
+ _C:_E ->
DisconnectMsg =
#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
description = "Encountered unexpected input",
@@ -1391,6 +1412,26 @@ generate_event(Msg, StateName, State0, EncData) ->
end.
+set_prefix_if_trouble(Msg = <<?BYTE(Op),_/binary>>, #state{ssh_params=SshParams})
+ when Op == 30;
+ Op == 31
+ ->
+ case catch atom_to_list(kex(SshParams)) of
+ "ecdh-sha2-" ++ _ ->
+ <<"ecdh",Msg/binary>>;
+ "diffie-hellman-group-exchange-" ++ _ ->
+ <<"dh_gex",Msg/binary>>;
+ "diffie-hellman-group" ++ _ ->
+ <<"dh",Msg/binary>>;
+ _ ->
+ Msg
+ end;
+set_prefix_if_trouble(Msg, _) ->
+ Msg.
+
+kex(#ssh{algorithms=#alg{kex=Kex}}) -> Kex;
+kex(_) -> undefined.
+
handle_request(ChannelPid, ChannelId, Type, Data, WantReply, From,
#state{connection_state =
@@ -1485,6 +1526,7 @@ new_channel_id(#state{connection_state = #connection{channel_id_seed = Id} =
= State) ->
{Id, State#state{connection_state =
Connection#connection{channel_id_seed = Id + 1}}}.
+
generate_event_new_state(#state{ssh_params =
#ssh{recv_sequence = SeqNum0}
= Ssh} = State, EncData) ->
diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl
index 7b786b8fff..cb1dcb67c5 100644
--- a/lib/ssh/src/ssh_message.erl
+++ b/lib/ssh/src/ssh_message.erl
@@ -259,6 +259,14 @@ encode(#ssh_msg_kex_dh_gex_reply{
EncSign = encode_sign(Key, Signature),
ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_REPLY, EncKey, F, EncSign], [byte, binary, mpint, binary]);
+encode(#ssh_msg_kex_ecdh_init{q_c = Q_c}) ->
+ ssh_bits:encode([?SSH_MSG_KEX_ECDH_INIT, Q_c], [byte, mpint]);
+
+encode(#ssh_msg_kex_ecdh_reply{public_host_key = Key, q_s = Q_s, h_sig = Sign}) ->
+ EncKey = encode_host_key(Key),
+ EncSign = encode_sign(Key, Sign),
+ ssh_bits:encode([?SSH_MSG_KEX_ECDH_REPLY, EncKey, Q_s, EncSign], [byte, binary, mpint, binary]);
+
encode(#ssh_msg_ignore{data = Data}) ->
ssh_bits:encode([?SSH_MSG_IGNORE, Data], [byte, string]);
@@ -422,30 +430,45 @@ decode(<<?BYTE(?SSH_MSG_USERAUTH_INFO_RESPONSE), ?UINT32(Num), Data/binary>>) ->
decode(<<?BYTE(?SSH_MSG_KEXINIT), Cookie:128, Data/binary>>) ->
decode_kex_init(Data, [Cookie, ssh_msg_kexinit], 10);
-decode(<<?BYTE(?SSH_MSG_KEXDH_INIT), ?UINT32(Len), E:Len/big-signed-integer-unit:8>>) ->
+decode(<<"dh",?BYTE(?SSH_MSG_KEXDH_INIT), ?UINT32(Len), E:Len/big-signed-integer-unit:8>>) ->
#ssh_msg_kexdh_init{e = E
};
+
+decode(<<"dh", ?BYTE(?SSH_MSG_KEXDH_REPLY),
+ ?UINT32(Len0), Key:Len0/binary,
+ ?UINT32(Len1), F:Len1/big-signed-integer-unit:8,
+ ?UINT32(Len2), Hashsign:Len2/binary>>) ->
+ #ssh_msg_kexdh_reply{
+ public_host_key = decode_host_key(Key),
+ f = F,
+ h_sig = decode_sign(Hashsign)
+ };
+
decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REQUEST), ?UINT32(Min), ?UINT32(N), ?UINT32(Max)>>) ->
#ssh_msg_kex_dh_gex_request{
min = Min,
n = N,
max = Max
};
-decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REQUEST_OLD), ?UINT32(N)>>) ->
+
+decode(<<"dh_gex",?BYTE(?SSH_MSG_KEX_DH_GEX_REQUEST_OLD), ?UINT32(N)>>) ->
#ssh_msg_kex_dh_gex_request_old{
n = N
};
-decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_GROUP),
+
+decode(<<"dh_gex",?BYTE(?SSH_MSG_KEX_DH_GEX_GROUP),
?UINT32(Len0), Prime:Len0/big-signed-integer-unit:8,
?UINT32(Len1), Generator:Len1/big-signed-integer-unit:8>>) ->
#ssh_msg_kex_dh_gex_group{
p = Prime,
g = Generator
};
+
decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_INIT), ?UINT32(Len), E:Len/big-signed-integer-unit:8>>) ->
#ssh_msg_kex_dh_gex_init{
e = E
};
+
decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REPLY),
?UINT32(Len0), Key:Len0/binary,
?UINT32(Len1), F:Len1/big-signed-integer-unit:8,
@@ -455,13 +478,21 @@ decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REPLY),
f = F,
h_sig = decode_sign(Hashsign)
};
-decode(<<?BYTE(?SSH_MSG_KEXDH_REPLY), ?UINT32(Len0), Key:Len0/binary,
- ?UINT32(Len1), F:Len1/big-signed-integer-unit:8,
- ?UINT32(Len2), Hashsign:Len2/binary>>) ->
- #ssh_msg_kexdh_reply{
+
+decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_INIT),
+ ?UINT32(Len0), Q_c:Len0/big-signed-integer-unit:8>>) ->
+ #ssh_msg_kex_ecdh_init{
+ q_c = Q_c
+ };
+
+decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_REPLY),
+ ?UINT32(Len1), Key:Len1/binary,
+ ?UINT32(Len2), Q_s:Len2/big-signed-integer-unit:8,
+ ?UINT32(Len3), Sig:Len3/binary>>) ->
+ #ssh_msg_kex_ecdh_reply{
public_host_key = decode_host_key(Key),
- f = F,
- h_sig = decode_sign(Hashsign)
+ q_s = Q_s,
+ h_sig = decode_sign(Sig)
};
decode(<<?SSH_MSG_SERVICE_REQUEST, ?UINT32(Len0), Service:Len0/binary>>) ->
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 38a0b7ec7c..2b6f0a3cdc 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -42,6 +42,8 @@
handle_kex_dh_gex_group/2, handle_kex_dh_gex_init/2, handle_kex_dh_gex_reply/2,
handle_new_keys/2, handle_kex_dh_gex_request/2,
handle_kexdh_reply/2,
+ handle_kex_ecdh_init/2,
+ handle_kex_ecdh_reply/2,
unpack/3, decompress/2, ssh_packet/2, pack/2, msg_data/1,
sign/3, verify/4]).
@@ -53,7 +55,7 @@
%%% user.
%%%
%%% A supported algorithm can be requested in the option 'preferred_algorithms',
-%%% but may give unexpected results because of being promoted to default.
+%%% but may give unexpected results before being promoted to default.
%%%
%%% This makes it possible to add experimental algorithms (in supported_algorithms)
%%% and test them without letting the default users know about them.
@@ -66,8 +68,6 @@ algo_classes() -> [kex, public_key, cipher, mac, compression].
default_algorithms(compression) ->
%% Do not announce '[email protected]' because there seem to be problems
supported_algorithms(compression, same(['[email protected]']));
-default_algorithms(kex) ->
- supported_algorithms(kex, []);
default_algorithms(Alg) ->
supported_algorithms(Alg).
@@ -76,10 +76,14 @@ supported_algorithms() -> [{K,supported_algorithms(K)} || K <- algo_classes()].
supported_algorithms(kex) ->
select_crypto_supported(
- [{'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}]}
+ [
+ {'ecdh-sha2-nistp256', [{public_keys,ecdh}, {ec_curve,secp256r1}, {hashs,sha256}]},
+ {'ecdh-sha2-nistp384', [{public_keys,ecdh}, {ec_curve,secp384r1}, {hashs,sha384}]},
+ {'ecdh-sha2-nistp521', [{public_keys,ecdh}, {ec_curve,secp521r1}, {hashs,sha512}]},
+ {'diffie-hellman-group14-sha1', [{public_keys,dh}, {hashs,sha}]},
+ {'diffie-hellman-group-exchange-sha256', [{public_keys,dh}, {hashs,sha256}]},
+ {'diffie-hellman-group-exchange-sha1', [{public_keys,dh}, {hashs,sha}]},
+ {'diffie-hellman-group1-sha1', [{public_keys,dh}, {hashs,sha}]}
]);
supported_algorithms(public_key) ->
ssh_auth:default_public_key_algorithms();
@@ -94,7 +98,8 @@ supported_algorithms(cipher) ->
supported_algorithms(mac) ->
same(
select_crypto_supported(
- [{'hmac-sha2-256', [{hashs,sha256}]},
+ [{'hmac-sha2-512', [{hashs,sha512}]},
+ {'hmac-sha2-256', [{hashs,sha256}]},
{'hmac-sha1', [{hashs,sha}]}
]
));
@@ -109,14 +114,19 @@ supported_algorithms(Key, BlackList) ->
supported_algorithms(Key) -- BlackList.
select_crypto_supported(L) ->
- Sup = crypto:supports(),
+ Sup = [{ec_curve,crypto_supported_curves()} | crypto:supports()],
[Name || {Name,CryptoRequires} <- L,
crypto_supported(CryptoRequires, Sup)].
+crypto_supported_curves() ->
+ try crypto:ec_curves()
+ catch _:_ -> []
+ end.
+
crypto_supported(Conditions, Supported) ->
- lists:all(fun({Tag,CryptoName}) ->
- lists:member(CryptoName, proplists:get_value(Tag,Supported,[]))
- end, Conditions).
+ lists:all( fun({Tag,CryptoName}) ->
+ lists:member(CryptoName, proplists:get_value(Tag,Supported,[]))
+ end, Conditions).
same(Algs) -> [{client2server,Algs}, {server2client,Algs}].
@@ -294,10 +304,7 @@ 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-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(#alg{kex = Kex}) -> lists:member(Kex, supported_algorithms(kex));
verify_algorithm(_) -> false.
%%%----------------------------------------------------------------
@@ -307,8 +314,7 @@ verify_algorithm(_) -> false.
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)
+ {Public, Private} = generate_key(dh, [P,G]),
{SshPacket, Ssh1} = ssh_packet(#ssh_msg_kexdh_init{e = Public}, Ssh0),
{ok, SshPacket,
Ssh1#ssh{keyex_key = {{Private, Public}, {G, P}}}};
@@ -324,7 +330,16 @@ key_exchange_first_msg(Kex, Ssh0) when Kex == 'diffie-hellman-group-exchange-sha
max = Max},
Ssh0),
{ok, SshPacket,
- Ssh1#ssh{keyex_info = {Min, Max, NBits}}}.
+ Ssh1#ssh{keyex_info = {Min, Max, NBits}}};
+
+key_exchange_first_msg(Kex, Ssh0) when Kex == 'ecdh-sha2-nistp256' ;
+ Kex == 'ecdh-sha2-nistp384' ;
+ Kex == 'ecdh-sha2-nistp521' ->
+ Curve = ecdh_curve(Kex),
+ {Public, Private} = generate_key(ecdh, Curve),
+ {SshPacket, Ssh1} = ssh_packet(#ssh_msg_kex_ecdh_init{q_c=Public}, Ssh0),
+ {ok, SshPacket,
+ Ssh1#ssh{keyex_key = {{Public,Private},Curve}}}.
%%%----------------------------------------------------------------
%%%
@@ -337,8 +352,8 @@ handle_kexdh_init(#ssh_msg_kexdh_init{e = E},
{G, P} = dh_group(Kex),
if
1=<E, E=<(P-1) ->
- {Private, Public} = dh_gen_key(G, P, 1024),
- K = dh_compute_key(G, P, E, Private),
+ {Public, Private} = generate_key(dh, [P,G]),
+ K = compute_key(dh, E, Private, [P,G]),
Key = get_host_key(Ssh0),
H = kex_h(Ssh0, Key, E, Public, K),
H_SIG = sign_host_key(Ssh0, Key, H),
@@ -367,7 +382,7 @@ handle_kexdh_reply(#ssh_msg_kexdh_reply{public_host_key = HostKey,
%% client
if
1=<F, F=<(P-1)->
- K = dh_compute_key(G, P, F, Private),
+ K = compute_key(dh, F, Private, [P,G]),
H = kex_h(Ssh0, HostKey, Public, F, K),
case verify_host_key(Ssh0, HostKey, H, H_SIG) of
@@ -405,7 +420,7 @@ handle_kex_dh_gex_request(#ssh_msg_kex_dh_gex_request{min = Min,
Ssh0=#ssh{opts=Opts}) when Min=<NBits, NBits=<Max ->
%% server
{G, P} = dh_gex_group(Min, NBits, Max, proplists:get_value(dh_gex_groups,Opts)),
- {Private, Public} = dh_gen_key(G, P, 1024),
+ {Public, Private} = generate_key(dh, [P,G]),
{SshPacket, Ssh} =
ssh_packet(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0),
{ok, SshPacket,
@@ -422,7 +437,7 @@ handle_kex_dh_gex_request(_, _) ->
handle_kex_dh_gex_group(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0) ->
%% client
- {Private, Public} = dh_gen_key(G, P, 1024),
+ {Public, Private} = generate_key(dh, [P,G]),
{SshPacket, Ssh1} =
ssh_packet(#ssh_msg_kex_dh_gex_init{e = Public}, Ssh0), % Pub = G^Priv mod P (def)
@@ -436,7 +451,7 @@ handle_kex_dh_gex_init(#ssh_msg_kex_dh_gex_init{e = E},
%% server
if
1=<E, E=<(P-1) ->
- K = dh_compute_key(G, P, E, Private),
+ K = compute_key(dh, E, Private, [P,G]),
if
1<K, K<(P-1) ->
HostKey = get_host_key(Ssh0),
@@ -476,7 +491,7 @@ handle_kex_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{public_host_key = HostKey,
%% client
if
1=<F, F=<(P-1)->
- K = dh_compute_key(G, P, F, Private),
+ K = compute_key(dh, F, Private, [P,G]),
if
1<K, K<(P-1) ->
H = kex_h(Ssh0, HostKey, Min, NBits, Max, P, G, Public, F, K),
@@ -513,12 +528,83 @@ handle_kex_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{public_host_key = HostKey,
end.
%%%----------------------------------------------------------------
+%%%
+%%% diffie-hellman-ecdh-sha2-*
+%%%
+handle_kex_ecdh_init(#ssh_msg_kex_ecdh_init{q_c = PeerPublic},
+ Ssh0 = #ssh{algorithms = #alg{kex=Kex}}) ->
+ %% at server
+ Curve = ecdh_curve(Kex),
+ case ecdh_validate_public_key(PeerPublic, Curve) of
+ true ->
+ {MyPublic, MyPrivate} = generate_key(ecdh, Curve),
+ K = compute_key(ecdh, PeerPublic, MyPrivate, Curve),
+ HostKey = get_host_key(Ssh0),
+ H = kex_h(Ssh0, Curve, HostKey, PeerPublic, MyPublic, K),
+ H_SIG = sign_host_key(Ssh0, HostKey, H),
+ {SshPacket, Ssh1} =
+ ssh_packet(#ssh_msg_kex_ecdh_reply{public_host_key = HostKey,
+ q_s = MyPublic,
+ h_sig = H_SIG},
+ Ssh0),
+ {ok, SshPacket, Ssh1#ssh{keyex_key = {{MyPublic,MyPrivate},Curve},
+ shared_secret = K,
+ exchanged_hash = H,
+ session_id = sid(Ssh1, H)}};
+
+ false ->
+ throw({{error,invalid_peer_public_key},
+ #ssh_msg_disconnect{
+ code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ description = "Peer ECDH public key is invalid",
+ language = ""}
+ })
+ end.
+
+handle_kex_ecdh_reply(#ssh_msg_kex_ecdh_reply{public_host_key = HostKey,
+ q_s = PeerPublic,
+ h_sig = H_SIG},
+ #ssh{keyex_key = {{MyPublic,MyPrivate}, Curve}} = Ssh0
+ ) ->
+ %% at client
+ case ecdh_validate_public_key(PeerPublic, Curve) of
+ true ->
+ K = compute_key(ecdh, PeerPublic, MyPrivate, Curve),
+ H = kex_h(Ssh0, Curve, HostKey, MyPublic, PeerPublic, K),
+ case verify_host_key(Ssh0, HostKey, H, H_SIG) of
+ ok ->
+ {SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
+ {ok, SshPacket, Ssh#ssh{shared_secret = K,
+ exchanged_hash = H,
+ session_id = sid(Ssh, H)}};
+ Error ->
+ throw({Error,
+ #ssh_msg_disconnect{
+ code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ description = "Key exchange failed",
+ language = ""}
+ })
+ end;
+
+ false ->
+ throw({{error,invalid_peer_public_key},
+ #ssh_msg_disconnect{
+ code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
+ description = "Peer ECDH public key is invalid",
+ language = ""}
+ })
+ end.
+
+
+ecdh_validate_public_key(_, _) -> true. % FIXME: Far too many false positives :)
+
+%%%----------------------------------------------------------------
handle_new_keys(#ssh_msg_newkeys{}, Ssh0) ->
try install_alg(Ssh0) of
#ssh{} = Ssh ->
{ok, Ssh}
catch
- error:_Error -> %% TODO: Throw earlier ....
+ _C:_Error -> %% TODO: Throw earlier ....
throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
description = "Install alg failed",
language = "en"})
@@ -546,10 +632,10 @@ get_host_key(SSH) ->
end.
sign_host_key(_Ssh, #'RSAPrivateKey'{} = Private, H) ->
- Hash = sha, %% Option ?!
+ Hash = sha,
_Signature = sign(H, Hash, Private);
sign_host_key(_Ssh, #'DSAPrivateKey'{} = Private, H) ->
- Hash = sha, %% Option ?!
+ Hash = sha,
_RawSignature = sign(H, Hash, Private).
verify_host_key(SSH, PublicKey, Digest, Signature) ->
@@ -715,14 +801,15 @@ alg_final(SSH0) ->
{ok,SSH6} = decompress_final(SSH5),
SSH6.
-select_all(CL, SL) when length(CL) + length(SL) < 50 ->
+select_all(CL, SL) when length(CL) + length(SL) < ?MAX_NUM_ALGORITHMS ->
A = CL -- SL, %% algortihms only used by client
%% algorithms used by client and server (client pref)
lists:map(fun(ALG) -> list_to_atom(ALG) end, (CL -- A));
-select_all(_CL, _SL) ->
+select_all(CL, SL) ->
+ Err = lists:concat(["Received too many algorithms (",length(CL),"+",length(SL)," >= ",?MAX_NUM_ALGORITHMS,")."]),
throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_PROTOCOL_ERROR,
- description = "Too many algorithms",
- language = "en"}).
+ description = Err,
+ language = ""}).
select([], []) ->
@@ -745,13 +832,20 @@ ssh_packet(Msg, Ssh) ->
pack(Data0, #ssh{encrypt_block_size = BlockSize,
send_sequence = SeqNum, send_mac = MacAlg,
- send_mac_key = MacKey}
+ send_mac_key = MacKey,
+ random_length_padding = RandomLengthPadding}
= Ssh0) when is_binary(Data0) ->
{Ssh1, Data} = compress(Ssh0, Data0),
PL = (BlockSize - ((4 + 1 + size(Data)) rem BlockSize)) rem BlockSize,
- PaddingLen = if PL < 4 -> PL + BlockSize;
- true -> PL
- end,
+ MinPaddingLen = if PL < 4 -> PL + BlockSize;
+ true -> PL
+ end,
+ PadBlockSize = max(BlockSize,4),
+ MaxExtraBlocks = (max(RandomLengthPadding,MinPaddingLen) - MinPaddingLen) div PadBlockSize,
+ ExtraPaddingLen = try crypto:rand_uniform(0,MaxExtraBlocks)*PadBlockSize
+ catch _:_ -> 0
+ end,
+ PaddingLen = MinPaddingLen + ExtraPaddingLen,
Padding = ssh_bits:random(PaddingLen),
PacketLen = 1 + PaddingLen + size(Data),
PacketData = <<?UINT32(PacketLen),?BYTE(PaddingLen),
@@ -1127,7 +1221,9 @@ mac('hmac-md5', Key, SeqNum, Data) ->
mac('hmac-md5-96', Key, SeqNum, Data) ->
crypto:hmac(md5, Key, [<<?UINT32(SeqNum)>>, Data], mac_digest_size('hmac-md5-96'));
mac('hmac-sha2-256', Key, SeqNum, Data) ->
- crypto:hmac(sha256, Key, [<<?UINT32(SeqNum)>>, Data]).
+ crypto:hmac(sha256, Key, [<<?UINT32(SeqNum)>>, Data]);
+mac('hmac-sha2-512', Key, SeqNum, Data) ->
+ crypto:hmac(sha512, Key, [<<?UINT32(SeqNum)>>, Data]).
%% return N hash bytes (HASH)
hash(SSH, Char, Bits) ->
@@ -1137,10 +1233,18 @@ hash(SSH, Char, Bits) ->
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' ->
fun(Data) -> crypto:hash(sha256, Data) end;
+
+ 'ecdh-sha2-nistp256' ->
+ fun(Data) -> crypto:hash(sha256,Data) end;
+ 'ecdh-sha2-nistp384' ->
+ fun(Data) -> crypto:hash(sha384,Data) end;
+ 'ecdh-sha2-nistp521' ->
+ fun(Data) -> crypto:hash(sha512,Data) end;
_ ->
exit({bad_algorithm,SSH#ssh.kex})
end,
@@ -1169,8 +1273,16 @@ kex_h(SSH, Key, E, F, K) ->
ssh_message:encode_host_key(Key), E,F,K],
[string,string,binary,binary,binary,
mpint,mpint,mpint]),
- crypto:hash(sha,L).
-
+ crypto:hash(sha((SSH#ssh.algorithms)#alg.kex), L).
+%% crypto:hash(sha,L).
+
+kex_h(SSH, Curve, Key, Q_c, Q_s, K) ->
+ L = ssh_bits:encode([SSH#ssh.c_version, SSH#ssh.s_version,
+ SSH#ssh.c_keyinit, SSH#ssh.s_keyinit,
+ ssh_message:encode_host_key(Key), Q_c, Q_s, K],
+ [string,string,binary,binary,binary,
+ mpint,mpint,mpint]),
+ crypto:hash(sha(Curve), L).
kex_h(SSH, Key, Min, NBits, Max, Prime, Gen, E, F, K) ->
L = if Min==-1; Max==-1 ->
@@ -1192,6 +1304,14 @@ kex_h(SSH, Key, Min, NBits, Max, Prime, Gen, E, F, K) ->
end,
crypto:hash(sha((SSH#ssh.algorithms)#alg.kex), L).
+sha('nistp256') -> sha256;
+sha('secp256r1')-> sha256;
+sha('nistp384') -> sha384;
+sha('secp384r1')-> sha384;
+sha('nistp521') -> sha512;
+sha('secp521r1')-> sha512;
+sha('diffie-hellman-group1-sha1') -> sha;
+sha('diffie-hellman-group14-sha1') -> sha;
sha('diffie-hellman-group-exchange-sha1') -> sha;
sha('diffie-hellman-group-exchange-sha256') -> sha256.
@@ -1200,6 +1320,7 @@ mac_key_size('hmac-sha1-96') -> 20*8;
mac_key_size('hmac-md5') -> 16*8;
mac_key_size('hmac-md5-96') -> 16*8;
mac_key_size('hmac-sha2-256')-> 32*8;
+mac_key_size('hmac-sha2-512')-> 512;
mac_key_size(none) -> 0.
mac_digest_size('hmac-sha1') -> 20;
@@ -1207,6 +1328,7 @@ mac_digest_size('hmac-sha1-96') -> 12;
mac_digest_size('hmac-md5') -> 20;
mac_digest_size('hmac-md5-96') -> 12;
mac_digest_size('hmac-sha2-256') -> 32;
+mac_digest_size('hmac-sha2-512') -> 64;
mac_digest_size(none) -> 0.
peer_name({Host, _}) ->
@@ -1218,14 +1340,10 @@ peer_name({Host, _}) ->
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-dh_group('diffie-hellman-group1-sha1') -> ?dh_group1;
-dh_group('diffie-hellman-group14-sha1') -> ?dh_group14.
+dh_group('diffie-hellman-group1-sha1') -> element(2, ?dh_group1);
+dh_group('diffie-hellman-group14-sha1') -> element(2, ?dh_group14).
-dh_gex_default_groups() ->
- [{1024, ?dh_group1 },
- {2048, ?dh_group14},
- {3072, ?dh_group15},
- {4096, ?dh_group16}].
+dh_gex_default_groups() -> ?dh_default_groups.
dh_gex_group(Min, N, Max, undefined) ->
@@ -1260,14 +1378,19 @@ dh_gex_group(Min, N, Max, Groups) ->
end.
-dh_gen_key(G, P, _) ->
- {Public, Private} = crypto:generate_key(dh, [P, G]),
- {crypto:bytes_to_integer(Private), crypto:bytes_to_integer(Public)}.
+generate_key(Algorithm, Args) ->
+ {Public,Private} = crypto:generate_key(Algorithm, Args),
+ {crypto:bytes_to_integer(Public), crypto:bytes_to_integer(Private)}.
+
+
+compute_key(Algorithm, OthersPublic, MyPrivate, Args) ->
+ Shared = crypto:compute_key(Algorithm, OthersPublic, MyPrivate, Args),
+ crypto:bytes_to_integer(Shared).
+
-dh_compute_key(G, P, OthersPublic, MyPrivate) ->
- crypto:bytes_to_integer(
- crypto:compute_key(dh, OthersPublic, MyPrivate, [P,G])
- ).
+ecdh_curve('ecdh-sha2-nistp256') -> secp256r1;
+ecdh_curve('ecdh-sha2-nistp384') -> secp384r1;
+ecdh_curve('ecdh-sha2-nistp521') -> secp521r1.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
diff --git a/lib/ssh/src/ssh_transport.hrl b/lib/ssh/src/ssh_transport.hrl
index 9e1de171c2..96ab1bb668 100644
--- a/lib/ssh/src/ssh_transport.hrl
+++ b/lib/ssh/src/ssh_transport.hrl
@@ -29,9 +29,12 @@
-define(DEFAULT_CLIENT_VERSION, {2, 0}).
-define(DEFAULT_SERVER_VERSION, {2, 0}).
--define(DEFAULT_DH_GROUP_MIN, 512).
--define(DEFAULT_DH_GROUP_NBITS, 1024).
--define(DEFAULT_DH_GROUP_MAX, 4096).
+
+-define(MAX_NUM_ALGORITHMS, 200).
+
+-define(DEFAULT_DH_GROUP_MIN, 1024).
+-define(DEFAULT_DH_GROUP_NBITS, 6144).
+-define(DEFAULT_DH_GROUP_MAX, 8192).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
@@ -109,8 +112,9 @@
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% diffie-hellman-group1-sha1
--define(SSH_MSG_KEXDH_INIT, 30).
+%% diffie-hellman-group1-sha1 | diffie-hellman-group14-sha1
+
+-define(SSH_MSG_KEXDH_INIT, 30).
-define(SSH_MSG_KEXDH_REPLY, 31).
-record(ssh_msg_kexdh_init,
@@ -134,7 +138,7 @@
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% diffie-hellman-group-exchange-sha1
+%% diffie-hellman-group-exchange-sha1 | diffie-hellman-group-exchange-sha256
-define(SSH_MSG_KEX_DH_GEX_REQUEST_OLD, 30).
-define(SSH_MSG_KEX_DH_GEX_REQUEST, 34).
-define(SSH_MSG_KEX_DH_GEX_GROUP, 31).
@@ -171,7 +175,36 @@
h_sig
}).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% KEY ECDH messages
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% ecdh-sha2-nistp256 | ecdh-sha2-nistp384 | ecdh-sha2-nistp521
+
+-define(SSH_MSG_KEX_ECDH_INIT, 30).
+-define(SSH_MSG_KEX_ECDH_REPLY, 31).
+
+-record(ssh_msg_kex_ecdh_init,
+ {
+ q_c % string (client's ephemeral public key octet string)
+ }).
+
+-record(ssh_msg_kex_ecdh_reply,
+ {
+ public_host_key, % string (server's public host key) (k_s)
+ q_s, % string (server's ephemeral public key octet string)
+ h_sig % string (the signature on the exchange hash)
+ }).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
%% error codes
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
-define(SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT, 1).
-define(SSH_DISCONNECT_PROTOCOL_ERROR, 2).
-define(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, 3).
@@ -188,24 +221,47 @@
-define(SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, 14).
-define(SSH_DISCONNECT_ILLEGAL_USER_NAME, 15).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
%% groups
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% rfc 2489, ch 6.2
-define(dh_group1,
- {2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF}).
+ {1024,
+ {2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF}}).
%%% rfc 3526, ch3
-define(dh_group14,
- {2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF}).
+ {2048,
+ {2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF}}).
%%% rfc 3526, ch4
-define(dh_group15,
- {2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF}).
+ {3072,
+ {2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF}}).
%%% rfc 3526, ch5
-define(dh_group16,
- {2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF}).
-
-
+ {4096,
+ {2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF}}).
+
+%%% rfc 3526, ch6
+-define(dh_group17,
+ {6144,
+ {2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF}}).
+
+%%% rfc 3526, ch7
+-define(dh_group18,
+ {8192,
+ {2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF}}).
+
+-define(dh_default_groups, [?dh_group14,
+ ?dh_group15,
+ ?dh_group16,
+ ?dh_group17,
+ ?dh_group18] ).
-endif. % -ifdef(ssh_transport).