qe_logic.cpp 10 KB

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