crypto/ssh
Filippo Valsorda 4d399097f0 ssh: fix diffie-hellman-group-exchange g and K bounds checks
The previous code

	if gex.g.Cmp(one) != 1 && gex.g.Cmp(pMinusOne) != -1 {

deobfuscates to the classic mistake

    if g <= 1 && g >= p - 1 {

which is never true.

What the code actually intended to do is

	if gex.g.Cmp(one) != 1 || gex.g.Cmp(pMinusOne) != -1 {

or more readably and consistently with the diffieHellman method

	if gex.g.Cmp(one) <= 0 || gex.g.Cmp(pMinusOne) >= 0 {

Now, is this a security issue? The incorrect checks apply to g and k,
but not what we call Y and the spec calls f. RFC 4419 says:

   Either side MUST NOT send or accept e or f values that are not in the
   range [1, p-1].  If this condition is violated, the key exchange
   fails.  To prevent confinement attacks, they MUST accept the shared
   secret K only if 1 < K < p - 1.

Note that RFC 8268, Section 4 updates the equivalent RFC 4253 statement
(although not the RFC 4419 one) about e and f, but we are already doing
the correct full check there.

      DH Public Key values MUST be checked and both conditions:

         1 < e < p-1

         1 < f < p-1

      MUST be true.  Values not within these bounds MUST NOT be sent or
      accepted by either side.  If either one of these conditions is
      violated, then the key exchange fails.

   This simple check ensures that:

   o  The remote peer behaves properly.

   o  The local system is not forced into the two-element subgroup.

The check on K seems like a proxy for checking a number of ways to fix
the DH output (for example by manipulating g) to one of 0, 1, or -1.
This should not be meaningful to security for two reasons:

   - all parameters end up in the "transcript" hash that will get signed
     by the server's host key, and if the attacker controls the host
     key's signature, they have the ability to MitM without resorting to
     confinement attacks

   - the client secret is ephemeral, so leaking bits of it by forcing it
     into small sub-groups does not gain the attacker anything, as the
     secret does not get reused

Indeed, this is the same explanation of why it's ok not to check that p
is indeed a (safe) prime, which even OpenSSH omits. Building an
equivalent attack by manipulating p instead of g is left as an exercise
to the reader.

For the future, this is a case study in why we should not add complexity
even when it looks easy enough to do. CL 174257 added the
diffie-hellman-group-exchange kex. That introduced a data race (arguably
a security issue), which was fixed in CL 222078. Then it was too slow,
which led to CL 252337 that removed the primalty check, which required a
full analysis of whether it's safe to skip it, and checking against
other implementations. Now we find there's a bug and we have to do
another security analysis that not even the RFC bothered to do in order
to decide if it's a security issue. My decision in
https://github.com/golang/go/issues/17230#issuecomment-489163656
does not look like the right one in hindsight.

While at it, clean up the code some

   - drop useless bit size bounds logic in the server stub that get
     ignored by the rest of the function

   - make p and g local variables instead of method fields, since they
     are not persistent state (this was originally a data race which was
     fixed in CL 222078 by making Client not a pointer receiver)

Updates golang/go#17230

Change-Id: I4b1c68537109f627ccd75ec381dcfab57ce1768c
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/392015
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>
2022-03-14 23:46:39 +00:00
..
agent acme, sha3, ssh: fix the typos 2022-02-09 15:53:12 +00:00
internal/bcrypt_pbkdf ssh: support encrypted OpenSSH private keys 2020-02-04 10:40:54 +00:00
knownhosts crypto/ssh/knownhosts: fix out-of-date documentation for checkAddr 2019-01-23 08:56:48 +00:00
terminal ssh/terminal: replace with a golang.org/x/term wrapper 2020-11-16 15:36:03 +00:00
test ssh: support RSA SHA-2 (RFC8332) signatures 2021-11-15 23:45:14 +00:00
testdata ssh: support RSA SHA-2 (RFC8332) signatures 2021-11-15 23:45:14 +00:00
benchmark_test.go all: fix ineffectual assignments 2019-01-31 18:25:04 +00:00
buffer.go ssh: remove unused buffer.eof return value 2017-09-25 11:19:01 +00:00
buffer_test.go go.crypto/ssh: import gosshnew. 2014-04-09 13:57:52 -07:00
certs.go ssh: support RSA SHA-2 (RFC8332) signatures 2021-11-15 23:45:14 +00:00
certs_test.go ssh: support RSA SHA-2 (RFC8332) signatures 2021-11-15 23:45:14 +00:00
channel.go all: fix errors reported by vet, golint 2017-11-28 17:48:09 +00:00
cipher.go ssh: don't assume packet plaintext size 2021-12-02 19:23:23 +00:00
cipher_test.go ssh: don't assume packet plaintext size 2021-12-02 19:23:23 +00:00
client.go ssh: support RSA SHA-2 (RFC8332) signatures 2021-11-15 23:45:14 +00:00
client_auth.go ssh: improve error message for KeyboardInteractiveChallenge 2020-10-16 22:06:09 +00:00
client_auth_test.go ssh: accept WSAECONNABORTED in TestClientAuthMaxAuthTriesPublicKey 2022-02-09 19:56:52 +00:00
client_test.go ssh: support RSA SHA-2 (RFC8332) signatures 2021-11-15 23:45:14 +00:00
common.go ssh: add diffie-hellman-group14-sha256 kex 2022-03-14 23:46:33 +00:00
common_test.go ssh: invert algorithm choices on the server 2019-04-18 16:56:55 +00:00
connection.go ssh: fixing a small typo in connection.go 2017-05-31 07:46:08 +00:00
doc.go ssh: require host key checking in the ClientConfig 2017-03-30 15:57:35 +00:00
example_test.go crypto/ssh: add Client.Close in Dial example 2020-10-12 17:37:05 +00:00
handshake.go ssh: support RSA SHA-2 (RFC8332) signatures 2021-11-15 23:45:14 +00:00
handshake_test.go ssh: ignore MAC if AEAD ciphers negotiated 2022-03-12 13:11:42 +00:00
kex.go ssh: fix diffie-hellman-group-exchange g and K bounds checks 2022-03-14 23:46:39 +00:00
kex_test.go ssh: fix data race in dh group exchange sha256 2020-03-17 14:21:12 +00:00
keys.go ssh: support RSA SHA-2 (RFC8332) signatures 2021-11-15 23:45:14 +00:00
keys_test.go ssh: reject unencrypted keys from ParsePrivateKeyWithPassphrase 2019-12-05 16:18:47 +00:00
mac.go ssh: Add the hmac-sha2-256-etm@openssh.com algorithm 2017-02-08 15:25:40 +00:00
mempipe_test.go ssh: fix spelling of test so that it runs 2015-07-15 23:39:58 +00:00
messages.go ssh: add diffie-hellman-group-exchange-sha256 2019-06-17 13:33:40 +00:00
messages_test.go x/crypto/ssh: support more keytypes in the agent. 2016-04-25 17:01:51 +00:00
mux.go ssh: don't err out on channel request msgs to unknown channels 2020-06-02 18:02:16 +00:00
mux_test.go ssh: don't err out on channel request msgs to unknown channels 2020-06-02 18:02:16 +00:00
server.go ssh: fix typo 2022-03-07 21:11:46 +00:00
session.go ssh: add IUTF8 constant from RFC 8160 2022-03-13 00:37:12 +00:00
session_test.go ssh: support RSA SHA-2 (RFC8332) signatures 2021-11-15 23:45:14 +00:00
ssh_gss.go ssh/gss: support kerberos authentication for ssh server and client 2019-05-10 10:41:15 +00:00
ssh_gss_test.go ssh/gss: support kerberos authentication for ssh server and client 2019-05-10 10:41:15 +00:00
streamlocal.go ssh: also start forward listeners on ListenUnix 2018-05-14 16:50:30 +00:00
tcpip.go ssh: don't start goroutines handling forwarded connections until needed 2018-05-14 11:17:49 +00:00
tcpip_test.go go.crypto/ssh: import gosshnew. 2014-04-09 13:57:52 -07:00
testdata_test.go ssh: support RSA SHA-2 (RFC8332) signatures 2021-11-15 23:45:14 +00:00
transport.go ssh: ignore MAC if AEAD ciphers negotiated 2022-03-12 13:11:42 +00:00
transport_test.go ssh: fix protocol version exchange (for multi-line) 2018-01-11 10:11:23 +00:00