Skip to content
This repository was archived by the owner on Apr 25, 2025. It is now read-only.

Commit e50cd25

Browse files
author
Aleksandar Likic
committed
[FAB-7513] MSP-like key and cert storage
This change introduces a key value store that supports MSP-like directory structure, the same that is currently used for pre-enrolled users (generated by the cryptogen tool). Also, the CredentialManager is modified to use this type of store for user private keys (in case of SW crypto provider) and user certs. Change-Id: I7e3dcd07d14354deb35514ee9275b88a5e9055ae Signed-off-by: Aleksandar Likic <aleksandar.likic@securekey.com>
1 parent 4c64194 commit e50cd25

File tree

27 files changed

+695
-262
lines changed

27 files changed

+695
-262
lines changed

api/apifabclient/keyvaluestore.go

Lines changed: 0 additions & 31 deletions
This file was deleted.

api/kvstore/kvstore.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
Copyright SecureKey Technologies Inc. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package kvstore
8+
9+
import "github.com/pkg/errors"
10+
11+
var (
12+
// ErrNotFound indicates that a value for the key does not exist
13+
ErrNotFound = errors.New("value for key not found")
14+
)
15+
16+
// KVStore is a generic key-value store interface.
17+
type KVStore interface {
18+
19+
/**
20+
* Store sets the value for the key.
21+
*/
22+
Store(key interface{}, value interface{}) error
23+
24+
/**
25+
* Load returns the value stored in the store for a key.
26+
* If a value for the key was not found, returns (nil, ErrNotFound)
27+
*/
28+
Load(key interface{}) (interface{}, error)
29+
30+
/**
31+
* Delete deletes the value for a key.
32+
*/
33+
Delete(key interface{}) error
34+
}

pkg/config/cryptoutil/cryptoutils.go

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,8 @@ var logger = logging.NewLogger("fabric_sdk_go")
2727
// GetPrivateKeyFromCert will return private key represented by SKI in cert's public key
2828
func GetPrivateKeyFromCert(cert []byte, cs apicryptosuite.CryptoSuite) (apicryptosuite.Key, error) {
2929

30-
dcert, _ := pem.Decode(cert)
31-
if dcert == nil {
32-
return nil, errors.Errorf("Unable to decode cert bytes [%v]", cert)
33-
}
34-
35-
x509Cert, err := x509.ParseCertificate(dcert.Bytes)
36-
if err != nil {
37-
return nil, errors.Errorf("Unable to parse cert from decoded bytes: %s", err)
38-
}
39-
4030
// get the public key in the right format
41-
certPubK, err := cs.KeyImport(x509Cert, factory.GetX509PublicKeyImportOpts(true))
31+
certPubK, err := GetPublicKeyFromCert(cert, cs)
4232
if err != nil {
4333
return nil, errors.WithMessage(err, "Failed to import certificate's public key")
4434
}
@@ -60,6 +50,28 @@ func GetPrivateKeyFromCert(cert []byte, cs apicryptosuite.CryptoSuite) (apicrypt
6050
return key, nil
6151
}
6252

53+
// GetPublicKeyFromCert will return public key the from cert
54+
func GetPublicKeyFromCert(cert []byte, cs apicryptosuite.CryptoSuite) (apicryptosuite.Key, error) {
55+
56+
dcert, _ := pem.Decode(cert)
57+
if dcert == nil {
58+
return nil, errors.Errorf("Unable to decode cert bytes [%v]", cert)
59+
}
60+
61+
x509Cert, err := x509.ParseCertificate(dcert.Bytes)
62+
if err != nil {
63+
return nil, errors.Errorf("Unable to parse cert from decoded bytes: %s", err)
64+
}
65+
66+
// get the public key in the right format
67+
key, err := cs.KeyImport(x509Cert, factory.GetX509PublicKeyImportOpts(true))
68+
if err != nil {
69+
return nil, errors.WithMessage(err, "Failed to import certificate's public key")
70+
}
71+
72+
return key, nil
73+
}
74+
6375
// X509KeyPair will return cer/key pair used for mutual TLS
6476
func X509KeyPair(certPEMBlock []byte, pk apicryptosuite.Key, cs apicryptosuite.CryptoSuite) (tls.Certificate, error) {
6577

pkg/cryptosuite/bccsp/sw/cryptosuiteimpl.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,21 @@ func GetSuiteByConfig(config apiconfig.Config) (apicryptosuite.CryptoSuite, erro
2727

2828
opts := getOptsByConfig(config)
2929
bccsp, err := getBCCSPFromOpts(opts)
30-
3130
if err != nil {
3231
return nil, err
3332
}
34-
return &wrapper.CryptoSuite{BCCSP: bccsp}, nil
33+
return wrapper.NewCryptoSuite(bccsp), nil
3534
}
3635

3736
//GetSuiteWithDefaultEphemeral returns cryptosuite adaptor for bccsp with default ephemeral options (intended to aid testing)
3837
func GetSuiteWithDefaultEphemeral() (apicryptosuite.CryptoSuite, error) {
3938
opts := getEphemeralOpts()
40-
bccsp, err := getBCCSPFromOpts(opts)
4139

40+
bccsp, err := getBCCSPFromOpts(opts)
4241
if err != nil {
4342
return nil, err
4443
}
45-
return &wrapper.CryptoSuite{BCCSP: bccsp}, nil
44+
return wrapper.NewCryptoSuite(bccsp), nil
4645
}
4746

4847
func getBCCSPFromOpts(config *bccspSw.SwOpts) (bccsp.BCCSP, error) {

pkg/cryptosuite/bccsp/wrapper/cryptosuiteimpl.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ import (
1717
var logger = logging.NewLogger("fabric_sdk_go")
1818

1919
//NewCryptoSuite returns cryptosuite adaptor for given bccsp.BCCSP implementation
20-
func NewCryptoSuite(bccsp bccsp.BCCSP) CryptoSuite {
21-
return CryptoSuite{bccsp}
20+
func NewCryptoSuite(bccsp bccsp.BCCSP) apicryptosuite.CryptoSuite {
21+
return &CryptoSuite{
22+
BCCSP: bccsp,
23+
}
2224
}
2325

2426
//GetKey returns implementation of of cryptosuite.Key

pkg/cryptosuite/bccsp/wrapper/cryptosuiteimpl_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515

1616
"github.com/golang/mock/gomock"
1717
"github.com/hyperledger/fabric-sdk-go/api/apiconfig/mocks"
18+
"github.com/hyperledger/fabric-sdk-go/api/apicryptosuite"
1819
"github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/bccsp"
1920
"github.com/hyperledger/fabric-sdk-go/pkg/logging/utils"
2021
)
@@ -146,7 +147,7 @@ func TestCreateInvalidSecurityProviderPanic(t *testing.T) {
146147
t.Fatalf("Getting cryptosuite with invalid security provider supposed to panic")
147148
}
148149

149-
func verifyCryptoSuite(t *testing.T, samplecryptoSuite CryptoSuite) {
150+
func verifyCryptoSuite(t *testing.T, samplecryptoSuite apicryptosuite.CryptoSuite) {
150151
//Test cryptosuite.Sign
151152
signedBytes, err := samplecryptoSuite.Sign(GetKey(getMockKey(signingKey)), nil, nil)
152153
utils.VerifyEmpty(t, err, "Not supposed to get any error for samplecryptoSuite.GetKey : %s", err)

pkg/fabric-client/client.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
config "github.com/hyperledger/fabric-sdk-go/api/apiconfig"
1313
fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
14+
"github.com/hyperledger/fabric-sdk-go/api/kvstore"
1415
"github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/common"
1516
pb "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/peer"
1617

@@ -29,7 +30,7 @@ var logger = logging.NewLogger("fabric_sdk_go")
2930
type Client struct {
3031
channels map[string]fab.Channel
3132
cryptoSuite apicryptosuite.CryptoSuite
32-
stateStore fab.KeyValueStore
33+
stateStore kvstore.KVStore
3334
signingIdentity fab.IdentityContext
3435
config config.Config
3536
signingManager fab.SigningManager
@@ -94,16 +95,16 @@ func (c *Client) QueryChannelInfo(name string, peers []fab.Peer) (fab.Channel, e
9495
// Deprecated: see fabsdk package.
9596
/*
9697
* The SDK should have a built-in key value store implementation (suggest a file-based implementation to allow easy setup during
97-
* development). But production systems would want a store backed by database for more robust storage and clustering,
98+
* development). But production systems would want a store backed by database for more robust kvstore and clustering,
9899
* so that multiple app instances can share app state via the database (note that this doesn’t necessarily make the app stateful).
99100
* This API makes this pluggable so that different store implementations can be selected by the application.
100101
*/
101-
func (c *Client) SetStateStore(stateStore fab.KeyValueStore) {
102+
func (c *Client) SetStateStore(stateStore kvstore.KVStore) {
102103
c.stateStore = stateStore
103104
}
104105

105106
// StateStore is a convenience method for obtaining the state store object in use for this client.
106-
func (c *Client) StateStore() fab.KeyValueStore {
107+
func (c *Client) StateStore() kvstore.KVStore {
107108
return c.stateStore
108109
}
109110

@@ -161,7 +162,7 @@ func (c *Client) SaveUserToStateStore(user fab.User) error {
161162
if err != nil {
162163
return errors.Wrap(err, "marshal json return error")
163164
}
164-
err = c.stateStore.SetValue(user.Name(), data)
165+
err = c.stateStore.Store(user.Name(), data)
165166
if err != nil {
166167
return errors.WithMessage(err, "stateStore SetValue failed")
167168
}
@@ -184,12 +185,19 @@ func (c *Client) LoadUserFromStateStore(name string) (fab.User, error) {
184185
if c.cryptoSuite == nil {
185186
return nil, errors.New("cryptoSuite required")
186187
}
187-
value, err := c.stateStore.Value(name)
188+
value, err := c.stateStore.Load(name)
188189
if err != nil {
189-
return nil, nil
190+
if err == kvstore.ErrNotFound {
191+
return nil, nil
192+
}
193+
return nil, err
194+
}
195+
valueBytes, ok := value.([]byte)
196+
if !ok {
197+
return nil, errors.New("state store return wrong data type")
190198
}
191199
var userJSON identity.JSON
192-
err = json.Unmarshal(value, &userJSON)
200+
err = json.Unmarshal(valueBytes, &userJSON)
193201
if err != nil {
194202
return nil, errors.Wrap(err, "unmarshal user JSON failed")
195203
}

pkg/fabric-client/client_test.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,17 +85,21 @@ func TestClientMethods(t *testing.T) {
8585
t.Fatalf("client.NewChain create wrong chain")
8686
}
8787

88-
stateStore, err := kvs.CreateNewFileKeyValueStore("/tmp/keyvaluestore")
88+
stateStore, err := kvs.NewFileKeyValueStore(&kvs.FileKeyValueStoreOptions{Path: "/tmp/keyvaluestore"})
8989
if err != nil {
9090
t.Fatalf("CreateNewFileKeyValueStore return error[%s]", err)
9191
}
9292
client.SetStateStore(stateStore)
93-
client.StateStore().SetValue("testvalue", []byte("data"))
94-
value, err := client.StateStore().Value("testvalue")
93+
client.StateStore().Store("testvalue", []byte("data"))
94+
value, err := client.StateStore().Load("testvalue")
9595
if err != nil {
96-
t.Fatalf("client.StateStore().GetValue() return error[%s]", err)
96+
t.Fatalf("client.StateStore().Load() return error[%s]", err)
9797
}
98-
if string(value) != "data" {
98+
valueBytes, ok := value.([]byte)
99+
if !ok {
100+
t.Fatalf("client.StateStore().Load() returned wrong data type")
101+
}
102+
if string(valueBytes) != "data" {
99103
t.Fatalf("client.StateStore().GetValue() didn't return the right value")
100104
}
101105

0 commit comments

Comments
 (0)