Skip to content

Commit 9d04269

Browse files
committed
[FAB-2061] Gossip inter-org confidentiality - P3
In the previous commit, I extended the pull mechanism to support filtering based on the remote peer. The goal was to ensure that peers only gossip identities of either their own organization, or of organizations they are gossiping with. (Meaning- if A gossips with B identities, the identities that are sent are either identities of A or of B). In this commit I hook a filter to the constructor of the identity puller that extracts the organization of the remote peer, and based on the organization of the digest (which is the PKI-ID of the identity), the filter ensures the confidentiality explained above. I also extended the test of the first commit in the series, to inspect identities that travel between organizations, to make sure that the confidentiality rules are preserved. I also did the following test, to make sure that state transfer between peers still works: network_setup.sh: Overided the docker-compose file with docker-compose-no-tls peer-base/peer-base-no-tls.yaml: I made both options: - CORE_PEER_GOSSIP_ORGLEADER=false - CORE_PEER_GOSSIP_USELEADERELECTION=false And in docker-compose-no-tls.yaml I made ONLY peer0 to be ORGLEADER-true Then I ran network_setup.sh up and it passed, so this proves that peer2 and peer3 got their blocks from peer0 (or peer1). Change-Id: Ied4979dd5cfc24ef7b0d1bc092653e9f037a64f2 Signed-off-by: Yacov Manevich <[email protected]>
1 parent 88ac3ba commit 9d04269

File tree

2 files changed

+78
-12
lines changed

2 files changed

+78
-12
lines changed

gossip/gossip/gossip_impl.go

+28-1
Original file line numberDiff line numberDiff line change
@@ -938,17 +938,44 @@ func (g *gossipServiceImpl) createCertStorePuller() pull.Mediator {
938938
g.logger.Warning("Failed associating PKI-ID with certificate:", err)
939939
}
940940
g.logger.Info("Learned of a new certificate:", idMsg.Cert)
941-
942941
}
943942
adapter := pull.PullAdapter{
944943
Sndr: g.comm,
945944
MemSvc: g.disc,
946945
IdExtractor: pkiIDFromMsg,
947946
MsgCons: certConsumer,
947+
DigFilter: g.sameOrgOrOurOrgPullFilter,
948948
}
949949
return pull.NewPullMediator(conf, adapter)
950950
}
951951

952+
func (g *gossipServiceImpl) sameOrgOrOurOrgPullFilter(msg proto.ReceivedMessage) func(string) bool {
953+
peersOrg := g.secAdvisor.OrgByPeerIdentity(msg.GetConnectionInfo().Identity)
954+
if len(peersOrg) == 0 {
955+
g.logger.Warning("Failed determining organization of", msg.GetConnectionInfo())
956+
return func(_ string) bool {
957+
return false
958+
}
959+
}
960+
961+
// If the peer is from our org, gossip all identities
962+
if bytes.Equal(g.selfOrg, peersOrg) {
963+
return func(_ string) bool {
964+
return true
965+
}
966+
}
967+
return func(item string) bool {
968+
pkiID := common.PKIidType(item)
969+
msgsOrg := g.getOrgOfPeer(pkiID)
970+
if len(msgsOrg) == 0 {
971+
g.logger.Warning("Failed determining organization of", pkiID)
972+
return false
973+
}
974+
// Peer from our org or identity from our org or identity from peer's org
975+
return bytes.Equal(msgsOrg, g.selfOrg) || bytes.Equal(msgsOrg, peersOrg)
976+
}
977+
}
978+
952979
func (g *gossipServiceImpl) createStateInfoMsg(metadata []byte, chainID common.ChainID) (*proto.SignedGossipMessage, error) {
953980
pkiID := g.comm.GetPKIid()
954981
stateInfMsg := &proto.StateInfo{

gossip/gossip/orgs_test.go

+50-11
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,10 @@ package gossip
1919
import (
2020
"bytes"
2121
"fmt"
22-
"testing"
23-
"time"
24-
2522
"sync"
2623
"sync/atomic"
24+
"testing"
25+
"time"
2726

2827
"github.com/hyperledger/fabric/bccsp/factory"
2928
"github.com/hyperledger/fabric/gossip/api"
@@ -271,6 +270,10 @@ func TestConfidentiality(t *testing.T) {
271270
peersInOrg := 3
272271
externalEndpointsInOrg := 2
273272

273+
// orgA: {12610, 12611, 12612}
274+
// orgB: {12613, 12614, 12615}
275+
// orgC: {12616, 12617, 12618}
276+
// orgD: {12619, 12620, 12621}
274277
orgs := []string{"A", "B", "C", "D"}
275278
channels := []string{"C0", "C1", "C2", "C3"}
276279
isOrgInChan := func(org string, channel string) bool {
@@ -335,15 +338,16 @@ func TestConfidentiality(t *testing.T) {
335338
finished := int32(0)
336339
var wg sync.WaitGroup
337340

338-
membershipMsgs := func(o interface{}) bool {
341+
membershipAndIdentitiesMsgs := func(o interface{}) bool {
339342
msg := o.(proto.ReceivedMessage).GetGossipMessage()
340-
return msg.IsAliveMsg() || msg.GetMemRes() != nil
343+
identitiesPull := msg.IsPullMsg() && msg.GetPullMsgType() == proto.PullMsgType_IDENTITY_MSG
344+
return msg.IsAliveMsg() || msg.GetMemRes() != nil || identitiesPull
341345
}
342346
// Listen to all peers membership messages and forward them to the inspection channel
343347
// where they will be inspected, and the test would fail if a confidentiality violation is found
344348
for _, p := range peers {
345349
wg.Add(1)
346-
_, msgs := p.Accept(membershipMsgs, true)
350+
_, msgs := p.Accept(membershipAndIdentitiesMsgs, true)
347351
peerNetMember := p.(*gossipServiceImpl).selfNetworkMember()
348352
targetORg := string(cs.OrgByPeerIdentity(api.PeerIdentityType(peerNetMember.InternalEndpoint)))
349353
go func(targetOrg string, msgs <-chan proto.ReceivedMessage) {
@@ -380,11 +384,15 @@ func TestConfidentiality(t *testing.T) {
380384
if isOrgInChan(org, ch) {
381385
for _, p := range peers {
382386
p.JoinChan(joinChanMsgsByChan[ch], common.ChainID(ch))
387+
p.UpdateChannelMetadata([]byte{}, common.ChainID(ch))
383388
}
384389
}
385390
}
386391
}
387392

393+
// Sleep a bit, to let peers gossip with each other
394+
time.Sleep(time.Second * 7)
395+
388396
assertMembership := func() bool {
389397
for _, org := range orgs {
390398
for i, p := range orgs2Peers[org] {
@@ -448,13 +456,44 @@ func extractOrgsFromMsg(msg *proto.GossipMessage, sec api.SecurityAdvisor) []str
448456
if msg.IsAliveMsg() {
449457
return []string{string(sec.OrgByPeerIdentity(api.PeerIdentityType(msg.GetAliveMsg().Membership.PkiId)))}
450458
}
459+
451460
orgs := map[string]struct{}{}
452-
alive := msg.GetMemRes().Alive
453-
dead := msg.GetMemRes().Dead
454-
for _, envp := range append(alive, dead...) {
455-
msg, _ := envp.ToGossipMessage()
456-
orgs[string(sec.OrgByPeerIdentity(api.PeerIdentityType(msg.GetAliveMsg().Membership.PkiId)))] = struct{}{}
461+
462+
if msg.IsPullMsg() {
463+
if msg.IsDigestMsg() || msg.IsDataReq() {
464+
var digests []string
465+
if msg.IsDigestMsg() {
466+
digests = msg.GetDataDig().Digests
467+
} else {
468+
digests = msg.GetDataReq().Digests
469+
}
470+
471+
for _, dig := range digests {
472+
org := sec.OrgByPeerIdentity(api.PeerIdentityType(dig))
473+
orgs[string(org)] = struct{}{}
474+
}
475+
}
476+
477+
if msg.IsDataUpdate() {
478+
for _, identityMsg := range msg.GetDataUpdate().Data {
479+
gMsg, _ := identityMsg.ToGossipMessage()
480+
id := string(gMsg.GetPeerIdentity().Cert)
481+
org := sec.OrgByPeerIdentity(api.PeerIdentityType(id))
482+
orgs[string(org)] = struct{}{}
483+
}
484+
}
485+
457486
}
487+
488+
if msg.GetMemRes() != nil {
489+
alive := msg.GetMemRes().Alive
490+
dead := msg.GetMemRes().Dead
491+
for _, envp := range append(alive, dead...) {
492+
msg, _ := envp.ToGossipMessage()
493+
orgs[string(sec.OrgByPeerIdentity(api.PeerIdentityType(msg.GetAliveMsg().Membership.PkiId)))] = struct{}{}
494+
}
495+
}
496+
458497
res := []string{}
459498
for org := range orgs {
460499
res = append(res, org)

0 commit comments

Comments
 (0)