-
Notifications
You must be signed in to change notification settings - Fork 90
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- initial go sdk extension for FPC that hides the FPC transaction flow from the user - integrate with test-network - CreateEnclave requires target peer endpoint - FPC invocations are invoked (queried) at a defined endpoint - Update go sdk version and address review Signed-off-by: bur <[email protected]> Co-authored-by: Michael Steiner <[email protected]>
- Loading branch information
1 parent
fdccf21
commit f95c5e5
Showing
10 changed files
with
624 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# FPC Go SDK | ||
|
||
we build on top of the new gateway API of the Fabric Go SDK | ||
|
||
|
||
Ensure you use the at least the following go sdk version or newer. | ||
```go | ||
go get -u github.com/hyperledger/fabric-sdk-go@2f93a3201bb40cf30b7c73dd402511ed788cceca | ||
``` | ||
|
||
## Testing |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package attestation | ||
|
||
import ( | ||
"log" | ||
|
||
"github.com/hyperledger-labs/fabric-private-chaincode/internal/protos" | ||
) | ||
|
||
func ToEvidence(credentials *protos.Credentials) (*protos.Credentials, error) { | ||
|
||
// do something | ||
log.Printf("Perform attestation to evidence transformation\n") | ||
|
||
// TODO call brunos attestation_to_evidence.sh | ||
// call $FPC_PATH/common/crypto/attestation-api/conversion/attestation_to_evidence.sh | ||
|
||
//credentials.Evidence = credentials.Attestation | ||
|
||
return credentials, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
/* | ||
Copyright 2020 IBM All Rights Reserved. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package fpc | ||
|
||
import ( | ||
"encoding/base64" | ||
"encoding/json" | ||
"log" | ||
|
||
"github.com/hyperledger-labs/fabric-private-chaincode/internal/utils" | ||
"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" | ||
"github.com/hyperledger/fabric-sdk-go/pkg/gateway" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
type ContractInterface interface { | ||
ManagementInterface | ||
Name() string | ||
EvaluateTransaction(name string, args ...string) ([]byte, error) | ||
SubmitTransaction(name string, args ...string) ([]byte, error) | ||
//CreateTransaction(name string, opts ...gateway.TransactionOption) (*gateway.Transaction, error) | ||
RegisterEvent(eventFilter string) (fab.Registration, <-chan *fab.CCEvent, error) | ||
Unregister(registration fab.Registration) | ||
} | ||
|
||
func GetContract(network *gateway.Network, chaincodeId string) ContractInterface { | ||
contract := network.GetContract(chaincodeId) | ||
ercc := network.GetContract("ercc") | ||
return &Contract{contract, ercc, nil, nil} | ||
} | ||
|
||
type Contract struct { | ||
contract *gateway.Contract | ||
ercc *gateway.Contract | ||
cachedChaincodeEncryptionKey []byte | ||
enclavePeers []string | ||
} | ||
|
||
func (c *Contract) Name() string { | ||
return c.contract.Name() | ||
} | ||
|
||
func (c *Contract) getChaincodeEncryptionKey() ([]byte, error) { | ||
if c.cachedChaincodeEncryptionKey == nil { | ||
ccKeyBytes, err := c.ercc.EvaluateTransaction("queryChaincodeEncryptionKey", c.Name()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
c.cachedChaincodeEncryptionKey = ccKeyBytes | ||
} | ||
return c.cachedChaincodeEncryptionKey, nil | ||
} | ||
|
||
func (c *Contract) getEnclavePeers() ([]string, error) { | ||
if c.enclavePeers == nil { | ||
// TODO: implement me to support multi-peer scenarios (currently createEnclave also populates c.enclavePeers ... | ||
} | ||
return c.enclavePeers, nil | ||
} | ||
|
||
// TODO better move to TX. crypto lib?! TBD | ||
func (c *Contract) prepareChaincodeInvocation(name string, args []string, resultEncryptionKey []byte) (string, error) { | ||
p := &utils.ChaincodeParams{ | ||
Function: name, | ||
Args: args, | ||
ResultEncryptionKey: resultEncryptionKey, | ||
} | ||
|
||
pBytes, err := json.Marshal(p) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
log.Printf("prepping chaincode params: %s\n", p) | ||
|
||
k, err := c.getChaincodeEncryptionKey() | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
encryptedParams, err := Encrypt(pBytes, k) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return base64.StdEncoding.EncodeToString(encryptedParams), nil | ||
} | ||
|
||
func (c *Contract) EvaluateTransaction(name string, args ...string) ([]byte, error) { | ||
|
||
// pick response encryption key | ||
resultEncryptionKey, err := KeyGen() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
encryptedParamsBase64, err := c.prepareChaincodeInvocation(name, args, resultEncryptionKey) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// note that WithEndorsingPeers is only used with txn.Submit!!! | ||
// GO SDK needs to be patched! We should create a PR for that! | ||
txn, err := c.contract.CreateTransaction( | ||
"__invoke", | ||
gateway.WithEndorsingPeers(c.enclavePeers...), | ||
) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
log.Printf("calling __invoke!\n") | ||
responseBytes, err := txn.Evaluate(encryptedParamsBase64) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// TODO maybe move this to a sub-function like prepareChaincodeInvocation?! TBD | ||
response, err := utils.UnmarshalResponse(responseBytes) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// decrypt result | ||
return Decrypt(response.ResponseData, resultEncryptionKey) | ||
} | ||
|
||
func (c *Contract) SubmitTransaction(name string, args ...string) ([]byte, error) { | ||
|
||
// pick response encryption key | ||
resultEncryptionKey, err := KeyGen() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
encryptedParamsBase64, err := c.prepareChaincodeInvocation(name, args, resultEncryptionKey) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
txn, err := c.contract.CreateTransaction( | ||
"__invoke", | ||
gateway.WithEndorsingPeers(c.enclavePeers...), | ||
) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
log.Printf("calling __invoke!\n") | ||
//responseBytes, err := c.contract.EvaluateTransaction("__invoke", encryptedParamsBase64) | ||
responseBytes, err := txn.Evaluate(encryptedParamsBase64) | ||
|
||
// first invoke (query) fpc chaincode | ||
//responseBytes, err := c.contract.EvaluateTransaction("__invoke", encryptedParamsBase64) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "evaluation transaction failed") | ||
} | ||
|
||
log.Printf("calling __endorse!\n") | ||
// next invoke chaincode endorsement | ||
_, err = c.contract.SubmitTransaction("__endorse", base64.StdEncoding.EncodeToString(responseBytes)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
response, err := utils.UnmarshalResponse(responseBytes) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return Decrypt(response.ResponseData, resultEncryptionKey) | ||
} | ||
|
||
//func (c *Contract) CreateTransaction(name string, opts ...gateway.TransactionOption) (*gateway.Transaction, error) { | ||
// return c.CreateTransaction(name, opts...) | ||
//} | ||
|
||
func (c *Contract) RegisterEvent(eventFilter string) (fab.Registration, <-chan *fab.CCEvent, error) { | ||
return c.contract.RegisterEvent(eventFilter) | ||
} | ||
|
||
func (c *Contract) Unregister(registration fab.Registration) { | ||
c.contract.Unregister(registration) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package fpc | ||
|
||
func Encrypt(input []byte, encryptionKey []byte) ([]byte, error) { | ||
return input, nil | ||
} | ||
|
||
func KeyGen() ([]byte, error) { | ||
return []byte("fake key"), nil | ||
} | ||
|
||
func Decrypt(encryptedResponse []byte, resultEncryptionKey []byte) ([]byte, error) { | ||
return encryptedResponse, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package fpc | ||
|
||
import ( | ||
"encoding/base64" | ||
"encoding/json" | ||
"fmt" | ||
"log" | ||
|
||
"github.com/hyperledger-labs/fabric-private-chaincode/client_sdk/go/fpc/attestation" | ||
"github.com/hyperledger-labs/fabric-private-chaincode/internal/utils" | ||
|
||
"github.com/golang/protobuf/proto" | ||
"github.com/hyperledger-labs/fabric-private-chaincode/internal/protos" | ||
"github.com/hyperledger/fabric-sdk-go/pkg/gateway" | ||
"github.com/hyperledger/fabric/protoutil" | ||
) | ||
|
||
type ManagementInterface interface { | ||
CreateEnclave(peer string, attestationParams ...string) error | ||
} | ||
|
||
type ManagementAPI struct { | ||
network *gateway.Network | ||
} | ||
|
||
func (c *Contract) CreateEnclave(peer string, attestationParams ...string) error { | ||
|
||
p, err := json.Marshal(&utils.AttestationParams{Params: attestationParams}) | ||
attestationParamsBase64 := base64.StdEncoding.EncodeToString(p) | ||
log.Printf("Prep attestation params: %s\n", attestationParamsBase64) | ||
|
||
txn, err := c.contract.CreateTransaction( | ||
"__initEnclave", | ||
gateway.WithEndorsingPeers(peer), | ||
) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
credentialsBytes, err := txn.Evaluate(attestationParamsBase64) | ||
if err != nil { | ||
return fmt.Errorf("evaluation error: %s", err) | ||
} | ||
|
||
credentials := &protos.Credentials{} | ||
err = proto.Unmarshal(credentialsBytes, credentials) | ||
if err != nil { | ||
return fmt.Errorf("cannot unmarshal credentials: %s", err) | ||
} | ||
log.Printf("Received credentials from enclave: %s\n", credentials) | ||
|
||
// perform attestation evidence transformation | ||
credentials, err = attestation.ToEvidence(credentials) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
credentialsBytes = protoutil.MarshalOrPanic(credentials) | ||
credentialsBase64 := base64.StdEncoding.EncodeToString(credentialsBytes) | ||
|
||
log.Printf("Call registerEnclave at ERCC: %s\n", attestationParamsBase64) | ||
_, err = c.ercc.SubmitTransaction("registerEnclave", credentialsBase64) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
c.enclavePeers = append(c.enclavePeers, peer) | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Copyright 2019 Intel Corporation | ||
# Copyright IBM Corp. All Rights Reserved. | ||
# | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
TOP = ../../.. | ||
include $(TOP)/build.mk | ||
|
||
build: | ||
$(GO) build | ||
|
||
test: | ||
$(GO) test $(GOTAGS) -v ./... | ||
|
||
clean: | ||
$(GO) clean | ||
rm -rf keystore wallet | ||
|
||
run: | ||
$(GO) run . |
Oops, something went wrong.