Skip to content

Commit db4ff06

Browse files
authored
Feature: skvs for rollback protection (#766)
This adds single key-Value store abstraction layer to protected against rollback attacks. Signed-off-by: chenchanglew <lewchenchang@gmail.com>
1 parent ff2a560 commit db4ff06

File tree

7 files changed

+204
-4
lines changed

7 files changed

+204
-4
lines changed

ecc_go/chaincode/enclave_go/enclave.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/hyperledger/fabric-private-chaincode/ecc_go/chaincode/enclave_go/attestation"
1919
"github.com/hyperledger/fabric-private-chaincode/internal/crypto"
2020
"github.com/hyperledger/fabric-private-chaincode/internal/protos"
21+
pb "github.com/hyperledger/fabric-protos-go/peer"
2122
"github.com/hyperledger/fabric/bccsp"
2223
"github.com/hyperledger/fabric/bccsp/factory"
2324
"github.com/hyperledger/fabric/common/flogging"
@@ -37,6 +38,7 @@ type EnclaveStub struct {
3738
hostParams *protos.HostParameters
3839
chaincodeParams *protos.CCParameters
3940
fabricCryptoProvider bccsp.BCCSP
41+
stubProvider func(shim.ChaincodeStubInterface, *pb.ChaincodeInput, *readWriteSet, StateEncryptionFunctions) shim.ChaincodeStubInterface
4042
}
4143

4244
func NewEnclaveStub(cc shim.Chaincode) *EnclaveStub {
@@ -49,6 +51,9 @@ func NewEnclaveStub(cc shim.Chaincode) *EnclaveStub {
4951
csp: crypto.GetDefaultCSP(),
5052
ccRef: cc,
5153
fabricCryptoProvider: cryptoProvider,
54+
stubProvider: func(stub shim.ChaincodeStubInterface, input *pb.ChaincodeInput, rwset *readWriteSet, sep StateEncryptionFunctions) shim.ChaincodeStubInterface {
55+
return NewFpcStubInterface(stub, input, rwset, sep)
56+
},
5257
}
5358
}
5459

@@ -161,7 +166,7 @@ func (e *EnclaveStub) ChaincodeInvoke(stub shim.ChaincodeStubInterface, chaincod
161166

162167
// Invoke chaincode
163168
// we wrap the stub with our FpcStubInterface
164-
fpcStub := NewFpcStubInterface(stub, cleartextChaincodeRequest.GetInput(), rwset, e.ccKeys)
169+
fpcStub := e.stubProvider(stub, cleartextChaincodeRequest.GetInput(), rwset, e.ccKeys)
165170
ccResponse := e.ccRef.Invoke(fpcStub)
166171

167172
// marshal chaincode response
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package enclave_go
8+
9+
import (
10+
"github.com/hyperledger/fabric-chaincode-go/shim"
11+
pb "github.com/hyperledger/fabric-protos-go/peer"
12+
)
13+
14+
func NewSkvsStub(cc shim.Chaincode) *EnclaveStub {
15+
enclaveStub := NewEnclaveStub(cc)
16+
enclaveStub.stubProvider = func(stub shim.ChaincodeStubInterface, input *pb.ChaincodeInput, rwset *readWriteSet, sep StateEncryptionFunctions) shim.ChaincodeStubInterface {
17+
return NewSkvsStubInterface(stub, input, rwset, sep)
18+
}
19+
return enclaveStub
20+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package enclave_go
8+
9+
import (
10+
"encoding/json"
11+
"fmt"
12+
13+
"github.com/hyperledger/fabric-chaincode-go/shim"
14+
pb "github.com/hyperledger/fabric-protos-go/peer"
15+
)
16+
17+
const SKVSKey = "SKVS"
18+
19+
type SkvsStubInterface struct {
20+
*FpcStubInterface
21+
allDataOld map[string][]byte
22+
allDataNew map[string][]byte
23+
key string
24+
}
25+
26+
func NewSkvsStubInterface(stub shim.ChaincodeStubInterface, input *pb.ChaincodeInput, rwset *readWriteSet, sep StateEncryptionFunctions) *SkvsStubInterface {
27+
fpcStub := NewFpcStubInterface(stub, input, rwset, sep)
28+
skvsStub := &SkvsStubInterface{
29+
FpcStubInterface: fpcStub,
30+
allDataOld: make(map[string][]byte),
31+
allDataNew: make(map[string][]byte),
32+
key: SKVSKey,
33+
}
34+
err := skvsStub.initSKVS()
35+
if err != nil {
36+
panic(fmt.Sprintf("Initializing SKVS failed, err: %v", err))
37+
}
38+
return skvsStub
39+
}
40+
41+
func (s *SkvsStubInterface) initSKVS() error {
42+
43+
// get current state, this will only operate once
44+
encValue, err := s.GetPublicState(s.key)
45+
if err != nil {
46+
return err
47+
}
48+
49+
// return if the key initially does not exist
50+
if len(encValue) == 0 {
51+
logger.Warningf("SKVS is empty, Initiating.")
52+
return nil
53+
}
54+
55+
value, err := s.sep.DecryptState(encValue)
56+
if err != nil {
57+
return err
58+
}
59+
logger.Debug("SKVS has default value, loading current value.")
60+
61+
err = json.Unmarshal(value, &s.allDataOld)
62+
if err != nil {
63+
logger.Errorf("SKVS Json unmarshal error: %s", err)
64+
return err
65+
}
66+
err = json.Unmarshal(value, &s.allDataNew)
67+
if err != nil {
68+
logger.Errorf("SKVS Json unmarshal error: %s", err)
69+
return err
70+
}
71+
return nil
72+
}
73+
74+
func (s *SkvsStubInterface) GetState(key string) ([]byte, error) {
75+
value, found := s.allDataOld[key]
76+
if !found {
77+
logger.Errorf("skvs allDataOld key: %s, not found", key)
78+
return nil, nil
79+
}
80+
return value, nil
81+
}
82+
83+
func (s *SkvsStubInterface) PutState(key string, value []byte) error {
84+
85+
s.allDataNew[key] = value
86+
byteAllData, err := json.Marshal(s.allDataNew)
87+
if err != nil {
88+
return err
89+
}
90+
encValue, err := s.sep.EncryptState(byteAllData)
91+
if err != nil {
92+
return err
93+
}
94+
95+
return s.PutPublicState(s.key, encValue)
96+
}
97+
98+
func (s *SkvsStubInterface) DelState(key string) error {
99+
delete(s.allDataNew, key)
100+
byteAllData, err := json.Marshal(s.allDataNew)
101+
if err != nil {
102+
return err
103+
}
104+
encValue, err := s.sep.EncryptState(byteAllData)
105+
if err != nil {
106+
return err
107+
}
108+
return s.PutPublicState(s.key, encValue)
109+
}
110+
111+
func (s *SkvsStubInterface) GetStateByRange(startKey string, endKey string) (shim.StateQueryIteratorInterface, error) {
112+
panic("not implemented") // TODO: Implement
113+
}
114+
115+
func (s *SkvsStubInterface) GetStateByRangeWithPagination(startKey string, endKey string, pageSize int32, bookmark string) (shim.StateQueryIteratorInterface, *pb.QueryResponseMetadata, error) {
116+
panic("not implemented") // TODO: Implement
117+
}

ecc_go/chaincode/private.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,24 @@ import (
1414
"github.com/hyperledger/fabric-private-chaincode/internal/endorsement"
1515
)
1616

17+
type BuildOption func(*chaincode.EnclaveChaincode, shim.Chaincode)
18+
1719
// NewPrivateChaincode creates a new chaincode! This is for go support only!!!
18-
func NewPrivateChaincode(cc shim.Chaincode) *chaincode.EnclaveChaincode {
20+
func NewPrivateChaincode(cc shim.Chaincode, options ...BuildOption) *chaincode.EnclaveChaincode {
1921
ecc := &chaincode.EnclaveChaincode{
2022
Enclave: enclave_go.NewEnclaveStub(cc),
2123
Validator: endorsement.NewValidator(),
2224
Extractor: &chaincode.ExtractorImpl{},
2325
Ercc: &ercc.StubImpl{},
2426
}
25-
27+
for _, o := range options {
28+
o(ecc, cc)
29+
}
2630
return ecc
2731
}
32+
33+
func WithSKVS() BuildOption {
34+
return func(ecc *chaincode.EnclaveChaincode, cc shim.Chaincode) {
35+
ecc.Enclave = enclave_go.NewSkvsStub(cc)
36+
}
37+
}

samples/chaincode/secret-keeper-go/Makefile

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44
# SPDX-License-Identifier: Apache-2.0
55

66
TOP = ../../..
7-
include $(TOP)/ecc_go/build.mk
87

98
CC_NAME ?= fpc-secret-keeper-go
9+
10+
# Define paths for cmd subdirectories
11+
DEFAULT= cmd/naive/main.go
12+
SKVS_PATH = cmd/skvs/main.go
13+
14+
ECC_MAIN_FILES ?=$(DEFAULT)
15+
16+
include $(TOP)/ecc_go/build.mk
File renamed without changes.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
Copyright 2020 Intel Corporation
4+
5+
SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
package main
9+
10+
import (
11+
"os"
12+
13+
"github.com/hyperledger/fabric-chaincode-go/shim"
14+
"github.com/hyperledger/fabric-contract-api-go/contractapi"
15+
fpc "github.com/hyperledger/fabric-private-chaincode/ecc_go/chaincode"
16+
"github.com/hyperledger/fabric-private-chaincode/samples/chaincode/secret-keeper-go/chaincode"
17+
)
18+
19+
func main() {
20+
21+
ccid := os.Getenv("CHAINCODE_PKG_ID")
22+
addr := os.Getenv("CHAINCODE_SERVER_ADDRESS")
23+
24+
// create chaincode
25+
secretChaincode, _ := contractapi.NewChaincode(&chaincode.SecretKeeper{})
26+
skvsChaincode := fpc.NewPrivateChaincode(secretChaincode, fpc.WithSKVS())
27+
28+
// start chaincode as a service
29+
server := &shim.ChaincodeServer{
30+
CCID: ccid,
31+
Address: addr,
32+
CC: skvsChaincode,
33+
TLSProps: shim.TLSProperties{
34+
Disabled: true, // just for testing good enough
35+
},
36+
}
37+
38+
if err := server.Start(); err != nil {
39+
panic(err)
40+
}
41+
}

0 commit comments

Comments
 (0)