provision_msg4.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  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 "provision_msg.h"
  32. #include <sgx_trts.h>
  33. #include "protocol.h"
  34. #include "cipher.h"
  35. #include "sgx_tcrypto.h"
  36. #ifdef __cplusplus
  37. extern "C" {
  38. #endif
  39. #include "epid/member/software_member.h"
  40. #include "epid/member/src/write_precomp.h"
  41. #include "epid/member/src/signbasic.h"
  42. #include "epid/member/src/nrprove.h"
  43. #ifdef __cplusplus
  44. }
  45. #endif
  46. #include "epid/common/errors.h"
  47. #include "epid/member/api.h"
  48. #include "pve_hardcoded_tlv_data.h"
  49. #include "byte_order.h"
  50. #include "pek_pub_key.h"
  51. #include "pve_qe_common.h"
  52. #include <string.h>
  53. #include <stdlib.h>
  54. #include "util.h"
  55. /**
  56. * File: provision_msg4.cpp
  57. * Description: Provide the implementation of code to process data from ProvMsg4 and generate EPID Data Blob
  58. *
  59. * Core Code of Provision Enclave
  60. */
  61. //Function to verify and process ProvMsg4.field1_2 and decrypt mce to get f part of EPID Private Key by PSK
  62. // to generate PrivKey
  63. //@mce: input pointer to decrypted membership credential and escrow data
  64. //@msg4_input: input data decoded from ProvMsg4
  65. //@prv_key: output the EPID Private Key on success
  66. //@return PVEC_SUCCESS on success and error code otherwise
  67. static pve_status_t proc_prov_msg4_membercredential(const membership_credential_with_escrow_t *mce,
  68. const proc_prov_msg4_input_t * msg4_input,
  69. PrivKey& prv_key)
  70. {
  71. pve_status_t ret = PVEC_SUCCESS;
  72. sgx_status_t sgx_status = SGX_SUCCESS;
  73. sgx_key_128bit_t psk;
  74. ret = get_pve_psk(&msg4_input->equivalent_psvn, &psk);//generate Provisioning Seal Key used to unseal f
  75. if(PVEC_SUCCESS != ret){
  76. goto ret_point;
  77. }
  78. if(mce->escrow.version!=0){//only support escrow version 0 now
  79. ret = PVEC_MSG_ERROR;
  80. goto ret_point;
  81. }
  82. //Decrypt private key f (which had been sealed in ProvMsg3)
  83. sgx_status = sgx_rijndael128GCM_decrypt(reinterpret_cast<const sgx_aes_gcm_128bit_key_t *>(&psk),
  84. reinterpret_cast<const uint8_t *>(&mce->escrow.f), sizeof(FpElemStr), reinterpret_cast<uint8_t *>(&prv_key.f),
  85. mce->escrow.iv, IV_SIZE, NULL, 0,
  86. reinterpret_cast<const sgx_aes_gcm_128bit_tag_t *>(mce->escrow.mac));
  87. if(SGX_ERROR_MAC_MISMATCH == sgx_status){
  88. ret = PVEC_MSG_ERROR;
  89. goto ret_point;
  90. }else if(SGX_SUCCESS != sgx_status){
  91. ret = sgx_error_to_pve_error(sgx_status);
  92. goto ret_point;
  93. }
  94. //copy A, x and gid
  95. memcpy(&prv_key.A, &mce->A,sizeof(prv_key.A));
  96. memcpy(&prv_key.x, &mce->x, sizeof(prv_key.x));
  97. memcpy(&prv_key.gid, &msg4_input->group_cert.key.gid, sizeof(GroupId));
  98. ret_point:
  99. if(PVEC_SUCCESS != ret){
  100. (void)memset_s(&prv_key, sizeof(prv_key),0, sizeof(prv_key));
  101. }
  102. (void)memset_s(&psk,sizeof(psk),0,sizeof(psk));
  103. return ret;
  104. }
  105. //check whether prv key is valid and generate epid blob if PrivKey is valid
  106. //@prv_key: input the EPID Private Key
  107. //@psvn: the equivalent psvn
  108. //@pub_key: input the EPID group public Key
  109. //@epid_blob: output the EPID_DATA_BLOB on success, the size of the buffer has been checked before calling to the function
  110. //@return PVEC_SUCCESS on success or error code on failure
  111. static pve_status_t gen_epid_blob(const extended_epid_group_blob_t* pxegb,
  112. const PrivKey *prv_key,
  113. const psvn_t *psvn,
  114. const GroupPubKey *pub_key,
  115. sgx_sealed_data_t *epid_blob)
  116. {
  117. uint8_t *tmp_buffer = NULL;
  118. pve_status_t ret = PVEC_SUCCESS;
  119. sgx_status_t sgx_status = SGX_SUCCESS;
  120. EpidStatus epid_ret = kEpidNoErr;
  121. MemberCtx *p_epid_context = NULL;
  122. se_secret_epid_data_sdk_t *epid_data = NULL;
  123. se_plaintext_epid_data_sdk_t *plaintext = NULL;
  124. uint32_t tmp_buffer_size = static_cast<uint32_t>(sizeof(se_plaintext_epid_data_sdk_t) + sizeof(se_secret_epid_data_sdk_t));
  125. //alloc one temp buffer to hold both plaintext and secret data before encryption
  126. //all data before encryption will be copied into the buffer inorder
  127. tmp_buffer = reinterpret_cast<uint8_t *>(malloc(tmp_buffer_size));
  128. if(!tmp_buffer)
  129. {
  130. ret =PVEC_MALLOC_ERROR;
  131. goto ret_point;
  132. }
  133. memset(tmp_buffer,0,tmp_buffer_size);
  134. plaintext = reinterpret_cast<se_plaintext_epid_data_sdk_t *>(tmp_buffer);//plaintext in the beginning of the buffer
  135. //group cert as part of aad
  136. memcpy(&plaintext->epid_group_cert, pub_key, sizeof(*pub_key));
  137. //PVE ISVSVN, CPUSVN and some public key from xegb in aad too
  138. epid_data = reinterpret_cast<se_secret_epid_data_sdk_t*>(plaintext + 1);//secret data in same buffer
  139. memcpy(&plaintext->equiv_cpu_svn, &psvn->cpu_svn, SGX_CPUSVN_SIZE); //equivalent CPUSVN and ISVSVN from PSVN of ProvMsgs used in AAD
  140. memcpy(&plaintext->equiv_pve_isv_svn, &psvn->isv_svn, sizeof(plaintext->equiv_pve_isv_svn));
  141. plaintext->seal_blob_type = PVE_SEAL_EPID_KEY_BLOB;
  142. plaintext->epid_key_version = EPID_KEY_BLOB_VERSION_SDK;
  143. plaintext->xeid = pxegb->xeid;
  144. memcpy(&plaintext->qsdk_exp, pxegb->qsdk_exp, sizeof(plaintext->qsdk_exp));
  145. memcpy(&plaintext->qsdk_mod, pxegb->qsdk_mod, sizeof(plaintext->qsdk_mod));
  146. memcpy(&plaintext->epid_sk, pxegb->epid_sk, sizeof(plaintext->epid_sk));
  147. memcpy(&epid_data->epid_private_key,prv_key,sizeof(PrivKey)); //EPID Private key is sealed in EPID_DATA_BLOB together with Member Precomputation
  148. epid_ret = epid_member_create(epid_random_func, NULL, NULL, &p_epid_context);
  149. if(kEpidNoErr!=epid_ret){
  150. ret = epid_error_to_pve_error(epid_ret);
  151. goto ret_point;
  152. }
  153. epid_ret = EpidProvisionKey(p_epid_context,
  154. &(plaintext->epid_group_cert),
  155. (PrivKey*)&(epid_data->epid_private_key),
  156. NULL);
  157. if (kEpidNoErr != epid_ret) {
  158. ret = epid_error_to_pve_error(epid_ret);
  159. goto ret_point;
  160. }
  161. // start member
  162. epid_ret = EpidMemberStartup(p_epid_context);
  163. if (kEpidNoErr != epid_ret) {
  164. ret = epid_error_to_pve_error(epid_ret);
  165. goto ret_point;
  166. }
  167. epid_ret = EpidMemberWritePrecomp(p_epid_context, &epid_data->member_precomp_data);//Create Member Precomputation
  168. if(kEpidNoErr!=epid_ret){
  169. ret = epid_error_to_pve_error(epid_ret);
  170. goto ret_point;
  171. }
  172. //call sgx_seal_data to generate EPID_DATA_BLOB
  173. if((sgx_status=sgx_seal_data(
  174. sizeof(se_plaintext_epid_data_sdk_t), reinterpret_cast<uint8_t*>(plaintext),//plaintext as AAD
  175. sizeof(se_secret_epid_data_sdk_t), reinterpret_cast<uint8_t*>(epid_data), //secret data to SEAL
  176. SGX_TRUSTED_EPID_BLOB_SIZE_SDK,
  177. epid_blob))!=SGX_SUCCESS){//generate EPID_DATA_BLOB in epid_blob
  178. ret = sgx_error_to_pve_error(sgx_status);
  179. goto ret_point;
  180. }
  181. ret_point:
  182. epid_member_delete(&p_epid_context);
  183. if(tmp_buffer){
  184. //reset memory to 0 of the temp buffer to defense in depth
  185. (void)memset_s(tmp_buffer,tmp_buffer_size, 0, tmp_buffer_size);
  186. free(tmp_buffer);
  187. }
  188. return ret;
  189. }
  190. //Function to process the decoded data from ProvMsg4 and generate EPID data blob
  191. //It will create EPIDDataBlob in output parameter epid_blob on success
  192. //@msg_input: input data decoded from ProvMsg4
  193. //@epid_blob: output buffer to hold the generated EPID_DATA_BLOB on success
  194. //@return PVEC_SUCCESS on success and error code otherwise
  195. pve_status_t proc_prov_msg4_data(const proc_prov_msg4_input_t *msg4_input,
  196. sgx_sealed_data_t *epid_blob)
  197. {
  198. uint8_t member_escrow_tlv_buf[MEMBERSHIP_CREDENTIAL_TLV_TOTAL_SIZE];
  199. pve_status_t ret = PVEC_SUCCESS;
  200. sgx_status_t sgx_status = SGX_SUCCESS;
  201. uint8_t pek_result = SGX_EC_INVALID_SIGNATURE;
  202. sgx_key_128bit_t pwk2;
  203. PrivKey prv_key;
  204. uint8_t aad_buf[sizeof(device_id_t)+sizeof(GroupId)];
  205. extended_epid_group_blob_t local_xegb;
  206. device_id_t *device_id_in_aad = reinterpret_cast<device_id_t *>(aad_buf+sizeof(GroupId));
  207. membership_credential_with_escrow_t *mce = reinterpret_cast<membership_credential_with_escrow_t *>(member_escrow_tlv_buf+MEMBERSHIP_CREDENTIAL_TLV_HEADER_SIZE);
  208. memset(member_escrow_tlv_buf, 0, sizeof(member_escrow_tlv_buf));
  209. memset(aad_buf, 0 ,sizeof(aad_buf));
  210. memset(&pwk2, 0, sizeof(pwk2));
  211. memset(&prv_key, 0, sizeof(prv_key));
  212. sgx_status = verify_xegb_with_default(msg4_input->xegb, &pek_result,local_xegb);
  213. if(SGX_SUCCESS != sgx_status){
  214. ret = sgx_error_to_pve_error(sgx_status);
  215. goto ret_point;
  216. }else if(pek_result != SGX_EC_VALID){
  217. ret = PVEC_XEGDSK_SIGN_ERROR;
  218. goto ret_point;
  219. }
  220. //Verify it is signed by EPID Signing key
  221. ret = check_signature_of_group_pub_cert(&msg4_input->group_cert, local_xegb.epid_sk);
  222. if (PVEC_SUCCESS != ret){
  223. goto ret_point;
  224. }
  225. //create PWK2
  226. ret = get_pwk2(&msg4_input->equivalent_psvn, msg4_input->n2, &pwk2);
  227. if (PVEC_SUCCESS != ret){
  228. goto ret_point;
  229. }
  230. //preparing device id for AAD
  231. memcpy(aad_buf, &msg4_input->group_cert.key.gid, sizeof(GroupId));
  232. memcpy(&device_id_in_aad->fmsp, &msg4_input->fmsp, sizeof(fmsp_t));
  233. memcpy(&device_id_in_aad->psvn, &msg4_input->equivalent_psvn, sizeof(psvn_t));
  234. memset(&device_id_in_aad->ppid, 0 ,sizeof(ppid_t));
  235. se_static_assert(sizeof(sgx_aes_gcm_128bit_key_t)==sizeof(pwk2)); /*SK_SIZE should be same as that of sgx_aes_gcm_128bit_key_t*/
  236. se_static_assert(sizeof(sgx_aes_gcm_128bit_tag_t)==sizeof(msg4_input->member_credential_mac)); /*member_credential_mac size should be same as that of sgx_aes_gcm_128bit_tag_t*/
  237. se_static_assert(HARD_CODED_EPID_MEMBER_WITH_ESCROW_TLV_SIZE == MEMBERSHIP_CREDENTIAL_TLV_TOTAL_SIZE); /*hardcoded size should be matched*/
  238. sgx_status = sgx_rijndael128GCM_decrypt(reinterpret_cast<sgx_aes_gcm_128bit_key_t *>(&pwk2),
  239. msg4_input->encrypted_member_credential,static_cast<uint32_t>(HARD_CODED_EPID_MEMBER_WITH_ESCROW_TLV_SIZE), member_escrow_tlv_buf,
  240. msg4_input->member_credential_iv, IV_SIZE, aad_buf, sizeof(aad_buf),
  241. reinterpret_cast<const sgx_aes_gcm_128bit_tag_t *>(msg4_input->member_credential_mac));//decrypt membership credential and escrow data TLV
  242. if(sgx_status == SGX_ERROR_MAC_MISMATCH){
  243. ret = PVEC_MSG_ERROR;
  244. goto ret_point;
  245. }else if(sgx_status != SGX_SUCCESS){
  246. ret = sgx_error_to_pve_error(sgx_status);
  247. goto ret_point;
  248. }
  249. if(memcmp(member_escrow_tlv_buf, MEMBERSHIP_CREDENTIAL_TLV_HEADER, MEMBERSHIP_CREDENTIAL_TLV_HEADER_SIZE)!=0){//checking TLV header matches hard-coded value
  250. ret = PVEC_MSG_ERROR;
  251. goto ret_point;
  252. }
  253. se_static_assert(sizeof(membership_credential_with_escrow_t)+MEMBERSHIP_CREDENTIAL_TLV_HEADER_SIZE==MEMBERSHIP_CREDENTIAL_TLV_TOTAL_SIZE); /*invalid hard-coded value*/
  254. ret = proc_prov_msg4_membercredential(mce, msg4_input, prv_key);//decrypt and generate epid private key
  255. if(PVEC_SUCCESS!=ret){
  256. goto ret_point;
  257. }
  258. ret = gen_epid_blob(&local_xegb, &prv_key, &msg4_input->equivalent_psvn, &msg4_input->group_cert.key, epid_blob);//seal epid private key to generate EPID data blob
  259. ret_point:
  260. //now clear secret data from memory to defense in depth
  261. (void)memset_s(&pwk2,sizeof(pwk2), 0, sizeof(pwk2));
  262. (void)memset_s(&prv_key, sizeof(prv_key), 0, sizeof(prv_key));
  263. (void)memset_s(member_escrow_tlv_buf, sizeof(member_escrow_tlv_buf), 0, sizeof(member_escrow_tlv_buf));
  264. (void)memset_s(aad_buf, sizeof(aad_buf), 0, sizeof(aad_buf));
  265. return ret;
  266. }