Skip to content

Commit ddfa821

Browse files
drakkangopherbot
authored andcommitted
ssh: ignore invalid MACs and KEXs just like we do for ciphers
Tighter validation could cause backwards incompatibility issues, eg configurations with valid and invalid MACs, KEXs, ciphers currently work if a supported algorithm is negotiated and that's also the scenario of removing support for an existing algorithm. Fixes golang/go#39397 Change-Id: If90253ba89e1d8f732cc1e1c3d24fe0a1e2dac71 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/512175 Run-TryBot: Han-Wen Nienhuys <hanwen@google.com> Reviewed-by: Filippo Valsorda <filippo@golang.org> Reviewed-by: Han-Wen Nienhuys <hanwen@google.com> Auto-Submit: Filippo Valsorda <filippo@golang.org> Reviewed-by: David Chase <drchase@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
1 parent d08e19b commit ddfa821

File tree

2 files changed

+113
-7
lines changed

2 files changed

+113
-7
lines changed

ssh/client_test.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,3 +254,93 @@ func TestNewClientConn(t *testing.T) {
254254
})
255255
}
256256
}
257+
258+
func TestUnsupportedAlgorithm(t *testing.T) {
259+
for _, tt := range []struct {
260+
name string
261+
config Config
262+
wantError string
263+
}{
264+
{
265+
"unsupported KEX",
266+
Config{
267+
KeyExchanges: []string{"unsupported"},
268+
},
269+
"no common algorithm",
270+
},
271+
{
272+
"unsupported and supported KEXs",
273+
Config{
274+
KeyExchanges: []string{"unsupported", kexAlgoCurve25519SHA256},
275+
},
276+
"",
277+
},
278+
{
279+
"unsupported cipher",
280+
Config{
281+
Ciphers: []string{"unsupported"},
282+
},
283+
"no common algorithm",
284+
},
285+
{
286+
"unsupported and supported ciphers",
287+
Config{
288+
Ciphers: []string{"unsupported", chacha20Poly1305ID},
289+
},
290+
"",
291+
},
292+
{
293+
"unsupported MAC",
294+
Config{
295+
MACs: []string{"unsupported"},
296+
// MAC is used for non AAED ciphers.
297+
Ciphers: []string{"aes256-ctr"},
298+
},
299+
"no common algorithm",
300+
},
301+
{
302+
"unsupported and supported MACs",
303+
Config{
304+
MACs: []string{"unsupported", "hmac-sha2-256-etm@openssh.com"},
305+
// MAC is used for non AAED ciphers.
306+
Ciphers: []string{"aes256-ctr"},
307+
},
308+
"",
309+
},
310+
} {
311+
t.Run(tt.name, func(t *testing.T) {
312+
c1, c2, err := netPipe()
313+
if err != nil {
314+
t.Fatalf("netPipe: %v", err)
315+
}
316+
defer c1.Close()
317+
defer c2.Close()
318+
319+
serverConf := &ServerConfig{
320+
Config: tt.config,
321+
PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) {
322+
return &Permissions{}, nil
323+
},
324+
}
325+
serverConf.AddHostKey(testSigners["rsa"])
326+
go NewServerConn(c1, serverConf)
327+
328+
clientConf := &ClientConfig{
329+
User: "testuser",
330+
Config: tt.config,
331+
Auth: []AuthMethod{
332+
Password("testpw"),
333+
},
334+
HostKeyCallback: InsecureIgnoreHostKey(),
335+
}
336+
_, _, _, err = NewClientConn(c2, "", clientConf)
337+
if err != nil {
338+
if tt.wantError == "" || !strings.Contains(err.Error(), tt.wantError) {
339+
t.Errorf("%s: got error %q, missing %q", tt.name, err.Error(), tt.wantError)
340+
}
341+
} else if tt.wantError != "" {
342+
t.Errorf("%s: succeeded, but want error string %q", tt.name, tt.wantError)
343+
}
344+
})
345+
}
346+
}

ssh/common.go

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -269,16 +269,16 @@ type Config struct {
269269
// unspecified, a size suitable for the chosen cipher is used.
270270
RekeyThreshold uint64
271271

272-
// The allowed key exchanges algorithms. If unspecified then a
273-
// default set of algorithms is used.
272+
// The allowed key exchanges algorithms. If unspecified then a default set
273+
// of algorithms is used. Unsupported values are silently ignored.
274274
KeyExchanges []string
275275

276-
// The allowed cipher algorithms. If unspecified then a sensible
277-
// default is used.
276+
// The allowed cipher algorithms. If unspecified then a sensible default is
277+
// used. Unsupported values are silently ignored.
278278
Ciphers []string
279279

280-
// The allowed MAC algorithms. If unspecified then a sensible default
281-
// is used.
280+
// The allowed MAC algorithms. If unspecified then a sensible default is
281+
// used. Unsupported values are silently ignored.
282282
MACs []string
283283
}
284284

@@ -295,7 +295,7 @@ func (c *Config) SetDefaults() {
295295
var ciphers []string
296296
for _, c := range c.Ciphers {
297297
if cipherModes[c] != nil {
298-
// reject the cipher if we have no cipherModes definition
298+
// Ignore the cipher if we have no cipherModes definition.
299299
ciphers = append(ciphers, c)
300300
}
301301
}
@@ -304,10 +304,26 @@ func (c *Config) SetDefaults() {
304304
if c.KeyExchanges == nil {
305305
c.KeyExchanges = preferredKexAlgos
306306
}
307+
var kexs []string
308+
for _, k := range c.KeyExchanges {
309+
if kexAlgoMap[k] != nil {
310+
// Ignore the KEX if we have no kexAlgoMap definition.
311+
kexs = append(kexs, k)
312+
}
313+
}
314+
c.KeyExchanges = kexs
307315

308316
if c.MACs == nil {
309317
c.MACs = supportedMACs
310318
}
319+
var macs []string
320+
for _, m := range c.MACs {
321+
if macModes[m] != nil {
322+
// Ignore the MAC if we have no macModes definition.
323+
macs = append(macs, m)
324+
}
325+
}
326+
c.MACs = macs
311327

312328
if c.RekeyThreshold == 0 {
313329
// cipher specific default

0 commit comments

Comments
 (0)