Skip to content

Commit 90573e8

Browse files
committed
[FAB-2962] Gossip- Channel name obfuscation
This commit changes the stateInfo messages in gossip in the following way: Instead of sending the plaintext of the channel in the channel field of the GossipMessage - it now sends instead: Hash(channel || PKI-ID). The added security benefit: Given a message M with a channel C, a peer not in C needs to do an exhaustive search / dictionary attack on channel names, in order to guess C. Without knowing C, it cannot ask an ordering service, or some other peer to get a block for that channel because sending the hash would be worthless. On reception of a StateInfo message from a peer with PKI-ID P, a peer iterates over all channels (denote CHAN as the current iteration) it participates in, and computes Hash(P || CHAN) and this way it knows the channel the message relates to. - If it is not in the channel, it would simply forward the message to peers in the organization (as done today). - Else, it forwards the message to peers that their organization is a member of the channel (as done today). Change-Id: I419ed3e440b936de80ec5624698b5d6e52376e98 Signed-off-by: Yacov Manevich <[email protected]>
1 parent c3009e6 commit 90573e8

File tree

6 files changed

+334
-146
lines changed

6 files changed

+334
-146
lines changed

gossip/gossip/channel/channel.go

+55-16
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"sync/atomic"
2424
"time"
2525

26+
common_utils "github.com/hyperledger/fabric/common/util"
2627
"github.com/hyperledger/fabric/gossip/api"
2728
"github.com/hyperledger/fabric/gossip/comm"
2829
"github.com/hyperledger/fabric/gossip/common"
@@ -115,6 +116,7 @@ type gossipChannel struct {
115116
sync.RWMutex
116117
shouldGossipStateInfo int32
117118
mcs api.MessageCryptoService
119+
pkiID common.PKIidType
118120
stopChan chan struct{}
119121
stateInfoMsg *proto.SignedGossipMessage
120122
orgs []api.OrgIdentityType
@@ -147,8 +149,9 @@ func (mf *membershipFilter) GetMembership() []discovery.NetworkMember {
147149
}
148150

149151
// NewGossipChannel creates a new GossipChannel
150-
func NewGossipChannel(mcs api.MessageCryptoService, chainID common.ChainID, adapter Adapter, joinMsg api.JoinChannelMessage) GossipChannel {
152+
func NewGossipChannel(pkiID common.PKIidType, mcs api.MessageCryptoService, chainID common.ChainID, adapter Adapter, joinMsg api.JoinChannelMessage) GossipChannel {
151153
gc := &gossipChannel{
154+
pkiID: pkiID,
152155
mcs: mcs,
153156
Adapter: adapter,
154157
logger: util.GetLogger(util.LoggingChannelModule, adapter.GetConf().ID),
@@ -359,7 +362,7 @@ func (gc *gossipChannel) HandleMessage(msg proto.ReceivedMessage) {
359362
return
360363
}
361364
if !gc.IsOrgInChannel(orgID) {
362-
gc.logger.Warning("Point to point message came from", msg.GetConnectionInfo().ID, "but it's not eligible for the channel", msg.GetGossipMessage().Channel)
365+
gc.logger.Warning("Point to point message came from", msg.GetConnectionInfo().ID, "but it's not eligible for the channel", string(gc.chainID))
363366
return
364367
}
365368

@@ -405,7 +408,7 @@ func (gc *gossipChannel) HandleMessage(msg proto.ReceivedMessage) {
405408
}
406409
if m.IsPullMsg() && m.GetPullMsgType() == proto.PullMsgType_BLOCK_MSG {
407410
if !gc.EligibleForChannel(discovery.NetworkMember{PKIid: msg.GetConnectionInfo().ID}) {
408-
gc.logger.Warning(msg.GetConnectionInfo().ID, "isn't eligible for channel", gc.chainID)
411+
gc.logger.Warning(msg.GetConnectionInfo().ID, "isn't eligible for channel", string(gc.chainID))
409412
return
410413
}
411414
if m.IsDataUpdate() {
@@ -437,35 +440,42 @@ func (gc *gossipChannel) HandleMessage(msg proto.ReceivedMessage) {
437440
}
438441

439442
func (gc *gossipChannel) handleStateInfSnapshot(m *proto.GossipMessage, sender common.PKIidType) {
443+
chanName := string(gc.chainID)
440444
for _, envelope := range m.GetStateSnapshot().Elements {
441445
stateInf, err := envelope.ToGossipMessage()
442446
if err != nil {
443-
gc.logger.Warning("StateInfo snapshot contains an invalid message:", err)
447+
gc.logger.Warning("Channel", chanName, ": StateInfo snapshot contains an invalid message:", err)
444448
return
445449
}
446450
if !stateInf.IsStateInfoMsg() {
447-
gc.logger.Warning("Element of StateInfoSnapshot isn't a StateInfoMessage:", stateInf, "message sent from", sender)
451+
gc.logger.Warning("Channel", chanName, ": Element of StateInfoSnapshot isn't a StateInfoMessage:",
452+
stateInf, "message sent from", sender)
448453
return
449454
}
450-
451-
orgID := gc.GetOrgOfPeer(stateInf.GetStateInfo().PkiId)
455+
si := stateInf.GetStateInfo()
456+
orgID := gc.GetOrgOfPeer(si.PkiId)
452457
if orgID == nil {
453-
gc.logger.Warning("Couldn't find org identity of peer", stateInf.GetStateInfo().PkiId, "message sent from", sender)
458+
gc.logger.Warning("Channel", chanName, ": Couldn't find org identity of peer",
459+
si.PkiId, "message sent from", sender)
454460
return
455461
}
456462

457463
if !gc.IsOrgInChannel(orgID) {
458-
gc.logger.Warning("Peer", stateInf.GetStateInfo().PkiId, "is not in an eligible org, can't process a stateInfo from it, sent from", sender)
464+
gc.logger.Warning("Channel", chanName, ": Peer", stateInf.GetStateInfo().PkiId,
465+
"is not in an eligible org, can't process a stateInfo from it, sent from", sender)
459466
return
460467
}
461468

462-
if !bytes.Equal(stateInf.Channel, []byte(gc.chainID)) {
463-
gc.logger.Warning("StateInfo message is of an invalid channel", stateInf, "sent from", sender)
469+
expectedMAC := ChannelMAC(si.PkiId, gc.chainID)
470+
if !bytes.Equal(si.ChannelMAC, expectedMAC) {
471+
gc.logger.Warning("Channel", chanName, ": StateInfo message", stateInf,
472+
", has an invalid MAC. Expected", expectedMAC, ", got", si.ChannelMAC, ", sent from", sender)
464473
return
465474
}
466475
err = gc.ValidateStateInfoMessage(stateInf)
467476
if err != nil {
468-
gc.logger.Warning("Failed validating state info message:", stateInf, ":", err, "sent from", sender)
477+
gc.logger.Warning("Channel", chanName, ": Failed validating state info message:",
478+
stateInf, ":", err, "sent from", sender)
469479
return
470480
}
471481
gc.stateInfoMsgStore.Add(stateInf)
@@ -524,6 +534,26 @@ func (gc *gossipChannel) verifyMsg(msg proto.ReceivedMessage) bool {
524534
return false
525535
}
526536

537+
if m.IsStateInfoMsg() {
538+
si := m.GetStateInfo()
539+
expectedMAC := ChannelMAC(si.PkiId, gc.chainID)
540+
if !bytes.Equal(expectedMAC, si.ChannelMAC) {
541+
gc.logger.Warning("Message contains wrong channel MAC(", si.ChannelMAC, "), expected", expectedMAC)
542+
return false
543+
}
544+
return true
545+
}
546+
547+
if m.IsStateInfoPullRequestMsg() {
548+
sipr := m.GetStateInfoPullReq()
549+
expectedMAC := ChannelMAC(msg.GetConnectionInfo().ID, gc.chainID)
550+
if !bytes.Equal(expectedMAC, sipr.ChannelMAC) {
551+
gc.logger.Warning("Message contains wrong channel MAC(", sipr.ChannelMAC, "), expected", expectedMAC)
552+
return false
553+
}
554+
return true
555+
}
556+
527557
if !bytes.Equal(m.Channel, []byte(gc.chainID)) {
528558
gc.logger.Warning("Message contains wrong channel(", m.Channel, "), expected", gc.chainID)
529559
return false
@@ -533,11 +563,12 @@ func (gc *gossipChannel) verifyMsg(msg proto.ReceivedMessage) bool {
533563

534564
func (gc *gossipChannel) createStateInfoRequest() *proto.SignedGossipMessage {
535565
return (&proto.GossipMessage{
536-
Channel: gc.chainID,
537-
Tag: proto.GossipMessage_CHAN_OR_ORG,
538-
Nonce: 0,
566+
Tag: proto.GossipMessage_CHAN_OR_ORG,
567+
Nonce: 0,
539568
Content: &proto.GossipMessage_StateInfoPullReq{
540-
StateInfoPullReq: &proto.StateInfoPullRequest{},
569+
StateInfoPullReq: &proto.StateInfoPullRequest{
570+
ChannelMAC: ChannelMAC(gc.pkiID, gc.chainID),
571+
},
541572
},
542573
}).NoopSign()
543574
}
@@ -586,3 +617,11 @@ func (cache *stateInfoCache) Add(msg *proto.SignedGossipMessage) bool {
586617
}
587618
return added
588619
}
620+
621+
// ChannelMAC returns a byte slice that is derived from the peer's PKI-ID
622+
// and a channel name
623+
func ChannelMAC(pkiID common.PKIidType, channelID common.ChainID) []byte {
624+
// Hash is computed on (PKI-ID || channel ID)
625+
preImage := append([]byte(pkiID), []byte(channelID)...)
626+
return common_utils.ComputeSHA256(preImage)
627+
}

0 commit comments

Comments
 (0)