Skip to content

Commit cc03cac

Browse files
committed
Gossip:Add option to skip handshake verification
This commit adds a configuration option to make gossip skip verification of signature upon handshake. It will be (hopefully!) removed once mutual TLS will be configured in the peers and integrated with gossip. Change-Id: I87f9aca86b8e92de885b769f05a7e999fa06a4e2 Signed-off-by: Yacov Manevich <[email protected]>
1 parent f19d8cc commit cc03cac

File tree

3 files changed

+83
-19
lines changed

3 files changed

+83
-19
lines changed

gossip/comm/comm_impl.go

+15-3
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ func NewCommInstanceWithServer(port int, idMapper identity.Mapper, peerIdentity
115115
proto.RegisterGossipServer(s, commInst)
116116
}
117117

118+
if viper.GetBool("peer.gossip.skipHandshake") {
119+
commInst.skipHandshake = true
120+
}
121+
118122
return commInst, nil
119123
}
120124

@@ -140,6 +144,7 @@ func NewCommInstance(s *grpc.Server, cert *tls.Certificate, idStore identity.Map
140144
}
141145

142146
type commImpl struct {
147+
skipHandshake bool
143148
selfCertHash []byte
144149
peerIdentity api.PeerIdentityType
145150
idMapper identity.Mapper
@@ -424,7 +429,7 @@ func (c *commImpl) authenticateRemotePeer(stream stream) (*proto.ConnectionInfo,
424429

425430
// If TLS is detected, sign the hash of our cert to bind our TLS cert
426431
// to the gRPC session
427-
if remoteCertHash != nil && c.selfCertHash != nil {
432+
if remoteCertHash != nil && c.selfCertHash != nil && !c.skipHandshake {
428433
signer = func(msg []byte) ([]byte, error) {
429434
return c.idMapper.Sign(msg)
430435
}
@@ -472,8 +477,8 @@ func (c *commImpl) authenticateRemotePeer(stream stream) (*proto.ConnectionInfo,
472477
Identity: receivedMsg.Cert,
473478
}
474479

475-
// if TLS is detected, verify remote peer
476-
if remoteCertHash != nil && c.selfCertHash != nil {
480+
// if TLS is enabled and detected, verify remote peer
481+
if remoteCertHash != nil && c.selfCertHash != nil && !c.skipHandshake {
477482
if !bytes.Equal(remoteCertHash, receivedMsg.Hash) {
478483
return nil, fmt.Errorf("Expected %v in remote hash, but got %v", remoteCertHash, receivedMsg.Hash)
479484
}
@@ -492,6 +497,13 @@ func (c *commImpl) authenticateRemotePeer(stream stream) (*proto.ConnectionInfo,
492497
}
493498
}
494499

500+
// TLS enabled but not detected on other side, and we're not configured to skip handshake verification
501+
if remoteCertHash == nil && c.selfCertHash != nil && !c.skipHandshake {
502+
err = fmt.Errorf("Remote peer %s didn't send TLS certificate", remoteAddress)
503+
c.logger.Warning(err)
504+
return nil, err
505+
}
506+
495507
c.logger.Debug("Authenticated", remoteAddress)
496508

497509
return connInfo, nil

gossip/comm/comm_test.go

+65-16
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ package comm
1818

1919
import (
2020
"bytes"
21+
"crypto/hmac"
22+
"crypto/sha256"
2123
"crypto/tls"
2224
"fmt"
2325
"math/rand"
@@ -49,7 +51,10 @@ func acceptAll(msg interface{}) bool {
4951
return true
5052
}
5153

52-
var naiveSec = &naiveSecProvider{}
54+
var (
55+
naiveSec = &naiveSecProvider{}
56+
hmacKey = []byte{0, 0, 0}
57+
)
5358

5459
type naiveSecProvider struct {
5560
}
@@ -72,15 +77,19 @@ func (*naiveSecProvider) VerifyBlock(chainID common.ChainID, signedBlock []byte)
7277
// Sign signs msg with this peer's signing key and outputs
7378
// the signature if no error occurred.
7479
func (*naiveSecProvider) Sign(msg []byte) ([]byte, error) {
75-
return msg, nil
80+
mac := hmac.New(sha256.New, hmacKey)
81+
mac.Write(msg)
82+
return mac.Sum(nil), nil
7683
}
7784

7885
// Verify checks that signature is a valid signature of message under a peer's verification key.
7986
// If the verification succeeded, Verify returns nil meaning no error occurred.
8087
// If peerCert is nil, then the signature is verified against this peer's verification key.
8188
func (*naiveSecProvider) Verify(peerIdentity api.PeerIdentityType, signature, message []byte) error {
82-
equal := bytes.Equal(signature, message)
83-
if !equal {
89+
mac := hmac.New(sha256.New, hmacKey)
90+
mac.Write(message)
91+
expected := mac.Sum(nil)
92+
if !bytes.Equal(signature, expected) {
8493
return fmt.Errorf("Wrong certificate:%v, %v", signature, message)
8594
}
8695
return nil
@@ -98,16 +107,22 @@ func newCommInstance(port int, sec api.MessageCryptoService) (Comm, error) {
98107
return inst, err
99108
}
100109

101-
func handshaker(endpoint string, comm Comm, t *testing.T, sigMutator func([]byte) []byte, pkiIDmutator func([]byte) []byte) <-chan proto.ReceivedMessage {
110+
func handshaker(endpoint string, comm Comm, t *testing.T, sigMutator func([]byte) []byte, pkiIDmutator func([]byte) []byte, mutualTLS bool) <-chan proto.ReceivedMessage {
102111
c := &commImpl{}
103112
err := generateCertificates("key.pem", "cert.pem")
104113
defer os.Remove("cert.pem")
105114
defer os.Remove("key.pem")
106115
cert, err := tls.LoadX509KeyPair("cert.pem", "key.pem")
107-
ta := credentials.NewTLS(&tls.Config{
116+
tlsCfg := &tls.Config{
108117
InsecureSkipVerify: true,
109-
Certificates: []tls.Certificate{cert},
110-
})
118+
}
119+
120+
if mutualTLS {
121+
tlsCfg.Certificates = []tls.Certificate{cert}
122+
}
123+
124+
ta := credentials.NewTLS(tlsCfg)
125+
111126
acceptChan := comm.Accept(acceptAll)
112127
conn, err := grpc.Dial("localhost:9611", grpc.WithTransportCredentials(&authCreds{tlsCreds: ta}), grpc.WithBlock(), grpc.WithTimeout(time.Second))
113128
assert.NoError(t, err, "%v", err)
@@ -119,16 +134,25 @@ func handshaker(endpoint string, comm Comm, t *testing.T, sigMutator func([]byte
119134
assert.NoError(t, err, "%v", err)
120135
if err != nil {
121136
return nil
137+
} // cert.Certificate[0]
138+
139+
var clientCertHash []byte
140+
if mutualTLS {
141+
clientCertHash = certHashFromRawCert(tlsCfg.Certificates[0].Certificate[0])
122142
}
123-
clientCertHash := certHashFromRawCert(cert.Certificate[0])
124143

125144
pkiID := common.PKIidType(endpoint)
126145
if pkiIDmutator != nil {
127146
pkiID = common.PKIidType(pkiIDmutator([]byte(endpoint)))
128147
}
129148
assert.NoError(t, err, "%v", err)
130149
msg := c.createConnectionMsg(pkiID, clientCertHash, []byte(endpoint), func(msg []byte) ([]byte, error) {
131-
return msg, nil
150+
if !mutualTLS {
151+
return msg, nil
152+
}
153+
mac := hmac.New(sha256.New, hmacKey)
154+
mac.Write(msg)
155+
return mac.Sum(nil), nil
132156
})
133157

134158
if sigMutator != nil {
@@ -143,9 +167,14 @@ func handshaker(endpoint string, comm Comm, t *testing.T, sigMutator func([]byte
143167
if sigMutator == nil {
144168
hash := extractCertificateHashFromContext(stream.Context())
145169
expectedMsg := c.createConnectionMsg(common.PKIidType("localhost:9611"), hash, []byte("localhost:9611"), func(msg []byte) ([]byte, error) {
146-
return msg, nil
170+
mac := hmac.New(sha256.New, hmacKey)
171+
mac.Write(msg)
172+
return mac.Sum(nil), nil
147173
})
148-
assert.Equal(t, expectedMsg.Envelope.Signature, msg.Envelope.Signature)
174+
if mutualTLS {
175+
assert.Equal(t, expectedMsg.Envelope.Signature, msg.Envelope.Signature)
176+
}
177+
149178
}
150179
assert.Equal(t, []byte("localhost:9611"), msg.GetConn().PkiId)
151180
msg2Send := createGossipMsg()
@@ -177,7 +206,7 @@ func TestHandshake(t *testing.T) {
177206
comm, _ := newCommInstance(9611, naiveSec)
178207
defer comm.Stop()
179208

180-
acceptChan := handshaker("localhost:9610", comm, t, nil, nil)
209+
acceptChan := handshaker("localhost:9610", comm, t, nil, nil, true)
181210
time.Sleep(2 * time.Second)
182211
assert.Equal(t, 1, len(acceptChan))
183212
msg := <-acceptChan
@@ -186,7 +215,8 @@ func TestHandshake(t *testing.T) {
186215
assert.Equal(t, api.PeerIdentityType("localhost:9610"), msg.GetConnectionInfo().Identity)
187216
assert.NotNil(t, msg.GetConnectionInfo().Auth)
188217
assert.True(t, msg.GetConnectionInfo().IsAuthenticated())
189-
assert.Equal(t, msg.GetConnectionInfo().Auth.Signature, msg.GetConnectionInfo().Auth.SignedData)
218+
sig, _ := (&naiveSecProvider{}).Sign(msg.GetConnectionInfo().Auth.SignedData)
219+
assert.Equal(t, sig, msg.GetConnectionInfo().Auth.Signature)
190220
// negative path, nothing should be read from the channel because the signature is wrong
191221
mutateSig := func(b []byte) []byte {
192222
if b[0] == 0 {
@@ -196,17 +226,36 @@ func TestHandshake(t *testing.T) {
196226
}
197227
return b
198228
}
199-
acceptChan = handshaker("localhost:9612", comm, t, mutateSig, nil)
229+
acceptChan = handshaker("localhost:9612", comm, t, mutateSig, nil, true)
200230
time.Sleep(time.Second)
201231
assert.Equal(t, 0, len(acceptChan))
202232

203233
// negative path, nothing should be read from the channel because the PKIid doesn't match the identity
204234
mutatePKIID := func(b []byte) []byte {
205235
return []byte("localhost:9650")
206236
}
207-
acceptChan = handshaker("localhost:9613", comm, t, nil, mutatePKIID)
237+
acceptChan = handshaker("localhost:9613", comm, t, nil, mutatePKIID, true)
208238
time.Sleep(time.Second)
209239
assert.Equal(t, 0, len(acceptChan))
240+
241+
// Now we test for a handshake without mutual TLS
242+
// The first time should fail
243+
acceptChan = handshaker("localhost:9614", comm, t, nil, nil, false)
244+
select {
245+
case <-acceptChan:
246+
assert.Fail(t, "Should not have successfully authenticated to remote peer")
247+
case <-time.After(time.Second):
248+
}
249+
250+
// And the second time should succeed
251+
comm.(*commImpl).skipHandshake = true
252+
acceptChan = handshaker("localhost:9615", comm, t, nil, nil, false)
253+
select {
254+
case <-acceptChan:
255+
case <-time.After(time.Second * 10):
256+
assert.Fail(t, "skipHandshake flag should have authorized the authentication")
257+
}
258+
210259
}
211260

212261
func TestBasic(t *testing.T) {

peer/core.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ peer:
126126
# This is an endpoint that is published to peers outside of the organization.
127127
# If this isn't set, the peer will not be known to other organizations.
128128
externalEndpoint:
129+
# Makes gossip skip verification of remote peer signature when performing
130+
# the authentication handshake with remote peers
131+
skipHandshake: false
129132

130133
# Leader election service configuration
131134
election:

0 commit comments

Comments
 (0)