qe_logic.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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 "aesm_epid_blob.h"
  32. #include "aesm_xegd_blob.h"
  33. #include "qe_logic.h"
  34. #include "pve_logic.h"
  35. #include "aesm_logic.h"
  36. #include "PVEClass.h"
  37. #include "QEClass.h"
  38. #include "se_sig_rl.h"
  39. #include "se_quote_internal.h"
  40. #include "se_wrapper.h"
  41. #include "prof_fun.h"
  42. #include "util.h"
  43. static ae_error_t get_qe_target(sgx_target_info_t *p_qe_target)
  44. {
  45. ae_error_t ae_ret = AE_SUCCESS;
  46. if((ae_ret = CQEClass::instance().load_enclave())!=AE_SUCCESS)
  47. {
  48. AESM_DBG_ERROR("Fail to load QE:(ae%d)",ae_ret);
  49. return ae_ret;
  50. }
  51. ae_ret = static_cast<ae_error_t>(CQEClass::instance().get_qe_target(p_qe_target));
  52. if(ae_ret != AE_SUCCESS)
  53. return ae_ret;
  54. return AE_SUCCESS;
  55. }
  56. //Function to do reprovision if flag updated is false and set it to true if updated successfully
  57. //The flag updated is used to simpilify logic in caller's code so that provision will not be invoked again
  58. //if a previous provision has been successfully run
  59. //After reprovision, the output epid_blob will be copied into output parameter epid_data
  60. static aesm_error_t try_reprovision_if_not(bool& updated, epid_blob_with_cur_psvn_t& epid_data)
  61. {
  62. aesm_error_t aesm_result;
  63. ae_error_t ae_ret;
  64. if(updated){
  65. // We've just got a EPID blob. It's a rare case to reach here.
  66. // No retry, just return error.
  67. AESM_DBG_ERROR("try to reprovision again after another provision");
  68. return AESM_EPIDBLOB_ERROR;
  69. }
  70. // The EPID blob is corrupted, and we've not provisioned yet, then
  71. // we need to start the provision process.
  72. if((aesm_result = PvEAESMLogic::provision(false, THREAD_TIMEOUT))!=AESM_SUCCESS){
  73. AESM_DBG_ERROR("pve provision failed:(aesm%d)", aesm_result);
  74. return aesm_result;
  75. }
  76. updated = true;
  77. // Update the epid blob after a successful provisioning.
  78. if((ae_ret = EPIDBlob::instance().read(epid_data))!=AE_SUCCESS){
  79. AESM_DBG_ERROR("read epid blob failed:(ae%d)", ae_ret);
  80. return AESM_EPIDBLOB_ERROR;
  81. }
  82. return AESM_SUCCESS;
  83. }
  84. //Function to fetch gid from Epid Data Blob and also return target info
  85. //EPID Provisioning will be redone if Epid Data Blob is not existing/invalid or
  86. // the qe_isv_svn or cpu_svn don't match that in Epid Data Blob
  87. aesm_error_t QEAESMLogic::init_quote(
  88. sgx_target_info_t *target,
  89. uint8_t *gid, uint32_t gid_size, uint16_t pce_isv_svn,
  90. uint16_t qe_isv_svn, const sgx_cpu_svn_t qe_cpu_svn)
  91. {
  92. ae_error_t ae_ret = AE_SUCCESS;
  93. EPIDBlob& epid_blob = EPIDBlob::instance();
  94. AESM_DBG_DEBUG("enter fun");
  95. aesm_error_t aesm_result = AESM_UNEXPECTED_ERROR;
  96. AESM_PROFILE_FUN;
  97. epid_blob_with_cur_psvn_t epid_data;
  98. bool resealed = false;
  99. bool updated = false;
  100. memset(&epid_data,0,sizeof(epid_data));
  101. uint32_t xegd_xeid = AESMLogic::get_active_extended_epid_group_id();
  102. AESM_DBG_TRACE("start read and verify old epid blob");
  103. uint32_t epid_xeid = 0;
  104. //EPID BLOB not exist
  105. if ((ae_ret = epid_blob.read(epid_data)) != AE_SUCCESS ){
  106. if (AESM_SUCCESS != (aesm_result = try_reprovision_if_not(updated, epid_data))){
  107. goto ret_point;
  108. }
  109. }
  110. //ExtEPIDGroupID not match
  111. else if ((ae_ret = epid_blob.get_extended_epid_group_id(&epid_xeid)) == AE_SUCCESS &&
  112. xegd_xeid != epid_xeid)
  113. {
  114. (void)epid_blob.remove();
  115. if (AESM_SUCCESS != (aesm_result = try_reprovision_if_not(updated, epid_data))){
  116. goto ret_point;
  117. }
  118. }
  119. if((ae_ret = CQEClass::instance().load_enclave())!=AE_SUCCESS)
  120. {
  121. AESM_DBG_ERROR("Fail to load QE:(ae%d)", ae_ret);
  122. if(ae_ret == AESM_AE_OUT_OF_EPC)
  123. aesm_result = AESM_OUT_OF_EPC;
  124. else
  125. aesm_result = AESM_UNEXPECTED_ERROR;
  126. goto ret_point;
  127. }
  128. se_static_assert(SGX_TRUSTED_EPID_BLOB_SIZE_SDK>=SGX_TRUSTED_EPID_BLOB_SIZE_SIK);
  129. ae_ret = static_cast<ae_error_t>(CQEClass::instance().verify_blob(epid_data.trusted_epid_blob,
  130. SGX_TRUSTED_EPID_BLOB_SIZE_SDK,
  131. &resealed));
  132. if(ae_ret == QE_EPIDBLOB_ERROR){
  133. (void)epid_blob.remove();
  134. if(AESM_SUCCESS!=(aesm_result = try_reprovision_if_not(updated, epid_data))){
  135. goto ret_point;
  136. }
  137. }
  138. else if(ae_ret == AESM_AE_OUT_OF_EPC)
  139. {
  140. aesm_result = AESM_OUT_OF_EPC;
  141. goto ret_point;
  142. }
  143. else if(ae_ret != AE_SUCCESS)
  144. {
  145. aesm_result = AESM_UNEXPECTED_ERROR;
  146. goto ret_point;
  147. }
  148. // Assert the size of GID, we have already checked it in upper level.
  149. assert(sizeof(uint32_t) == gid_size);
  150. UNUSED(gid_size);
  151. ae_ret = get_qe_target(target);
  152. if(ae_ret!=AE_SUCCESS){
  153. AESM_DBG_ERROR("get qe target failed (ae%d)",ae_ret);
  154. if(ae_ret==AESM_AE_OUT_OF_EPC)
  155. aesm_result = AESM_OUT_OF_EPC;
  156. else
  157. aesm_result = AESM_UNEXPECTED_ERROR;
  158. goto ret_point;
  159. }
  160. AESM_DBG_TRACE("get qe_target flags:%llx xfrm:%llx",
  161. target->attributes.flags, target->attributes.xfrm);
  162. //Any Quoting enclave related code must be before this section to avoid QE/PvE unloading each other
  163. //do the upgrade reprovision after all Quoting Enclave works
  164. AESM_DBG_TRACE("qe_isv_svn %d, epid_isv_svn %d",qe_isv_svn, epid_data.cur_pi.pve_svn);
  165. if((qe_isv_svn > epid_data.cur_pi.pve_svn)
  166. || (pce_isv_svn > epid_data.cur_pi.pce_svn)
  167. || (0!=memcmp(&qe_cpu_svn, &epid_data.cur_pi.cpu_svn,
  168. sizeof(sgx_cpu_svn_t))))
  169. {
  170. if(AESM_SUCCESS == (aesm_result = try_reprovision_if_not(updated, epid_data))){
  171. resealed = false;
  172. }else if(AESM_PROXY_SETTING_ASSIST == aesm_result ||
  173. AESM_BUSY == aesm_result ||
  174. AESM_UPDATE_AVAILABLE == aesm_result ){//we should not ignore the three special error
  175. goto ret_point;
  176. }
  177. }
  178. //Any Quoting enclave related code must be before this section to avoid QE/PvE unloading each other */
  179. aesm_result = AESM_SUCCESS;
  180. ret_point:
  181. if(aesm_result == AESM_SUCCESS){
  182. if (resealed) {
  183. AESM_DBG_TRACE("Update epid blob");
  184. if ((ae_ret = epid_blob.write(epid_data)) != AE_SUCCESS) {
  185. AESM_DBG_WARN("Fail to update epid blob:(ae%d)", ae_ret);
  186. }
  187. }
  188. if (AE_SUCCESS != EPIDBlob::instance().get_sgx_gid((uint32_t*)gid)) {
  189. aesm_result = AESM_UNEXPECTED_ERROR;
  190. }
  191. else {
  192. AESM_DBG_TRACE("get gid %d from epid blob (little-endian)",
  193. *(uint32_t*)gid);
  194. }
  195. }
  196. return aesm_result;
  197. }
  198. /* Assuming buffer size is checked before calling this function, and get_quote
  199. in QE will also check size. */
  200. aesm_error_t QEAESMLogic::get_quote(const uint8_t *report,
  201. uint32_t quote_type,
  202. const uint8_t *spid,
  203. const uint8_t *nonce,
  204. const uint8_t *sigrl, uint32_t sigrl_size,
  205. uint8_t *qe_report,
  206. uint8_t *quote, uint32_t buf_size, uint16_t pce_isv_svn)
  207. {
  208. epid_blob_with_cur_psvn_t epid_data;
  209. uint32_t ae_ret = AE_SUCCESS;
  210. aesm_error_t aesm_result = AESM_UNEXPECTED_ERROR;
  211. EPIDBlob& epid_blob = EPIDBlob::instance();
  212. AESM_PROFILE_FUN;
  213. memset(&epid_data, 0, sizeof(epid_data));
  214. AESM_DBG_TRACE("start to read and verify epid blob");
  215. if((ae_ret = epid_blob.read(epid_data))!=AE_SUCCESS){
  216. if((aesm_result = PvEAESMLogic::provision(false, THREAD_TIMEOUT))!=AESM_SUCCESS){
  217. AESM_DBG_ERROR("pve provision failed:(aesm%d)", aesm_result);
  218. goto CLEANUP;
  219. }
  220. }
  221. if((ae_ret = CQEClass::instance().load_enclave())!=AE_SUCCESS)
  222. {
  223. AESM_DBG_ERROR("load QE failed(ae%d)",ae_ret);
  224. if(ae_ret == AESM_AE_OUT_OF_EPC)
  225. aesm_result = AESM_OUT_OF_EPC;
  226. else
  227. aesm_result = AESM_UNEXPECTED_ERROR;
  228. goto CLEANUP;
  229. }
  230. AESM_DBG_TRACE("start to get quote");
  231. ae_ret = CQEClass::instance().get_quote(epid_data.trusted_epid_blob,
  232. SGX_TRUSTED_EPID_BLOB_SIZE_SDK,
  233. reinterpret_cast<const sgx_report_t *>(report),
  234. static_cast<sgx_quote_sign_type_t>(quote_type),
  235. reinterpret_cast<const sgx_spid_t *>(spid),
  236. reinterpret_cast<const sgx_quote_nonce_t *>(nonce),
  237. sigrl,
  238. sigrl_size,
  239. reinterpret_cast<sgx_report_t *>(qe_report),
  240. quote,
  241. buf_size, pce_isv_svn);
  242. if(ae_ret != AE_SUCCESS)
  243. {
  244. AESM_DBG_TRACE("get_quote failed:(ae%d)",ae_ret);
  245. if(ae_ret == QE_EPIDBLOB_ERROR)
  246. aesm_result = AESM_EPIDBLOB_ERROR;
  247. else if(ae_ret == QE_PARAMETER_ERROR)
  248. aesm_result = AESM_PARAMETER_ERROR;
  249. else if(ae_ret == QE_REVOKED_ERROR)
  250. aesm_result = AESM_EPID_REVOKED_ERROR;
  251. else
  252. aesm_result = AESM_UNEXPECTED_ERROR;
  253. goto CLEANUP;
  254. }
  255. AESM_DBG_TRACE("get quote succ");
  256. aesm_result = AESM_SUCCESS;
  257. CLEANUP:
  258. return aesm_result;
  259. }