Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 763ce2e

Browse filesBrowse files
authored
Merge pull request #1510 from hiddeco/mtls-support
[v5] plumbing: support mTLS for HTTPS protocol
2 parents 6f444d3 + 5320e1b commit 763ce2e
Copy full SHA for 763ce2e

File tree

Expand file treeCollapse file tree

8 files changed

+111
-33
lines changed
Filter options
Expand file treeCollapse file tree

8 files changed

+111
-33
lines changed

‎options.go

Copy file name to clipboardExpand all lines: options.go
+46-10Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"time"
99

1010
"github.com/ProtonMail/go-crypto/openpgp"
11+
1112
"github.com/go-git/go-git/v5/config"
1213
"github.com/go-git/go-git/v5/plumbing"
1314
formatcfg "github.com/go-git/go-git/v5/plumbing/format/config"
@@ -72,9 +73,16 @@ type CloneOptions struct {
7273
// Tags describe how the tags will be fetched from the remote repository,
7374
// by default is AllTags.
7475
Tags TagMode
75-
// InsecureSkipTLS skips ssl verify if protocol is https
76+
// InsecureSkipTLS skips SSL verification if protocol is HTTPS.
7677
InsecureSkipTLS bool
77-
// CABundle specify additional ca bundle with system cert pool
78+
// ClientCert is the client certificate to use for mutual TLS authentication
79+
// over the HTTPS protocol.
80+
ClientCert []byte
81+
// ClientKey is the client key to use for mutual TLS authentication over
82+
// the HTTPS protocol.
83+
ClientKey []byte
84+
// CABundle specifies an additional CA bundle to use together with the
85+
// system cert pool.
7886
CABundle []byte
7987
// ProxyOptions provides info required for connecting to a proxy.
8088
ProxyOptions transport.ProxyOptions
@@ -153,9 +161,16 @@ type PullOptions struct {
153161
// Force allows the pull to update a local branch even when the remote
154162
// branch does not descend from it.
155163
Force bool
156-
// InsecureSkipTLS skips ssl verify if protocol is https
164+
// InsecureSkipTLS skips SSL verification if protocol is HTTPS.
157165
InsecureSkipTLS bool
158-
// CABundle specify additional ca bundle with system cert pool
166+
// ClientCert is the client certificate to use for mutual TLS authentication
167+
// over the HTTPS protocol.
168+
ClientCert []byte
169+
// ClientKey is the client key to use for mutual TLS authentication over
170+
// the HTTPS protocol.
171+
ClientKey []byte
172+
// CABundle specifies an additional CA bundle to use together with the
173+
// system cert pool.
159174
CABundle []byte
160175
// ProxyOptions provides info required for connecting to a proxy.
161176
ProxyOptions transport.ProxyOptions
@@ -211,9 +226,16 @@ type FetchOptions struct {
211226
// Force allows the fetch to update a local branch even when the remote
212227
// branch does not descend from it.
213228
Force bool
214-
// InsecureSkipTLS skips ssl verify if protocol is https
229+
// InsecureSkipTLS skips SSL verification if protocol is HTTPS.
215230
InsecureSkipTLS bool
216-
// CABundle specify additional ca bundle with system cert pool
231+
// ClientCert is the client certificate to use for mutual TLS authentication
232+
// over the HTTPS protocol.
233+
ClientCert []byte
234+
// ClientKey is the client key to use for mutual TLS authentication over
235+
// the HTTPS protocol.
236+
ClientKey []byte
237+
// CABundle specifies an additional CA bundle to use together with the
238+
// system cert pool.
217239
CABundle []byte
218240
// ProxyOptions provides info required for connecting to a proxy.
219241
ProxyOptions transport.ProxyOptions
@@ -267,9 +289,16 @@ type PushOptions struct {
267289
// Force allows the push to update a remote branch even when the local
268290
// branch does not descend from it.
269291
Force bool
270-
// InsecureSkipTLS skips ssl verify if protocol is https
292+
// InsecureSkipTLS skips SSL verification if protocol is HTTPS.
271293
InsecureSkipTLS bool
272-
// CABundle specify additional ca bundle with system cert pool
294+
// ClientCert is the client certificate to use for mutual TLS authentication
295+
// over the HTTPS protocol.
296+
ClientCert []byte
297+
// ClientKey is the client key to use for mutual TLS authentication over
298+
// the HTTPS protocol.
299+
ClientKey []byte
300+
// CABundle specifies an additional CA bundle to use together with the
301+
// system cert pool.
273302
CABundle []byte
274303
// RequireRemoteRefs only allows a remote ref to be updated if its current
275304
// value is the one specified here.
@@ -693,9 +722,16 @@ func (o *CreateTagOptions) loadConfigTagger(r *Repository) error {
693722
type ListOptions struct {
694723
// Auth credentials, if required, to use with the remote repository.
695724
Auth transport.AuthMethod
696-
// InsecureSkipTLS skips ssl verify if protocol is https
725+
// InsecureSkipTLS skips SSL verification if protocol is HTTPS.
697726
InsecureSkipTLS bool
698-
// CABundle specify additional ca bundle with system cert pool
727+
// ClientCert is the client certificate to use for mutual TLS authentication
728+
// over the HTTPS protocol.
729+
ClientCert []byte
730+
// ClientKey is the client key to use for mutual TLS authentication over
731+
// the HTTPS protocol.
732+
ClientKey []byte
733+
// CABundle specifies an additional CA bundle to use together with the
734+
// system cert pool.
699735
CABundle []byte
700736
// PeelingOption defines how peeled objects are handled during a
701737
// remote list.

‎plumbing/transport/common.go

Copy file name to clipboardExpand all lines: plumbing/transport/common.go
+10-2Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,17 @@ type Endpoint struct {
113113
Port int
114114
// Path is the repository path.
115115
Path string
116-
// InsecureSkipTLS skips ssl verify if protocol is https
116+
// InsecureSkipTLS skips SSL verification if Protocol is HTTPS.
117117
InsecureSkipTLS bool
118-
// CaBundle specify additional ca bundle with system cert pool
118+
// ClientCert specifies an optional client certificate to use for mutual
119+
// TLS authentication if Protocol is HTTPS.
120+
ClientCert []byte
121+
// ClientKey specifies an optional client key to use for mutual TLS
122+
// authentication if Protocol is HTTPS.
123+
ClientKey []byte
124+
// CaBundle specifies an optional CA bundle to use for SSL verification
125+
// if Protocol is HTTPS. The bundle is added in addition to the system
126+
// CA bundle.
119127
CaBundle []byte
120128
// Proxy provides info required for connecting to a proxy.
121129
Proxy ProxyOptions

‎plumbing/transport/http/common.go

Copy file name to clipboardExpand all lines: plumbing/transport/http/common.go
+28-4Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@ import (
1515
"strings"
1616
"sync"
1717

18+
"github.com/golang/groupcache/lru"
19+
1820
"github.com/go-git/go-git/v5/plumbing"
1921
"github.com/go-git/go-git/v5/plumbing/protocol/packp"
2022
"github.com/go-git/go-git/v5/plumbing/protocol/packp/capability"
2123
"github.com/go-git/go-git/v5/plumbing/transport"
2224
"github.com/go-git/go-git/v5/utils/ioutil"
23-
"github.com/golang/groupcache/lru"
2425
)
2526

2627
// it requires a bytes.Buffer, because we need to know the length
@@ -185,6 +186,18 @@ func transportWithInsecureTLS(transport *http.Transport) {
185186
transport.TLSClientConfig.InsecureSkipVerify = true
186187
}
187188

189+
func transportWithClientCert(transport *http.Transport, cert, key []byte) error {
190+
keyPair, err := tls.X509KeyPair(cert, key)
191+
if err != nil {
192+
return err
193+
}
194+
if transport.TLSClientConfig == nil {
195+
transport.TLSClientConfig = &tls.Config{}
196+
}
197+
transport.TLSClientConfig.Certificates = []tls.Certificate{keyPair}
198+
return nil
199+
}
200+
188201
func transportWithCABundle(transport *http.Transport, caBundle []byte) error {
189202
rootCAs, err := x509.SystemCertPool()
190203
if err != nil {
@@ -206,6 +219,11 @@ func transportWithProxy(transport *http.Transport, proxyURL *url.URL) {
206219
}
207220

208221
func configureTransport(transport *http.Transport, ep *transport.Endpoint) error {
222+
if len(ep.ClientCert) > 0 && len(ep.ClientKey) > 0 {
223+
if err := transportWithClientCert(transport, ep.ClientCert, ep.ClientKey); err != nil {
224+
return err
225+
}
226+
}
209227
if len(ep.CaBundle) > 0 {
210228
if err := transportWithCABundle(transport, ep.CaBundle); err != nil {
211229
return err
@@ -230,7 +248,7 @@ func newSession(c *client, ep *transport.Endpoint, auth transport.AuthMethod) (*
230248

231249
// We need to configure the http transport if there are transport specific
232250
// options present in the endpoint.
233-
if len(ep.CaBundle) > 0 || ep.InsecureSkipTLS || ep.Proxy.URL != "" {
251+
if len(ep.ClientKey) > 0 || len(ep.ClientCert) > 0 || len(ep.CaBundle) > 0 || ep.InsecureSkipTLS || ep.Proxy.URL != "" {
234252
var transport *http.Transport
235253
// if the client wasn't configured to have a cache for transports then just configure
236254
// the transport and use it directly, otherwise try to use the cache.
@@ -242,9 +260,13 @@ func newSession(c *client, ep *transport.Endpoint, auth transport.AuthMethod) (*
242260
}
243261

244262
transport = tr.Clone()
245-
configureTransport(transport, ep)
263+
if err := configureTransport(transport, ep); err != nil {
264+
return nil, err
265+
}
246266
} else {
247267
transportOpts := transportOptions{
268+
clientCert: string(ep.ClientCert),
269+
clientKey: string(ep.ClientKey),
248270
caBundle: string(ep.CaBundle),
249271
insecureSkipTLS: ep.InsecureSkipTLS,
250272
}
@@ -260,7 +282,9 @@ func newSession(c *client, ep *transport.Endpoint, auth transport.AuthMethod) (*
260282

261283
if !found {
262284
transport = c.client.Transport.(*http.Transport).Clone()
263-
configureTransport(transport, ep)
285+
if err := configureTransport(transport, ep); err != nil {
286+
return nil, err
287+
}
264288
c.addTransport(transportOpts, transport)
265289
}
266290
}

‎plumbing/transport/http/common_test.go

Copy file name to clipboardExpand all lines: plumbing/transport/http/common_test.go
+6-6Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,12 @@ func (s *ClientSuite) TestNewUnexpectedError(c *C) {
111111

112112
func (s *ClientSuite) Test_newSession(c *C) {
113113
cl := NewClientWithOptions(nil, &ClientOptions{
114-
CacheMaxEntries: 2,
114+
CacheMaxEntries: 3,
115115
}).(*client)
116116

117-
insecureEP := s.Endpoint
117+
insecureEP := *s.Endpoint
118118
insecureEP.InsecureSkipTLS = true
119-
session, err := newSession(cl, insecureEP, nil)
119+
session, err := newSession(cl, &insecureEP, nil)
120120
c.Assert(err, IsNil)
121121

122122
sessionTransport := session.client.Transport.(*http.Transport)
@@ -131,7 +131,7 @@ func (s *ClientSuite) Test_newSession(c *C) {
131131

132132
caEndpoint := insecureEP
133133
caEndpoint.CaBundle = []byte("this is the way")
134-
session, err = newSession(cl, caEndpoint, nil)
134+
session, err = newSession(cl, &caEndpoint, nil)
135135
c.Assert(err, IsNil)
136136

137137
sessionTransport = session.client.Transport.(*http.Transport)
@@ -146,7 +146,7 @@ func (s *ClientSuite) Test_newSession(c *C) {
146146
// cached transport should be the one that's used.
147147
c.Assert(sessionTransport, Equals, t)
148148

149-
session, err = newSession(cl, caEndpoint, nil)
149+
session, err = newSession(cl, &caEndpoint, nil)
150150
c.Assert(err, IsNil)
151151
sessionTransport = session.client.Transport.(*http.Transport)
152152
// transport that's going to be used should be cached already.
@@ -156,7 +156,7 @@ func (s *ClientSuite) Test_newSession(c *C) {
156156

157157
// if the cache does not exist, the transport should still be correctly configured.
158158
cl.transports = nil
159-
session, err = newSession(cl, insecureEP, nil)
159+
session, err = newSession(cl, &insecureEP, nil)
160160
c.Assert(err, IsNil)
161161

162162
sessionTransport = session.client.Transport.(*http.Transport)

‎plumbing/transport/http/transport.go

Copy file name to clipboardExpand all lines: plumbing/transport/http/transport.go
+4-2Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ import (
99
type transportOptions struct {
1010
insecureSkipTLS bool
1111
// []byte is not comparable.
12-
caBundle string
13-
proxyURL url.URL
12+
clientCert string
13+
clientKey string
14+
caBundle string
15+
proxyURL url.URL
1416
}
1517

1618
func (c *client) addTransport(opts transportOptions, transport *http.Transport) {

‎remote.go

Copy file name to clipboardExpand all lines: remote.go
+11-9Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ func (r *Remote) PushContext(ctx context.Context, o *PushOptions) (err error) {
114114
o.RemoteURL = r.c.URLs[len(r.c.URLs)-1]
115115
}
116116

117-
s, err := newSendPackSession(o.RemoteURL, o.Auth, o.InsecureSkipTLS, o.CABundle, o.ProxyOptions)
117+
s, err := newSendPackSession(o.RemoteURL, o.Auth, o.InsecureSkipTLS, o.ClientCert, o.ClientKey, o.CABundle, o.ProxyOptions)
118118
if err != nil {
119119
return err
120120
}
@@ -416,7 +416,7 @@ func (r *Remote) fetch(ctx context.Context, o *FetchOptions) (sto storer.Referen
416416
o.RemoteURL = r.c.URLs[0]
417417
}
418418

419-
s, err := newUploadPackSession(o.RemoteURL, o.Auth, o.InsecureSkipTLS, o.CABundle, o.ProxyOptions)
419+
s, err := newUploadPackSession(o.RemoteURL, o.Auth, o.InsecureSkipTLS, o.ClientCert, o.ClientKey, o.CABundle, o.ProxyOptions)
420420
if err != nil {
421421
return nil, err
422422
}
@@ -532,31 +532,33 @@ func depthChanged(before []plumbing.Hash, s storage.Storer) (bool, error) {
532532
return false, nil
533533
}
534534

535-
func newUploadPackSession(url string, auth transport.AuthMethod, insecure bool, cabundle []byte, proxyOpts transport.ProxyOptions) (transport.UploadPackSession, error) {
536-
c, ep, err := newClient(url, insecure, cabundle, proxyOpts)
535+
func newUploadPackSession(url string, auth transport.AuthMethod, insecure bool, clientCert, clientKey, caBundle []byte, proxyOpts transport.ProxyOptions) (transport.UploadPackSession, error) {
536+
c, ep, err := newClient(url, insecure, clientCert, clientKey, caBundle, proxyOpts)
537537
if err != nil {
538538
return nil, err
539539
}
540540

541541
return c.NewUploadPackSession(ep, auth)
542542
}
543543

544-
func newSendPackSession(url string, auth transport.AuthMethod, insecure bool, cabundle []byte, proxyOpts transport.ProxyOptions) (transport.ReceivePackSession, error) {
545-
c, ep, err := newClient(url, insecure, cabundle, proxyOpts)
544+
func newSendPackSession(url string, auth transport.AuthMethod, insecure bool, clientCert, clientKey, caBundle []byte, proxyOpts transport.ProxyOptions) (transport.ReceivePackSession, error) {
545+
c, ep, err := newClient(url, insecure, clientCert, clientKey, caBundle, proxyOpts)
546546
if err != nil {
547547
return nil, err
548548
}
549549

550550
return c.NewReceivePackSession(ep, auth)
551551
}
552552

553-
func newClient(url string, insecure bool, cabundle []byte, proxyOpts transport.ProxyOptions) (transport.Transport, *transport.Endpoint, error) {
553+
func newClient(url string, insecure bool, clientCert, clientKey, caBundle []byte, proxyOpts transport.ProxyOptions) (transport.Transport, *transport.Endpoint, error) {
554554
ep, err := transport.NewEndpoint(url)
555555
if err != nil {
556556
return nil, nil, err
557557
}
558558
ep.InsecureSkipTLS = insecure
559-
ep.CaBundle = cabundle
559+
ep.ClientCert = clientCert
560+
ep.ClientKey = clientKey
561+
ep.CaBundle = caBundle
560562
ep.Proxy = proxyOpts
561563

562564
c, err := client.NewClient(ep)
@@ -1356,7 +1358,7 @@ func (r *Remote) list(ctx context.Context, o *ListOptions) (rfs []*plumbing.Refe
13561358
return nil, ErrEmptyUrls
13571359
}
13581360

1359-
s, err := newUploadPackSession(r.c.URLs[0], o.Auth, o.InsecureSkipTLS, o.CABundle, o.ProxyOptions)
1361+
s, err := newUploadPackSession(r.c.URLs[0], o.Auth, o.InsecureSkipTLS, o.ClientCert, o.ClientKey, o.CABundle, o.ProxyOptions)
13601362
if err != nil {
13611363
return nil, err
13621364
}

‎repository.go

Copy file name to clipboardExpand all lines: repository.go
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/go-git/go-billy/v5"
2020
"github.com/go-git/go-billy/v5/osfs"
2121
"github.com/go-git/go-billy/v5/util"
22+
2223
"github.com/go-git/go-git/v5/config"
2324
"github.com/go-git/go-git/v5/internal/path_util"
2425
"github.com/go-git/go-git/v5/internal/revision"
@@ -930,6 +931,8 @@ func (r *Repository) clone(ctx context.Context, o *CloneOptions) error {
930931
Tags: o.Tags,
931932
RemoteName: o.RemoteName,
932933
InsecureSkipTLS: o.InsecureSkipTLS,
934+
ClientCert: o.ClientCert,
935+
ClientKey: o.ClientKey,
933936
CABundle: o.CABundle,
934937
ProxyOptions: o.ProxyOptions,
935938
}, o.ReferenceName)

‎worktree.go

Copy file name to clipboardExpand all lines: worktree.go
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
"github.com/go-git/go-billy/v5"
1414
"github.com/go-git/go-billy/v5/util"
15+
1516
"github.com/go-git/go-git/v5/config"
1617
"github.com/go-git/go-git/v5/plumbing"
1718
"github.com/go-git/go-git/v5/plumbing/filemode"
@@ -79,6 +80,8 @@ func (w *Worktree) PullContext(ctx context.Context, o *PullOptions) error {
7980
Progress: o.Progress,
8081
Force: o.Force,
8182
InsecureSkipTLS: o.InsecureSkipTLS,
83+
ClientCert: o.ClientCert,
84+
ClientKey: o.ClientKey,
8285
CABundle: o.CABundle,
8386
ProxyOptions: o.ProxyOptions,
8487
})

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.