DRM_enclave.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  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. #include "DRM_enclave_t.h"
  32. #include "sgx_trts.h"
  33. #include "sgx_tseal.h"
  34. #include "sgx_tae_service.h"
  35. #include "string.h"
  36. #include "../include/sealed_data_defines.h"
  37. #define REPLAY_PROTECTED_SECRET_SIZE 32
  38. typedef struct _activity_log
  39. {
  40. uint32_t release_version;
  41. uint32_t max_release_version;
  42. }activity_log;
  43. typedef struct _replay_protected_pay_load
  44. {
  45. sgx_mc_uuid_t mc;
  46. uint32_t mc_value;
  47. uint8_t secret[REPLAY_PROTECTED_SECRET_SIZE];
  48. activity_log log;
  49. }replay_protected_pay_load;
  50. static uint32_t verify_mc(replay_protected_pay_load* data2verify)
  51. {
  52. uint32_t ret = 0;
  53. uint32_t mc_value;
  54. ret = sgx_read_monotonic_counter(&data2verify->mc,&mc_value);
  55. if(ret != SGX_SUCCESS)
  56. {
  57. switch(ret)
  58. {
  59. case SGX_ERROR_SERVICE_UNAVAILABLE:
  60. /* Architecture Enclave Service Manager is not installed or not
  61. working properly.*/
  62. break;
  63. case SGX_ERROR_SERVICE_TIMEOUT:
  64. /* retry the operation later*/
  65. break;
  66. case SGX_ERROR_BUSY:
  67. /* retry the operation later*/
  68. break;
  69. case SGX_ERROR_MC_NOT_FOUND:
  70. /* the the Monotonic Counter ID is invalid.*/
  71. break;
  72. default:
  73. /*other errors*/
  74. break;
  75. }
  76. }
  77. else if(mc_value!=data2verify->mc_value)
  78. {
  79. ret = REPLAY_DETECTED;
  80. }
  81. return ret;
  82. }
  83. static uint32_t verify_sealed_data(
  84. const sgx_sealed_data_t* data2unseal,
  85. replay_protected_pay_load* data_unsealed)
  86. {
  87. uint32_t ret = 0;
  88. replay_protected_pay_load temp_unseal;
  89. uint32_t unseal_length = sizeof(replay_protected_pay_load);
  90. ret = sgx_unseal_data(data2unseal, NULL, 0,
  91. (uint8_t*)&temp_unseal, &unseal_length);
  92. if(ret != SGX_SUCCESS)
  93. {
  94. switch(ret)
  95. {
  96. case SGX_ERROR_MAC_MISMATCH:
  97. /* MAC of the sealed data is incorrect.
  98. The sealed data has been tampered.*/
  99. break;
  100. case SGX_ERROR_INVALID_ATTRIBUTE:
  101. /*Indicates attribute field of the sealed data is incorrect.*/
  102. break;
  103. case SGX_ERROR_INVALID_ISVSVN:
  104. /* Indicates isv_svn field of the sealed data is greater than
  105. the enclave’s ISVSVN. This is a downgraded enclave.*/
  106. break;
  107. case SGX_ERROR_INVALID_CPUSVN:
  108. /* Indicates cpu_svn field of the sealed data is greater than
  109. the platform’s cpu_svn. enclave is on a downgraded platform.*/
  110. break;
  111. case SGX_ERROR_INVALID_KEYNAME:
  112. /*Indicates key_name field of the sealed data is incorrect.*/
  113. break;
  114. default:
  115. /*other errors*/
  116. break;
  117. }
  118. return ret;
  119. }
  120. ret = verify_mc(&temp_unseal);
  121. if (ret == SGX_SUCCESS)
  122. memcpy(data_unsealed,&temp_unseal,sizeof(replay_protected_pay_load));
  123. /* remember to clear secret data after been used by memset_s */
  124. memset_s(&temp_unseal, sizeof(replay_protected_pay_load), 0,
  125. sizeof(replay_protected_pay_load));
  126. return ret;
  127. }
  128. uint32_t create_sealed_policy(uint8_t* sealed_log, uint32_t sealed_log_size )
  129. {
  130. uint32_t ret = 0;
  131. int busy_retry_times = 2;
  132. replay_protected_pay_load data2seal;
  133. memset(&data2seal, 0, sizeof(data2seal));
  134. uint32_t size = sgx_calc_sealed_data_size(0,
  135. sizeof(replay_protected_pay_load));
  136. if(sealed_log_size != size)
  137. return SGX_ERROR_INVALID_PARAMETER;
  138. do{
  139. ret = sgx_create_pse_session();
  140. }while (ret == SGX_ERROR_BUSY && busy_retry_times--);
  141. if (ret != SGX_SUCCESS)
  142. return ret;
  143. do
  144. {
  145. ret = sgx_create_monotonic_counter(&data2seal.mc,&data2seal.mc_value);
  146. if(ret != SGX_SUCCESS)
  147. {
  148. switch(ret)
  149. {
  150. case SGX_ERROR_SERVICE_UNAVAILABLE:
  151. /* Architecture Enclave Service Manager is not installed or not
  152. working properly.*/
  153. break;
  154. case SGX_ERROR_SERVICE_TIMEOUT:
  155. /* retry the operation later*/
  156. break;
  157. case SGX_ERROR_BUSY:
  158. /* retry the operation later*/
  159. break;
  160. case SGX_ERROR_MC_OVER_QUOTA:
  161. /* SGX Platform Service enforces a quota scheme on the Monotonic
  162. Counters a SGX app can maintain. the enclave has reached the
  163. quota.*/
  164. break;
  165. case SGX_ERROR_MC_USED_UP:
  166. /* the Monotonic Counter has been used up and cannot create
  167. Monotonic Counter anymore.*/
  168. break;
  169. default:
  170. /*other errors*/
  171. break;
  172. }
  173. break;
  174. }
  175. /* secret should be provisioned into enclave after the enclave attests to
  176. the secret owner.
  177. For example, the server that delivers the encrypted DRM content.
  178. In this sample code, a random number is used to represent the secret */
  179. ret = sgx_read_rand(data2seal.secret, REPLAY_PROTECTED_SECRET_SIZE);
  180. if(ret != SGX_SUCCESS)
  181. break;
  182. data2seal.log.release_version = 0;
  183. /* the secret can be updated for 5 times */
  184. data2seal.log.max_release_version =
  185. REPLAY_PROTECTED_PAY_LOAD_MAX_RELEASE_VERSION;
  186. /*sealing the plaintext to ciphertext. The ciphertext can be delivered
  187. outside of enclave.*/
  188. ret = sgx_seal_data(0, NULL,sizeof(data2seal),(uint8_t*)&data2seal,
  189. sealed_log_size, (sgx_sealed_data_t*)sealed_log);
  190. } while (0);
  191. /* remember to clear secret data after been used by memset_s */
  192. memset_s(&data2seal, sizeof(replay_protected_pay_load), 0,
  193. sizeof(replay_protected_pay_load));
  194. sgx_close_pse_session();
  195. return ret;
  196. }
  197. uint32_t perform_sealed_policy(const uint8_t* sealed_log,
  198. uint32_t sealed_log_size)
  199. {
  200. uint32_t ret = 0;
  201. int busy_retry_times = 2;
  202. replay_protected_pay_load data_unsealed;
  203. if(sealed_log_size != sgx_calc_sealed_data_size(0,
  204. sizeof(replay_protected_pay_load)))
  205. return SGX_ERROR_INVALID_PARAMETER;
  206. do{
  207. ret = sgx_create_pse_session();
  208. }while (ret == SGX_ERROR_BUSY && busy_retry_times--);
  209. if (ret != SGX_SUCCESS)
  210. return ret;
  211. ret = verify_sealed_data((const sgx_sealed_data_t*) sealed_log,
  212. &data_unsealed);
  213. if (SGX_SUCCESS == ret)
  214. {
  215. /* release the secret to perform the requested functions,
  216. for example, decrypt the DRM content*/
  217. }
  218. else
  219. {
  220. /* activity log update fail to verify activity log,
  221. refuse to release the secret */
  222. }
  223. sgx_close_pse_session();
  224. /* remember to clear secret data after been used by memset_s */
  225. memset_s(&data_unsealed, sizeof(data_unsealed),
  226. 0, sizeof(replay_protected_pay_load) );
  227. return ret;
  228. }
  229. uint32_t update_sealed_policy(uint8_t* sealed_log, uint32_t sealed_log_size)
  230. {
  231. uint32_t ret = 0;
  232. int busy_retry_times = 2;
  233. replay_protected_pay_load data_unsealed;
  234. replay_protected_pay_load data2seal;
  235. if(sealed_log_size != sgx_calc_sealed_data_size(0,
  236. sizeof(replay_protected_pay_load)))
  237. return SGX_ERROR_INVALID_PARAMETER;
  238. do{
  239. ret = sgx_create_pse_session();
  240. }while (ret == SGX_ERROR_BUSY && busy_retry_times--);
  241. if (ret != SGX_SUCCESS)
  242. return ret;
  243. do
  244. {
  245. ret = verify_sealed_data((sgx_sealed_data_t*) sealed_log,
  246. &data_unsealed);
  247. if(ret != SGX_SUCCESS)
  248. break;
  249. memcpy(&data2seal,&data_unsealed, sizeof(replay_protected_pay_load));
  250. ret = sgx_increment_monotonic_counter(&data2seal.mc,
  251. &data2seal.mc_value);
  252. if(ret != SGX_SUCCESS)
  253. {
  254. switch(ret)
  255. {
  256. case SGX_ERROR_SERVICE_UNAVAILABLE:
  257. /* Architecture Enclave Service Manager is not installed or not
  258. working properly.*/
  259. break;
  260. case SGX_ERROR_SERVICE_TIMEOUT:
  261. /* retry the operation*/
  262. break;
  263. case SGX_ERROR_BUSY:
  264. /* retry the operation later*/
  265. break;
  266. case SGX_ERROR_MC_NOT_FOUND:
  267. /* The Monotonic Counter was deleted or invalidated.
  268. This might happen under certain conditions.
  269. For example, the Monotonic Counter has been deleted, the SGX
  270. Platform Service lost its data or the system is under attack. */
  271. break;
  272. case SGX_ERROR_MC_NO_ACCESS_RIGHT:
  273. /* The Monotonic Counter is not accessible by this enclave.
  274. This might happen under certain conditions.
  275. For example, the SGX Platform Service lost its data or the
  276. system is under attack. */
  277. break;
  278. default:
  279. /*other errors*/
  280. break;
  281. }
  282. break;
  283. }
  284. /* If the counter value returns doesn't match the expected value,
  285. some other entity has updated the counter, for example, another instance
  286. of this enclave. The system might be under attack */
  287. if(data2seal.mc_value!= data_unsealed.mc_value+1)
  288. {
  289. ret = REPLAY_DETECTED;
  290. break;
  291. }
  292. if(data2seal.log.release_version >= data2seal.log.max_release_version)
  293. {
  294. /* the max release version has reached, cannot update. Delete the
  295. monotonic_counter, whether the deleting is successful or not. */
  296. (void)sgx_destroy_monotonic_counter(&data2seal.mc);
  297. ret= MAX_RELEASE_REACHED;
  298. break;
  299. }
  300. /* next release versiona */
  301. data2seal.log.release_version++;
  302. /* release next data2seal.secret, here is a sample */
  303. for(int i = 0; i< REPLAY_PROTECTED_SECRET_SIZE; i++)
  304. data2seal.secret[i]++;
  305. /* seal the new log */
  306. ret = sgx_seal_data(0, NULL, sizeof(data2seal), (uint8_t*)&data2seal,
  307. sealed_log_size, (sgx_sealed_data_t*)sealed_log);
  308. } while (0);
  309. /* remember to clear secret data after been used by memset_s */
  310. memset_s(&data_unsealed, sizeof(replay_protected_pay_load), 0,
  311. sizeof(replay_protected_pay_load));
  312. /* remember to clear secret data after been used by memset_s */
  313. memset_s(&data2seal, sizeof(replay_protected_pay_load), 0,
  314. sizeof(replay_protected_pay_load));
  315. sgx_close_pse_session();
  316. return ret;
  317. }
  318. uint32_t delete_sealed_policy(const uint8_t* sealed_log,
  319. uint32_t sealed_log_size)
  320. {
  321. uint32_t ret = 0;
  322. int busy_retry_times = 2;
  323. replay_protected_pay_load data_unsealed;
  324. if(sealed_log_size != sgx_calc_sealed_data_size(0,
  325. sizeof(replay_protected_pay_load)))
  326. return SGX_ERROR_INVALID_PARAMETER;
  327. do{
  328. ret = sgx_create_pse_session();
  329. }while (ret == SGX_ERROR_BUSY && busy_retry_times--);
  330. if (ret != SGX_SUCCESS)
  331. return ret;
  332. do
  333. {
  334. ret = verify_sealed_data((const sgx_sealed_data_t*) sealed_log,
  335. &data_unsealed);
  336. if(ret != SGX_SUCCESS)
  337. break;
  338. ret = sgx_destroy_monotonic_counter(&data_unsealed.mc);
  339. if(ret != SGX_SUCCESS)
  340. {
  341. switch(ret)
  342. {
  343. case SGX_ERROR_SERVICE_UNAVAILABLE:
  344. /* Architecture Enclave Service Manager is not installed or not
  345. working properly.*/
  346. break;
  347. case SGX_ERROR_SERVICE_TIMEOUT:
  348. /* retry the operation later*/
  349. break;
  350. case SGX_ERROR_BUSY:
  351. /* retry the operation later*/
  352. break;
  353. case SGX_ERROR_MC_NOT_FOUND:
  354. /* the the Monotonic Counter ID is invalid.*/
  355. break;
  356. case SGX_ERROR_MC_NO_ACCESS_RIGHT:
  357. /* the Monotonic Counter is not accessible by this enclave.
  358. This might happen under certain conditions.
  359. For example, the SGX Platform Service lost its data or
  360. the system is under attack. */
  361. break;
  362. default:
  363. /*other errors*/
  364. break;
  365. }
  366. }
  367. } while (0);
  368. /* remember to clear secret data after been used by memset_s */
  369. memset_s(&data_unsealed, sizeof(replay_protected_pay_load), 0,
  370. sizeof(replay_protected_pay_load));
  371. sgx_close_pse_session();
  372. return ret;
  373. }
  374. /* The secret required to render service is stored together with the time based
  375. policy.If an attack tampered with or destroyed the time based policy data, the
  376. service won't be rendered */
  377. #define TIME_BASED_SECRET_SIZE 16
  378. typedef struct _time_based_pay_load
  379. {
  380. sgx_time_source_nonce_t nonce;
  381. sgx_time_t timestamp_base;
  382. uint8_t secret[TIME_BASED_SECRET_SIZE];
  383. sgx_time_t lease_duration;
  384. }time_based_pay_load;
  385. uint32_t create_time_based_policy(uint8_t* sealed_log,
  386. uint32_t sealed_log_size )
  387. {
  388. uint32_t ret = 0;
  389. int busy_retry_times = 2;
  390. time_based_pay_load payload2seal;
  391. memset(&payload2seal, 0, sizeof(time_based_pay_load));
  392. uint32_t size = sgx_calc_sealed_data_size(0,sizeof(payload2seal));
  393. if(sealed_log_size != size)
  394. return SGX_ERROR_INVALID_PARAMETER;
  395. do{
  396. ret = sgx_create_pse_session();
  397. }while (ret == SGX_ERROR_BUSY && busy_retry_times--);
  398. if (ret != SGX_SUCCESS)
  399. return ret;
  400. do
  401. {
  402. ret = sgx_get_trusted_time(&payload2seal.timestamp_base,
  403. &payload2seal.nonce);
  404. if(ret != SGX_SUCCESS)
  405. {
  406. switch(ret)
  407. {
  408. case SGX_ERROR_SERVICE_UNAVAILABLE:
  409. /* Architecture Enclave Service Manager is not installed or not
  410. working properly.*/
  411. break;
  412. case SGX_ERROR_SERVICE_TIMEOUT:
  413. /* retry the operation*/
  414. break;
  415. case SGX_ERROR_BUSY:
  416. /* retry the operation later*/
  417. break;
  418. default:
  419. /*other errors*/
  420. break;
  421. }
  422. break;
  423. }
  424. /*secret should be provisioned into enclave after the enclave attests to
  425. the secret owner, for example, the server that delivers the encrypted
  426. DRM content.
  427. In this sample code, a random number is used to represent the secret*/
  428. ret = sgx_read_rand(payload2seal.secret, TIME_BASED_SECRET_SIZE);
  429. if(ret != SGX_SUCCESS)
  430. break;
  431. payload2seal.lease_duration = TIME_BASED_LEASE_DURATION_SECOND;
  432. /* sead the pay load */
  433. ret = sgx_seal_data(0, NULL,
  434. sizeof(payload2seal), (uint8_t*)&payload2seal,
  435. sealed_log_size, (sgx_sealed_data_t*)sealed_log);
  436. }while(0);
  437. /* clear the plaintext secret after used */
  438. memset_s(&payload2seal, sizeof(payload2seal), 0,
  439. sizeof(time_based_pay_load));
  440. sgx_close_pse_session();
  441. return ret;
  442. }
  443. uint32_t perform_time_based_policy(const uint8_t* sealed_log,
  444. uint32_t sealed_log_size )
  445. {
  446. uint32_t ret = 0;
  447. int busy_retry_times = 2;
  448. time_based_pay_load unsealed_data;
  449. uint32_t data2seal_length = sizeof(time_based_pay_load);
  450. uint32_t size = sgx_calc_sealed_data_size(0,sizeof(time_based_pay_load));
  451. if(sealed_log_size != size)
  452. return SGX_ERROR_INVALID_PARAMETER;
  453. ret = sgx_unseal_data((const sgx_sealed_data_t*)sealed_log, NULL, 0,
  454. (uint8_t*)&unsealed_data, &data2seal_length);
  455. if(ret != SGX_SUCCESS)
  456. {
  457. switch(ret)
  458. {
  459. case SGX_ERROR_MAC_MISMATCH:
  460. /* MAC of the sealed data is incorrect. the sealed data has been
  461. tampered.*/
  462. break;
  463. case SGX_ERROR_INVALID_ATTRIBUTE:
  464. /*Indicates attribute field of the sealed data is incorrect.*/
  465. break;
  466. case SGX_ERROR_INVALID_ISVSVN:
  467. /* Indicates isv_svn field of the sealed data is greater than the
  468. enclave’s ISVSVN. This is a downgraded enclave.*/
  469. break;
  470. case SGX_ERROR_INVALID_CPUSVN:
  471. /* Indicates cpu_svn field of the sealed data is greater than the
  472. platform’s cpu_svn. enclave is on a downgraded platform.*/
  473. break;
  474. case SGX_ERROR_INVALID_KEYNAME:
  475. /*Indicates key_name field of the sealed data is incorrect.*/
  476. break;
  477. default:
  478. /*other errors*/
  479. break;
  480. }
  481. return ret;
  482. }
  483. do{
  484. ret = sgx_create_pse_session();
  485. }while (ret == SGX_ERROR_BUSY && busy_retry_times--);
  486. if (ret != SGX_SUCCESS)
  487. {
  488. memset_s(&unsealed_data, sizeof(unsealed_data), 0,
  489. sizeof(time_based_pay_load));
  490. return ret;
  491. }
  492. do
  493. {
  494. sgx_time_source_nonce_t nonce = {0};
  495. sgx_time_t current_timestamp;
  496. ret = sgx_get_trusted_time(&current_timestamp, &nonce);
  497. if(ret != SGX_SUCCESS)
  498. {
  499. switch(ret)
  500. {
  501. case SGX_ERROR_SERVICE_UNAVAILABLE:
  502. /* Architecture Enclave Service Manager is not installed or not
  503. working properly.*/
  504. break;
  505. case SGX_ERROR_SERVICE_TIMEOUT:
  506. /* retry the operation*/
  507. break;
  508. case SGX_ERROR_BUSY:
  509. /* retry the operation later*/
  510. break;
  511. default:
  512. /*other errors*/
  513. break;
  514. }
  515. break;
  516. }
  517. /*source nonce must be the same, otherwise time source is changed and
  518. the two timestamps are not comparable.*/
  519. if (memcmp(&nonce,&unsealed_data.nonce,
  520. sizeof(sgx_time_source_nonce_t)))
  521. {
  522. ret = TIMESOURCE_CHANGED;
  523. break;
  524. }
  525. /* This should not happen.
  526. SGX Platform service guarantees that the time stamp reading moves
  527. forward, unless the time source is changed.*/
  528. if(current_timestamp < unsealed_data.timestamp_base)
  529. {
  530. ret = TIMESTAMP_UNEXPECTED;
  531. break;
  532. }
  533. /*compare lease_duration and timestamp_diff
  534. if lease_duration is less than difference of current time and base time,
  535. lease tern has expired.*/
  536. if(current_timestamp - unsealed_data.timestamp_base >
  537. unsealed_data.lease_duration)
  538. {
  539. ret = LEASE_EXPIRED;
  540. break;
  541. }
  542. }while(0);
  543. if (SGX_SUCCESS == ret)
  544. {
  545. /* release the secret to render service, for example, decrypt the DRM
  546. content*/
  547. }
  548. else
  549. {
  550. /* The secret is not released. the service won't be rendered and the DRM
  551. content can be deleted.*/
  552. }
  553. /* clear the plaintext secret after used */
  554. memset_s(&unsealed_data, sizeof(unsealed_data), 0,
  555. sizeof(time_based_pay_load));
  556. sgx_close_pse_session();
  557. return ret;
  558. }