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

Commit b99661a

Browse files
emirshAleksandar Likic
authored andcommitted
[FAB-6805] Mutual TLS
This patch enables TLS client authentication. The existing system cert pool configuration is merged into the new TLSCerts configuration. Change-Id: Ia9eacabf8a88f046028ca544b0ab6a99b65a5ea6 Signed-off-by: Emir Heidinger <emir.heidinger@securekey.com> Signed-off-by: Troy Ronda <troy@troyronda.com> Signed-off-by: Aleksandar Likic <aleksandar.likic@securekey.com>
1 parent 3651028 commit b99661a

File tree

27 files changed

+475
-209
lines changed

27 files changed

+475
-209
lines changed

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,4 +344,5 @@ clean:
344344
-$(GO_CMD) clean
345345
-rm -Rf /tmp/enroll_user /tmp/msp /tmp/keyvaluestore /tmp/hfc-kvs /tmp/state
346346
-rm -f integration-report.xml report.xml
347-
-FIXTURE_PROJECT_NAME=$(FIXTURE_PROJECT_NAME) DOCKER_REMOVE_FORCE=$(FIXTURE_DOCKER_REMOVE_FORCE) $(TEST_SCRIPTS_PATH)/clean_integration.sh
347+
-FIXTURE_PROJECT_NAME=$(FIXTURE_PROJECT_NAME) DOCKER_REMOVE_FORCE=$(FIXTURE_DOCKER_REMOVE_FORCE) $(TEST_SCRIPTS_PATH)/clean_integration.sh
348+

api/apiconfig/configprovider.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ SPDX-License-Identifier: Apache-2.0
77
package apiconfig
88

99
import (
10+
"crypto/tls"
1011
"crypto/x509"
1112
"time"
1213
)
@@ -48,6 +49,7 @@ type Config interface {
4849
KeyStorePath() string
4950
CAKeyStorePath() string
5051
CryptoConfigPath() string
52+
TLSClientCerts() ([]tls.Certificate, error)
5153
}
5254

5355
// TimeoutType enumerates the different types of outgoing connections

api/apiconfig/mocks/mockconfig.gen.go

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

api/apiconfig/network.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ type ClientConfig struct {
2626
Logging LoggingType
2727
CryptoConfig CCType
2828
TLS TLSType
29+
TLSCerts MutualTLSConfig
30+
2931
// currently not used by GO-SDK
3032
CredentialStore CredentialStoreType
3133
}
@@ -136,7 +138,7 @@ type TLSConfig struct {
136138
// MutualTLSConfig Mutual TLS configurations
137139
type MutualTLSConfig struct {
138140
Pem []string
139-
// Certfiles root certificates for TLS validation (Comma serparated path list)
141+
// Certfiles root certificates for TLS validation (Comma separated path list)
140142
Path string
141143
// Client client TLS information
142144
Client struct {

api/apifabca/mocks/mockfabriccaclient.gen.go

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

api/apitxn/mocks/mockapitxn.gen.go

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

pkg/config/comm/comm.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
Copyright SecureKey Technologies Inc. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package comm
8+
9+
import (
10+
"crypto/tls"
11+
12+
"github.com/hyperledger/fabric-sdk-go/api/apiconfig"
13+
"github.com/hyperledger/fabric-sdk-go/pkg/errors"
14+
)
15+
16+
// TLSConfig returns the appropriate config for TLS including the root CAs,
17+
// certs for mutual TLS, and server host override
18+
func TLSConfig(certificate string, serverhostoverride string, config apiconfig.Config) (*tls.Config, error) {
19+
certPool, _ := config.TLSCACertPool("")
20+
21+
if len(certificate) == 0 && (certPool == nil || len(certPool.Subjects()) == 0) {
22+
return nil, errors.New("certificate is required")
23+
}
24+
25+
tlsCaCertPool, err := config.TLSCACertPool(certificate)
26+
if err != nil {
27+
return nil, err
28+
}
29+
30+
clientCerts, err := config.TLSClientCerts()
31+
if err != nil {
32+
return nil, errors.Errorf("Error loading cert/key pair for TLS client credentials: %v", err)
33+
}
34+
35+
return &tls.Config{RootCAs: tlsCaCertPool, Certificates: clientCerts, ServerName: serverhostoverride}, nil
36+
}

pkg/config/config.go

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package config
88

99
import (
1010
"bytes"
11+
"crypto/tls"
1112
"crypto/x509"
1213
"encoding/pem"
1314
"io/ioutil"
@@ -125,7 +126,7 @@ func initConfigWithCmdRoot(configFile string, cmdRootPrefix string) (*Config, er
125126

126127
func getCertPool(myViper *viper.Viper) (*x509.CertPool, error) {
127128
tlsCertPool := x509.NewCertPool()
128-
if myViper.GetBool("client.systemcertpool") == true {
129+
if myViper.GetBool("client.tlsCerts.systemCertPool") == true {
129130
var err error
130131
if tlsCertPool, err = x509.SystemCertPool(); err != nil {
131132
return nil, err
@@ -173,6 +174,11 @@ func (c *Config) Client() (*apiconfig.ClientConfig, error) {
173174
return nil, err
174175
}
175176
client := config.Client
177+
178+
client.TLSCerts.Path = substPathVars(client.TLSCerts.Path)
179+
client.TLSCerts.Client.Keyfile = substPathVars(client.TLSCerts.Client.Keyfile)
180+
client.TLSCerts.Client.Certfile = substPathVars(client.TLSCerts.Client.Certfile)
181+
176182
return &client, nil
177183
}
178184

@@ -438,7 +444,7 @@ func (c *Config) OrderersConfig() ([]apiconfig.OrdererConfig, error) {
438444

439445
if orderer.TLSCACerts.Path != "" {
440446
orderer.TLSCACerts.Path = substPathVars(orderer.TLSCACerts.Path)
441-
} else if len(orderer.TLSCACerts.Pem) == 0 && c.configViper.GetBool("client.systemcertpool") == false {
447+
} else if len(orderer.TLSCACerts.Pem) == 0 && c.configViper.GetBool("client.tlsCerts.systemCertPool") == false {
442448
errors.Errorf("Orderer has no certs configured. Make sure TLSCACerts.Pem or TLSCACerts.Path is set for %s", orderer.URL)
443449
}
444450

@@ -697,7 +703,7 @@ func (c *Config) verifyPeerConfig(p apiconfig.PeerConfig, peerName string, tlsEn
697703
if p.EventURL == "" {
698704
return errors.Errorf("event URL does not exist or empty for peer %s", peerName)
699705
}
700-
if tlsEnabled && len(p.TLSCACerts.Pem) == 0 && p.TLSCACerts.Path == "" && c.configViper.GetBool("client.systemcertpool") == false {
706+
if tlsEnabled && len(p.TLSCACerts.Pem) == 0 && p.TLSCACerts.Path == "" && c.configViper.GetBool("client.tlsCerts.systemCertPool") == false {
701707
return errors.Errorf("tls.certificate does not exist or empty for peer %s", peerName)
702708
}
703709
return nil
@@ -810,6 +816,35 @@ func (c *Config) CryptoConfigPath() string {
810816
return substPathVars(c.configViper.GetString("client.cryptoconfig.path"))
811817
}
812818

819+
// TLSClientCerts loads the client's certs for mutual TLS
820+
// It checks the config for embedded pem files before looking for cert files
821+
func (c *Config) TLSClientCerts() ([]tls.Certificate, error) {
822+
config, err := c.NetworkConfig()
823+
if err != nil {
824+
return nil, err
825+
}
826+
827+
clientConfig := config.Client
828+
var clientCerts tls.Certificate
829+
830+
if clientConfig.TLSCerts.Client.CertPem != "" {
831+
clientCerts, err = tls.X509KeyPair([]byte(clientConfig.TLSCerts.Client.CertPem), []byte(clientConfig.TLSCerts.Client.KeyPem))
832+
if err != nil {
833+
return nil, errors.Errorf("Error loading cert/key pair as TLS client credentials: %v", err)
834+
}
835+
836+
} else if clientConfig.TLSCerts.Client.Certfile != "" {
837+
clientConfig.TLSCerts.Client.Keyfile = substPathVars(clientConfig.TLSCerts.Client.Keyfile)
838+
clientConfig.TLSCerts.Client.Certfile = substPathVars(clientConfig.TLSCerts.Client.Certfile)
839+
clientCerts, err = tls.LoadX509KeyPair(clientConfig.TLSCerts.Client.Certfile, clientConfig.TLSCerts.Client.Keyfile)
840+
if err != nil {
841+
return nil, errors.Errorf("Error loading cert/key pair as TLS client credentials: %v", err)
842+
}
843+
}
844+
845+
return []tls.Certificate{clientCerts}, nil
846+
}
847+
813848
// loadCAKey
814849
func loadCAKey(rawData []byte) (*x509.Certificate, error) {
815850
block, _ := pem.Decode(rawData)

pkg/config/config.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,9 @@ client:
9696
#library: "/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so, /usr/lib/softhsm/libsofthsm2.so ,/usr/lib/s390x-linux-gnu/softhsm/libsofthsm2.so, /usr/lib/powerpc64le-linux-gnu/softhsm/libsofthsm2.so, /usr/local/Cellar/softhsm/2.1.0/lib/softhsm/libsofthsm2.so"
9797
library: "add BCCSP library here"
9898

99-
# [Optional]. Use system certificate pool when connecting to peers, orderers (for negotiating TLS) Default: false
100-
# systemcertpool: true
99+
#tlsCerts:
100+
# [Optional]. Use system certificate pool when connecting to peers, orderers (for negotiating TLS) Default: false
101+
#systemCertPool: true
101102

102103
#
103104
# [Optional]. But most apps would have this section so that channel objects can be constructed

pkg/config/config_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,7 @@ func TestSystemCertPoolEnabled(t *testing.T) {
701701
t.Fatal("System Cert Pool not loaded even though it is enabled")
702702
}
703703

704-
// Org2 'mychannel' peer is missing cert + pem (it should not fail when systemcertpool enabled)
704+
// Org2 'mychannel' peer is missing cert + pem (it should not fail when systemCertPool enabled)
705705
_, err = c.ChannelPeers("mychannel")
706706
if err != nil {
707707
t.Fatalf("Should have skipped verifying ca cert + pem: %s", err)

0 commit comments

Comments
 (0)