Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SSH Client fails handshake when using publickey method #1380

Open
0x7f opened this issue Mar 21, 2024 · 10 comments
Open

SSH Client fails handshake when using publickey method #1380

0x7f opened this issue Mar 21, 2024 · 10 comments

Comments

@0x7f
Copy link

0x7f commented Mar 21, 2024

I'm building a SSH server using your Node.js library and I'm building the SSH client using the x/crypto/ssh Golang library. The client aborts the SSH handshake when using the publickey authentication method.

I built an example project including server and client here: https://github.com/0x7f/ssh-authentication-bug

Even though the server offers [publickey] authentication methods when initiating the handshake with authentication method none, the client fails to connect. The client uses the publickey method and offers the key, and the server accepts the key, but the client still prints the error:

2024/03/21 09:07:40 Failed to dial: ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain

I'm trying to figure out whether this is a bug in the server library or the client library. I already posted a bug in the Golang project: golang/go#66438. Either the Node.js server library is doing something non-standard during the handshake, or the client has some issue, or I'm stupid and did something wrong in the code. The OpenSSH client works though.

Let me know when you need more information.

@mscdex
Copy link
Owner

mscdex commented Mar 21, 2024

Out of curiosity can you post debug output on the ssh2 side (setting debug: console.log in the server config object)?

@mscdex
Copy link
Owner

mscdex commented Mar 21, 2024

Also have you tried different key types to try to isolate the problem?

@0x7f
Copy link
Author

0x7f commented Mar 21, 2024

Below you can find the output of the debug log. I will try other authentication types (password and different key types) and let you know.

SSH server successfully started on ssh://127.0.0.1:8022
[516174.643760916] Custom crypto binding available
[516174.643760916] Local ident: 'SSH-2.0-ssh2js1.15.0'
[516174.643760916] Remote ident: 'SSH-2.0-Go'
SSH Client connected
[516174.643760916] Outbound: Sending KEXINIT
[516174.643760916] Inbound: Handshake in progress
[516174.643760916] Handshake: (local) KEX method: [email protected],curve25519-sha256,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha256,diffie-hellman-group15-sha512,diffie-hellman-group16-sha512,diffie-hellman-group17-sha512,diffie-hellman-group18-sha512,[email protected]
[516174.643760916] Handshake: (remote) KEX method: curve25519-sha256,[email protected],ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group14-sha256,diffie-hellman-group14-sha1,ext-info-c,[email protected]
[516174.643760916] Handshake: strict KEX mode enabled
[516174.643760916] Handshake: KEX algorithm: curve25519-sha256
[516174.643760916] Handshake: (local) Host key format: rsa-sha2-512,rsa-sha2-256,ssh-rsa
[516174.643760916] Handshake: (remote) Host key format: [email protected],[email protected],[email protected],[email protected],[email protected],[email protected],[email protected],[email protected],ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,rsa-sha2-256,rsa-sha2-512,ssh-rsa,ssh-dss,ssh-ed25519
[516174.643760916] Handshake: Host key format: rsa-sha2-256
[516174.643760916] Handshake: (local) C->S cipher: [email protected],[email protected],aes128-ctr,aes192-ctr,aes256-ctr,[email protected]
[516174.643760916] Handshake: (remote) C->S cipher: [email protected],[email protected],[email protected],aes128-ctr,aes192-ctr,aes256-ctr
[516174.643760916] Handshake: C->S Cipher: [email protected]
[516174.643760916] Handshake: (local) S->C cipher: [email protected],[email protected],aes128-ctr,aes192-ctr,aes256-ctr,[email protected]
[516174.643760916] Handshake: (remote) S->C cipher: [email protected],[email protected],[email protected],aes128-ctr,aes192-ctr,aes256-ctr
[516174.643760916] Handshake: S->C cipher: [email protected]
[516174.643760916] Handshake: (local) C->S MAC: [email protected],[email protected],[email protected],hmac-sha2-256,hmac-sha2-512,hmac-sha1
[516174.643760916] Handshake: (remote) C->S MAC: [email protected],[email protected],hmac-sha2-256,hmac-sha2-512,hmac-sha1,hmac-sha1-96
[516174.643760916] Handshake: C->S MAC: <implicit>
[516174.643760916] Handshake: (local) S->C MAC: [email protected],[email protected],[email protected],hmac-sha2-256,hmac-sha2-512,hmac-sha1
[516174.643760916] Handshake: (remote) S->C MAC: [email protected],[email protected],hmac-sha2-256,hmac-sha2-512,hmac-sha1,hmac-sha1-96
[516174.643760916] Handshake: S->C MAC: <implicit>
[516174.643760916] Handshake: (local) C->S compression: none,[email protected],zlib
[516174.643760916] Handshake: (remote) C->S compression: none
[516174.643760916] Handshake: C->S compression: none
[516174.643760916] Handshake: (local) S->C compression: none,[email protected],zlib
[516174.643760916] Handshake: (remote) S->C compression: none
[516174.643760916] Handshake: S->C compression: none
[516174.643760916] Received DH Init
[516174.643760916] Generating signature ...
[516174.643760916] Outbound: Sending KEXECDH_REPLY
[516174.643760916] Outbound: Sending NEWKEYS
[516174.643760916] Inbound: NEWKEYS
[516174.643760916] Handshake completed
[516174.643760916] Outbound: Sending EXT_INFO
[516174.643760916] Inbound: Received SERVICE_REQUEST (ssh-userauth)
[516174.643760916] Outbound: Sending SERVICE_ACCEPT (ssh-userauth)
[516174.643760916] Inbound: Received USERAUTH_REQUEST (none)
authentication none test
Auth request with method none
[516174.643760916] Outbound: Sending USERAUTH_FAILURE
[516174.643760916] Inbound: Received USERAUTH_REQUEST (publickey -- check)
authentication publickey test
User test successfully authenticated with public key
[516174.643760916] Outbound: Sending USERAUTH_PK_OK
[516174.643760916] Socket ended
Client disconnected
[516174.643760916] Socket closed

@0x7f
Copy link
Author

0x7f commented Mar 21, 2024

It looks like it is working as expected when using a key of type ed25519. I created a branch in the other repo to show the client code changes: 0x7f/ssh-authentication-bug#1 The client prints this:

2024/03/21 14:55:22 Connected to SSH server

And these are the debug logs of the server:

SSH server successfully started on ssh://127.0.0.1:8022
[518853.545241708] Custom crypto binding available
[518853.545241708] Local ident: 'SSH-2.0-ssh2js1.15.0'
[518853.545241708] Remote ident: 'SSH-2.0-Go'
SSH Client connected
[518853.545241708] Outbound: Sending KEXINIT
[518853.545241708] Inbound: Handshake in progress
[518853.545241708] Handshake: (local) KEX method: [email protected],curve25519-sha256,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha256,diffie-hellman-group15-sha512,diffie-hellman-group16-sha512,diffie-hellman-group17-sha512,diffie-hellman-group18-sha512,[email protected]
[518853.545241708] Handshake: (remote) KEX method: curve25519-sha256,[email protected],ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group14-sha256,diffie-hellman-group14-sha1,ext-info-c,[email protected]
[518853.545241708] Handshake: strict KEX mode enabled
[518853.545241708] Handshake: KEX algorithm: curve25519-sha256
[518853.545241708] Handshake: (local) Host key format: rsa-sha2-512,rsa-sha2-256,ssh-rsa
[518853.545241708] Handshake: (remote) Host key format: [email protected],[email protected],[email protected],[email protected],[email protected],[email protected],[email protected],[email protected],ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,rsa-sha2-256,rsa-sha2-512,ssh-rsa,ssh-dss,ssh-ed25519
[518853.545241708] Handshake: Host key format: rsa-sha2-256
[518853.545241708] Handshake: (local) C->S cipher: [email protected],[email protected],aes128-ctr,aes192-ctr,aes256-ctr,[email protected]
[518853.545241708] Handshake: (remote) C->S cipher: [email protected],[email protected],[email protected],aes128-ctr,aes192-ctr,aes256-ctr
[518853.545241708] Handshake: C->S Cipher: [email protected]
[518853.545241708] Handshake: (local) S->C cipher: [email protected],[email protected],aes128-ctr,aes192-ctr,aes256-ctr,[email protected]
[518853.545241708] Handshake: (remote) S->C cipher: [email protected],[email protected],[email protected],aes128-ctr,aes192-ctr,aes256-ctr
[518853.545241708] Handshake: S->C cipher: [email protected]
[518853.545241708] Handshake: (local) C->S MAC: [email protected],[email protected],[email protected],hmac-sha2-256,hmac-sha2-512,hmac-sha1
[518853.545241708] Handshake: (remote) C->S MAC: [email protected],[email protected],hmac-sha2-256,hmac-sha2-512,hmac-sha1,hmac-sha1-96
[518853.545241708] Handshake: C->S MAC: <implicit>
[518853.545241708] Handshake: (local) S->C MAC: [email protected],[email protected],[email protected],hmac-sha2-256,hmac-sha2-512,hmac-sha1
[518853.545241708] Handshake: (remote) S->C MAC: [email protected],[email protected],hmac-sha2-256,hmac-sha2-512,hmac-sha1,hmac-sha1-96
[518853.545241708] Handshake: S->C MAC: <implicit>
[518853.545241708] Handshake: (local) C->S compression: none,[email protected],zlib
[518853.545241708] Handshake: (remote) C->S compression: none
[518853.545241708] Handshake: C->S compression: none
[518853.545241708] Handshake: (local) S->C compression: none,[email protected],zlib
[518853.545241708] Handshake: (remote) S->C compression: none
[518853.545241708] Handshake: S->C compression: none
[518853.545241708] Received DH Init
[518853.545241708] Generating signature ...
[518853.545241708] Outbound: Sending KEXECDH_REPLY
[518853.545241708] Outbound: Sending NEWKEYS
[518853.545241708] Inbound: NEWKEYS
[518853.545241708] Handshake completed
[518853.545241708] Outbound: Sending EXT_INFO
[518853.545241708] Inbound: Received SERVICE_REQUEST (ssh-userauth)
[518853.545241708] Outbound: Sending SERVICE_ACCEPT (ssh-userauth)
[518853.545241708] Inbound: Received USERAUTH_REQUEST (none)
authentication none test
Auth request with method none
[518853.545241708] Outbound: Sending USERAUTH_FAILURE
[518853.545241708] Inbound: Received USERAUTH_REQUEST (publickey -- check)
authentication publickey test
User test successfully authenticated with public key
[518853.545241708] Outbound: Sending USERAUTH_PK_OK
[518853.545241708] Inbound: Received USERAUTH_REQUEST (publickey)
authentication publickey test
User test successfully authenticated with public key
[518853.545241708] Outbound: Sending USERAUTH_SUCCESS
Client authenticated!
[518853.545241708] Socket ended
Client disconnected
[518853.545241708] Socket closed

@0x7f
Copy link
Author

0x7f commented Mar 24, 2024

@mscdex as far as o understand the latest comment in the other issue (golang/go#66438 (comment)) the ssh2 library is doing something non-standard which is handled by OpenSSL client, but not by the go client. The go folks want to add this to their client as well. But maybe it is worth changing the ssh2 server component to be compatible with other clients still? For example, I have clients out in the wild which are compiled with the old version of the go library and are not able to connect.

@0x7f
Copy link
Author

0x7f commented Mar 27, 2024

I did some more testing. I can confirm that my issue is fixed when using the proposed patch for the golang SSH client which accepts the algo returned by the ssh2 server. That's great.

But as mentioned above, I'd love to have the server compatible with old versions of the golang client as well. So I did the following local change to the PKAuthContext class:

@@ -144,11 +144,24 @@
   accept() {
     if (!this.signature) {
       this._initialResponse = true;
-      this._protocol.authPKOK(this.key.algo, this.key.data);
+      this._protocol.authPKOK(this.getResponseAlgo(), this.key.data);
     } else {
       AuthContext.prototype.accept.call(this);
     }
   }
+
+  getResponseAlgo() {
+    if (this.key.algo === 'ssh-rsa') {
+      switch (this.hashAlgo) {
+        case 'sha256':
+          return 'rsa-sha2-256';
+        case 'sha512':
+          return 'rsa-sha2-512';
+      }
+    }
+
+    return this.key.algo;
+  }
 }

 class HostbasedAuthContext extends AuthContext {

It is not beautiful and most probably the mapping belongs somewhere else (either Protocol.js or kex.js), but it works. With this change, the old golang client can connect as well. The openssh client can connect to this version of the server as well.

I'm not sure though whether this is really what the RFC requires (see this comment).

see According to RFC 4252 Section 7 the algorithm in SSH_MSG_USERAUTH_REQUEST should match that of the request, so our code was correct, but some server send the key type instead.

@mscdex can you please have a look at this? Happy to provide a PR if needed.

@0x7f
Copy link
Author

0x7f commented Apr 28, 2024

@mscdex let me know if I can help in any way to get this fixed.

@Kycermann
Copy link

Using MacOS Terminal.app I get the same. RSA keys don't work. ED25519 keys work.

@JoshuaWise
Copy link

JoshuaWise commented Oct 30, 2024

Also experiencing this. In my case, RSA keys don't work when connecting to Fedora Linux, but other key types work fine. All key types seem to work when connecting to Debian Linux. I'm using ssh2 version 1.16.0

@JoshuaWise
Copy link

It turns out my issue was solved by changing the key bit length from 1024 to 2048. I used a small key since my use-case is just in a VM sandbox for testing purposes, but I guess some default configurations block RSA keys of small bit lengths

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants