pse_op_logic.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. /*
  2. * Copyright (C) 2011-2018 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 "pse_op_logic.h"
  32. #include "aesm_logic.h"
  33. #include "PSEClass.h"
  34. #include "PSEPRClass.h"
  35. #include "aesm_long_lived_thread.h"
  36. #include "platform_info_logic.h"
  37. #include <assert.h>
  38. static aesm_error_t pse_ret_to_aesm_ret(ae_error_t ret_pse)
  39. {
  40. switch(ret_pse)
  41. {
  42. case AE_SUCCESS:
  43. return AESM_SUCCESS;
  44. case PSE_OP_PARAMETER_ERROR:
  45. return AESM_PARAMETER_ERROR;
  46. case PSE_OP_MAX_NUM_SESSION_REACHED:
  47. return AESM_MAX_NUM_SESSION_REACHED;
  48. case PSE_OP_SESSION_INVALID:
  49. return AESM_SESSION_INVALID;
  50. case PSE_OP_SERVICE_MSG_ERROR:
  51. return AESM_MSG_ERROR;
  52. case AESM_PSDA_NOT_AVAILABLE:
  53. return AESM_PSDA_UNAVAILABLE;
  54. case PSE_OP_ERROR_KDF_MISMATCH:
  55. return AESM_KDF_MISMATCH;
  56. default:
  57. return AESM_UNEXPECTED_ERROR;
  58. }
  59. }
  60. // Local helper function to log to the admin log based on error code
  61. // Note: In some cases, PSEOP functions also log PS errors directly
  62. static void log_admin_ps_ae(ae_error_t ae_error_code)
  63. {
  64. switch (ae_error_code)
  65. {
  66. case AE_SUCCESS:
  67. break;
  68. case PSE_OP_MAX_NUM_SESSION_REACHED:
  69. AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_RESOURCE_ERROR]);
  70. break;
  71. case PSE_OP_PARAMETER_ERROR:
  72. case PSE_OP_SESSION_INVALID:
  73. case PSE_OP_SERVICE_MSG_ERROR:
  74. case AESM_PSDA_NOT_AVAILABLE:
  75. default:
  76. AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_ERROR]);
  77. break;
  78. }
  79. }
  80. aesm_error_t PSEOPAESMLogic::get_ps_cap(
  81. uint64_t* ps_cap)
  82. {
  83. AESM_DBG_INFO("PSEOPAESMLogic::get_ps_cap");
  84. ae_error_t ret_pse = CPSEClass::instance().get_ps_cap(ps_cap);
  85. return pse_ret_to_aesm_ret(ret_pse);
  86. }
  87. // Get ready for PS service. Establish ephemeral session or long term pairing according to current
  88. // status. Update status accordingly.
  89. aesm_error_t PSEOPAESMLogic::prepare_for_ps_request(void)
  90. {
  91. AESM_DBG_INFO("PSEOPAESMLogic::prepare_for_ps_request");
  92. pse_status_t status = CPSEClass::instance().get_status();
  93. switch(status)
  94. {
  95. case PSE_STATUS_INIT:
  96. AESM_DBG_ERROR("unexpeted status PSE_STATUS_INIT");
  97. AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_CERT_ERROR]);
  98. return AESM_UNEXPECTED_ERROR;
  99. case PSE_STATUS_UNAVAILABLE:
  100. AESM_DBG_ERROR("status PSE_STATUS_UNAVAILABLE");
  101. AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_DAL_ERROR]);
  102. return AESM_PSDA_UNAVAILABLE;
  103. case PSE_STATUS_CSE_PROVISIONED:
  104. {
  105. AESM_DBG_TRACE("status PSE_STATUS_CSE_PROVISIONED");
  106. aesm_error_t ret = establish_ephemeral_session(false);
  107. // If PS is still not ready after trying to establish the ephemeral session, log a general
  108. // error. The PS_INIT_FAIL log will have more details, so we don't have to log them here.
  109. if (CPSEClass::instance().get_status() != PSE_STATUS_SERVICE_READY)
  110. AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_ERROR]);
  111. return ret;
  112. }
  113. case PSE_STATUS_SERVICE_READY:
  114. return AESM_SUCCESS;
  115. default:
  116. AESM_DBG_ERROR("unexpeted status %d", (int)status);
  117. return AESM_UNEXPECTED_ERROR;
  118. }
  119. }
  120. aesm_error_t PSEOPAESMLogic::create_session(
  121. uint32_t* session_id,
  122. uint8_t* se_dh_msg1, uint32_t se_dh_msg1_size)
  123. {
  124. aesm_error_t result = AESM_UNEXPECTED_ERROR;
  125. // prepare for service request
  126. result = prepare_for_ps_request();
  127. if (result != AESM_SUCCESS)
  128. return result;
  129. ae_error_t ret_pse = CPSEClass::instance().create_session(
  130. session_id,
  131. se_dh_msg1,
  132. se_dh_msg1_size);
  133. if (ret_pse == PSE_OP_EPHEMERAL_SESSION_INVALID)
  134. {
  135. AESM_DBG_ERROR("Ephemeral session is broken");
  136. // Ephemeral session is broken , re-establish ephemeral session and retry create_session.
  137. if ((result = establish_ephemeral_session(true)) != AESM_SUCCESS) {
  138. AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_ERROR]);
  139. return result;
  140. }
  141. AESM_DBG_INFO("create session again");
  142. ret_pse = CPSEClass::instance().create_session(
  143. session_id,
  144. se_dh_msg1,
  145. se_dh_msg1_size);
  146. }
  147. log_admin_ps_ae(ret_pse);
  148. return pse_ret_to_aesm_ret(ret_pse);
  149. }
  150. ae_error_t PSEOPAESMLogic::certificate_provisioning_and_long_term_pairing_func(bool& is_new_pairing)
  151. {
  152. ae_error_t psStatus = AE_SUCCESS;
  153. AESM_DBG_INFO("certificate_provisioning_and_long_term_pairing_func()");
  154. is_new_pairing = false;
  155. ae_error_t ltpStatus = CPSEPRClass::instance().long_term_pairing(&is_new_pairing);
  156. SGX_DBGPRINT_ONE_STRING_TWO_INTS_CREATE_SESSION(__FUNCTION__" ltpStatus = ", ltpStatus, __LINE__);
  157. switch (ltpStatus)
  158. {
  159. case AE_SUCCESS:
  160. case OAL_PROXY_SETTING_ASSIST:
  161. case AESM_AE_OUT_OF_EPC:
  162. return ltpStatus;
  163. // for below errors need to check cert status
  164. case AESM_NPC_NO_PSE_CERT:
  165. case AESM_LTP_PSE_CERT_REVOKED:
  166. case PSE_PAIRING_BLOB_UNSEALING_ERROR:
  167. case PSE_PAIRING_BLOB_INVALID_ERROR:
  168. case AESM_PSDA_LT_SESSION_INTEGRITY_ERROR:
  169. {
  170. ae_error_t pcphStatus = PlatformInfoLogic::pse_cert_provisioning_helper(NULL);
  171. switch (pcphStatus)
  172. {
  173. case OAL_NETWORK_UNAVAILABLE_ERROR:
  174. case OAL_PROXY_SETTING_ASSIST:
  175. case PSW_UPDATE_REQUIRED:
  176. case AESM_AE_OUT_OF_EPC:
  177. case AESM_PCP_PSE_CERT_PROVISIONING_ATTESTATION_FAILURE_MIGHT_NEED_EPID_UPDATE:
  178. case AESM_PCP_SIMPLE_PSE_CERT_PROVISIONING_ERROR:
  179. case AESM_PCP_SIMPLE_EPID_PROVISION_ERROR:
  180. case AESM_PCP_PSE_CERT_PROVISIONING_ATTESTATION_FAILURE_NEED_EPID_UPDATE:
  181. case AESM_PCP_NEED_PSE_UPDATE:
  182. return pcphStatus;
  183. case AE_SUCCESS:
  184. {
  185. //
  186. // retry one time
  187. //
  188. ltpStatus = CPSEPRClass::instance().long_term_pairing(&is_new_pairing);
  189. SGX_DBGPRINT_ONE_STRING_TWO_INTS_CREATE_SESSION(__FUNCTION__" ltpStatus = ", ltpStatus, __LINE__);
  190. switch (ltpStatus)
  191. {
  192. case AE_SUCCESS:
  193. case OAL_PROXY_SETTING_ASSIST:
  194. case AESM_AE_OUT_OF_EPC:
  195. case OAL_THREAD_TIMEOUT_ERROR:
  196. psStatus = ltpStatus;
  197. break;
  198. case AESM_NPC_NO_PSE_CERT:
  199. case AESM_LTP_PSE_CERT_REVOKED:
  200. {
  201. AESM_DBG_ERROR("long_term_pairing Return: 0x%X", ltpStatus);
  202. AESM_LOG_ERROR_UNICODE("%s", g_event_string_table[SGX_EVENT_LTP_FAILURE]);
  203. psStatus = AESM_LTP_SIMPLE_LTP_ERROR;
  204. break;
  205. }
  206. default:
  207. {
  208. psStatus = AESM_LTP_SIMPLE_LTP_ERROR;
  209. break;
  210. }
  211. }
  212. break;
  213. }
  214. default:
  215. {
  216. assert(false); break;
  217. }
  218. }
  219. break;
  220. }
  221. default:
  222. {
  223. psStatus = AESM_LTP_SIMPLE_LTP_ERROR;
  224. break;
  225. }
  226. }
  227. return psStatus;
  228. }
  229. static aesm_error_t redo_long_term_pairing(
  230. bool* is_new_pairing)
  231. {
  232. ae_error_t ae_ret = AE_FAILURE;
  233. ae_ret = start_long_term_pairing_thread(*is_new_pairing);
  234. switch (ae_ret)
  235. {
  236. case AE_SUCCESS:
  237. return AESM_SUCCESS;
  238. case OAL_THREAD_TIMEOUT_ERROR:
  239. return AESM_BUSY;
  240. case PVE_PROV_ATTEST_KEY_NOT_FOUND:
  241. return AESM_UNRECOGNIZED_PLATFORM;
  242. case OAL_PROXY_SETTING_ASSIST:
  243. return AESM_PROXY_SETTING_ASSIST;
  244. case PSW_UPDATE_REQUIRED:
  245. return AESM_UPDATE_AVAILABLE;
  246. case AESM_AE_OUT_OF_EPC:
  247. return AESM_OUT_OF_EPC;
  248. default:
  249. return AESM_LONG_TERM_PAIRING_FAILED;
  250. break;
  251. }
  252. }
  253. aesm_error_t PSEOPAESMLogic::establish_ephemeral_session(bool force_redo)
  254. {
  255. AESM_DBG_INFO("PSEOPAESMLogic::establish_ephemeral_session");
  256. ae_error_t ret = AE_SUCCESS;
  257. // If session already exists and force_redo is false, session is already ready
  258. if (force_redo == false && CPSEClass::instance().get_status() == PSE_STATUS_SERVICE_READY)
  259. return AESM_SUCCESS;
  260. AESM_LOG_INFO_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_START]);
  261. // establish ephemeral session
  262. // Note: Admin Logging of success/failure after this point is owned by create_ephemeral_session_pse_cse()
  263. ret = CPSEClass::instance().create_ephemeral_session_pse_cse(false, force_redo);
  264. // Attempt retry/recovery, where appropriate
  265. switch (ret)
  266. {
  267. case PSE_PAIRING_BLOB_UNSEALING_ERROR:
  268. case PSE_PAIRING_BLOB_INVALID_ERROR:
  269. case AESM_PSDA_NEED_REPAIRING:
  270. case PSE_OP_ERROR_EPH_SESSION_ESTABLISHMENT_INTEGRITY_ERROR:
  271. case PSE_OP_LTPB_SEALING_OUT_OF_DATE:
  272. {
  273. // Pairing blob doesn't exist or blob size is wrong
  274. // or pse-op fails to unseal pairing blob
  275. // or PSDA reports session integrity error
  276. // or pse-op reports session integrity error
  277. bool is_new_pairing = false;//out
  278. aesm_error_t retValue = AESM_SUCCESS;
  279. retValue = redo_long_term_pairing(&is_new_pairing);
  280. if (AESM_SUCCESS == retValue)
  281. {
  282. // retry ephemeral session
  283. ret = CPSEClass::instance().create_ephemeral_session_pse_cse(is_new_pairing, true);
  284. goto exit; // handle non retry results for both create_ephemeral_session_pse_cse() calls below
  285. }
  286. // else log failure, since we're returning here
  287. switch (retValue)
  288. {
  289. case AESM_SUCCESS: // handled above
  290. case AESM_BUSY: // don't log an error here
  291. break;
  292. case AESM_PROXY_SETTING_ASSIST: // don't log an error here
  293. break;
  294. case AESM_UPDATE_AVAILABLE:
  295. AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_FAIL_PSWVER]);
  296. break;
  297. case AESM_OUT_OF_EPC:
  298. AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_FAIL]);
  299. break;
  300. case AESM_LONG_TERM_PAIRING_FAILED:
  301. default:
  302. AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_FAIL_LTP]);
  303. break;
  304. }
  305. AESM_DBG_ERROR("Ephemeral session failed");
  306. return retValue;
  307. }
  308. default:
  309. goto exit; // handle non retry cases for both create_ephemeral_session_pse_cse() calls below
  310. }
  311. //All error code handled
  312. exit:
  313. // Log result of create_ephemeral_session_pse_cse() and map return value
  314. switch (ret)
  315. {
  316. case AE_SUCCESS:
  317. AESM_LOG_INFO_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_SUCCESS]);
  318. AESM_DBG_INFO("PSEOPAESMLogic::establish_ephemeral_session success");
  319. return AESM_SUCCESS;
  320. case AESM_AE_OUT_OF_EPC:
  321. AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_FAIL]);
  322. AESM_DBG_ERROR("Ephemeral session failed");
  323. return AESM_OUT_OF_EPC;
  324. case PSE_PAIRING_BLOB_UNSEALING_ERROR:
  325. case PSE_PAIRING_BLOB_INVALID_ERROR:
  326. case PSE_OP_ERROR_EPH_SESSION_ESTABLISHMENT_INTEGRITY_ERROR:
  327. case PSE_OP_LTPB_SEALING_OUT_OF_DATE:
  328. AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_FAIL_LTP]);
  329. AESM_DBG_ERROR("Ephemeral session failed");
  330. return AESM_EPH_SESSION_FAILED;
  331. case AESM_PSDA_NEED_REPAIRING:
  332. case AESM_PSDA_INTERNAL_ERROR:
  333. case AESM_PSDA_SESSION_LOST:
  334. // This is logged as an ERROR here, since we know the system is expecting PS capability at this point
  335. AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_FAIL_DAL]);
  336. AESM_DBG_ERROR("Ephemeral session failed");
  337. return AESM_EPH_SESSION_FAILED;
  338. case AE_FAILURE:
  339. case AE_OUT_OF_MEMORY_ERROR:
  340. default:
  341. AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_FAIL]);
  342. AESM_DBG_ERROR("Ephemeral session failed");
  343. return AESM_EPH_SESSION_FAILED;
  344. }
  345. }
  346. aesm_error_t PSEOPAESMLogic::exchange_report(
  347. uint32_t session_id,
  348. const uint8_t* se_dh_msg2, uint32_t se_dh_msg2_size,
  349. uint8_t* se_dh_msg3, uint32_t se_dh_msg3_size)
  350. {
  351. aesm_error_t ret = AESM_UNEXPECTED_ERROR;
  352. // prepare for service request
  353. ret = prepare_for_ps_request();
  354. if (ret != AESM_SUCCESS)
  355. return ret;
  356. ae_error_t ret_pse = CPSEClass::instance().exchange_report(
  357. session_id,
  358. const_cast<uint8_t *>(se_dh_msg2),se_dh_msg2_size,
  359. se_dh_msg3,se_dh_msg3_size);
  360. if (ret_pse == PSE_OP_EPHEMERAL_SESSION_INVALID)
  361. {
  362. AESM_DBG_ERROR("Ephemeral session is broken");
  363. // Ephemeral session is broken , re-establish ephemeral session and retry exchange_report.
  364. aesm_error_t result = AESM_UNEXPECTED_ERROR;
  365. if ((result = establish_ephemeral_session(true)) != AESM_SUCCESS) {
  366. AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_ERROR]);
  367. return result;
  368. }
  369. AESM_DBG_INFO("Exchange report again");
  370. // If CPSECLass:exchange_report() returned PSE_OP_EPHMERAL_SESSIOn_INVALID because PSE-Op loss,
  371. // the retry here will fail too, as the session is also lost when enclave is lost.
  372. ret_pse = CPSEClass::instance().exchange_report(
  373. session_id,
  374. const_cast<uint8_t *>(se_dh_msg2),se_dh_msg2_size,
  375. se_dh_msg3,se_dh_msg3_size);
  376. }
  377. log_admin_ps_ae(ret_pse);
  378. return pse_ret_to_aesm_ret(ret_pse);
  379. }
  380. aesm_error_t PSEOPAESMLogic::invoke_service(
  381. const uint8_t* pse_message_req, uint32_t pse_message_req_size,
  382. uint8_t* pse_message_resp, uint32_t pse_message_resp_size)
  383. {
  384. aesm_error_t result;
  385. // prepare for service request
  386. result = prepare_for_ps_request();
  387. if (result != AESM_SUCCESS)
  388. return result;
  389. ae_error_t ret_pse = CPSEClass::instance().invoke_service(
  390. const_cast<uint8_t *>(pse_message_req),pse_message_req_size,
  391. pse_message_resp,pse_message_resp_size);
  392. if (ret_pse == PSE_OP_EPHEMERAL_SESSION_INVALID || ret_pse == AESM_PSDA_SESSION_LOST)
  393. {
  394. AESM_DBG_ERROR("Ephemeral session is broken");
  395. // Ephemeral session is broken , re-establish ephemeral session and retry invoke_service.
  396. if ((result = establish_ephemeral_session(true)) != AESM_SUCCESS) {
  397. AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_ERROR]);
  398. return result;
  399. }
  400. AESM_DBG_INFO("Invoke service again");
  401. // If CPSECLass:invoke_service() returned PSE_OP_EPHEMERAL_SESSION_INVALID because PSE-Op loss,
  402. // the retry here will fail too, as the session is also lost when enclave is lost.
  403. ret_pse = CPSEClass::instance().invoke_service(
  404. const_cast<uint8_t *>(pse_message_req),pse_message_req_size,
  405. pse_message_resp,pse_message_resp_size);
  406. }
  407. log_admin_ps_ae(ret_pse);
  408. return pse_ret_to_aesm_ret(ret_pse);
  409. }
  410. aesm_error_t PSEOPAESMLogic::close_session(
  411. uint32_t session_id)
  412. {
  413. ae_error_t ret_pse = CPSEClass::instance().close_session(
  414. session_id);
  415. if (ret_pse == PSE_OP_EPHEMERAL_SESSION_INVALID)
  416. {
  417. AESM_DBG_ERROR("Ephemeral session is broken");
  418. // Ephemeral session is broken , re-establish ephemeral session
  419. aesm_error_t result = AESM_UNEXPECTED_ERROR;
  420. if ((result = establish_ephemeral_session(true)) != AESM_SUCCESS)
  421. return result;
  422. // Here PSE_OP_EPHEMERAL_SESSION_INVALID is returned only when power event occurs,
  423. // and the session is also lost when enclave is lost, so always return SUCCESS
  424. ret_pse = AE_SUCCESS;
  425. }
  426. return pse_ret_to_aesm_ret(ret_pse);
  427. }