isv_app.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. /*
  2. * Copyright (C) 2011-2016 Intel Corporation. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in
  12. * the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Intel Corporation nor the names of its
  15. * contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. *
  30. */
  31. #include <stdio.h>
  32. #include <limits.h>
  33. // Needed for definition of remote attestation messages.
  34. #include "remote_attestation_result.h"
  35. #include "isv_enclave_u.h"
  36. // Needed to call untrusted key exchange library APIs, i.e. sgx_ra_proc_msg2.
  37. #include "sgx_ukey_exchange.h"
  38. // Needed to get service provider's information, in your real project, you will
  39. // need to talk to real server.
  40. #include "network_ra.h"
  41. // Needed to create enclave and do ecall.
  42. #include "sgx_urts.h"
  43. #include "service_provider.h"
  44. #ifndef SAFE_FREE
  45. #define SAFE_FREE(ptr) {if (NULL != (ptr)) {free(ptr); (ptr) = NULL;}}
  46. #endif
  47. // In addition to generating and sending messages, this application
  48. // can use pre-generated messages to verify the generation of
  49. // messages and the information flow.
  50. #include "sample_messages.h"
  51. #define ENCLAVE_PATH "isv_enclave.signed.so"
  52. uint8_t* msg1_samples[] = { msg1_sample1, msg1_sample2 };
  53. uint8_t* msg2_samples[] = { msg2_sample1, msg2_sample2 };
  54. uint8_t* msg3_samples[MSG3_BODY_SIZE] = { msg3_sample1, msg3_sample2 };
  55. uint8_t* attestation_msg_samples[] =
  56. { attestation_msg_sample1, attestation_msg_sample2};
  57. // Some utility functions to output some of the data structures passed between
  58. // the ISV app and the remote attestation service provider.
  59. void PRINT_BYTE_ARRAY(
  60. FILE *file, void *mem, uint32_t len)
  61. {
  62. if(!mem || !len)
  63. {
  64. fprintf(file, "\n( null )\n");
  65. return;
  66. }
  67. uint8_t *array = (uint8_t *)mem;
  68. fprintf(file, "%u bytes:\n{\n", len);
  69. uint32_t i = 0;
  70. for(i = 0; i < len - 1; i++)
  71. {
  72. fprintf(file, "0x%x, ", array[i]);
  73. if(i % 8 == 7) fprintf(file, "\n");
  74. }
  75. fprintf(file, "0x%x ", array[i]);
  76. fprintf(file, "\n}\n");
  77. }
  78. void PRINT_ATTESTATION_SERVICE_RESPONSE(
  79. FILE *file,
  80. ra_samp_response_header_t *response)
  81. {
  82. if(!response)
  83. {
  84. fprintf(file, "\t\n( null )\n");
  85. return;
  86. }
  87. fprintf(file, "RESPONSE TYPE: 0x%x\n", response->type);
  88. fprintf(file, "RESPONSE STATUS: 0x%x 0x%x\n", response->status[0],
  89. response->status[1]);
  90. fprintf(file, "RESPONSE BODY SIZE: %u\n", response->size);
  91. if(response->type == TYPE_RA_MSG2)
  92. {
  93. sgx_ra_msg2_t* p_msg2_body = (sgx_ra_msg2_t*)(response->body);
  94. fprintf(file, "MSG2 gb - ");
  95. PRINT_BYTE_ARRAY(file, &(p_msg2_body->g_b), sizeof(p_msg2_body->g_b));
  96. fprintf(file, "MSG2 spid - ");
  97. PRINT_BYTE_ARRAY(file, &(p_msg2_body->spid), sizeof(p_msg2_body->spid));
  98. fprintf(file, "MSG2 sign_gb_ga - ");
  99. PRINT_BYTE_ARRAY(file, &(p_msg2_body->sign_gb_ga),
  100. sizeof(p_msg2_body->sign_gb_ga));
  101. fprintf(file, "MSG2 mac - ");
  102. PRINT_BYTE_ARRAY(file, &(p_msg2_body->mac), sizeof(p_msg2_body->mac));
  103. fprintf(file, "MSG2 sig_rl - ");
  104. PRINT_BYTE_ARRAY(file, &(p_msg2_body->sig_rl),
  105. p_msg2_body->sig_rl_size);
  106. }
  107. else if(response->type == TYPE_RA_ATT_RESULT)
  108. {
  109. sample_ra_att_result_msg_t *p_att_result =
  110. (sample_ra_att_result_msg_t *)(response->body);
  111. fprintf(file, "ATTESTATION RESULT MSG platform_info_blob - ");
  112. PRINT_BYTE_ARRAY(file, &(p_att_result->platform_info_blob),
  113. sizeof(p_att_result->platform_info_blob));
  114. fprintf(file, "ATTESTATION RESULT MSG mac - ");
  115. PRINT_BYTE_ARRAY(file, &(p_att_result->mac), sizeof(p_att_result->mac));
  116. fprintf(file, "ATTESTATION RESULT MSG secret.payload_tag - %u bytes\n",
  117. p_att_result->secret.payload_size);
  118. fprintf(file, "ATTESTATION RESULT MSG secret.payload - ");
  119. PRINT_BYTE_ARRAY(file, p_att_result->secret.payload,
  120. p_att_result->secret.payload_size);
  121. }
  122. else
  123. {
  124. fprintf(file, "\nERROR in printing out the response. "
  125. "Response of type not supported %d\n", response->type);
  126. }
  127. }
  128. // This sample code doesn't have any recovery/retry mechanisms for the remote
  129. // attestation. Since the enclave can be lost due S3 transitions, apps
  130. // susceptible to S3 transtions should have logic to restart attestation in
  131. // these scenenarios.
  132. #define _T(x) x
  133. int main(int argc, char* argv[])
  134. {
  135. int ret = 0;
  136. ra_samp_request_header_t *p_msg1_full = NULL;
  137. ra_samp_response_header_t *p_msg2_full = NULL;
  138. sgx_ra_msg3_t *p_msg3 = NULL;
  139. ra_samp_response_header_t* p_att_result_msg_full = NULL;
  140. sgx_enclave_id_t enclave_id = 0;
  141. int enclave_lost_retry_time = 1;
  142. int busy_retry_time = 2;
  143. sgx_ra_context_t context = INT_MAX;
  144. sgx_status_t status = SGX_SUCCESS;
  145. ra_samp_request_header_t* p_msg3_full = NULL;
  146. int32_t verify_index = -1;
  147. int32_t verification_samples = sizeof(msg1_samples)/sizeof(msg1_samples[0]);
  148. FILE* OUTPUT = stdout;
  149. #define VERIFICATION_INDEX_IS_VALID() (verify_index > 0 && \
  150. verify_index <= verification_samples)
  151. #define GET_VERIFICATION_ARRAY_INDEX() (verify_index-1)
  152. if(argc > 1)
  153. {
  154. verify_index = atoi(argv[1]);
  155. if( VERIFICATION_INDEX_IS_VALID())
  156. {
  157. fprintf(OUTPUT, "\nVerifying precomputed attestation messages "
  158. "using precomputed values# %d\n", verify_index);
  159. }
  160. else
  161. {
  162. fprintf(OUTPUT, "\nValid invocations are:\n");
  163. fprintf(OUTPUT, "\n\tisv_app\n");
  164. fprintf(OUTPUT, "\n\tisv_app <verification index>\n");
  165. fprintf(OUTPUT, "\nValid indices are [1 - %d]\n",
  166. verification_samples);
  167. fprintf(OUTPUT, "\nUsing a verification index uses precomputed "
  168. "messages to assist debugging the remote attestation "
  169. "service provider.\n");
  170. return -1;
  171. }
  172. }
  173. // Remote attestaton will be initiated the ISV server challenges the ISV
  174. // app or if the ISV app detects it doesn't have the credentials
  175. // (shared secret) from a previous attestation required for secure
  176. // communication with the server.
  177. {
  178. // ISV application creates the ISV enclave.
  179. int launch_token_update = 0;
  180. sgx_launch_token_t launch_token = {0};
  181. memset(&launch_token, 0, sizeof(sgx_launch_token_t));
  182. do
  183. {
  184. ret = sgx_create_enclave(_T(ENCLAVE_PATH),
  185. SGX_DEBUG_FLAG,
  186. &launch_token,
  187. &launch_token_update,
  188. &enclave_id, NULL);
  189. if(SGX_SUCCESS != ret)
  190. {
  191. ret = -1;
  192. fprintf(OUTPUT, "\nError, call sgx_create_enclave fail [%s].",
  193. __FUNCTION__);
  194. return ret;
  195. }
  196. fprintf(OUTPUT, "\nCall sgx_create_enclave success.");
  197. ret = enclave_init_ra(enclave_id,
  198. &status,
  199. false,
  200. &context);
  201. //Ideally, this check would be around the full attestation flow.
  202. } while (SGX_ERROR_ENCLAVE_LOST == ret && enclave_lost_retry_time--);
  203. if(SGX_SUCCESS != ret || status)
  204. {
  205. ret = -1;
  206. fprintf(OUTPUT, "\nError, call enclave_init_ra fail [%s].",
  207. __FUNCTION__);
  208. goto CLEANUP;
  209. }
  210. fprintf(OUTPUT, "\nCall enclave_init_ra success.");
  211. // isv application call uke sgx_ra_get_msg1
  212. p_msg1_full = (ra_samp_request_header_t*)
  213. malloc(sizeof(ra_samp_request_header_t)
  214. + sizeof(sgx_ra_msg1_t));
  215. if(NULL == p_msg1_full)
  216. {
  217. ret = -1;
  218. goto CLEANUP;
  219. }
  220. p_msg1_full->type = TYPE_RA_MSG1;
  221. p_msg1_full->size = sizeof(sgx_ra_msg1_t);
  222. do
  223. {
  224. ret = sgx_ra_get_msg1(context, enclave_id, sgx_ra_get_ga,
  225. (sgx_ra_msg1_t*)((uint8_t*)p_msg1_full
  226. + sizeof(ra_samp_request_header_t)));
  227. } while (SGX_ERROR_BUSY == ret && busy_retry_time--);
  228. if(SGX_SUCCESS != ret)
  229. {
  230. ret = -1;
  231. fprintf(OUTPUT, "\nError, call sgx_ra_get_msg1 fail [%s].",
  232. __FUNCTION__);
  233. goto CLEANUP;
  234. }
  235. else
  236. {
  237. fprintf(OUTPUT, "\nCall sgx_ra_get_msg1 success.\n");
  238. fprintf(OUTPUT, "\nMSG1 body generated -\n");
  239. PRINT_BYTE_ARRAY(OUTPUT, p_msg1_full->body, p_msg1_full->size);
  240. }
  241. if(VERIFICATION_INDEX_IS_VALID())
  242. {
  243. memcpy_s(p_msg1_full->body, p_msg1_full->size,
  244. msg1_samples[GET_VERIFICATION_ARRAY_INDEX()],
  245. p_msg1_full->size);
  246. fprintf(OUTPUT, "\nInstead of using the recently generated MSG1, "
  247. "we will use the following precomputed MSG1 -\n");
  248. PRINT_BYTE_ARRAY(OUTPUT, p_msg1_full->body, p_msg1_full->size);
  249. }
  250. // The ISV application sends msg1 to the SP to get msg2,
  251. // msg2 needs to be freed when no longer needed.
  252. // The ISV decides whether to use linkable or unlinkable signatures.
  253. fprintf(OUTPUT, "\nSending msg1 to remote attestation service provider."
  254. "Expecting msg2 back.\n");
  255. ret = ra_network_send_receive("http://SampleServiceProvider.intel.com/",
  256. p_msg1_full,
  257. &p_msg2_full);
  258. if(ret != 0 || !p_msg2_full)
  259. {
  260. fprintf(OUTPUT, "\nError, ra_network_send_receive for msg1 failed "
  261. "[%s].", __FUNCTION__);
  262. if(VERIFICATION_INDEX_IS_VALID())
  263. {
  264. fprintf(OUTPUT, "\nBecause we are in verification mode we will "
  265. "ignore this error.\n");
  266. fprintf(OUTPUT, "\nInstead, we will pretend we received the "
  267. "following MSG2 - \n");
  268. SAFE_FREE(p_msg2_full);
  269. ra_samp_response_header_t* precomputed_msg2 =
  270. (ra_samp_response_header_t*)msg2_samples[
  271. GET_VERIFICATION_ARRAY_INDEX()];
  272. const size_t msg2_full_size = sizeof(ra_samp_response_header_t)
  273. + precomputed_msg2->size;
  274. p_msg2_full =
  275. (ra_samp_response_header_t*)malloc(msg2_full_size);
  276. if(NULL == p_msg2_full)
  277. {
  278. ret = -1;
  279. goto CLEANUP;
  280. }
  281. memcpy_s(p_msg2_full, msg2_full_size, precomputed_msg2,
  282. msg2_full_size);
  283. PRINT_BYTE_ARRAY(OUTPUT, p_msg2_full,
  284. sizeof(ra_samp_response_header_t)
  285. + p_msg2_full->size);
  286. }
  287. else
  288. {
  289. goto CLEANUP;
  290. }
  291. }
  292. else
  293. {
  294. // Successfully sent msg1 and received a msg2 back.
  295. // Time now to check msg2.
  296. if(TYPE_RA_MSG2 != p_msg2_full->type)
  297. {
  298. fprintf(OUTPUT, "\nError, didn't get MSG2 in response to MSG1. "
  299. "[%s].", __FUNCTION__);
  300. if(VERIFICATION_INDEX_IS_VALID())
  301. {
  302. fprintf(OUTPUT, "\nBecause we are in verification mode we "
  303. "will ignore this error.");
  304. }
  305. else
  306. {
  307. goto CLEANUP;
  308. }
  309. }
  310. fprintf(OUTPUT, "\nSent MSG1 to remote attestation service "
  311. "provider. Received the following MSG2:\n");
  312. PRINT_BYTE_ARRAY(OUTPUT, p_msg2_full,
  313. sizeof(ra_samp_response_header_t)
  314. + p_msg2_full->size);
  315. fprintf(OUTPUT, "\nA more descriptive representation of MSG2:\n");
  316. PRINT_ATTESTATION_SERVICE_RESPONSE(OUTPUT, p_msg2_full);
  317. if( VERIFICATION_INDEX_IS_VALID() )
  318. {
  319. // The response should match the precomputed MSG2:
  320. ra_samp_response_header_t* precomputed_msg2 =
  321. (ra_samp_response_header_t *)
  322. msg2_samples[GET_VERIFICATION_ARRAY_INDEX()];
  323. if(memcmp( precomputed_msg2, p_msg2_full,
  324. sizeof(ra_samp_response_header_t) + p_msg2_full->size))
  325. {
  326. fprintf(OUTPUT, "\nVerification ERROR. Our precomputed "
  327. "value for MSG2 does NOT match.\n");
  328. fprintf(OUTPUT, "\nPrecomputed value for MSG2:\n");
  329. PRINT_BYTE_ARRAY(OUTPUT, precomputed_msg2,
  330. sizeof(ra_samp_response_header_t)
  331. + precomputed_msg2->size);
  332. fprintf(OUTPUT, "\nA more descriptive representation "
  333. "of precomputed value for MSG2:\n");
  334. PRINT_ATTESTATION_SERVICE_RESPONSE(OUTPUT,
  335. precomputed_msg2);
  336. }
  337. else
  338. {
  339. fprintf(OUTPUT, "\nVerification COMPLETE. Remote "
  340. "attestation service provider generated a "
  341. "matching MSG2.\n");
  342. }
  343. }
  344. }
  345. sgx_ra_msg2_t* p_msg2_body = (sgx_ra_msg2_t*)((uint8_t*)p_msg2_full
  346. + sizeof(ra_samp_response_header_t));
  347. uint32_t msg3_size = 0;
  348. if( VERIFICATION_INDEX_IS_VALID())
  349. {
  350. // We cannot generate a valid MSG3 using the precomputed messages
  351. // we have been using. We will use the precomputed msg3 instead.
  352. msg3_size = MSG3_BODY_SIZE;
  353. p_msg3 = (sgx_ra_msg3_t*)malloc(msg3_size);
  354. if(NULL == p_msg3)
  355. {
  356. ret = -1;
  357. goto CLEANUP;
  358. }
  359. memcpy_s(p_msg3, msg3_size,
  360. msg3_samples[GET_VERIFICATION_ARRAY_INDEX()], msg3_size);
  361. fprintf(OUTPUT, "\nBecause MSG1 was a precomputed value, the MSG3 "
  362. "we use will also be. PRECOMPUTED MSG3 - \n");
  363. }
  364. else
  365. {
  366. busy_retry_time = 2;
  367. // The ISV app now calls uKE sgx_ra_proc_msg2,
  368. // The ISV app is responsible for freeing the returned p_msg3!!
  369. do
  370. {
  371. ret = sgx_ra_proc_msg2(context,
  372. enclave_id,
  373. sgx_ra_proc_msg2_trusted,
  374. sgx_ra_get_msg3_trusted,
  375. p_msg2_body,
  376. p_msg2_full->size,
  377. &p_msg3,
  378. &msg3_size);
  379. } while (SGX_ERROR_BUSY == ret && busy_retry_time--);
  380. if(!p_msg3)
  381. {
  382. fprintf(OUTPUT, "\nError, call sgx_ra_proc_msg2 fail. "
  383. "p_msg3 = 0x%p [%s].", p_msg3, __FUNCTION__);
  384. ret = -1;
  385. goto CLEANUP;
  386. }
  387. if(SGX_SUCCESS != (sgx_status_t)ret)
  388. {
  389. fprintf(OUTPUT, "\nError, call sgx_ra_proc_msg2 fail. "
  390. "ret = 0x%08x [%s].", ret, __FUNCTION__);
  391. ret = -1;
  392. goto CLEANUP;
  393. }
  394. else
  395. {
  396. fprintf(OUTPUT, "\nCall sgx_ra_proc_msg2 success.\n");
  397. fprintf(OUTPUT, "\nMSG3 - \n");
  398. }
  399. }
  400. PRINT_BYTE_ARRAY(OUTPUT, p_msg3, msg3_size);
  401. p_msg3_full = (ra_samp_request_header_t*)malloc(
  402. sizeof(ra_samp_request_header_t) + msg3_size);
  403. if(NULL == p_msg3_full)
  404. {
  405. ret = -1;
  406. goto CLEANUP;
  407. }
  408. p_msg3_full->type = TYPE_RA_MSG3;
  409. p_msg3_full->size = msg3_size;
  410. if(memcpy_s(p_msg3_full->body, msg3_size, p_msg3, msg3_size))
  411. {
  412. fprintf(OUTPUT,"\nError: INTERNAL ERROR - memcpy failed in [%s].",
  413. __FUNCTION__);
  414. ret = -1;
  415. goto CLEANUP;
  416. }
  417. // The ISV application sends msg3 to the SP to get the attestation
  418. // result message, attestation result message needs to be freed when
  419. // no longer needed. The ISV service provider decides whether to use
  420. // linkable or unlinkable signatures. The format of the attestation
  421. // result is up to the service provider. This format is used for
  422. // demonstration. Note that the attestation result message makes use
  423. // of both the MK for the MAC and the SK for the secret. These keys are
  424. // established from the SIGMA secure channel binding.
  425. ret = ra_network_send_receive("http://SampleServiceProvider.intel.com/",
  426. p_msg3_full,
  427. &p_att_result_msg_full);
  428. if(ret || !p_att_result_msg_full)
  429. {
  430. ret = -1;
  431. fprintf(OUTPUT, "\nError, sending msg3 failed [%s].", __FUNCTION__);
  432. goto CLEANUP;
  433. }
  434. sample_ra_att_result_msg_t * p_att_result_msg_body =
  435. (sample_ra_att_result_msg_t *)((uint8_t*)p_att_result_msg_full
  436. + sizeof(ra_samp_response_header_t));
  437. if(TYPE_RA_ATT_RESULT != p_att_result_msg_full->type)
  438. {
  439. ret = -1;
  440. fprintf(OUTPUT, "\nError. Sent MSG3 successfully, but the message "
  441. "received was NOT of type att_msg_result. Type = "
  442. "%d. [%s].", p_att_result_msg_full->type,
  443. __FUNCTION__);
  444. goto CLEANUP;
  445. }
  446. else
  447. {
  448. fprintf(OUTPUT, "\nSent MSG3 successfully. Received an attestation "
  449. "result message back\n.");
  450. if( VERIFICATION_INDEX_IS_VALID() )
  451. {
  452. if(memcmp(p_att_result_msg_full->body,
  453. attestation_msg_samples[GET_VERIFICATION_ARRAY_INDEX()],
  454. p_att_result_msg_full->size) )
  455. {
  456. fprintf(OUTPUT, "\nSent MSG3 successfully. Received an "
  457. "attestation result message back that did "
  458. "NOT match the expected value.\n");
  459. fprintf(OUTPUT, "\nEXPECTED ATTESTATION RESULT -");
  460. PRINT_BYTE_ARRAY(OUTPUT,
  461. attestation_msg_samples[GET_VERIFICATION_ARRAY_INDEX()],
  462. p_att_result_msg_full->size);
  463. }
  464. }
  465. }
  466. fprintf(OUTPUT, "\nATTESTATION RESULT RECEIVED - ");
  467. PRINT_BYTE_ARRAY(OUTPUT, p_att_result_msg_full->body,
  468. p_att_result_msg_full->size);
  469. if( VERIFICATION_INDEX_IS_VALID() )
  470. {
  471. fprintf(OUTPUT, "\nBecause we used precomputed values for the "
  472. "messages, the attestation result message will "
  473. "not pass further verification tests, so we will "
  474. "skip them.\n");
  475. goto CLEANUP;
  476. }
  477. // Check the MAC using MK on the attestation result message.
  478. // The format of the attestation result message is ISV specific.
  479. // This is a simple form for demonstration. In a real product,
  480. // the ISV may want to communicate more information.
  481. ret = verify_att_result_mac(enclave_id,
  482. &status,
  483. context,
  484. (uint8_t*)&p_att_result_msg_body->platform_info_blob,
  485. sizeof(ias_platform_info_blob_t),
  486. (uint8_t*)&p_att_result_msg_body->mac,
  487. sizeof(sgx_mac_t));
  488. if((SGX_SUCCESS != ret) ||
  489. (SGX_SUCCESS != status))
  490. {
  491. ret = -1;
  492. fprintf(OUTPUT, "\nError: INTEGRITY FAILED - attestation result "
  493. "message MK based cmac failed in [%s].",
  494. __FUNCTION__);
  495. goto CLEANUP;
  496. }
  497. bool attestation_passed = true;
  498. // Check the attestation result for pass or fail.
  499. // @TODO: Check the status. This is ISV defined.
  500. if(0 != p_att_result_msg_full->status[0]
  501. || 0 != p_att_result_msg_full->status[1])
  502. {
  503. fprintf(OUTPUT, "\nError, attestation result message MK based cmac "
  504. "failed in [%s].", __FUNCTION__);
  505. attestation_passed = false;
  506. }
  507. // the SGX blob analysis API. The ISV will take action based on the
  508. // update_info. (upgrade PSW or uCode), the second param should be 1 if
  509. // the attestation failed, otherwise should be 0.
  510. // sgx_update_info_bit_t update_info;
  511. // ret = sgx_report_attestation_status(
  512. // &p_att_result_msg_body->platform_info_blob,
  513. // attestation_passed ? 0 : 1, &update_info);
  514. // Get the shared secret sent by the server using SK (if attestation
  515. // passed)
  516. if(attestation_passed)
  517. {
  518. ret = put_secret_data(enclave_id,
  519. &status,
  520. context,
  521. p_att_result_msg_body->secret.payload,
  522. p_att_result_msg_body->secret.payload_size,
  523. p_att_result_msg_body->secret.payload_tag);
  524. if((SGX_SUCCESS != ret) || (SGX_SUCCESS != status))
  525. {
  526. fprintf(OUTPUT, "\nError, attestation result message secret "
  527. "using SK based AESGCM failed in [%s]. ret = "
  528. "0x%0x. status = 0x%0x", __FUNCTION__, ret,
  529. status);
  530. goto CLEANUP;
  531. }
  532. }
  533. fprintf(OUTPUT, "\nSecret successfully received from server.");
  534. fprintf(OUTPUT, "\nRemote attestation success!");
  535. }
  536. CLEANUP:
  537. // Clean-up
  538. // Need to close the RA key state.
  539. if(INT_MAX != context)
  540. {
  541. int ret_save = ret;
  542. ret = enclave_ra_close(enclave_id, &status, context);
  543. if(SGX_SUCCESS != ret || status)
  544. {
  545. ret = -1;
  546. fprintf(OUTPUT, "\nError, call enclave_ra_close fail [%s].",
  547. __FUNCTION__);
  548. }
  549. else
  550. {
  551. // enclave_ra_close was successful, let's restore the value that
  552. // led us to this point in the code.
  553. ret = ret_save;
  554. }
  555. fprintf(OUTPUT, "\nCall enclave_ra_close success.");
  556. }
  557. sgx_destroy_enclave(enclave_id);
  558. ra_free_network_response_buffer(p_msg2_full);
  559. ra_free_network_response_buffer(p_att_result_msg_full);
  560. // p_msg3 is malloc'd by the untrused KE library. App needs to free.
  561. SAFE_FREE(p_msg3);
  562. SAFE_FREE(p_msg3_full);
  563. SAFE_FREE(p_msg1_full);
  564. printf("\nEnter a character before exit ...\n");
  565. getchar();
  566. return ret;
  567. }