ssh: wrap errors from client handshake

When an error is returned by a user defined host key callback,
it is now possible to handle it using standard Go mechanisms
such as errors.Is or errors.As.

Fixes golang/go#61309

Change-Id: I4269c5f8eacd8e7e8d85070ad249f0e27777b15f
GitHub-Last-Rev: d2a34d5c82
GitHub-Pull-Request: golang/crypto#266
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/508876
Run-TryBot: Nicola Murino <nicola.murino@gmail.com>
Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Muhammad Shulhan <m.shulhan@gmail.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Nicola Murino <nicola.murino@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Pavel Repin 2023-11-27 16:26:11 +00:00 коммит произвёл Gopher Robot
Родитель bda2f3f5cf
Коммит 7e6fbd82c8
2 изменённых файлов: 24 добавлений и 3 удалений

Просмотреть файл

@ -82,7 +82,7 @@ func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan
if err := conn.clientHandshake(addr, &fullConf); err != nil { if err := conn.clientHandshake(addr, &fullConf); err != nil {
c.Close() c.Close()
return nil, nil, nil, fmt.Errorf("ssh: handshake failed: %v", err) return nil, nil, nil, fmt.Errorf("ssh: handshake failed: %w", err)
} }
conn.mux = newMux(conn.transport) conn.mux = newMux(conn.transport)
return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil

Просмотреть файл

@ -7,6 +7,9 @@ package ssh
import ( import (
"bytes" "bytes"
"crypto/rand" "crypto/rand"
"errors"
"fmt"
"net"
"strings" "strings"
"testing" "testing"
) )
@ -207,9 +210,12 @@ func TestBannerCallback(t *testing.T) {
} }
func TestNewClientConn(t *testing.T) { func TestNewClientConn(t *testing.T) {
errHostKeyMismatch := errors.New("host key mismatch")
for _, tt := range []struct { for _, tt := range []struct {
name string name string
user string user string
simulateHostKeyMismatch HostKeyCallback
}{ }{
{ {
name: "good user field for ConnMetadata", name: "good user field for ConnMetadata",
@ -219,6 +225,13 @@ func TestNewClientConn(t *testing.T) {
name: "empty user field for ConnMetadata", name: "empty user field for ConnMetadata",
user: "", user: "",
}, },
{
name: "host key mismatch",
user: "testuser",
simulateHostKeyMismatch: func(hostname string, remote net.Addr, key PublicKey) error {
return fmt.Errorf("%w: %s", errHostKeyMismatch, bytes.TrimSpace(MarshalAuthorizedKey(key)))
},
},
} { } {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c1, c2, err := netPipe() c1, c2, err := netPipe()
@ -243,8 +256,16 @@ func TestNewClientConn(t *testing.T) {
}, },
HostKeyCallback: InsecureIgnoreHostKey(), HostKeyCallback: InsecureIgnoreHostKey(),
} }
if tt.simulateHostKeyMismatch != nil {
clientConf.HostKeyCallback = tt.simulateHostKeyMismatch
}
clientConn, _, _, err := NewClientConn(c2, "", clientConf) clientConn, _, _, err := NewClientConn(c2, "", clientConf)
if err != nil { if err != nil {
if tt.simulateHostKeyMismatch != nil && errors.Is(err, errHostKeyMismatch) {
return
}
t.Fatal(err) t.Fatal(err)
} }