comms.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  1. #include <vector>
  2. #include <functional>
  3. #include <cstring>
  4. #include <pthread.h>
  5. #include "sgx_tcrypto.h"
  6. #include "sgx_tseal.h"
  7. #include "Enclave_t.h"
  8. #include "utils.hpp"
  9. #include "config.hpp"
  10. #include "comms.hpp"
  11. // Our public and private identity keys
  12. static sgx_ec256_private_t g_privkey;
  13. static sgx_ec256_public_t g_pubkey;
  14. // The communication states for all the nodes. There's an entry for
  15. // ourselves in here, but it is unused.
  16. std::vector<NodeCommState> commstates;
  17. static nodenum_t tot_nodes, my_node_num;
  18. static class CompletedHandshakeCounter {
  19. // Mutex around completed_handshakes
  20. pthread_mutex_t mutex;
  21. // The number of completed handshakes
  22. nodenum_t completed_handshakes;
  23. // The callback pointer to use when all handshakes complete
  24. void *complete_handshake_cbpointer;
  25. public:
  26. CompletedHandshakeCounter() {
  27. pthread_mutex_init(&mutex, NULL);
  28. completed_handshakes = 0;
  29. complete_handshake_cbpointer = NULL;
  30. }
  31. void reset(void *cbpointer) {
  32. pthread_mutex_lock(&mutex);
  33. completed_handshakes = 0;
  34. complete_handshake_cbpointer = cbpointer;
  35. pthread_mutex_unlock(&mutex);
  36. }
  37. void inc() {
  38. pthread_mutex_lock(&mutex);
  39. ++completed_handshakes;
  40. nodenum_t num_completed = completed_handshakes;
  41. pthread_mutex_unlock(&mutex);
  42. if (num_completed == tot_nodes - 1) {
  43. pthread_mutex_lock(&mutex);
  44. void *cbpointer = complete_handshake_cbpointer;
  45. complete_handshake_cbpointer = NULL;
  46. completed_handshakes = 0;
  47. pthread_mutex_unlock(&mutex);
  48. ocall_comms_ready(cbpointer);
  49. }
  50. }
  51. } completed_handshake_counter;
  52. // A typical default in_msg_get_buf handler. It computes the maximum
  53. // possible size of the decrypted data, allocates that much memory, and
  54. // returns a pointer to it.
  55. static uint8_t* default_in_msg_get_buf(NodeCommState &commst,
  56. uint32_t tot_enc_chunk_size)
  57. {
  58. uint32_t max_plaintext_bytes = tot_enc_chunk_size;
  59. // If the handshake is complete, chunks will be encrypted and have a
  60. // MAC tag attached which will not correspond to plaintext bytes, so
  61. // we can trim them.
  62. if (commst.handshake_step == HANDSHAKE_COMPLETE) {
  63. // The minimum number of chunks needed to transmit this message
  64. uint32_t min_num_chunks =
  65. (tot_enc_chunk_size + (FRAME_SIZE-1)) / FRAME_SIZE;
  66. // The maximum number of plaintext bytes this message could contain
  67. max_plaintext_bytes = tot_enc_chunk_size -
  68. SGX_AESGCM_MAC_SIZE * min_num_chunks;
  69. }
  70. return new uint8_t[max_plaintext_bytes];
  71. }
  72. static void default_in_msg_received(NodeCommState &nodest,
  73. uint8_t *data, uint32_t plaintext_len, uint32_t)
  74. {
  75. printf("Received message of %u bytes from node %lu:\n",
  76. plaintext_len, nodest.node_num);
  77. for (uint32_t i=0;i<plaintext_len;++i) {
  78. printf("%02x", data[i]);
  79. }
  80. printf("\n");
  81. delete[] data;
  82. }
  83. static void handshake_1_msg_received(NodeCommState &nodest,
  84. uint8_t *data, uint32_t plaintext_len, uint32_t);
  85. static void handshake_2_msg_received(NodeCommState &nodest,
  86. uint8_t *data, uint32_t plaintext_len, uint32_t);
  87. static void handshake_3_msg_received(NodeCommState &nodest,
  88. uint8_t *data, uint32_t plaintext_len, uint32_t);
  89. // Receive (at the server) the first handshake message
  90. static void handshake_1_msg_received(NodeCommState &nodest,
  91. uint8_t *data, uint32_t plaintext_len, uint32_t)
  92. {
  93. /*
  94. printf("Received handshake_1 message of %u bytes:\n", plaintext_len);
  95. for (uint32_t i=0;i<plaintext_len;++i) {
  96. printf("%02x", data[i]);
  97. }
  98. printf("\n");
  99. */
  100. if (plaintext_len != sizeof(sgx_ec256_public_t)) {
  101. printf("Received handshake_1 message of incorrect size %u\n",
  102. plaintext_len);
  103. return;
  104. }
  105. sgx_ecc_state_handle_t ecc_handle;
  106. sgx_ec256_public_t peer_dh_pubkey;
  107. memmove(&peer_dh_pubkey, data, sizeof(peer_dh_pubkey));
  108. delete[] data;
  109. sgx_ecc256_open_context(&ecc_handle);
  110. int valid;
  111. if (sgx_ecc256_check_point(&peer_dh_pubkey, ecc_handle, &valid)
  112. || !valid) {
  113. printf("Invalid public key received from node %hu\n",
  114. nodest.node_num);
  115. sgx_ecc256_close_context(ecc_handle);
  116. return;
  117. }
  118. printf("Valid public key received from node %hu\n", nodest.node_num);
  119. // Create our own DH key pair
  120. sgx_ec256_public_t our_dh_pubkey;
  121. sgx_ec256_private_t our_dh_privkey;
  122. sgx_ecc256_create_key_pair(&our_dh_privkey, &our_dh_pubkey, ecc_handle);
  123. // Construct the shared secret
  124. sgx_ec256_dh_shared_t sharedsecret;
  125. sgx_ecc256_compute_shared_dhkey(&our_dh_privkey, &peer_dh_pubkey,
  126. &sharedsecret, ecc_handle);
  127. memset(&our_dh_privkey, 0, sizeof(our_dh_privkey));
  128. // Compute H1(sharedsecret) and H2(sharedsecret)
  129. sgx_sha_state_handle_t sha_handle;
  130. sgx_sha256_hash_t h1, h2;
  131. sgx_sha256_init(&sha_handle);
  132. sgx_sha256_update((const uint8_t*)"\x01", 1, sha_handle);
  133. sgx_sha256_update((uint8_t*)&sharedsecret, sizeof(sharedsecret),
  134. sha_handle);
  135. sgx_sha256_get_hash(sha_handle, &h1);
  136. sgx_sha256_close(sha_handle);
  137. sgx_sha256_init(&sha_handle);
  138. sgx_sha256_update((const uint8_t*)"\x02", 1, sha_handle);
  139. sgx_sha256_update((uint8_t*)&sharedsecret, sizeof(sharedsecret),
  140. sha_handle);
  141. sgx_sha256_get_hash(sha_handle, &h2);
  142. sgx_sha256_close(sha_handle);
  143. // Compute the server-to-client MAC
  144. sgx_hmac_state_handle_t hmac_handle;
  145. uint8_t srv_cli_mac[16];
  146. sgx_hmac256_init(h1, 16, &hmac_handle);
  147. sgx_hmac256_update((uint8_t*)&our_dh_pubkey, sizeof(our_dh_pubkey),
  148. hmac_handle);
  149. sgx_hmac256_update((uint8_t*)&peer_dh_pubkey, sizeof(peer_dh_pubkey),
  150. hmac_handle);
  151. sgx_hmac256_update((uint8_t*)&g_pubkey, sizeof(g_pubkey),
  152. hmac_handle);
  153. sgx_hmac256_update((uint8_t*)&nodest.pubkey, sizeof(nodest.pubkey),
  154. hmac_handle);
  155. sgx_hmac256_final(srv_cli_mac, 16, hmac_handle);
  156. sgx_hmac256_close(hmac_handle);
  157. // Compute the client-to-server MAC
  158. uint8_t cli_srv_mac[16];
  159. sgx_hmac256_init(((uint8_t*)h1)+16, 16, &hmac_handle);
  160. sgx_hmac256_update((uint8_t*)&peer_dh_pubkey, sizeof(peer_dh_pubkey),
  161. hmac_handle);
  162. sgx_hmac256_update((uint8_t*)&our_dh_pubkey, sizeof(our_dh_pubkey),
  163. hmac_handle);
  164. sgx_hmac256_update((uint8_t*)&nodest.pubkey, sizeof(nodest.pubkey),
  165. hmac_handle);
  166. sgx_hmac256_update((uint8_t*)&g_pubkey, sizeof(g_pubkey),
  167. hmac_handle);
  168. sgx_hmac256_final(cli_srv_mac, 16, hmac_handle);
  169. sgx_hmac256_close(hmac_handle);
  170. // Sign the server-to-client MAC
  171. sgx_ec256_signature_t srv_cli_sig;
  172. sgx_ecdsa_sign(srv_cli_mac, 16, &g_privkey, &srv_cli_sig, ecc_handle);
  173. sgx_ecc256_close_context(ecc_handle);
  174. // Save the state we'll need to process handshake message 3
  175. memmove(&nodest.in_aes_key, h2, 16);
  176. memmove(&nodest.out_aes_key, ((uint8_t*)h2)+16, 16);
  177. memmove(&nodest.handshake_cli_srv_mac, cli_srv_mac, 16);
  178. // Get us ready to receive handshake message 3
  179. nodest.in_msg_get_buf = default_in_msg_get_buf;
  180. nodest.in_msg_received = handshake_3_msg_received;
  181. nodest.handshake_step = HANDSHAKE_S_SENT_2;
  182. // Send handshake message 2
  183. nodest.message_start(sizeof(our_dh_pubkey) + sizeof(srv_cli_sig),
  184. false);
  185. nodest.message_data((uint8_t*)&our_dh_pubkey, sizeof(our_dh_pubkey),
  186. false);
  187. nodest.message_data((uint8_t*)&srv_cli_sig, sizeof(srv_cli_sig),
  188. false);
  189. }
  190. // Receive (at the client) the secong handshake message
  191. static void handshake_2_msg_received(NodeCommState &nodest,
  192. uint8_t *data, uint32_t plaintext_len, uint32_t)
  193. {
  194. /*
  195. printf("Received handshake_2 message of %u bytes:\n", plaintext_len);
  196. for (uint32_t i=0;i<plaintext_len;++i) {
  197. printf("%02x", data[i]);
  198. }
  199. printf("\n");
  200. */
  201. if (plaintext_len != sizeof(sgx_ec256_public_t) +
  202. sizeof(sgx_ec256_signature_t)) {
  203. printf("Received handshake_2 message of incorrect size %u\n",
  204. plaintext_len);
  205. return;
  206. }
  207. sgx_ecc_state_handle_t ecc_handle;
  208. sgx_ec256_public_t peer_dh_pubkey;
  209. sgx_ec256_signature_t peer_sig;
  210. memmove(&peer_dh_pubkey, data, sizeof(peer_dh_pubkey));
  211. memmove(&peer_sig, data+sizeof(peer_dh_pubkey), sizeof(peer_sig));
  212. delete[] data;
  213. sgx_ecc256_open_context(&ecc_handle);
  214. int valid;
  215. if (sgx_ecc256_check_point(&peer_dh_pubkey, ecc_handle, &valid)
  216. || !valid) {
  217. printf("Invalid public key received from node %hu\n",
  218. nodest.node_num);
  219. sgx_ecc256_close_context(ecc_handle);
  220. return;
  221. }
  222. // Construct the shared secret
  223. sgx_ec256_dh_shared_t sharedsecret;
  224. sgx_ecc256_compute_shared_dhkey(&nodest.handshake_dh_privkey,
  225. &peer_dh_pubkey, &sharedsecret, ecc_handle);
  226. memset(&nodest.handshake_dh_privkey, 0,
  227. sizeof(nodest.handshake_dh_privkey));
  228. // Compute H1(sharedsecret) and H2(sharedsecret)
  229. sgx_sha_state_handle_t sha_handle;
  230. sgx_sha256_hash_t h1, h2;
  231. sgx_sha256_init(&sha_handle);
  232. sgx_sha256_update((const uint8_t*)"\x01", 1, sha_handle);
  233. sgx_sha256_update((uint8_t*)&sharedsecret, sizeof(sharedsecret),
  234. sha_handle);
  235. sgx_sha256_get_hash(sha_handle, &h1);
  236. sgx_sha256_close(sha_handle);
  237. sgx_sha256_init(&sha_handle);
  238. sgx_sha256_update((const uint8_t*)"\x02", 1, sha_handle);
  239. sgx_sha256_update((uint8_t*)&sharedsecret, sizeof(sharedsecret),
  240. sha_handle);
  241. sgx_sha256_get_hash(sha_handle, &h2);
  242. sgx_sha256_close(sha_handle);
  243. // Compute the server-to-client MAC
  244. sgx_hmac_state_handle_t hmac_handle;
  245. uint8_t srv_cli_mac[16];
  246. sgx_hmac256_init(h1, 16, &hmac_handle);
  247. sgx_hmac256_update((uint8_t*)&peer_dh_pubkey, sizeof(peer_dh_pubkey),
  248. hmac_handle);
  249. sgx_hmac256_update((uint8_t*)&nodest.handshake_dh_pubkey,
  250. sizeof(nodest.handshake_dh_pubkey), hmac_handle);
  251. sgx_hmac256_update((uint8_t*)&nodest.pubkey, sizeof(nodest.pubkey),
  252. hmac_handle);
  253. sgx_hmac256_update((uint8_t*)&g_pubkey, sizeof(g_pubkey),
  254. hmac_handle);
  255. sgx_hmac256_final(srv_cli_mac, 16, hmac_handle);
  256. sgx_hmac256_close(hmac_handle);
  257. // Compute the client-to-server MAC
  258. uint8_t cli_srv_mac[16];
  259. sgx_hmac256_init(((uint8_t*)h1)+16, 16, &hmac_handle);
  260. sgx_hmac256_update((uint8_t*)&nodest.handshake_dh_pubkey,
  261. sizeof(nodest.handshake_dh_pubkey), hmac_handle);
  262. sgx_hmac256_update((uint8_t*)&peer_dh_pubkey, sizeof(peer_dh_pubkey),
  263. hmac_handle);
  264. sgx_hmac256_update((uint8_t*)&g_pubkey, sizeof(g_pubkey),
  265. hmac_handle);
  266. sgx_hmac256_update((uint8_t*)&nodest.pubkey, sizeof(nodest.pubkey),
  267. hmac_handle);
  268. sgx_hmac256_final(cli_srv_mac, 16, hmac_handle);
  269. sgx_hmac256_close(hmac_handle);
  270. // Verify the signature on the server-to-client MAC
  271. uint8_t result;
  272. if (sgx_ecdsa_verify(srv_cli_mac, 16, &nodest.pubkey, &peer_sig,
  273. &result, ecc_handle) || result != SGX_EC_VALID) {
  274. printf("Invalid signature received from node %hu\n",
  275. nodest.node_num);
  276. sgx_ecc256_close_context(ecc_handle);
  277. return;
  278. }
  279. printf("Valid signature received from node %hu\n", nodest.node_num);
  280. // Sign the client-to-server MAC
  281. sgx_ec256_signature_t cli_srv_sig;
  282. sgx_ecdsa_sign(cli_srv_mac, 16, &g_privkey, &cli_srv_sig, ecc_handle);
  283. sgx_ecc256_close_context(ecc_handle);
  284. // Our side of the handshake is complete
  285. memmove(&nodest.out_aes_key, h2, 16);
  286. memmove(&nodest.in_aes_key, ((uint8_t*)h2)+16, 16);
  287. memset(&nodest.out_aes_iv, 0, SGX_AESGCM_IV_SIZE);
  288. memset(&nodest.in_aes_iv, 0, SGX_AESGCM_IV_SIZE);
  289. nodest.handshake_step = HANDSHAKE_COMPLETE;
  290. nodest.in_msg_get_buf = default_in_msg_get_buf;
  291. nodest.in_msg_received = default_in_msg_received;
  292. // Send handshake message 3
  293. nodest.message_start(sizeof(cli_srv_sig), false);
  294. nodest.message_data((uint8_t*)&cli_srv_sig, sizeof(cli_srv_sig),
  295. false);
  296. // Mark the handshake as complete
  297. completed_handshake_counter.inc();
  298. }
  299. static void handshake_3_msg_received(NodeCommState &nodest,
  300. uint8_t *data, uint32_t plaintext_len, uint32_t)
  301. {
  302. /*
  303. printf("Received handshake_3 message of %u bytes:\n", plaintext_len);
  304. for (uint32_t i=0;i<plaintext_len;++i) {
  305. printf("%02x", data[i]);
  306. }
  307. printf("\n");
  308. */
  309. if (plaintext_len != sizeof(sgx_ec256_signature_t)) {
  310. printf("Received handshake_3 message of incorrect size %u\n",
  311. plaintext_len);
  312. return;
  313. }
  314. sgx_ecc_state_handle_t ecc_handle;
  315. sgx_ec256_signature_t peer_sig;
  316. memmove(&peer_sig, data, sizeof(peer_sig));
  317. delete[] data;
  318. sgx_ecc256_open_context(&ecc_handle);
  319. // Verify the signature on the client-to-server MAC
  320. uint8_t result;
  321. if (sgx_ecdsa_verify(nodest.handshake_cli_srv_mac, 16,
  322. &nodest.pubkey, &peer_sig, &result, ecc_handle)
  323. || result != SGX_EC_VALID) {
  324. printf("Invalid signature received from node %hu\n",
  325. nodest.node_num);
  326. sgx_ecc256_close_context(ecc_handle);
  327. return;
  328. }
  329. printf("Valid signature received from node %hu\n", nodest.node_num);
  330. // Our side of the handshake is complete
  331. memset(&nodest.out_aes_iv, 0, SGX_AESGCM_IV_SIZE);
  332. memset(&nodest.in_aes_iv, 0, SGX_AESGCM_IV_SIZE);
  333. nodest.handshake_step = HANDSHAKE_COMPLETE;
  334. nodest.in_msg_get_buf = default_in_msg_get_buf;
  335. nodest.in_msg_received = default_in_msg_received;
  336. // Mark the handshake as complete
  337. completed_handshake_counter.inc();
  338. }
  339. // Start a new outgoing message. Pass the number of _plaintext_ bytes
  340. // the message will be.
  341. void NodeCommState::message_start(uint32_t plaintext_len, bool encrypt)
  342. {
  343. uint32_t ciphertext_len = plaintext_len;
  344. // If the handshake is complete, add SGX_AESGCM_MAC_SIZE bytes for
  345. // every FRAME_SIZE-SGX_AESGCM_MAC_SIZE bytes of plaintext.
  346. if (encrypt) {
  347. uint32_t num_chunks = (plaintext_len +
  348. FRAME_SIZE - SGX_AESGCM_MAC_SIZE - 1) /
  349. (FRAME_SIZE - SGX_AESGCM_MAC_SIZE);
  350. ciphertext_len = plaintext_len +
  351. num_chunks * SGX_AESGCM_MAC_SIZE;
  352. }
  353. ocall_message(&frame, node_num, ciphertext_len);
  354. frame_offset = 0;
  355. msg_size = ciphertext_len;
  356. msg_frame_offset = 0;
  357. msg_plaintext_size = plaintext_len;
  358. msg_plaintext_processed = 0;
  359. if (plaintext_len < FRAME_SIZE - SGX_AESGCM_MAC_SIZE) {
  360. msg_plaintext_chunk_remain = plaintext_len;
  361. } else {
  362. msg_plaintext_chunk_remain = FRAME_SIZE - SGX_AESGCM_MAC_SIZE;
  363. }
  364. if (!frame) {
  365. printf("Received NULL back from ocall_message\n");
  366. }
  367. if (msg_plaintext_chunk_remain > 0) {
  368. if (encrypt) {
  369. *(size_t*)out_aes_iv += 1;
  370. sgx_aes_gcm128_enc_init(out_aes_key, out_aes_iv,
  371. SGX_AESGCM_IV_SIZE, NULL, 0, &out_aes_gcm_state);
  372. }
  373. }
  374. }
  375. // Process len bytes of plaintext data into the current message.
  376. void NodeCommState::message_data(uint8_t *data, uint32_t len, bool encrypt)
  377. {
  378. while (len > 0) {
  379. if (msg_plaintext_chunk_remain == 0) {
  380. printf("Attempt to queue too much message data\n");
  381. return;
  382. }
  383. uint32_t bytes_to_process = len;
  384. if (bytes_to_process > msg_plaintext_chunk_remain) {
  385. bytes_to_process = msg_plaintext_chunk_remain;
  386. }
  387. if (frame == NULL) {
  388. printf("frame is NULL when queueing message data\n");
  389. return;
  390. }
  391. if (encrypt) {
  392. // Encrypt the data
  393. sgx_aes_gcm128_enc_update(data, bytes_to_process,
  394. frame+frame_offset, out_aes_gcm_state);
  395. } else {
  396. // Just copy the plaintext data during the handshake
  397. memmove(frame+frame_offset, data, bytes_to_process);
  398. }
  399. frame_offset += bytes_to_process;
  400. msg_plaintext_processed += bytes_to_process;
  401. msg_plaintext_chunk_remain -= bytes_to_process;
  402. len -= bytes_to_process;
  403. data += bytes_to_process;
  404. if (msg_plaintext_chunk_remain == 0) {
  405. // Complete and send this chunk
  406. if (encrypt) {
  407. sgx_aes_gcm128_enc_get_mac(frame+frame_offset,
  408. out_aes_gcm_state);
  409. frame_offset += SGX_AESGCM_MAC_SIZE;
  410. }
  411. uint8_t *nextframe = NULL;
  412. ocall_chunk(&nextframe, node_num, frame, frame_offset);
  413. frame = nextframe;
  414. msg_frame_offset += frame_offset;
  415. frame_offset = 0;
  416. msg_plaintext_chunk_remain =
  417. msg_plaintext_size - msg_plaintext_processed;
  418. if (msg_plaintext_chunk_remain >
  419. FRAME_SIZE - SGX_AESGCM_MAC_SIZE) {
  420. msg_plaintext_chunk_remain =
  421. FRAME_SIZE - SGX_AESGCM_MAC_SIZE;
  422. }
  423. if (encrypt) {
  424. sgx_aes_gcm_close(out_aes_gcm_state);
  425. if (msg_plaintext_chunk_remain > 0) {
  426. *(size_t*)out_aes_iv += 1;
  427. sgx_aes_gcm128_enc_init(out_aes_key, out_aes_iv,
  428. SGX_AESGCM_IV_SIZE, NULL, 0, &out_aes_gcm_state);
  429. }
  430. }
  431. }
  432. }
  433. }
  434. // Generate a new identity signature key. Output the public key and the
  435. // sealed private key. outsealedpriv must point to SEALEDPRIVKEY_SIZE =
  436. // sizeof(sgx_sealed_data_t) + sizeof(sgx_ec256_private_t) + 18 bytes of
  437. // memory.
  438. void ecall_identity_key_new(sgx_ec256_public_t *outpub,
  439. sgx_sealed_data_t *outsealedpriv)
  440. {
  441. sgx_ecc_state_handle_t ecc_handle;
  442. sgx_ecc256_open_context(&ecc_handle);
  443. sgx_ecc256_create_key_pair(&g_privkey, &g_pubkey, ecc_handle);
  444. memmove(outpub, &g_pubkey, sizeof(g_pubkey));
  445. sgx_ecc256_close_context(ecc_handle);
  446. sgx_seal_data(18, (const uint8_t*)"TEEMS Identity key",
  447. sizeof(g_privkey), (const uint8_t*)&g_privkey,
  448. SEALED_PRIVKEY_SIZE, outsealedpriv);
  449. }
  450. // Load an identity key from a sealed privkey. Output the resulting
  451. // public key. insealedpriv must point to sizeof(sgx_sealed_data_t) +
  452. // sizeof(sgx_ec256_private_t) bytes of memory. Returns true for
  453. // success, false for failure.
  454. bool ecall_identity_key_load(sgx_ec256_public_t *outpub,
  455. const sgx_sealed_data_t *insealedpriv)
  456. {
  457. sgx_ecc_state_handle_t ecc_handle;
  458. char aad[18];
  459. uint32_t aadsize = sizeof(aad);
  460. sgx_ec256_private_t privkey;
  461. uint32_t privkeysize = sizeof(privkey);
  462. sgx_status_t res = sgx_unseal_data(
  463. insealedpriv, (uint8_t*)aad, &aadsize,
  464. (uint8_t*)&privkey, &privkeysize);
  465. if (res || aadsize != sizeof(aad) || privkeysize != sizeof(privkey)
  466. || memcmp(aad, "TEEMS Identity key", sizeof(aad))) {
  467. return false;
  468. }
  469. sgx_ecc256_open_context(&ecc_handle);
  470. sgx_ec256_public_t pubkey;
  471. int valid;
  472. if (sgx_ecc256_calculate_pub_from_priv(&privkey, &pubkey) ||
  473. sgx_ecc256_check_point(&pubkey, ecc_handle, &valid) ||
  474. !valid) {
  475. sgx_ecc256_close_context(ecc_handle);
  476. return false;
  477. }
  478. sgx_ecc256_close_context(ecc_handle);
  479. memmove(&g_pubkey, &pubkey, sizeof(pubkey));
  480. memmove(&g_privkey, &privkey, sizeof(privkey));
  481. memmove(outpub, &pubkey, sizeof(pubkey));
  482. return true;
  483. }
  484. bool comms_init_nodestate(const EnclaveAPINodeConfig *apinodeconfigs,
  485. nodenum_t num_nodes, nodenum_t me)
  486. {
  487. sgx_ecc_state_handle_t ecc_handle;
  488. sgx_ecc256_open_context(&ecc_handle);
  489. commstates.clear();
  490. tot_nodes = 0;
  491. commstates.reserve(num_nodes);
  492. for (nodenum_t i=0; i<num_nodes; ++i) {
  493. // Check that the pubkey is valid
  494. int valid;
  495. if (sgx_ecc256_check_point(&apinodeconfigs[i].pubkey,
  496. ecc_handle, &valid) ||
  497. !valid) {
  498. printf("Pubkey for node %hu invalid\n", i);
  499. commstates.clear();
  500. sgx_ecc256_close_context(ecc_handle);
  501. return false;
  502. }
  503. commstates.emplace_back(&apinodeconfigs[i].pubkey, i);
  504. }
  505. sgx_ecc256_close_context(ecc_handle);
  506. my_node_num = me;
  507. // Check that no one other than us has our pubkey (deals with
  508. // reflection attacks)
  509. for (nodenum_t i=0; i<num_nodes; ++i) {
  510. if (i == my_node_num) continue;
  511. if (!memcmp(&commstates[i].pubkey,
  512. &commstates[my_node_num].pubkey,
  513. sizeof(commstates[i].pubkey))) {
  514. printf("Pubkey %hu matches our own; possible reflection attack?\n",
  515. i);
  516. commstates.clear();
  517. return false;
  518. }
  519. }
  520. tot_nodes = num_nodes;
  521. // There will be an enclave-to-enclave channel between us and each
  522. // other node's enclave. For the node numbers smaller than ours, we
  523. // will be the server for the handshake for that channel. Prepare
  524. // to receive the first handshake message from those nodes'
  525. // enclaves.
  526. for (nodenum_t i=0; i<my_node_num; ++i) {
  527. commstates[i].in_msg_get_buf = default_in_msg_get_buf;
  528. commstates[i].in_msg_received = handshake_1_msg_received;
  529. }
  530. return true;
  531. }
  532. bool ecall_message(nodenum_t node_num, uint32_t message_len)
  533. {
  534. if (node_num >= tot_nodes) {
  535. printf("Out-of-range node_num %hu received in ecall_message\n",
  536. node_num);
  537. return false;
  538. }
  539. NodeCommState &nodest = commstates[node_num];
  540. if (nodest.in_msg_size != nodest.in_msg_offset) {
  541. printf("Received ecall_message without completing previous message\n");
  542. return false;
  543. }
  544. if (!nodest.in_msg_get_buf) {
  545. printf("No message header handler registered\n");
  546. return false;
  547. }
  548. uint8_t *buf = nodest.in_msg_get_buf(nodest, message_len);
  549. if (!buf) {
  550. printf("Message header handler returned NULL\n");
  551. return false;
  552. }
  553. nodest.in_msg_size = message_len;
  554. nodest.in_msg_offset = 0;
  555. nodest.in_msg_plaintext_processed = 0;
  556. nodest.in_msg_buf = buf;
  557. return true;
  558. }
  559. bool ecall_chunk(nodenum_t node_num, const uint8_t *chunkdata,
  560. uint32_t chunklen)
  561. {
  562. if (node_num >= tot_nodes) {
  563. printf("Out-of-range node_num %hu received in ecall_chunk\n",
  564. node_num);
  565. return false;
  566. }
  567. NodeCommState &nodest = commstates[node_num];
  568. if (nodest.in_msg_size == nodest.in_msg_offset) {
  569. printf("Received ecall_chunk after completing message\n");
  570. return false;
  571. }
  572. if (!nodest.in_msg_buf) {
  573. printf("No incoming message buffer allocated\n");
  574. return false;
  575. }
  576. if (!nodest.in_msg_received) {
  577. printf("No message received handler registered\n");
  578. return false;
  579. }
  580. if (nodest.in_msg_offset + chunklen > nodest.in_msg_size) {
  581. printf("Chunk larger than remaining message size\n");
  582. return false;
  583. }
  584. if (nodest.handshake_step == HANDSHAKE_COMPLETE) {
  585. // Decrypt the incoming data
  586. *(size_t*)(nodest.in_aes_iv) += 1;
  587. if (sgx_rijndael128GCM_decrypt(&nodest.in_aes_key, chunkdata,
  588. chunklen - SGX_AESGCM_MAC_SIZE,
  589. nodest.in_msg_buf + nodest.in_msg_plaintext_processed,
  590. nodest.in_aes_iv, SGX_AESGCM_IV_SIZE, NULL, 0,
  591. (const sgx_aes_gcm_128bit_tag_t *)
  592. (chunkdata + chunklen - SGX_AESGCM_MAC_SIZE))) {
  593. printf("Decryption failed\n");
  594. return false;
  595. }
  596. nodest.in_msg_plaintext_processed +=
  597. chunklen - SGX_AESGCM_MAC_SIZE;
  598. } else {
  599. // Just copy the handshake data
  600. memmove(nodest.in_msg_buf + nodest.in_msg_plaintext_processed,
  601. chunkdata, chunklen);
  602. nodest.in_msg_plaintext_processed += chunklen;
  603. }
  604. nodest.in_msg_offset += chunklen;
  605. if (nodest.in_msg_offset == nodest.in_msg_size) {
  606. // This was the last chunk; handle the received message
  607. uint8_t* buf = nodest.in_msg_buf;
  608. uint32_t plaintext_processed = nodest.in_msg_plaintext_processed;
  609. uint32_t msg_size = nodest.in_msg_size;
  610. nodest.in_msg_buf = NULL;
  611. nodest.in_msg_size = 0;
  612. nodest.in_msg_offset = 0;
  613. nodest.in_msg_plaintext_processed = 0;
  614. nodest.in_msg_received(nodest, buf, plaintext_processed, msg_size);
  615. }
  616. return true;
  617. }
  618. // Start the handshake (as the client)
  619. void NodeCommState::handshake_start()
  620. {
  621. sgx_ecc_state_handle_t ecc_handle;
  622. sgx_ecc256_open_context(&ecc_handle);
  623. // Create a DH keypair
  624. sgx_ecc256_create_key_pair(&handshake_dh_privkey, &handshake_dh_pubkey,
  625. ecc_handle);
  626. sgx_ecc256_close_context(ecc_handle);
  627. // Get us ready to receive handshake message 2
  628. in_msg_get_buf = default_in_msg_get_buf;
  629. in_msg_received = handshake_2_msg_received;
  630. handshake_step = HANDSHAKE_C_SENT_1;
  631. // Send the public key as the first message
  632. message_start(sizeof(handshake_dh_pubkey), false);
  633. message_data((uint8_t*)&handshake_dh_pubkey,
  634. sizeof(handshake_dh_pubkey), false);
  635. }
  636. // Start all handshakes for which we are the client. Call
  637. // ocall_comms_ready(cbpointer) when the handshakes with all other nodes
  638. // (for which we are client or server) are complete.
  639. bool ecall_comms_start(void *cbpointer)
  640. {
  641. completed_handshake_counter.reset(cbpointer);
  642. for (nodenum_t t = my_node_num+1; t<tot_nodes; ++t) {
  643. commstates[t].handshake_start();
  644. }
  645. return true;
  646. }