Skip to content

Commit 0fbdb7d

Browse files
author
Jason Yellick
committed
[FAB-1693] Do not validate modPolicy without mod
https://jira.hyperledger.org/browse/FAB-1693 The previous configuratoin transaction manager verified all signature policies against signature sets every time regardless of whether they had been modified. This caused a problem that if the backing policy changed, or the certificate expired, etc., an existing policy item might cause a config transaction to be rejected. This changeset fixes this oversight. Change-Id: Iec2f42d51a9a213650b80a2f735ff2fc8d8d16ac Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
1 parent 6da52bc commit 0fbdb7d

File tree

2 files changed

+70
-28
lines changed

2 files changed

+70
-28
lines changed

common/configtx/manager.go

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ limitations under the License.
1717
package configtx
1818

1919
import (
20-
"bytes"
2120
"fmt"
21+
"reflect"
2222

2323
"github.com/hyperledger/fabric/common/policies"
2424
cb "github.com/hyperledger/fabric/protos/common"
@@ -205,45 +205,45 @@ func (cm *configurationManager) processConfig(configtx *cb.ConfigurationEnvelope
205205
return nil, fmt.Errorf("Error unmarshaling ConfigurationItem: %s", err)
206206
}
207207

208-
// Get the modification policy for this config item if one was previously specified
209-
// or the default if this is a new config item
210-
var policy policies.Policy
211-
oldItem, ok := cm.configuration[config.Type][config.Key]
212-
if ok {
213-
policy, _ = cm.pm.GetPolicy(oldItem.ModificationPolicy)
214-
} else {
215-
policy = defaultModificationPolicy
216-
}
217-
218-
// Get signatures
219-
signedData, err := entry.AsSignedData()
220-
if err != nil {
221-
return nil, err
222-
}
223-
224-
// Ensure the policy is satisfied
225-
if err = policy.Evaluate(signedData); err != nil {
226-
return nil, err
227-
}
228-
229208
// Ensure the config sequence numbers are correct to prevent replay attacks
230209
isModified := false
231210

232211
if val, ok := cm.configuration[config.Type][config.Key]; ok {
233-
// Config was modified if the LastModified or the Data contents changed
234-
isModified = (val.LastModified != config.LastModified) || !bytes.Equal(config.Value, val.Value)
212+
// Config was modified if any of the contents changed
213+
isModified = !reflect.DeepEqual(val, config)
235214
} else {
236215
if config.LastModified != seq {
237216
return nil, fmt.Errorf("Key %v for type %v was new, but had an older Sequence %d set", config.Key, config.Type, config.LastModified)
238217
}
239218
isModified = true
240219
}
241220

242-
// If a config item was modified, its LastModified must be set correctly
221+
// If a config item was modified, its LastModified must be set correctly, and it must satisfy the modification policy
243222
if isModified {
244223
if config.LastModified != seq {
245224
return nil, fmt.Errorf("Key %v for type %v was modified, but its LastModified %d does not equal current configtx Sequence %d", config.Key, config.Type, config.LastModified, seq)
246225
}
226+
227+
// Get the modification policy for this config item if one was previously specified
228+
// or the default if this is a new config item
229+
var policy policies.Policy
230+
oldItem, ok := cm.configuration[config.Type][config.Key]
231+
if ok {
232+
policy, _ = cm.pm.GetPolicy(oldItem.ModificationPolicy)
233+
} else {
234+
policy = defaultModificationPolicy
235+
}
236+
237+
// Get signatures
238+
signedData, err := entry.AsSignedData()
239+
if err != nil {
240+
return nil, err
241+
}
242+
243+
// Ensure the policy is satisfied
244+
if err = policy.Evaluate(signedData); err != nil {
245+
return nil, err
246+
}
247247
}
248248

249249
// Ensure the type handler agrees the config is well formed

common/configtx/manager_test.go

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ import (
2323
"github.com/hyperledger/fabric/common/policies"
2424
cb "github.com/hyperledger/fabric/protos/common"
2525

26-
"github.com/golang/protobuf/proto"
2726
"errors"
27+
"github.com/golang/protobuf/proto"
2828
)
2929

3030
var defaultChain = "DefaultChainID"
@@ -40,12 +40,19 @@ func defaultHandlers() map[cb.ConfigurationItem_ConfigurationType]Handler {
4040
// mockPolicy always returns the error set as policyResult
4141
type mockPolicy struct {
4242
policyResult error
43+
// validReplies is the number of times to successfully validate before returning policyResult
44+
// it is decremented at each invocation
45+
validReplies int
4346
}
4447

4548
func (mp *mockPolicy) Evaluate(signedData []*cb.SignedData) error {
4649
if mp == nil {
4750
return errors.New("Invoked nil policy")
4851
}
52+
if mp.validReplies > 0 {
53+
return nil
54+
}
55+
mp.validReplies--
4956
return mp.policyResult
5057
}
5158

@@ -328,7 +335,7 @@ func TestSilentConfigModification(t *testing.T) {
328335
func TestInvalidInitialConfigByPolicy(t *testing.T) {
329336
_, err := NewConfigurationManager(&cb.ConfigurationEnvelope{
330337
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
331-
}, &mockPolicyManager{&mockPolicy{fmt.Errorf("err")}}, defaultHandlers())
338+
}, &mockPolicyManager{&mockPolicy{policyResult: fmt.Errorf("err")}}, defaultHandlers())
332339
// mockPolicyManager will return non-validating defualt policy
333340

334341
if err == nil {
@@ -348,7 +355,7 @@ func TestConfigChangeViolatesPolicy(t *testing.T) {
348355
t.Fatalf("Error constructing configuration manager: %s", err)
349356
}
350357
// Set the mock policy to error
351-
mpm.policy = &mockPolicy{fmt.Errorf("err")}
358+
mpm.policy = &mockPolicy{policyResult: fmt.Errorf("err")}
352359

353360
newConfig := &cb.ConfigurationEnvelope{
354361
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 1, []byte("foo"), defaultChain)},
@@ -365,6 +372,41 @@ func TestConfigChangeViolatesPolicy(t *testing.T) {
365372
}
366373
}
367374

375+
// TestUnchangedConfigViolatesPolicy checks to make sure that existing config items are not revalidated against their modification policies
376+
// as the policy may have changed, certs revoked, etc. since the config was adopted.
377+
func TestUnchangedConfigViolatesPolicy(t *testing.T) {
378+
mpm := &mockPolicyManager{}
379+
cm, err := NewConfigurationManager(&cb.ConfigurationEnvelope{
380+
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
381+
}, mpm, defaultHandlers())
382+
383+
if err != nil {
384+
t.Fatalf("Error constructing configuration manager: %s", err)
385+
}
386+
// Set the mock policy to error
387+
mpm.policy = &mockPolicy{
388+
policyResult: fmt.Errorf("err"),
389+
validReplies: 1,
390+
}
391+
392+
newConfig := &cb.ConfigurationEnvelope{
393+
Items: []*cb.SignedConfigurationItem{
394+
makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain),
395+
makeSignedConfigurationItem("bar", "bar", 1, []byte("foo"), defaultChain),
396+
},
397+
}
398+
399+
err = cm.Validate(newConfig)
400+
if err != nil {
401+
t.Errorf("Should not have errored validating config, but got %s", err)
402+
}
403+
404+
err = cm.Apply(newConfig)
405+
if err != nil {
406+
t.Errorf("Should not have errored applying config, but got %s", err)
407+
}
408+
}
409+
368410
type failHandler struct{}
369411

370412
func (fh failHandler) BeginConfig() {}

0 commit comments

Comments
 (0)