Skip to content

Commit

Permalink
[FAB-5207] Check channel create channelID mismatch
Browse files Browse the repository at this point in the history
The flow for channel creation works loosely as follows.

1. Look up channel resources by channelID from ChannelHeader
2. If missing, propose a new channel, based on the config update
3. Extract the channel ID from the config update, create a template
config from the consortium definition, and check if the config update
satisfies the channel creation policy.
4. Add the new channel resources to the channels map.

The problem is that between step 1/2 if the channelID is mismatched, the
internal channel construction logic will believe it is building
channelInner, while externally, this channel gets registered as
channelOuter.

Thus, it is possible to replay a channel creation TX by modifying the
outer header.  The new channel will be somewhat broken and all
configuration updates against it will fail.

This CR adds a simple check to verify that the ChannelHeader ChannelID
matches the ConfigUpdate channelID.

Change-Id: I23b088563016e0aa9f30524887c3c3d49b5942fb
Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
  • Loading branch information
Jason Yellick committed Jul 7, 2017
1 parent 9d159a7 commit 4709b33
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 0 deletions.
9 changes: 9 additions & 0 deletions orderer/multichain/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,11 +213,20 @@ func (ml *multiLedger) NewChannelConfig(envConfigUpdate *cb.Envelope) (configtxa
return nil, fmt.Errorf("Failing initial channel config creation because of config update envelope unmarshaling error: %s", err)
}

if configUpdatePayload.Header == nil {
return nil, fmt.Errorf("Failed initial channel config creation because config update header was missing")
}
channelHeader, err := utils.UnmarshalChannelHeader(configUpdatePayload.Header.ChannelHeader)

configUpdate, err := configtx.UnmarshalConfigUpdate(configUpdateEnv.ConfigUpdate)
if err != nil {
return nil, fmt.Errorf("Failing initial channel config creation because of config update unmarshaling error: %s", err)
}

if configUpdate.ChannelId != channelHeader.ChannelId {
return nil, fmt.Errorf("Failing initial channel config creation: mismatched channel IDs: '%s' != '%s'", configUpdate.ChannelId, channelHeader.ChannelId)
}

if configUpdate.WriteSet == nil {
return nil, fmt.Errorf("Config update has an empty writeset")
}
Expand Down
30 changes: 30 additions & 0 deletions orderer/multichain/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ func TestNewChannelConfig(t *testing.T) {
{
"BadConfigUpdate",
&cb.Payload{
Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))},
Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
ConfigUpdate: []byte("bad config update envelope data"),
}),
Expand All @@ -308,6 +309,7 @@ func TestNewChannelConfig(t *testing.T) {
{
"EmptyConfigUpdateWriteSet",
&cb.Payload{
Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))},
Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
ConfigUpdate: utils.MarshalOrPanic(
&cb.ConfigUpdate{},
Expand All @@ -319,6 +321,7 @@ func TestNewChannelConfig(t *testing.T) {
{
"WriteSetNoGroups",
&cb.Payload{
Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))},
Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
ConfigUpdate: utils.MarshalOrPanic(
&cb.ConfigUpdate{
Expand All @@ -332,6 +335,7 @@ func TestNewChannelConfig(t *testing.T) {
{
"WriteSetNoApplicationGroup",
&cb.Payload{
Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))},
Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
ConfigUpdate: utils.MarshalOrPanic(
&cb.ConfigUpdate{
Expand All @@ -347,6 +351,7 @@ func TestNewChannelConfig(t *testing.T) {
{
"BadWriteSetApplicationGroupVersion",
&cb.Payload{
Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))},
Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
ConfigUpdate: utils.MarshalOrPanic(
&cb.ConfigUpdate{
Expand All @@ -366,6 +371,7 @@ func TestNewChannelConfig(t *testing.T) {
{
"MissingWriteSetConsortiumValue",
&cb.Payload{
Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))},
Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
ConfigUpdate: utils.MarshalOrPanic(
&cb.ConfigUpdate{
Expand All @@ -386,6 +392,7 @@ func TestNewChannelConfig(t *testing.T) {
{
"BadWriteSetConsortiumValueValue",
&cb.Payload{
Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))},
Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
ConfigUpdate: utils.MarshalOrPanic(
&cb.ConfigUpdate{
Expand All @@ -410,6 +417,7 @@ func TestNewChannelConfig(t *testing.T) {
{
"UnknownConsortiumName",
&cb.Payload{
Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))},
Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
ConfigUpdate: utils.MarshalOrPanic(
&cb.ConfigUpdate{
Expand Down Expand Up @@ -438,6 +446,7 @@ func TestNewChannelConfig(t *testing.T) {
{
"Missing consortium members",
&cb.Payload{
Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))},
Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
ConfigUpdate: utils.MarshalOrPanic(
&cb.ConfigUpdate{
Expand Down Expand Up @@ -466,6 +475,7 @@ func TestNewChannelConfig(t *testing.T) {
{
"Member not in consortium",
&cb.Payload{
Header: &cb.Header{ChannelHeader: utils.MarshalOrPanic(utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, 0, "", epoch))},
Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
ConfigUpdate: utils.MarshalOrPanic(
&cb.ConfigUpdate{
Expand Down Expand Up @@ -505,6 +515,26 @@ func TestNewChannelConfig(t *testing.T) {
// SampleConsortium
}

func TestMismatchedChannelIDs(t *testing.T) {
innerChannelID := "foo"
outerChannelID := "bar"
template := configtx.NewChainCreationTemplate(genesisconfig.SampleConsortiumName, nil)
configUpdateEnvelope, err := template.Envelope(innerChannelID)
createTx, err := utils.CreateSignedEnvelope(cb.HeaderType_CONFIG_UPDATE, outerChannelID, nil, configUpdateEnvelope, msgVersion, epoch)
assert.NoError(t, err)

lf, _ := NewRAMLedgerAndFactory(10)

consenters := make(map[string]Consenter)
consenters[conf.Orderer.OrdererType] = &mockConsenter{}

manager := NewManagerImpl(lf, consenters, mockCrypto())

_, err = manager.NewChannelConfig(createTx)
assert.Error(t, err, "Mismatched channel IDs")
assert.Regexp(t, "mismatched channel IDs", err.Error())
}

// This test brings up the entire system, with the mock consenter, including the broadcasters etc. and creates a new chain
func TestNewChain(t *testing.T) {
expectedLastConfigBlockNumber := uint64(0)
Expand Down

0 comments on commit 4709b33

Please sign in to comment.