Skip to content

Commit bad7bdc

Browse files
author
Jason Yellick
committed
[FAB-1420] Convert signature policy to provider
https://jira.hyperledger.org/browse/FAB-1420 The cuathdsl signature policy type used to be the only policy type available. In order to allow new types of policy, a provider framework is needed. This changeset introduces the provider framework and converts the existing cauthdsl based signature policy work to be one of these providers. Finally, in response to some changeset feedback, it also introduces the notion of a SignedData struct which can be common to all of the crypto implementations (and signficiantly simplifies the interface definitions). Change-Id: Ib67ff9f6de0433f73c96e5a4b229f1587a0f0363 Signed-off-by: Jason Yellick <[email protected]>
1 parent 46f7af0 commit bad7bdc

12 files changed

+409
-157
lines changed

common/cauthdsl/cauthdsl.go

+9-36
Original file line numberDiff line numberDiff line change
@@ -25,35 +25,14 @@ import (
2525

2626
// CryptoHelper is used to provide a plugin point for different signature validation types
2727
type CryptoHelper interface {
28-
VerifySignature(msg []byte, id []byte, signature []byte) bool
29-
}
30-
31-
// SignaturePolicyEvaluator is useful for a chain Reader to stream blocks as they are created
32-
type SignaturePolicyEvaluator struct {
33-
compiledAuthenticator func([]byte, [][]byte, [][]byte) bool
34-
}
35-
36-
// NewSignaturePolicyEvaluator evaluates a protbuf SignaturePolicy to produce a 'compiled' version which can be invoked in code
37-
func NewSignaturePolicyEvaluator(policy *cb.SignaturePolicyEnvelope, ch CryptoHelper) (*SignaturePolicyEvaluator, error) {
38-
if policy.Version != 0 {
39-
return nil, fmt.Errorf("This evaluator only understands messages of version 0, but version was %d", policy.Version)
40-
}
41-
42-
compiled, err := compile(policy.Policy, policy.Identities, ch)
43-
if err != nil {
44-
return nil, err
45-
}
46-
47-
return &SignaturePolicyEvaluator{
48-
compiledAuthenticator: compiled,
49-
}, nil
28+
VerifySignature(signedData *cb.SignedData) error
5029
}
5130

5231
// compile recursively builds a go evaluatable function corresponding to the policy specified
53-
func compile(policy *cb.SignaturePolicy, identities [][]byte, ch CryptoHelper) (func([]byte, [][]byte, [][]byte) bool, error) {
32+
func compile(policy *cb.SignaturePolicy, identities [][]byte, ch CryptoHelper) (func([]*cb.SignedData) bool, error) {
5433
switch t := policy.Type.(type) {
5534
case *cb.SignaturePolicy_From:
56-
policies := make([]func([]byte, [][]byte, [][]byte) bool, len(t.From.Policies))
35+
policies := make([]func([]*cb.SignedData) bool, len(t.From.Policies))
5736
for i, policy := range t.From.Policies {
5837
compiledPolicy, err := compile(policy, identities, ch)
5938
if err != nil {
@@ -62,10 +41,10 @@ func compile(policy *cb.SignaturePolicy, identities [][]byte, ch CryptoHelper) (
6241
policies[i] = compiledPolicy
6342

6443
}
65-
return func(msg []byte, ids [][]byte, signatures [][]byte) bool {
44+
return func(signedData []*cb.SignedData) bool {
6645
verified := int32(0)
6746
for _, policy := range policies {
68-
if policy(msg, ids, signatures) {
47+
if policy(signedData) {
6948
verified++
7049
}
7150
}
@@ -76,21 +55,15 @@ func compile(policy *cb.SignaturePolicy, identities [][]byte, ch CryptoHelper) (
7655
return nil, fmt.Errorf("Identity index out of range, requested %d, but identies length is %d", t.SignedBy, len(identities))
7756
}
7857
signedByID := identities[t.SignedBy]
79-
return func(msg []byte, ids [][]byte, signatures [][]byte) bool {
80-
for i, id := range ids {
81-
if bytes.Equal(id, signedByID) {
82-
return ch.VerifySignature(msg, id, signatures[i])
58+
return func(signedData []*cb.SignedData) bool {
59+
for _, sd := range signedData {
60+
if bytes.Equal(sd.Identity, signedByID) {
61+
return ch.VerifySignature(sd) == nil
8362
}
8463
}
8564
return false
8665
}, nil
8766
default:
8867
return nil, fmt.Errorf("Unknown type: %T:%v", t, t)
8968
}
90-
91-
}
92-
93-
// Authenticate returns nil if the authentication policy is satisfied, or an error indicating why the authentication failed
94-
func (ape *SignaturePolicyEvaluator) Authenticate(msg []byte, ids [][]byte, signatures [][]byte) bool {
95-
return ape.compiledAuthenticator(msg, ids, signatures)
9669
}

common/cauthdsl/cauthdsl_test.go

+41-24
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package cauthdsl
1818

1919
import (
2020
"bytes"
21+
"fmt"
2122
"testing"
2223

2324
"github.com/golang/protobuf/proto"
@@ -27,71 +28,87 @@ import (
2728
var invalidSignature = []byte("badsigned")
2829
var validSignature = []byte("signed")
2930
var signers = [][]byte{[]byte("signer0"), []byte("signer1")}
31+
var msgs = [][]byte{nil, nil}
3032

3133
type mockCryptoHelper struct {
3234
}
3335

34-
func (mch *mockCryptoHelper) VerifySignature(msg []byte, id []byte, signature []byte) bool {
35-
return bytes.Equal(signature, validSignature)
36+
func (mch *mockCryptoHelper) VerifySignature(sd *cb.SignedData) error {
37+
if !bytes.Equal(sd.Signature, validSignature) {
38+
return fmt.Errorf("Bad signature")
39+
}
40+
return nil
41+
}
42+
43+
func toSignedData(data [][]byte, identities [][]byte, signatures [][]byte) []*cb.SignedData {
44+
signedData := make([]*cb.SignedData, len(data))
45+
for i := range signedData {
46+
signedData[i] = &cb.SignedData{
47+
Data: data[i],
48+
Identity: identities[i],
49+
Signature: signatures[i],
50+
}
51+
}
52+
return signedData
3653
}
3754

3855
func TestSimpleSignature(t *testing.T) {
3956
mch := &mockCryptoHelper{}
4057
policy := Envelope(SignedBy(0), signers)
4158

42-
spe, err := NewSignaturePolicyEvaluator(policy, mch)
59+
spe, err := compile(policy.Policy, policy.Identities, mch)
4360
if err != nil {
4461
t.Fatalf("Could not create a new SignaturePolicyEvaluator using the given policy, crypto-helper: %s", err)
4562
}
4663

47-
if !spe.Authenticate(nil, [][]byte{signers[0]}, [][]byte{validSignature}) {
48-
t.Error("Expected authentication to succeed with valid signatures")
64+
if !spe([]*cb.SignedData{&cb.SignedData{Identity: signers[0], Signature: validSignature}}) {
65+
t.Errorf("Expected authentication to succeed with valid signatures")
4966
}
50-
if spe.Authenticate(nil, [][]byte{signers[0]}, [][]byte{invalidSignature}) {
51-
t.Error("Expected authentication to fail given the invalid signature")
67+
if spe([]*cb.SignedData{&cb.SignedData{Identity: signers[0], Signature: invalidSignature}}) {
68+
t.Errorf("Expected authentication to fail given the invalid signature")
5269
}
53-
if spe.Authenticate(nil, [][]byte{signers[1]}, [][]byte{validSignature}) {
54-
t.Error("Expected authentication to fail because signers[1] is not authorized in the policy, despite his valid signature")
70+
if spe([]*cb.SignedData{&cb.SignedData{Identity: signers[1], Signature: validSignature}}) {
71+
t.Errorf("Expected authentication to fail because signers[1] is not authorized in the policy, despite his valid signature")
5572
}
5673
}
5774

5875
func TestMultipleSignature(t *testing.T) {
5976
mch := &mockCryptoHelper{}
6077
policy := Envelope(And(SignedBy(0), SignedBy(1)), signers)
6178

62-
spe, err := NewSignaturePolicyEvaluator(policy, mch)
79+
spe, err := compile(policy.Policy, policy.Identities, mch)
6380
if err != nil {
6481
t.Fatalf("Could not create a new SignaturePolicyEvaluator using the given policy, crypto-helper: %s", err)
6582
}
6683

67-
if !spe.Authenticate(nil, signers, [][]byte{validSignature, validSignature}) {
68-
t.Error("Expected authentication to succeed with valid signatures")
84+
if !spe(toSignedData(msgs, signers, [][]byte{validSignature, validSignature})) {
85+
t.Errorf("Expected authentication to succeed with valid signatures")
6986
}
70-
if spe.Authenticate(nil, signers, [][]byte{validSignature, invalidSignature}) {
71-
t.Error("Expected authentication to fail given one of two invalid signatures")
87+
if spe(toSignedData(msgs, signers, [][]byte{validSignature, invalidSignature})) {
88+
t.Errorf("Expected authentication to fail given one of two invalid signatures")
7289
}
73-
if spe.Authenticate(nil, [][]byte{signers[0], signers[0]}, [][]byte{validSignature, validSignature}) {
74-
t.Error("Expected authentication to fail because although there were two valid signatures, one was duplicated")
90+
if spe(toSignedData(msgs, [][]byte{signers[0], signers[0]}, [][]byte{validSignature, validSignature})) {
91+
t.Errorf("Expected authentication to fail because although there were two valid signatures, one was duplicated")
7592
}
7693
}
7794

7895
func TestComplexNestedSignature(t *testing.T) {
7996
mch := &mockCryptoHelper{}
8097
policy := Envelope(And(Or(And(SignedBy(0), SignedBy(1)), And(SignedBy(0), SignedBy(0))), SignedBy(0)), signers)
8198

82-
spe, err := NewSignaturePolicyEvaluator(policy, mch)
99+
spe, err := compile(policy.Policy, policy.Identities, mch)
83100
if err != nil {
84101
t.Fatalf("Could not create a new SignaturePolicyEvaluator using the given policy, crypto-helper: %s", err)
85102
}
86103

87-
if !spe.Authenticate(nil, signers, [][]byte{validSignature, validSignature}) {
88-
t.Error("Expected authentication to succeed with valid signatures")
104+
if !spe(toSignedData(msgs, signers, [][]byte{validSignature, validSignature})) {
105+
t.Errorf("Expected authentication to succeed with valid signatures")
89106
}
90-
if spe.Authenticate(nil, signers, [][]byte{invalidSignature, validSignature}) {
91-
t.Error("Expected authentication failure as only the signature of signer[1] was valid")
107+
if spe(toSignedData(msgs, signers, [][]byte{invalidSignature, validSignature})) {
108+
t.Errorf("Expected authentication failure as only the signature of signer[1] was valid")
92109
}
93-
if !spe.Authenticate(nil, [][]byte{signers[0], signers[0]}, [][]byte{validSignature, validSignature}) {
94-
t.Error("Expected authentication to succeed because the rule allows duplicated signatures for signer[0]")
110+
if !spe(toSignedData(msgs, [][]byte{signers[0], signers[0]}, [][]byte{validSignature, validSignature})) {
111+
t.Errorf("Expected authentication to succeed because the rule allows duplicated signatures for signer[0]")
95112
}
96113
}
97114

@@ -102,7 +119,7 @@ func TestNegatively(t *testing.T) {
102119
b, _ := proto.Marshal(rpolicy)
103120
policy := &cb.SignaturePolicyEnvelope{}
104121
_ = proto.Unmarshal(b, policy)
105-
_, err := NewSignaturePolicyEvaluator(policy, mch)
122+
_, err := compile(policy.Policy, policy.Identities, mch)
106123
if err == nil {
107124
t.Fatal("Should have errored compiling because the Type field was nil")
108125
}

common/cauthdsl/policy.go

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
Copyright IBM Corp. 2016 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package cauthdsl
18+
19+
import (
20+
"errors"
21+
"fmt"
22+
23+
"github.com/hyperledger/fabric/common/policies"
24+
cb "github.com/hyperledger/fabric/protos/common"
25+
26+
"github.com/golang/protobuf/proto"
27+
)
28+
29+
type provider struct {
30+
helper CryptoHelper
31+
}
32+
33+
// NewProviderImpl provides a policy generator for cauthdsl type policies
34+
func NewPolicyProvider(helper CryptoHelper) policies.Provider {
35+
return &provider{
36+
helper: helper,
37+
}
38+
}
39+
40+
// NewPolicy creates a new policy based on the policy bytes
41+
func (pr *provider) NewPolicy(data []byte) (policies.Policy, error) {
42+
sigPolicy := &cb.SignaturePolicyEnvelope{}
43+
if err := proto.Unmarshal(data, sigPolicy); err != nil {
44+
return nil, fmt.Errorf("Error unmarshaling to SignaturePolicy: %s", err)
45+
}
46+
47+
if sigPolicy.Version != 0 {
48+
return nil, fmt.Errorf("This evaluator only understands messages of version 0, but version was %d", sigPolicy.Version)
49+
}
50+
51+
compiled, err := compile(sigPolicy.Policy, sigPolicy.Identities, pr.helper)
52+
if err != nil {
53+
return nil, err
54+
}
55+
56+
return &policy{
57+
evaluator: compiled,
58+
}, nil
59+
60+
}
61+
62+
type policy struct {
63+
evaluator func([]*cb.SignedData) bool
64+
}
65+
66+
// Evaluate takes a set of SignedData and evaluates whether this set of signatures satisfies the policy
67+
func (p *policy) Evaluate(signatureSet []*cb.SignedData) error {
68+
if p == nil {
69+
return fmt.Errorf("No such policy")
70+
}
71+
72+
ok := p.evaluator(signatureSet)
73+
if !ok {
74+
return errors.New("Failed to authenticate policy")
75+
}
76+
return nil
77+
}

common/policies/policy_test.go common/cauthdsl/policy_test.go

+17-18
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,18 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package policies
17+
package cauthdsl
1818

1919
import (
2020
"fmt"
2121
"testing"
2222

23-
"github.com/hyperledger/fabric/common/cauthdsl"
23+
"github.com/hyperledger/fabric/common/policies"
2424
cb "github.com/hyperledger/fabric/protos/common"
2525

2626
"github.com/golang/protobuf/proto"
2727
)
2828

29-
type mockCryptoHelper struct{}
30-
31-
func (mch *mockCryptoHelper) VerifySignature(msg []byte, identity []byte, signature []byte) bool {
32-
return true
33-
}
34-
3529
var acceptAllPolicy []byte
3630
var rejectAllPolicy []byte
3731

@@ -52,9 +46,9 @@ func marshalOrPanic(msg proto.Message) []byte {
5246
func makePolicySource(policyResult bool) []byte {
5347
var policyData *cb.SignaturePolicyEnvelope
5448
if policyResult {
55-
policyData = cauthdsl.AcceptAllPolicy
49+
policyData = AcceptAllPolicy
5650
} else {
57-
policyData = cauthdsl.RejectAllPolicy
51+
policyData = RejectAllPolicy
5852
}
5953
marshaledPolicy := marshalOrPanic(&cb.Policy{
6054
Type: int32(cb.Policy_SIGNATURE),
@@ -63,7 +57,7 @@ func makePolicySource(policyResult bool) []byte {
6357
return marshaledPolicy
6458
}
6559

66-
func addPolicy(manager *ManagerImpl, id string, policy []byte) {
60+
func addPolicy(manager *policies.ManagerImpl, id string, policy []byte) {
6761
manager.BeginConfig()
6862
err := manager.ProposeConfig(&cb.ConfigurationItem{
6963
Type: cb.ConfigurationItem_Policy,
@@ -76,42 +70,47 @@ func addPolicy(manager *ManagerImpl, id string, policy []byte) {
7670
manager.CommitConfig()
7771
}
7872

73+
func providerMap() map[int32]policies.Provider {
74+
r := make(map[int32]policies.Provider)
75+
r[int32(cb.Policy_SIGNATURE)] = NewPolicyProvider(&mockCryptoHelper{})
76+
return r
77+
}
78+
7979
func TestAccept(t *testing.T) {
8080
policyID := "policyID"
81-
m := NewManagerImpl(&mockCryptoHelper{})
82-
t.Logf("%p %x %v", acceptAllPolicy, acceptAllPolicy, acceptAllPolicy)
81+
m := policies.NewManagerImpl(providerMap())
8382
addPolicy(m, policyID, acceptAllPolicy)
8483
policy, ok := m.GetPolicy(policyID)
8584
if !ok {
8685
t.Error("Should have found policy which was just added, but did not")
8786
}
88-
err := policy.Evaluate(nil, nil, nil, nil)
87+
err := policy.Evaluate([]*cb.SignedData{})
8988
if err != nil {
9089
t.Fatalf("Should not have errored evaluating an acceptAll policy: %s", err)
9190
}
9291
}
9392

9493
func TestReject(t *testing.T) {
9594
policyID := "policyID"
96-
m := NewManagerImpl(&mockCryptoHelper{})
95+
m := policies.NewManagerImpl(providerMap())
9796
addPolicy(m, policyID, rejectAllPolicy)
9897
policy, ok := m.GetPolicy(policyID)
9998
if !ok {
10099
t.Error("Should have found policy which was just added, but did not")
101100
}
102-
err := policy.Evaluate(nil, nil, nil, nil)
101+
err := policy.Evaluate([]*cb.SignedData{})
103102
if err == nil {
104103
t.Fatal("Should have errored evaluating the rejectAll policy")
105104
}
106105
}
107106

108107
func TestRejectOnUnknown(t *testing.T) {
109-
m := NewManagerImpl(&mockCryptoHelper{})
108+
m := policies.NewManagerImpl(providerMap())
110109
policy, ok := m.GetPolicy("FakePolicyID")
111110
if ok {
112111
t.Error("Should not have found policy which was never added, but did")
113112
}
114-
err := policy.Evaluate(nil, nil, nil, nil)
113+
err := policy.Evaluate([]*cb.SignedData{})
115114
if err == nil {
116115
t.Fatal("Should have errored evaluating the default policy")
117116
}

0 commit comments

Comments
 (0)