Skip to content

Commit 186b1a1

Browse files
committed
FAB-1046 Gossip identity learning
The current gossip component assumes the upper layers are able to fetch each remote peer's certificate by its corresponding PKI-ID. This is true for 0.5 but this isn't the case for v1, so this commit makes each peer send the other peer its certificate and each peer creates a mapping between PKIid-->certificate. The gossip layer now disseminates certificates of peers in the following ways: 1) During the handshake with a remote peer 2) At initialization time, there is a configurable period in which the cert is appended to the AliveMessage 3) Peers can now exchange with remote peers certificates by comparing the pkiIDs of the certificates. This works with the standard built-in pull mechanism. This commit also moves the comm layer into the gossip, instead of what was before- where the gossip was given an instance of the comm. Change-Id: I7fc3bb0fc59911759566a4b8a9759281ae843f08 Signed-off-by: Yacov Manevich <[email protected]>
1 parent bc1d8ae commit 186b1a1

21 files changed

+677
-573
lines changed

gossip/api/channel.go

+4-7
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import (
2727
type SecurityAdvisor interface {
2828
// IsInMyOrg returns whether the given peer's certificate represents
2929
// a peer in the invoker's organization
30-
IsInMyOrg(PeerCert) bool
30+
IsInMyOrg(PeerIdentityType) bool
3131

3232
// Verify verifies a JoinChannelMessage, returns nil on success,
3333
// and an error on failure
@@ -54,10 +54,7 @@ type JoinChannelMessage interface {
5454

5555
// ChannelMember is a peer's certificate and endpoint (host:port)
5656
type ChannelMember struct {
57-
Cert PeerCert // Cert defines the certificate of the remote peer
58-
Host string // Host is the hostname/ip address of the remote peer
59-
Port int // Port is the port the remote peer is listening on
57+
Cert PeerIdentityType // PeerIdentityType defines the certificate of the remote peer
58+
Host string // Host is the hostname/ip address of the remote peer
59+
Port int // Port is the port the remote peer is listening on
6060
}
61-
62-
// PeerCert defines the cryptographic identity of a peer
63-
type PeerCert []byte

gossip/api/crypto.go

+5
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ type MessageCryptoService interface {
3939
// If the verification succeeded, Verify returns nil meaning no error occurred.
4040
// If peerCert is nil, then the signature is verified against this peer's verification key.
4141
Verify(peerIdentity PeerIdentityType, signature, message []byte) error
42+
43+
// ValidateIdentity validates the identity of a remote peer.
44+
// If the identity is invalid, revoked, expired it returns an error.
45+
// Else, returns nil
46+
ValidateIdentity(peerIdentity PeerIdentityType) error
4247
}
4348

4449
// PeerIdentityType is the peer's certificate

gossip/comm/comm.go

-17
Original file line numberDiff line numberDiff line change
@@ -64,23 +64,6 @@ func (p *RemotePeer) String() string {
6464
return fmt.Sprintf("%s, PKIid:%v", p.Endpoint, p.PKIID)
6565
}
6666

67-
// SecurityProvider enables the communication module to perform
68-
// a handshake that authenticates the client to the server and vice versa
69-
type SecurityProvider interface {
70-
71-
// isEnabled returns whether this
72-
IsEnabled() bool
73-
74-
// Sign signs msg with this peers signing key and outputs
75-
// the signature if no error occurred.
76-
Sign(msg []byte) ([]byte, error)
77-
78-
// Verify checks that signature if a valid signature of message under vkID's verification key.
79-
// If the verification succeeded, Verify returns nil meaning no error occurred.
80-
// If vkID is nil, then the signature is verified against this validator's verification key.
81-
Verify(vkID, signature, message []byte) error
82-
}
83-
8467
// ReceivedMessage is a GossipMessage wrapper that
8568
// enables the user to send a message to the origin from which
8669
// the ReceivedMessage was sent from

gossip/comm/comm_impl.go

+42-27
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ import (
2727
"sync/atomic"
2828
"time"
2929

30+
"github.com/hyperledger/fabric/gossip/api"
3031
"github.com/hyperledger/fabric/gossip/common"
32+
"github.com/hyperledger/fabric/gossip/identity"
3133
"github.com/hyperledger/fabric/gossip/proto"
3234
"github.com/hyperledger/fabric/gossip/util"
3335
"github.com/op/go-logging"
@@ -62,7 +64,7 @@ func (c *commImpl) SetDialOpts(opts ...grpc.DialOption) {
6264
}
6365

6466
// NewCommInstanceWithServer creates a comm instance that creates an underlying gRPC server
65-
func NewCommInstanceWithServer(port int, sec SecurityProvider, pkID common.PKIidType, dialOpts ...grpc.DialOption) (Comm, error) {
67+
func NewCommInstanceWithServer(port int, idMapper identity.Mapper, peerIdentity api.PeerIdentityType, dialOpts ...grpc.DialOption) (Comm, error) {
6668
var ll net.Listener
6769
var s *grpc.Server
6870
var secOpt grpc.DialOption
@@ -77,10 +79,11 @@ func NewCommInstanceWithServer(port int, sec SecurityProvider, pkID common.PKIid
7779
}
7880

7981
commInst := &commImpl{
82+
PKIID: idMapper.GetPKIidOfCert(peerIdentity),
83+
idMapper: idMapper,
8084
logger: util.GetLogger(util.LOGGING_COMM_MODULE, fmt.Sprintf("%d", port)),
81-
PKIID: pkID,
85+
peerIdentity: peerIdentity,
8286
opts: dialOpts,
83-
sec: sec,
8487
port: port,
8588
lsnr: ll,
8689
gSrv: s,
@@ -92,15 +95,15 @@ func NewCommInstanceWithServer(port int, sec SecurityProvider, pkID common.PKIid
9295
subscriptions: make([]chan ReceivedMessage, 0),
9396
blackListedPKIIDs: make([]common.PKIidType, 0),
9497
}
95-
commInst.connStore = newConnStore(commInst, pkID, commInst.logger)
98+
commInst.connStore = newConnStore(commInst, commInst.logger)
99+
commInst.idMapper.Put(idMapper.GetPKIidOfCert(peerIdentity), peerIdentity)
96100

97101
if port > 0 {
98102
go func() {
99103
commInst.stopWG.Add(1)
100104
defer commInst.stopWG.Done()
101105
s.Serve(ll)
102106
}()
103-
104107
proto.RegisterGossipServer(s, commInst)
105108
}
106109

@@ -110,8 +113,8 @@ func NewCommInstanceWithServer(port int, sec SecurityProvider, pkID common.PKIid
110113
}
111114

112115
// NewCommInstance creates a new comm instance that binds itself to the given gRPC server
113-
func NewCommInstance(s *grpc.Server, sec SecurityProvider, PKIID common.PKIidType, dialOpts ...grpc.DialOption) (Comm, error) {
114-
commInst, err := NewCommInstanceWithServer(-1, sec, PKIID, dialOpts...)
116+
func NewCommInstance(s *grpc.Server, idStore identity.Mapper, peerIdentity api.PeerIdentityType, dialOpts ...grpc.DialOption) (Comm, error) {
117+
commInst, err := NewCommInstanceWithServer(-1, idStore, peerIdentity, dialOpts...)
115118
if err != nil {
116119
return nil, err
117120
}
@@ -120,8 +123,9 @@ func NewCommInstance(s *grpc.Server, sec SecurityProvider, PKIID common.PKIidTyp
120123
}
121124

122125
type commImpl struct {
126+
peerIdentity api.PeerIdentityType
127+
idMapper identity.Mapper
123128
logger *util.Logger
124-
sec SecurityProvider
125129
opts []grpc.DialOption
126130
connStore *connectionStore
127131
PKIID []byte
@@ -168,7 +172,6 @@ func (c *commImpl) createConnection(endpoint string, expectedPKIID common.PKIidT
168172
if expectedPKIID != nil && !bytes.Equal(pkiID, expectedPKIID) {
169173
// PKIID is nil when we don't know the remote PKI id's
170174
c.logger.Warning("Remote endpoint claims to be a different peer, expected", expectedPKIID, "but got", pkiID)
171-
cc.Close()
172175
return nil, fmt.Errorf("Authentication failure")
173176
}
174177
conn := newConnection(cl, cc, stream, nil)
@@ -252,18 +255,20 @@ func (c *commImpl) isStopping() bool {
252255
return atomic.LoadInt32(&c.stopping) == int32(1)
253256
}
254257

255-
func (c *commImpl) Probe(peer *RemotePeer) error {
258+
func (c *commImpl) Probe(remotePeer *RemotePeer) error {
259+
endpoint := remotePeer.Endpoint
260+
pkiID := remotePeer.PKIID
256261
if c.isStopping() {
257262
return fmt.Errorf("Stopping")
258263
}
259-
c.logger.Debug("Entering, endpoint:", peer.Endpoint, "PKIID:", peer.PKIID)
264+
c.logger.Debug("Entering, endpoint:", endpoint, "PKIID:", pkiID)
260265
var err error
261266

262267
opts := c.opts
263268
if opts == nil {
264269
opts = []grpc.DialOption{grpc.WithInsecure(), grpc.WithTimeout(dialTimeout)}
265270
}
266-
cc, err := grpc.Dial(peer.Endpoint, append(opts, grpc.WithBlock())...)
271+
cc, err := grpc.Dial(endpoint, append(opts, grpc.WithBlock())...)
267272
if err != nil {
268273
c.logger.Debug("Returning", err)
269274
return err
@@ -373,45 +378,54 @@ func (c *commImpl) authenticateRemotePeer(stream stream) (common.PKIidType, erro
373378
tlsUnique := ExtractTLSUnique(ctx)
374379
var sig []byte
375380
var err error
376-
if tlsUnique != nil && c.sec.IsEnabled() {
377-
sig, err = c.sec.Sign(tlsUnique)
381+
if tlsUnique != nil {
382+
sig, err = c.idMapper.Sign(tlsUnique)
378383
if err != nil {
379384
c.logger.Error("Failed signing TLS-Unique:", err)
380385
return nil, err
381386
}
382387
}
383388

384-
cMsg := createConnectionMsg(c.PKIID, sig)
389+
cMsg := createConnectionMsg(c.PKIID, sig, c.peerIdentity)
390+
c.logger.Debug("Sending", cMsg, "to", remoteAddress)
385391
stream.Send(cMsg)
386392
m := readWithTimeout(stream, defConnTimeout)
387393
if m == nil {
388394
c.logger.Warning("Timed out waiting for connection message from", remoteAddress)
389395
return nil, fmt.Errorf("Timed out")
390396
}
391-
connMsg := m.GetConn()
392-
if connMsg == nil {
393-
c.logger.Warning("Expected connection message but got", connMsg)
397+
receivedMsg := m.GetConn()
398+
if receivedMsg == nil {
399+
c.logger.Warning("Expected connection message but got", receivedMsg)
394400
return nil, fmt.Errorf("Wrong type")
395401
}
396-
if c.isPKIblackListed(connMsg.PkiID) {
402+
403+
if receivedMsg.PkiID == nil {
404+
c.logger.Warning("%s didn't send a pkiID")
405+
return nil, fmt.Errorf("%s didn't send a pkiID", remoteAddress)
406+
}
407+
408+
if c.isPKIblackListed(receivedMsg.PkiID) {
397409
c.logger.Warning("Connection attempt from", remoteAddress, "but it is black-listed")
398410
return nil, fmt.Errorf("Black-listed")
399411
}
412+
c.logger.Debug("Received", receivedMsg, "from", remoteAddress)
413+
err = c.idMapper.Put(receivedMsg.PkiID, receivedMsg.Cert)
414+
if err != nil {
415+
c.logger.Warning("Identity store rejected", remoteAddress, ":", err)
416+
return nil, err
417+
}
400418

401-
if tlsUnique != nil && c.sec.IsEnabled() {
402-
err = c.sec.Verify(connMsg.PkiID, connMsg.Sig, tlsUnique)
419+
if tlsUnique != nil {
420+
err = c.idMapper.Verify(receivedMsg.PkiID, receivedMsg.Sig, tlsUnique)
403421
if err != nil {
404422
c.logger.Error("Failed verifying signature from", remoteAddress, ":", err)
405423
return nil, err
406424
}
407425
}
408426

409-
if connMsg.PkiID == nil {
410-
return nil, fmt.Errorf("%s didn't send a pkiID", "Didn't send a pkiID")
411-
}
412-
413427
c.logger.Debug("Authenticated", remoteAddress)
414-
return connMsg.PkiID, nil
428+
return receivedMsg.PkiID, nil
415429

416430
}
417431

@@ -486,12 +500,13 @@ func readWithTimeout(stream interface{}, timeout time.Duration) *proto.GossipMes
486500
}
487501
}
488502

489-
func createConnectionMsg(pkiID common.PKIidType, sig []byte) *proto.GossipMessage {
503+
func createConnectionMsg(pkiID common.PKIidType, sig []byte, cert api.PeerIdentityType) *proto.GossipMessage {
490504
return &proto.GossipMessage{
491505
Tag: proto.GossipMessage_EMPTY,
492506
Nonce: 0,
493507
Content: &proto.GossipMessage_Conn{
494508
Conn: &proto.ConnEstablish{
509+
Cert: cert,
495510
PkiID: pkiID,
496511
Sig: sig,
497512
},

0 commit comments

Comments
 (0)