-
Notifications
You must be signed in to change notification settings - Fork 47
/
Copy pathmain.rs
355 lines (316 loc) · 11.1 KB
/
main.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
/*
Copyright 2019 Supercomputing Systems AG
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#[macro_use]
extern crate clap;
extern crate env_logger;
extern crate log;
extern crate my_node_runtime;
extern crate nan_preserving_float;
extern crate node_primitives;
extern crate parity_codec;
extern crate primitive_types;
extern crate primitives;
extern crate rust_base58;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate sgx_crypto_helper;
extern crate sgx_types;
extern crate sgx_ucrypto as crypto;
extern crate sgx_urts;
extern crate substrate_api_client;
extern crate substratee_node_calls;
extern crate substratee_worker_api;
extern crate substrate_keyring;
extern crate system;
extern crate wabt;
extern crate ws;
extern crate cid;
extern crate futures;
extern crate hyper;
extern crate ipfs_api;
extern crate multihash;
extern crate sha2;
use clap::App;
use constants::*;
use enclave_api::{perform_ra};
use enclave_wrappers::*;
use init_enclave::init_enclave;
use log::*;
use my_node_runtime::{Event, Hash};
use my_node_runtime::UncheckedExtrinsic;
use parity_codec::Decode;
use parity_codec::Encode;
use primitive_types::U256;
use sgx_types::*;
use std::fs;
use std::str;
use std::sync::mpsc::channel;
use std::thread;
use substrate_api_client::{Api, hexstr_to_vec};
use utils::{check_files, get_first_worker_that_is_not_equal_to_self};
use wasm::sgx_enclave_wasm_init;
use ws_server::start_ws_server;
use enclave_tls_ra::{Mode, run_enclave_server, run_enclave_client};
use substratee_node_calls::get_worker_amount;
use substratee_worker_api::Api as WorkerApi;
mod utils;
mod constants;
mod enclave_api;
mod init_enclave;
mod ws_server;
mod enclave_wrappers;
mod enclave_tls_ra;
mod wasm;
mod attestation_ocalls;
mod ipfs;
mod tests;
fn main() {
// Setup logging
env_logger::init();
let yml = load_yaml!("cli.yml");
let matches = App::from_yaml(yml).get_matches();
let node_ip = matches.value_of("node-server").unwrap_or("127.0.0.1");
let node_port = matches.value_of("node-port").unwrap_or("9944");
let n_url = format!("{}:{}", node_ip, node_port);
info!("Interacting with node on {}", n_url);
let w_ip = matches.value_of("w-server").unwrap_or("127.0.0.1");
let w_port = matches.value_of("w-port").unwrap_or("2000");
info!("Worker listening on {}:{}", w_ip, w_port);
let mu_ra_port = matches.value_of("mu-ra-port").unwrap_or("3443");
info!("MU-RA server on port {}", mu_ra_port);
if let Some(_matches) = matches.subcommand_matches("worker") {
println!("*** Starting substraTEE-worker\n");
worker(&n_url, w_ip, w_port, mu_ra_port);
} else if matches.is_present("getpublickey") {
println!("*** Get the public key from the TEE\n");
get_public_key_tee();
} else if matches.is_present("getsignkey") {
println!("*** Get the signing key from the TEE\n");
get_signing_key_tee();
} else if matches.is_present("run_server") {
println!("*** Running Enclave TLS server\n");
enclave_tls_ra::run(Mode::Server, mu_ra_port);
} else if matches.is_present("run_client") {
println!("*** Running Enclave TLS client\n");
enclave_tls_ra::run(Mode::Client, mu_ra_port);
} else if let Some(m) = matches.subcommand_matches("test_enclave") {
tests::run_enclave_tests(m, node_port);
} else {
println!("For options: use --help");
}
}
fn worker(node_url: &str, w_ip: &str, w_port: &str, mu_ra_port: &str) {
let mut status = sgx_status_t::SGX_SUCCESS;
// ------------------------------------------------------------------------
// check for required files
let missing_files = check_files();
match missing_files {
0 => {
debug!("All files found\n");
},
1 => {
error!("Stopping as 1 required file is missing\n");
return;
},
_ => {
error!("Stopping as {} required files are missing\n", missing_files);
return;
}
};
// ------------------------------------------------------------------------
// initialize the enclave
println!("*** Starting enclave");
let enclave = match init_enclave() {
Ok(r) => {
println!("[+] Init Enclave Successful. EID = {}!\n", r.geteid());
r
},
Err(x) => {
error!("[-] Init Enclave Failed {}!\n", x);
return;
},
};
// ------------------------------------------------------------------------
// initialize the sgxwasm specific driver engine
let result = sgx_enclave_wasm_init(enclave.geteid());
match result {
Ok(_r) => {
println!("[+] Init Wasm in enclave successful\n");
},
Err(x) => {
error!("[-] Init Wasm in enclave failed {}!\n", x.as_str());
return;
},
}
// ------------------------------------------------------------------------
// start the ws server to listen for worker requests
let w_url = format!("{}:{}", w_ip, w_port);
start_ws_server(enclave.geteid(), w_url.clone(), mu_ra_port.to_string());
// ------------------------------------------------------------------------
let eid = enclave.geteid();
let ra_url = format!("{}:{}", w_ip, mu_ra_port);
thread::spawn(move || {
run_enclave_server(eid, sgx_quote_sign_type_t::SGX_UNLINKABLE_SIGNATURE, &ra_url)
});
// ------------------------------------------------------------------------
// start the substrate-api-client to communicate with the node
let mut api = Api::new(format!("ws://{}", node_url));
api.init();
// ------------------------------------------------------------------------
// get required fields for the extrinsic
let genesis_hash = api.genesis_hash.unwrap().as_bytes().to_vec();
// get the public signing key of the TEE
let mut key = [0; 32];
let ecc_key = fs::read(ECC_PUB_KEY).expect("Unable to open ECC public key file");
key.copy_from_slice(&ecc_key[..]);
info!("[+] Got ECC public key of TEE = {:?}", key);
// get enclaves's account nonce
let nonce = get_account_nonce(&api, key);
let nonce_bytes = U256::encode(&nonce);
info!("Enclave nonce = {:?}", nonce);
// prepare the unchecked extrinsic
// the size is determined in the enclave
let unchecked_extrinsic_size = 5000;
let mut unchecked_extrinsic : Vec<u8> = vec![0u8; unchecked_extrinsic_size as usize];
// ------------------------------------------------------------------------
// perform a remote attestation and get an unchecked extrinsic back
println!("*** Perform a remote attestation of the enclave");
let result = unsafe {
perform_ra(
enclave.geteid(),
&mut status,
genesis_hash.as_ptr(),
genesis_hash.len() as u32,
nonce_bytes.as_ptr(),
nonce_bytes.len() as u32,
w_url.as_ptr(),
w_url.len() as u32,
unchecked_extrinsic.as_mut_ptr(),
unchecked_extrinsic_size as u32
)
};
if result != sgx_status_t::SGX_SUCCESS || status != sgx_status_t::SGX_SUCCESS {
println!("[-] Remote attestation of the enclave failed.\n");
return;
}
println!();
println!("[+] Remote attestation of the enclave successful\n");
// hex encode the extrinsic
let ue = UncheckedExtrinsic::decode(&mut unchecked_extrinsic.as_slice()).unwrap();
let mut _xthex = hex::encode(ue.encode());
_xthex.insert_str(0, "0x");
// send the extrinsic and wait for confirmation
println!("[>] Register the enclave (send the extrinsic)");
let tx_hash = api.send_extrinsic(_xthex).unwrap();
println!("[<] Extrinsic got finalized. Hash: {:?}\n", tx_hash);
match get_worker_amount(&api) {
0 => {
error!("No worker in registry after registering!");
return;
},
1 => {
info!("one worker registered, should be me");
},
_ => {
println!("*** There are already workers registered, fetching keys from first one...");
let w1 = get_first_worker_that_is_not_equal_to_self(&api, ecc_key).unwrap();
let w_api = WorkerApi::new(w1.url.clone());
let ra_port = w_api.get_mu_ra_port().unwrap();
info!("Got Port for MU-RA from other worker: {}", ra_port);
info!("Performing MU-RA");
let w1_url_port: Vec<&str> = w1.url.split(':').collect();
run_enclave_client(enclave.geteid(), sgx_quote_sign_type_t::SGX_UNLINKABLE_SIGNATURE, &format!("{}:{}", w1_url_port[0], ra_port));
println!();
println!("[+] MU-RA successfully performed.\n");
},
};
// ------------------------------------------------------------------------
// subscribe to events and react on firing
println!("*** Subscribing to events");
let (events_in, events_out) = channel();
let _eventsubscriber = thread::Builder::new()
.name("eventsubscriber".to_owned())
.spawn(move || {
api.subscribe_events(events_in.clone());
})
.unwrap();
println!("[+] Subscribed, waiting for event...");
println!();
loop {
let event_str = events_out.recv().unwrap();
let _unhex = hexstr_to_vec(event_str);
let mut _er_enc = _unhex.as_slice();
let _events = Vec::<system::EventRecord::<Event, Hash>>::decode(&mut _er_enc);
match _events {
Some(evts) => {
for evr in &evts {
debug!("Decoded: phase = {:?}, event = {:?}", evr.phase, evr.event);
match &evr.event {
Event::balances(be) => {
println!("[+] Received balances event");
debug!("{:?}", be);
match &be {
balances::RawEvent::Transfer(transactor, dest, value, fee) => {
println!(" Transactor: {:?}", transactor);
println!(" Destination: {:?}", dest);
println!(" Value: {:?}", value);
println!(" Fee: {:?}", fee);
println!();
},
_ => {
info!("Ignoring unsupported balances event");
},
}
},
Event::substratee_registry(re) => {
println!("[+] Received substratee_registry event");
debug!("{:?}", re);
match &re {
my_node_runtime::substratee_registry::RawEvent::AddedEnclave(sender, worker_url) => {
println!("[+] Received AddedEnclave event");
println!(" Sender (Worker): {:?}", sender);
println!(" Registered URL: {:?}", str::from_utf8(worker_url).unwrap());
println!();
},
my_node_runtime::substratee_registry::RawEvent::Forwarded(sender, payload) => {
println!("[+] Received Forwarded event");
debug!(" From: {:?}", sender);
debug!(" Payload: {:?}", hex::encode(payload));
println!();
// process the payload and send extrinsic
process_forwarded_payload(enclave.geteid(), payload.to_vec(), &mut status, node_url);
},
my_node_runtime::substratee_registry::RawEvent::CallConfirmed(sender, payload) => {
println!("[+] Received CallConfirmed event");
debug!(" From: {:?}", sender);
debug!(" Payload: {:?}", hex::encode(payload));
println!();
},
_ => {
info!("Ignoring unsupported substratee_registry event");
},
}
},
_ => {
debug!("event = {:?}", evr);
info!("Ignoring event\n");
},
}
}
}
None => error!("Couldn't decode event record list")
}
}
}