From 10d262032cf458731a71cd0f0a9262b3a68cf73e Mon Sep 17 00:00:00 2001 From: Sunny Date: Thu, 28 Oct 2021 17:21:41 +0530 Subject: [PATCH] libgit2: handle EOF in parseKnownHosts() parseKnownHosts() uses golang.org/x/crypto/ssh's ParseKnownHosts() for parsing known hosts. It returns EOF error when the input is not a host public key, but a valid known_hosts content, like a comment line. With this fix, lines causing EOF error are skipped and the parsing of the known_hosts file continues. But invalid lines still cause parsing failure. Signed-off-by: Sunny --- pkg/git/libgit2/transport.go | 6 +++ pkg/git/libgit2/transport_test.go | 68 ++++++++++++++++++++++++++++++- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/pkg/git/libgit2/transport.go b/pkg/git/libgit2/transport.go index 83d9107e..a15c725d 100644 --- a/pkg/git/libgit2/transport.go +++ b/pkg/git/libgit2/transport.go @@ -25,6 +25,7 @@ import ( "crypto/x509" "fmt" "hash" + "io" "net" "strings" "time" @@ -168,6 +169,11 @@ func parseKnownHosts(s string) ([]knownKey, error) { for scanner.Scan() { _, hosts, pubKey, _, _, err := ssh.ParseKnownHosts(scanner.Bytes()) if err != nil { + // Lines that aren't host public key result in EOF, like a comment + // line. Continue parsing the other lines. + if err == io.EOF { + continue + } return []knownKey{}, err } diff --git a/pkg/git/libgit2/transport_test.go b/pkg/git/libgit2/transport_test.go index 6f1e9545..15eb6400 100644 --- a/pkg/git/libgit2/transport_test.go +++ b/pkg/git/libgit2/transport_test.go @@ -251,7 +251,7 @@ func Test_knownHostsCallback(t *testing.T) { } } -func Test_parseKnownHosts(t *testing.T) { +func Test_parseKnownHosts_matches(t *testing.T) { tests := []struct { name string hostkey git2go.HostkeyCertificate @@ -280,6 +280,72 @@ func Test_parseKnownHosts(t *testing.T) { } } +func Test_parseKnownHosts(t *testing.T) { + tests := []struct { + name string + fixture string + wantErr bool + }{ + { + name: "empty file", + fixture: "", + wantErr: false, + }, + { + name: "single host", + fixture: `github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==`, + wantErr: false, + }, + { + name: "single host with comment", + fixture: `# github.com +github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==`, + wantErr: false, + }, + { + name: "multiple hosts with comments", + fixture: `# github.com +github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== +# gitlab.com +gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf`, + }, + { + name: "no host key, only comments", + fixture: `# example.com +#github.com +# gitlab.com`, + wantErr: false, + }, + { + name: "invalid host entry", + fixture: `github.com ssh-rsa`, + wantErr: true, + }, + { + name: "invalid content", + fixture: `some random text`, + wantErr: true, + }, + { + name: "invalid line with valid host key", + fixture: `some random text +gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf`, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + _, err := parseKnownHosts(tt.fixture) + if tt.wantErr { + g.Expect(err).To(HaveOccurred()) + } else { + g.Expect(err).ToNot(HaveOccurred()) + } + }) + } +} + func md5Fingerprint(in string) [16]byte { var out [16]byte copy(out[:], in)