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

Support for optional fallback to ssh-rsa public key algorithm in case target server doesn't support "server-sig-algs" extension #262

Open
jgolda opened this issue Jan 5, 2023 · 13 comments

Comments

@jgolda
Copy link

jgolda commented Jan 5, 2023

Hello,

I'm using your implemetation of JSch in a project done at the company i work for. After upgrading from 0.1.55 to 0.1.72 i faced problems with an SFTP server, which doesn't support server-sig-algs extension and most likely doesn't support rsa-sha2-256 or rsa-sha2-512 as well. Most likely it's legacy AF and should be updated or replaced, but the company's client still uses it and it might not be possible to persuade him to move to anything else.
Unfortunatelly this server also fails to correctly follow the public key authentication flow as described in RFC 4252 section 7. It responds to initial SSH_MSG_USERAUTH_REQUEST containing one of the above algorithms with SSH_MSG_USERAUTH_PK_OK, but then it returns SSH_MSG_USERAUTH_FAILURE in response to the second one, resulting with authentication failure.

It sounds quite incorrect given the requirements specified in RFC. On the other hand, this behaviour is also described in RFC 8332, section 3.3:
"Implementation experience has shown that there are servers that apply
authentication penalties to clients attempting public key algorithms
that the SSH server does not support.
(...)
When authenticating with an RSA key against a server that does not
implement the "server-sig-algs" extension, clients MAY default to an
"ssh-rsa" signature to avoid authentication penalties."

I need to handle it this way or another so I'm thinking about contributing this feature to JSch if you consider that it's worth introducing to the project. It sounds quite doable. If not, i'll have to work around it in some other way in the application space.
Please let me know of your thoughts on this.

Best regards,
Jacek

@edit: fixed version numbers in the second sentence

@norrisjeremy
Copy link
Contributor

Hi @jgolda,

Does simply following the instructions in the FAQ to manually enable ssh-rsa not work?

Thanks,
Jeremy

@jgolda
Copy link
Author

jgolda commented Jan 5, 2023

I'm afraid it won't. The problem (or sort of) lies in com.jcraft.jsch.UserAuthPublicKey class.

  1. Around line 200 Jsch sends the initial request with value 0 (indicating, that it's only checking if the server supports the public key algorithm rsa-sha2-512).
  2. The server sends SSH_MSG_USERAUTH_PK_OK in response around line 210
  3. Around line 286 JSch sends the actual authentication request with generated signature
  4. This time the server responds with SSH_MSG_USERAUTH_FAILURE, resulting in failure.
    The problem is that JSch attempts to negotiate anything else then ssh-rsa, for some reason the server doesn't like it. I know that it's a problem with the server, but since it was noted in the RFC i thought it might be a more common issue.

I'm quite sure it will also occur in latest library version, even though i physically checked it only with 0.1.72. According to the diffs, there were no notable changes in the logic in this class between those versions. I'll double-check the bahaviour on monday.

I'm 100% sure i had ssh-rsa enabled, which is also the default in 0.1.72. In fact, the only workaround i've found was explicitly disabling rsa-sha2-512 and rsa-sha2-256 in config. Then it works like a charm, but the solution is less then ideal, since i'd have to restore algorithms manually if the client upgrades his server

@norrisjeremy
Copy link
Contributor

Hi @jgolda,

We're unlikely to approve anything that would automagically re-add ssh-rsa, since RSA/SHA1 is insecure.

Can you enable logging in JSch and send over all the logging output? That may help us to better understand what is causing an issue for you.

Thanks,
Jeremy

@jgolda
Copy link
Author

jgolda commented Jan 5, 2023

If you're not planning to approve such fix, even though it's suggested in RFC as a way of supporting legacy servers, then this issue can be closed. I'll work around the problem on application side, it shouldn't be a big deal, just thought that a fix in library might be beneficial to other users.

I think the logs won't tell you much more than the scenario in my previous comment, since the server behaves in an odd way - as if it was written with assumption that ssh-rsa is and will be the only supported algorithm, even thought the original RFC states differently. If you still need it, i'll post it on monday. If not, feel free to close this issue.

Thank you for your time :)
Jacek

@norrisjeremy
Copy link
Contributor

Hi @jgolda,

When you cited RFC 8332 section 3.3, you left out the following important sentence:

   When the new
   rsa-sha2-* algorithms have been sufficiently widely adopted to
   warrant disabling "ssh-rsa", clients MAY default to one of the new
   algorithms.

RSA/SHA1 is widely considered to be cryptographically insecure now, so we're unlikely to be convinced to reenable it by default. Additionally, JSch isn't the only SSH client that doesn't enable ssh-rsa by default either: OpenSSH has disabled it by default for awhile as well.

That said, I'm not sure I fully grasp what the issue you are seeing is, which is why I asked if you could provide a copy of the JSch logs, so that I could perhaps better understand and determine if there are any other alternative workarounds that could be implemented (or if there is perhaps even some other latent bug in JSch that is triggering the issue you are seeing).

Thanks,
Jeremy

@jgolda
Copy link
Author

jgolda commented Jan 5, 2023

Sure, i get your point about security and agree with it. I'd also rather work with servers which are up to date and implement the RFCs fully and correctly, but unfortunatelly it's not always the case

@jgolda
Copy link
Author

jgolda commented Jan 9, 2023

Connection log:
Level: 1, message: Connecting to target_hostname port target_port
Level: 1, message: Connection established
Level: 1, message: Remote version string: remote_server_name
Level: 1, message: Local version string: SSH-2.0-JSCH-0.1.72
Level: 1, message: CheckCiphers: chacha20-poly1305@openssh.com
Level: 1, message: CheckKexes: curve25519-sha256,curve25519-sha256@libssh.org,curve448-sha512
Level: 1, message: CheckSignatures: ssh-ed25519,ssh-ed448
Level: 0, message: server_host_key proposal before known_host reordering is: ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,rsa-sha2-512,rsa-sha2-256,ssh-rsa,ssh-dss
Level: 0, message: server_host_key proposal after known_host reordering is: ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,rsa-sha2-512,rsa-sha2-256,ssh-rsa,ssh-dss
Level: 1, message: SSH_MSG_KEXINIT sent
Level: 1, message: SSH_MSG_KEXINIT received
Level: 1, message: kex: server: ecdh-sha2-nistp256,ecdh-sha2-nistp384,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha256,diffie-hellman-group16-sha512,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1
Level: 1, message: kex: server: ssh-rsa,rsa-sha2-512,rsa-sha2-256,x509v3-sign-rsa
Level: 1, message: kex: server: aes256-ctr,aes256-cbc,aes192-ctr,aes192-cbc,aes128-ctr,aes128-cbc,blowfish-cbc,twofish256-cbc,twofish192-cbc,twofish128-cbc,cast128-cbc,3des-cbc
Level: 1, message: kex: server: aes256-ctr,aes256-cbc,aes192-ctr,aes192-cbc,aes128-ctr,aes128-cbc,blowfish-cbc,twofish256-cbc,twofish192-cbc,twofish128-cbc,cast128-cbc,3des-cbc
Level: 1, message: kex: server: hmac-sha2-256,hmac-sha1,hmac-sha1-96,hmac-md5,hmac-md5-96
Level: 1, message: kex: server: hmac-sha2-256,hmac-sha1,hmac-sha1-96,hmac-md5,hmac-md5-96
Level: 1, message: kex: server: none,zlib
Level: 1, message: kex: server: none,zlib
Level: 1, message: kex: server:
Level: 1, message: kex: server:
Level: 1, message: kex: client: 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,diffie-hellman-group14-sha256,ext-info-c
Level: 1, message: kex: client: ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,rsa-sha2-512,rsa-sha2-256,ssh-rsa,ssh-dss
Level: 1, message: kex: client: aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
Level: 1, message: kex: client: aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
Level: 1, message: kex: client: hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1
Level: 1, message: kex: client: hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1
Level: 1, message: kex: client: none
Level: 1, message: kex: client: none
Level: 1, message: kex: client:
Level: 1, message: kex: client:
Level: 1, message: kex: algorithm: ecdh-sha2-nistp256
Level: 1, message: kex: host key algorithm: rsa-sha2-512
Level: 1, message: kex: server->client cipher: aes128-ctr MAC: hmac-sha2-256 compression: none
Level: 1, message: kex: client->server cipher: aes128-ctr MAC: hmac-sha2-256 compression: none
Level: 1, message: SSH_MSG_KEX_ECDH_INIT sent
Level: 1, message: expecting SSH_MSG_KEX_ECDH_REPLY
Level: 1, message: ssh_rsa_verify: rsa-sha2-512 signature true
Level: 2, message: Permanently added 'target_hostname' (RSA) to the list of known hosts.
Level: 1, message: SSH_MSG_NEWKEYS sent
Level: 1, message: SSH_MSG_NEWKEYS received
Level: 1, message: SSH_MSG_SERVICE_REQUEST sent
Level: 1, message: SSH_MSG_SERVICE_ACCEPT received
Level: 1, message: Authentications that can continue: publickey,keyboard-interactive,password
Level: 1, message: Next authentication method: publickey
Level: 0, message: PubkeyAcceptedAlgorithms = ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,rsa-sha2-512,rsa-sha2-256,ssh-rsa
Level: 0, message: No server-sig-algs found, using PubkeyAcceptedAlgorithms = [ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, rsa-sha2-512, rsa-sha2-256, ssh-rsa]
Level: 0, message: rsa-sha2-512 preauth success
Level: 0, message: rsa-sha2-512 auth failure
Level: 1, message: Disconnecting from target_hostname port target_port

I think it's worth noticing, that the target server doesn't send SSH_MSG_EXT_INFO

@norrisjeremy
Copy link
Contributor

Hi @jgolda,

Is this the literal remote version string the server sent, or did you mask it?

Level: 1, message: Remote version string: remote_server_name

I also find it odd that the server seemed to support rsa-sha2-512 for the host key algorithm, but that same algorithm failed when used for user authentication:

...
Level: 1, message: kex: host key algorithm: rsa-sha2-512
...
Level: 1, message: ssh_rsa_verify: rsa-sha2-512 signature true
Level: 2, message: Permanently added 'target_hostname' (RSA) to the list of known hosts.
...
Level: 0, message: rsa-sha2-512 preauth success
Level: 0, message: rsa-sha2-512 auth failure
...

Thanks,
Jeremy

@jgolda
Copy link
Author

jgolda commented Jan 9, 2023

Nope, the remote_server_name is a replacement for the actual name. I had to replace it, since the name was nothing i could google, and giving it out might identify our client.

The second part is the thing i was trying to get through in every comment from the very beginning. I'm quite sure the server doesn't support anything except ssh-rsa and even worse, i think it doesn't support negotiation of the algorithm. It's possible that the server was implemented in the stone age, when there was nothing except ssh-rsa, even far away on the horizon. I guess the implementors simply skipped the part which determines if the server supports some algorithm and hardcoded a preauth succes, because... "Come on, why would anyone need anything better then ssh-rsa?" :D It could explain such weird behaviour and it also matches the RFC description of a legacy server's behaviour i cited in the original post.

I wasn't actually talking about implicit restoring of ssh-rsa, rather than falling back to it in case this feature (fallback) is enabled in config and the target server doesn't send the SSH_MSG_EXT_INFO (or server-sig-algs, which is inside), which could indicate that it doesn't support anything except ssh-rsa and negotiation might fail. Sorry if i didn't make it clear enough.

Best regards,
Jacek

@norrisjeremy
Copy link
Contributor

Nope, the remote_server_name is a replacement for the actual name. I had to replace it, since the name was nothing i could google, and giving it out might identify our client.

Can you provide any sort of details as to what type of server software you are dealing with?
Is it some sort of custom built SSH server that isn't publicly distributed?

The second part is the thing i was trying to get through in every comment from the very beginning. I'm quite sure the server doesn't support anything except ssh-rsa and even worse, i think it doesn't support negotiation of the algorithm. It's possible that the server was implemented in the stone age, when there was nothing except ssh-rsa, even far away on the horizon. I guess the implementors simply skipped the part which determines if the server supports some algorithm and hardcoded a preauth succes, because... "Come on, why would anyone need anything better then ssh-rsa?" :D It could explain such weird behaviour and it also matches the RFC description of a legacy server's behaviour i cited in the original post.

Well, we know that the server supports rsa-sha2-512 well enough that it uses it correctly for the host-key as I indicated above. So it seems kind of peculiar that it doesn't support it for user auth.

I wasn't actually talking about implicit restoring of ssh-rsa, rather than falling back to it in case this feature (fallback) is enabled in config and the target server doesn't send the SSH_MSG_EXT_INFO (or server-sig-algs, which is inside), which could indicate that it doesn't support anything except ssh-rsa and negotiation might fail. Sorry if i didn't make it clear enough.

That sort of behavior would seem to violate RFC 8308 section 3.1's definition of the server-sig-algs extension, since it implies the lack of this extension means it must not make any assumptions as to which algorithms it supports:

If a server does not send this extension, a client MUST NOT make any
assumptions about the server's public key algorithm support, and MAY
proceed with authentication requests using trial and error.  Note
that implementations are known to exist that apply authentication
penalties if the client attempts to use an unexpected public key
algorithm.

Additionally, RFC 8332 section 3.3 only states a server SHOULD, not MUST here, which means it's not absolutely required:

Servers that accept rsa-sha2-* signatures for client authentication
SHOULD implement the extension negotiation mechanism defined in
[RFC8308], including especially the "server-sig-algs" extension.

Best regards, Jacek

@jgolda
Copy link
Author

jgolda commented Jan 10, 2023

Can you provide any sort of details as to what type of server software you are dealing with?
Is it some sort of custom built SSH server that isn't publicly distributed?

Frankly i don't even know it myself, since i don't recognise the name and it doesn't show up in google. It might be proprietary or custom.

That sort of behavior would seem to violate RFC 8308 section 3.1's definition of the server-sig-algs extension

I believe i provided all RFC backup to support my point of view in the original post. If you disagree, please close this issue. I'm already working around this problem on the application side, so it's not a big deal for me

@norrisjeremy
Copy link
Contributor

Hi @jgolda,

Would you be able to test a build from my PR #264 from the below location and see if it works for you if when you don't hardcode JSch to only accept ssh-rsa? I.e., if you have ssh-rsa at the end of the PubkeyAcceptedAlgorithms list?

https://github.com/mwiede/jsch/suites/10561053626/artifacts/525493489

This PR has the following change applied that may help address the issue you have with this server:

    Attempt to authenticate using other signature algorithms supported by the same public key.
    
    Some servers incorrectly respond with SSH_MSG_USERAUTH_PK_OK to the
    intial auth query, but then fail the full SSH_MSG_USERAUTH_REQUEST for
    RSA keys (which can support multiple signautre algorithms).
    
    Allow the new behavior to potentially try other algorithms to be
    disabled via a new config option `try_additional_pubkey_algorithms`.
    
    Additionally, add a new config option `use_pubkey_auth_query` to allow
    skipping auth queries and skip straight to attempting full
    SSH_MSG_USERAUTH_REQUEST's.

Another user reported a server that behaves similarly to yours in #271.

Thanks,
Jeremy

@jgolda
Copy link
Author

jgolda commented Jan 30, 2023

Sorry for the delay, i thought you rejected this issue and i missed the email notification. It still doesn't work with 0.2.7, this time the server rejects the second attempt with public key and disconnects. I could work around it by setting the "enable_pubkey_auth_query", but i cannot do this on a per client basis in my app for now, so i stick with setting of ssh-rsa algorithm - i have it handled already on application side. I don't really need this feature anymore

Log:
Authentications that can continue: publickey,keyboard-interactive,password
Next authentication method: publickey
PubkeyAcceptedAlgorithms = ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,rsa-sha2-512,rsa-sha2-256,ssh-rsa
No server-sig-algs found, using PubkeyAcceptedAlgorithms = [ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, rsa-sha2-512, rsa-sha2-256, ssh-rsa]
rsa-sha2-512 preauth success
rsa-sha2-512 auth failure
rsa-sha2-256 preauth success
Disconnecting from server_hostname port port_name

And the exception thrown:
Caused by: com.jcraft.jsch.JSchException: SSH_MSG_DISCONNECT: 11 Too many failed authentication attempts
at com.jcraft.jsch.Session.read(Session.java:1259) ~[jsch-0.2.7.jar:0.2.7]
at com.jcraft.jsch.UserAuthPublicKey._start(UserAuthPublicKey.java:328) ~[jsch-0.2.7.jar:0.2.7]
at com.jcraft.jsch.UserAuthPublicKey.start(UserAuthPublicKey.java:119) ~[jsch-0.2.7.jar:0.2.7]
at com.jcraft.jsch.Session.connect(Session.java:480) ~[jsch-0.2.7.jar:0.2.7]
at com.jcraft.jsch.Session.connect(Session.java:190) ~[jsch-0.2.7.jar:0.2.7]

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

2 participants