Description
Describe the bug
Using the SSH client from dropbear might fail to connect to the SSH server implementation of OTP, with following error:
10:05:48.080 [notice] Erlang SSH :server version: 5.1.1 (OpenSSL 3.2.1 30 Jan 2024. FIPS available but not enabled).
Address: 127.0.0.1:2222
Peer client version: ~c"SSH-2.0-dropbear_2024.85"
Peer address: 127.0.0.1:57220
Disconnects with code = 2 [RFC4253 11.1]: Protocol error
State = {new_keys,server,init}
Module = ssh_connection_handler, Line = 1370.
Details:
Message ssh_msg_kex_ecdh_init in wrong state ({new_keys,server,init})
The reason is that the dropbear client may send a guess KEXINIT and if the guess doesn't match it will send another KEXINIT which then fails the state machine. This is described in RFC4253 sec 7:
However, if the guess was wrong, and a packet was optimistically sent
by one or both parties, such packets MUST be ignored (even if the
error in the guess would not affect the contents of the initial
packet(s)), and the appropriate side MUST send the correct initial
packet.
The initial guess send happens here:
https://github.com/mkj/dropbear/blob/2674736bce847bc51a30a07c191562047659ac1f/src/common-kex.c#L112
and depending on whether the first guess matches or not, another KEX might be send:
https://github.com/mkj/dropbear/blob/2674736bce847bc51a30a07c191562047659ac1f/src/common-kex.c#L1037
The OTP ssh code only seems to encode the first_kex_packet_follows
in the ssh_msg_kexinit
but doesn't appear to support it in the receiving part.
To Reproduce
Use dropbear dbclient to connect to OTP SSH daemon and cause the preferred_algorithms
kex
and public_key
to not match the order of what dropbear uses.
dropbear should build easily:
$ git clone https://github.com/mkj/dropbear
$ cd dropbear
$ ./configure
$ make
$ ./dbclient -y -y user@host/port
change the order of the kex
and public_key
values when starting the daemon:
$ mkdir sysdir
$ ssh-keygen -t ed25519 -f sysdir/ssh_host_ed25519_key
$ erl
1> ssh:start().
2> ssh:daemon(2222, [{system_dir, "sysdir"}, {password, "pass"}, {preferred_algorithms, [ {kex, ['curve448-sha512', 'curve25519-sha256']}, {public_key,['ssh-dss', 'ssh-ed25519']} ]} ]).
If the first entry doesn't match the first guess dropbear uses, it will send another KEXDH_INIT causing the connection to terminate.
Expected behavior
OTP SSH should support the key exchange guess as described in RFC4253 section 7.
Affected versions
tested on OTP SSH 5.1.1 and 5.2
Additional context
The dropbear code has a define to disable this code:
/* A client should try and send an initial key exchange packet guessing
* the algorithm that will match - saves a round trip connecting, has little
* overhead if the guess was "wrong". */
#ifndef DROPBEAR_KEX_FIRST_FOLLOWS
#define DROPBEAR_KEX_FIRST_FOLLOWS 1
#endif
https://github.com/mkj/dropbear/blob/2674736bce847bc51a30a07c191562047659ac1f/src/sysoptions.h#L55
but this is ofcourse not a solution as one can't always control which client is used.