7
7
package main
8
8
9
9
import (
10
+ "bufio"
11
+ "encoding/json"
10
12
"fmt"
11
13
"io/ioutil"
12
14
"os"
15
+ "strings"
13
16
14
17
"github.com/hyperledger-labs/fabric-private-chaincode/client_sdk/go/fpc"
18
+ "github.com/hyperledger-labs/fabric-private-chaincode/client_sdk/go/fpc/crypto"
19
+ "github.com/hyperledger/fabric/common/flogging"
15
20
)
16
21
22
+ var logger = flogging .MustGetLogger ("peer-cli-assist" )
23
+
17
24
func printHelp () {
18
25
fmt .Printf (
19
- `Usage: %s [attestation2Evidence | createEncryptRequest | processEncryptedResponse ]
26
+ `Usage: %s [attestation2Evidence | handleRequestAndResponse <cid> <pipe> ]
20
27
- attestation2Evidence: convert attestation to evidence in (base64-encoded) Credentials protobuf
21
- - createEncryptRequest: create a (base64-encoded) encrypted fpc chaincode request protobuf
22
- - processEncryptedResponse: decrypt and validate an (base64-encoded) encrypted fpc chaincode response protobuf
23
- Input and outpus are via stdin and stdout, respectively.` ,
28
+ (Input and outpus are via stdin and stdout, respectively.)
29
+ - handleRequestAndResponse: handles the encryption of invocation requests as well as the decryption
30
+ of the corresponding responses.
31
+ Expects three parameters
32
+ - <c_ek> the chaincode encryption key, as returned from ercc.QueryChaincodeEncryptionKey
33
+ (i.e., a base64-encoded string)
34
+ - <pipe> a path to an (existing) fifo file through which the results are communicated back
35
+ As input, expects two lines
36
+ - a (single line!) json string in peer cli format '{"Function": "...", "Args": [...]}' with the invocation params,
37
+ after which it returns (as single line) the (base64-encoded) ChaincodeRequestMessage protobuf, and then
38
+ - a (base64-encoded) ChaincodeResponseMessage protobuf, after which it will decrypt it and
39
+ return a json-encoded fabric response protobuf object
40
+ ` ,
24
41
os .Args [0 ])
42
+ // TODO: above we have to fix the response payload format (json?)
25
43
}
26
44
27
45
func main () {
@@ -45,12 +63,13 @@ func main() {
45
63
os .Exit (1 )
46
64
}
47
65
fmt .Printf ("%s\n " , credentialsStringOut )
48
- case "createEncryptRequest" :
49
- fmt .Fprintf (os .Stderr , "FATAL: command %s not yet implemented\n " , os .Args [1 ])
50
- os .Exit (1 )
51
- case "processEncryptedResponse" :
52
- fmt .Fprintf (os .Stderr , "FATAL: command %s not yet implemented\n " , os .Args [1 ])
53
- os .Exit (1 )
66
+ case "handleRequestAndResponse" :
67
+ if len (os .Args ) != 4 {
68
+ fmt .Fprintf (os .Stderr , "ERROR: command 'handleRequestAndResponse' needs exactly two arguments\n " )
69
+ printHelp ()
70
+ os .Exit (1 )
71
+ }
72
+ handleEncryptedRequestAndResponse (os .Args [2 ], os .Args [3 ])
54
73
default :
55
74
fmt .Fprintf (os .Stderr , "ERROR: Illegal command '%s'\n " , os .Args [1 ])
56
75
printHelp ()
@@ -59,3 +78,74 @@ func main() {
59
78
60
79
os .Exit (0 )
61
80
}
81
+
82
+ func handleEncryptedRequestAndResponse (chaincodeEncryptionKey string , resultPipeName string ) {
83
+ reader := bufio .NewReader (os .Stdin )
84
+ resultPipeFile , err := os .OpenFile (resultPipeName , os .O_APPEND | os .O_WRONLY , 0644 )
85
+ if err != nil {
86
+ fmt .Fprintf (os .Stderr , "ERROR: couldn't open pipe '%s': %v\n " , resultPipeName , err )
87
+ os .Exit (1 )
88
+ }
89
+
90
+ // read request
91
+ requestJSON , err := reader .ReadString ('\n' )
92
+ if err != nil {
93
+ fmt .Fprintf (os .Stderr , "ERROR: couldn't read json request: %v\n " , err )
94
+ os .Exit (1 )
95
+ }
96
+ type Request struct {
97
+ Function string
98
+ Args []string
99
+ }
100
+ clearRequest := & Request {}
101
+ if err := json .Unmarshal ([]byte (requestJSON ), clearRequest ); err != nil {
102
+ fmt .Fprintf (os .Stderr , "ERROR: unexpected json '%s': %v\n " , requestJSON , err )
103
+ os .Exit (1 )
104
+ }
105
+
106
+ // setup crypto context
107
+ ep := & crypto.EncryptionProviderImpl {
108
+ GetCcEncryptionKey : func () ([]byte , error ) {
109
+ // TODO: might have to do some re-formatting, e.g., de-hex, here?
110
+ return []byte (chaincodeEncryptionKey ), nil
111
+ }}
112
+
113
+ ctx , err := ep .NewEncryptionContext ()
114
+ if err != nil {
115
+ fmt .Fprintf (os .Stderr , "ERROR: could not setup crypto context: %v\n " , err )
116
+ os .Exit (1 )
117
+ }
118
+ logger .Debugf ("Setup crypto context based on CC-ek '%v'" , chaincodeEncryptionKey )
119
+
120
+ // encrypt request ...
121
+ encryptedRequest , err := ctx .Conceal (clearRequest .Function , clearRequest .Args )
122
+ if err != nil {
123
+ fmt .Fprintf (os .Stderr , "ERROR: could not encrypt request: %v\n " , err )
124
+ os .Exit (1 )
125
+ }
126
+ // ... and return it
127
+ logger .Debugf ("Transformed request '%v' to '%v' and write to pipe '%s'" , clearRequest , encryptedRequest , resultPipeName )
128
+ resultPipeFile .WriteString (fmt .Sprintf ("%s\n " , encryptedRequest ))
129
+
130
+ // read encrypted response ...
131
+ encryptedResponse , err := reader .ReadString ('\n' )
132
+ if err != nil {
133
+ fmt .Fprintf (os .Stderr , "ERROR: couldn't read encrypted response: %v\n " , err )
134
+ os .Exit (1 )
135
+ }
136
+ encryptedResponse = strings .TrimSuffix (encryptedResponse , "\n " )
137
+
138
+ // .. decrypt it ..
139
+ // TODO: requires fix in Conceal & ecc/mock
140
+ // - should be base64 encoded
141
+ // - encrypted response should be a proper (serialized) response object, not only a string, and hence conceal should
142
+ // return the deserialized response, not a byte array ..
143
+ clearResponse , err := ctx .Reveal ([]byte (encryptedResponse ))
144
+ if err != nil {
145
+ fmt .Fprintf (os .Stderr , "ERROR: could not decrypt response: %v\n " , err )
146
+ os .Exit (1 )
147
+ }
148
+ // TODO: create a (single-line) json encoding once we get above a proper response object ...
149
+ logger .Debugf ("Transformed response '%v' to '%v' and write to pipe '%s'" , encryptedResponse , clearResponse , resultPipeName )
150
+ resultPipeFile .WriteString (fmt .Sprintf ("%s\n " , clearResponse ))
151
+ }
0 commit comments