qe_logic.cpp 9.3 KB

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