Skip to content
This repository was archived by the owner on Apr 25, 2025. It is now read-only.

Commit 830bdea

Browse files
committed
[FAB-9601] Make system cert pool access thread safe
We currently only synchronize writes but not reads. The comm package uses this cert pool for all outgoing connections making it hard to sync reads. As the x509 std lib does not allow deep copies of its cert pool, we reload the cert pool whenever a new cert is encountered, writing only to the fresh cert pool. The attached benchmark verifies performance for the common case: BenchmarkTLSCertPool-8 30000000 50.4 ns/op BenchmarkTLSCertPoolSameCert-8 10000000 123 ns/op BenchmarkTLSCertPoolDifferentCert-8 50 25575114 ns/op This also partially reverts commit 65a56e2 as TLSCACertPool() can now return an error. Change-Id: I72a1f2a1eb21036e5e382fad208c9d44b6f09b96 Signed-off-by: Divyank Katira <Divyank.Katira@securekey.com>
1 parent e328e9d commit 830bdea

File tree

19 files changed

+336
-117
lines changed

19 files changed

+336
-117
lines changed

pkg/client/resmgmt/resmgmt_test.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1643,7 +1643,7 @@ func getInvalidOrdererBackend(backend core.ConfigBackend) *mocks.MockConfigBacke
16431643
}
16441644
exampleOrderer := networkConfig.Orderers["orderer.example.com"]
16451645
exampleOrderer.TLSCACerts.Path = "/some/invalid/path"
1646-
exampleOrderer.TLSCACerts.Pem = ""
1646+
exampleOrderer.TLSCACerts.Pem = validRootCA
16471647
networkConfig.Orderers["orderer.example.com"] = exampleOrderer
16481648

16491649
mockConfigBackend := getCustomBackend(backend)
@@ -1671,3 +1671,20 @@ func getNoEventSourceBackend(backend core.ConfigBackend) *mocks.MockConfigBacken
16711671

16721672
return mockConfigBackend
16731673
}
1674+
1675+
var validRootCA = `-----BEGIN CERTIFICATE-----
1676+
MIICYjCCAgmgAwIBAgIUB3CTDOU47sUC5K4kn/Caqnh114YwCgYIKoZIzj0EAwIw
1677+
fzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh
1678+
biBGcmFuY2lzY28xHzAdBgNVBAoTFkludGVybmV0IFdpZGdldHMsIEluYy4xDDAK
1679+
BgNVBAsTA1dXVzEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMTYxMDEyMTkzMTAw
1680+
WhcNMjExMDExMTkzMTAwWjB/MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZv
1681+
cm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEfMB0GA1UEChMWSW50ZXJuZXQg
1682+
V2lkZ2V0cywgSW5jLjEMMAoGA1UECxMDV1dXMRQwEgYDVQQDEwtleGFtcGxlLmNv
1683+
bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABKIH5b2JaSmqiQXHyqC+cmknICcF
1684+
i5AddVjsQizDV6uZ4v6s+PWiJyzfA/rTtMvYAPq/yeEHpBUB1j053mxnpMujYzBh
1685+
MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQXZ0I9
1686+
qp6CP8TFHZ9bw5nRtZxIEDAfBgNVHSMEGDAWgBQXZ0I9qp6CP8TFHZ9bw5nRtZxI
1687+
EDAKBggqhkjOPQQDAgNHADBEAiAHp5Rbp9Em1G/UmKn8WsCbqDfWecVbZPQj3RK4
1688+
oG5kQQIgQAe4OOKYhJdh3f7URaKfGTf492/nmRmtK+ySKjpHSrU=
1689+
-----END CERTIFICATE-----
1690+
`

pkg/common/providers/fab/provider.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ type EndpointConfig interface {
9696
ChannelConfig(name string) (*ChannelNetworkConfig, error)
9797
ChannelPeers(name string) ([]ChannelPeer, error)
9898
ChannelOrderers(name string) ([]OrdererConfig, error)
99-
TLSCACertPool(certConfig ...*x509.Certificate) *x509.CertPool
99+
TLSCACertPool(certConfig ...*x509.Certificate) (*x509.CertPool, error)
100100
EventServiceType() EventServiceType
101101
TLSClientCerts() ([]tls.Certificate, error)
102102
CryptoConfigPath() string

pkg/common/providers/test/mockfab/mockconfig.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ const ErrorMessage = "default error message"
3535
func DefaultMockConfig(mockCtrl *gomock.Controller) *MockEndpointConfig {
3636
config := NewMockEndpointConfig(mockCtrl)
3737

38-
config.EXPECT().TLSCACertPool(GoodCert).Return(CertPool).AnyTimes()
39-
config.EXPECT().TLSCACertPool().Return(CertPool).AnyTimes()
38+
config.EXPECT().TLSCACertPool(GoodCert).Return(CertPool, nil).AnyTimes()
39+
config.EXPECT().TLSCACertPool(BadCert).Return(CertPool, errors.New(ErrorMessage)).AnyTimes()
40+
config.EXPECT().TLSCACertPool().Return(CertPool, nil).AnyTimes()
4041
config.EXPECT().Timeout(fab.EndorserConnection).Return(time.Second * 5).AnyTimes()
4142
config.EXPECT().TLSClientCerts().Return([]tls.Certificate{TLSCert}, nil).AnyTimes()
4243

@@ -47,8 +48,9 @@ func DefaultMockConfig(mockCtrl *gomock.Controller) *MockEndpointConfig {
4748
func BadTLSClientMockConfig(mockCtrl *gomock.Controller) *MockEndpointConfig {
4849
config := NewMockEndpointConfig(mockCtrl)
4950

50-
config.EXPECT().TLSCACertPool(GoodCert).Return(CertPool).AnyTimes()
51-
config.EXPECT().TLSCACertPool().Return(CertPool).AnyTimes()
51+
config.EXPECT().TLSCACertPool(GoodCert).Return(CertPool, nil).AnyTimes()
52+
config.EXPECT().TLSCACertPool(BadCert).Return(CertPool, errors.New(ErrorMessage)).AnyTimes()
53+
config.EXPECT().TLSCACertPool().Return(CertPool, nil).AnyTimes()
5254
config.EXPECT().Timeout(fab.EndorserConnection).Return(time.Second * 5).AnyTimes()
5355
config.EXPECT().TLSClientCerts().Return(nil, errors.Errorf(ErrorMessage)).AnyTimes()
5456

pkg/common/providers/test/mockfab/mockfab.gen.go

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/core/config/comm/comm.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,21 @@ import (
1919
// TLSConfig returns the appropriate config for TLS including the root CAs,
2020
// certs for mutual TLS, and server host override. Works with certs loaded either from a path or embedded pem.
2121
func TLSConfig(cert *x509.Certificate, serverName string, config fab.EndpointConfig) (*tls.Config, error) {
22-
certPool := config.TLSCACertPool()
22+
certPool, err := config.TLSCACertPool()
23+
if err != nil {
24+
return nil, err
25+
}
26+
2327
if cert == nil && (certPool == nil || len(certPool.Subjects()) == 0) {
2428
//Return empty tls config if there is no cert provided or if certpool unavailable
2529
return &tls.Config{}, nil
2630
}
2731

28-
tlsCaCertPool := config.TLSCACertPool(cert)
32+
tlsCaCertPool, err := config.TLSCACertPool(cert)
33+
34+
if err != nil {
35+
return nil, err
36+
}
2937

3038
clientCerts, err := config.TLSClientCerts()
3139
if err != nil {

pkg/core/config/comm/comm_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,22 @@ import (
2121
"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/test/mockfab"
2222
)
2323

24+
func TestTLSConfigErrorAddingCertificate(t *testing.T) {
25+
mockCtrl := gomock.NewController(t)
26+
defer mockCtrl.Finish()
27+
28+
config := mockfab.DefaultMockConfig(mockCtrl)
29+
30+
_, err := TLSConfig(mockfab.BadCert, "", config)
31+
if err == nil {
32+
t.Fatal("Expected failure adding invalid certificate")
33+
}
34+
35+
if !strings.Contains(err.Error(), mockfab.ErrorMessage) {
36+
t.Fatalf("Expected error: %s", mockfab.ErrorMessage)
37+
}
38+
}
39+
2440
func TestTLSConfigErrorFromClientCerts(t *testing.T) {
2541
mockCtrl := gomock.NewController(t)
2642
defer mockCtrl.Finish()

pkg/core/config/testdata/config_test_embedded_pems.yaml

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,22 @@ peers:
439439
#will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs
440440
allow-insecure: false
441441
tlsCACerts:
442-
pem:
442+
# pem supersedes path
443+
pem: |
444+
-----BEGIN CERTIFICATE-----
445+
MIICNjCCAdygAwIBAgIRAILSPmMB3BzoLIQGsFxwZr8wCgYIKoZIzj0EAwIwbDEL
446+
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
447+
cmFuY2lzY28xFDASBgNVBAoTC2V4YW1wbGUuY29tMRowGAYDVQQDExF0bHNjYS5l
448+
eGFtcGxlLmNvbTAeFw0xNzA3MjgxNDI3MjBaFw0yNzA3MjYxNDI3MjBaMGwxCzAJ
449+
BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJh
450+
bmNpc2NvMRQwEgYDVQQKEwtleGFtcGxlLmNvbTEaMBgGA1UEAxMRdGxzY2EuZXhh
451+
bXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQfgKb4db53odNzdMXn
452+
P5FZTZTFztOO1yLvCHDofSNfTPq/guw+YYk7ZNmhlhj8JHFG6dTybc9Qb/HOh9hh
453+
gYpXo18wXTAOBgNVHQ8BAf8EBAMCAaYwDwYDVR0lBAgwBgYEVR0lADAPBgNVHRMB
454+
Af8EBTADAQH/MCkGA1UdDgQiBCBxaEP3nVHQx4r7tC+WO//vrPRM1t86SKN0s6XB
455+
8LWbHTAKBggqhkjOPQQDAgNIADBFAiEA96HXwCsuMr7tti8lpcv1oVnXg0FlTxR/
456+
SQtE5YgdxkUCIHReNWh/pluHTxeGu2jNCH1eh6o2ajSGeeizoapvdJbN
457+
-----END CERTIFICATE-----
443458
path:
444459
#path: ${GOPATH}/src/github.com/hyperledger/fabric-sdk-go/${CRYPTOCONFIG_FIXTURES_PATH}/peerOrganizations/org2.example.com/tlsca/tlsca.org2.example.com-cert.pem
445460

@@ -534,4 +549,4 @@ certificateAuthorities:
534549
enrollId: admin
535550
enrollSecret: adminpw
536551
# [Optional] The optional name of the CA.
537-
caName: ca-org2
552+
caName: ca-org2

pkg/core/config/testdata/config_test_pem.yaml

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,22 @@ peers:
272272
ssl-target-name-override: peer0.org2.example.com
273273
allow-insecure: false
274274
tlsCACerts:
275-
pem:
275+
# pem supersedes path
276+
pem: |
277+
-----BEGIN CERTIFICATE-----
278+
MIICNjCCAdygAwIBAgIRAILSPmMB3BzoLIQGsFxwZr8wCgYIKoZIzj0EAwIwbDEL
279+
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
280+
cmFuY2lzY28xFDASBgNVBAoTC2V4YW1wbGUuY29tMRowGAYDVQQDExF0bHNjYS5l
281+
eGFtcGxlLmNvbTAeFw0xNzA3MjgxNDI3MjBaFw0yNzA3MjYxNDI3MjBaMGwxCzAJ
282+
BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJh
283+
bmNpc2NvMRQwEgYDVQQKEwtleGFtcGxlLmNvbTEaMBgGA1UEAxMRdGxzY2EuZXhh
284+
bXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQfgKb4db53odNzdMXn
285+
P5FZTZTFztOO1yLvCHDofSNfTPq/guw+YYk7ZNmhlhj8JHFG6dTybc9Qb/HOh9hh
286+
gYpXo18wXTAOBgNVHQ8BAf8EBAMCAaYwDwYDVR0lBAgwBgYEVR0lADAPBgNVHRMB
287+
Af8EBTADAQH/MCkGA1UdDgQiBCBxaEP3nVHQx4r7tC+WO//vrPRM1t86SKN0s6XB
288+
8LWbHTAKBggqhkjOPQQDAgNIADBFAiEA96HXwCsuMr7tti8lpcv1oVnXg0FlTxR/
289+
SQtE5YgdxkUCIHReNWh/pluHTxeGu2jNCH1eh6o2ajSGeeizoapvdJbN
290+
-----END CERTIFICATE-----
276291
path:
277292
#path: ${GOPATH}/src/github.com/hyperledger/fabric-sdk-go/${CRYPTOCONFIG_FIXTURES_PATH}/peerOrganizations/org2.example.com/tlsca/tlsca.org2.example.com-cert.pem
278293

@@ -366,4 +381,4 @@ certificateAuthorities:
366381
enrollId: admin
367382
enrollSecret: adminpw
368383
# [Optional] The optional name of the CA.
369-
caName: ca.org2.example.com
384+
caName: ca.org2.example.com

pkg/fab/channel/membership/membership.go

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -99,15 +99,13 @@ func createMSPManager(ctx Context, cfg fab.ChannelCfg) (msp.MSPManager, error) {
9999
if err := mspManager.Setup(msps); err != nil {
100100
return nil, errors.WithMessage(err, "MSPManager Setup failed")
101101
}
102-
102+
var certs [][]byte
103103
for _, msp := range msps {
104-
for _, cert := range msp.GetTLSRootCerts() {
105-
addCertsToConfig(ctx.EndpointConfig, cert)
106-
}
107-
108-
for _, cert := range msp.GetTLSIntermediateCerts() {
109-
addCertsToConfig(ctx.EndpointConfig, cert)
110-
}
104+
certs = append(certs, msp.GetTLSRootCerts()...)
105+
certs = append(certs, msp.GetTLSIntermediateCerts()...)
106+
}
107+
if len(certs) > 0 {
108+
addCertsToConfig(ctx.EndpointConfig, certs)
111109
}
112110
}
113111

@@ -185,25 +183,33 @@ func getFabricConfig(config *mb.MSPConfig) (*mb.FabricMSPConfig, error) {
185183
}
186184

187185
//addCertsToConfig adds cert bytes to config TLSCACertPool
188-
func addCertsToConfig(config fab.EndpointConfig, pemCerts []byte) {
189-
for len(pemCerts) > 0 {
190-
var block *pem.Block
191-
block, pemCerts = pem.Decode(pemCerts)
192-
if block == nil {
193-
break
194-
}
195-
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
196-
continue
197-
}
186+
func addCertsToConfig(config fab.EndpointConfig, pemCertsList [][]byte) {
187+
var certs []*x509.Certificate
188+
for _, pemCerts := range pemCertsList {
189+
for len(pemCerts) > 0 {
190+
var block *pem.Block
191+
block, pemCerts = pem.Decode(pemCerts)
192+
if block == nil {
193+
break
194+
}
195+
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
196+
continue
197+
}
198198

199-
cert, err := x509.ParseCertificate(block.Bytes)
200-
if err != nil {
201-
continue
202-
}
203-
err = verifier.ValidateCertificateDates(cert)
204-
if err != nil {
205-
logger.Warn("%v", err)
199+
cert, err := x509.ParseCertificate(block.Bytes)
200+
if err != nil {
201+
continue
202+
}
203+
err = verifier.ValidateCertificateDates(cert)
204+
if err != nil {
205+
logger.Warn("%v", err)
206+
}
207+
208+
certs = append(certs, cert)
206209
}
207-
_ = config.TLSCACertPool(cert)
210+
}
211+
_, err := config.TLSCACertPool(certs...)
212+
if err != nil {
213+
logger.Warnf("TLSCACertPool failed %v", err)
208214
}
209215
}

0 commit comments

Comments
 (0)