Skip to content

Commit e4dc69e

Browse files
committed
ssh: return specific error for invalid signature algorithm
Previously, this would return the default error "no auth passed yet". Not only is the new error more specific, it makes it easier to verify the control flow of server authentication code. Change-Id: I6c8de4e3f91da74274acbe9d87ec4f6158b4a94f Reviewed-on: https://go-review.googlesource.com/c/142897 Run-TryBot: Han-Wen Nienhuys <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent bfa7d42 commit e4dc69e

File tree

2 files changed

+53
-2
lines changed

2 files changed

+53
-2
lines changed

ssh/client_auth_test.go

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"crypto/rand"
1010
"errors"
1111
"fmt"
12+
"io"
1213
"os"
1314
"strings"
1415
"testing"
@@ -28,8 +29,14 @@ func (cr keyboardInteractive) Challenge(user string, instruction string, questio
2829
var clientPassword = "tiger"
2930

3031
// tryAuth runs a handshake with a given config against an SSH server
31-
// with config serverConfig
32+
// with config serverConfig. Returns both client and server side errors.
3233
func tryAuth(t *testing.T, config *ClientConfig) error {
34+
err, _ := tryAuthBothSides(t, config)
35+
return err
36+
}
37+
38+
// tryAuthBothSides runs the handshake and returns the resulting errors from both sides of the connection.
39+
func tryAuthBothSides(t *testing.T, config *ClientConfig) (clientError error, serverAuthErrors []error) {
3340
c1, c2, err := netPipe()
3441
if err != nil {
3542
t.Fatalf("netPipe: %v", err)
@@ -79,9 +86,13 @@ func tryAuth(t *testing.T, config *ClientConfig) error {
7986
}
8087
serverConfig.AddHostKey(testSigners["rsa"])
8188

89+
serverConfig.AuthLogCallback = func(conn ConnMetadata, method string, err error) {
90+
serverAuthErrors = append(serverAuthErrors, err)
91+
}
92+
8293
go newServer(c1, serverConfig)
8394
_, _, _, err = NewClientConn(c2, "", config)
84-
return err
95+
return err, serverAuthErrors
8596
}
8697

8798
func TestClientAuthPublicKey(t *testing.T) {
@@ -213,6 +224,45 @@ func TestAuthMethodRSAandDSA(t *testing.T) {
213224
}
214225
}
215226

227+
type invalidAlgSigner struct {
228+
Signer
229+
}
230+
231+
func (s *invalidAlgSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
232+
sig, err := s.Signer.Sign(rand, data)
233+
if sig != nil {
234+
sig.Format = "invalid"
235+
}
236+
return sig, err
237+
}
238+
239+
func TestMethodInvalidAlgorithm(t *testing.T) {
240+
config := &ClientConfig{
241+
User: "testuser",
242+
Auth: []AuthMethod{
243+
PublicKeys(&invalidAlgSigner{testSigners["rsa"]}),
244+
},
245+
HostKeyCallback: InsecureIgnoreHostKey(),
246+
}
247+
248+
err, serverErrors := tryAuthBothSides(t, config)
249+
if err == nil {
250+
t.Fatalf("login succeeded")
251+
}
252+
253+
found := false
254+
want := "algorithm \"invalid\""
255+
256+
var errStrings []string
257+
for _, err := range serverErrors {
258+
found = found || (err != nil && strings.Contains(err.Error(), want))
259+
errStrings = append(errStrings, err.Error())
260+
}
261+
if !found {
262+
t.Errorf("server got error %q, want substring %q", errStrings, want)
263+
}
264+
}
265+
216266
func TestClientHMAC(t *testing.T) {
217267
for _, mac := range supportedMACs {
218268
config := &ClientConfig{

ssh/server.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,7 @@ userAuthLoop:
484484
// sig.Format. This is usually the same, but
485485
// for certs, the names differ.
486486
if !isAcceptableAlgo(sig.Format) {
487+
authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format)
487488
break
488489
}
489490
signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData)

0 commit comments

Comments
 (0)