golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
123.46k stars 17.59k forks source link

x/crypto/ssh: support RSA SHA-2 host key signatures #37278

Closed hansnielsen closed 2 years ago

hansnielsen commented 4 years ago

What version of Go are you using (go version)?

$ go version
1.13.8

Version of x/crypto: 1d94cc7ab1c630336ab82ccb9c9cda72a875c382

Does this issue reproduce with the latest release?

Yes.

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
n/a

What did you do?

I tried to connect to an OpenSSH 8.2 server with the ssh-rsa host key algorithm disabled on the server. I also tried to run an x/crypto/ssh server and connect from an OpenSSH client with ssh-rsa disabled. Lastly, I tried to sign a host certificate with ssh.Certificate.SignCert with a SHA-2 based signature.

What did you expect to see?

I expected the RSA host key and certificate to validate successfully with the new SHA-2 based signatures introduced in RFC 8332. I also expected to be able to sign host certificates and have them automatically received a SHA-2 based signature.

OpenSSH has already deprecated ssh-rsa (i.e. SHA-1 based) signatures in host certificates in version 8.2 because of safety reasons. They can still be used by the host key algorithm must be manually specified.

What did you see instead?

I was unable to connect either as a server or a client if ssh-rsa wasn't enabled while using RSA host keys or host certificates. I was able to sign a certificate with the AlgorithmSigner wrapper approach (i.e. by forcefully overriding Sign) proposed by @stoggi in #36261, but it's not a great experience for users.

hansnielsen commented 4 years ago

I spent some time hacking away at a solution for this and believe I have something largely ready to make a CL from: https://github.com/hansnielsen/golang-x-crypto/compare/master...hans-rsa-sha2-support

The main change is that when given an ssh-rsa-type key or an RSA crypto.Signer (and not a custom ssh.Signer), the code will automatically register the ssh-rsa, rsa-sha2-256, and rsa-sha2-512 host key algorithms for use. This means that for users who haven't specified explicit algorithm preferences, they'll get the new SHA-2 based signatures just by updating. There shouldn't be any external-facing changes beyond algorithm support and the certificate signing choice mentioned below.

The approach OpenSSH chose for these new signature types is somewhat interesting: they have the same key type (ssh-rsa) but different signature algorithms. This makes it slightly tricky to integrate while keeping the existing tests working. There's a little more explicit special-casing of the RSA SHA-2 signature family than I'd like.

The one main choice I made in here (beyond just adding support for the new signature types) is that certificates now default to rsa-sha2-512 instead of ssh-rsa. I think given the already-deprecated nature of ssh-rsa plus the reasonable threat model for host certificates, this is the correct choice. The "wrapped AlgorithmSigner" approach can still be used to force an RSA SHA-1 signature and there's no need to encourage this.

Feedback welcome! If the approach in the code above looks good, I'll work on submitting a CL.

josharian commented 4 years ago

cc @hanwen @FiloSottile

FiloSottile commented 4 years ago

Sounds good on both adding the algorithms and changing the certificate default.

OpenSSH 8.2 already stopped supporting ssh-rsa signed certificates, right?

alex commented 4 years ago

Only for host certificates I think, client certs still can use it.

hansnielsen commented 4 years ago

I considered removing the SHA-1 RSA signature for host certs but wanted to keep this issue to algorithm addition. There are some choices in the client host key algorithm list that are probably worth revisiting as well and it’d probably be best to handle that as one issue.

FiloSottile commented 4 years ago

How long has OpenSSH supported rsa-sha2-512 certificates?

hansnielsen commented 4 years ago

OpenSSH 7.3 was the first version with rsa-sha2-512 certificate support, released on 2016-08-01. Ubuntu xenial stands out as being the largest distro that's still on 7.2 with backported security fixes.

alex commented 4 years ago

I always regret asking things like this, but surely support non-SHA1 signature algorithms is as deserving of a security backport as an actual CVE?

gopherbot commented 4 years ago

Change https://golang.org/cl/220037 mentions this issue: ssh: support RSA SHA-2 (RFC8332) signatures

rsc commented 4 years ago

Based on the discussion above, this seems like a likely accept.

rsc commented 4 years ago

No change in consensus, so accepted.

awly commented 4 years ago

Looks like https://go-review.googlesource.com/c/crypto/+/220037 has had no progress since Feb 20th. Since everyone seems to agree on the change, @hansnielsen @FiloSottile do you have the time to finish that CL review?

This is causing teleport some interop problems with newer openssh versions.

SwampDragons commented 4 years ago

This issue is hitting us over in Packer at https://github.com/hashicorp/packer/issues/8609. We use the ssh client, generating the Auth method first by calling ParsePrivateKey and then feeding that signer into the PublicKeys method to retrieve the publickeycallback. code: https://github.com/hashicorp/packer/blob/master/helper/communicator/config.go#L320-L324

I can create my own algorithm signer to set the algorithm and call the wrappedSigner's SignWithAlgorithm, but it doesn't work with the proposed change at https://go-review.googlesource.com/c/crypto/+/220037 unless the publickeycallback is also modified, because it's still sending the key type as the algorithm, in this case "ssh-rsa".

By hardcoding lines https://github.com/golang/crypto/blob/75b288015ac94e66e3d6715fb68a9b41bf046ec2/ssh/client_auth.go#L218 and https://github.com/golang/crypto/blob/75b288015ac94e66e3d6715fb68a9b41bf046ec2/ssh/client_auth.go#L232 to SigAlgoRSASHA2256, I can force this to work to connect to an ssh server that doesn't allow the "ssh-rsa" algorithm, but obviously this isn't a viable patch for the module.

This is my first time doing a real dive into this library so I'm wondering if anyone else on this thread has an instinct about how to extend the ssh.PublicKeys() method to make it work for AlgorithmSigners that are actually using custom algorithms.

awly commented 4 years ago

I tried working around this by implementing a custom ssh.AlgorithmSigner around an ssh.Signer (which is derived from an SSH certificate). You can sign new certificates using a CA this way and it seems to work fine with OpenSSH.

However, you can't use such signers for actual SSH handshakes against a Go SSH server, because of https://github.com/golang/crypto/blob/75b288015ac94e66e3d6715fb68a9b41bf046ec2/ssh/server.go#L556-L564. That's a hardcoded check for algorithms supported in handshake signatures. So, without https://go-review.googlesource.com/c/crypto/+/220037, you can only get cert signing to work.

For reference, here's our workaround for certs: https://github.com/gravitational/teleport/pull/3777/files#diff-193b31b40b2b216b00568f93daa82603

SwampDragons commented 4 years ago

Turns out my particular client key handling needs aren't actually directly relevant to this patch, though the underlying "this module is having some problems with handling rsa sha-2 algorithms" is the same -- I think it needs its own GH issue. I'll work on setting up my own case and my own patch suggestion 😬

dustymabe commented 4 years ago

In order to workaround this issue I tried to use an ecdsa key instead, which worked fine until we hit a brick wall because AWS only supports RSA keys.

Any chance we can increase the priority of the code review in https://go-review.googlesource.com/c/crypto/+/220037/ ?

FiloSottile commented 4 years ago

Yes, I plan to get to it this week.

On Tue, Oct 6, 2020 at 3:59 PM Dusty Mabe notifications@github.com wrote:

In order to workaround this issue I tried to use an ecdsa key instead https://github.com/coreos/coreos-assembler/pull/1749, which worked fine until we hit a brick wall because AWS only supports RSA keys https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html#how-to-generate-your-own-key-and-import-it-to-aws .

Any chance we can increase the priority of the code review in https://go-review.googlesource.com/c/crypto/+/220037/ ?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/golang/go/issues/37278#issuecomment-704287991, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAJLETV5T6CYFTTKYBT6XZ3SJMPCJANCNFSM4KW5GR3A .

SwampDragons commented 4 years ago

When you look at this one, if you have time to take a look at a related patch over here: https://github.com/golang/go/issues/39885 that'd be super rad

nathanj commented 3 years ago

I ran into this issue on a new install of Fedora 33. ssh-rsa is disabled by default now, so I was not able to connect to our golang ssh server.

The ssh error message for googleability: debug1: send_pubkey_test: no mutual signature algorithm

Workarounds at https://bugzilla.redhat.com/show_bug.cgi?id=1884920 , but it would be nice if fixed in golang.

dustymabe commented 3 years ago

Hey @FiloSottile - friendly ping. Are there still plans to push https://go-review.googlesource.com/c/crypto/+/220037/ forward?

Snawoot commented 3 years ago

This issue makes Go SSH servers with RSA hostkey unusable with SSH clients having hardened configuration w/o insecure algorithms enabled. E.g. with following .ssh/config:

Host *
    Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr,chacha20-poly1305@openssh.com
    KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
    HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ssh-ed25519,rsa-sha2-256,rsa-sha2-512
    MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512
josebalius commented 3 years ago

Are there any further updates on this?

asciifaceman commented 3 years ago

Is there currently no reasonable way to do rsa-sha2-256 host key signing in golang? This was signed off on and then kind of died

josebalius commented 3 years ago

I pinged @FiloSottile the other day on Slack. He mentioned it is on his radar to look at soon. He said he needs get back into the crypto/ssh pkg and hopefully take this to the finish line. So hopefully we'll see progress soon! 🙏

zrait commented 3 years ago

It's not clear to me that @hansnielsen is still actively working on this issue as @rolandshoemaker made some requests on August 23rd.

If @hansnielsen is not actively working on this, could someone from the golang security team take this over and make the last few changes needed to integrate it?

Certificate signing for RSA keys has been incompatible with the default settings in OpenSSH since 8.2 (released in February 2020!), and OpenSSH claims they are disabling SHA1 for RSA keys in the next release which will break all non-cert uses of RSA keys as well. This kind of breakage seems fairly unacceptable for a package unless it's considered unmaintained.

hansnielsen commented 3 years ago

I'm still here (and active on the Gerrit changelist)! Hopefully we'll figure out the last few tweaks to get this merged soon.

SURA907 commented 2 years ago

Is there a rough timetable for this? Thanks

Wu-yikun commented 2 years ago

The new version of Git for Windows uses OpenSSH version 8.8, which uses THE RSA-SHA2 algorithm by default. However, the Golang SSH library used by Gitee uses the RSA-SHA1 algorithm, so the public key authentication fails.

Add the following information to the config file under ~/.ssh/ :

Host gitee.com 
HostkeyAlgorithms +ssh-rsa 
PubkeyAcceptedAlgorithms +ssh-rsa
antoinedeschenes commented 2 years ago

GitHub drops RSA with SHA-1 signatures as well. https://github.blog/2021-09-01-improving-git-protocol-security-github/

pinpox commented 2 years ago

Are there any workarounds for this on the client side? Here is a minimal example code to reproduce the issue. The linked code errors with:

$ go run main.go
2021/11/10 20:41:23 unable to connect: ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain
exit status 1

The sshd logs show

Nov 10 20:46:39 ahorn sshd[1357046]: userauth_pubkey: key type ssh-rsa not in PubkeyAcceptedAlgorithms [preauth]
Nov 10 20:46:39 ahorn sshd[1357046]: Connection closed by authenticating user pinpox ::1 port 40968 [preauth]

Using the same key with ssh -i /path/to/key localhost works perfectly

josebalius commented 2 years ago

The only workaround right now is to use a forked crypto pkg and apply the changeset in the linked PR. It's how we are using it at the moment.

pinpox commented 2 years ago

changeset in the linked PR

Sorry to ask, but which PR do you mean? Sidebar shows:

Linked pull requests
None yet
josebalius commented 2 years ago

@pinpox https://golang.org/cl/220037

fcharlie commented 2 years ago

In fact, this Issue should be reopened. Since https://golang.org/cl/220037 does not implement server-sig-algs, OpenSSH will not choose the local RSA Key because it does not know whether the server supports rsa-sha2- 256/rsa-sha2-512

pinpox commented 2 years ago

In fact, this Issue should be reopened. Since https://golang.org/cl/220037 does not implement server-sig-algs, OpenSSH will not choose the local RSA Key because it does not know whether the server supports rsa-sha2- 256/rsa-sha2-512

I can confirm the error can still be reproduced with the code linked above.

fcharlie commented 2 years ago

In fact, this Issue should be reopened. Since https://golang.org/cl/220037 does not implement server-sig-algs, OpenSSH will not choose the local RSA Key because it does not know whether the server supports rsa-sha2- 256/rsa-sha2-512

I can confirm the error can still be reproduced with the code linked above.

PR: https://github.com/golang/crypto/pull/197 fixed.

mukundjnathan commented 2 years ago

I have the latest x/crypto. I am using a user cert that is based on rsa generated using ssh-keygen with no options. My ssh client is set to use the agent auth.
If I supply the id_ecdsa public key to generate the user cert everything works. Kex match etc. If I supply id_rsa.pub I get the error you are all seeing.
If this fix is in (merged..), I expected it to work but no. (The cert works fine if I use Openssh via command line) Is there any configuration on the Client side that will help. ?