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: Consider relaxing public key and signature matching for RSA keys in SSH_MSG_USERAUTH_REQUEST #53391

Open
stanhu opened this issue Jun 15, 2022 · 2 comments · May be fixed by golang/crypto#221
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@stanhu
Copy link

stanhu commented Jun 15, 2022

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

$ go version
go version go1.17.9 darwin/arm64

Does this issue reproduce with the latest release?

No, but if SSH server extension is implemented (golang/crypto#197), this issue will show up under certain circumstances for older clients.

What did you do?

I applied golang/crypto#197, which implements RFC 3808 (server extension negotiation), to the master branch. Then I attempted to log into a Go SSH server with an Yubikey RSA key on Ubuntu 18.04. The login failed:

ssh: signature "ssh-rsa" came in for selected algorithm "rsa-sha2-512", public key is type ssh-rsa

In https://github.com/golang/crypto/blob/793ad666bf5ec61392092b27061be9618e4e219b/ssh/server.go#L567, the SSH server performs this check:

if underlyingAlgo(algo) != sig.Format {
	authErr = fmt.Errorf("ssh: signature %q not compatible with selected algorithm %q", sig.Format, algo)
	break
}

This is a sensible check and works for most cases. However, in Ubuntu 18.04 with gpg-agent v2.2.4 and OpenSSH v7.6, logins that use an RSA key with gpg-agent will fail to login. This problem does not happen with an OpenSSH server, however.

What did you expect to see?

As the example from RFC8332 shows, here is an example SSH_MSG_USERAUTH_REQUEST message:

     byte      SSH_MSG_USERAUTH_REQUEST
     string    user name
     string    service name
     string    "publickey"
     boolean   TRUE
     string    "rsa-sha2-512"     <--- 1 - Public key algorithm name (algo) (https://datatracker.ietf.org/doc/html/rfc4252#page-8)
     string    public key blob:
         string    "ssh-rsa"      <--- 2 - Public key type (pubKey.Type())
         mpint     e
         mpint     n
     string    signature:
         string    "rsa-sha2-512" <--- 3 - Signature format (sig.Format)
         string    rsa_signature_blob

Why does this happen? Since the server advertises it supports rsa-sha2-512, the OpenSSH client will attempt to use it in the signature. However, gpg-agent v2.2.4 does not support rsa-sha2-512; this was added in v2.2.6 via gpg/gnupg@80b775b. As a result, it appears that the SSH_MSG_USERAUTH_REQUEST has rsa-sha2-512 in 1 but ssh-sha for 3.

The Go crypto library expects that 1 and 3 match. However, OpenSSH is a bit more lenient, and it only checks that 1 is an RSA algorithm (rsa-dsa, rsa-sha2-256, or rsa-sha2-512), and that this matches with an RSA key in 2. In more detail:

  1. In https://github.com/openssh/openssh-portable/blob/abd59663df37a42152e37980113ccaa405b9a282/auth2-pubkey.c#L112, sshkey_type_from_name(pkalg) returns KEY_RSA type (https://github.com/openssh/openssh-portable/blob/0f3455356bc284d7c6f4d3c1614d31161bd5dcc2/sshkey.c#L91-L94).
  2. The public key is of type KEY_RSA, so https://github.com/openssh/openssh-portable/blob/abd59663df37a42152e37980113ccaa405b9a282/auth2-pubkey.c#L127 matches.
  3. https://github.com/openssh/openssh-portable/blob/abd59663df37a42152e37980113ccaa405b9a282/auth2-pubkey.c#L200 attempts to verify the public key with the signature by calling ssh_rsa_verify in https://github.com/openssh/openssh-portable/blob/83fa3a044891887369ce8b487ce88d713a04df48/ssh-rsa.c#L222. It determines the signature format in 3.

https://datatracker.ietf.org/doc/html/rfc8332#section-3.2 speaks to the problem we're seeing here:

   If the client includes the signature field, the client MUST encode
   the same algorithm name in the signature as in
   SSH_MSG_USERAUTH_REQUEST -- either "rsa-sha2-256" or "rsa-sha2-512".
   If a server receives a mismatching request, it MAY apply arbitrary
   authentication penalties, including but not limited to authentication
   failure or disconnect.

   OpenSSH 7.2 (but not 7.2p2) incorrectly encodes the algorithm in the
   signature as "ssh-rsa" when the algorithm in SSH_MSG_USERAUTH_REQUEST
   is "rsa-sha2-256" or "rsa-sha2-512".  In this case, the signature
   does actually use either SHA-256 or SHA-512.  A server MAY, but is
   not required to, accept this variant or another variant that
   corresponds to a good-faith implementation and is considered safe to
   accept.

Technically, the spec says here that the strict match on the server side is acceptable, but the spec also says that a server may relax this match since we know that:

  1. The SSH_MSG_USERAUTH_REQUEST public key algorithm is ssh-rsa.
  2. The public key type is rsa-sha.
  3. The signature type can be rsa-sha, rsa-sha2-256, or rsa-sha2-512.
  4. The verification of the public key with the signature still must pass.

I realize this may just be covering up old bugs related to gpg-agent or OpenSSH, but that's what we're seeing in the wild.

@seankhliao seankhliao changed the title crypto/ssh: Consider relaxing public key and signature matching for RSA keys in SSH_MSG_USERAUTH_REQUEST x/crypto/ssh: Consider relaxing public key and signature matching for RSA keys in SSH_MSG_USERAUTH_REQUEST Jun 15, 2022
@gopherbot gopherbot added this to the Unreleased milestone Jun 15, 2022
@seankhliao seankhliao added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Jun 15, 2022
@seankhliao
Copy link
Member

seankhliao commented Jun 15, 2022

This could probably have been a comment on #49269
Note: OpenSSH 7.6 is from 2017-10-03 and Ubuntu 18.04 reached EOL in 2021-04 (LTS still has 1 more year of standard support + 5 years on ESM)

cc @golang/security

@stanhu
Copy link
Author

stanhu commented Jun 15, 2022

I created a new issue because the fix could be made independent of #49269 since anytime the client decides to use rsa-sha2-512, a Go SSH server may run into this mismatch. With the current master branch of the x/crypto/ssh repository, I've seeing ssh-rsa being used as the signature type.

I believe Ubuntu 18.04 LTS is supported through 2028: https://ubuntu.com/about/release-cycle. I will raise a bug report with gpg-agent there.

UPDATE: Filed https://bugs.launchpad.net/ubuntu/+source/gnupg2/+bug/1978851.

maxlazio pushed a commit to gitlabhq/gitlab-shell that referenced this issue Jun 16, 2022
When we put gitlab-sshd in production, we noticed a number of clients
using RSA keys would fail to login. The server would report:

```
ssh: signature "ssh-rsa" not compatible with selected algorithm "rsa-sha2-512"
```

This is reproducible On Ubuntu 18.04, which ships gpg-agent v2.2.4 and
OpenSSH v7.6. That version of gpg-agent does not support
`rsa-sha2-256` or `rsa-sha2-512`, but OpenSSH does. As a result,
OpenSSH specifies `rsa-sha-512` as the public key algorithm to use in
the user authentication request message, but gpg-agent includes an
`ssh-rsa` signature. OpenSSH servers tolerates this discrepancy, but
the Go implementation fails because it expects a strict match.

This commit pulls in
https://gitlab.com/gitlab-org/golang-crypto/-/merge_requests/9 to fix
the problem.

Relates to:

1. golang/go#53391
2. https://gitlab.com/gitlab-org/gitlab-shell/-/issues/587

Changelog: fixed
maxlazio pushed a commit to gitlabhq/gitlab-shell that referenced this issue Jun 16, 2022
When we put gitlab-sshd in production, we noticed a number of clients
using RSA keys would fail to login. The server would report:

```
ssh: signature "ssh-rsa" not compatible with selected algorithm "rsa-sha2-512"
```

This is reproducible on Ubuntu 18.04, which ships gpg-agent v2.2.4 and
OpenSSH v7.6. That version of gpg-agent does not support
`rsa-sha2-256` or `rsa-sha2-512`, but OpenSSH does. As a result,
OpenSSH specifies `rsa-sha-512` as the public key algorithm to use in
the user authentication request message, but gpg-agent includes an
`ssh-rsa` signature. OpenSSH servers tolerates this discrepancy, but
the Go implementation fails because it expects a strict match.

This commit pulls in
https://gitlab.com/gitlab-org/golang-crypto/-/merge_requests/9 to fix
the problem.

Relates to:

1. golang/go#53391
2. https://gitlab.com/gitlab-org/gitlab-shell/-/issues/587

Changelog: fixed
stanhu added a commit to stanhu/crypto that referenced this issue Jun 16, 2022
Buggy SSH clients, such as gpg-agent v2.2.4 and OpenSSH v7.6 shipped
in Ubuntu 18.04, may send `ssh-rsa-512` as the public key algorithm
but actually include an `rsa-sha` signature.

If RFC 3808 (extension negotiation) is implemented, these clients will
fail to authenticate with the error:

```
ssh: signature "ssh-rsa" came in for selected algorithm "rsa-sha2-512", public key is type ssh-rsa
```

According to RFC 8332 section 3.2:

If the client includes the signature field, the client MUST encode the
same algorithm name in the signature as in SSH_MSG_USERAUTH_REQUEST --
either "rsa-sha2-256" or "rsa-sha2-512".  If a server receives a
mismatching request, it MAY apply arbitrary authentication penalties,
including but not limited to authentication failure or disconnect.

...A server MAY, but is not required to, accept this variant or another
variant that corresponds to a good-faith implementation and is
considered safe to accept.

While the client is expected to do the right thing, in practice older
clients may not fully support `ssh-rsa-256` and `ssh-rsa-512`. For
example, gpg-agent v2.2.6 added support for these newer signature
types.

To accomodate these clients, relax the mat constraint: if the
`SSH_MSG_USERAUTH_REQUEST` message specifies an RSA public key
algorithm and includes an RSA public key, then allow any of the
following signature types:

- `rsa-sha-512`
- `rsa-sha-256`
- `rsa-sha`

This emulates what OpenSSH does. OpenSSH only considers that the RSA
family is specified and then verifies if the signature and public key
match.

Closes golang/go#53391
stanhu added a commit to stanhu/crypto that referenced this issue Jun 16, 2022
Buggy SSH clients, such as gpg-agent v2.2.4 and OpenSSH v7.6 shipped
in Ubuntu 18.04, may send `ssh-rsa-512` as the public key algorithm
but actually include an `rsa-sha` signature.

If RFC 3808 (extension negotiation) is implemented, these clients will
fail to authenticate with the error:

```
ssh: signature "ssh-rsa" came in for selected algorithm "rsa-sha2-512", public key is type ssh-rsa
```

According to RFC 8332 section 3.2:

If the client includes the signature field, the client MUST encode the
same algorithm name in the signature as in SSH_MSG_USERAUTH_REQUEST --
either "rsa-sha2-256" or "rsa-sha2-512".  If a server receives a
mismatching request, it MAY apply arbitrary authentication penalties,
including but not limited to authentication failure or disconnect.

...A server MAY, but is not required to, accept this variant or another
variant that corresponds to a good-faith implementation and is
considered safe to accept.

While the client is expected to do the right thing, in practice older
clients may not fully support `ssh-rsa-256` and `ssh-rsa-512`. For
example, gpg-agent v2.2.6 added support for these newer signature
types.

To accomodate these clients, relax the matching constraint: if the
`SSH_MSG_USERAUTH_REQUEST` message specifies an RSA public key
algorithm and includes an RSA public key, then allow any of the
following signature types:

- `rsa-sha-512`
- `rsa-sha-256`
- `rsa-sha`

This emulates what OpenSSH does. OpenSSH only considers that the RSA
family is specified and then verifies if the signature and public key
match.

Closes golang/go#53391
stanhu added a commit to stanhu/crypto that referenced this issue Feb 15, 2023
Buggy SSH clients, such as gpg-agent v2.2.4 and OpenSSH v7.6 shipped
in Ubuntu 18.04, may send `ssh-rsa-512` as the public key algorithm
but actually include an `rsa-sha` signature.

If RFC 3808 (extension negotiation) is implemented, these clients will
fail to authenticate with the error:

```
ssh: signature "ssh-rsa" came in for selected algorithm "rsa-sha2-512", public key is type ssh-rsa
```

According to RFC 8332 section 3.2:

If the client includes the signature field, the client MUST encode the
same algorithm name in the signature as in SSH_MSG_USERAUTH_REQUEST --
either "rsa-sha2-256" or "rsa-sha2-512".  If a server receives a
mismatching request, it MAY apply arbitrary authentication penalties,
including but not limited to authentication failure or disconnect.

...A server MAY, but is not required to, accept this variant or another
variant that corresponds to a good-faith implementation and is
considered safe to accept.

While the client is expected to do the right thing, in practice older
clients may not fully support `ssh-rsa-256` and `ssh-rsa-512`. For
example, gpg-agent v2.2.6 added support for these newer signature
types.

To accomodate these clients, relax the matching constraint: if the
`SSH_MSG_USERAUTH_REQUEST` message specifies an RSA public key
algorithm and includes an RSA public key, then allow any of the
following signature types:

- `rsa-sha-512`
- `rsa-sha-256`
- `rsa-sha`

This emulates what OpenSSH does. OpenSSH only considers that the RSA
family is specified and then verifies if the signature and public key
match.

Closes golang/go#53391
stanhu added a commit to stanhu/crypto that referenced this issue Feb 15, 2023
Buggy SSH clients, such as gpg-agent v2.2.4 and OpenSSH v7.6 shipped
in Ubuntu 18.04, may send `ssh-rsa-512` as the public key algorithm
but actually include an `rsa-sha` signature.

If RFC 3808 (extension negotiation) is implemented, these clients will
fail to authenticate with the error:

```
ssh: signature "ssh-rsa" came in for selected algorithm "rsa-sha2-512", public key is type ssh-rsa
```

According to RFC 8332 section 3.2:

If the client includes the signature field, the client MUST encode the
same algorithm name in the signature as in SSH_MSG_USERAUTH_REQUEST --
either "rsa-sha2-256" or "rsa-sha2-512".  If a server receives a
mismatching request, it MAY apply arbitrary authentication penalties,
including but not limited to authentication failure or disconnect.

...A server MAY, but is not required to, accept this variant or another
variant that corresponds to a good-faith implementation and is
considered safe to accept.

While the client is expected to do the right thing, in practice older
clients may not fully support `ssh-rsa-256` and `ssh-rsa-512`. For
example, gpg-agent v2.2.6 added support for these newer signature
types.

To accomodate these clients, relax the matching constraint: if the
`SSH_MSG_USERAUTH_REQUEST` message specifies an RSA public key
algorithm and includes an RSA public key, then allow any of the
following signature types:

- `rsa-sha-512`
- `rsa-sha-256`
- `rsa-sha`

This emulates what OpenSSH does. OpenSSH only considers that the RSA
family is specified and then verifies if the signature and public key
match.

Closes golang/go#53391
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants