kex protocol error: type 7 seq xxx error message

Aris Adamantiadis
Wed, 24 Aug 2016 17:06:29 -0000

Hi,

mancha and me debugged a problem with OpenSSH 7.3p1 that was reported on
the #openssh freenode channel. Symptoms were that this message was
popping on the console during a busy X11 session:
kex protocol error: type 7 seq 1234

I managed to reproduce the problem, it is related to the SSH_EXT_INFO
packet that is send by the server every time it is sending an
SSH_NEWKEYS packet, hence after every rekeying. I reproduced it on my
system with OpenSSH 7.3p1 and manually rekeying with escape R
http://pastebin.com/Xk0dF0mc

on the client side:
sshconnect2.c:
void
ssh_userauth2(const char *local_user, const char *server_user, char *host,
    Sensitive *sensitive)
{
...
        ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_ext_info);
        ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_ACCEPT,
&input_userauth_service_accept);
        ssh_dispatch_run(ssh, DISPATCH_BLOCK, &authctxt.success,
&authctxt);    /* loop until success */

        pubkey_cleanup(&authctxt);
        ssh_dispatch_range(ssh, SSH2_MSG_USERAUTH_MIN,
SSH2_MSG_USERAUTH_MAX, NULL);

        debug("Authentication succeeded (%s).",
authctxt.method->name);
}

Is the only place where the dispatch for that packet is set. However in
kex.c:
int
kex_input_ext_info(int type, u_int32_t seq, void *ctxt)
{
...
        debug("SSH2_MSG_EXT_INFO received");
        ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error);
...
}

Ensuring this packet will only be accepted before authentication.
However the server side is different:
int
kex_send_newkeys(struct ssh *ssh)
{
...
        debug("SSH2_MSG_NEWKEYS sent");
        debug("expecting SSH2_MSG_NEWKEYS");
        ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys);
        if (ssh->kex->ext_info_c)
                if ((r = kex_send_ext_info(ssh)) != 0)
                        return r;
        return 0;
}

There doesn't seem to have any logic in the client side that restricts
sending ext-info-c in the list of kex algorithms after the first key
exchange. However I couldn't find it in my kexinit proposal (even the
first one):
debug2: local client KEXINIT proposal
debug2: KEX algorithms:
curve25519-sha256 at
libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha256,diffie-hellman-group14-sha1
debug2: host key algorithms:
ecdsa-sha2-nistp256-cert-v01 at openssh.com,ecdsa-sha2-nistp384-cert-v01 at
openssh.com,ecdsa-sha2-nistp521-cert-v01 at
openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-ed25519-cert-v01
at openssh.com,ssh-rsa-cert-v01 at
openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa
debug2: ciphers ctos:
chacha20-poly1305 at openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm at
openssh.com,aes256-gcm at openssh.com,aes128-cbc,aes192-cbc,aes256-cbc,3des-cbc
debug2: ciphers stoc:
chacha20-poly1305 at openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm at
openssh.com,aes256-gcm at openssh.com,aes128-cbc,aes192-cbc,aes256-cbc,3des-cbc
debug2: MACs ctos:
umac-64-etm at openssh.com,umac-128-etm at openssh.com,hmac-sha2-256-etm at
openssh.com,hmac-sha2-512-etm at openssh.com,hmac-sha1-etm at
openssh.com,umac-64 at openssh.com,umac-128 at
openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1
debug2: MACs stoc:
umac-64-etm at openssh.com,umac-128-etm at openssh.com,hmac-sha2-256-etm at
openssh.com,hmac-sha2-512-etm at openssh.com,hmac-sha1-etm at
openssh.com,umac-64 at openssh.com,umac-128 at
openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1
debug2: compression ctos: none,zlib at openssh.com,zlib
debug2: compression stoc: none,zlib at openssh.com,zlib
debug2: languages ctos:
debug2: languages stoc:

Mancha couldn't reproduce the issue, despite running both OpenSSH 7.3p1
client & server from upstream, with an empty configuration file. At this
point I don't know why he's not affected.

This bug is not very important anyway because the packet is simply
dropped with no consequence.

Aris