The KiTTY SSH client for Windows gives a blank screen and hangs when connecting to my Fedora 22 box (which runs OpenSSH 6.9). KiTTY is a fork of PuTTY, which I am happy with, so there’s no particular reason for me to use KiTTY except that I am checking it out.
After a while it gives an error that the server closed the connection.
I have an Ubuntu Server 14.10 and CentOS 6.7 and KiTTY works fine with them. So it seems to be related to the version of OpenSSH in Fedora 22.
Fedora 22 logs show entries like these:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# journalctl -o cat -u sshd.service Server listening on 0.0.0.0 port 22. error: Hm, kex protocol error: type 30 seq 1 [preauth] Bad protocol version identification '' from 10.50.0.201 port 64147 Connection closed by 10.50.0.201 [preauth] error: Hm, kex protocol error: type 30 seq 1 [preauth] error: Hm, kex protocol error: type 30 seq 1 [preauth] Connection closed by 10.50.0.201 [preauth] Connection closed by 10.50.0.201 [preauth] Server listening on 0.0.0.0 port 22. error: Hm, kex protocol error: type 30 seq 1 [preauth] Connection closed by 10.50.0.209 [preauth] Received signal 15; terminating. Server listening on 0.0.0.0 port 22. error: Hm, kex protocol error: type 30 seq 1 [preauth] Received signal 15; terminating. Server listening on 0.0.0.0 port 22. error: Hm, kex protocol error: type 30 seq 1 [preauth] |
Looks like key-exchange was failing?
/*
Note to self: An alternative command syntax to the above is this:
1 |
# journalctl _SYSTEMD_UNIT=sshd.service -o cat |
I also noticed that including SELinux in the output gave a bit more info. Not that it helped but it’s worth mentioning here as a reference to myself. For that I include the sshd.service
unit and also the SELinux context for SSHD.
1 |
# journalctl _SELINUX_CONTEXT=system_u:system_r:sshd_t:s0-s0:c0.c1023 + _SYSTEMD_UNIT=sshd.service -o cat |
Tip: After typing journalctl it is possible to keep pressing TAB
to get the fields and their values. That’s how I discovered the SSHD context above.
On the topic of journalctl
: this intro post by its creator and this DigitalOcean tutorial are worth a read.
Another useful tip with journalctrl
: by default it doesn’t wrap the output but you can scroll left and right with the keyboard. This isn’t useful when you want to copy-paste the logs somewhere. The work-around is to use the --no-pager
switch so everything’s dumped out together and then pipe it into less
which wraps the text:
1 |
# journalctl _SELINUX_CONTEXT=system_u:system_r:sshd_t:s0-s0:c0.c1023 + _SYSTEMD_UNIT=sshd.service --no-pager | less |
*/
I turned on SSH packet and raw data logging in KiTTY.
From the log files I could see a sequence of events like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
Outgoing packet #0x0, type 20 / 0x14 (SSH2_MSG_KEXINIT) 00000000 5e b0 68 10 4b 9e 33 c7 ac 37 be 83 d0 02 36 65 ^.h.K.3..7....6e 00000010 00 00 00 9a 64 69 66 66 69 65 2d 68 65 6c 6c 6d ....diffie-hellm 00000020 61 6e 2d 67 72 6f 75 70 2d 65 78 63 68 61 6e 67 an-group-exchang 00000030 65 2d 73 68 61 32 35 36 2c 64 69 66 66 69 65 2d e-sha256,diffie- 00000040 68 65 6c 6c 6d 61 6e 2d 67 72 6f 75 70 2d 65 78 hellman-group-ex 00000050 63 68 61 6e 67 65 2d 73 68 61 31 2c 64 69 66 66 change-sha1,diff ... Outgoing raw data at 2015-08-07 14:11:09 00000000 00 00 02 9c 0a 14 5e b0 68 10 4b 9e 33 c7 ac 37 ......^.h.K.3..7 00000010 be 83 d0 02 36 65 00 00 00 9a 64 69 66 66 69 65 ....6e....diffie 00000020 2d 68 65 6c 6c 6d 61 6e 2d 67 72 6f 75 70 2d 65 -hellman-group-e 00000030 78 63 68 61 6e 67 65 2d 73 68 61 32 35 36 2c 64 xchange-sha256,d 00000040 69 66 66 69 65 2d 68 65 6c 6c 6d 61 6e 2d 67 72 iffie-hellman-gr 00000050 6f 75 70 2d 65 78 63 68 61 6e 67 65 2d 73 68 61 oup-exchange-sha ... Incoming raw data at 2015-08-07 14:11:09 00000000 00 00 03 ac 04 14 01 f7 78 c4 43 a2 09 93 25 94 ........x.C...%. 00000010 2f 4f 2d f6 86 24 00 00 00 96 63 75 72 76 65 32 /O-..$....curve2 00000020 35 35 31 39 2d 73 68 61 32 35 36 40 6c 69 62 73 5519-sha256@libs 00000030 73 68 2e 6f 72 67 2c 65 63 64 68 2d 73 68 61 32 sh.org,ecdh-sha2 00000040 2d 6e 69 73 74 70 32 35 36 2c 65 63 64 68 2d 73 -nistp256,ecdh-s ... Incoming packet #0x0, type 20 / 0x14 (SSH2_MSG_KEXINIT) 00000000 01 f7 78 c4 43 a2 09 93 25 94 2f 4f 2d f6 86 24 ..x.C...%./O-..$ 00000010 00 00 00 96 63 75 72 76 65 32 35 35 31 39 2d 73 ....curve25519-s 00000020 68 61 32 35 36 40 6c 69 62 73 73 68 2e 6f 72 67 ha256@libssh.org ... Event Log: Doing Diffie-Hellman group exchange Outgoing packet #0x1, type 30 / 0x1e (SSH2_MSG_KEX_DH_GEX_REQUEST) 00000000 00 00 10 00 .... Outgoing raw data at 2015-08-07 14:11:09 00000000 00 00 00 0c 06 1e 00 00 10 00 9e a7 e1 58 8d 1d .............X.. |
And with that it stops. So it looked like the DH Key Exchange was failing. Which confirms what I saw on the server side too.
SSH protocol 2 supports DSA, ECDSA, Ed25519 and RSA keys when clients establish a connection to the server. However, the first step is a Key Exchange for forward-secrecy and for this the DH algorithm is used. From the sshd(8)
manpage:
For protocol 2, forward security is provided through a Diffie-Hellman key agreement. This key agreement results in a shared session key. The rest of the session is encrypted using a symmetric cipher, currently 128-bit AES, Blowfish, 3DES, CAST128, Arcfour, 192-bit AES, or 256-bit AES. The client selects the encryption algorithm to use from those offered by the server. Additionally, session integrity is provided through a cryptographic message authentication code (hmac-md5, hmac-sha1, umac-64, umac-128, hmac-ripemd160, hmac-sha2-256 or hmac-sha2-512).
From the
sshd_config(5)
manpage:The supported algorithms are:
curve25519-sha256@libssh.org
diffie-hellman-group1-sha1
diffie-hellman-group14-sha1
diffie-hellman-group-exchange-sha1
diffie-hellman-group-exchange-sha256
ecdh-sha2-nistp256
ecdh-sha2-nistp384
ecdh-sha2-nistp521The default is:
curve25519-sha256@libssh.org,
ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,
diffie-hellman-group-exchange-sha256,
diffie-hellman-group14-sha1
The KexAlgorithms
option can be used to change this but the point is all these are variants of the DH algorithm.
KiTTY has the following algorithm selection options:
For protocol 2 only the first three (Diffie-Hellman options) apply. The fourth one (RSA-based key exchange) only applies for protocol 1. Comparing this with the preferred order for OpenSSH only the first and second options are common:
- Diffie-Hellman group exchange (a.k.a.
diffie-hellman-group-exchange-sha256
) - Diffie-Hellman group 14 (a.k.a.
diffie-hellman-group14-sha1
)
Of these the second one (diffie-hellman-group14-sha1
) is the older one. It is defined in RFC 4253. This RFC defines two key exchange algorithms: diffie-hellman-group14-sha1
and diffie-hellman-group1-sha1
. (The group number defines the number of bits in the key. Group 1 has 768 bits, group 14 has 2048 bits. Larger is better). (Correction: Turns out diffie-hellman-group1-sha1
is actually Group 2).
The key exchange algorithms of RFC 4253 are updated via RFC 4419 – which defines two additional algorithms: diffie-hellman-group-exchange-sha1
and diffie-hellman-group-exchange-sha256
. I am not very clear about these but it looks like they remove any weaknesses to do with groups that define the fixed number of bits and introduces the ability for the client and server to negotiate a custom group (of 1024 – 8192 bits). From RFC 4419:
Currently, SSH performs the initial key exchange using the “diffie-hellman-group1-sha1” method [RFC4253]. This method prescribes a fixed group on which all operations are performed.
The security of the Diffie-Hellman key exchange is based on the difficulty of solving the Discrete Logarithm Problem (DLP). Since we expect that the SSH protocol will be in use for many years in the future, we fear that extensive precomputation and more efficient algorithms to compute the discrete logarithm over a fixed group might pose a security threat to the SSH protocol.
The ability to propose new groups will reduce the incentive to use precomputation for more efficient calculation of the discrete logarithm. The server can constantly compute new groups in the background.
So, to summarize: the common algorithms between KiTTY and OpenSSH are diffie-hellman-group-exchange-sha256
and diffie-hellman-group14-sha1
. By default the preferred order between KiTTY client and OpenSSH server are in the order I specified above. In terms of security diffie-hellman-group-exchange-sha256
is preferred over diffie-hellman-group14-sha1
. For some reason, however, KiTTY breaks with the newer version of OpenSSH when it comes to this stage.
Since diffie-hellman-group-exchange-sha256
is what both would be using I changed the preferred order on KiTTY such that diffie-hellman-group14-sha1
is selected.
Once I did that KiTTY connected successfully with OpenSSH – so that worked around the problem for now albeit by using a weaker algorithm – but at least it works. I wonder why diffie-hellman-group-exchange-sha256
breaks though.
I downloaded the latest version of PuTTY and gave that a shot with the default options (which are same as KiTTY). That worked fine! From the PuTTY logs I could see that at the point where KiTTY failed PuTTY manages to negotiate a key successfully:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
Outgoing packet #0x1, type 34 / 0x22 (SSH2_MSG_KEX_DH_GEX_REQUEST) 00000000 00 00 04 00 00 00 10 00 00 00 20 00 .......... . Outgoing raw data at 2015-08-07 14:19:25 00000000 00 00 00 14 06 22 00 00 04 00 00 00 10 00 00 00 .....".......... 00000010 20 00 5d fd 2a 7d 42 6f .].*}Bo Incoming raw data at 2015-08-07 14:19:25 00000000 00 00 02 14 08 1f 00 00 02 01 00 c8 bc e5 2e 2a ...............* 00000010 e7 ae 1e c2 00 56 b2 d0 76 40 47 c9 23 92 c9 df .....V..v@G.#... 00000020 75 c3 a5 7e b8 af 10 62 a8 09 e6 ea 97 5d 99 10 u..~...b.....].. 00000030 aa 5c 55 83 3c c4 7d 4d a7 6e 92 bf 63 fe bb 28 .\U.<.}M.n..c..( ... Event Log: ssh-rsa 2048 1b:09:2b:fa:6f:f1:d6:0e:88:5e:fe:70:d7:d4:c9:8b Outgoing packet #0x3, type 21 / 0x15 (SSH2_MSG_NEWKEYS) Outgoing raw data at 2015-08-07 14:19:25 00000000 00 00 00 0c 0a 15 bd 0f 90 8c 43 70 dc a0 05 12 ..........Cp.... Event Log: Initialised AES-256 SDCTR client->server encryption Event Log: Initialised HMAC-SHA-256 client->server MAC algorithm Outgoing raw data at 2015-08-07 14:19:25 Incoming packet #0x3, type 21 / 0x15 (SSH2_MSG_NEWKEYS) Event Log: Initialised AES-256 SDCTR server->client encryption Event Log: Initialised HMAC-SHA-256 server->client MAC algorithm Outgoing packet #0x4, type 5 / 0x05 (SSH2_MSG_SERVICE_REQUEST) 00000000 00 00 00 0c 73 73 68 2d 75 73 65 72 61 75 74 68 ....ssh-userauth |
Comparing the configuration settings of PuTTY and KiTTY I found the following:
If I change the setting from “Auto” to “Yes”, PuTTY also hangs like KiTTY. So that narrows down the problem. RFC 4419 is the one I mentioned above, which introduced the new algorithms. Looks like that has been updated and KiTTY doesn’t support the new algorithms whereas PuTTY is able to.
PuTTY’s changelog didn’t have anything but its wishlist contained mention of what was going on. Apparently it isn’t a case of an update to RFC 4419 or any new algorithms, it is just a case of OpenSSH now strictly implementing the message format of RFC 4419 and thus breaking clients who do not implement this yet. To understand this have a look at this bit from the log entries of PuTTY and KiTTY at the point where KiTTY fails:
1 2 3 4 5 6 7 |
== PuTTY == Outgoing packet #0x1, type 34 / 0x22 (SSH2_MSG_KEX_DH_GEX_REQUEST) 00000000 00 00 04 00 00 00 10 00 00 00 20 00 .......... . = KiTTY == Outgoing packet #0x1, type 30 / 0x1e (SSH2_MSG_KEX_DH_GEX_REQUEST) 00000000 00 00 10 00 .... |
Pretty identical except for the type number. KiTTY uses 30 while PuTTY now uses 34. If you look at RFC 4419 these numbers are defined thus:
The following message numbers have been defined in this document.
They are in a name space private to this document and not assigned by IANA.
#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
#define SSH_MSG_KEX_DH_GEX_INIT 32
#define SSH_MSG_KEX_DH_GEX_REPLY 33SSH_MSG_KEX_DH_GEX_REQUEST_OLD is used for backward compatibility. Instead of sending “min || n || max”, the client only sends “n”. In addition, the hash is calculated using only “n” instead of “min || n || max”.
So RFC 4419 has updated the type number to 34 and set aside 30 for backward compatibility. Ideally clients should be sending type number 34 as their request. From the PuTTY wishlist link I saw the OpenSSH commit that removed the server from accepting type 30 any more. That’s why KiTTY was breaking, while PuTTY had updated their message type to the correct one and was successfully connecting! :)
(While digging around I saw that WinSCP too is (was?) affected.)