ssh/agent: prevent panic on pathological ed25519 inputs

parseEd25519Key and parseEd25519Cert cast wire bytes
to ed25519.PrivateKey without checking length; a short
payload panics at priv[32:] in Public().

Fixes CVE-2026-46598
Fixes golang/go#46598

Change-Id: I127bc6a22adff1c4beb4d54533062bebc388de47
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/781360
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Nicholas Husin <nsh@golang.org>
Reviewed-by: Nicholas Husin <husin@google.com>
diff --git a/ssh/agent/server.go b/ssh/agent/server.go
index 2a7658c..248ab6a 100644
--- a/ssh/agent/server.go
+++ b/ssh/agent/server.go
@@ -270,6 +270,9 @@
 	if err := ssh.Unmarshal(req, &k); err != nil {
 		return nil, err
 	}
+	if len(k.Priv) != ed25519.PrivateKeySize {
+		return nil, fmt.Errorf("agent: bad ED25519 key size: %d", len(k.Priv))
+	}
 	priv := ed25519.PrivateKey(k.Priv)
 
 	addedKey := &AddedKey{PrivateKey: &priv, Comment: k.Comments}
@@ -336,6 +339,9 @@
 	if err != nil {
 		return nil, err
 	}
+	if len(k.Priv) != ed25519.PrivateKeySize {
+		return nil, fmt.Errorf("agent: bad ED25519 key size: %d", len(k.Priv))
+	}
 	priv := ed25519.PrivateKey(k.Priv)
 	cert, ok := pubKey.(*ssh.Certificate)
 	if !ok {
diff --git a/ssh/agent/server_test.go b/ssh/agent/server_test.go
index 6309e2d..9e790eb 100644
--- a/ssh/agent/server_test.go
+++ b/ssh/agent/server_test.go
@@ -271,3 +271,35 @@
 		t.Errorf("unexpected error: %v", err)
 	}
 }
+
+func TestParseEd25519KeyShortPanic(t *testing.T) {
+	msg := ssh.Marshal(ed25519KeyMsg{
+		Type: ssh.KeyAlgoED25519,
+		Pub:  []byte{1, 2, 3},
+		Priv: []byte{1, 2, 3, 4, 5},
+	})
+
+	a, b, err := netPipe()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer a.Close()
+	defer b.Close()
+
+	done := make(chan error, 1)
+	go func() { done <- ServeAgent(NewKeyring(), a) }()
+
+	c := NewClient(b)
+	_, err = c.(*client).call(msg)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	keys, err := c.List()
+	if err != nil {
+		t.Fatalf("agent died: %v", err)
+	}
+	if len(keys) != 0 {
+		t.Error("short ed25519 key was accepted into keyring")
+	}
+}