qe_logic.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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 "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:%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:%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:%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:%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. if (AE_SUCCESS != EPIDBlob::instance().get_sgx_gid((uint32_t*) gid)) {
  152. aesm_result = AESM_UNEXPECTED_ERROR;
  153. goto ret_point;
  154. }
  155. AESM_DBG_TRACE("get gid %d from epid blob (little-endian)",
  156. *(uint32_t*) gid);
  157. ae_ret = get_qe_target(target);
  158. if(ae_ret!=AE_SUCCESS){
  159. AESM_DBG_ERROR("get qe target failed");
  160. if(ae_ret==AESM_AE_OUT_OF_EPC)
  161. aesm_result = AESM_OUT_OF_EPC;
  162. else
  163. aesm_result = AESM_UNEXPECTED_ERROR;
  164. goto ret_point;
  165. }
  166. AESM_DBG_TRACE("get qe_target flags:%llx xfrm:%llx",
  167. target->attributes.flags, target->attributes.xfrm);
  168. //Any Quoting enclave related code must be before this section to avoid QE/PvE unloading each other
  169. //do the upgrade reprovision after all Quoting Enclave works
  170. AESM_DBG_TRACE("qe_isv_svn %d, epid_isv_svn %d",qe_isv_svn, epid_data.cur_pi.pve_svn);
  171. if((qe_isv_svn > epid_data.cur_pi.pve_svn)
  172. || (pce_isv_svn > epid_data.cur_pi.pce_svn)
  173. || (0!=memcmp(&qe_cpu_svn, &epid_data.cur_pi.cpu_svn,
  174. sizeof(sgx_cpu_svn_t))))
  175. {
  176. if(AESM_SUCCESS == (aesm_result = try_reprovision_if_not(updated, epid_data))){
  177. resealed = false;
  178. }else if(AESM_PROXY_SETTING_ASSIST == aesm_result ||
  179. AESM_BUSY == aesm_result ||
  180. AESM_UPDATE_AVAILABLE == aesm_result ){//we should not ignore the three special error
  181. goto ret_point;
  182. }
  183. }
  184. //Any Quoting enclave related code must be before this section to avoid QE/PvE unloading each other */
  185. aesm_result = AESM_SUCCESS;
  186. ret_point:
  187. if(resealed && aesm_result == AESM_SUCCESS){
  188. AESM_DBG_TRACE("Update epid blob");
  189. if((ae_ret=epid_blob.write(epid_data))!=AE_SUCCESS){
  190. AESM_DBG_WARN("Fail to update epid blob:%d",ae_ret);
  191. }
  192. }
  193. return aesm_result;
  194. }
  195. /* Assuming buffer size is checked before calling this function, and get_quote
  196. in QE will also check size. */
  197. aesm_error_t QEAESMLogic::get_quote(const uint8_t *report,
  198. uint32_t quote_type,
  199. const uint8_t *spid,
  200. const uint8_t *nonce,
  201. const uint8_t *sigrl, uint32_t sigrl_size,
  202. uint8_t *qe_report,
  203. uint8_t *quote, uint32_t buf_size, uint16_t pce_isv_svn)
  204. {
  205. epid_blob_with_cur_psvn_t epid_data;
  206. uint32_t ae_ret = AE_SUCCESS;
  207. aesm_error_t aesm_result = AESM_UNEXPECTED_ERROR;
  208. EPIDBlob& epid_blob = EPIDBlob::instance();
  209. AESM_PROFILE_FUN;
  210. memset(&epid_data, 0, sizeof(epid_data));
  211. AESM_DBG_TRACE("start to read and verify epid blob");
  212. if((ae_ret = epid_blob.read(epid_data))!=AE_SUCCESS){
  213. if((aesm_result = PvEAESMLogic::provision(false, THREAD_TIMEOUT))!=AESM_SUCCESS){
  214. AESM_DBG_ERROR("pve provision failed:%d", aesm_result);
  215. goto CLEANUP;
  216. }
  217. }
  218. if((ae_ret = CQEClass::instance().load_enclave())!=AE_SUCCESS)
  219. {
  220. AESM_DBG_ERROR("load QE failed");
  221. if(ae_ret == AESM_AE_OUT_OF_EPC)
  222. aesm_result = AESM_OUT_OF_EPC;
  223. else
  224. aesm_result = AESM_UNEXPECTED_ERROR;
  225. goto CLEANUP;
  226. }
  227. AESM_DBG_TRACE("start to get quote");
  228. ae_ret = CQEClass::instance().get_quote(epid_data.trusted_epid_blob,
  229. SGX_TRUSTED_EPID_BLOB_SIZE_SDK,
  230. reinterpret_cast<const sgx_report_t *>(report),
  231. static_cast<sgx_quote_sign_type_t>(quote_type),
  232. reinterpret_cast<const sgx_spid_t *>(spid),
  233. reinterpret_cast<const sgx_quote_nonce_t *>(nonce),
  234. sigrl,
  235. sigrl_size,
  236. reinterpret_cast<sgx_report_t *>(qe_report),
  237. quote,
  238. buf_size, pce_isv_svn);
  239. if(ae_ret != AE_SUCCESS)
  240. {
  241. AESM_DBG_TRACE("get_quote failed:%d",ae_ret);
  242. if(ae_ret == QE_EPIDBLOB_ERROR)
  243. aesm_result = AESM_EPIDBLOB_ERROR;
  244. else if(ae_ret == QE_PARAMETER_ERROR)
  245. aesm_result = AESM_PARAMETER_ERROR;
  246. else if(ae_ret == QE_REVOKED_ERROR)
  247. aesm_result = AESM_EPID_REVOKED_ERROR;
  248. else
  249. aesm_result = AESM_UNEXPECTED_ERROR;
  250. goto CLEANUP;
  251. }
  252. AESM_DBG_TRACE("get quote succ");
  253. aesm_result = AESM_SUCCESS;
  254. CLEANUP:
  255. return aesm_result;
  256. }