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

x/crypto/ssh: rsa-sha2-256/rsa-sha2-512 tracking issue #49952

Open
3 of 7 tasks
FiloSottile opened this issue Dec 3, 2021 · 10 comments
Open
3 of 7 tasks

x/crypto/ssh: rsa-sha2-256/rsa-sha2-512 tracking issue #49952

FiloSottile opened this issue Dec 3, 2021 · 10 comments
Labels
NeedsFix umbrella
Milestone

Comments

@FiloSottile
Copy link
Contributor

@FiloSottile FiloSottile commented Dec 3, 2021

OpenSSH migrated the ssh-rsa key type, which historically used the ssh-rsa signature algorithm based on SHA-1, to the new rsa-sha2-256 and rsa-sha2-512 signature algorithms.

x/crypto/ssh was not ready for the key type / signature algorithm mismatch, so it needs a few changes. Moreover, OpenSSH implemented a few mechanisms at the same time to enable the rollout, which we need to assess and expose.

This is a tracking issue for the effort in general. Here's a list of not-duplicate related issues:

We'll also need some tests against OpenSSH proper, like the crypto/tls recorded tests against OpenSSL, since https://golang.org/cl/220037 turned out to be a partial fix.

@FiloSottile FiloSottile added this to the Unreleased milestone Dec 3, 2021
@mknyszek mknyszek added the NeedsFix label Dec 3, 2021
bfritz added a commit to bfritz/homelab-bootstrap that referenced this issue Dec 7, 2021
The [alpine-chroot-install] upgrade is needed for [this commit] where
the Alpine 3.15 signing keys are added to the known key list.

Gotcha to be aware of:  The go ssh library may have trouble connecting
to the new version of openssh-server in Alpine 3.15 unless this line is
added to the `sshd_config`:

    PubkeyAcceptedAlgorithms +ssh-rsa

See golang/go#49952 .  Noticed with [k0sctl]
and the [make build_cluster] target.

[alpine-chroot-install]: https://github.com/alpinelinux/alpine-chroot-install
[k0sctl]: https://github.com/k0sproject/k0sctl
[make build_cluster]: https://github.com/bfritz/homelab-bootstrap/blob/v0.0.3/k0s/Makefile#L52-L53
[this commit]: alpinelinux/alpine-chroot-install@d4ab61f
bfritz added a commit to bfritz/homelab-bootstrap that referenced this issue Dec 7, 2021
The [alpine-chroot-install] upgrade is needed for [this commit] where
the Alpine 3.15 signing keys are added to the known key list.

Gotcha to be aware of:  The go ssh library may have trouble connecting
to the new version of openssh-server in Alpine 3.15 unless this line is
added to the `sshd_config`:

    PubkeyAcceptedAlgorithms +ssh-rsa

See golang/go#49952 .  Noticed with [k0sctl]
and the [make build_cluster] target.

[alpine-chroot-install]: https://github.com/alpinelinux/alpine-chroot-install
[k0sctl]: https://github.com/k0sproject/k0sctl
[make build_cluster]: https://github.com/bfritz/homelab-bootstrap/blob/v0.0.3/k0s/Makefile#L52-L53
[this commit]: alpinelinux/alpine-chroot-install@d4ab61f
@owenthereal
Copy link

@owenthereal owenthereal commented Mar 3, 2022

👋 I ran into this issue with my project: owenthereal/upterm#93 (comment). I'm wondering whether there is anything I could help.

@gopherbot
Copy link

@gopherbot gopherbot commented Mar 14, 2022

Change https://go.dev/cl/392355 mentions this issue: ssh: don't advertise rsa-sha2 algorithms if we can't use them

@gopherbot
Copy link

@gopherbot gopherbot commented Mar 14, 2022

Change https://go.dev/cl/392354 mentions this issue: ssh: deprecate and replace SigAlgo constants

@gopherbot
Copy link

@gopherbot gopherbot commented Mar 14, 2022

Change https://go.dev/cl/392394 mentions this issue: ssh: support rsa-sha2-256/512 for client authentication (client-side)

pete-woods pushed a commit to CircleCI-Public/golang-crypto that referenced this issue Mar 14, 2022
RFC 8332, Section 2 sets up two overlapping namespaces: public key
formats and public key algorithms.

* The formats are what we currently have KeyAlgo constants for, and they
  appear in PublicKey.Type.

* The algorithms are the set of both KeyAlgo and SigAlgo constants, and
  they appear in Signature.Format (amongst other places).

This is incoherent, because that means Signature.Format can be both a
KeyAlgo (like KeyAlgoECDSA256) or a SigAlgo (like SigAlgoRSASHA2256).

One solution would be to duplicate all the KeyAlgo constants into the
SigAlgo namespace, but that would be confusing because applications are
currently using KeyAlgos where they'd be supposed to use the new
SigAlgos (while we can't deprecate the KeyAlgos because they are still
necessary for the PublicKey.Type namespace).

Instead, drop the separate namespaces, and use KeyAlgos throughout.
There are simply some KeyAlgos that can't be a PublicKey.Type.

Take the opportunity to fix the stuttering SHA22565/SHA2512 names. It's
totally ok to call those hashes SHA-256 and SHA-512 without the family
infix.

For golang/go#49952

Change-Id: Ia1fce3912a7e60aa70a88f75ed311be331fd19d5
pete-woods pushed a commit to CircleCI-Public/golang-crypto that referenced this issue Mar 14, 2022
The server implementation looks at the HostKeys to advertise and
negotiate host key signature algorithms. A fundamental issue of the
Signer and AlgorithmSigner interfaces is that they don't expose the
supported signature algorithms, so really the server has to guess.

Currently, it would guess exclusively based on the PublicKey.Type,
regardless of whether the host key implemented AlgorithmSigner. This
means that a legacy Signer that only supports ssh-rsa still led the
server to negotiate rsa-sha2 algorithms. The server would then fail to
find a suitable host key to make the signature and crash.

This won't happen if only Signers from this package are used, but if a
custom Signer that doesn't support SignWithAlgorithm() but returns
"ssh-rsa" from PublicKey().Type() is used as a HostKey, the server is
vulnerable to DoS.

The only workable rules to determine what to advertise seems to be:

   1. a pure Signer will always Sign with the PublicKey.Type

   2. an AlgorithmSigner supports all algorithms associated with the
      PublicKey.Type

Rule number two means that we can't add new supported algorithms in the
future, which is not great, but it's too late to fix that.

rsaSigner was breaking rule number one, and although it would have been
fine where it's used, I didn't want to break our own interface contract.

It's unclear why we had separate test key entries for rsa-sha2
algorithms, since we can use the ssh-rsa key for those. The only test
that used them, TestCertTypes, seemed broken: the init was actually
failing at making the corresponding signers rsaSigners, and indeed the
test for the SHA-256 signer expected and checked a SHA-512 signature.

Pending CVE
For golang/go#49952

Change-Id: Ie658eefcadd87906e63fc7faae8249376aa96c79
pete-woods pushed a commit to CircleCI-Public/golang-crypto that referenced this issue Mar 14, 2022
CL 220037 had implemented support for host authentication using
rsa-sha2-256/512, but not client public key authentication. OpenSSH
disabled the SHA-1 based ssh-rsa by default in version 8.8 (after
pre-announcing it in versions 8.2, 8.3, 8.4, 8.5, 8.6, and 8.7) although
some distributions re-enable it. GitHub will start rejecting ssh-rsa for
keys uploaded before November 2, 2021 on March 15, 2022.

https://github.blog/2021-09-01-improving-git-protocol-security-github/

The server side already worked, as long as the client selected one of
the SHA-2 algorithms, because the signature flowed freely to Verify.
There was however nothing verifying that the signature algorithm matched
the advertised one. The comment suggested the check was being performed,
but it got lost back in CL 86190043. Not a security issue because the
signature had to pass the callback's Verify method regardless, and both
values were checked to be acceptable.

Tested with OpenSSH 8.8 configured with "PubkeyAcceptedKeyTypes -ssh-rsa"
and no application-side changes.

The Signers returned by ssh/agent (when backed by an agent client)
didn't actually implement AlgorithmSigner but ParameterizedSigner, an
interface defined in an earlier version of CL 123955.

Changed the type in TestClientAuthErrorList just so we wouldn't get 3
errors for one key.

Fixes golang/go#39885
For golang/go#49952

Change-Id: I13b41db8041f1112a70f106c55f077b904b12cb8
pete-woods pushed a commit to CircleCI-Public/golang-crypto that referenced this issue Mar 14, 2022
RFC 8332, Section 2 sets up two overlapping namespaces: public key
formats and public key algorithms.

* The formats are what we currently have KeyAlgo constants for, and they
  appear in PublicKey.Type.

* The algorithms are the set of both KeyAlgo and SigAlgo constants, and
  they appear in Signature.Format (amongst other places).

This is incoherent, because that means Signature.Format can be both a
KeyAlgo (like KeyAlgoECDSA256) or a SigAlgo (like SigAlgoRSASHA2256).

One solution would be to duplicate all the KeyAlgo constants into the
SigAlgo namespace, but that would be confusing because applications are
currently using KeyAlgos where they'd be supposed to use the new
SigAlgos (while we can't deprecate the KeyAlgos because they are still
necessary for the PublicKey.Type namespace).

Instead, drop the separate namespaces, and use KeyAlgos throughout.
There are simply some KeyAlgos that can't be a PublicKey.Type.

Take the opportunity to fix the stuttering SHA22565/SHA2512 names. It's
totally ok to call those hashes SHA-256 and SHA-512 without the family
infix.

For golang/go#49952

Change-Id: Ia1fce3912a7e60aa70a88f75ed311be331fd19d5
pete-woods pushed a commit to CircleCI-Public/golang-crypto that referenced this issue Mar 14, 2022
The server implementation looks at the HostKeys to advertise and
negotiate host key signature algorithms. A fundamental issue of the
Signer and AlgorithmSigner interfaces is that they don't expose the
supported signature algorithms, so really the server has to guess.

Currently, it would guess exclusively based on the PublicKey.Type,
regardless of whether the host key implemented AlgorithmSigner. This
means that a legacy Signer that only supports ssh-rsa still led the
server to negotiate rsa-sha2 algorithms. The server would then fail to
find a suitable host key to make the signature and crash.

This won't happen if only Signers from this package are used, but if a
custom Signer that doesn't support SignWithAlgorithm() but returns
"ssh-rsa" from PublicKey().Type() is used as a HostKey, the server is
vulnerable to DoS.

The only workable rules to determine what to advertise seems to be:

   1. a pure Signer will always Sign with the PublicKey.Type

   2. an AlgorithmSigner supports all algorithms associated with the
      PublicKey.Type

Rule number two means that we can't add new supported algorithms in the
future, which is not great, but it's too late to fix that.

rsaSigner was breaking rule number one, and although it would have been
fine where it's used, I didn't want to break our own interface contract.

It's unclear why we had separate test key entries for rsa-sha2
algorithms, since we can use the ssh-rsa key for those. The only test
that used them, TestCertTypes, seemed broken: the init was actually
failing at making the corresponding signers rsaSigners, and indeed the
test for the SHA-256 signer expected and checked a SHA-512 signature.

Pending CVE
For golang/go#49952

Change-Id: Ie658eefcadd87906e63fc7faae8249376aa96c79
pete-woods pushed a commit to CircleCI-Public/golang-crypto that referenced this issue Mar 14, 2022
CL 220037 had implemented support for host authentication using
rsa-sha2-256/512, but not client public key authentication. OpenSSH
disabled the SHA-1 based ssh-rsa by default in version 8.8 (after
pre-announcing it in versions 8.2, 8.3, 8.4, 8.5, 8.6, and 8.7) although
some distributions re-enable it. GitHub will start rejecting ssh-rsa for
keys uploaded before November 2, 2021 on March 15, 2022.

https://github.blog/2021-09-01-improving-git-protocol-security-github/

The server side already worked, as long as the client selected one of
the SHA-2 algorithms, because the signature flowed freely to Verify.
There was however nothing verifying that the signature algorithm matched
the advertised one. The comment suggested the check was being performed,
but it got lost back in CL 86190043. Not a security issue because the
signature had to pass the callback's Verify method regardless, and both
values were checked to be acceptable.

Tested with OpenSSH 8.8 configured with "PubkeyAcceptedKeyTypes -ssh-rsa"
and no application-side changes.

The Signers returned by ssh/agent (when backed by an agent client)
didn't actually implement AlgorithmSigner but ParameterizedSigner, an
interface defined in an earlier version of CL 123955.

Updates golang/go#49269
Fixes golang/go#39885
For golang/go#49952

Change-Id: I13b41db8041f1112a70f106c55f077b904b12cb8
gopherbot pushed a commit to golang/crypto that referenced this issue Mar 14, 2022
RFC 8332, Section 2 sets up two overlapping namespaces: public key
formats and public key algorithms.

* The formats are what we currently have KeyAlgo constants for, and they
  appear in PublicKey.Type.

* The algorithms are the set of both KeyAlgo and SigAlgo constants, and
  they appear in Signature.Format (amongst other places).

This is incoherent, because that means Signature.Format can be both a
KeyAlgo (like KeyAlgoECDSA256) or a SigAlgo (like SigAlgoRSASHA2256).

One solution would be to duplicate all the KeyAlgo constants into the
SigAlgo namespace, but that would be confusing because applications are
currently using KeyAlgos where they'd be supposed to use the new
SigAlgos (while we can't deprecate the KeyAlgos because they are still
necessary for the PublicKey.Type namespace).

Instead, drop the separate namespaces, and use KeyAlgos throughout.
There are simply some KeyAlgos that can't be a PublicKey.Type.

Take the opportunity to fix the stuttering SHA22565/SHA2512 names. It's
totally ok to call those hashes SHA-256 and SHA-512 without the family
infix.

For golang/go#49952

Change-Id: Ia1fce3912a7e60aa70a88f75ed311be331fd19d5
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/392354
Trust: Filippo Valsorda <filippo@golang.org>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
gopherbot pushed a commit to golang/crypto that referenced this issue Mar 14, 2022
The server implementation looks at the HostKeys to advertise and
negotiate host key signature algorithms. A fundamental issue of the
Signer and AlgorithmSigner interfaces is that they don't expose the
supported signature algorithms, so really the server has to guess.

Currently, it would guess exclusively based on the PublicKey.Type,
regardless of whether the host key implemented AlgorithmSigner. This
means that a legacy Signer that only supports ssh-rsa still led the
server to negotiate rsa-sha2 algorithms. The server would then fail to
find a suitable host key to make the signature and crash.

This won't happen if only Signers from this package are used, but if a
custom Signer that doesn't support SignWithAlgorithm() but returns
"ssh-rsa" from PublicKey().Type() is used as a HostKey, the server is
vulnerable to DoS.

The only workable rules to determine what to advertise seems to be:

   1. a pure Signer will always Sign with the PublicKey.Type

   2. an AlgorithmSigner supports all algorithms associated with the
      PublicKey.Type

Rule number two means that we can't add new supported algorithms in the
future, which is not great, but it's too late to fix that.

rsaSigner was breaking rule number one, and although it would have been
fine where it's used, I didn't want to break our own interface contract.

It's unclear why we had separate test key entries for rsa-sha2
algorithms, since we can use the ssh-rsa key for those. The only test
that used them, TestCertTypes, seemed broken: the init was actually
failing at making the corresponding signers rsaSigners, and indeed the
test for the SHA-256 signer expected and checked a SHA-512 signature.

Pending CVE
For golang/go#49952

Change-Id: Ie658eefcadd87906e63fc7faae8249376aa96c79
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/392355
Trust: Filippo Valsorda <filippo@golang.org>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
gopherbot pushed a commit to golang/crypto that referenced this issue Mar 14, 2022
CL 220037 had implemented support for host authentication using
rsa-sha2-256/512, but not client public key authentication. OpenSSH
disabled the SHA-1 based ssh-rsa by default in version 8.8 (after
pre-announcing it in versions 8.2, 8.3, 8.4, 8.5, 8.6, and 8.7) although
some distributions re-enable it. GitHub will start rejecting ssh-rsa for
keys uploaded before November 2, 2021 on March 15, 2022.

https://github.blog/2021-09-01-improving-git-protocol-security-github/

The server side already worked, as long as the client selected one of
the SHA-2 algorithms, because the signature flowed freely to Verify.
There was however nothing verifying that the signature algorithm matched
the advertised one. The comment suggested the check was being performed,
but it got lost back in CL 86190043. Not a security issue because the
signature had to pass the callback's Verify method regardless, and both
values were checked to be acceptable.

Tested with OpenSSH 8.8 configured with "PubkeyAcceptedKeyTypes -ssh-rsa"
and no application-side changes.

The Signers returned by ssh/agent (when backed by an agent client)
didn't actually implement AlgorithmSigner but ParameterizedSigner, an
interface defined in an earlier version of CL 123955.

Updates golang/go#49269
Fixes golang/go#39885
For golang/go#49952

Change-Id: I13b41db8041f1112a70f106c55f077b904b12cb8
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/392394
Trust: Filippo Valsorda <filippo@golang.org>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
@pete-woods
Copy link

@pete-woods pete-woods commented Mar 15, 2022

Should this issue (and others), be marked resolved now?

@FiloSottile
Copy link
Contributor Author

@FiloSottile FiloSottile commented Mar 15, 2022

Almost but not quite, we should also implement server-sig-algs on the server side before we can claim we're done.

Then we can open follow-up issues for adding OpenSSH recorded tests, extending the AlgorithmSigner interface (with another interface upgrade) to allow advertising specific supported algorithms and their preference order, and finally to disable SHA-1 by default throughout (making sure it's possible to turn it back on at least for a bit, which will be complex).

@gopherbot
Copy link

@gopherbot gopherbot commented Mar 15, 2022

Change https://go.dev/cl/392974 mentions this issue: ssh: support rsa-sha2-256/512 for client certificates

gopherbot pushed a commit to golang/crypto that referenced this issue Mar 15, 2022
The server-sig-algs logic was not working for certificate algorithms.
Follow-up on CL 392394.

Tested with OpenSSH 8.8 configured with

    PubkeyAcceptedKeyTypes -ssh-rsa-cert-v01@openssh.com

Updates golang/go#39885
For golang/go#49952

Change-Id: Ic230dd6f98e96b7938acbd0128ab37d33b70abe5
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/392974
Trust: Filippo Valsorda <filippo@golang.org>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
jorgemarey pushed a commit to jorgemarey/crypto that referenced this issue May 30, 2022
The server-sig-algs logic was not working for certificate algorithms.
Follow-up on CL 392394.

Tested with OpenSSH 8.8 configured with

    PubkeyAcceptedKeyTypes -ssh-rsa-cert-v01@openssh.com

Updates golang/go#39885
For golang/go#49952

Change-Id: Ic230dd6f98e96b7938acbd0128ab37d33b70abe5
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/392974
Trust: Filippo Valsorda <filippo@golang.org>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
@cipherboy
Copy link

@cipherboy cipherboy commented Jun 6, 2022

@FiloSottile I believe a fifth part is also missing, which is allowing x/crypto/ssh based CAs to sign keys with these algorithms? Per documentation it appears the new types aren't enabled for SSH Certificate usage. This prohibits us from signing SSH certificates with these newer types, based on my read of the code.

Is this tracked elsewhere or should I file a new issue for it so it can be tracked here?

@FiloSottile
Copy link
Contributor Author

@FiloSottile FiloSottile commented Jun 9, 2022

@cipherboy What you describe is tracked by #36261, and would be resolved by #52132.

By the way, "CertAlgoRSASHA256v01 and CertAlgoRSASHA512v01 can't appear as a Certificate.Type (or PublicKey.Type)" doesn't mean they can't be used for signing, but means that the certificate type will still be CertAlgoRSAv01, the same way as a KeyAlgoRSA public key generates KeyAlgoRSASHA256/512 signatures.

It's all a bit complicated, but we'll add an example as part of #52132.

@cipherboy
Copy link

@cipherboy cipherboy commented Jun 9, 2022

Thanks @FiloSottile for the pointers! Reading that after reading the cert spec format again makes sense to me how that'd work.

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

No branches or pull requests

6 participants