Eugeny / russh

Rust SSH client & server library
https://docs.rs/russh
883 stars 96 forks source link

Connection from libgit2 (libssh2) fails with "failed to start SSH session: Unable to exchange encryption keys" #245

Open Qix- opened 7 months ago

Qix- commented 7 months ago

Hi there. I'm trying to get a libgit2 client (via the git2 crate) connecting to russh for integration testing purposes and I'm getting a rather unhelpful error from libgit2 - failed to start SSH session: Unable to exchange encryption keys.

I did a pcap of the negotiation and it looks like the client simply hangs up after russh tries to initiate a key exchange. I'm not well versed in the exchange details so this very well could be a problem with libgit2, but we don't have issues connecting to other servers - just russh.

Negotation packets (client hangs up directly after this):

``` SSH Protocol Protocol: SSH-2.0-libssh2_1.10.1_DEV [Direction: server-to-client] ``` ``` SSH Protocol Protocol: SSH-2.0-russh_0.41.0-beta.4 [Direction: client-to-server] ``` ``` SSH Protocol SSH Version 2 Packet Length: 1196 Padding Length: 11 Key Exchange (method:curve25519-sha256) Message Code: Key Exchange Init (20) Algorithms Cookie: 199acd9dc98b56be0d562512369ee374 kex_algorithms length: 331 kex_algorithms string [truncated]: curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,dif server_host_key_algorithms length: 265 server_host_key_algorithms string [truncated]: ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed255 encryption_algorithms_client_to_server length: 146 encryption_algorithms_client_to_server string: aes128-ctr,aes192-ctr,aes256-ctr,aes256-cbc,rijndael-cbc@lysator.liu.se,aes192-cbc,aes128-cbc,blowfish-cbc,arcfour128,arcfour,cast128-cbc,3des-cbc encryption_algorithms_server_to_client length: 146 encryption_algorithms_server_to_client string: aes128-ctr,aes192-ctr,aes256-ctr,aes256-cbc,rijndael-cbc@lysator.liu.se,aes192-cbc,aes128-cbc,blowfish-cbc,arcfour128,arcfour,cast128-cbc,3des-cbc mac_algorithms_client_to_server length: 113 mac_algorithms_client_to_server string: hmac-sha2-256,hmac-sha2-512,hmac-sha1,hmac-sha1-96,hmac-md5,hmac-md5-96,hmac-ripemd160,hmac-ripemd160@openssh.com mac_algorithms_server_to_client length: 113 mac_algorithms_server_to_client string: hmac-sha2-256,hmac-sha2-512,hmac-sha1,hmac-sha1-96,hmac-md5,hmac-md5-96,hmac-ripemd160,hmac-ripemd160@openssh.com compression_algorithms_client_to_server length: 4 compression_algorithms_client_to_server string: none compression_algorithms_server_to_client length: 4 compression_algorithms_server_to_client string: none languages_client_to_server length: 0 languages_client_to_server string: languages_server_to_client length: 0 languages_server_to_client string: First KEX Packet Follows: 0 Reserved: 00000000 [hasshServerAlgorithms [truncated]: curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,dif] [hasshServer: 19a8bc97d71fe02f6899cd96937a5202] Padding String: 2ffd9404a0bee872b5bcc1 Sequence number: 0 [Direction: server-to-client] ``` ``` SSH Protocol SSH Version 2 Packet Length: 764 Padding Length: 10 Key Exchange (method:curve25519-sha256) Message Code: Key Exchange Init (20) Algorithms Cookie: fbb9d45baee0ef5ecc4ccc09a1567ab0 kex_algorithms length: 146 kex_algorithms string: curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group14-sha256,ext-info-s,kex-strict-s-v00@openssh.com server_host_key_algorithms length: 77 server_host_key_algorithms string: ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp521,rsa-sha2-256,rsa-sha2-512 encryption_algorithms_client_to_server length: 85 encryption_algorithms_client_to_server string: chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr encryption_algorithms_server_to_client length: 85 encryption_algorithms_server_to_client string: chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr mac_algorithms_client_to_server length: 123 mac_algorithms_client_to_server string: hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,hmac-sha1-etm@openssh.com,hmac-sha1 mac_algorithms_server_to_client length: 123 mac_algorithms_server_to_client string: hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,hmac-sha1-etm@openssh.com,hmac-sha1 compression_algorithms_client_to_server length: 26 compression_algorithms_client_to_server string: none,zlib,zlib@openssh.com compression_algorithms_server_to_client length: 26 compression_algorithms_server_to_client string: none,zlib,zlib@openssh.com languages_client_to_server length: 0 languages_client_to_server string: languages_server_to_client length: 0 languages_server_to_client string: First KEX Packet Follows: 0 Reserved: 00000000 [hasshAlgorithms [truncated]: curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group14-sha256,ext-info-s,kex-strict-s-v00@openssh.com;chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr] [hassh: 4b1a36b25874bf1affea42deb0f90ba0] Padding String: 00000000000000000000 Sequence number: 0 [Direction: client-to-server] ``` ``` SSH Protocol SSH Version 2 Packet Length: 44 Padding Length: 6 Key Exchange (method:curve25519-sha256) Message Code: Elliptic Curve Diffie-Hellman Key Exchange Init (30) ECDH client's ephemeral public key length: 32 ECDH client's ephemeral public key (Q_C): 790edbec4a082f8295961b6990a1360093106f33276e32cc81fbef46d924a537 Padding String: 57ac5d71360e Sequence number: 1 [Direction: server-to-client] ```

I've attached the PCAPng file directly given that wireshark truncates column data for some reason: key-exchange-libssh2-russh.pcapng.zip

The initialization code is just this:

        let listener = TcpListener::bind(("127.0.0.1", 0)).await.unwrap();
        let addr = listener.local_addr().unwrap();
        let port = addr.port();

        let config = Arc::new(russh::server::Config {
            inactivity_timeout: Some(std::time::Duration::from_secs(10)),
            auth_rejection_time: std::time::Duration::from_secs(3),
            auth_rejection_time_initial: Some(std::time::Duration::from_secs(3)),
            keys: vec![
                russh_keys::key::KeyPair::generate_ed25519().unwrap(),
            ],
            ..Default::default()
        });

        let socket_future = russh::server::run_on_socket(config, &listener, self);

Perhaps I'm missing something on the config side but I'm honestly not sure how to debug further given that neither side (libgit2 nor russh) have any additional callbacks I can specify to show more involved output. Is this an issue with unsupported key exchange algorithms?

For what it's worth, git (mainstream CLI) works fine.

Eugeny commented 7 months ago

Looks like the session ends up negotiating a missing ecdsa-sha2-nistp256 host key, which is then the same bug as #227 (just fixed) - please check

Qix- commented 7 months ago

Nope, unfortunately still the same issue. Should I do another PCAP dump?