Skip to content

Commit

Permalink
Merge pull request #290 from fluxcd/fix/hash-type
Browse files Browse the repository at this point in the history
libgit2: check hostkey type when validating hostkey
  • Loading branch information
Philip Laine committed Feb 12, 2021
2 parents ca2bb80 + 0a1631d commit d1ee618
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 6 deletions.
26 changes: 20 additions & 6 deletions pkg/git/libgit2/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ package libgit2
import (
"bufio"
"bytes"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/x509"
"fmt"
"hash"
"net"
"net/url"
"strings"
Expand Down Expand Up @@ -157,7 +160,7 @@ func (s *PublicKeyAuth) Method(secret corev1.Secret) (*git.Auth, error) {
// is an entry for the hostname _and_ port.
host = knownhosts.Normalize(s.host)
for _, k := range kk {
if k.matches(host, cert.Hostkey.HashSHA1[:]) {
if k.matches(host, cert.Hostkey) {
return git2go.ErrOk
}
}
Expand Down Expand Up @@ -195,17 +198,28 @@ func parseKnownHosts(s string) ([]knownKey, error) {
return knownHosts, nil
}

func (k knownKey) matches(host string, key []byte) bool {
func (k knownKey) matches(host string, hostkey git2go.HostkeyCertificate) bool {
if !containsHost(k.hosts, host) {
return false
}

hash := sha1.Sum(k.key.Marshal())
if bytes.Compare(hash[:], key) != 0 {
var fingerprint []byte
var hasher hash.Hash
switch {
case hostkey.Kind&git2go.HostkeySHA256 > 0:
fingerprint = hostkey.HashSHA256[:]
hasher = sha256.New()
case hostkey.Kind&git2go.HostkeySHA1 > 0:
fingerprint = hostkey.HashSHA1[:]
hasher = sha1.New()
case hostkey.Kind&git2go.HostkeyMD5 > 0:
fingerprint = hostkey.HashMD5[:]
hasher = md5.New()
default:
return false
}

return true
hasher.Write(k.key.Marshal())
return bytes.Compare(hasher.Sum(nil), fingerprint) == 0
}

func containsHost(hosts []string, host string) bool {
Expand Down
59 changes: 59 additions & 0 deletions pkg/git/libgit2/transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ limitations under the License.
package libgit2

import (
"encoding/base64"
"reflect"
"testing"

git2go "github.com/libgit2/git2go/v31"
corev1 "k8s.io/api/core/v1"

"github.com/fluxcd/source-controller/pkg/git"
Expand Down Expand Up @@ -145,3 +147,60 @@ func TestPublicKeyStrategy_Method(t *testing.T) {
})
}
}

func TestKnownKeyHash(t *testing.T) {
tests := []struct {
name string
hostkey git2go.HostkeyCertificate
wantMatches bool
}{
{"good sha256 hostkey", git2go.HostkeyCertificate{Kind: git2go.HostkeySHA256 | git2go.HostkeySHA1 | git2go.HostkeyMD5, HashSHA256: sha256Fingerprint("nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8")}, true},
{"bad sha256 hostkey", git2go.HostkeyCertificate{Kind: git2go.HostkeySHA256 | git2go.HostkeySHA1 | git2go.HostkeyMD5, HashSHA256: sha256Fingerprint("ROQFvPThGrW4RuWLoL9tq9I9zJ42fK4XywyRtbOz/EQ")}, false},
{"good sha1 hostkey", git2go.HostkeyCertificate{Kind: git2go.HostkeySHA1 | git2go.HostkeyMD5, HashSHA1: sha1Fingerprint("v2toJdKXfFEaR1u++4iq1UqSrHM")}, true},
{"bad sha1 hostkey", git2go.HostkeyCertificate{Kind: git2go.HostkeySHA1 | git2go.HostkeyMD5, HashSHA1: sha1Fingerprint("tfpLlQhDDFP3yGdewTvHNxWmAdk")}, false},
{"good md5 hostkey", git2go.HostkeyCertificate{Kind: git2go.HostkeyMD5, HashMD5: md5Fingerprint("\x16\x27\xac\xa5\x76\x28\x2d\x36\x63\x1b\x56\x4d\xeb\xdf\xa6\x48")}, true},
{"bad md5 hostkey", git2go.HostkeyCertificate{Kind: git2go.HostkeyMD5, HashMD5: md5Fingerprint("\xb6\x03\x0e\x39\x97\x9e\xd0\xe7\x24\xce\xa3\x77\x3e\x01\x42\x09")}, false},
{"invalid hostkey", git2go.HostkeyCertificate{}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
knownKeys, err := parseKnownHosts(knownHostsFixture)
if err != nil {
t.Error(err)
return
}

matches := knownKeys[0].matches("github.com", tt.hostkey)
if matches != tt.wantMatches {
t.Errorf("Method() matches = %v, wantMatches %v", matches, tt.wantMatches)
return
}
})
}
}

func md5Fingerprint(in string) [16]byte {
var out [16]byte
copy(out[:], []byte(in))
return out
}

func sha1Fingerprint(in string) [20]byte {
d, err := base64.RawStdEncoding.DecodeString(in)
if err != nil {
panic(err)
}
var out [20]byte
copy(out[:], d)
return out
}

func sha256Fingerprint(in string) [32]byte {
d, err := base64.RawStdEncoding.DecodeString(in)
if err != nil {
panic(err)
}
var out [32]byte
copy(out[:], d)
return out
}

0 comments on commit d1ee618

Please sign in to comment.