diff --git a/ssh/known_hosts.go b/ssh/known_hosts.go index 4faeb3556..b04855041 100644 --- a/ssh/known_hosts.go +++ b/ssh/known_hosts.go @@ -124,6 +124,8 @@ func (kc *HostKeyChecker) GetHostKeyAlgorithms(addr string) []string { for _, hostKey := range keys { results = append(results, hostKey.Type()) } + // If we get here, it means we found a match, so break out of loop + break } return results @@ -165,6 +167,8 @@ func (kc *HostKeyChecker) Check(addr string, remote net.Addr, key gossh.PublicKe // and note exactly which key failed (file + line number) mismatched = true } + // If we get here, it means we found a match, so break out of loop + break } if mismatched { @@ -304,11 +308,6 @@ func parseKnownHostsLine(line []byte) (string, gossh.PublicKey, error) { hosts := string(line[:end]) keyBytes := line[end+1:] - // Check for hashed host names. - if strings.HasPrefix(hosts, sshHashDelim) { - return "", nil, errors.New("hashed hosts not implemented") - } - // Finally, actually try to extract the key. key, _, _, _, err := gossh.ParseAuthorizedKey(keyBytes) if err != nil { diff --git a/ssh/match.go b/ssh/match.go index b362df0a0..c5f3a8fd1 100644 --- a/ssh/match.go +++ b/ssh/match.go @@ -14,7 +14,12 @@ package ssh -import "strings" +import ( + "crypto/hmac" + "crypto/sha1" + "encoding/base64" + "strings" +) // matchHost tries to match the given host name against a comma-separated // sequence of subpatterns s (each possibly preceded by ! to indicate negation). @@ -22,6 +27,19 @@ import "strings" // Any matched negations take precedence over any other possible matches in the // pattern. func matchHost(host, pattern string) bool { + // Check for hashed host names. + if strings.HasPrefix(pattern, sshHashDelim) { + hostHash := strings.Split(strings.Split(pattern, "|1|")[1], sshHashDelim) + decodedSalt, _ := base64.StdEncoding.DecodeString(hostHash[0]) + + hmacSha1 := hmac.New(sha1.New, decodedSalt) + hmacSha1.Write([]byte(host)) + sum := hmacSha1.Sum(nil) + + encodedSum := base64.StdEncoding.EncodeToString(sum) + return encodedSum == hostHash[1] + } + subpatterns := strings.Split(pattern, ",") found := false for _, s := range subpatterns {