From e7c36ccb477ccdb9f0f9b77025a9384de23dcc9c Mon Sep 17 00:00:00 2001 From: Neal Patel Date: Thu, 21 May 2026 10:29:46 -0400 Subject: [PATCH] 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 Reviewed-by: Roland Shoemaker Reviewed-by: Nicholas Husin Reviewed-by: Nicholas Husin --- ssh/agent/server.go | 6 ++++++ ssh/agent/server_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) 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 @@ func parseEd25519Key(req []byte) (*AddedKey, error) { 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 @@ func parseEd25519Cert(req []byte) (*AddedKey, error) { 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 @@ func TestParseConstraints(t *testing.T) { 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") + } +}