ssh/agent: prevent panic on malformed constraint

An attacker could supply a malformed Constraint that
would trigger a panic in a serving agent, effectively
causing denial of service.

Thank you to Jakub Ciolek for reporting this issue.

Fixes CVE-2025-47914
Fixes golang/go#76364

Change-Id: I195bbc68b1560d4f04897722a6a653a7cbf086eb
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/721960
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Roland Shoemaker <roland@golang.org>
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/ssh/agent/server.go b/ssh/agent/server.go
index 88ce4da..4e8ff86 100644
--- a/ssh/agent/server.go
+++ b/ssh/agent/server.go
@@ -203,6 +203,9 @@
 	for len(constraints) != 0 {
 		switch constraints[0] {
 		case agentConstrainLifetime:
+			if len(constraints) < 5 {
+				return 0, false, nil, io.ErrUnexpectedEOF
+			}
 			lifetimeSecs = binary.BigEndian.Uint32(constraints[1:5])
 			constraints = constraints[5:]
 		case agentConstrainConfirm:
diff --git a/ssh/agent/server_test.go b/ssh/agent/server_test.go
index 7700d18..6309e2d 100644
--- a/ssh/agent/server_test.go
+++ b/ssh/agent/server_test.go
@@ -8,6 +8,7 @@
 	"crypto"
 	"crypto/rand"
 	"fmt"
+	"io"
 	pseudorand "math/rand"
 	"reflect"
 	"strings"
@@ -258,6 +259,12 @@
 		t.Errorf("got extension %v, want %v", extensions, expect)
 	}
 
+	// Test Malformed Constraint
+	_, _, _, err = parseConstraints([]byte{1})
+	if err != io.ErrUnexpectedEOF {
+		t.Errorf("got %v, want %v", err, io.ErrUnexpectedEOF)
+	}
+
 	// Test Unknown Constraint
 	_, _, _, err = parseConstraints([]byte{128})
 	if err == nil || !strings.Contains(err.Error(), "unknown constraint") {