Skip to content

Commit bf2fd1d

Browse files
committed
Integration of MSP into cauthdsl
This change set introduces a more flexible way of describing the identity associated to a policy. So far we had support for serializing the certificate associated to the identity. We introduce a new structure that supports that and 3 other ways of listing identities: i) the admin of an MSP, ii) the CA of an MSP and iii) a valid certificate for an MSP. Furthermore, policy evaluation is now performed using the MSP infrastructure: cauthdsl receives a policy principal and an Identity instance and then it can use the interfaces offered by the MSP to check whether the identity satisfies the principal and whether the signature verifies. The semantics of policy verification has somewhat changed: an identity (and its signature) can be used to satisfy only a single principal. This has the benefit of better dealing with the policy "two signatures from org0", but it has the downside that a single identity can no longer be used to satisfy two principals (e.g. if we need signatures from an identity with attribute A and one with attribute B, a single signature from an identity with both attributes would not be sufficient). Change-Id: Id18a5933e341781334080965b5d04dc07d4f1b99 Signed-off-by: Alessandro Sorniotti <[email protected]>
1 parent bbe8e8c commit bf2fd1d

14 files changed

+314
-136
lines changed

common/cauthdsl/cauthdsl.go

+113-14
Original file line numberDiff line numberDiff line change
@@ -17,53 +17,152 @@ limitations under the License.
1717
package cauthdsl
1818

1919
import (
20-
"bytes"
2120
"fmt"
2221

22+
"bytes"
23+
24+
"github.com/hyperledger/fabric/msp"
2325
cb "github.com/hyperledger/fabric/protos/common"
26+
"github.com/op/go-logging"
27+
"github.com/syndtr/goleveldb/leveldb/errors"
2428
)
2529

26-
// CryptoHelper is used to provide a plugin point for different signature validation types
27-
type CryptoHelper interface {
28-
VerifySignature(signedData *cb.SignedData) error
29-
}
30+
var cauthdslLogger = logging.MustGetLogger("cauthdsl")
3031

3132
// compile recursively builds a go evaluatable function corresponding to the policy specified
32-
func compile(policy *cb.SignaturePolicy, identities [][]byte, ch CryptoHelper) (func([]*cb.SignedData) bool, error) {
33+
func compile(policy *cb.SignaturePolicy, identities []*cb.MSPPrincipal, deserializer msp.Common) (func([]*cb.SignedData, []bool) bool, error) {
3334
switch t := policy.Type.(type) {
3435
case *cb.SignaturePolicy_From:
35-
policies := make([]func([]*cb.SignedData) bool, len(t.From.Policies))
36+
policies := make([]func([]*cb.SignedData, []bool) bool, len(t.From.Policies))
3637
for i, policy := range t.From.Policies {
37-
compiledPolicy, err := compile(policy, identities, ch)
38+
compiledPolicy, err := compile(policy, identities, deserializer)
3839
if err != nil {
3940
return nil, err
4041
}
4142
policies[i] = compiledPolicy
4243

4344
}
44-
return func(signedData []*cb.SignedData) bool {
45+
return func(signedData []*cb.SignedData, used []bool) bool {
46+
cauthdslLogger.Debug("Gate evaluation starts: (%s)", t)
4547
verified := int32(0)
48+
_used := make([]bool, len(used))
4649
for _, policy := range policies {
47-
if policy(signedData) {
50+
copy(_used, used)
51+
if policy(signedData, _used) {
4852
verified++
53+
copy(used, _used)
4954
}
5055
}
56+
57+
if verified >= t.From.N {
58+
cauthdslLogger.Debug("Gate evaluation succeeds: (%s)", t)
59+
} else {
60+
cauthdslLogger.Debug("Gate evaluation fails: (%s)", t)
61+
}
62+
5163
return verified >= t.From.N
5264
}, nil
5365
case *cb.SignaturePolicy_SignedBy:
5466
if t.SignedBy < 0 || t.SignedBy >= int32(len(identities)) {
5567
return nil, fmt.Errorf("Identity index out of range, requested %d, but identies length is %d", t.SignedBy, len(identities))
5668
}
5769
signedByID := identities[t.SignedBy]
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
70+
return func(signedData []*cb.SignedData, used []bool) bool {
71+
cauthdslLogger.Debug("Principal evaluation starts: (%s) (used %s)", t, used)
72+
for i, sd := range signedData {
73+
if used[i] {
74+
continue
75+
}
76+
// FIXME: what should I do with the error below?
77+
identity, _ := deserializer.DeserializeIdentity(sd.Identity)
78+
err := identity.SatisfiesPrincipal(signedByID)
79+
if err == nil {
80+
err := identity.Verify(sd.Data, sd.Signature)
81+
if err == nil {
82+
cauthdslLogger.Debug("Principal evaluation succeeds: (%s)", t, used)
83+
used[i] = true
84+
return true
85+
}
6286
}
6387
}
88+
cauthdslLogger.Debug("Principal evaluation fails: (%s)", t, used)
6489
return false
6590
}, nil
6691
default:
6792
return nil, fmt.Errorf("Unknown type: %T:%v", t, t)
6893
}
6994
}
95+
96+
// FIXME: remove the code below as soon as we can use MSP from the policy manager code
97+
var invalidSignature = []byte("badsigned")
98+
99+
type mockIdentity struct {
100+
idBytes []byte
101+
}
102+
103+
func (id *mockIdentity) SatisfiesPrincipal(p *cb.MSPPrincipal) error {
104+
if bytes.Compare(id.idBytes, p.Principal) == 0 {
105+
return nil
106+
} else {
107+
return errors.New("Principals do not match")
108+
}
109+
}
110+
111+
func (id *mockIdentity) GetIdentifier() *msp.IdentityIdentifier {
112+
return &msp.IdentityIdentifier{Mspid: "Mock", Id: "Bob"}
113+
}
114+
115+
func (id *mockIdentity) GetMSPIdentifier() string {
116+
return "Mock"
117+
}
118+
119+
func (id *mockIdentity) Validate() error {
120+
return nil
121+
}
122+
123+
func (id *mockIdentity) GetOrganizationUnits() string {
124+
return "dunno"
125+
}
126+
127+
func (id *mockIdentity) Verify(msg []byte, sig []byte) error {
128+
if bytes.Compare(sig, invalidSignature) == 0 {
129+
return errors.New("Invalid signature")
130+
} else {
131+
return nil
132+
}
133+
}
134+
135+
func (id *mockIdentity) VerifyOpts(msg []byte, sig []byte, opts msp.SignatureOpts) error {
136+
return nil
137+
}
138+
139+
func (id *mockIdentity) VerifyAttributes(proof [][]byte, spec *msp.AttributeProofSpec) error {
140+
return nil
141+
}
142+
143+
func (id *mockIdentity) Serialize() ([]byte, error) {
144+
return id.idBytes, nil
145+
}
146+
147+
func toSignedData(data [][]byte, identities [][]byte, signatures [][]byte) ([]*cb.SignedData, []bool) {
148+
signedData := make([]*cb.SignedData, len(data))
149+
for i := range signedData {
150+
signedData[i] = &cb.SignedData{
151+
Data: data[i],
152+
Identity: identities[i],
153+
Signature: signatures[i],
154+
}
155+
}
156+
return signedData, make([]bool, len(signedData))
157+
}
158+
159+
type mockDeserializer struct {
160+
}
161+
162+
func NewMockDeserializer() msp.Common {
163+
return &mockDeserializer{}
164+
}
165+
166+
func (md *mockDeserializer) DeserializeIdentity(serializedIdentity []byte) (msp.Identity, error) {
167+
return &mockIdentity{idBytes: serializedIdentity}, nil
168+
}

common/cauthdsl/cauthdsl_builder.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,15 @@ func init() {
5252

5353
// Envelope builds an envelope message embedding a SignaturePolicy
5454
func Envelope(policy *cb.SignaturePolicy, identities [][]byte) *cb.SignaturePolicyEnvelope {
55+
ids := make([]*cb.MSPPrincipal, len(identities))
56+
for i, _ := range ids {
57+
ids[i] = &cb.MSPPrincipal{PrincipalClassification: cb.MSPPrincipal_ByIdentity, Principal: identities[i]}
58+
}
59+
5560
return &cb.SignaturePolicyEnvelope{
5661
Version: 0,
5762
Policy: policy,
58-
Identities: identities,
63+
Identities: ids,
5964
}
6065
}
6166

common/cauthdsl/cauthdsl_test.go

+20-42
Original file line numberDiff line numberDiff line change
@@ -17,66 +17,40 @@ limitations under the License.
1717
package cauthdsl
1818

1919
import (
20-
"bytes"
21-
"fmt"
2220
"testing"
2321

2422
"github.com/golang/protobuf/proto"
2523
cb "github.com/hyperledger/fabric/protos/common"
2624
)
2725

28-
var invalidSignature = []byte("badsigned")
2926
var validSignature = []byte("signed")
3027
var signers = [][]byte{[]byte("signer0"), []byte("signer1")}
3128
var msgs = [][]byte{nil, nil}
32-
33-
type mockCryptoHelper struct {
34-
}
35-
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
53-
}
29+
var moreMsgs = [][]byte{nil, nil, nil}
5430

5531
func TestSimpleSignature(t *testing.T) {
56-
mch := &mockCryptoHelper{}
5732
policy := Envelope(SignedBy(0), signers)
5833

59-
spe, err := compile(policy.Policy, policy.Identities, mch)
34+
spe, err := compile(policy.Policy, policy.Identities, &mockDeserializer{})
6035
if err != nil {
6136
t.Fatalf("Could not create a new SignaturePolicyEvaluator using the given policy, crypto-helper: %s", err)
6237
}
6338

64-
if !spe([]*cb.SignedData{&cb.SignedData{Identity: signers[0], Signature: validSignature}}) {
65-
t.Errorf("Expected authentication to succeed with valid signatures")
39+
if !spe(toSignedData([][]byte{nil}, [][]byte{signers[0]}, [][]byte{validSignature})) {
40+
t.Errorf("Expected authentication to succeed with valid signatures")
6641
}
67-
if spe([]*cb.SignedData{&cb.SignedData{Identity: signers[0], Signature: invalidSignature}}) {
42+
if spe(toSignedData([][]byte{nil}, [][]byte{signers[0]}, [][]byte{invalidSignature})) {
6843
t.Errorf("Expected authentication to fail given the invalid signature")
6944
}
70-
if spe([]*cb.SignedData{&cb.SignedData{Identity: signers[1], Signature: validSignature}}) {
45+
if spe(toSignedData([][]byte{nil}, [][]byte{signers[1]}, [][]byte{validSignature})) {
7146
t.Errorf("Expected authentication to fail because signers[1] is not authorized in the policy, despite his valid signature")
7247
}
7348
}
7449

7550
func TestMultipleSignature(t *testing.T) {
76-
mch := &mockCryptoHelper{}
7751
policy := Envelope(And(SignedBy(0), SignedBy(1)), signers)
7852

79-
spe, err := compile(policy.Policy, policy.Identities, mch)
53+
spe, err := compile(policy.Policy, policy.Identities, &mockDeserializer{})
8054
if err != nil {
8155
t.Fatalf("Could not create a new SignaturePolicyEvaluator using the given policy, crypto-helper: %s", err)
8256
}
@@ -93,33 +67,37 @@ func TestMultipleSignature(t *testing.T) {
9367
}
9468

9569
func TestComplexNestedSignature(t *testing.T) {
96-
mch := &mockCryptoHelper{}
9770
policy := Envelope(And(Or(And(SignedBy(0), SignedBy(1)), And(SignedBy(0), SignedBy(0))), SignedBy(0)), signers)
9871

99-
spe, err := compile(policy.Policy, policy.Identities, mch)
72+
spe, err := compile(policy.Policy, policy.Identities, &mockDeserializer{})
10073
if err != nil {
10174
t.Fatalf("Could not create a new SignaturePolicyEvaluator using the given policy, crypto-helper: %s", err)
10275
}
10376

104-
if !spe(toSignedData(msgs, signers, [][]byte{validSignature, validSignature})) {
77+
if !spe(toSignedData(moreMsgs, append(signers, [][]byte{[]byte("signer0")}...), [][]byte{validSignature, validSignature, validSignature})) {
10578
t.Errorf("Expected authentication to succeed with valid signatures")
10679
}
107-
if spe(toSignedData(msgs, signers, [][]byte{invalidSignature, validSignature})) {
108-
t.Errorf("Expected authentication failure as only the signature of signer[1] was valid")
80+
if !spe(toSignedData(moreMsgs, [][]byte{[]byte("signer0"), []byte("signer0"), []byte("signer0")}, [][]byte{validSignature, validSignature, validSignature})) {
81+
t.Errorf("Expected authentication to succeed with valid signatures")
82+
}
83+
if spe(toSignedData(msgs, signers, [][]byte{validSignature, validSignature})) {
84+
t.Errorf("Expected authentication to fail with too few signatures")
85+
}
86+
if spe(toSignedData(moreMsgs, append(signers, [][]byte{[]byte("signer0")}...), [][]byte{validSignature, invalidSignature, validSignature})) {
87+
t.Errorf("Expected authentication failure as the signature of signer[1] was invalid")
10988
}
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]")
89+
if spe(toSignedData(moreMsgs, append(signers, [][]byte{[]byte("signer1")}...), [][]byte{validSignature, validSignature, validSignature})) {
90+
t.Errorf("Expected authentication failure as there was a signature from signer[0] missing")
11291
}
11392
}
11493

11594
func TestNegatively(t *testing.T) {
116-
mch := &mockCryptoHelper{}
11795
rpolicy := Envelope(And(SignedBy(0), SignedBy(1)), signers)
11896
rpolicy.Policy.Type = nil
11997
b, _ := proto.Marshal(rpolicy)
12098
policy := &cb.SignaturePolicyEnvelope{}
12199
_ = proto.Unmarshal(b, policy)
122-
_, err := compile(policy.Policy, policy.Identities, mch)
100+
_, err := compile(policy.Policy, policy.Identities, &mockDeserializer{})
123101
if err == nil {
124102
t.Fatal("Should have errored compiling because the Type field was nil")
125103
}

common/cauthdsl/policy.go

+7-6
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,17 @@ import (
2424
cb "github.com/hyperledger/fabric/protos/common"
2525

2626
"github.com/golang/protobuf/proto"
27+
"github.com/hyperledger/fabric/msp"
2728
)
2829

2930
type provider struct {
30-
helper CryptoHelper
31+
deserializer msp.Common
3132
}
3233

3334
// NewProviderImpl provides a policy generator for cauthdsl type policies
34-
func NewPolicyProvider(helper CryptoHelper) policies.Provider {
35+
func NewPolicyProvider(deserializer msp.Common) policies.Provider {
3536
return &provider{
36-
helper: helper,
37+
deserializer: deserializer,
3738
}
3839
}
3940

@@ -48,7 +49,7 @@ func (pr *provider) NewPolicy(data []byte) (policies.Policy, error) {
4849
return nil, fmt.Errorf("This evaluator only understands messages of version 0, but version was %d", sigPolicy.Version)
4950
}
5051

51-
compiled, err := compile(sigPolicy.Policy, sigPolicy.Identities, pr.helper)
52+
compiled, err := compile(sigPolicy.Policy, sigPolicy.Identities, pr.deserializer)
5253
if err != nil {
5354
return nil, err
5455
}
@@ -60,7 +61,7 @@ func (pr *provider) NewPolicy(data []byte) (policies.Policy, error) {
6061
}
6162

6263
type policy struct {
63-
evaluator func([]*cb.SignedData) bool
64+
evaluator func([]*cb.SignedData, []bool) bool
6465
}
6566

6667
// Evaluate takes a set of SignedData and evaluates whether this set of signatures satisfies the policy
@@ -69,7 +70,7 @@ func (p *policy) Evaluate(signatureSet []*cb.SignedData) error {
6970
return fmt.Errorf("No such policy")
7071
}
7172

72-
ok := p.evaluator(signatureSet)
73+
ok := p.evaluator(signatureSet, make([]bool, len(signatureSet)))
7374
if !ok {
7475
return errors.New("Failed to authenticate policy")
7576
}

common/cauthdsl/policy_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func addPolicy(manager *policies.ManagerImpl, id string, policy []byte) {
7272

7373
func providerMap() map[int32]policies.Provider {
7474
r := make(map[int32]policies.Provider)
75-
r[int32(cb.Policy_SIGNATURE)] = NewPolicyProvider(&mockCryptoHelper{})
75+
r[int32(cb.Policy_SIGNATURE)] = NewPolicyProvider(&mockDeserializer{})
7676
return r
7777
}
7878

msp/identities.go

+6
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"github.com/golang/protobuf/proto"
2929
"github.com/hyperledger/fabric/bccsp"
3030
"github.com/hyperledger/fabric/bccsp/signer"
31+
"github.com/hyperledger/fabric/protos/common"
3132
)
3233

3334
type identity struct {
@@ -49,6 +50,11 @@ func newIdentity(id *IdentityIdentifier, cert *x509.Certificate, pk bccsp.Key, m
4950
return &identity{id: id, cert: cert, pk: pk, msp: msp}
5051
}
5152

53+
// SatisfiesPrincipal returns null if this instance matches the supplied principal or an error otherwise
54+
func (id *identity) SatisfiesPrincipal(principal *common.MSPPrincipal) error {
55+
return id.msp.SatisfiesPrincipal(id, principal)
56+
}
57+
5258
// GetIdentifier returns the identifier (MSPID/IDID) for this instance
5359
func (id *identity) GetIdentifier() *IdentityIdentifier {
5460
return id.id

0 commit comments

Comments
 (0)