endpoint_select_info.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. /*
  2. * Copyright (C) 2011-2017 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 "endpoint_select_info.h"
  32. #include "PVEClass.h"
  33. #include "prov_msg_size.h"
  34. #include "network_encoding_wrapper.h"
  35. #include "ipp_wrapper.h"
  36. #include "sgx_tcrypto.h"
  37. #include "ippcp.h"
  38. #include "ippcore.h"
  39. #include "aesm_xegd_blob.h"
  40. #include "peksk_pub.hh"
  41. #include "sgx_read_rand.h"
  42. #include <time.h>
  43. //Function to do basic checking of the endpoint selection blob. Esp to avoid no zero-ending in the input string url
  44. static bool is_valid_endpoint_selection_info(const endpoint_selection_infos_t& es_info)
  45. {
  46. if(es_info.aesm_data_type != AESM_DATA_ENDPOINT_SELECTION_INFOS)
  47. return false;
  48. if(es_info.aesm_data_version != AESM_DATA_ENDPOINT_SELECTION_VERSION)
  49. return false;
  50. if(strnlen(es_info.provision_url,MAX_PATH)>=MAX_PATH)
  51. return false;
  52. return true;
  53. }
  54. ae_error_t EndpointSelectionInfo::read_pek(endpoint_selection_infos_t& es_info)
  55. {
  56. ae_error_t ae_err=AE_SUCCESS;
  57. uint32_t es_info_size = sizeof(es_info);
  58. ae_err = aesm_read_data(FT_PERSISTENT_STORAGE, PROVISION_PEK_BLOB_FID, reinterpret_cast<uint8_t *>(&es_info), &es_info_size);
  59. if(AE_SUCCESS == ae_err && (es_info_size != sizeof(es_info)||!is_valid_endpoint_selection_info(es_info))){
  60. AESM_DBG_ERROR("Invalid ES result in persistent storage:size %d, expected size %d", es_info_size, sizeof(es_info));
  61. ae_err = OAL_FILE_ACCESS_ERROR;
  62. }
  63. if(AE_SUCCESS == ae_err){
  64. AESM_DBG_INFO("Read ES result from persistent storage successfully");
  65. }else{
  66. AESM_DBG_WARN("ES result in persistent storage failed to load:%d", ae_err);
  67. }
  68. return ae_err;
  69. }
  70. ae_error_t EndpointSelectionInfo::write_pek(const endpoint_selection_infos_t& es_info)
  71. {
  72. return aesm_write_data(FT_PERSISTENT_STORAGE, PROVISION_PEK_BLOB_FID, reinterpret_cast<const uint8_t *>(&es_info), sizeof(es_info));
  73. }
  74. static ae_error_t ipp_error_to_ae_error(IppStatus ipp_status)
  75. {
  76. if(ipp_status == ippStsNoErr) return AE_SUCCESS;
  77. else if(ipp_status == ippStsMemAllocErr||
  78. ipp_status == ippStsNoMemErr) return AE_OUT_OF_MEMORY_ERROR;
  79. else return AE_FAILURE;//unknown or unexpected ipp error
  80. }
  81. static bool is_valid_server_url_infos(const aesm_server_url_infos_t& server_urls)
  82. {
  83. if(server_urls.aesm_data_type!=AESM_DATA_SERVER_URL_INFOS||
  84. (server_urls.aesm_data_version!=AESM_DATA_SERVER_URL_VERSION&&
  85. server_urls.aesm_data_version != AESM_DATA_SERVER_URL_VERSION_1))//still support version 1 since the first 3 urls in version 1 is still same as the urls in version 2
  86. return false;
  87. if(strnlen(server_urls.endpoint_url,MAX_PATH)>=MAX_PATH)
  88. return false;
  89. if (strnlen(server_urls.pse_rl_url, MAX_PATH) >= MAX_PATH)
  90. return false;
  91. if (strnlen(server_urls.pse_ocsp_url, MAX_PATH) >= MAX_PATH)
  92. return false;
  93. return true;
  94. }
  95. ae_error_t EndpointSelectionInfo::verify_file_by_xgid(uint32_t xgid)
  96. {
  97. if (xgid == DEFAULT_EGID){//always return true for DEFAULT_EGID
  98. return AE_SUCCESS;
  99. }
  100. aesm_server_url_infos_t urls;
  101. uint32_t server_urls_size = sizeof(urls);
  102. ae_error_t ae_err = aesm_read_data(FT_PERSISTENT_STORAGE, AESM_SERVER_URL_FID, reinterpret_cast<uint8_t *>(&urls), &server_urls_size, xgid);
  103. if (AE_SUCCESS != ae_err ||
  104. server_urls_size != sizeof(urls) ||
  105. !is_valid_server_url_infos(urls)){
  106. return OAL_CONFIG_FILE_ERROR;
  107. }
  108. return AE_SUCCESS;
  109. }
  110. //Function to read urls from configure files
  111. ae_error_t EndpointSelectionInfo::get_url_info()
  112. {
  113. ae_error_t ae_err=AE_SUCCESS;
  114. uint32_t server_urls_size = sizeof(_server_urls);
  115. ae_err = aesm_read_data(FT_PERSISTENT_STORAGE, AESM_SERVER_URL_FID, reinterpret_cast<uint8_t *>(&_server_urls), &server_urls_size, AESMLogic::get_active_extended_epid_group_id());
  116. if(AE_SUCCESS != ae_err ||
  117. server_urls_size != sizeof(_server_urls)||
  118. !is_valid_server_url_infos(_server_urls)){ //If fail to read or data format error, use default value
  119. _is_server_url_valid = false;
  120. if(AE_SUCCESS == ae_err){//File available but format error, report ERROR LOG
  121. AESM_LOG_WARN("Server URL Blob file format error");
  122. AESM_DBG_INFO("fail to read server url info from persistent storage, error code (%d), size %d, expected size %d",
  123. ae_err, server_urls_size, sizeof(_server_urls));
  124. ae_err = OAL_CONFIG_FILE_ERROR;
  125. }else{
  126. AESM_DBG_INFO("server url blob file not available in persistent storage");
  127. }
  128. if (AESMLogic::get_active_extended_epid_group_id() == DEFAULT_EGID){
  129. if (strcpy_s(_server_urls.endpoint_url, MAX_PATH, DEFAULT_URL) != 0)
  130. return AE_FAILURE;
  131. if (strcpy_s(_server_urls.pse_rl_url, MAX_PATH, DEFAULT_PSE_RL_URL) != 0)
  132. return AE_FAILURE;
  133. if (strcpy_s(_server_urls.pse_ocsp_url, MAX_PATH, DEFAULT_PSE_OCSP_URL) != 0)
  134. return AE_FAILURE;
  135. _is_server_url_valid = true;
  136. return AE_SUCCESS;
  137. }
  138. else{
  139. return ae_err;
  140. }
  141. }
  142. _is_server_url_valid = true;
  143. return AE_SUCCESS;
  144. }
  145. ae_error_t EndpointSelectionInfo::get_url_info(aesm_server_url_infos_t& server_url)
  146. {
  147. AESMLogicLock lock(_es_lock);
  148. if (!_is_server_url_valid){
  149. (void)get_url_info();
  150. }
  151. if (_is_server_url_valid)
  152. {
  153. if (memcpy_s(&server_url, sizeof(server_url), &_server_urls, sizeof(_server_urls)) != 0){
  154. return AE_FAILURE;
  155. }
  156. }
  157. else
  158. {
  159. return AE_FAILURE;
  160. }
  161. return AE_SUCCESS;
  162. }
  163. ae_error_t aesm_check_pek_signature(const signed_pek_t& signed_pek, const extended_epid_group_blob_t& xegb);
  164. IppStatus get_provision_server_rsa_pub_key_in_ipp_format(const signed_pek_t& pek, IppsRSAPublicKeyState **rsa_pub_key);
  165. //The function is to verify the PEK ECDSA Signature and RSA Signature for ES Msg2
  166. // When PvE uses PEK, it will re-check the ECDSA Signature
  167. //The function will only be called after ES protocol is completed. But it will not be called when reading data back from persitent storage
  168. //@param provision_ttl: The TTL field from ES Msg2 in little endian format
  169. //@param rsa_signature: The RSA Signature in ES Msg2, it is RSA Signature to XID:TTL:provision_url
  170. //@param xid: The transaction id (XID) of the ES Protocol
  171. //@return AE_SUCCESS if signature verification success and passed
  172. //@return PVE_MSG_ERROR if signature verification failed or message error
  173. //other kinds of error code could be returned too due to corresponding error situation
  174. ae_error_t EndpointSelectionInfo::verify_signature(const endpoint_selection_infos_t& es_info, uint8_t xid[XID_SIZE], uint8_t rsa_signature[PVE_RSA_KEY_BYTES], uint16_t provision_ttl)
  175. {
  176. //Do signature verification here
  177. ae_error_t ae_err = AE_SUCCESS;
  178. IppsRSAPublicKeyState *rsa_pub_key = NULL;
  179. Ipp8u *buffer = NULL;
  180. int public_key_buffer_size = 0;
  181. int vr = 0;
  182. uint16_t ttl=_htons(provision_ttl);
  183. IppStatus ipp_status = ippStsNoErr;
  184. uint8_t msg_buf[XID_SIZE + sizeof(ttl) + MAX_PATH];
  185. uint32_t buf_size = 0;
  186. extended_epid_group_blob_t xegb;
  187. memset(&xegb, 0, sizeof(xegb));
  188. if (AE_SUCCESS != (ae_err=XEGDBlob::instance().read(xegb))){
  189. return ae_err;
  190. }
  191. ae_err = aesm_check_pek_signature(es_info.pek, xegb);
  192. if(AE_SUCCESS != ae_err){
  193. AESM_DBG_ERROR("PEK Signature verifcation not passed:%d",ae_err);
  194. goto ret_point;
  195. }
  196. AESM_DBG_INFO("PEK signature verified successfully");
  197. buf_size = XID_SIZE +static_cast<uint32_t>(sizeof(ttl) + strnlen(es_info.provision_url, MAX_PATH));
  198. if(0!=memcpy_s(msg_buf,sizeof(msg_buf), xid, XID_SIZE)||
  199. 0!=memcpy_s(msg_buf+XID_SIZE, sizeof(ttl) + MAX_PATH, &ttl, sizeof(ttl))||
  200. 0!=memcpy_s(msg_buf+XID_SIZE+sizeof(ttl), MAX_PATH, es_info.provision_url, buf_size-XID_SIZE-sizeof(ttl))){
  201. ae_err = AE_FAILURE;
  202. AESM_DBG_ERROR("memcpy error");
  203. goto ret_point;
  204. }
  205. ipp_status = get_provision_server_rsa_pub_key_in_ipp_format(es_info.pek, &rsa_pub_key);
  206. if(ippStsNoErr != ipp_status){
  207. AESM_DBG_ERROR("Fail to load rsa public key from PEK:%d", ipp_status);
  208. ae_err = ipp_error_to_ae_error(ipp_status);
  209. goto ret_point;
  210. }
  211. ipp_status = ippsRSA_GetBufferSizePublicKey(&public_key_buffer_size, rsa_pub_key);
  212. if(ippStsNoErr != ipp_status){
  213. AESM_DBG_ERROR("Fail to get rsa public key size:%s", ipp_status);
  214. ae_err = ipp_error_to_ae_error(ipp_status);
  215. goto ret_point;
  216. }
  217. buffer = (Ipp8u *)malloc(public_key_buffer_size);
  218. if(NULL == buffer){
  219. AESM_DBG_ERROR("malloc error");
  220. ae_err = AE_OUT_OF_MEMORY_ERROR;
  221. goto ret_point;
  222. }
  223. ipp_status = ippsRSAVerify_PKCS1v15(msg_buf, buf_size, rsa_signature, &vr, rsa_pub_key, ippHashAlg_SHA256, buffer);
  224. if(ippStsNoErr != ipp_status){
  225. AESM_DBG_ERROR("Fail to verify rsa signature:%d", ipp_status);
  226. ae_err = ipp_error_to_ae_error(ipp_status);
  227. goto ret_point;
  228. }
  229. if(vr == 0){
  230. AESM_DBG_TRACE("rsa signature verification failed");
  231. ae_err = PVE_MSG_ERROR;
  232. goto ret_point;
  233. }else{
  234. AESM_DBG_TRACE("rsa signature verification passed");
  235. ae_err = AE_SUCCESS;
  236. }
  237. ret_point:
  238. if(NULL != rsa_pub_key){
  239. secure_free_rsa_pub_key(PVE_RSA_KEY_BYTES, sizeof(uint32_t), rsa_pub_key);
  240. }
  241. if(NULL != buffer){
  242. free(buffer);
  243. }
  244. return ae_err;
  245. }
  246. #define MAX_ENCLAVE_LOST_RETRY_TIME 1
  247. bool read_aesm_config(aesm_config_infos_t& infos);
  248. //Function to implement the end point selection protocol
  249. ae_error_t EndpointSelectionInfo::start_protocol(endpoint_selection_infos_t& es_info)
  250. {
  251. AESMLogicLock lock(_es_lock);
  252. uint32_t msg_size = 0;
  253. uint8_t *resp = NULL;
  254. uint32_t resp_size = 0;
  255. uint16_t provision_ttl = 0;
  256. uint8_t *msg = NULL;
  257. uint8_t rsa_signature[PVE_RSA_KEY_BYTES];
  258. gen_endpoint_selection_output_t enclave_output;
  259. ae_error_t ae_ret = AE_SUCCESS;
  260. uint32_t enclave_lost_count = 0;
  261. AESM_DBG_DEBUG("enter fun");
  262. memset(&es_info, 0, sizeof(es_info));
  263. memset(&enclave_output, 0, sizeof(enclave_output));
  264. if(!_is_server_url_valid){
  265. ae_ret = get_url_info();
  266. if(AE_SUCCESS != ae_ret){//It is not likely happen, only fail when memcpy_s failed
  267. AESM_DBG_ERROR("Fail to initialize server URL information");
  268. goto final_point;
  269. }
  270. }
  271. do{
  272. if((ae_ret = CPVEClass::instance().load_enclave())!=AE_SUCCESS){
  273. AESM_DBG_ERROR("Fail to load PVE enclave:%d", ae_ret);
  274. goto final_point;
  275. }
  276. //call PvE to generate the partition and xid
  277. ae_ret = static_cast<ae_error_t>(CPVEClass::instance().gen_es_msg1_data(&enclave_output));
  278. if(ae_ret == AE_ENCLAVE_LOST&& (++enclave_lost_count)<=MAX_ENCLAVE_LOST_RETRY_TIME ){
  279. CPVEClass::instance().unload_enclave();//unload and reload PvE when enclave lost encountered
  280. continue;
  281. }else if(ae_ret == AE_SUCCESS){
  282. break;
  283. }else{
  284. AESM_DBG_ERROR("fail to generate parition by PvE");
  285. goto final_point;
  286. }
  287. }while(1);
  288. AESM_DBG_TRACE("use parition %d from PvE", (int)enclave_output.selector_id);
  289. AESM_DBG_INFO("Connect to server url \"%s\" for endpoint selection", _server_urls.endpoint_url);
  290. msg_size = estimate_es_msg1_size();
  291. assert(msg_size>0);
  292. msg = static_cast<uint8_t *>(malloc(msg_size));
  293. if(msg == NULL){
  294. AESM_DBG_ERROR("malloc error");
  295. ae_ret = AE_OUT_OF_MEMORY_ERROR;
  296. goto final_point;
  297. }
  298. memset(msg, 0, msg_size);
  299. ae_ret = static_cast<ae_error_t>(CPVEClass::instance().gen_es_msg1(msg, msg_size, enclave_output));//Generate EndPoint Selection Msg1
  300. if(ae_ret != AE_SUCCESS){
  301. AESM_DBG_ERROR("ES msg1 generation failed:%d",ae_ret);
  302. goto final_point;
  303. }
  304. AESM_DBG_TRACE("ES msg1 generated");
  305. ae_ret = AESMNetworkEncoding::aesm_send_recv_msg_encoding(_server_urls.endpoint_url, msg, msg_size, resp, resp_size);//Encoding/send/receive/Decoding
  306. if(ae_ret != AE_SUCCESS){
  307. AESM_DBG_ERROR("fail to send ES msg1 to backend server:%d",ae_ret);
  308. if(OAL_PROXY_SETTING_ASSIST == ae_ret){//when proxy setting assistant required, return directly
  309. goto final_point;
  310. }
  311. if(read_pek(es_info)==AE_SUCCESS){
  312. ae_ret = AE_SUCCESS;//use es_info inside persistent storage and ignore network error
  313. }
  314. goto final_point;
  315. }
  316. assert(resp != NULL);
  317. AESM_DBG_TRACE("start to process ES msg2");
  318. ae_ret = static_cast<ae_error_t>(CPVEClass::instance().proc_es_msg2(resp, resp_size, es_info.provision_url, provision_ttl, enclave_output.xid, rsa_signature , es_info.pek));
  319. if(AE_SUCCESS != ae_ret){
  320. AESM_DBG_WARN("Fail to process ES msg2 from backend server:%d",ae_ret);
  321. goto final_point;
  322. }
  323. AESM_DBG_TRACE("ES Msg2 decoded successfully, ttl %ds",provision_ttl);
  324. ae_ret = verify_signature(es_info, enclave_output.xid, rsa_signature, provision_ttl);
  325. if(AE_SUCCESS != ae_ret){
  326. AESM_DBG_WARN("Signature verification in ES Msg2 failed");
  327. goto final_point;
  328. }
  329. AESM_DBG_TRACE("Signature in ES Msg2 verified");
  330. es_info.aesm_data_type = AESM_DATA_ENDPOINT_SELECTION_INFOS;
  331. es_info.aesm_data_version = AESM_DATA_ENDPOINT_SELECTION_VERSION;
  332. (void)write_pek(es_info);//ignore file writing error
  333. AESM_DBG_TRACE("end point selection succ, provisioning url: %s",es_info.provision_url);
  334. final_point:
  335. if(msg!=NULL)free(msg);
  336. if(resp!=NULL){
  337. AESMNetworkEncoding::aesm_free_response_msg(resp);
  338. }
  339. return ae_ret;
  340. }
  341. const char *EndpointSelectionInfo::get_server_url(aesm_network_server_enum_type_t type)
  342. {
  343. AESMLogicLock lock(_es_lock);
  344. if (type == SGX_WHITE_LIST_FILE){
  345. if (!_is_white_list_url_valid){
  346. (void)read_aesm_config(_config_urls);
  347. _is_white_list_url_valid = true;
  348. }
  349. return _config_urls.white_list_url;
  350. }
  351. if(!_is_server_url_valid){
  352. (void)get_url_info();
  353. }
  354. if(!_is_server_url_valid){
  355. return NULL;
  356. }
  357. switch(type){
  358. case ENDPOINT_SELECTION:
  359. return _server_urls.endpoint_url;
  360. case REVOCATION_LIST_RETRIEVAL:
  361. return _server_urls.pse_rl_url;
  362. case PSE_OCSP:
  363. return _server_urls.pse_ocsp_url;
  364. default://invalid case
  365. assert(0);
  366. return NULL;
  367. }
  368. }
  369. void EndpointSelectionInfo::get_proxy(uint32_t& proxy_type, char proxy_url[MAX_PATH])
  370. {
  371. AESMLogicLock lock(_es_lock);
  372. if(!_is_white_list_url_valid){
  373. (void)read_aesm_config(_config_urls);
  374. _is_white_list_url_valid=true;
  375. }
  376. proxy_type = _config_urls.proxy_type;
  377. strcpy_s(proxy_url, MAX_PATH, _config_urls.aesm_proxy);
  378. }
  379. const char *EndpointSelectionInfo::get_pse_provisioning_url(const endpoint_selection_infos_t& es_info)
  380. {
  381. return es_info.provision_url;
  382. }