aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeal Patel <nealpatel@google.com>2025-11-19 13:35:12 -0500
committerGopher Robot <gobot@golang.org>2025-11-19 11:28:37 -0800
commite79546e28b85ea53dd37afe1c4102746ef553b9c (patch)
tree1fea6dd50a03f22132077b4a32efd929fbc697b0
parentf91f7a7c31bf90b39c1de895ad116a2bacc88748 (diff)
downloadgo-x-crypto-e79546e28b85ea53dd37afe1c4102746ef553b9c.tar.xz
ssh: curb GSSAPI DoS risk by limiting number of specified OIDs
Previously, an attacker could specify an integer up to 0xFFFFFFFF that would directly allocate memory despite the observability of the rest of the payload. This change places a hard cap on the amount of mechanisms that can be specified and encoded in the payload. Additionally, it performs a small sanity check to deny payloads whose stated size is contradictory to the observed payload. Thank you to Jakub Ciolek for reporting this issue. Fixes CVE-2025-58181 Fixes golang/go#76363 Change-Id: I0307ab3e906a3f2ae763b5f9f0310f7073f84485 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/721961 Auto-Submit: Roland Shoemaker <roland@golang.org> Reviewed-by: Damien Neil <dneil@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
-rw-r--r--ssh/ssh_gss.go8
-rw-r--r--ssh/ssh_gss_test.go31
2 files changed, 38 insertions, 1 deletions
diff --git a/ssh/ssh_gss.go b/ssh/ssh_gss.go
index 24bd7c8..a6249a1 100644
--- a/ssh/ssh_gss.go
+++ b/ssh/ssh_gss.go
@@ -106,6 +106,13 @@ func parseGSSAPIPayload(payload []byte) (*userAuthRequestGSSAPI, error) {
if !ok {
return nil, errors.New("parse uint32 failed")
}
+ // Each ASN.1 encoded OID must have a minimum
+ // of 2 bytes; 64 maximum mechanisms is an
+ // arbitrary, but reasonable ceiling.
+ const maxMechs = 64
+ if n > maxMechs || int(n)*2 > len(rest) {
+ return nil, errors.New("invalid mechanism count")
+ }
s := &userAuthRequestGSSAPI{
N: n,
OIDS: make([]asn1.ObjectIdentifier, n),
@@ -122,7 +129,6 @@ func parseGSSAPIPayload(payload []byte) (*userAuthRequestGSSAPI, error) {
if rest, err = asn1.Unmarshal(desiredMech, &s.OIDS[i]); err != nil {
return nil, err
}
-
}
return s, nil
}
diff --git a/ssh/ssh_gss_test.go b/ssh/ssh_gss_test.go
index 39a1112..9e3ea8c 100644
--- a/ssh/ssh_gss_test.go
+++ b/ssh/ssh_gss_test.go
@@ -17,6 +17,37 @@ func TestParseGSSAPIPayload(t *testing.T) {
}
}
+func TestParseDubiousGSSAPIPayload(t *testing.T) {
+ for _, tc := range []struct {
+ name string
+ payload []byte
+ wanterr bool
+ }{
+ {
+ "num mechanisms is unrealistic",
+ []byte{0xFF, 0x00, 0x00, 0xFF,
+ 0x00, 0x00, 0x00, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02},
+ true,
+ },
+ {
+ "num mechanisms greater than payload",
+ []byte{0x00, 0x00, 0x00, 0x40, // 64, |rest| too small
+ 0x00, 0x00, 0x00, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02},
+ true,
+ },
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ _, err := parseGSSAPIPayload(tc.payload)
+ if tc.wanterr && err == nil {
+ t.Errorf("got nil, want error")
+ }
+ if !tc.wanterr && err != nil {
+ t.Errorf("got %v, want nil", err)
+ }
+ })
+ }
+}
+
func TestBuildMIC(t *testing.T) {
sessionID := []byte{134, 180, 134, 194, 62, 145, 171, 82, 119, 149, 254, 196, 125, 173, 177, 145, 187, 85, 53,
183, 44, 150, 219, 129, 166, 195, 19, 33, 209, 246, 175, 121}