Here's a trivial server:
#include <libssh/libssh.h> #include <libssh/server.h> #include <libssh/callbacks.h> #include <stdio.h> #include <assert.h> #include <stdlib.h> #include <errno.h> int main (int argc, char **argv) { ssh_bind sshbind; ssh_event event; ssh_session session; int port = 4321; int r; event = ssh_event_new (); assert (event != NULL); sshbind = ssh_bind_new (); session = ssh_new (); ssh_bind_options_set (sshbind, SSH_BIND_OPTIONS_BINDADDR, "127.0.0.1"); ssh_bind_options_set (sshbind, SSH_BIND_OPTIONS_BINDPORT, &port); ssh_bind_options_set (sshbind, SSH_BIND_OPTIONS_RSAKEY, "ssh_host_rsa_key"); /* Broken: "curve25519-sha256" (default) * Workaround: "ecdh-sha2-nistp256" (for example) */ if (argc > 1) ssh_options_set (session, SSH_OPTIONS_KEY_EXCHANGE, argv[1]); if (ssh_bind_listen (sshbind) < 0) { fprintf (stderr, "couldn't listen on socket: %s", ssh_get_error (sshbind)); return 1; } r = ssh_bind_accept (sshbind, session); if (r == SSH_ERROR) { fprintf (stderr, "accepting connection failed: %s", ssh_get_error (sshbind)); return 1; } if (ssh_handle_key_exchange (session)) { const char *msg = ssh_get_error (session); if (!strstr (msg, "_DISCONNECT")) fprintf (stderr, "key exchange failed: %s", msg); return 1; } if (ssh_event_add_session (event, session) != SSH_OK) abort (); do { ssh_event_dopoll (event, 10000); } while (ssh_is_connected (session)); ssh_event_remove_session (event, session); ssh_event_free (event); ssh_free (session); ssh_bind_free (sshbind); return 0; }
Running this under valgrind on i386 causes a connecting ssh to fail. Here's what `ssh -v -p 4321 localhost' looks like:
OpenSSH_7.9p1 Ubuntu-10, OpenSSL 1.1.1b 26 Feb 2019 debug1: Reading configuration data /etc/ssh/ssh_config debug1: /etc/ssh/ssh_config line 19: Applying options for * debug1: Connecting to localhost [127.0.0.1] port 4321. debug1: Connection established. debug1: identity file /home/builder/.ssh/id_rsa type -1 debug1: identity file /home/builder/.ssh/id_rsa-cert type -1 debug1: identity file /home/builder/.ssh/id_dsa type -1 debug1: identity file /home/builder/.ssh/id_dsa-cert type -1 debug1: identity file /home/builder/.ssh/id_ecdsa type -1 debug1: identity file /home/builder/.ssh/id_ecdsa-cert type -1 debug1: identity file /home/builder/.ssh/id_ed25519 type -1 debug1: identity file /home/builder/.ssh/id_ed25519-cert type -1 debug1: identity file /home/builder/.ssh/id_xmss type -1 debug1: identity file /home/builder/.ssh/id_xmss-cert type -1 debug1: Local version string SSH-2.0-OpenSSH_7.9p1 Ubuntu-10 debug1: Remote protocol version 2.0, remote software version libssh_0.8.6 debug1: no match: libssh_0.8.6 debug1: Authenticating to localhost:4321 as 'builder' debug1: SSH2_MSG_KEXINIT sent debug1: SSH2_MSG_KEXINIT received debug1: kex: algorithm: curve25519-sha256 debug1: kex: host key algorithm: rsa-sha2-512 debug1: kex: server->client cipher: chacha20-poly1305@openssh.com MAC: <implicit> compression: none debug1: kex: client->server cipher: chacha20-poly1305@openssh.com MAC: <implicit> compression: none debug1: expecting SSH2_MSG_KEX_ECDH_REPLY debug1: Server host key: ssh-rsa SHA256:XQ8a7zGxMFstDrGecBRUP9OMnOUXd/T3vkNGtYShs2w debug1: Host '[localhost]:4321' is known and matches the RSA host key. debug1: Found key in /home/builder/.ssh/known_hosts:4 ssh_dispatch_run_fatal: Connection to 127.0.0.1 port 4321: incorrect signature
Running the test server with the argument ecdh-sha2-nistp256 (disabling curve25519-sha256) is an effective workaround.
This bug is present on Ubuntu 19.04 libssh 0.8.6-3, linked against libssl 1.1.1b-1ubuntu2, but is not present on Ubuntu 16.04 libssh 0.6.3-4.3ubuntu0.2 linked against libssl 1.0.2g-1ubuntu4.15.