Skip to content

Commit 6b853fb

Browse files
caarlos0gopherbot
authored andcommitted
ssh/knownhosts: check more than one key
I believe this fixes golang/go#36126 . The problem was that it was keeping only the first known key of each type found. If you have a server advertising multiple keys of the same type, you might get a missmatch key error. Per sshd(8) man page, it should allow reapeatable hosts with different host keys, although it don't specify anything about hosts being from different types: "It is permissible (but not recommended) to have several lines or different host keys for the same names. This will inevitably happen when short forms of host names from different domains are put in the file. It is possible that the files contain conflicting information; authentication is accepted if valid information can be found from either file." So, this changes knownhosts behavior to accept any of the keys for a given host, regardless of type. Fixes #36126 Change-Id: I3450ff954259a403f2471082d013a5f79def0e16 GitHub-Last-Rev: 361bd2b GitHub-Pull-Request: #254 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/478535 Reviewed-by: Junyang Shao <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Nicola Murino <[email protected]> Reviewed-by: Michael Pratt <[email protected]> Auto-Submit: Nicola Murino <[email protected]>
1 parent 49bf5b8 commit 6b853fb

File tree

2 files changed

+24
-36
lines changed

2 files changed

+24
-36
lines changed

Diff for: ssh/knownhosts/knownhosts.go

+11-25
Original file line numberDiff line numberDiff line change
@@ -302,8 +302,8 @@ func (k *KnownKey) String() string {
302302
// applications can offer an interactive prompt to the user.
303303
type KeyError struct {
304304
// Want holds the accepted host keys. For each key algorithm,
305-
// there can be one hostkey. If Want is empty, the host is
306-
// unknown. If Want is non-empty, there was a mismatch, which
305+
// there can be multiple hostkeys. If Want is empty, the host
306+
// is unknown. If Want is non-empty, there was a mismatch, which
307307
// can signify a MITM attack.
308308
Want []KnownKey
309309
}
@@ -358,34 +358,20 @@ func (db *hostKeyDB) checkAddr(a addr, remoteKey ssh.PublicKey) error {
358358
// is just a key for the IP address, but not for the
359359
// hostname?
360360

361-
// Algorithm => key.
362-
knownKeys := map[string]KnownKey{}
363-
for _, l := range db.lines {
364-
if l.match(a) {
365-
typ := l.knownKey.Key.Type()
366-
if _, ok := knownKeys[typ]; !ok {
367-
knownKeys[typ] = l.knownKey
368-
}
369-
}
370-
}
371-
372361
keyErr := &KeyError{}
373-
for _, v := range knownKeys {
374-
keyErr.Want = append(keyErr.Want, v)
375-
}
376362

377-
// Unknown remote host.
378-
if len(knownKeys) == 0 {
379-
return keyErr
380-
}
363+
for _, l := range db.lines {
364+
if !l.match(a) {
365+
continue
366+
}
381367

382-
// If the remote host starts using a different, unknown key type, we
383-
// also interpret that as a mismatch.
384-
if known, ok := knownKeys[remoteKey.Type()]; !ok || !keyEq(known.Key, remoteKey) {
385-
return keyErr
368+
keyErr.Want = append(keyErr.Want, l.knownKey)
369+
if keyEq(l.knownKey.Key, remoteKey) {
370+
return nil
371+
}
386372
}
387373

388-
return nil
374+
return keyErr
389375
}
390376

391377
// The Read function parses file contents.

Diff for: ssh/knownhosts/knownhosts_test.go

+13-11
Original file line numberDiff line numberDiff line change
@@ -201,17 +201,6 @@ func TestHostNamePrecedence(t *testing.T) {
201201
}
202202
}
203203

204-
func TestDBOrderingPrecedenceKeyType(t *testing.T) {
205-
str := fmt.Sprintf("server.org,%s %s\nserver.org,%s %s", testAddr, edKeyStr, testAddr, alternateEdKeyStr)
206-
db := testDB(t, str)
207-
208-
if err := db.check("server.org:22", testAddr, alternateEdKey); err == nil {
209-
t.Errorf("check succeeded")
210-
} else if _, ok := err.(*KeyError); !ok {
211-
t.Errorf("got %T, want *KeyError", err)
212-
}
213-
}
214-
215204
func TestNegate(t *testing.T) {
216205
str := fmt.Sprintf("%s,!server.org %s", testAddr, edKeyStr)
217206
db := testDB(t, str)
@@ -354,3 +343,16 @@ func TestHashedHostkeyCheck(t *testing.T) {
354343
t.Errorf("got error %v, want %v", got, want)
355344
}
356345
}
346+
347+
func TestIssue36126(t *testing.T) {
348+
str := fmt.Sprintf("server.org,%s %s\nserver.org,%s %s", testAddr, edKeyStr, testAddr, alternateEdKeyStr)
349+
db := testDB(t, str)
350+
351+
if err := db.check("server.org:22", testAddr, edKey); err != nil {
352+
t.Errorf("should have passed the check, got %v", err)
353+
}
354+
355+
if err := db.check("server.org:22", testAddr, alternateEdKey); err != nil {
356+
t.Errorf("should have passed the check, got %v", err)
357+
}
358+
}

0 commit comments

Comments
 (0)