ssh/agent: return an error for unexpected message types

Previously, receiving an unexpected message type in response to a key
listing or a signing request could cause a panic due to a failed type
assertion.

This change adds a default case to the type switch in order to detect
and explicitly handle unknown or invalid message types, returning a
descriptive error instead of crashing.

Fixes golang/go#75178

Change-Id: Icbc3432adc79fe3c56b1ff23c6724d7a6f710f3a
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/700295
Reviewed-by: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Jakub Ciolek <jakub@ciolek.dev>
This commit is contained in:
Nicola Murino
2025-09-09 02:56:19 -07:00
parent 5307a0ce6d
commit 559e062ce8
2 changed files with 52 additions and 2 deletions
+4 -2
View File
@@ -430,8 +430,9 @@ func (c *client) List() ([]*Key, error) {
return keys, nil
case *failureAgentMsg:
return nil, errors.New("agent: failed to list keys")
default:
return nil, fmt.Errorf("agent: failed to list keys, unexpected message type %T", msg)
}
panic("unreachable")
}
// Sign has the agent sign the data using a protocol 2 key as defined
@@ -462,8 +463,9 @@ func (c *client) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFl
return &sig, nil
case *failureAgentMsg:
return nil, errors.New("agent: failed to sign challenge")
default:
return nil, fmt.Errorf("agent: failed to sign challenge, unexpected message type %T", msg)
}
panic("unreachable")
}
// unmarshal parses an agent message in packet, returning the parsed
+48
View File
@@ -7,6 +7,7 @@ package agent
import (
"bytes"
"crypto/rand"
"encoding/binary"
"errors"
"io"
"net"
@@ -347,6 +348,53 @@ func TestServerResponseTooLarge(t *testing.T) {
}
}
func TestInvalidResponses(t *testing.T) {
a, b, err := netPipe()
if err != nil {
t.Fatalf("netPipe: %v", err)
}
done := make(chan struct{})
defer func() { <-done }()
defer a.Close()
defer b.Close()
agent := NewClient(a)
go func() {
defer close(done)
resp := []byte{agentSuccess}
msg := make([]byte, 4+len(resp))
binary.BigEndian.PutUint32(msg[:4], uint32(len(resp)))
copy(msg[4:], resp)
if _, err := b.Write(msg); err != nil {
t.Errorf("unexpected error sending agent reply: %v", err)
b.Close()
return
}
if _, err := b.Write(msg); err != nil {
t.Errorf("unexpected error sending agent reply: %v", err)
b.Close()
}
}()
_, err = agent.List()
if err == nil {
t.Fatal("error expected")
}
if !strings.Contains(err.Error(), "failed to list keys, unexpected message type") {
t.Fatalf("unexpected error: %v", err)
}
_, err = agent.Sign(testPublicKeys["rsa"], []byte("message"))
if err == nil {
t.Fatal("error expected")
}
if !strings.Contains(err.Error(), "failed to sign challenge, unexpected message type") {
t.Fatalf("unexpected error: %v", err)
}
}
func TestAuth(t *testing.T) {
agent, _, cleanup := startOpenSSHAgent(t)
defer cleanup()