Example #1
0
ae_error_t CertificateProvisioningProtocol::aesGCMDecrypt(const upse::Buffer& iv, const upse::Buffer& key, const upse::Buffer& cipherText,
                            const upse::Buffer& aad, const upse::Buffer& mac, upse::Buffer& plainText)
{
    ae_error_t status = AE_FAILURE;

    do
    {
        if (key.getSize() != sizeof(sgx_aes_gcm_128bit_key_t))
            break;

        status = plainText.Alloc(cipherText.getSize());
        if (AE_FAILED(status))
            break;

        uint8_t* pPlainText = NULL;
        status = upse::BufferWriter(plainText).reserve(plainText.getSize(), &pPlainText);
        if (AE_FAILED(status))
            break;

        sgx_status_t sgx_status;
        sgx_status = sgx_rijndael128GCM_decrypt(reinterpret_cast<const sgx_aes_gcm_128bit_key_t *>(key.getData()),
                        cipherText.getData(), cipherText.getSize(), pPlainText, iv.getData(), IV_SIZE, aad.getData(), aad.getSize(),
                        reinterpret_cast<const sgx_aes_gcm_128bit_tag_t *>(mac.getData()));
        if (SGX_SUCCESS != sgx_status)
        {
            AESM_LOG_ERROR("%s", g_event_string_table[SGX_EVENT_PSE_CERT_PROV_INTEGRITY_ERROR]);
            status = AE_FAILURE;
            break;
        }

        status = AE_SUCCESS;
    } while (0);

    return status;
}
Example #2
0
sgx_status_t put_secret_data(
    sgx_ra_context_t context,
    uint8_t *p_secret,
    uint32_t secret_size,
    uint8_t *p_gcm_mac)
{
    sgx_status_t ret = SGX_SUCCESS;
    sgx_ec_key_128bit_t sk_key;

    do {
        if(secret_size != 8)
        {
            ret = SGX_ERROR_INVALID_PARAMETER;
            break;
        }

        ret = sgx_ra_get_keys(context, SGX_RA_KEY_SK, &sk_key);
        if(SGX_SUCCESS != ret)
        {
            break;
        }

        uint8_t aes_gcm_iv[12] = {0};
        ret = sgx_rijndael128GCM_decrypt(&sk_key,
                                         p_secret,
                                         secret_size,
                                         &g_secret[0],
                                         &aes_gcm_iv[0],
                                         12,
                                         NULL,
                                         0,
                                         (const sgx_aes_gcm_128bit_tag_t *)
                                            (p_gcm_mac));

        uint32_t i;
        bool secret_match = true;
        for(i=0;i<secret_size;i++)
        {
            if(g_secret[i] != i)
            {
                secret_match = false;
            }
        }

        if(!secret_match)
        {
            ret = SGX_ERROR_UNEXPECTED;
        }

        // Once the server has the shared secret, it should be sealed to
        // persistent storage for future use. This will prevents having to
        // perform remote attestation until the secret goes stale. Once the
        // enclave is created again, the secret can be unsealed.
    } while(0);
    return ret;
}
Example #3
0
uint32_t aes128gcm_decrypt(const sgx_aes_gcm_128bit_key_t *key,
						   const uint8_t *bufin, const size_t bufinlen,
						   uint8_t *bufout, size_t bufoutlen)
{
	size_t ciphertextlen = bufinlen - (SGX_AESGCM_IV_SIZE + SGX_AESGCM_MAC_SIZE);
	// check buffer bounds
	if(bufoutlen < aes128gcm_plaintext_size(bufinlen))
	{
		return 0Xffffffff;
	}
	// decrypt
	if(SGX_SUCCESS != sgx_rijndael128GCM_decrypt(key,
		bufin + SGX_AESGCM_IV_SIZE + SGX_AESGCM_MAC_SIZE, ciphertextlen, // ciphertext
		bufout, // plaintext
		bufin, SGX_AESGCM_IV_SIZE, // IV
		NULL, 0, // aad
		(const sgx_aes_gcm_128bit_tag_t*) (bufin + SGX_AESGCM_IV_SIZE)
		))
	{
		return 0xffffffff;
	}
	return 0;
}
Example #4
0
//Function to decode ProvMsg4 and generate epid data blob
uint32_t CPVEClass::proc_prov_msg4(
        bool  use_ek2_in_input,
        const uint8_t ek2[SK_SIZE],
        const uint8_t* msg4,
        uint32_t msg4_size,
        uint8_t* data_blob,
        uint32_t blob_size)
{
    ae_error_t ret = AE_SUCCESS;
    uint8_t local_ek2[SK_SIZE];
    uint8_t *decoded_msg4 = NULL;
    const provision_response_header_t *msg4_header = reinterpret_cast<const provision_response_header_t *>(msg4);
    if(msg4_size < PROVISION_RESPONSE_HEADER_SIZE){
        AESM_DBG_ERROR("invalid msg4 size");
        return PVE_MSG_ERROR;
    }
    if(blob_size != HARD_CODED_EPID_BLOB_SIZE){
        AESM_DBG_FATAL("invalid input epid blob size");
        return PVE_PARAMETER_ERROR;
    }

    ret = check_prov_msg4_header(msg4_header, msg4_size);
    if( AE_SUCCESS != ret){
        AESM_DBG_ERROR("Invalid ProvMsg4 Header:%d",ret);
        return ret;
    }
    ret = check_epid_pve_pg_status_before_mac_verification(msg4_header);
    if( AE_SUCCESS != ret){
        AESM_DBG_ERROR("Backend return failure in ProvMsg4 Header:%d",ret);
        return ret;
    }

    do{
        TLVsMsg tlvs_msg4;
        tlv_status_t tlv_status;
        tlv_status = tlvs_msg4.init_from_buffer(msg4+static_cast<uint32_t>(PROVISION_RESPONSE_HEADER_SIZE), msg4_size - static_cast<uint32_t>(PROVISION_RESPONSE_HEADER_SIZE));
        ret = tlv_error_2_pve_error(tlv_status);
        if(AE_SUCCESS!=ret){
            AESM_DBG_ERROR("fail to decode ProvMsg4:%d",tlv_status);
            break;
        }
        ret = msg4_integrity_checking(tlvs_msg4);
        if(AE_SUCCESS != ret){
            AESM_DBG_ERROR("ProvMsg4 integrity checking error:%d",ret);
            break;
        }
        AESM_DBG_TRACE("ProvMsg4 decoded");
        if(!use_ek2_in_input){ //we need generate ek2
            prov_get_ek2_input_t ek2_input;
            if(memcpy_s(ek2_input.nonce, NONCE_SIZE, MSG4_TOP_FIELD_NONCE.payload, NONCE_SIZE)!=0){
                AESM_DBG_ERROR("fail in memcpy");
                ret = PVE_UNEXPECTED_ERROR;
                break;
            }
            if(memcpy_s(ek2_input.xid, XID_SIZE, msg4_header->xid, XID_SIZE)!=0){
                AESM_DBG_ERROR("fail in memcpy");
                ret = PVE_UNEXPECTED_ERROR;
                break;
            }
            //call PvE to get EK2
            se_static_assert(SK_SIZE == sizeof(prov_get_ek2_output_t));

            ret = (ae_error_t)get_ek2(&ek2_input, reinterpret_cast<prov_get_ek2_output_t *>(local_ek2));
            if(AE_SUCCESS != ret){
                AESM_DBG_ERROR("fail to get EK2:%d",ret);
                break;
            }
        }else{//reuse ek2 generated in processing ProvMsg2
            if(0!=memcpy_s(local_ek2, sizeof(local_ek2), ek2, SK_SIZE)){
                AESM_DBG_ERROR("fail in memcpy");
                ret = PVE_UNEXPECTED_ERROR;
                break;
            }
        }
        se_static_assert(SK_SIZE==sizeof(sgx_aes_gcm_128bit_key_t));
        tlv_msg_t field1 = block_cipher_tlv_get_encrypted_text(MSG4_TOP_FIELD_DATA);
        decoded_msg4 = reinterpret_cast<uint8_t *>(malloc(field1.msg_size));
        if(NULL == decoded_msg4){
            AESM_DBG_ERROR("malloc error");
            ret = AE_OUT_OF_MEMORY_ERROR;
            break;
        }
        sgx_status_t sgx_status = sgx_rijndael128GCM_decrypt(reinterpret_cast<const sgx_aes_gcm_128bit_key_t *>(local_ek2),
            field1.msg_buf, field1.msg_size, decoded_msg4, 
            reinterpret_cast<uint8_t *>(block_cipher_tlv_get_iv(MSG4_TOP_FIELD_DATA)), IV_SIZE, 
            reinterpret_cast<const uint8_t *>(msg4_header), PROVISION_RESPONSE_HEADER_SIZE,
            reinterpret_cast<const sgx_aes_gcm_128bit_tag_t *>(MSG4_TOP_FIELD_MAC.payload));
        if(SGX_ERROR_MAC_MISMATCH == sgx_status){
            AESM_DBG_ERROR("fail to decrypt ProvMsg4 by EK2");
            ret = PVE_INTEGRITY_CHECK_ERROR;
            break;
        }
        if( AE_SUCCESS != (ret = sgx_error_to_ae_error(sgx_status))){
            AESM_DBG_ERROR("error in decrypting ProvMsg4:%d",sgx_status);
            break;
        }
        AESM_DBG_TRACE("ProvMsg4 decrypted by EK2 successfully");
        ret = check_epid_pve_pg_status_after_mac_verification(msg4_header);
        if(AE_SUCCESS != ret){
            AESM_DBG_ERROR("Backend reported error passed MAC verification:%d",ret);
            break;
        }
        TLVsMsg tlvs_field1;
        tlv_status = tlvs_field1.init_from_buffer(decoded_msg4, field1.msg_size);
        ret = tlv_error_2_pve_error(tlv_status);
        if(AE_SUCCESS != ret){
            AESM_DBG_ERROR("ProvMsg4 Field2.1 decoding failed:%d",tlv_status);
            break;
        }
        ret = msg4_field1_msg_checking(tlvs_field1);
        if( AE_SUCCESS != ret){
            AESM_DBG_ERROR("ProvMsg4 Field2.1 invalid:%d",ret);
            break;
        }
        proc_prov_msg4_input_t msg4_input;
        if(sizeof(proc_prov_msg4_output_t)!=SGX_TRUSTED_EPID_BLOB_SIZE){
            AESM_DBG_FATAL("Trusted ProvMsg4 output buffer size error");
            ret = PVE_UNEXPECTED_ERROR;
            break;
        }
        tlv_msg_t tcb_data = block_cipher_tlv_get_encrypted_text(MSG4_FIELD1_ENC_TCB);
        tlv_msg_t Axf_data = block_cipher_tlv_get_encrypted_text(MSG4_FIELD1_ENC_Axf);
        if(0!=memcpy_s(&msg4_input.group_cert, sizeof(msg4_input.group_cert), MSG4_FIELD1_GROUP_CERT.payload, MSG4_FIELD1_GROUP_CERT.size)||
            0!=memcpy_s(&msg4_input.equivalent_psvn, sizeof(psvn_t), device_id_tlv_get_psvn(MSG4_FIELD1_DEVICE_ID), sizeof(psvn_t))||
            0!=memcpy_s(&msg4_input.fmsp, sizeof(fmsp_t), device_id_tlv_get_fmsp(MSG4_FIELD1_DEVICE_ID), sizeof(fmsp_t))||
            0!=memcpy_s(&msg4_input.tcb_iv, IV_SIZE, block_cipher_tlv_get_iv(MSG4_FIELD1_ENC_TCB), IV_SIZE)||
            0!=memcpy_s(&msg4_input.encrypted_tcb, SK_SIZE, tcb_data.msg_buf, tcb_data.msg_size)||
            0!=memcpy_s(&msg4_input.tcb_mac, MAC_SIZE, MSG4_FIELD1_MAC_TCB.payload, MSG4_FIELD1_MAC_TCB.size)||
            0!=memcpy_s(&msg4_input.member_credential_iv, IV_SIZE, block_cipher_tlv_get_iv(MSG4_FIELD1_ENC_Axf), IV_SIZE)||
            0!=memcpy_s(&msg4_input.encrypted_member_credential, HARD_CODED_EPID_MEMBER_WITH_ESCROW_TLV_SIZE, Axf_data.msg_buf, Axf_data.msg_size)||
            0!=memcpy_s(&msg4_input.member_credential_mac, MAC_SIZE, MSG4_FIELD1_MAC_Axf.payload, MSG4_FIELD1_MAC_Axf.size)){
                AESM_DBG_ERROR("memcpy error");
                ret = PVE_UNEXPECTED_ERROR;
                break;
        }
        ret = (ae_error_t)proc_prov_msg4_data(&msg4_input, reinterpret_cast<proc_prov_msg4_output_t *>(data_blob));
        AESM_DBG_TRACE("PvE return %d in Process ProvMsg4",ret);
    }while(0);
    if(decoded_msg4)free(decoded_msg4);
    return ret;
}
Example #5
0
//Function to decode ProvMsg4 and generate epid data blob
uint32_t CPVEClass::proc_prov_msg4(
    const pve_data_t &data,
    const uint8_t *msg4,
    uint32_t msg4_size,
    uint8_t *data_blob,
    uint32_t blob_size)
{
    ae_error_t ret = AE_SUCCESS;
    uint8_t local_ek2[SK_SIZE];
    uint8_t *decoded_msg4 = NULL;
    uint8_t temp[XID_SIZE+NONCE_SIZE];
    sgx_status_t sgx_status;
    const provision_response_header_t *msg4_header = reinterpret_cast<const provision_response_header_t *>(msg4);
    if(msg4_size < PROVISION_RESPONSE_HEADER_SIZE) {
        AESM_DBG_ERROR("invalid msg4 size");
        return PVE_MSG_ERROR;
    }
    if (blob_size != SGX_TRUSTED_EPID_BLOB_SIZE_PAK) {
        AESM_DBG_FATAL("invalid input epid blob size");
        return PVE_PARAMETER_ERROR;
    }

    ret = check_prov_msg4_header(msg4_header, msg4_size);
    if( AE_SUCCESS != ret) {
        AESM_DBG_ERROR("Invalid ProvMsg4 Header:(ae%d)",ret);
        return ret;
    }
    if(0!=memcmp(msg4_header->xid, data.xid, XID_SIZE)) {
        AESM_DBG_ERROR("Invalid XID in msg4 header");
        return PVE_MSG_ERROR;
    }
    ret = check_epid_pve_pg_status_before_mac_verification(msg4_header);
    if( AE_SUCCESS != ret) {
        AESM_DBG_ERROR("Backend return failure in ProvMsg4 Header:(ae%d)",ret);
        return ret;
    }

    do {
        TLVsMsg tlvs_msg4;
        uint8_t aad[PROVISION_RESPONSE_HEADER_SIZE+NONCE_SIZE];
        tlv_status_t tlv_status;
        tlv_status = tlvs_msg4.init_from_buffer(msg4+static_cast<uint32_t>(PROVISION_RESPONSE_HEADER_SIZE), msg4_size - static_cast<uint32_t>(PROVISION_RESPONSE_HEADER_SIZE));
        ret = tlv_error_2_pve_error(tlv_status);
        if(AE_SUCCESS!=ret) {
            AESM_DBG_ERROR("fail to decode ProvMsg4:(ae%d)",ret);
            break;
        }
        ret = msg4_integrity_checking(tlvs_msg4);
        if(AE_SUCCESS != ret) {
            AESM_DBG_ERROR("ProvMsg4 integrity checking error:(ae%d)",ret);
            break;
        }
        AESM_DBG_TRACE("ProvMsg4 decoded");
        se_static_assert(sizeof(sgx_cmac_128bit_key_t)==SK_SIZE);
        if(0!=memcpy_s(temp,sizeof(temp), data.xid, XID_SIZE)||
                0!=memcpy_s(temp+XID_SIZE, sizeof(temp)-XID_SIZE, MSG4_TOP_FIELD_NONCE.payload, NONCE_SIZE)) {
            AESM_DBG_ERROR("Fail in memcpy");
            ret = AE_FAILURE;
            break;
        }
        if((sgx_status=sgx_rijndael128_cmac_msg(reinterpret_cast<const sgx_cmac_128bit_key_t *>(data.sk),
                                                temp, XID_SIZE+NONCE_SIZE, reinterpret_cast<sgx_cmac_128bit_tag_t *>(local_ek2)))!=SGX_SUCCESS) {
            AESM_DBG_ERROR("Fail to generate ek2:(sgx0x%x)",sgx_status);
            ret = AE_FAILURE;
            break;

        }
        se_static_assert(SK_SIZE==sizeof(sgx_aes_gcm_128bit_key_t));
        tlv_msg_t field1 = block_cipher_tlv_get_encrypted_text(MSG4_TOP_FIELD_DATA);
        decoded_msg4 = reinterpret_cast<uint8_t *>(malloc(field1.msg_size));
        if(NULL == decoded_msg4) {
            AESM_DBG_ERROR("malloc error");
            ret = AE_OUT_OF_MEMORY_ERROR;
            break;
        }
        if (memcpy_s(aad, sizeof(aad), msg4_header, PROVISION_RESPONSE_HEADER_SIZE) != 0 ||
                memcpy_s(aad + PROVISION_RESPONSE_HEADER_SIZE, sizeof(aad)-PROVISION_RESPONSE_HEADER_SIZE,
                         MSG4_TOP_FIELD_NONCE.payload, MSG4_TOP_FIELD_NONCE.size) != 0) {
            AESM_DBG_ERROR("memcpy failure");
            ret = AE_FAILURE;
            break;
        }
        sgx_status_t sgx_status = sgx_rijndael128GCM_decrypt(reinterpret_cast<const sgx_aes_gcm_128bit_key_t *>(local_ek2),
                                  field1.msg_buf, field1.msg_size, decoded_msg4,
                                  reinterpret_cast<uint8_t *>(block_cipher_tlv_get_iv(MSG4_TOP_FIELD_DATA)), IV_SIZE,
                                  aad, sizeof(aad),
                                  reinterpret_cast<const sgx_aes_gcm_128bit_tag_t *>(MSG4_TOP_FIELD_MAC.payload));
        if(SGX_ERROR_MAC_MISMATCH == sgx_status) {
            AESM_DBG_ERROR("fail to decrypt ProvMsg4 by EK2 (sgx0x%x)",sgx_status);
            ret = PVE_INTEGRITY_CHECK_ERROR;
            break;
        }
        if( AE_SUCCESS != (ret = sgx_error_to_ae_error(sgx_status))) {
            AESM_DBG_ERROR("error in decrypting ProvMsg4:(sgx0x%x)",sgx_status);
            break;
        }
        AESM_DBG_TRACE("ProvMsg4 decrypted by EK2 successfully");
        ret = check_epid_pve_pg_status_after_mac_verification(msg4_header);
        if(AE_SUCCESS != ret) {
            AESM_DBG_ERROR("Backend reported error passed MAC verification:(ae%d)",ret);
            break;
        }
        TLVsMsg tlvs_field1;
        tlv_status = tlvs_field1.init_from_buffer(decoded_msg4, field1.msg_size);
        ret = tlv_error_2_pve_error(tlv_status);
        if(AE_SUCCESS != ret) {
            AESM_DBG_ERROR("ProvMsg4 Field2.1 decoding failed:(ae%d)",ret);
            break;
        }
        ret = msg4_field1_msg_checking(tlvs_field1);
        if( AE_SUCCESS != ret) {
            AESM_DBG_ERROR("ProvMsg4 Field2.1 invalid:(ae%d)",ret);
            break;
        }
        proc_prov_msg4_input_t msg4_input;
        tlv_msg_t Axf_data = block_cipher_tlv_get_encrypted_text(MSG4_FIELD1_ENC_Axf);
        if(0!=memcpy_s(&msg4_input.group_cert, sizeof(msg4_input.group_cert), MSG4_FIELD1_GROUP_CERT.payload, MSG4_FIELD1_GROUP_CERT.size)||
                0!=memcpy_s(&msg4_input.n2, NONCE_2_SIZE, MSG4_FIELD1_Nonce2.payload, MSG4_FIELD1_Nonce2.size) ||
                0!=memcpy_s(&msg4_input.equivalent_psvn, sizeof(psvn_t), platform_info_tlv_get_psvn(MSG4_FIELD1_PLATFORM_INFO), sizeof(psvn_t))||
                0!=memcpy_s(&msg4_input.fmsp, sizeof(fmsp_t), platform_info_tlv_get_fmsp(MSG4_FIELD1_PLATFORM_INFO), sizeof(fmsp_t))||
                0!=memcpy_s(&msg4_input.member_credential_iv, IV_SIZE, block_cipher_tlv_get_iv(MSG4_FIELD1_ENC_Axf), IV_SIZE)||
                0!=memcpy_s(&msg4_input.encrypted_member_credential, HARD_CODED_EPID_MEMBER_WITH_ESCROW_TLV_SIZE, Axf_data.msg_buf, Axf_data.msg_size)||
                0!=memcpy_s(&msg4_input.member_credential_mac, MAC_SIZE, MSG4_FIELD1_MAC_Axf.payload, MSG4_FIELD1_MAC_Axf.size)) {
            AESM_DBG_ERROR("memcpy error");
            ret = PVE_UNEXPECTED_ERROR;
            break;
        }
        if (AE_SUCCESS != (ret =XEGDBlob::instance().read(msg4_input.xegb))) {
            AESM_DBG_ERROR("Fail to read extend epid blob info (ae%d)",ret);
            return ret;
        }

        ret = CPVEClass::instance().load_enclave();//Load PvE enclave now
        if( ret != AE_SUCCESS) {
            AESM_DBG_ERROR("Fail to load PvE enclave:(ae%d)\n",ret);
            break;
        }
        ret = (ae_error_t)proc_prov_msg4_data(&msg4_input, reinterpret_cast<proc_prov_msg4_output_t *>(data_blob));
        AESM_DBG_TRACE("PvE return (ae%d) in Process ProvMsg4",ret);
    } while(0);
    if(decoded_msg4)free(decoded_msg4);
    return ret;
}
Example #6
0
file_mht_node_t* protected_fs_file::read_mht_node(uint64_t mht_node_number)
{
	int32_t result32;
	sgx_status_t status;

	if (mht_node_number == 0)
		return &root_mht;

	uint64_t physical_node_number = 1 + // meta data node
										mht_node_number * (1 + ATTACHED_DATA_NODES_COUNT); // the '1' is for the mht node preceding every 96 data nodes

	file_mht_node_t* file_mht_node = (file_mht_node_t*)cache.find(physical_node_number);
	if (file_mht_node != NULL)
		return file_mht_node;

	file_mht_node_t* parent_file_mht_node = read_mht_node((mht_node_number - 1) / CHILD_MHT_NODES_COUNT);
	if (parent_file_mht_node == NULL) // some error happened
		return NULL;

	try {
		file_mht_node = new file_mht_node_t;
	}
	catch (std::bad_alloc& e) {
		(void)e; // remove warning
		last_error = ENOMEM;
		return NULL;
	}
	memset(file_mht_node, 0, sizeof(file_mht_node_t));
	file_mht_node->type = FILE_MHT_NODE_TYPE;
	file_mht_node->mht_node_number = mht_node_number;
	file_mht_node->physical_node_number = physical_node_number;
	file_mht_node->parent = parent_file_mht_node;
		
	status = u_sgxprotectedfs_fread_node(&result32, file, file_mht_node->physical_node_number, file_mht_node->encrypted.cipher, NODE_SIZE);
	if (status != SGX_SUCCESS || result32 != 0)
	{
		delete file_mht_node;
		last_error = (status != SGX_SUCCESS) ? status : 
					 (result32 != -1) ? result32 : EIO;
		return NULL;
	}
	
	gcm_crypto_data_t* gcm_crypto_data = &file_mht_node->parent->plain.mht_nodes_crypto[(file_mht_node->mht_node_number - 1) % CHILD_MHT_NODES_COUNT];

	// this function decrypt the data _and_ checks the integrity of the data against the gmac
	status = sgx_rijndael128GCM_decrypt(&gcm_crypto_data->key, file_mht_node->encrypted.cipher, NODE_SIZE, (uint8_t*)&file_mht_node->plain, empty_iv, SGX_AESGCM_IV_SIZE, NULL, 0, &gcm_crypto_data->gmac);
	if (status != SGX_SUCCESS)
	{
		delete file_mht_node;
		last_error = status;
		if (status == SGX_ERROR_MAC_MISMATCH)
		{
			file_status = SGX_FILE_STATUS_CORRUPTED;
		}
		return NULL;
	}

	if (cache.add(file_mht_node->physical_node_number, file_mht_node) == false)
	{
		memset_s(&file_mht_node->plain, sizeof(mht_node_t), 0, sizeof(mht_node_t));
		delete file_mht_node;
		last_error = ENOMEM;
		return NULL;
	}

	return file_mht_node;
}
Example #7
0
file_data_node_t* protected_fs_file::read_data_node()
{
	uint64_t data_node_number;
	uint64_t physical_node_number;
	file_mht_node_t* file_mht_node;
	int32_t result32;
	sgx_status_t status;

	get_node_numbers(offset, NULL, &data_node_number, NULL, &physical_node_number);

	file_data_node_t* file_data_node = (file_data_node_t*)cache.get(physical_node_number);
	if (file_data_node != NULL)
		return file_data_node;
	
	// need to read the data node from the disk

	file_mht_node = get_mht_node();
	if (file_mht_node == NULL) // some error happened
		return NULL;

	try {
		file_data_node = new file_data_node_t;
	}
	catch (std::bad_alloc& e) {
		(void)e; // remove warning
		last_error = ENOMEM;
		return NULL;
	}
	memset(file_data_node, 0, sizeof(file_data_node_t));
	file_data_node->type = FILE_DATA_NODE_TYPE;
	file_data_node->data_node_number = data_node_number;
	file_data_node->physical_node_number = physical_node_number;
	file_data_node->parent = file_mht_node;
		
	status = u_sgxprotectedfs_fread_node(&result32, file, file_data_node->physical_node_number, file_data_node->encrypted.cipher, NODE_SIZE);
	if (status != SGX_SUCCESS || result32 != 0)
	{
		delete file_data_node;
		last_error = (status != SGX_SUCCESS) ? status : 
					 (result32 != -1) ? result32 : EIO;
		return NULL;
	}

	gcm_crypto_data_t* gcm_crypto_data = &file_data_node->parent->plain.data_nodes_crypto[file_data_node->data_node_number % ATTACHED_DATA_NODES_COUNT];

	// this function decrypt the data _and_ checks the integrity of the data against the gmac
	status = sgx_rijndael128GCM_decrypt(&gcm_crypto_data->key, file_data_node->encrypted.cipher, NODE_SIZE, file_data_node->plain.data, empty_iv, SGX_AESGCM_IV_SIZE, NULL, 0, &gcm_crypto_data->gmac);
	if (status != SGX_SUCCESS)
	{
		delete file_data_node;
		last_error = status;
		if (status == SGX_ERROR_MAC_MISMATCH)
		{
			file_status = SGX_FILE_STATUS_CORRUPTED;
		}
		return NULL;
	}
		
	if (cache.add(file_data_node->physical_node_number, file_data_node) == false)
	{
		memset_s(&file_data_node->plain, sizeof(data_node_t), 0, sizeof(data_node_t)); // scrub the plaintext data
		delete file_data_node;
		last_error = ENOMEM;
		return NULL;
	}

	return file_data_node;
}