crypto/tls: reject low-order Curve25519 points

The RFC recommends checking the X25519 output to ensure it's not the
zero value, to guard against peers trying to remove contributory
behavior.

In TLS there should be enough transcript involvement to mitigate any
attack, and the RSA key exchange would suffer from the same issues by
design, so not proposing a backport.

See #31846

Change-Id: I8e657f8ee8aa72c3f8ca3b124555202638c53f5e
Reviewed-on: https://go-review.googlesource.com/c/go/+/183039
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
diff --git a/src/crypto/tls/key_schedule.go b/src/crypto/tls/key_schedule.go
index 3cd6e82..83e5480 100644
--- a/src/crypto/tls/key_schedule.go
+++ b/src/crypto/tls/key_schedule.go
@@ -7,6 +7,7 @@
 import (
 	"crypto/elliptic"
 	"crypto/hmac"
+	"crypto/subtle"
 	"errors"
 	"golang.org/x/crypto/cryptobyte"
 	"golang.org/x/crypto/curve25519"
@@ -193,8 +194,16 @@
 	if len(peerPublicKey) != 32 {
 		return nil
 	}
+
 	var theirPublicKey, sharedKey [32]byte
 	copy(theirPublicKey[:], peerPublicKey)
 	curve25519.ScalarMult(&sharedKey, &p.privateKey, &theirPublicKey)
+
+	// Check for low-order inputs. See RFC 8422, Section 5.11.
+	var allZeroes [32]byte
+	if subtle.ConstantTimeCompare(allZeroes[:], sharedKey[:]) == 1 {
+		return nil
+	}
+
 	return sharedKey[:]
 }