@@ -22,12 +22,13 @@ import (
2222 "crypto/sha1"
2323 "crypto/x509"
2424 "fmt"
25+ "net"
2526 "net/url"
2627 "strings"
2728
28- "golang.org/x/crypto/ssh"
29-
3029 git2go "github.com/libgit2/git2go/v31"
30+ "golang.org/x/crypto/ssh"
31+ "golang.org/x/crypto/ssh/knownhosts"
3132 corev1 "k8s.io/api/core/v1"
3233
3334 "github.com/fluxcd/source-controller/pkg/git"
@@ -43,7 +44,7 @@ func AuthSecretStrategyForURL(URL string) (git.AuthSecretStrategy, error) {
4344 case u .Scheme == "http" , u .Scheme == "https" :
4445 return & BasicAuth {}, nil
4546 case u .Scheme == "ssh" :
46- return & PublicKeyAuth {user : u .User .Username ()}, nil
47+ return & PublicKeyAuth {user : u .User .Username (), host : u . Host }, nil
4748 default :
4849 return nil , fmt .Errorf ("no auth secret strategy for scheme %s" , u .Scheme )
4950 }
@@ -62,7 +63,7 @@ func (s *BasicAuth) Method(secret corev1.Secret) (*git.Auth, error) {
6263 password = string (d )
6364 }
6465 if username != "" && password != "" {
65- credCallback = func (url string , username_from_url string , allowed_types git2go.CredType ) (* git2go.Cred , error ) {
66+ credCallback = func (url string , usernameFromURL string , allowedTypes git2go.CredType ) (* git2go.Cred , error ) {
6667 cred , err := git2go .NewCredUserpassPlaintext (username , password )
6768 if err != nil {
6869 return nil , err
@@ -97,11 +98,12 @@ func (s *BasicAuth) Method(secret corev1.Secret) (*git.Auth, error) {
9798
9899type PublicKeyAuth struct {
99100 user string
101+ host string
100102}
101103
102104func (s * PublicKeyAuth ) Method (secret corev1.Secret ) (* git.Auth , error ) {
103105 if _ , ok := secret .Data [git .CAFile ]; ok {
104- return nil , fmt .Errorf ("found caFile key in secret '%s' but libgit2 SSH transport does not support custom certificates" , secret .Name )
106+ return nil , fmt .Errorf ("found %s key in secret '%s' but libgit2 SSH transport does not support custom certificates" , git . CAFile , secret .Name )
105107 }
106108 identity := secret .Data ["identity" ]
107109 knownHosts := secret .Data ["known_hosts" ]
@@ -126,20 +128,40 @@ func (s *PublicKeyAuth) Method(secret corev1.Secret) (*git.Auth, error) {
126128 user = git .DefaultPublicKeyAuthUser
127129 }
128130
129- credCallback := func (url string , username_from_url string , allowed_types git2go.CredType ) (* git2go.Cred , error ) {
131+ credCallback := func (url string , usernameFromURL string , allowedTypes git2go.CredType ) (* git2go.Cred , error ) {
130132 cred , err := git2go .NewCredSshKeyFromMemory (user , "" , string (identity ), "" )
131133 if err != nil {
132134 return nil , err
133135 }
134136 return cred , nil
135137 }
136138 certCallback := func (cert * git2go.Certificate , valid bool , hostname string ) git2go.ErrorCode {
139+ // First, attempt to split the configured host and port to validate
140+ // the port-less hostname given to the callback.
141+ host , _ , err := net .SplitHostPort (s .host )
142+ if err != nil {
143+ // SplitHostPort returns an error if the host is missing
144+ // a port, assume the host has no port.
145+ host = s .host
146+ }
147+
148+ // Check if the configured host matches the hostname given to
149+ // the callback.
150+ if host != hostname {
151+ return git2go .ErrUser
152+ }
153+
154+ // We are now certain that the configured host and the hostname
155+ // given to the callback match. Use the configured host (that
156+ // includes the port), and normalize it so we can check if there
157+ // is an entry for the hostname _and_ port.
158+ host = knownhosts .Normalize (s .host )
137159 for _ , k := range kk {
138- if k .matches (hostname , cert .Hostkey .HashSHA1 [:]) {
160+ if k .matches (host , cert .Hostkey .HashSHA1 [:]) {
139161 return git2go .ErrOk
140162 }
141163 }
142- return git2go .ErrGeneric
164+ return git2go .ErrCertificate
143165 }
144166
145167 return & git.Auth {CredCallback : credCallback , CertCallback : certCallback }, nil
@@ -151,7 +173,7 @@ type knownKey struct {
151173}
152174
153175func parseKnownHosts (s string ) ([]knownKey , error ) {
154- knownHosts := []knownKey {}
176+ var knownHosts []knownKey
155177 scanner := bufio .NewScanner (strings .NewReader (s ))
156178 for scanner .Scan () {
157179 _ , hosts , pubKey , _ , _ , err := ssh .ParseKnownHosts (scanner .Bytes ())
@@ -178,7 +200,7 @@ func (k knownKey) matches(host string, key []byte) bool {
178200 return false
179201 }
180202
181- hash := sha1 .Sum ([] byte ( k .key .Marshal () ))
203+ hash := sha1 .Sum (k .key .Marshal ())
182204 if bytes .Compare (hash [:], key ) != 0 {
183205 return false
184206 }
0 commit comments