ssh/knownhosts: verify declared key type matches decoded key

The parseLine function previously ignored the key type field (e.g.,
"ssh-rsa") in known_hosts entries, relying solely on the type
information embedded within the base64-encoded key blob.

OpenSSH's sshkey_read implementation explicitly verifies that the key
type declared in the text matches the type of the parsed key, returning
SSH_ERR_KEY_TYPE_MISMATCH if they differ.

This change adds a check to ensure the declared key type matches
key.Type(), returning an error for malformed lines where they diverge.

This issue was found during a security audit by NCC Group Cryptography
Services, sponsored by Teleport, and was assessed and is being fixed as
a non-security bug.

Change-Id: Id4f35c74055f5691088273630b50cdd02c81bfe9
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/782427
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
This commit is contained in:
Nicola Murino
2026-06-02 00:24:24 -07:00
parent 9f72eccdf6
commit 3872a2bc69
2 changed files with 21 additions and 2 deletions
+5 -2
View File
@@ -192,8 +192,7 @@ func parseLine(line []byte) (marker, host string, key ssh.PublicKey, err error)
return "", "", nil, errors.New("knownhosts: missing host pattern")
}
// ignore the keytype as it's in the key blob anyway.
_, line = nextWord(line)
wantType, line := nextWord(line)
if len(line) == 0 {
return "", "", nil, errors.New("knownhosts: missing key type pattern")
}
@@ -209,6 +208,10 @@ func parseLine(line []byte) (marker, host string, key ssh.PublicKey, err error)
return "", "", nil, err
}
if key.Type() != wantType {
return "", "", nil, fmt.Errorf("knownhosts: key type mismatch: found %q, want %q", key.Type(), wantType)
}
return marker, host, key, nil
}
+16
View File
@@ -12,6 +12,7 @@ import (
"fmt"
"net"
"reflect"
"strings"
"testing"
"golang.org/x/crypto/ssh"
@@ -446,3 +447,18 @@ func TestUnicodeSpaceTrimming(t *testing.T) {
t.Errorf("Did not match dirty host, implying parsing issue")
}
}
func TestKeyTypeMismatch(t *testing.T) {
line := fmt.Sprintf("server.org ssh-rsa %s", base64.StdEncoding.EncodeToString(edKey.Marshal()))
db := newHostKeyDB()
err := db.Read(bytes.NewBufferString(line), "testdb")
if err == nil {
t.Fatal("Read succeeded on line with key type mismatch, expected error")
}
expectedErr := `knownhosts: key type mismatch: found "ssh-ed25519", want "ssh-rsa"`
if !strings.Contains(err.Error(), expectedErr) {
t.Fatalf("got error %q, want to contain %q", err.Error(), expectedErr)
}
}