Skip to content

Commit

Permalink
Check hostkey type when validating hostkey
Browse files Browse the repository at this point in the history
Signed-off-by: Philip Laine <philip.laine@gmail.com>
  • Loading branch information
phillebaba committed Feb 11, 2021
1 parent ca2bb80 commit 6b3d96e
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 4 deletions.
26 changes: 22 additions & 4 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,13 +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 hostkey.Kind {
case git2go.HostkeyMD5:
fingerprint = hostkey.HashMD5[:]
hasher = md5.New()
case git2go.HostkeySHA1:
fingerprint = hostkey.HashSHA1[:]
hasher = sha1.New()
case git2go.HostkeySHA256:
fingerprint = hostkey.HashSHA256[:]
hasher = sha256.New()
default:
return false
}
hasher.Write(k.key.Marshal())
if bytes.Compare(hasher.Sum(nil), fingerprint) != 0 {
return false
}

Expand Down
50 changes: 50 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,51 @@ 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, HashSHA256: sha256Fingerprint("nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8")}, true},
{"bad sha256 hostkey", git2go.HostkeyCertificate{Kind: git2go.HostkeySHA256, HashSHA256: sha256Fingerprint("ROQFvPThGrW4RuWLoL9tq9I9zJ42fK4XywyRtbOz/EQ")}, false},
{"good sha1 hostkey", git2go.HostkeyCertificate{Kind: git2go.HostkeySHA1, HashSHA1: sha1Fingerprint("v2toJdKXfFEaR1u++4iq1UqSrHM")}, true},
{"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 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 6b3d96e

Please sign in to comment.