Skip to content

Commit 88e3f8f

Browse files
committed
Change signature of internal evaluator function
Towards a refactoring of the validation/committer, we need to decouple signature/identity validation and policy checking. This change-set enables this by changing the signature of the function that internally evaluates the policy: instead of directly invoking functions to deserialize the supplied identity, checking compliance of the identity with an MSP principal and verifying a signature, it calls functions of a suitable interface. Implementers of the interface are then free to perform any appropriate precomputation. FAB-12774 #done Change-Id: I9df76f801a6b26f303070899ee50f0b699f06e36 Signed-off-by: Alessandro Sorniotti <ale.linux@sopit.net>
1 parent 20aa221 commit 88e3f8f

File tree

4 files changed

+179
-58
lines changed

4 files changed

+179
-58
lines changed

common/cauthdsl/cauthdsl.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,19 @@ import (
2020
var cauthdslLogger = flogging.MustGetLogger("cauthdsl")
2121

2222
// deduplicate removes any duplicated identities while otherwise preserving identity order
23-
func deduplicate(sds []*cb.SignedData, deserializer msp.IdentityDeserializer) []*cb.SignedData {
23+
func deduplicate(sds []IdentityAndSignature) []IdentityAndSignature {
2424
ids := make(map[string]struct{})
25-
result := make([]*cb.SignedData, 0, len(sds))
25+
result := make([]IdentityAndSignature, 0, len(sds))
2626
for i, sd := range sds {
27-
identity, err := deserializer.DeserializeIdentity(sd.Identity)
27+
identity, err := sd.Identity()
2828
if err != nil {
29-
cauthdslLogger.Errorf("Principal deserialization failure (%s) for identity %x", err, sd.Identity)
29+
cauthdslLogger.Errorf("Principal deserialization failure (%s) for identity %d", err, i)
3030
continue
3131
}
3232
key := identity.GetIdentifier().Mspid + identity.GetIdentifier().Id
3333

3434
if _, ok := ids[key]; ok {
35-
cauthdslLogger.Warningf("De-duplicating identity %x at index %d in signature set", sd.Identity, i)
35+
cauthdslLogger.Warningf("De-duplicating identity [%s] at index %d in signature set", key, i)
3636
} else {
3737
result = append(result, sd)
3838
ids[key] = struct{}{}
@@ -43,14 +43,14 @@ func deduplicate(sds []*cb.SignedData, deserializer msp.IdentityDeserializer) []
4343

4444
// compile recursively builds a go evaluatable function corresponding to the policy specified, remember to call deduplicate on identities before
4545
// passing them to this function for evaluation
46-
func compile(policy *cb.SignaturePolicy, identities []*mb.MSPPrincipal, deserializer msp.IdentityDeserializer) (func([]*cb.SignedData, []bool) bool, error) {
46+
func compile(policy *cb.SignaturePolicy, identities []*mb.MSPPrincipal, deserializer msp.IdentityDeserializer) (func([]IdentityAndSignature, []bool) bool, error) {
4747
if policy == nil {
4848
return nil, fmt.Errorf("Empty policy element")
4949
}
5050

5151
switch t := policy.Type.(type) {
5252
case *cb.SignaturePolicy_NOutOf_:
53-
policies := make([]func([]*cb.SignedData, []bool) bool, len(t.NOutOf.Rules))
53+
policies := make([]func([]IdentityAndSignature, []bool) bool, len(t.NOutOf.Rules))
5454
for i, policy := range t.NOutOf.Rules {
5555
compiledPolicy, err := compile(policy, identities, deserializer)
5656
if err != nil {
@@ -59,7 +59,7 @@ func compile(policy *cb.SignaturePolicy, identities []*mb.MSPPrincipal, deserial
5959
policies[i] = compiledPolicy
6060

6161
}
62-
return func(signedData []*cb.SignedData, used []bool) bool {
62+
return func(signedData []IdentityAndSignature, used []bool) bool {
6363
grepKey := time.Now().UnixNano()
6464
cauthdslLogger.Debugf("%p gate %d evaluation starts", signedData, grepKey)
6565
verified := int32(0)
@@ -85,7 +85,7 @@ func compile(policy *cb.SignaturePolicy, identities []*mb.MSPPrincipal, deserial
8585
return nil, fmt.Errorf("identity index out of range, requested %v, but identies length is %d", t.SignedBy, len(identities))
8686
}
8787
signedByID := identities[t.SignedBy]
88-
return func(signedData []*cb.SignedData, used []bool) bool {
88+
return func(signedData []IdentityAndSignature, used []bool) bool {
8989
cauthdslLogger.Debugf("%p signed by %d principal evaluation starts (used %v)", signedData, t.SignedBy, used)
9090
for i, sd := range signedData {
9191
if used[i] {
@@ -96,9 +96,9 @@ func compile(policy *cb.SignaturePolicy, identities []*mb.MSPPrincipal, deserial
9696
// Unlike most places, this is a huge print statement, and worth checking log level before create garbage
9797
cauthdslLogger.Debugf("%p processing identity %d with bytes of %x", signedData, i, sd.Identity)
9898
}
99-
identity, err := deserializer.DeserializeIdentity(sd.Identity)
99+
identity, err := sd.Identity()
100100
if err != nil {
101-
cauthdslLogger.Errorf("Principal deserialization failure (%s) for identity %x", err, sd.Identity)
101+
cauthdslLogger.Errorf("Principal deserialization failure (%s) for identity %d", err, i)
102102
continue
103103
}
104104
err = identity.SatisfiesPrincipal(signedByID)
@@ -107,7 +107,7 @@ func compile(policy *cb.SignaturePolicy, identities []*mb.MSPPrincipal, deserial
107107
continue
108108
}
109109
cauthdslLogger.Debugf("%p principal matched by identity %d", signedData, i)
110-
err = identity.Verify(sd.Data, sd.Signature)
110+
err = sd.Verify()
111111
if err != nil {
112112
cauthdslLogger.Debugf("%p signature for identity %d is invalid: %s", signedData, i, err)
113113
continue

common/cauthdsl/cauthdsl_test.go

Lines changed: 107 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,16 @@ func (id *mockIdentity) Serialize() ([]byte, error) {
7171
return id.idBytes, nil
7272
}
7373

74-
func toSignedData(data [][]byte, identities [][]byte, signatures [][]byte) ([]*cb.SignedData, []bool) {
75-
signedData := make([]*cb.SignedData, len(data))
74+
func toSignedData(data [][]byte, identities [][]byte, signatures [][]byte, deserializer msp.IdentityDeserializer) ([]IdentityAndSignature, []bool) {
75+
signedData := make([]IdentityAndSignature, len(data))
7676
for i := range signedData {
77-
signedData[i] = &cb.SignedData{
78-
Data: data[i],
79-
Identity: identities[i],
80-
Signature: signatures[i],
77+
signedData[i] = &deserializeAndVerify{
78+
signedData: &cb.SignedData{
79+
Data: data[i],
80+
Identity: identities[i],
81+
Signature: signatures[i],
82+
},
83+
deserializer: deserializer,
8184
}
8285
}
8386
return signedData, make([]bool, len(signedData))
@@ -111,13 +114,13 @@ func TestSimpleSignature(t *testing.T) {
111114
t.Fatalf("Could not create a new SignaturePolicyEvaluator using the given policy, crypto-helper: %s", err)
112115
}
113116

114-
if !spe(toSignedData([][]byte{nil}, [][]byte{signers[0]}, [][]byte{validSignature})) {
117+
if !spe(toSignedData([][]byte{nil}, [][]byte{signers[0]}, [][]byte{validSignature}, &mockDeserializer{})) {
115118
t.Errorf("Expected authentication to succeed with valid signatures")
116119
}
117-
if spe(toSignedData([][]byte{nil}, [][]byte{signers[0]}, [][]byte{invalidSignature})) {
120+
if spe(toSignedData([][]byte{nil}, [][]byte{signers[0]}, [][]byte{invalidSignature}, &mockDeserializer{})) {
118121
t.Errorf("Expected authentication to fail given the invalid signature")
119122
}
120-
if spe(toSignedData([][]byte{nil}, [][]byte{signers[1]}, [][]byte{validSignature})) {
123+
if spe(toSignedData([][]byte{nil}, [][]byte{signers[1]}, [][]byte{validSignature}, &mockDeserializer{})) {
121124
t.Errorf("Expected authentication to fail because signers[1] is not authorized in the policy, despite his valid signature")
122125
}
123126
}
@@ -130,13 +133,13 @@ func TestMultipleSignature(t *testing.T) {
130133
t.Fatalf("Could not create a new SignaturePolicyEvaluator using the given policy, crypto-helper: %s", err)
131134
}
132135

133-
if !spe(toSignedData(msgs, signers, [][]byte{validSignature, validSignature})) {
136+
if !spe(toSignedData(msgs, signers, [][]byte{validSignature, validSignature}, &mockDeserializer{})) {
134137
t.Errorf("Expected authentication to succeed with valid signatures")
135138
}
136-
if spe(toSignedData(msgs, signers, [][]byte{validSignature, invalidSignature})) {
139+
if spe(toSignedData(msgs, signers, [][]byte{validSignature, invalidSignature}, &mockDeserializer{})) {
137140
t.Errorf("Expected authentication to fail given one of two invalid signatures")
138141
}
139-
if spe(toSignedData(msgs, [][]byte{signers[0], signers[0]}, [][]byte{validSignature, validSignature})) {
142+
if spe(toSignedData(msgs, [][]byte{signers[0], signers[0]}, [][]byte{validSignature, validSignature}, &mockDeserializer{})) {
140143
t.Errorf("Expected authentication to fail because although there were two valid signatures, one was duplicated")
141144
}
142145
}
@@ -149,19 +152,19 @@ func TestComplexNestedSignature(t *testing.T) {
149152
t.Fatalf("Could not create a new SignaturePolicyEvaluator using the given policy, crypto-helper: %s", err)
150153
}
151154

152-
if !spe(toSignedData(moreMsgs, append(signers, [][]byte{[]byte("signer0")}...), [][]byte{validSignature, validSignature, validSignature})) {
155+
if !spe(toSignedData(moreMsgs, append(signers, [][]byte{[]byte("signer0")}...), [][]byte{validSignature, validSignature, validSignature}, &mockDeserializer{})) {
153156
t.Errorf("Expected authentication to succeed with valid signatures")
154157
}
155-
if !spe(toSignedData(moreMsgs, [][]byte{[]byte("signer0"), []byte("signer0"), []byte("signer0")}, [][]byte{validSignature, validSignature, validSignature})) {
158+
if !spe(toSignedData(moreMsgs, [][]byte{[]byte("signer0"), []byte("signer0"), []byte("signer0")}, [][]byte{validSignature, validSignature, validSignature}, &mockDeserializer{})) {
156159
t.Errorf("Expected authentication to succeed with valid signatures")
157160
}
158-
if spe(toSignedData(msgs, signers, [][]byte{validSignature, validSignature})) {
161+
if spe(toSignedData(msgs, signers, [][]byte{validSignature, validSignature}, &mockDeserializer{})) {
159162
t.Errorf("Expected authentication to fail with too few signatures")
160163
}
161-
if spe(toSignedData(moreMsgs, append(signers, [][]byte{[]byte("signer0")}...), [][]byte{validSignature, invalidSignature, validSignature})) {
164+
if spe(toSignedData(moreMsgs, append(signers, [][]byte{[]byte("signer0")}...), [][]byte{validSignature, invalidSignature, validSignature}, &mockDeserializer{})) {
162165
t.Errorf("Expected authentication failure as the signature of signer[1] was invalid")
163166
}
164-
if spe(toSignedData(moreMsgs, append(signers, [][]byte{[]byte("signer1")}...), [][]byte{validSignature, validSignature, validSignature})) {
167+
if spe(toSignedData(moreMsgs, append(signers, [][]byte{[]byte("signer1")}...), [][]byte{validSignature, validSignature, validSignature}, &mockDeserializer{})) {
165168
t.Errorf("Expected authentication failure as there was a signature from signer[0] missing")
166169
}
167170
}
@@ -184,46 +187,109 @@ func TestNilSignaturePolicyEnvelope(t *testing.T) {
184187
}
185188

186189
func TestDeduplicate(t *testing.T) {
187-
ids := []*cb.SignedData{
188-
{
189-
Identity: []byte("id1"),
190-
},
191-
{
192-
Identity: []byte("id2"),
193-
},
194-
{
195-
Identity: []byte("id3"),
196-
},
197-
}
198-
199190
t.Run("Empty", func(t *testing.T) {
200-
result := deduplicate([]*cb.SignedData{}, &mockDeserializer{})
201-
assert.Equal(t, []*cb.SignedData{}, result, "Should have no identities")
191+
result := deduplicate([]IdentityAndSignature{})
192+
assert.Equal(t, []IdentityAndSignature{}, result, "Should have no identities")
202193
})
203194

204195
t.Run("NoDuplication", func(t *testing.T) {
205-
result := deduplicate(ids, &mockDeserializer{})
196+
md := &mockDeserializer{}
197+
ids := []IdentityAndSignature{
198+
&deserializeAndVerify{
199+
signedData: &cb.SignedData{
200+
Identity: []byte("id1"),
201+
},
202+
deserializer: md,
203+
},
204+
&deserializeAndVerify{
205+
signedData: &cb.SignedData{
206+
Identity: []byte("id2"),
207+
},
208+
deserializer: md,
209+
},
210+
&deserializeAndVerify{
211+
signedData: &cb.SignedData{
212+
Identity: []byte("id3"),
213+
},
214+
deserializer: md,
215+
},
216+
}
217+
result := deduplicate(ids)
206218
assert.Equal(t, ids, result, "No identities should have been removed")
207219
})
208220

209221
t.Run("AllDuplication", func(t *testing.T) {
210-
result := deduplicate([]*cb.SignedData{ids[0], ids[0], ids[0]}, &mockDeserializer{})
211-
assert.Equal(t, []*cb.SignedData{ids[0]}, result, "All but the first identity should have been removed")
222+
md := &mockDeserializer{}
223+
ids := []IdentityAndSignature{
224+
&deserializeAndVerify{
225+
signedData: &cb.SignedData{
226+
Identity: []byte("id1"),
227+
},
228+
deserializer: md,
229+
},
230+
}
231+
result := deduplicate([]IdentityAndSignature{ids[0], ids[0], ids[0]})
232+
assert.Equal(t, []IdentityAndSignature{ids[0]}, result, "All but the first identity should have been removed")
212233
})
213234

214235
t.Run("DuplicationPreservesOrder", func(t *testing.T) {
215-
result := deduplicate([]*cb.SignedData{ids[1], ids[0], ids[0]}, &mockDeserializer{})
216-
assert.Equal(t, []*cb.SignedData{ids[1], ids[0]}, result, "The third identity should have been dropped")
236+
md := &mockDeserializer{}
237+
ids := []IdentityAndSignature{
238+
&deserializeAndVerify{
239+
signedData: &cb.SignedData{
240+
Identity: []byte("id1"),
241+
},
242+
deserializer: md,
243+
},
244+
&deserializeAndVerify{
245+
signedData: &cb.SignedData{
246+
Identity: []byte("id2"),
247+
},
248+
deserializer: md,
249+
},
250+
}
251+
result := deduplicate([]IdentityAndSignature{ids[1], ids[0], ids[0]})
252+
assert.Equal(t, result, []IdentityAndSignature{ids[1], ids[0]}, "The third identity should have been dropped")
217253
})
218254

219255
t.Run("ComplexDuplication", func(t *testing.T) {
220-
result := deduplicate([]*cb.SignedData{ids[1], ids[0], ids[0], ids[1], ids[2], ids[0], ids[2], ids[1]}, &mockDeserializer{})
221-
assert.Equal(t, []*cb.SignedData{ids[1], ids[0], ids[2]}, result, "Expected only three non-duplicate identities")
256+
md := &mockDeserializer{}
257+
ids := []IdentityAndSignature{
258+
&deserializeAndVerify{
259+
signedData: &cb.SignedData{
260+
Identity: []byte("id1"),
261+
},
262+
deserializer: md,
263+
},
264+
&deserializeAndVerify{
265+
signedData: &cb.SignedData{
266+
Identity: []byte("id2"),
267+
},
268+
deserializer: md,
269+
},
270+
&deserializeAndVerify{
271+
signedData: &cb.SignedData{
272+
Identity: []byte("id3"),
273+
},
274+
deserializer: md,
275+
},
276+
}
277+
result := deduplicate([]IdentityAndSignature{ids[1], ids[0], ids[0], ids[1], ids[2], ids[0], ids[2], ids[1]})
278+
assert.Equal(t, []IdentityAndSignature{ids[1], ids[0], ids[2]}, result, "Expected only three non-duplicate identities")
222279
})
223280

224281
t.Run("BadIdentity", func(t *testing.T) {
225-
result := deduplicate([]*cb.SignedData{ids[1]}, &mockDeserializer{fail: errors.New("error")})
226-
assert.Equal(t, []*cb.SignedData{}, result, "No valid identities")
282+
md := &mockDeserializer{fail: errors.New("error")}
283+
ids := []IdentityAndSignature{
284+
&deserializeAndVerify{
285+
signedData: &cb.SignedData{
286+
Identity: []byte("id1"),
287+
},
288+
deserializer: md,
289+
},
290+
}
291+
result := deduplicate([]IdentityAndSignature{ids[0]})
292+
assert.Equal(t, []IdentityAndSignature{}, result, "No valid identities")
227293
})
228294
}
229295

@@ -292,7 +358,7 @@ func TestDeserializeIdentityError(t *testing.T) {
292358
cauthdslLogger = logger
293359

294360
// Call
295-
signedData, used := toSignedData([][]byte{nil}, [][]byte{nil}, [][]byte{nil})
361+
signedData, used := toSignedData([][]byte{nil}, [][]byte{nil}, [][]byte{nil}, &mockDeserializer{fail: errors.New("myError")})
296362
ret := spe(signedData, used)
297363

298364
// Check result (ret and log)

common/cauthdsl/policy.go

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,51 @@ import (
1414
"github.com/hyperledger/fabric/common/policies"
1515
"github.com/hyperledger/fabric/msp"
1616
cb "github.com/hyperledger/fabric/protos/common"
17+
mspp "github.com/hyperledger/fabric/protos/msp"
1718
)
1819

20+
type Identity interface {
21+
// SatisfiesPrincipal checks whether this instance matches
22+
// the description supplied in MSPPrincipal. The check may
23+
// involve a byte-by-byte comparison (if the principal is
24+
// a serialized identity) or may require MSP validation
25+
SatisfiesPrincipal(principal *mspp.MSPPrincipal) error
26+
27+
// GetIdentifier returns the identifier of that identity
28+
GetIdentifier() *msp.IdentityIdentifier
29+
}
30+
31+
type IdentityAndSignature interface {
32+
// Identity returns the identity associated to this instance
33+
Identity() (Identity, error)
34+
35+
// Verify returns the validity status of this identity's signature over the message
36+
Verify() error
37+
}
38+
39+
type deserializeAndVerify struct {
40+
signedData *cb.SignedData
41+
deserializer msp.IdentityDeserializer
42+
deserializedIdentity msp.Identity
43+
}
44+
45+
func (d *deserializeAndVerify) Identity() (Identity, error) {
46+
deserializedIdentity, err := d.deserializer.DeserializeIdentity(d.signedData.Identity)
47+
if err != nil {
48+
return nil, err
49+
}
50+
51+
d.deserializedIdentity = deserializedIdentity
52+
return deserializedIdentity, nil
53+
}
54+
55+
func (d *deserializeAndVerify) Verify() error {
56+
if d.deserializedIdentity == nil {
57+
cauthdslLogger.Panicf("programming error, Identity must be called prior to Verify")
58+
}
59+
return d.deserializedIdentity.Verify(d.signedData.Data, d.signedData.Signature)
60+
}
61+
1962
type provider struct {
2063
deserializer msp.IdentityDeserializer
2164
}
@@ -51,7 +94,7 @@ func (pr *provider) NewPolicy(data []byte) (policies.Policy, proto.Message, erro
5194
}
5295

5396
type policy struct {
54-
evaluator func([]*cb.SignedData, []bool) bool
97+
evaluator func([]IdentityAndSignature, []bool) bool
5598
deserializer msp.IdentityDeserializer
5699
}
57100

@@ -60,8 +103,15 @@ func (p *policy) Evaluate(signatureSet []*cb.SignedData) error {
60103
if p == nil {
61104
return fmt.Errorf("No such policy")
62105
}
106+
idAndS := make([]IdentityAndSignature, len(signatureSet))
107+
for i, sd := range signatureSet {
108+
idAndS[i] = &deserializeAndVerify{
109+
signedData: sd,
110+
deserializer: p.deserializer,
111+
}
112+
}
63113

64-
ok := p.evaluator(deduplicate(signatureSet, p.deserializer), make([]bool, len(signatureSet)))
114+
ok := p.evaluator(deduplicate(idAndS), make([]bool, len(signatureSet)))
65115
if !ok {
66116
return errors.New("signature set did not satisfy policy")
67117
}

0 commit comments

Comments
 (0)