Skip to content

Commit 69eeaf5

Browse files
committed
FAB-1046 Gossip internal identity mapper
The current gossip component assumes the upper layers are able to fetch each remote peer's certificate by its corresponding PKI-ID. This is true for 0.5 but this isn't the case for v1, so this commit makes each peer send the other peer its certificate and each peer creates a mapping between PKIid-->certificate. This commit adds an identity mapper that is used for the comm layer and the gossip layer to map pkiIDs to certificates, in order to be able to verify messages signed by peers but not having the certificates inside the messages. Change-Id: Iab1c99929515c01704ffb0295dca05ccefd8793f Signed-off-by: Yacov Manevich <[email protected]>
1 parent baea89c commit 69eeaf5

File tree

2 files changed

+221
-0
lines changed

2 files changed

+221
-0
lines changed

gossip/identity/identity.go

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
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 identity
18+
19+
import (
20+
"bytes"
21+
"fmt"
22+
"sync"
23+
24+
"github.com/hyperledger/fabric/gossip/api"
25+
"github.com/hyperledger/fabric/gossip/common"
26+
)
27+
28+
// Mapper holds mappings between pkiID
29+
// to certificates(identities) of peers
30+
type Mapper interface {
31+
// Put associates an identity to its given pkiID, and returns an error
32+
// in case the given pkiID doesn't match the identity
33+
Put(pkiID common.PKIidType, identity api.PeerIdentityType) error
34+
35+
// Get returns the identity of a given pkiID, or error if such an identity
36+
// isn't found
37+
Get(pkiID common.PKIidType) (api.PeerIdentityType, error)
38+
39+
// Sign signs a message, returns a signed message on success
40+
// or an error on failure
41+
Sign(msg []byte) ([]byte, error)
42+
43+
// Verify verifies a signed message
44+
Verify(vkID, signature, message []byte) error
45+
46+
// GetPKIidOfCert returns the PKI-ID of a certificate
47+
GetPKIidOfCert(api.PeerIdentityType) common.PKIidType
48+
}
49+
50+
// identityMapperImpl is a struct that implements Mapper
51+
type identityMapperImpl struct {
52+
mcs api.MessageCryptoService
53+
pkiID2Cert map[string]api.PeerIdentityType
54+
sync.RWMutex
55+
}
56+
57+
// NewIdentityStore method, all we need is a reference to a MessageCryptoService
58+
func NewIdentityMapper(mcs api.MessageCryptoService) Mapper {
59+
return &identityMapperImpl{
60+
mcs: mcs,
61+
pkiID2Cert: make(map[string]api.PeerIdentityType),
62+
}
63+
}
64+
65+
// put associates an identity to its given pkiID, and returns an error
66+
// in case the given pkiID doesn't match the identity
67+
func (is *identityMapperImpl) Put(pkiID common.PKIidType, identity api.PeerIdentityType) error {
68+
if pkiID == nil {
69+
return fmt.Errorf("pkiID is nil")
70+
}
71+
if identity == nil {
72+
return fmt.Errorf("identity is nil")
73+
}
74+
75+
id := is.mcs.GetPKIidOfCert(identity)
76+
if !bytes.Equal(pkiID, id) {
77+
return fmt.Errorf("Identity doesn't match the computed pkiID")
78+
}
79+
80+
is.Lock()
81+
defer is.Unlock()
82+
is.pkiID2Cert[string(id)] = identity
83+
return nil
84+
}
85+
86+
// get returns the identity of a given pkiID, or error if such an identity
87+
// isn't found
88+
func (is *identityMapperImpl) Get(pkiID common.PKIidType) (api.PeerIdentityType, error) {
89+
is.RLock()
90+
defer is.RUnlock()
91+
identity, exists := is.pkiID2Cert[string(pkiID)]
92+
if !exists {
93+
return nil, fmt.Errorf("pkiID wasn't found")
94+
}
95+
return identity, nil
96+
}
97+
98+
// Sign signs a message, returns a signed message on success
99+
// or an error on failure
100+
func (is *identityMapperImpl) Sign(msg []byte) ([]byte, error) {
101+
return is.mcs.Sign(msg)
102+
}
103+
104+
// Verify verifies a signed message
105+
func (is *identityMapperImpl) Verify(vkID, signature, message []byte) error {
106+
cert, err := is.Get(vkID)
107+
if err != nil {
108+
return err
109+
}
110+
return is.mcs.Verify(cert, signature, message)
111+
}
112+
113+
// GetPKIidOfCert returns the PKI-ID of a certificate
114+
func (is *identityMapperImpl) GetPKIidOfCert(identity api.PeerIdentityType) common.PKIidType {
115+
return is.mcs.GetPKIidOfCert(identity)
116+
}

gossip/identity/identity_test.go

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
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 identity
18+
19+
import (
20+
"bytes"
21+
"fmt"
22+
"testing"
23+
24+
"github.com/hyperledger/fabric/gossip/api"
25+
"github.com/hyperledger/fabric/gossip/common"
26+
"github.com/stretchr/testify/assert"
27+
)
28+
29+
var msgCryptoService = &naiveCryptoService{}
30+
31+
type naiveCryptoService struct {
32+
}
33+
34+
func (*naiveCryptoService) ValidateIdentity(peerIdentity api.PeerIdentityType) error {
35+
return nil
36+
}
37+
38+
// GetPKIidOfCert returns the PKI-ID of a peer's identity
39+
func (*naiveCryptoService) GetPKIidOfCert(peerIdentity api.PeerIdentityType) common.PKIidType {
40+
return common.PKIidType(peerIdentity)
41+
}
42+
43+
// VerifyBlock returns nil if the block is properly signed,
44+
// else returns error
45+
func (*naiveCryptoService) VerifyBlock(signedBlock api.SignedBlock) error {
46+
return nil
47+
}
48+
49+
// Sign signs msg with this peer's signing key and outputs
50+
// the signature if no error occurred.
51+
func (*naiveCryptoService) Sign(msg []byte) ([]byte, error) {
52+
return msg, nil
53+
}
54+
55+
// Verify checks that signature is a valid signature of message under a peer's verification key.
56+
// If the verification succeeded, Verify returns nil meaning no error occurred.
57+
// If peerCert is nil, then the signature is verified against this peer's verification key.
58+
func (*naiveCryptoService) Verify(peerIdentity api.PeerIdentityType, signature, message []byte) error {
59+
equal := bytes.Equal(signature, message)
60+
if !equal {
61+
return fmt.Errorf("Wrong certificate")
62+
}
63+
return nil
64+
}
65+
66+
func TestPut(t *testing.T) {
67+
idStore := NewIdentityMapper(msgCryptoService)
68+
identity := []byte("yacovm")
69+
identity2 := []byte("not-yacovm")
70+
pkiID := msgCryptoService.GetPKIidOfCert(api.PeerIdentityType(identity))
71+
pkiID2 := msgCryptoService.GetPKIidOfCert(api.PeerIdentityType(identity2))
72+
assert.NoError(t, idStore.Put(pkiID, identity))
73+
assert.Error(t, idStore.Put(nil, identity))
74+
assert.Error(t, idStore.Put(pkiID2, nil))
75+
assert.Error(t, idStore.Put(pkiID2, identity))
76+
assert.Error(t, idStore.Put(pkiID, identity2))
77+
}
78+
79+
func TestGet(t *testing.T) {
80+
idStore := NewIdentityMapper(msgCryptoService)
81+
identity := []byte("yacovm")
82+
identity2 := []byte("not-yacovm")
83+
pkiID := msgCryptoService.GetPKIidOfCert(api.PeerIdentityType(identity))
84+
pkiID2 := msgCryptoService.GetPKIidOfCert(api.PeerIdentityType(identity2))
85+
assert.NoError(t, idStore.Put(pkiID, identity))
86+
cert, err := idStore.Get(pkiID)
87+
assert.NoError(t, err)
88+
assert.Equal(t, api.PeerIdentityType(identity), cert)
89+
cert, err = idStore.Get(pkiID2)
90+
assert.Nil(t, cert)
91+
assert.Error(t, err)
92+
}
93+
94+
func TestVerify(t *testing.T) {
95+
idStore := NewIdentityMapper(msgCryptoService)
96+
identity := []byte("yacovm")
97+
identity2 := []byte("not-yacovm")
98+
pkiID := msgCryptoService.GetPKIidOfCert(api.PeerIdentityType(identity))
99+
pkiID2 := msgCryptoService.GetPKIidOfCert(api.PeerIdentityType(identity2))
100+
idStore.Put(pkiID, api.PeerIdentityType(identity))
101+
signed, err := idStore.Sign([]byte("bla bla"))
102+
assert.NoError(t, err)
103+
assert.NoError(t, idStore.Verify(pkiID, signed, []byte("bla bla")))
104+
assert.Error(t, idStore.Verify(pkiID2, signed, []byte("bla bla")))
105+
}

0 commit comments

Comments
 (0)