//Function to get provisioning key using the provided PSVN //If the psvn is NULL, both CPUSVN and ISVSVN is set to 0 (used for PPID generation only) //Input: psvn, the psvn used to generate provisioning key //Output: key, the provisioning key to return // return PVEC_SUCCESS on success static pve_status_t get_provision_key(sgx_key_128bit_t *key, const psvn_t *psvn) { sgx_status_t se_ret = SGX_SUCCESS; sgx_key_request_t wrap_key_req; //memset here will also set cpusvn isvsvn to 0 for the case when psvn==NULL memset(&wrap_key_req, 0, sizeof(sgx_key_request_t)); if(psvn==NULL){ //keeping isv_svn and cpu_svn all 0 according to spec (this is for calcuation of PPID) }else{ memcpy(&wrap_key_req.cpu_svn, &psvn->cpu_svn, sizeof(wrap_key_req.cpu_svn)); memcpy(&wrap_key_req.isv_svn, &psvn->isv_svn, sizeof(wrap_key_req.isv_svn)); } wrap_key_req.key_name = SGX_KEYSELECT_PROVISION; //provisioning key wrap_key_req.attribute_mask.xfrm = 0; wrap_key_req.misc_mask = 0xFFFFFFFF; wrap_key_req.attribute_mask.flags = ~SGX_FLAGS_MODE64BIT; //set all bits except the SGX_FLAGS_MODE64BIT se_ret = sgx_get_key(&wrap_key_req, key); if(SGX_SUCCESS != se_ret) { return sgx_error_to_pve_error(se_ret); } return PVEC_SUCCESS; }
//Function to generate Provisioning Sealing Key given the psvn //The key is used to seal the private parameter f before sending to backend server pve_status_t get_pve_psk( const psvn_t* psvn, sgx_key_128bit_t* seal_key) { sgx_status_t se_ret = SGX_SUCCESS; sgx_key_request_t seal_key_req; if(psvn == NULL) return PVEC_PARAMETER_ERROR; memset(&seal_key_req, 0, sizeof(sgx_key_request_t)); memcpy(&seal_key_req.cpu_svn, &psvn->cpu_svn, SGX_CPUSVN_SIZE); memcpy(&seal_key_req.isv_svn, &psvn->isv_svn, sizeof(psvn->isv_svn)); seal_key_req.key_name = SGX_KEYSELECT_PROVISION_SEAL; //provisioning sealling key seal_key_req.attribute_mask.xfrm = 0; seal_key_req.attribute_mask.flags = ~SGX_FLAGS_MODE64BIT; se_ret = sgx_get_key(&seal_key_req, seal_key); if(SGX_SUCCESS != se_ret) { return sgx_error_to_pve_error(se_ret); } return PVEC_SUCCESS; }
sgx_status_t sgx_verify_report(const sgx_report_t *report) { sgx_mac_t mac; sgx_key_request_t key_request; sgx_key_128bit_t key; sgx_status_t err = SGX_ERROR_UNEXPECTED; //check parameter if(!report||!sgx_is_within_enclave(report, sizeof(*report))) { return SGX_ERROR_INVALID_PARAMETER; } memset(&mac, 0, sizeof(sgx_mac_t)); memset(&key_request, 0, sizeof(sgx_key_request_t)); memset(&key, 0, sizeof(sgx_key_128bit_t)); //prepare the key_request key_request.key_name = SGX_KEYSELECT_REPORT; memcpy_s(&key_request.key_id, sizeof(key_request.key_id), &report->key_id, sizeof(report->key_id)); //get the report key // Since the key_request is not an input parameter by caller, // we suppose sgx_get_key would never return the following error code: // SGX_ERROR_INVALID_PARAMETER // SGX_ERROR_INVALID_ATTRIBUTE // SGX_ERROR_INVALID_CPUSVN // SGX_ERROR_INVALID_ISVSVN // SGX_ERROR_INVALID_KEYNAME err = sgx_get_key(&key_request, &key); if(err != SGX_SUCCESS) { return err; // err must be SGX_ERROR_OUT_OF_MEMORY or SGX_ERROR_UNEXPECTED } //get the report mac err = sgx_rijndael128_cmac_msg((sgx_cmac_128bit_key_t*)&key, (const uint8_t *)(&report->body), sizeof(sgx_report_body_t), &mac); memset_s (&key, sizeof(sgx_key_128bit_t), 0, sizeof(sgx_key_128bit_t)); if (SGX_SUCCESS != err) { if(err != SGX_ERROR_OUT_OF_MEMORY) err = SGX_ERROR_UNEXPECTED; return err; } if(consttime_memequal(mac, report->mac, sizeof(sgx_mac_t)) == 0) { return SGX_ERROR_MAC_MISMATCH; } else { return SGX_SUCCESS; } }
//calculate launch token. key_id, attributes_le and then mac is updated. //return AE_SUCCESS on success static ae_error_t le_calc_lic_token(token_t* lictoken) { //calculate launch token sgx_key_request_t key_request; sgx_key_128bit_t launch_key; if(SGX_SUCCESS != sgx_read_rand((uint8_t*)&lictoken->key_id, sizeof(sgx_key_id_t))) { return LE_UNEXPECTED_ERROR; } // Create Key Request memset(&key_request, 0, sizeof(key_request)); //setup key_request parameters to derive launch key key_request.key_name = SGX_KEYSELECT_LICENSE; memcpy(&key_request.key_id, &lictoken->key_id, sizeof(key_request.key_id)); memcpy(&key_request.cpu_svn, &(lictoken->cpu_svn_le), sizeof(key_request.cpu_svn)); memcpy(&key_request.isv_svn, &(lictoken->isv_svn_le), sizeof(key_request.isv_svn)); key_request.attribute_mask.xfrm = 0; //0xFFFFFFFFFFFFFFFB: ~SGX_FLAGS_MODE64BIT key_request.attribute_mask.flags = ~SGX_FLAGS_MODE64BIT; key_request.misc_mask = 0xFFFFFFFF; lictoken->masked_misc_select_le &= key_request.misc_mask; lictoken->attributes_le.flags = (lictoken->attributes_le.flags) & (key_request.attribute_mask.flags); lictoken->attributes_le.xfrm = (lictoken->attributes_le.xfrm) & (key_request.attribute_mask.xfrm); // EGETKEY sgx_status_t sgx_ret = sgx_get_key(&key_request,&launch_key); if(SGX_SUCCESS != sgx_ret) { return LE_GET_LICENSE_KEY_ERROR; } sgx_cmac_state_handle_t p_cmac_handle = NULL; do{ sgx_ret = sgx_cmac128_init(&launch_key, &p_cmac_handle); if(SGX_SUCCESS != sgx_ret) { break; } sgx_ret = sgx_cmac128_update((uint8_t*)&lictoken->body, sizeof(lictoken->body), p_cmac_handle); if(SGX_SUCCESS != sgx_ret) { break; } sgx_ret = sgx_cmac128_final(p_cmac_handle, (sgx_cmac_128bit_tag_t*)&lictoken->mac); }while(0); if (p_cmac_handle != NULL) { sgx_cmac128_close(p_cmac_handle); } //clear launch_key after being used memset_s(launch_key,sizeof(launch_key), 0, sizeof(launch_key)); if (SGX_SUCCESS != sgx_ret) { return AE_FAILURE; } return AE_SUCCESS; }