isv_app.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. /*
  2. * Copyright (C) 2011-2017 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. // This sample is confined to the communication between a SGX client platform
  32. // and an ISV Application Server.
  33. #include <stdio.h>
  34. #include <limits.h>
  35. #include <unistd.h>
  36. // Needed for definition of remote attestation messages.
  37. #include "remote_attestation_result.h"
  38. #include "isv_enclave_u.h"
  39. // Needed to call untrusted key exchange library APIs, i.e. sgx_ra_proc_msg2.
  40. #include "sgx_ukey_exchange.h"
  41. // Needed to get service provider's information, in your real project, you will
  42. // need to talk to real server.
  43. #include "network_ra.h"
  44. // Needed to create enclave and do ecall.
  45. #include "sgx_urts.h"
  46. // Needed to query extended epid group id.
  47. #include "sgx_uae_service.h"
  48. #include "service_provider.h"
  49. #ifndef SAFE_FREE
  50. #define SAFE_FREE(ptr) {if (NULL != (ptr)) {free(ptr); (ptr) = NULL;}}
  51. #endif
  52. // In addition to generating and sending messages, this application
  53. // can use pre-generated messages to verify the generation of
  54. // messages and the information flow.
  55. #include "sample_messages.h"
  56. #define ENCLAVE_PATH "isv_enclave.signed.so"
  57. uint8_t* msg1_samples[] = { msg1_sample1, msg1_sample2 };
  58. uint8_t* msg2_samples[] = { msg2_sample1, msg2_sample2 };
  59. uint8_t* msg3_samples[] = { msg3_sample1, msg3_sample2 };
  60. uint8_t* attestation_msg_samples[] =
  61. { attestation_msg_sample1, attestation_msg_sample2};
  62. // Some utility functions to output some of the data structures passed between
  63. // the ISV app and the remote attestation service provider.
  64. void PRINT_BYTE_ARRAY(
  65. FILE *file, void *mem, uint32_t len)
  66. {
  67. if(!mem || !len)
  68. {
  69. fprintf(file, "\n( null )\n");
  70. return;
  71. }
  72. uint8_t *array = (uint8_t *)mem;
  73. fprintf(file, "%u bytes:\n{\n", len);
  74. uint32_t i = 0;
  75. for(i = 0; i < len - 1; i++)
  76. {
  77. fprintf(file, "0x%x, ", array[i]);
  78. if(i % 8 == 7) fprintf(file, "\n");
  79. }
  80. fprintf(file, "0x%x ", array[i]);
  81. fprintf(file, "\n}\n");
  82. }
  83. void PRINT_ATTESTATION_SERVICE_RESPONSE(
  84. FILE *file,
  85. ra_samp_response_header_t *response)
  86. {
  87. if(!response)
  88. {
  89. fprintf(file, "\t\n( null )\n");
  90. return;
  91. }
  92. fprintf(file, "RESPONSE TYPE: 0x%x\n", response->type);
  93. fprintf(file, "RESPONSE STATUS: 0x%x 0x%x\n", response->status[0],
  94. response->status[1]);
  95. fprintf(file, "RESPONSE BODY SIZE: %u\n", response->size);
  96. if(response->type == TYPE_RA_MSG2)
  97. {
  98. sgx_ra_msg2_t* p_msg2_body = (sgx_ra_msg2_t*)(response->body);
  99. fprintf(file, "MSG2 gb - ");
  100. PRINT_BYTE_ARRAY(file, &(p_msg2_body->g_b), sizeof(p_msg2_body->g_b));
  101. fprintf(file, "MSG2 spid - ");
  102. PRINT_BYTE_ARRAY(file, &(p_msg2_body->spid), sizeof(p_msg2_body->spid));
  103. fprintf(file, "MSG2 quote_type : %hx\n", p_msg2_body->quote_type);
  104. fprintf(file, "MSG2 kdf_id : %hx\n", p_msg2_body->kdf_id);
  105. fprintf(file, "MSG2 sign_gb_ga - ");
  106. PRINT_BYTE_ARRAY(file, &(p_msg2_body->sign_gb_ga),
  107. sizeof(p_msg2_body->sign_gb_ga));
  108. fprintf(file, "MSG2 mac - ");
  109. PRINT_BYTE_ARRAY(file, &(p_msg2_body->mac), sizeof(p_msg2_body->mac));
  110. fprintf(file, "MSG2 sig_rl - ");
  111. PRINT_BYTE_ARRAY(file, &(p_msg2_body->sig_rl),
  112. p_msg2_body->sig_rl_size);
  113. }
  114. else if(response->type == TYPE_RA_ATT_RESULT)
  115. {
  116. sample_ra_att_result_msg_t *p_att_result =
  117. (sample_ra_att_result_msg_t *)(response->body);
  118. fprintf(file, "ATTESTATION RESULT MSG platform_info_blob - ");
  119. PRINT_BYTE_ARRAY(file, &(p_att_result->platform_info_blob),
  120. sizeof(p_att_result->platform_info_blob));
  121. fprintf(file, "ATTESTATION RESULT MSG mac - ");
  122. PRINT_BYTE_ARRAY(file, &(p_att_result->mac), sizeof(p_att_result->mac));
  123. fprintf(file, "ATTESTATION RESULT MSG secret.payload_tag - %u bytes\n",
  124. p_att_result->secret.payload_size);
  125. fprintf(file, "ATTESTATION RESULT MSG secret.payload - ");
  126. PRINT_BYTE_ARRAY(file, p_att_result->secret.payload,
  127. p_att_result->secret.payload_size);
  128. }
  129. else
  130. {
  131. fprintf(file, "\nERROR in printing out the response. "
  132. "Response of type not supported %d\n", response->type);
  133. }
  134. }
  135. // This sample code doesn't have any recovery/retry mechanisms for the remote
  136. // attestation. Since the enclave can be lost due S3 transitions, apps
  137. // susceptible to S3 transitions should have logic to restart attestation in
  138. // these scenarios.
  139. #define _T(x) x
  140. int main(int argc, char* argv[])
  141. {
  142. int ret = 0;
  143. ra_samp_request_header_t *p_msg0_full = NULL;
  144. ra_samp_response_header_t *p_msg0_resp_full = NULL;
  145. ra_samp_request_header_t *p_msg1_full = NULL;
  146. ra_samp_response_header_t *p_msg2_full = NULL;
  147. sgx_ra_msg3_t *p_msg3 = NULL;
  148. ra_samp_response_header_t* p_att_result_msg_full = NULL;
  149. sgx_enclave_id_t enclave_id = 0;
  150. int enclave_lost_retry_time = 1;
  151. int busy_retry_time = 4;
  152. sgx_ra_context_t context = INT_MAX;
  153. sgx_status_t status = SGX_SUCCESS;
  154. ra_samp_request_header_t* p_msg3_full = NULL;
  155. int32_t verify_index = -1;
  156. int32_t verification_samples = sizeof(msg1_samples)/sizeof(msg1_samples[0]);
  157. FILE* OUTPUT = stdout;
  158. #define VERIFICATION_INDEX_IS_VALID() (verify_index > 0 && \
  159. verify_index <= verification_samples)
  160. #define GET_VERIFICATION_ARRAY_INDEX() (verify_index-1)
  161. if(argc > 1)
  162. {
  163. verify_index = atoi(argv[1]);
  164. if( VERIFICATION_INDEX_IS_VALID())
  165. {
  166. fprintf(OUTPUT, "\nVerifying precomputed attestation messages "
  167. "using precomputed values# %d\n", verify_index);
  168. }
  169. else
  170. {
  171. fprintf(OUTPUT, "\nValid invocations are:\n");
  172. fprintf(OUTPUT, "\n\tisv_app\n");
  173. fprintf(OUTPUT, "\n\tisv_app <verification index>\n");
  174. fprintf(OUTPUT, "\nValid indices are [1 - %d]\n",
  175. verification_samples);
  176. fprintf(OUTPUT, "\nUsing a verification index uses precomputed "
  177. "messages to assist debugging the remote attestation "
  178. "service provider.\n");
  179. return -1;
  180. }
  181. }
  182. // Preparation for remote attestation by configuring extended epid group id.
  183. {
  184. uint32_t extended_epid_group_id = 0;
  185. ret = sgx_get_extended_epid_group_id(&extended_epid_group_id);
  186. if (SGX_SUCCESS != ret)
  187. {
  188. ret = -1;
  189. fprintf(OUTPUT, "\nError, call sgx_get_extended_epid_group_id fail [%s].",
  190. __FUNCTION__);
  191. return ret;
  192. }
  193. fprintf(OUTPUT, "\nCall sgx_get_extended_epid_group_id success.");
  194. p_msg0_full = (ra_samp_request_header_t*)
  195. malloc(sizeof(ra_samp_request_header_t)
  196. +sizeof(uint32_t));
  197. if (NULL == p_msg0_full)
  198. {
  199. ret = -1;
  200. goto CLEANUP;
  201. }
  202. p_msg0_full->type = TYPE_RA_MSG0;
  203. p_msg0_full->size = sizeof(uint32_t);
  204. *(uint32_t*)((uint8_t*)p_msg0_full + sizeof(ra_samp_request_header_t)) = extended_epid_group_id;
  205. {
  206. fprintf(OUTPUT, "\nMSG0 body generated -\n");
  207. PRINT_BYTE_ARRAY(OUTPUT, p_msg0_full->body, p_msg0_full->size);
  208. }
  209. // The ISV application sends msg0 to the SP.
  210. // The ISV decides whether to support this extended epid group id.
  211. fprintf(OUTPUT, "\nSending msg0 to remote attestation service provider.\n");
  212. ret = ra_network_send_receive("http://SampleServiceProvider.intel.com/",
  213. p_msg0_full,
  214. &p_msg0_resp_full);
  215. if (ret != 0)
  216. {
  217. fprintf(OUTPUT, "\nError, ra_network_send_receive for msg0 failed "
  218. "[%s].", __FUNCTION__);
  219. goto CLEANUP;
  220. }
  221. fprintf(OUTPUT, "\nSent MSG0 to remote attestation service.\n");
  222. }
  223. // Remote attestation will be initiated the ISV server challenges the ISV
  224. // app or if the ISV app detects it doesn't have the credentials
  225. // (shared secret) from a previous attestation required for secure
  226. // communication with the server.
  227. {
  228. // ISV application creates the ISV enclave.
  229. int launch_token_update = 0;
  230. sgx_launch_token_t launch_token = {0};
  231. memset(&launch_token, 0, sizeof(sgx_launch_token_t));
  232. do
  233. {
  234. ret = sgx_create_enclave(_T(ENCLAVE_PATH),
  235. SGX_DEBUG_FLAG,
  236. &launch_token,
  237. &launch_token_update,
  238. &enclave_id, NULL);
  239. if(SGX_SUCCESS != ret)
  240. {
  241. ret = -1;
  242. fprintf(OUTPUT, "\nError, call sgx_create_enclave fail [%s].",
  243. __FUNCTION__);
  244. goto CLEANUP;
  245. }
  246. fprintf(OUTPUT, "\nCall sgx_create_enclave success.");
  247. ret = enclave_init_ra(enclave_id,
  248. &status,
  249. false,
  250. &context);
  251. //Ideally, this check would be around the full attestation flow.
  252. } while (SGX_ERROR_ENCLAVE_LOST == ret && enclave_lost_retry_time--);
  253. if(SGX_SUCCESS != ret || status)
  254. {
  255. ret = -1;
  256. fprintf(OUTPUT, "\nError, call enclave_init_ra fail [%s].",
  257. __FUNCTION__);
  258. goto CLEANUP;
  259. }
  260. fprintf(OUTPUT, "\nCall enclave_init_ra success.");
  261. // isv application call uke sgx_ra_get_msg1
  262. p_msg1_full = (ra_samp_request_header_t*)
  263. malloc(sizeof(ra_samp_request_header_t)
  264. + sizeof(sgx_ra_msg1_t));
  265. if(NULL == p_msg1_full)
  266. {
  267. ret = -1;
  268. goto CLEANUP;
  269. }
  270. p_msg1_full->type = TYPE_RA_MSG1;
  271. p_msg1_full->size = sizeof(sgx_ra_msg1_t);
  272. do
  273. {
  274. ret = sgx_ra_get_msg1(context, enclave_id, sgx_ra_get_ga,
  275. (sgx_ra_msg1_t*)((uint8_t*)p_msg1_full
  276. + sizeof(ra_samp_request_header_t)));
  277. sleep(3); // Wait 3s between retries
  278. } while (SGX_ERROR_BUSY == ret && busy_retry_time--);
  279. if(SGX_SUCCESS != ret)
  280. {
  281. ret = -1;
  282. fprintf(OUTPUT, "\nError, call sgx_ra_get_msg1 fail [%s].",
  283. __FUNCTION__);
  284. goto CLEANUP;
  285. }
  286. else
  287. {
  288. fprintf(OUTPUT, "\nCall sgx_ra_get_msg1 success.\n");
  289. fprintf(OUTPUT, "\nMSG1 body generated -\n");
  290. PRINT_BYTE_ARRAY(OUTPUT, p_msg1_full->body, p_msg1_full->size);
  291. }
  292. if(VERIFICATION_INDEX_IS_VALID())
  293. {
  294. memcpy_s(p_msg1_full->body, p_msg1_full->size,
  295. msg1_samples[GET_VERIFICATION_ARRAY_INDEX()],
  296. p_msg1_full->size);
  297. fprintf(OUTPUT, "\nInstead of using the recently generated MSG1, "
  298. "we will use the following precomputed MSG1 -\n");
  299. PRINT_BYTE_ARRAY(OUTPUT, p_msg1_full->body, p_msg1_full->size);
  300. }
  301. // The ISV application sends msg1 to the SP to get msg2,
  302. // msg2 needs to be freed when no longer needed.
  303. // The ISV decides whether to use linkable or unlinkable signatures.
  304. fprintf(OUTPUT, "\nSending msg1 to remote attestation service provider."
  305. "Expecting msg2 back.\n");
  306. ret = ra_network_send_receive("http://SampleServiceProvider.intel.com/",
  307. p_msg1_full,
  308. &p_msg2_full);
  309. if(ret != 0 || !p_msg2_full)
  310. {
  311. fprintf(OUTPUT, "\nError, ra_network_send_receive for msg1 failed "
  312. "[%s].", __FUNCTION__);
  313. if(VERIFICATION_INDEX_IS_VALID())
  314. {
  315. fprintf(OUTPUT, "\nBecause we are in verification mode we will "
  316. "ignore this error.\n");
  317. fprintf(OUTPUT, "\nInstead, we will pretend we received the "
  318. "following MSG2 - \n");
  319. SAFE_FREE(p_msg2_full);
  320. ra_samp_response_header_t* precomputed_msg2 =
  321. (ra_samp_response_header_t*)msg2_samples[
  322. GET_VERIFICATION_ARRAY_INDEX()];
  323. const size_t msg2_full_size = sizeof(ra_samp_response_header_t)
  324. + precomputed_msg2->size;
  325. p_msg2_full =
  326. (ra_samp_response_header_t*)malloc(msg2_full_size);
  327. if(NULL == p_msg2_full)
  328. {
  329. ret = -1;
  330. goto CLEANUP;
  331. }
  332. memcpy_s(p_msg2_full, msg2_full_size, precomputed_msg2,
  333. msg2_full_size);
  334. PRINT_BYTE_ARRAY(OUTPUT, p_msg2_full,
  335. sizeof(ra_samp_response_header_t)
  336. + p_msg2_full->size);
  337. }
  338. else
  339. {
  340. goto CLEANUP;
  341. }
  342. }
  343. else
  344. {
  345. // Successfully sent msg1 and received a msg2 back.
  346. // Time now to check msg2.
  347. if(TYPE_RA_MSG2 != p_msg2_full->type)
  348. {
  349. fprintf(OUTPUT, "\nError, didn't get MSG2 in response to MSG1. "
  350. "[%s].", __FUNCTION__);
  351. if(VERIFICATION_INDEX_IS_VALID())
  352. {
  353. fprintf(OUTPUT, "\nBecause we are in verification mode we "
  354. "will ignore this error.");
  355. }
  356. else
  357. {
  358. goto CLEANUP;
  359. }
  360. }
  361. fprintf(OUTPUT, "\nSent MSG1 to remote attestation service "
  362. "provider. Received the following MSG2:\n");
  363. PRINT_BYTE_ARRAY(OUTPUT, p_msg2_full,
  364. sizeof(ra_samp_response_header_t)
  365. + p_msg2_full->size);
  366. fprintf(OUTPUT, "\nA more descriptive representation of MSG2:\n");
  367. PRINT_ATTESTATION_SERVICE_RESPONSE(OUTPUT, p_msg2_full);
  368. if( VERIFICATION_INDEX_IS_VALID() )
  369. {
  370. // The response should match the precomputed MSG2:
  371. ra_samp_response_header_t* precomputed_msg2 =
  372. (ra_samp_response_header_t *)
  373. msg2_samples[GET_VERIFICATION_ARRAY_INDEX()];
  374. if(MSG2_BODY_SIZE !=
  375. sizeof(ra_samp_response_header_t) + p_msg2_full->size ||
  376. memcmp( precomputed_msg2, p_msg2_full,
  377. sizeof(ra_samp_response_header_t) + p_msg2_full->size))
  378. {
  379. fprintf(OUTPUT, "\nVerification ERROR. Our precomputed "
  380. "value for MSG2 does NOT match.\n");
  381. fprintf(OUTPUT, "\nPrecomputed value for MSG2:\n");
  382. PRINT_BYTE_ARRAY(OUTPUT, precomputed_msg2,
  383. sizeof(ra_samp_response_header_t)
  384. + precomputed_msg2->size);
  385. fprintf(OUTPUT, "\nA more descriptive representation "
  386. "of precomputed value for MSG2:\n");
  387. PRINT_ATTESTATION_SERVICE_RESPONSE(OUTPUT,
  388. precomputed_msg2);
  389. }
  390. else
  391. {
  392. fprintf(OUTPUT, "\nVerification COMPLETE. Remote "
  393. "attestation service provider generated a "
  394. "matching MSG2.\n");
  395. }
  396. }
  397. }
  398. sgx_ra_msg2_t* p_msg2_body = (sgx_ra_msg2_t*)((uint8_t*)p_msg2_full
  399. + sizeof(ra_samp_response_header_t));
  400. uint32_t msg3_size = 0;
  401. if( VERIFICATION_INDEX_IS_VALID())
  402. {
  403. // We cannot generate a valid MSG3 using the precomputed messages
  404. // we have been using. We will use the precomputed msg3 instead.
  405. msg3_size = MSG3_BODY_SIZE;
  406. p_msg3 = (sgx_ra_msg3_t*)malloc(msg3_size);
  407. if(NULL == p_msg3)
  408. {
  409. ret = -1;
  410. goto CLEANUP;
  411. }
  412. memcpy_s(p_msg3, msg3_size,
  413. msg3_samples[GET_VERIFICATION_ARRAY_INDEX()], msg3_size);
  414. fprintf(OUTPUT, "\nBecause MSG1 was a precomputed value, the MSG3 "
  415. "we use will also be. PRECOMPUTED MSG3 - \n");
  416. }
  417. else
  418. {
  419. busy_retry_time = 2;
  420. // The ISV app now calls uKE sgx_ra_proc_msg2,
  421. // The ISV app is responsible for freeing the returned p_msg3!!
  422. do
  423. {
  424. ret = sgx_ra_proc_msg2(context,
  425. enclave_id,
  426. sgx_ra_proc_msg2_trusted,
  427. sgx_ra_get_msg3_trusted,
  428. p_msg2_body,
  429. p_msg2_full->size,
  430. &p_msg3,
  431. &msg3_size);
  432. } while (SGX_ERROR_BUSY == ret && busy_retry_time--);
  433. if(!p_msg3)
  434. {
  435. fprintf(OUTPUT, "\nError, call sgx_ra_proc_msg2 fail. "
  436. "p_msg3 = 0x%p [%s].", p_msg3, __FUNCTION__);
  437. ret = -1;
  438. goto CLEANUP;
  439. }
  440. if(SGX_SUCCESS != (sgx_status_t)ret)
  441. {
  442. fprintf(OUTPUT, "\nError, call sgx_ra_proc_msg2 fail. "
  443. "ret = 0x%08x [%s].", ret, __FUNCTION__);
  444. ret = -1;
  445. goto CLEANUP;
  446. }
  447. else
  448. {
  449. fprintf(OUTPUT, "\nCall sgx_ra_proc_msg2 success.\n");
  450. fprintf(OUTPUT, "\nMSG3 - \n");
  451. }
  452. }
  453. PRINT_BYTE_ARRAY(OUTPUT, p_msg3, msg3_size);
  454. p_msg3_full = (ra_samp_request_header_t*)malloc(
  455. sizeof(ra_samp_request_header_t) + msg3_size);
  456. if(NULL == p_msg3_full)
  457. {
  458. ret = -1;
  459. goto CLEANUP;
  460. }
  461. p_msg3_full->type = TYPE_RA_MSG3;
  462. p_msg3_full->size = msg3_size;
  463. if(memcpy_s(p_msg3_full->body, msg3_size, p_msg3, msg3_size))
  464. {
  465. fprintf(OUTPUT,"\nError: INTERNAL ERROR - memcpy failed in [%s].",
  466. __FUNCTION__);
  467. ret = -1;
  468. goto CLEANUP;
  469. }
  470. // The ISV application sends msg3 to the SP to get the attestation
  471. // result message, attestation result message needs to be freed when
  472. // no longer needed. The ISV service provider decides whether to use
  473. // linkable or unlinkable signatures. The format of the attestation
  474. // result is up to the service provider. This format is used for
  475. // demonstration. Note that the attestation result message makes use
  476. // of both the MK for the MAC and the SK for the secret. These keys are
  477. // established from the SIGMA secure channel binding.
  478. ret = ra_network_send_receive("http://SampleServiceProvider.intel.com/",
  479. p_msg3_full,
  480. &p_att_result_msg_full);
  481. if(ret || !p_att_result_msg_full)
  482. {
  483. ret = -1;
  484. fprintf(OUTPUT, "\nError, sending msg3 failed [%s].", __FUNCTION__);
  485. goto CLEANUP;
  486. }
  487. sample_ra_att_result_msg_t * p_att_result_msg_body =
  488. (sample_ra_att_result_msg_t *)((uint8_t*)p_att_result_msg_full
  489. + sizeof(ra_samp_response_header_t));
  490. if(TYPE_RA_ATT_RESULT != p_att_result_msg_full->type)
  491. {
  492. ret = -1;
  493. fprintf(OUTPUT, "\nError. Sent MSG3 successfully, but the message "
  494. "received was NOT of type att_msg_result. Type = "
  495. "%d. [%s].", p_att_result_msg_full->type,
  496. __FUNCTION__);
  497. goto CLEANUP;
  498. }
  499. else
  500. {
  501. fprintf(OUTPUT, "\nSent MSG3 successfully. Received an attestation "
  502. "result message back\n.");
  503. if( VERIFICATION_INDEX_IS_VALID() )
  504. {
  505. if(ATTESTATION_MSG_BODY_SIZE != p_att_result_msg_full->size ||
  506. memcmp(p_att_result_msg_full->body,
  507. attestation_msg_samples[GET_VERIFICATION_ARRAY_INDEX()],
  508. p_att_result_msg_full->size) )
  509. {
  510. fprintf(OUTPUT, "\nSent MSG3 successfully. Received an "
  511. "attestation result message back that did "
  512. "NOT match the expected value.\n");
  513. fprintf(OUTPUT, "\nEXPECTED ATTESTATION RESULT -");
  514. PRINT_BYTE_ARRAY(OUTPUT,
  515. attestation_msg_samples[GET_VERIFICATION_ARRAY_INDEX()],
  516. ATTESTATION_MSG_BODY_SIZE);
  517. }
  518. }
  519. }
  520. fprintf(OUTPUT, "\nATTESTATION RESULT RECEIVED - ");
  521. PRINT_BYTE_ARRAY(OUTPUT, p_att_result_msg_full->body,
  522. p_att_result_msg_full->size);
  523. if( VERIFICATION_INDEX_IS_VALID() )
  524. {
  525. fprintf(OUTPUT, "\nBecause we used precomputed values for the "
  526. "messages, the attestation result message will "
  527. "not pass further verification tests, so we will "
  528. "skip them.\n");
  529. goto CLEANUP;
  530. }
  531. // Check the MAC using MK on the attestation result message.
  532. // The format of the attestation result message is ISV specific.
  533. // This is a simple form for demonstration. In a real product,
  534. // the ISV may want to communicate more information.
  535. ret = verify_att_result_mac(enclave_id,
  536. &status,
  537. context,
  538. (uint8_t*)&p_att_result_msg_body->platform_info_blob,
  539. sizeof(ias_platform_info_blob_t),
  540. (uint8_t*)&p_att_result_msg_body->mac,
  541. sizeof(sgx_mac_t));
  542. if((SGX_SUCCESS != ret) ||
  543. (SGX_SUCCESS != status))
  544. {
  545. ret = -1;
  546. fprintf(OUTPUT, "\nError: INTEGRITY FAILED - attestation result "
  547. "message MK based cmac failed in [%s].",
  548. __FUNCTION__);
  549. goto CLEANUP;
  550. }
  551. bool attestation_passed = true;
  552. // Check the attestation result for pass or fail.
  553. // Whether attestation passes or fails is a decision made by the ISV Server.
  554. // When the ISV server decides to trust the enclave, then it will return success.
  555. // When the ISV server decided to not trust the enclave, then it will return failure.
  556. if(0 != p_att_result_msg_full->status[0]
  557. || 0 != p_att_result_msg_full->status[1])
  558. {
  559. fprintf(OUTPUT, "\nError, attestation result message MK based cmac "
  560. "failed in [%s].", __FUNCTION__);
  561. attestation_passed = false;
  562. }
  563. // The attestation result message should contain a field for the Platform
  564. // Info Blob (PIB). The PIB is returned by attestation server in the attestation report.
  565. // It is not returned in all cases, but when it is, the ISV app
  566. // should pass it to the blob analysis API called sgx_report_attestation_status()
  567. // along with the trust decision from the ISV server.
  568. // The ISV application will take action based on the update_info.
  569. // returned in update_info by the API.
  570. // This call is stubbed out for the sample.
  571. //
  572. // sgx_update_info_bit_t update_info;
  573. // ret = sgx_report_attestation_status(
  574. // &p_att_result_msg_body->platform_info_blob,
  575. // attestation_passed ? 0 : 1, &update_info);
  576. // Get the shared secret sent by the server using SK (if attestation
  577. // passed)
  578. if(attestation_passed)
  579. {
  580. ret = put_secret_data(enclave_id,
  581. &status,
  582. context,
  583. p_att_result_msg_body->secret.payload,
  584. p_att_result_msg_body->secret.payload_size,
  585. p_att_result_msg_body->secret.payload_tag);
  586. if((SGX_SUCCESS != ret) || (SGX_SUCCESS != status))
  587. {
  588. fprintf(OUTPUT, "\nError, attestation result message secret "
  589. "using SK based AESGCM failed in [%s]. ret = "
  590. "0x%0x. status = 0x%0x", __FUNCTION__, ret,
  591. status);
  592. goto CLEANUP;
  593. }
  594. }
  595. fprintf(OUTPUT, "\nSecret successfully received from server.");
  596. fprintf(OUTPUT, "\nRemote attestation success!");
  597. }
  598. CLEANUP:
  599. // Clean-up
  600. // Need to close the RA key state.
  601. if(INT_MAX != context)
  602. {
  603. int ret_save = ret;
  604. ret = enclave_ra_close(enclave_id, &status, context);
  605. if(SGX_SUCCESS != ret || status)
  606. {
  607. ret = -1;
  608. fprintf(OUTPUT, "\nError, call enclave_ra_close fail [%s].",
  609. __FUNCTION__);
  610. }
  611. else
  612. {
  613. // enclave_ra_close was successful, let's restore the value that
  614. // led us to this point in the code.
  615. ret = ret_save;
  616. }
  617. fprintf(OUTPUT, "\nCall enclave_ra_close success.");
  618. }
  619. sgx_destroy_enclave(enclave_id);
  620. ra_free_network_response_buffer(p_msg0_resp_full);
  621. ra_free_network_response_buffer(p_msg2_full);
  622. ra_free_network_response_buffer(p_att_result_msg_full);
  623. // p_msg3 is malloc'd by the untrusted KE library. App needs to free.
  624. SAFE_FREE(p_msg3);
  625. SAFE_FREE(p_msg3_full);
  626. SAFE_FREE(p_msg1_full);
  627. SAFE_FREE(p_msg0_full);
  628. printf("\nEnter a character before exit ...\n");
  629. getchar();
  630. return ret;
  631. }