Skip to content

Commit 39b2dde

Browse files
committed
Add SystemCertPool usage as client option
1 parent 3174af9 commit 39b2dde

File tree

8 files changed

+43
-7
lines changed

8 files changed

+43
-7
lines changed

config/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type TLSClientConfig struct {
2424
InsecureSkipVerify bool `help:"Skip TLS verification on client side."`
2525
File TLSClientFiles `embed:"" prefix:"file."`
2626
KeyPassword string `help:"Optional password to decrypt RSA private key."`
27+
UseSystemPool bool `help:"Use system pool for root CAs."`
2728
}
2829

2930
type TLSClientFiles struct {

tls/client/config/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ func GetTLSClientConfigFunc(logger *slog.Logger, conf *config.TLSClientConfig, o
2020
filesource.WithClientCert(conf.File.Cert, conf.File.Key),
2121
filesource.WithClientRootCAs(conf.File.RootCAs),
2222
filesource.WithKeyPassword(conf.KeyPassword),
23+
filesource.WithSystemPool(conf.UseSystemPool),
2324
)
2425
if err != nil {
2526
return nil, fmt.Errorf("setup client cert file source: %w", err)

tls/client/filesource/filesource.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type fileSource struct {
1818
keyFile string
1919
keyPassword string
2020
rootCAsFile string
21+
useSystemPool bool
2122
refresh time.Duration
2223
logger *slog.Logger
2324
notifyFunc func()
@@ -95,8 +96,9 @@ func (s *fileSource) ClientCerts() chan tlscert.ClientCerts {
9596
}
9697

9798
func (s *fileSource) Load() (pemBlocks *tlscert.ClientPEMs, err error) {
98-
pemBlocks = &tlscert.ClientPEMs{}
99-
99+
pemBlocks = &tlscert.ClientPEMs{
100+
UseSystemPool: s.useSystemPool,
101+
}
100102
if (s.certFile == "") != (s.keyFile == "") {
101103
return nil, errors.New("cert file source: both certFile and keyFile must be set or be empty")
102104
}

tls/client/filesource/filesource_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ func TestKeyEncryption(t *testing.T) {
9797
WithClientCert(bundle.ClientCert.Name(), bundle.ClientKeyEncrypted.Name()),
9898
WithKeyPassword(bundle.ClientKeyPassword),
9999
WithRefresh(1*time.Second),
100+
WithSystemPool(true),
100101
).(*fileSource)
101102

102103
clientCertsStore, err := tlsclient.NewTLSClientCertsStore(slog.Default(), clientSource)

tls/client/filesource/option.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,9 @@ func WithNotifyFunc(notifyFunc func()) Option {
4949
c.notifyFunc = notifyFunc
5050
}
5151
}
52+
53+
func WithSystemPool(useSystemPool bool) Option {
54+
return func(c *fileSource) {
55+
c.useSystemPool = useSystemPool
56+
}
57+
}

tls/client/roundtripper.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func WithClientCertsStore(source *source.ClientCertsStore) RoundTripperOption {
3434
}
3535
}
3636

37-
func WithRootCA(cert *x509.Certificate) RoundTripperOption {
37+
func WithSystemRootCA(cert *x509.Certificate) RoundTripperOption {
3838
certPool, err := x509.SystemCertPool()
3939
if err != nil {
4040
certPool = x509.NewCertPool()
@@ -43,6 +43,12 @@ func WithRootCA(cert *x509.Certificate) RoundTripperOption {
4343
return WithRootCAs(certPool)
4444
}
4545

46+
func WithRootCA(cert *x509.Certificate) RoundTripperOption {
47+
certPool := x509.NewCertPool()
48+
certPool.AddCert(cert)
49+
return WithRootCAs(certPool)
50+
}
51+
4652
func WithRootCAs(rootCAs *x509.CertPool) RoundTripperOption {
4753
return func(rt *RoundTripper) {
4854
if rt.transport.TLSClientConfig == nil {

tls/client/source/pems.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ type ClientPEMs struct {
1515
CertPEMBlock []byte
1616
KeyPEMBlock []byte
1717
RootCAsPEMBlock []byte
18+
UseSystemPool bool
1819
}
1920

2021
func (s ClientPEMs) Checksum() []byte {
@@ -39,12 +40,19 @@ func (s ClientPEMs) RootCAs() (*x509.CertPool, error) {
3940
if len(s.RootCAsPEMBlock) == 0 {
4041
return nil, nil
4142
}
42-
certPool, err := x509.SystemCertPool()
43-
if err != nil {
44-
certPool = x509.NewCertPool()
45-
}
43+
certPool := s.newCertPool()
4644
if !certPool.AppendCertsFromPEM(s.RootCAsPEMBlock) {
4745
return nil, errors.New("client PEMs: building client CAs failed")
4846
}
4947
return certPool, nil
5048
}
49+
50+
func (s ClientPEMs) newCertPool() *x509.CertPool {
51+
if s.UseSystemPool {
52+
certPool, err := x509.SystemCertPool()
53+
if err == nil {
54+
return certPool
55+
}
56+
}
57+
return x509.NewCertPool()
58+
}

tls/server/filesource/filesource_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,17 @@ func TestServerConfig(t *testing.T) {
6464
))
6565
},
6666
},
67+
{
68+
name: "Client trusted CA added to system pool",
69+
transportFunc: func() http.RoundTripper {
70+
return tlsclient.NewDefaultRoundTripper(tlsclient.WithSystemRootCA(bundle.CAX509Cert))
71+
},
72+
configFunc: func() *tls.Config {
73+
return servertls.MustNewServerConfig(logger, MustNew(
74+
WithX509KeyPair(bundle.ServerCert.Name(), bundle.ServerKey.Name()),
75+
))
76+
},
77+
},
6778
{
6879
name: "Client without required certificate",
6980
transportFunc: func() http.RoundTripper {

0 commit comments

Comments
 (0)