comms.cpp 26 KB

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