@@ -22,12 +22,13 @@ import (
22
22
"crypto/sha1"
23
23
"crypto/x509"
24
24
"fmt"
25
+ "net"
25
26
"net/url"
26
27
"strings"
27
28
28
- "golang.org/x/crypto/ssh"
29
-
30
29
git2go "github.com/libgit2/git2go/v31"
30
+ "golang.org/x/crypto/ssh"
31
+ "golang.org/x/crypto/ssh/knownhosts"
31
32
corev1 "k8s.io/api/core/v1"
32
33
33
34
"github.com/fluxcd/source-controller/pkg/git"
@@ -43,7 +44,7 @@ func AuthSecretStrategyForURL(URL string) (git.AuthSecretStrategy, error) {
43
44
case u .Scheme == "http" , u .Scheme == "https" :
44
45
return & BasicAuth {}, nil
45
46
case u .Scheme == "ssh" :
46
- return & PublicKeyAuth {user : u .User .Username ()}, nil
47
+ return & PublicKeyAuth {user : u .User .Username (), host : u . Host }, nil
47
48
default :
48
49
return nil , fmt .Errorf ("no auth secret strategy for scheme %s" , u .Scheme )
49
50
}
@@ -62,7 +63,7 @@ func (s *BasicAuth) Method(secret corev1.Secret) (*git.Auth, error) {
62
63
password = string (d )
63
64
}
64
65
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 ) {
66
67
cred , err := git2go .NewCredUserpassPlaintext (username , password )
67
68
if err != nil {
68
69
return nil , err
@@ -97,11 +98,12 @@ func (s *BasicAuth) Method(secret corev1.Secret) (*git.Auth, error) {
97
98
98
99
type PublicKeyAuth struct {
99
100
user string
101
+ host string
100
102
}
101
103
102
104
func (s * PublicKeyAuth ) Method (secret corev1.Secret ) (* git.Auth , error ) {
103
105
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 )
105
107
}
106
108
identity := secret .Data ["identity" ]
107
109
knownHosts := secret .Data ["known_hosts" ]
@@ -126,20 +128,40 @@ func (s *PublicKeyAuth) Method(secret corev1.Secret) (*git.Auth, error) {
126
128
user = git .DefaultPublicKeyAuthUser
127
129
}
128
130
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 ) {
130
132
cred , err := git2go .NewCredSshKeyFromMemory (user , "" , string (identity ), "" )
131
133
if err != nil {
132
134
return nil , err
133
135
}
134
136
return cred , nil
135
137
}
136
138
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 to the
149
+ // 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 )
137
159
for _ , k := range kk {
138
- if k .matches (hostname , cert .Hostkey .HashSHA1 [:]) {
160
+ if k .matches (s . host , cert .Hostkey .HashSHA1 [:]) {
139
161
return git2go .ErrOk
140
162
}
141
163
}
142
- return git2go .ErrGeneric
164
+ return git2go .ErrCertificate
143
165
}
144
166
145
167
return & git.Auth {CredCallback : credCallback , CertCallback : certCallback }, nil
@@ -151,7 +173,7 @@ type knownKey struct {
151
173
}
152
174
153
175
func parseKnownHosts (s string ) ([]knownKey , error ) {
154
- knownHosts := []knownKey {}
176
+ var knownHosts []knownKey
155
177
scanner := bufio .NewScanner (strings .NewReader (s ))
156
178
for scanner .Scan () {
157
179
_ , hosts , pubKey , _ , _ , err := ssh .ParseKnownHosts (scanner .Bytes ())
@@ -178,7 +200,7 @@ func (k knownKey) matches(host string, key []byte) bool {
178
200
return false
179
201
}
180
202
181
- hash := sha1 .Sum ([] byte ( k .key .Marshal () ))
203
+ hash := sha1 .Sum (k .key .Marshal ())
182
204
if bytes .Compare (hash [:], key ) != 0 {
183
205
return false
184
206
}
0 commit comments