otp
otp copied to clipboard
SSH server key exchange fails with dropbear dbclient due to RFC4253 sec 7 "each side MAY guess"
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.
Respective implemenation in openssh: https://github.com/openssh/openssh-portable/blob/7717b9e9155209916cc6b4b4b54f4e8fa578e889/kex.c#L1050
thanks for detailed report. indeed does not seem to be supported. I will investigate it further.
we plan to fix this interop issue. but this task might be scheduled for later due to other ssh work planned earlier.