Skip to content

Commit 312628c

Browse files
Jason Yellickkchristidis
Jason Yellick
authored andcommitted
[FAB-1302] (PA) Add channel create authorization
There is currently no inspection of the channel creation transaction. This means that during a channel creation, the creator could inappropriately specify config, including items like orderer parameters, and the ordering service would silently accept this incorrect parameters. This is especially troublesome from a security perspective, as a specially crafted config tx could potentially trick another user into believe they were participating in a channel with one member when they are actually participating with another. This CR adds this checking by leveraging the existing underlying authorization mechanisms of the configuration transaction. It ensures that the creating members are not only authorized to create the channel, but also ensures that all channel config that is set is done so in accordance with the underlying governance for that config element. This means that a collection of authorized ordering organizations may choose to modifying ordering parameters in a channel creation request while a set of application orgs would not be able to. This CR is somewhat large due to the significant invasive nature of this change, and that the entire end to end must be modified, not just a single component. However, given the increase in function with decrease in complexity, the diff stat is hopefully acceptable. Change-Id: I9bb64d3f70d07eb8a8a4ea4893c71cf1112b4bf7 Signed-off-by: Jason Yellick <[email protected]> Signed-off-by: Kostas Christidis <[email protected]>
1 parent 8288a7f commit 312628c

File tree

23 files changed

+642
-366
lines changed

23 files changed

+642
-366
lines changed

common/cauthdsl/cauthdsl.go

+11-8
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func compile(policy *cb.SignaturePolicy, identities []*mb.MSPPrincipal, deserial
4141

4242
}
4343
return func(signedData []*cb.SignedData, used []bool) bool {
44-
cauthdslLogger.Debugf("Gate evaluation starts: (%s)", t)
44+
cauthdslLogger.Debugf("Gate evaluation starts: (%v)", t)
4545
verified := int32(0)
4646
_used := make([]bool, len(used))
4747
for _, policy := range policies {
@@ -53,20 +53,20 @@ func compile(policy *cb.SignaturePolicy, identities []*mb.MSPPrincipal, deserial
5353
}
5454

5555
if verified >= t.NOutOf.N {
56-
cauthdslLogger.Debugf("Gate evaluation succeeds: (%s)", t)
56+
cauthdslLogger.Debugf("Gate evaluation succeeds: (%v)", t)
5757
} else {
58-
cauthdslLogger.Debugf("Gate evaluation fails: (%s)", t)
58+
cauthdslLogger.Debugf("Gate evaluation fails: (%v)", t)
5959
}
6060

6161
return verified >= t.NOutOf.N
6262
}, nil
6363
case *cb.SignaturePolicy_SignedBy:
6464
if t.SignedBy < 0 || t.SignedBy >= int32(len(identities)) {
65-
return nil, fmt.Errorf("Identity index out of range, requested %d, but identies length is %d", t.SignedBy, len(identities))
65+
return nil, fmt.Errorf("Identity index out of range, requested %v, but identies length is %d", t.SignedBy, len(identities))
6666
}
6767
signedByID := identities[t.SignedBy]
6868
return func(signedData []*cb.SignedData, used []bool) bool {
69-
cauthdslLogger.Debugf("Principal evaluation starts: (%s) (used %s)", t, used)
69+
cauthdslLogger.Debugf("Principal evaluation starts: (%v) (used %v)", t, used)
7070
for i, sd := range signedData {
7171
if used[i] {
7272
continue
@@ -78,15 +78,18 @@ func compile(policy *cb.SignaturePolicy, identities []*mb.MSPPrincipal, deserial
7878
}
7979
err = identity.SatisfiesPrincipal(signedByID)
8080
if err == nil {
81-
err := identity.Verify(sd.Data, sd.Signature)
81+
cauthdslLogger.Debugf("Principal matched by identity: (%v) for %v", t, sd.Identity)
82+
err = identity.Verify(sd.Data, sd.Signature)
8283
if err == nil {
83-
cauthdslLogger.Debugf("Principal evaluation succeeds: (%s) (used %s)", t, used)
84+
cauthdslLogger.Debugf("Principal evaluation succeeds: (%v) (used %v)", t, used)
8485
used[i] = true
8586
return true
8687
}
88+
} else {
89+
cauthdslLogger.Debugf("Identity (%v) does not satisfy principal: %s", sd.Identity, err)
8790
}
8891
}
89-
cauthdslLogger.Debugf("Principal evaluation fails: (%s)", t, used)
92+
cauthdslLogger.Debugf("Principal evaluation fails: (%v) %v", t, used)
9093
return false
9194
}, nil
9295
default:

common/configtx/template.go

+38-14
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ import (
2020
"fmt"
2121

2222
"github.com/hyperledger/fabric/common/config"
23+
configmsp "github.com/hyperledger/fabric/common/config/msp"
24+
"github.com/hyperledger/fabric/common/policies"
2325
"github.com/hyperledger/fabric/common/util"
2426
"github.com/hyperledger/fabric/msp"
2527
cb "github.com/hyperledger/fabric/protos/common"
26-
ab "github.com/hyperledger/fabric/protos/orderer"
2728
"github.com/hyperledger/fabric/protos/utils"
2829

2930
"github.com/golang/protobuf/proto"
@@ -195,28 +196,51 @@ type channelCreationTemplate struct {
195196
orgs []string
196197
}
197198

198-
// NewChainCreationTemplate takes a CreationPolicy and a Template to produce a
199+
// NewChainCreationTemplate takes a consortium name and a Template to produce a
199200
// Template which outputs an appropriately constructed list of ConfigUpdateEnvelopes.
200-
func NewChainCreationTemplate(creationPolicy string, template Template) Template {
201-
result := cb.NewConfigGroup()
202-
result.Groups[config.OrdererGroupKey] = cb.NewConfigGroup()
203-
result.Groups[config.OrdererGroupKey].Values[CreationPolicyKey] = &cb.ConfigValue{
204-
Value: utils.MarshalOrPanic(&ab.CreationPolicy{
205-
Policy: creationPolicy,
206-
}),
201+
func NewChainCreationTemplate(consortiumName string, orgs []string) Template {
202+
return &channelCreationTemplate{
203+
consortiumName: consortiumName,
204+
orgs: orgs,
205+
}
206+
}
207+
208+
func (cct *channelCreationTemplate) Envelope(channelID string) (*cb.ConfigUpdateEnvelope, error) {
209+
rSet := config.TemplateConsortium(cct.consortiumName)
210+
wSet := config.TemplateConsortium(cct.consortiumName)
211+
212+
rSet.Groups[config.ApplicationGroupKey] = cb.NewConfigGroup()
213+
wSet.Groups[config.ApplicationGroupKey] = cb.NewConfigGroup()
214+
215+
for _, org := range cct.orgs {
216+
rSet.Groups[config.ApplicationGroupKey].Groups[org] = cb.NewConfigGroup()
217+
wSet.Groups[config.ApplicationGroupKey].Groups[org] = cb.NewConfigGroup()
207218
}
208-
return NewCompositeTemplate(NewSimpleTemplate(result), template)
219+
220+
wSet.Groups[config.ApplicationGroupKey].ModPolicy = configmsp.AdminsPolicyKey
221+
wSet.Groups[config.ApplicationGroupKey].Policies[configmsp.AdminsPolicyKey] = policies.ImplicitMetaPolicyWithSubPolicy(configmsp.AdminsPolicyKey, cb.ImplicitMetaPolicy_MAJORITY)
222+
wSet.Groups[config.ApplicationGroupKey].Policies[configmsp.WritersPolicyKey] = policies.ImplicitMetaPolicyWithSubPolicy(configmsp.WritersPolicyKey, cb.ImplicitMetaPolicy_ANY)
223+
wSet.Groups[config.ApplicationGroupKey].Policies[configmsp.ReadersPolicyKey] = policies.ImplicitMetaPolicyWithSubPolicy(configmsp.ReadersPolicyKey, cb.ImplicitMetaPolicy_ANY)
224+
wSet.Groups[config.ApplicationGroupKey].Version = 1
225+
226+
return &cb.ConfigUpdateEnvelope{
227+
ConfigUpdate: utils.MarshalOrPanic(&cb.ConfigUpdate{
228+
ChannelId: channelID,
229+
ReadSet: rSet,
230+
WriteSet: wSet,
231+
}),
232+
}, nil
209233
}
210234

211235
// MakeChainCreationTransaction is a handy utility function for creating new chain transactions using the underlying Template framework
212-
func MakeChainCreationTransaction(creationPolicy string, chainID string, signer msp.SigningIdentity, templates ...Template) (*cb.Envelope, error) {
236+
func MakeChainCreationTransaction(channelID string, consortium string, signer msp.SigningIdentity, orgs ...string) (*cb.Envelope, error) {
213237
sSigner, err := signer.Serialize()
214238
if err != nil {
215239
return nil, fmt.Errorf("Serialization of identity failed, err %s", err)
216240
}
217241

218-
newChainTemplate := NewChainCreationTemplate(creationPolicy, NewCompositeTemplate(templates...))
219-
newConfigUpdateEnv, err := newChainTemplate.Envelope(chainID)
242+
newChainTemplate := NewChainCreationTemplate(consortium, orgs)
243+
newConfigUpdateEnv, err := newChainTemplate.Envelope(channelID)
220244
if err != nil {
221245
return nil, err
222246
}
@@ -229,7 +253,7 @@ func MakeChainCreationTransaction(creationPolicy string, chainID string, signer
229253
return nil, err
230254
}
231255

232-
payloadChannelHeader := utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, msgVersion, chainID, epoch)
256+
payloadChannelHeader := utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, msgVersion, channelID, epoch)
233257
payloadSignatureHeader := utils.MakeSignatureHeader(sSigner, utils.CreateNonceOrPanic())
234258
utils.SetTxID(payloadChannelHeader, payloadSignatureHeader)
235259
payloadHeader := utils.MakePayloadHeader(payloadChannelHeader, payloadSignatureHeader)

common/configtx/template_test.go

+14-21
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,10 @@ import (
2020
"fmt"
2121
"testing"
2222

23-
"github.com/golang/protobuf/proto"
2423
"github.com/hyperledger/fabric/common/config"
2524
cb "github.com/hyperledger/fabric/protos/common"
26-
ab "github.com/hyperledger/fabric/protos/orderer"
2725

26+
"github.com/golang/protobuf/proto"
2827
"github.com/stretchr/testify/assert"
2928
)
3029

@@ -105,38 +104,32 @@ func TestModPolicySettingTemplate(t *testing.T) {
105104
}
106105

107106
func TestNewChainTemplate(t *testing.T) {
108-
simple := NewSimpleTemplate(
109-
simpleGroup(0),
110-
simpleGroup(1),
111-
)
112-
113-
creationPolicy := "Test"
114-
nct := NewChainCreationTemplate(creationPolicy, simple)
107+
consortiumName := "Test"
108+
orgs := []string{"org1", "org2", "org3"}
109+
nct := NewChainCreationTemplate(consortiumName, orgs)
115110

116111
newChainID := "foo"
117112
configEnv, err := nct.Envelope(newChainID)
118113
if err != nil {
119114
t.Fatalf("Error creation a chain creation config")
120115
}
121116

122-
configNext, err := UnmarshalConfigUpdate(configEnv.ConfigUpdate)
117+
configUpdate, err := UnmarshalConfigUpdate(configEnv.ConfigUpdate)
123118
if err != nil {
124119
t.Fatalf("Should not have errored: %s", err)
125120
}
126121

127-
assert.Equal(t, len(configNext.WriteSet.Values), 2, "Not the right number of config values")
122+
consortiumProto := &cb.Consortium{}
123+
err = proto.Unmarshal(configUpdate.WriteSet.Values[config.ConsortiumKey].Value, consortiumProto)
124+
assert.NoError(t, err)
125+
assert.Equal(t, consortiumName, consortiumProto.Name, "Should have set correct consortium name")
128126

129-
for i := 0; i < 2; i++ {
130-
_, ok := configNext.WriteSet.Values[fmt.Sprintf("%d", i)]
131-
assert.True(t, ok, "Expected to find %d but did not", i)
132-
}
127+
assert.Equal(t, configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Version, uint64(1))
133128

134-
configValue, ok := configNext.WriteSet.Groups[config.OrdererGroupKey].Values[CreationPolicyKey]
135-
assert.True(t, ok, "Did not find creation policy")
129+
assert.Len(t, configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups, len(orgs))
136130

137-
creationPolicyMessage := new(ab.CreationPolicy)
138-
if err := proto.Unmarshal(configValue.Value, creationPolicyMessage); err != nil {
139-
t.Fatal("Should not have errored:", err)
131+
for _, org := range orgs {
132+
_, ok := configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org]
133+
assert.True(t, ok, "Expected to find %s but did not", org)
140134
}
141-
assert.Equal(t, creationPolicy, creationPolicyMessage.Policy, "Policy names don't match")
142135
}

0 commit comments

Comments
 (0)