Quantcast
Channel: 英特尔开发人员专区文章
Viewing all articles
Browse latest Browse all 154

英特尔® Software Guard Extensions 教程系列: 第六部分,双代码路径

$
0
0

英特尔® Software Guard Extensions(英特尔® SGX)) 教程系列的第六部分,我们先将安全区搁在一旁,来处理第二部分应用设计中提出的重要设计要求:支持双代码路径。 我们希望无论主机是否具备英特尔 SGX 功能,都能够支持 Tutorial Password Manager 运行。 本部分的大多数内容摘录自文章准确检测应用中的英特尔® Software Guard 扩展

文章英特尔® Software Guard Extensions 教程系列简介列举了所有已经发布的教程。

本系列的安装部分将提供源代码。

所有英特尔® Software Guard Extensions 应用都需要双代码路径

首先必须指出,所有英特尔 SGX 应用都需要双代码路径。 即使应用编写后只能在英特尔 SGX 可用并已启用的情况下执行,也必须有备用代码路径以向用户显示实用的错误信息,然后体面地退出。

简言之,应用不能仅仅因为平台不支持英特尔 SGX 而出现崩溃或无法启动的情况。

确定问题

第五部分我们完成了第一版应用安全区,并通过硬编码安全区支持,对其进行了测试。 具体做法是在 PasswordCoreNative.cpp 中设置 _supports_sgx标记。

PasswordManagerCoreNative::PasswordManagerCoreNative(void)
{
	_supports_sgx= 1;
	adsize= 0;
	accountdata= NULL;
	timer = NULL;
}

显然,我们不能将其默认为打开状态。 特性检测的惯例是特性默认处于关闭状态,如果需要进行检测,再将其打开。 因此第一步是取消更改,重新将标记设置为 0,以有效禁用英特尔 SGX 代码路径。

PasswordManagerCoreNative::PasswordManagerCoreNative(void)
{
	_supports_sgx= 0;
	adsize= 0;
	accountdata= NULL;
	timer = NULL;
}

不过,进入特性检测流程之前,我们对运行测试套件(CLI 测试应用)的控制台应用进行一次快速的功能测试,具体方法是在不支持英特尔 SGX 特性的老旧系统上执行该应用。 标记设置为 0 时,应用将不选择英特尔 SGX 代码路径,并且应该能够正常运行。

以下是基于第四代智能英特尔® 酷睿™ i7 处理器,运行 64 位 Microsoft Windows* 8.1 的笔记本电脑的输出。 该系统不支持英特尔 SGX。

CLI 测试应用

结果如何?

显然,即使软件中明确禁用了英特尔 SGX 代码路径,我们也遇到了问题。 该应用经过编写,无法在不支持英特尔 SGX 的系统上执行。 它甚至没有开始执行。 具体情况如何?

控制台窗口中显示的错误消息给出了提示:

System.IO.FileNotFoundException: 无法加载文件或汇编‘PasswordManagerCore.dll’或其依赖性。 找不到特定文件。

我们首先查看 PasswordManagerCore.dll 及其依赖性:

其他依赖性

除了核心操作系统库外,我们还依赖 bcrypt.lib and EnclaveBridge.lib,它在运行时需要 bcrypt.dllEnclaveBridge.dll。 由于 bcrypt.dll来源于 Microsoft 并包含在操作系统中,因此我们有理由假定依赖性已安装(如有), 从而留下了 EnclaveBridge.dll

检查依赖性,我们看到:

其他依赖性

这就是问题所在。 即使明确禁用了英特尔 SGX 代码路径,EnclaveBridge.dll依然能够参考英特尔 SGX 运行时库。 加载后,必须解析对象模块中的所有符号。 是否禁用英特尔 SGX 代码路径都无关紧要:未定义符号仍然在 DLL 中。 PasswordManagerCore.dll加载时,通过加载 bcrypt.dllEnclaveBridge.dll解析未定义符号,后者反过来通过加载 sgx_urts.dllsgx_uae_service.dll尝试解析未定义符号。 支持我们尝试运行命令行测试应用的系统没有自己的库,而且由于操作系统无法解析所有符号,因此会出现异常,甚至程序在启动之前崩溃的情况。

这两个 DLL 是英特尔 SGX 平台软件 (PSW) 包的一部分,没有它们,用英特尔 SGX 软件开发套件 (SDK) 编写的英特尔 SGX 应用将无法执行。 即使没有这些库,我们的应用也必须能够运行。

平台软件包

如之前所述,运行时库是 PSW 的一部分。 除了这些支持库外,PSW 还包括:

  • 在系统上支持并维护可信计算模块 (TCB) 的服务
  • 执行和管理部分英特尔 SGX 操作(比如验证)的服务
  • 连接可信时间和单调计数器等平台服务的接口

部署英特尔 SGX 应用时,必须由应用安装程序来安装 PSW,因为英特尔不支持最终用户直接下载 PSW。 软件厂商不能假定目标系统安装了该 PSW。 事实上,英特尔 SGX 许可协议明确规定,被许可方必须根据应用重新分发 PSW。

本系列的安装部分将详细介绍 PSW 安装程序,包括如何打包和部署。

检测英特尔 Software Guard Extensions 支持

到目前为止我们一直专注于在不支持英特尔 SGX — 具体来说是没有 PSW — 的情况下启动系统中的应用。 接下来检测应用运行过程中是否存在并启用了英特尔 SGX 支持。

遗憾的是,英特尔 SGX 特性检测流程非常复杂。 想要系统支持英特尔 SGX,必须满足以下四个条件:

  1. CPU 必须支持英特尔 SGX。
  2. BIOS 必须支持英特尔 SGX。
  3. 在 BIOS 中必须明确启用英特尔 SGX 并将其设置为“software controlled”状态。
  4. 平台必须安装 PSW。

请注意,仅 CPUID 指令并不足以检测平台是否支持英特尔 SGX。 它可告知 CPU 是否支持该特性,但无法提供有关 BIOS 配置或系统是否安装了该软件的信息。 仅依靠 CPUID 结果来制定有关英特尔 SGX 支持的决策可能会导致出现运行时故障。

特性检测更加困难,检查 BIOS 状态并非易事,而且用户通常无法完成这项操作。 幸运的是,英特尔 SGX SDK 提供了一种简单的方法:函数 sgx_enable_device 既能检查系统是否支持英特尔 SGX,还能在 BIOS 设置为软件控制状态时尝试启用该软件(软件控制设置的目的在于支持应用启用英特尔 SGX,用户无需重启系统或进入 BIOS 设置屏幕(对于非技术用户来说是一项异常艰巨的任务))。

但 sgx_enable_device 存在的问题是,它是英特尔 SGX 运行时的一部分,这意味着系统必须安装 PSW 才能使用该函数。 因此在尝试调用 sgx_enable_device 之前,必须首先检测 PSW 是否存在。

实施

确定问题后,现在我们安排必须遵循的步骤,以便双代码路径正常运行。 应用必须:

  1. 即使没有英特尔 SGX 运行时库也依然能够加载并开始执行。
  2. 确定是否安装了 PSW 软件包。
  3. 确定是否启用了英特尔 SGX(并尝试启用)。

在没有英特尔 Software Guard Extensions 运行时的情况下加载和执行

我们的主应用依赖 PasswordManagerCore.dll,后者依赖 EnclaveBridge.dll,而它又反过来依赖英特尔 SGX 运行时。 由于应用加载时需要解析所有符号,因此我们需要防止加载程序解析来自于英特尔 SGX 运行时库的符号。 有以下两种选择:

选择一: 动态加载      

在动态加载过程中,不要明确链接项目中的库。 而是通过系统调用在运行时加载库,然后查看计划使用的函数名称,以便获取它们在内存中的地址。 之后通过函数指示器间接调用库中的函数。

动态加载非常麻烦。 即使只需几个函数,也必须不厌其烦地为所需的函数构建函数指示器原型,并获取加载地址(一次一个)。 由于无法按照名称明确调用函数,因此会失去集成开发环境的部分优势(比如原型辅助)。

动态加载通常用于可扩展应用架构(例如插件)。

选择二: 延迟加载 DLL

采用此方法时,动态链接项目中的所有库,但需要通知 Windows 延迟加载问题 DLL。 延迟加载 DLL 时,Windows 不会在应用启动时尝试解析 DLL 定义的符号, 而是等待程序首次调用该 DLL 中定义的函数,DLL 在该点进行加载,符号(及依赖性)也完成解析。 这意味着只有在应用需要时才会加载 DLL。 此方法的优点是它支持应用引用未安装的 DLL,只要该 DLL 中的函数未经调用。

英特尔 SGX 特性标记关闭时,正好符合这种情况,因此我们选择第二种方法。

在面向从属应用或 DLL 的项目配置中指定需要延迟加载的 DLL。 就本 Tutorial Password Manager 而言,标记为延迟加载的最佳 DLL 为 EnclaveBridge.dll,因为如果启用英特尔 SGX 路径,我们只需调用该 DLL。 如果该 DLL 不加载,两个英特尔 SGX 运行时 DLL 也不加载。

我们设置 PasswordManagerCore.dll 项目配置 Linker -> Input页面中的选项:

密码管理器

第四代智能英特尔酷睿处理器系统重新构建并安装 DLL 后,控制台测试应用将按预期运行。

CLI 测试应用

检测平台软件包

调用 sgx_enable_device 函数检查平台是否支持英特尔 SGX 之前,首先需要确保 PSW 已安装,因为 sgx_enable_device 是英特尔 SGX 运行时的一部分。 最好的方法的尝试加载运行时库。

通过之前的步骤我们知道,不能直接动态加载,因为如果尝试在不支持英特尔 SGX(或没有安装 PSW 包)的系统上运行程序,会导致出现异常。 但我们也不能依赖延迟加载 DLL:延迟加载无法告诉我们库是否已安装,因为如果没有安装,应用将会崩溃! 这意味着我们必须使用动态加载测试是否存在运行时库。

PSW 运行时库应该安装在 Windows 系统目录中,以便我们使用 GetSystemDirectory 获取该路径,并通过调用 SetDllDirectory 限制 DLL 搜索路径。 最后使用 LoadLibrary 加载这两个库。 如果其中一种调用失败,我们将知道 PSW 尚未安装,而且主应用不会尝试运行英特尔 SGX 代码路径。

检测和启用英特尔 Software Guard Extensions

由于上一步骤动态加载了 PSW 运行时库,因此我们只能手动查看有关 sgx_enable_device 的符号,然后通过函数指示器调用该函数。 结果将告诉我们英特尔 SGX 是否已启用。

实施

我们将创建一个名为 FeatureSupport.dll 的新 DLL,以在 Tutorial Password Manager 中实施上述方法。 我们能够安全地通过主应用动态链接此 DLL,因为它不依赖其他 DLL。

特性检测将进入一个名为 FeatureSupport 的 C++/CLI 类,这样还会包含部分高级函数以获取有关英特尔 SGX 状态的信息。 在极少数情况下,通过软件启用英特尔 SGX 可能要求重启系统,此外,还会出现软件启用操作失败并迫使用户在 BIOS 中明确启用该特性的罕见情况。

针对 FeatureSupport 的类声明如下所示。

typedef sgx_status_t(SGXAPI *fp_sgx_enable_device_t)(sgx_device_status_t *);


public ref class FeatureSupport {
private:
	UINT sgx_support;
	HINSTANCE h_urts, h_service;

	// Function pointers

	fp_sgx_enable_device_t fp_sgx_enable_device;

	int is_psw_installed(void);
	void check_sgx_support(void);
	void load_functions(void);

public:
	FeatureSupport();
	~FeatureSupport();

	UINT get_sgx_support(void);
	int is_enabled(void);
	int is_supported(void);
	int reboot_required(void);
	int bios_enable_required(void);

	// Wrappers around SGX functions

	sgx_status_t enable_device(sgx_device_status_t *device_status);

};

以下低级例程可用于检查 PSW 包并尝试检测和启用英特尔 SGX。

int FeatureSupport::is_psw_installed()
{
	_TCHAR *systemdir;
	UINT rv, sz;

	// Get the system directory path. Start by finding out how much space we need
	// to hold it.

	sz = GetSystemDirectory(NULL, 0);
	if (sz == 0) return 0;

	systemdir = new _TCHAR[sz + 1];
	rv = GetSystemDirectory(systemdir, sz);
	if (rv == 0 || rv > sz) return 0;

	// Set our DLL search path to just the System directory so we don't accidentally
	// load the DLLs from an untrusted path.

	if (SetDllDirectory(systemdir) == 0) {
		delete systemdir;
		return 0;
	}

	delete systemdir; // No longer need this

	// Need to be able to load both of these DLLs from the System directory.

	if ((h_service = LoadLibrary(_T("sgx_uae_service.dll"))) == NULL) {
		return 0;
	}

	if ((h_urts = LoadLibrary(_T("sgx_urts.dll"))) == NULL) {
		FreeLibrary(h_service);
		h_service = NULL;
		return 0;
	}

	load_functions();

	return 1;
}

void FeatureSupport::check_sgx_support()
{
	sgx_device_status_t sgx_device_status;

	if (sgx_support != SGX_SUPPORT_UNKNOWN) return;

	sgx_support = SGX_SUPPORT_NO;

	// Check for the PSW

	if (!is_psw_installed()) return;

	sgx_support = SGX_SUPPORT_YES;

	// Try to enable SGX

	if (this->enable_device(&sgx_device_status) != SGX_SUCCESS) return;

	// If SGX isn't enabled yet, perform the software opt-in/enable.

	if (sgx_device_status != SGX_ENABLED) {
		switch (sgx_device_status) {
		case SGX_DISABLED_REBOOT_REQUIRED:
			// A reboot is required.
			sgx_support |= SGX_SUPPORT_REBOOT_REQUIRED;
			break;
		case SGX_DISABLED_LEGACY_OS:
			// BIOS enabling is required
			sgx_support |= SGX_SUPPORT_ENABLE_REQUIRED;
			break;
		}

		return;
	}

	sgx_support |= SGX_SUPPORT_ENABLED;
}

void FeatureSupport::load_functions()
{
	fp_sgx_enable_device = (fp_sgx_enable_device_t)GetProcAddress(h_service, "sgx_enable_device");
}

// Wrappers around SDK functions so the user doesn't have to mess with dynamic loading by hand.

sgx_status_t FeatureSupport::enable_device(sgx_device_status_t *device_status)
{
	check_sgx_support();

	if (fp_sgx_enable_device == NULL) {
		return SGX_ERROR_UNEXPECTED;
	}

	return fp_sgx_enable_device(device_status);
}

总结

通过修改代码,我们已将英特尔 SGX 特性检测集成至应用之中! 不管系统支不支持英特尔 SGX,它都将顺畅执行,并选择合适的代码分支。

如简介部分所述,本部分将提供示例代码供您下载。 随附档案包含面向 Tutorial Password Manager 内核的源代码,包括新的特性检测 DLL。 另外,我们添加了一个新的基于 GUI 的测试程序,可自动选择英特尔 SGX 代码路径,不过也支持您根据需要禁用该特性(此选项仅适用于系统支持英特尔 SGX 的情况)。

SGX 代码分支

基于控制台的测试程序已经过更新,可检测英特尔 SGX,不过它无法进行配置以在不修改源代码的情况下关闭英特尔 SGX。

即将推出

第七部分将重新介绍安全区,以对其界面进行微调。 敬请关注!


Viewing all articles
Browse latest Browse all 154

Trending Articles