【SGX系列教程】(二)第一个 SGX 程序: HelloWorld,linux下运行
文章目录
- 0. SGX基础原理分析
- 一.准备工作
- 1.1 前提条件
- 1.2 SGX IDE
- 1.3 基本原理
- 二.程序设计
- 2.1 目录结构
- 2.2 源码设计
- 2.2.1 Encalve/Enclave.edl:Enclave Description Language
- 2.2.2 Enclave/Enclave.lds: Enclave linker script
- 2.2.3 Enclave/Enclave.config.xml: Enclave 配置文件,如堆栈大小、是否支持 Debug 等
- 2.2.4 Enclave/Enclave.h
- 2.2.5 Enclave/Enclave.cpp
- 2.2.6 Enclave/Enclave_private.pem:enclave.so 的签名私钥
- 2.2.7 App/App.h
- 2.2.8 App/App.cpp
- 2.3 Makefile
- 2.4 编译 & 运行
- 2.5 总结
- 三.参考链接
- 四. 感谢支持
0. SGX基础原理分析
本文将向大家展示如何基于 Intel SGX SDK
开发一个最简单 SGX 应用:HelloWorld
,这个程序在可信区生产 "Hello world"并传递给不可信代码(缓冲区)打印输出到终端。 虽然 Intel SGX SDK
安装目录中默认提供了数个 Sample,但每个 Sample 对于初学者来说非常复杂和难以理解。 我们先快速上手,然后再逐个分析每个Sample。关于 SGX 开发运行环境的搭建可参考之前的一篇博客:【SGX系列教程】(一)。
为了更深刻理解理解SGX工程上运行原理,我们先对SGX原理做介绍:
1. 开发者眼中SGX长什么样子?
简单来说SGX就是提供了一个安全内存及其相关。下面稍微讲一下SGX软件栈结构(具体见《SGX软件栈》文档)。
总的来说,SGX是划分两个世界的——可信世界和不可信世界。每一个世界中,想要使用SGX的开发都需要开发哪一个世界的代码,一般来说,不可信世界开发非敏感代码(称为APP,另一种理解就是APP也包含Enclave,这样为了区分,就把不可信的叫做APP),可信世界开发敏感代码(Enclave),或者说敏感代码移入了可信世界。
既然有了两个世界,他们之间的连接就需要有一个叫做桥函数的东西,ECALL桥能让APP可以调用桥函数间接调用Enclave中写好的API函数。反向的有个叫OCALL桥的东西。桥函数上承载着两个世界间传递的参数,而且ECALL中,Enclave并不信任APP传给Enclave的ECALL参数,所以需要参数的消毒检查。OCALL有点类似。
既然要开发程序,就要用到SDK(我这里是把可信Enclave使用的SDK称为SDK,这也符合Intel的叫法,另一种理解是SDK包括给不可信APP使用的PSW、给可信Enclave使用的SDK、桥函数)和PSW,这两个都是Intel提供的(linux下见: github.com/intel/linux-sgx)。由于Enclave要保证自己内部开发的函数尽可能不会离开Enclave,所以Enclave内部用的SDK都是用静态库链接,除非万不得已,比如系统调用等,那么就得同OCALL桥到不可信世界完成任务。然后顶多是启发式的对OCALL返回值进行检查(而且目前Intel并无消毒检查,除非Enclave开发者自己做检查)。
PSW、SDK一部分功能是用于我们传统的那种为了具有某个功能而开发的函数,还有一部分是对CPU提供的SGX功能指令的包装,主要用于SGX特性的支持,为了让你真正和CPU沟通,并获得SGX特性支持。SGX特性是通过CPU向外面提供Ring0指令和Ring3指令,其中Ring0指令ENCLS主要有一些比如创建Enclave这种生命周期管理、页权限管理的指令。Ring3指令ENCLU主要是让控制流能够在两个世界之间流动,比如进出Enclave这种。这一块的细节可以看《SGX软件栈》。
2. SGX访问控制是什么?
SGX访问控制是说对Enclave安全内存进行访问控制,不能让攻击者非法访问敏感内存。这主要还是通过CPU内部实现的。有SGX特性CPU能够让不可信APP只有满足进入它的Enclave的条件时才能放行,而且Enclave A和Enclave B之间是互相不可访问的。这种逻辑是CPU里面的EPCM和内存RAM中被CPU定义为EPC里面的SECS结构体、TCS结构体这些单元连动完成的。《SGX技术的分析和研究》有介绍具体有哪几则访问控制。
3. CPU里面SGX长什么样子?
4. SGX内存分配方式?
一.准备工作
1.1 前提条件
[必须] 你的开发环境必须安装了 Intel SGX SDK
。在安装时安装到了 /opt/intel/sgxsdk
。
[可选] 开发环境主机 CPU 支持 SGX;若不支持,可采用模拟器编译运行(本文实际在硬件支持条件下测试)。
1.2 SGX IDE
本文在ubuntu22.04
中执行,主要是参考了Sample
中工程代码的组织方法。
1.3 基本原理
在演示代码之前,有必要先了解下 SGX 程序最基本的原理:
-
SGX应用由两部分组成:
1. untrusted 不可信区:代码和数据运行在普通非加密内存区域,程序 main 入口必须在非可信区;上图中的 main() 和 bar() 函数均在非可信区。
2. truested 可信区:代码和数据运行在硬件加密内存区域,此区域由 CPU 创建的且只有CPU有权限访问; 上图中的 helloworld() 和 foo() 函数运行在可信区。 -
非可信区只能通过 ECALL 函数调用可信区内的函数。
-
可信区只能通过 OCALL 函数调用非可信区的函数。
-
ECALL 函数和 OCALL 函数通过 EDL 文件声明。
二.程序设计
第一个SGX 程序: HelloWorld
2.1 目录结构
HelloWorld/
├── App
│ ├── App.cpp
│ └── App.h
├── Enclave
│ ├── Enclave.config.xml
│ ├── Enclave.cpp
│ ├── Enclave.edl
│ ├── Enclave.h
│ ├── Enclave.lds
│ └── Enclave_private.pem
├── Include
└── Makefile
上面目录结构仿照了 sgxsdk/SampleCode
目录下示例代码目录:
App
目录内为不可信区域代码,包括 main
入口、OCALL
函数内具体逻辑代码等等。
Enclave
目录为可信区域代码,包括 ECALL
函数内具体逻辑代码实现。
- Enclave.edl: EDL(Enclave Description Language)文件。
- Enclave.lds: Enclave linker script。
- Enclave_private.pem: enclave.so 的签名私钥。
- Enclave.config.xml: Enclave 配置文件,如堆栈大小、是否支持 Debug 等。
- Enclave.h & Enclave.cpp: 应用安全区代码实现。
Include
目录是不可信代码和可信代码共享的头文件。
2.2 源码设计
2.2.1 Encalve/Enclave.edl:Enclave Description Language
enclave {trusted {public void ecall_hello_from_enclave([out, size=len] char* buf, size_t len);};
};
- EDL 中声明了一个公共
ECALL
函数,每个 SGX 应用的 EDL 必须至少声明一个public
类型的ECALL
函数。 trusted {...}
内声明ECALL
函数,untrusted {...}
内申明 OCALL 函数,由于本例中安全区不需要向非安全区调用(OCALL),所以只声明了一个 ECALL 函数ecall_hello_from_enclave
,这个 ECALL 函数目的是在安全区创建一个Buffer
并填充"Hello world"
,然后这个 Buffer 的内容拷贝到非安全的 Buffer 中,非安全区调用printf
打印这个非安全 Buffer 内容。
2.2.2 Enclave/Enclave.lds: Enclave linker script
enclave.so
{global:g_global_data_sim;g_global_data;enclave_entry;g_peak_heap_used;local:*;
};
2.2.3 Enclave/Enclave.config.xml: Enclave 配置文件,如堆栈大小、是否支持 Debug 等
<EnclaveConfiguration><ProdID>0</ProdID><ISVSVN>0</ISVSVN><StackMaxSize>0x40000</StackMaxSize><HeapMaxSize>0x100000</HeapMaxSize><TCSNum>10</TCSNum><TCSPolicy>1</TCSPolicy><!-- Recommend changing 'DisableDebug' to 1 to make the enclave undebuggable for enclave release --><DisableDebug>0</DisableDebug><MiscSelect>0</MiscSelect><MiscMask>0xFFFFFFFF</MiscMask>
</EnclaveConfiguration>
这个配置文件是用来定义Intel SGX信任域(Enclave)的各种参数的。下面是对每一行代码的详细分析,包括它们的功能和用途:
<EnclaveConfiguration>
开始标签:表示SGX信任域配置文件的开始。<ProdID>0</ProdID>
ProdID:表示产品ID。这个值可以由开发者定义,用于区分不同的产品版本。在这里,它被设置为0,表示默认产品ID。<ISVSVN>0</ISVSVN>
ISVSVN:表示独立软件供应商(ISV)的安全版本号。这个值由ISV管理,用于跟踪代码的安全更新。这里设置为0,表示初始的安全版本。<StackMaxSize>0x40000</StackMaxSize>
StackMaxSize:堆栈的最大大小,以十六进制表示。这里设置为0x40000(262144字节或256KB),表示信任域的堆栈内存上限为256KB
。<HeapMaxSize>0x100000</HeapMaxSize>
HeapMaxSize:堆的最大大小,以十六进制表示。这里设置为0x100000(1048576字节或1MB),表示信任域的堆内存上限为1MB
。<TCSNum>10</TCSNum>
TCSNum:线程控制结构(TCS)的数量。这里设置为10,表示可以有10个并发线程在信任域中运行。<TCSPolicy>1</TCSPolicy>
TCSPolicy:TCS的策略。一般情况下,设置为1表示使用默认策略。<DisableDebug>0</DisableDebug>
DisableDebug:定义是否禁用调试。设置为0表示启用调试模式,方便开发调试。但建议在发布版本中设置为1,这样信任域将无法被调试,增强安全性。<MiscSelect>0</MiscSelect>
MiscSelect:选择Miscellaneous功能。这里设置为0,表示未选择任何特定的Misc功能。<MiscMask>0xFFFFFFFF</MiscMask>
MiscMask:定义可用Miscellaneous功能的掩码。0xFFFFFFFF表示允许所有Misc功能。</EnclaveConfiguration>
结束标签:表示SGX信任域配置文件的结束。
总的来说,这个配置文件定义了一个SGX信任域的各种参数和属性,包括产品ID、安全版本号、堆栈和堆内存大小、并发线程数量和策略、调试功能以及Misc功能掩码等。通过设置这些参数,开发者可以控制信任域的内存使用、并发控制以及调试属性,确保信任域在运行时具有所需的功能和安全性。
2.2.4 Enclave/Enclave.h
这个头文件内容基本为空的。
#ifndef _ENCLAVE_H_
#define _ENCLAVE_H_
#endif
2.2.5 Enclave/Enclave.cpp
#include "Enclave.h"
#include "Enclave_t.h" /* print_string */
#include <string.h>void ecall_hello_from_enclave(char *buf, size_t len)
{const char *hello = "Hello world";size_t size = len;if(strlen(hello) < len){size = strlen(hello) + 1;}memcpy(buf, hello, size - 1);buf[size-1] = '\0';
}
2.2.6 Enclave/Enclave_private.pem:enclave.so 的签名私钥
基于openssl命令生成私钥:
openssl genrsa -out Enclave/Enclave_private.pem -3 3072
2.2.7 App/App.h
#ifndef _APP_H_
#define _APP_H_#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>#include "sgx_error.h" /* sgx_status_t */
#include "sgx_eid.h" /* sgx_enclave_id_t */#ifndef TRUE
# define TRUE 1
#endif#ifndef FALSE
# define FALSE 0
#endif# define TOKEN_FILENAME "enclave.token"
# define ENCLAVE_FILENAME "enclave.signed.so"extern sgx_enclave_id_t global_eid; /* global enclave id */#if defined(__cplusplus)
extern "C" {
#endif#if defined(__cplusplus)
}
#endif#endif /* !_APP_H_ */
2.2.8 App/App.cpp
#include <stdio.h>
#include <string.h>
#include <assert.h># include <unistd.h>
# include <pwd.h>
# define MAX_PATH FILENAME_MAX#include "sgx_urts.h"
#include "App.h"
#include "Enclave_u.h"/* Global EID shared by multiple threads */
sgx_enclave_id_t global_eid = 0;int initialize_enclave(void)
{sgx_status_t ret = SGX_ERROR_UNEXPECTED;/* 调用 sgx_create_enclave 创建一个 Enclave 实例 *//* Debug Support: set 2nd parameter to 1 */ret = sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, NULL, NULL, &global_eid, NULL);if (ret != SGX_SUCCESS) {printf("Failed to create enclave, ret code: %d\n", ret);return -1;}return 0;
}/* 应用程序入口 */
int SGX_CDECL main(int argc, char *argv[])
{(void)(argc);(void)(argv);const size_t max_buf_len = 100;char buffer[max_buf_len] = {0};/* 创建并初始化 Enclave */if(initialize_enclave() < 0){printf("Enter a character before exit ...\n");getchar();return -1;}/* ECALL 调用 */ecall_hello_from_enclave(global_eid, buffer, max_buf_len);printf("%s\n", buffer);/* 销毁 Enclave */sgx_destroy_enclave(global_eid);printf("Info: SampleEnclave successfully returned.\n");printf("Enter a character before exit ...\n");getchar();return 0;
}
2.3 Makefile
随便在Sample中找一个工程中的Makefile,稍加改改就能用!!!
######## SGX SDK Settings ########
# 设置 SGX SDK 的路径、模式、架构和调试选项
# SGX SDK 安装路径
SGX_SDK ?= /opt/intel/sgxsdk
# SGX 模式:硬件模式(HW)
SGX_MODE ?= HW
# SGX 架构:64 位(x64)
SGX_ARCH ?= x64
# SGX 调试模式:启用(1)
SGX_DEBUG ?= 1# 判断系统的位数,如果是 32 位,设置架构为 x86
ifeq ($(shell getconf LONG_BIT), 32)SGX_ARCH := x86
# 如果编译器标志中包含 -m32,也设置架构为 x86
else ifeq ($(findstring -m32, $(CXXFLAGS)), -m32)SGX_ARCH := x86
endif# 根据架构选择编译器标志、库路径和工具路径
ifeq ($(SGX_ARCH), x86)SGX_COMMON_FLAGS := -m32 # 设置 32 位编译标志SGX_LIBRARY_PATH := $(SGX_SDK)/lib # 32 位库路径SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x86/sgx_sign # 使用 32 位签名工具SGX_EDGER8R := $(SGX_SDK)/bin/x86/sgx_edger8r # 使用 32 位 Edger8r 工具
elseSGX_COMMON_FLAGS := -m64 # 设置 64 位编译标志SGX_LIBRARY_PATH := $(SGX_SDK)/lib64 # 64 位库路径SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x64/sgx_sign # 使用 64 位签名工具SGX_EDGER8R := $(SGX_SDK)/bin/x64/sgx_edger8r # 使用 64 位 Edger8r 工具
endif# 检查是否同时设置了调试模式和预发布模式
ifeq ($(SGX_DEBUG), 1)
ifeq ($(SGX_PRERELEASE), 1)
$(error Cannot set SGX_DEBUG and SGX_PRERELEASE at the same time!!)
# 如果两个都设置了,报错 "不能同时设置调试模式和预发布模式"
endif
endif# 根据是否启用调试模式设置编译标志
ifeq ($(SGX_DEBUG), 1)SGX_COMMON_FLAGS += -O0 -g # 调试模式:不进行优化,包含调试信息
elseSGX_COMMON_FLAGS += -O2 # 生产模式:优化代码
endif# 设置更多的编译器警告标志,确保代码质量
SGX_COMMON_FLAGS += -Wall -Wextra -Winit-self -Wpointer-arith -Wreturn-type \-Waddress -Wsequence-point -Wformat-security \-Wmissing-include-dirs -Wfloat-equal -Wundef -Wshadow \-Wcast-align -Wcast-qual -Wconversion -Wredundant-decls
SGX_COMMON_CFLAGS := $(SGX_COMMON_FLAGS) -Wjump-misses-init -Wstrict-prototypes -Wunsuffixed-float-constants # C 编译标志
SGX_COMMON_CXXFLAGS := $(SGX_COMMON_FLAGS) -Wnon-virtual-dtor -std=c++11 # C++ 编译标志,使用 C++11 标准######## App Settings ######### 应用程序设置
ifneq ($(SGX_MODE), HW)Urts_Library_Name := sgx_urts_sim # 如果不是硬件模式,使用仿真库
elseUrts_Library_Name := sgx_urts # 如果是硬件模式,使用真实库
endif# 指定应用程序的源文件和包含路径
App_Cpp_Files := App/App.cpp $(wildcard App/TrustedLibrary/*.cpp)
App_Include_Paths := -IApp -I$(SGX_SDK)/include# 设置应用程序的编译标志
App_C_Flags := -fPIC -Wno-attributes $(App_Include_Paths)# 根据不同的配置模式,设置不同的宏定义
# Three configuration modes - Debug, prerelease, release
# Debug - Macro DEBUG enabled.
# Prerelease - Macro NDEBUG and EDEBUG enabled.
# Release - Macro NDEBUG enabled.
ifeq ($(SGX_DEBUG), 1)App_C_Flags += -DDEBUG -UNDEBUG -UEDEBUG
else ifeq ($(SGX_PRERELEASE), 1)App_C_Flags += -DNDEBUG -DEDEBUG -UDEBUG
elseApp_C_Flags += -DNDEBUG -UEDEBUG -UDEBUG
endifApp_Cpp_Flags := $(App_C_Flags)
App_Link_Flags := -L$(SGX_LIBRARY_PATH) -l$(Urts_Library_Name) -lpthread # 生成对象文件的规则
App_Cpp_Objects := $(App_Cpp_Files:.cpp=.o)
# 指定生成的应用程序名称
App_Name := app######## Enclave Settings ########
# 设置信任域版本脚本文件根据调试模式与硬件模式判断
Enclave_Version_Script := Enclave/Enclave.lds
ifeq ($(SGX_MODE), HW)
ifneq ($(SGX_DEBUG), 1)
ifneq ($(SGX_PRERELEASE), 1)# 硬件发布模式下使用的版本脚本文件# Choose to use 'Enclave.lds' for HW release modeEnclave_Version_Script = Enclave/Enclave.lds
endif
endif
endif# 仿真模式与硬件模式下使用不同的库
ifneq ($(SGX_MODE), HW)Trts_Library_Name := sgx_trts_sim # 仿真模式库Service_Library_Name := sgx_tservice_sim # 仿真模式服务库
elseTrts_Library_Name := sgx_trts # 硬件模式库Service_Library_Name := sgx_tservice # 硬件模式服务库
endif
Crypto_Library_Name := sgx_tcrypto # 加密库# 指定信任域的源文件和包含路径
Enclave_Cpp_Files := Enclave/Enclave.cpp $(wildcard Enclave/TrustedLibrary/*.cpp)
Enclave_Include_Paths := -IEnclave -I$(SGX_SDK)/include -I$(SGX_SDK)/include/libcxx -I$(SGX_SDK)/include/tlibc # 设置信任域的编译标志
Enclave_C_Flags := -nostdinc -fvisibility=hidden -fpie -fstack-protector -fno-builtin-printf $(Enclave_Include_Paths)
Enclave_Cpp_Flags := $(Enclave_C_Flags) -nostdinc++# 启用安全链接选项
Enclave_Security_Link_Flags := -Wl,-z,relro,-z,now,-z,noexecstack# 生成信任域的正确链接规则
# 按步骤链接信任库
Enclave_Link_Flags := $(Enclave_Security_Link_Flags) \-Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \-Wl,--whole-archive -l$(Trts_Library_Name) -Wl,--no-whole-archive \-Wl,--start-group -lsgx_tstdc -lsgx_tcxx -l$(Crypto_Library_Name) -l$(Service_Library_Name) -Wl,--end-group \-Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \-Wl,-pie,-eenclave_entry -Wl,--export-dynamic \-Wl,--defsym,__ImageBase=0 \-Wl,--version-script=$(Enclave_Version_Script)
# 指定信任域生成的对象文件
Enclave_Cpp_Objects := $(Enclave_Cpp_Files:.cpp=.o)
# 指定生成的信任域库名
Enclave_Name := enclave.so
Signed_Enclave_Name := enclave.signed.so
# 配置文件和测试密钥文件
Enclave_Config_File := Enclave/Enclave.config.xml
Enclave_Key := Enclave/Enclave_private.pem# 生成不同的构建模式名称
ifeq ($(SGX_MODE), HW)
ifeq ($(SGX_DEBUG), 1)Build_Mode = HW_DEBUG
else ifeq ($(SGX_PRERELEASE), 1)Build_Mode = HW_PRERELEASE
elseBuild_Mode = HW_RELEASE
endif
else
ifeq ($(SGX_DEBUG), 1)Build_Mode = SIM_DEBUG
else ifeq ($(SGX_PRERELEASE), 1)Build_Mode = SIM_PRERELEASE
elseBuild_Mode = SIM_RELEASE
endif
endif.PHONY: all run target
all: .config_$(Build_Mode)_$(SGX_ARCH)@$(MAKE) targetifeq ($(Build_Mode), HW_RELEASE)
target: $(App_Name) $(Enclave_Name)@echo "The project has been built in release hardware mode."@echo "Please sign the $(Enclave_Name) first with your signing key before you run the $(App_Name) to launch and access the enclave."@echo "To sign the enclave use the command:"@echo " $(SGX_ENCLAVE_SIGNER) sign -key <your key> -enclave $(Enclave_Name) -out <$(Signed_Enclave_Name)> -config $(Enclave_Config_File)"@echo "You can also sign the enclave using an external signing tool."@echo "To build the project in simulation mode set SGX_MODE=SIM. To build the project in prerelease mode set SGX_PRERELEASE=1 and SGX_MODE=HW."
else
target: $(App_Name) $(Signed_Enclave_Name)
ifeq ($(Build_Mode), HW_DEBUG)@echo "The project has been built in debug hardware mode."
else ifeq ($(Build_Mode), SIM_DEBUG)@echo "The project has been built in debug simulation mode."
else ifeq ($(Build_Mode), HW_PRERELEASE)@echo "The project has been built in pre-release hardware mode."
else ifeq ($(Build_Mode), SIM_PRERELEASE)@echo "The project has been built in pre-release simulation mode."
else@echo "The project has been built in release simulation mode."
endif
endif# 运行目标规则,首先构建所有目标,然后运行应用程序,除非是在硬件发布模式下。
run: all
ifneq ($(Build_Mode), HW_RELEASE)@$(CURDIR)/$(App_Name)@echo "RUN => $(App_Name) [$(SGX_MODE)|$(SGX_ARCH), OK]"
endif# 配置文件生成规则,如果构建模式和架构改变,重新生成配置
.config_$(Build_Mode)_$(SGX_ARCH):@rm -f .config_* $(App_Name) $(Enclave_Name) $(Signed_Enclave_Name) $(App_Cpp_Objects) App/Enclave_u.* $(Enclave_Cpp_Objects) Enclave/Enclave_t.*@touch .config_$(Build_Mode)_$(SGX_ARCH)######## App Objects ######### 生成 Enclave_u.h,如果 Enclave.edl 改变
App/Enclave_u.h: $(SGX_EDGER8R) Enclave/Enclave.edl@cd App && $(SGX_EDGER8R) --untrusted ../Enclave/Enclave.edl --search-path ../Enclave --search-path $(SGX_SDK)/include@echo "GEN => $@"App/Enclave_u.c: App/Enclave_u.h# 编译 Enclave_u.c 生成对象文件
App/Enclave_u.o: App/Enclave_u.c@$(CC) $(SGX_COMMON_CFLAGS) $(App_C_Flags) -c $< -o $@@echo "CC <= $<"# 编译应用程序源文件生成对象文件
App/%.o: App/%.cpp App/Enclave_u.h@$(CXX) $(SGX_COMMON_CXXFLAGS) $(App_Cpp_Flags) -c $< -o $@@echo "CXX <= $<"# 链接对象文件生成应用程序可执行文件
$(App_Name): App/Enclave_u.o $(App_Cpp_Objects)@$(CXX) $^ -o $@ $(App_Link_Flags)@echo "LINK => $@"######## Enclave Objects ########
# 生成 Enclave_t.h,如果 Enclave.edl 改变
Enclave/Enclave_t.h: $(SGX_EDGER8R) Enclave/Enclave.edl@cd Enclave && $(SGX_EDGER8R) --trusted ../Enclave/Enclave.edl --search-path ../Enclave --search-path $(SGX_SDK)/include@echo "GEN => $@"Enclave/Enclave_t.c: Enclave/Enclave_t.h# 编译 Enclave_t.c 生成对象文件
Enclave/Enclave_t.o: Enclave/Enclave_t.c@$(CC) $(SGX_COMMON_CFLAGS) $(Enclave_C_Flags) -c $< -o $@@echo "CC <= $<"# 编译信任域源文件生成对象文件
Enclave/%.o: Enclave/%.cpp@$(CXX) $(SGX_COMMON_CXXFLAGS) $(Enclave_Cpp_Flags) -c $< -o $@@echo "CXX <= $<"# 生成信任域对象文件
$(Enclave_Cpp_Objects): Enclave/Enclave_t.h# 链接对象文件生成信任域共享库文件
$(Enclave_Name): Enclave/Enclave_t.o $(Enclave_Cpp_Objects)@$(CXX) $^ -o $@ $(Enclave_Link_Flags)@echo "LINK => $@"# 使用测试私钥签名信任域共享库文件
$(Signed_Enclave_Name): $(Enclave_Name)
ifeq ($(wildcard $(Enclave_Key)),)@echo "There is no enclave test key<Enclave_private_test.pem>."@echo "The project will generate a key<Enclave_private_test.pem> for test."@openssl genrsa -out $(Enclave_Key) -3 3072
endif@$(SGX_ENCLAVE_SIGNER) sign -key $(Enclave_Key) -enclave $(Enclave_Name) -out $@ -config $(Enclave_Config_File)@echo "SIGN => $@"# clean 目标,删除生成的文件
.PHONY: cleanclean:@rm -f .config_* $(App_Name) $(Enclave_Name) $(Signed_Enclave_Name) $(App_Cpp_Objects) App/Enclave_u.* $(Enclave_Cpp_Objects) Enclave/Enclave_t.*
2.4 编译 & 运行
比较简单,直接在项目目录下执行 make
,在项目根目录下会生成一个名为 app
的 Binary,运行这个 app
:
$ make
make[1]: 进入目录“/home/hututu/myproject/sgx/helloworld”
GEN => App/Enclave_u.h
CC <= App/Enclave_u.c
CXX <= App/App.cpp
LINK => app
GEN => Enclave/Enclave_t.h
CC <= Enclave/Enclave_t.c
CXX <= Enclave/Enclave.cpp
LINK => enclave.so
<EnclaveConfiguration><ProdID>0</ProdID><ISVSVN>0</ISVSVN><StackMaxSize>0x40000</StackMaxSize><HeapMaxSize>0x100000</HeapMaxSize><TCSNum>10</TCSNum><TCSPolicy>1</TCSPolicy><!-- Recommend changing 'DisableDebug' to 1 to make the enclave undebuggable for enclave release --><DisableDebug>0</DisableDebug><MiscSelect>0</MiscSelect><MiscMask>0xFFFFFFFF</MiscMask>
</EnclaveConfiguration>
tcs_num 10, tcs_max_num 10, tcs_min_pool 1
INFO: Enclave configuration 'MiscSelect' and 'MiscSelectMask' will prevent enclave from using dynamic features. To use the dynamic features on SGX2 platform, suggest to set MiscMask[0]=0 and MiscSelect[0]=1.
The required memory is 3997696B.
The required memory is 0x3d0000, 3904 KB.
handle_compatible_metadata: Overwrite with metadata version 0x100000004
Succeed.
SIGN => enclave.signed.so
The project has been built in debug hardware mode.
make[1]: 离开目录“/home/hututu/myproject/sgx/helloworld”$ ./app
Hello world
Info: SampleEnclave successfully returned.
Enter a character before exit ...
编译基本流程(Makefile):
- 通过
sgx_edger8r
工具在App/
目录下生成不可信代码(Enclave_u.c
和Enclave_u.h
),这部分生成代码主要会调用ECALL (sgx_ecall)
; - 编译不可信部分
Binary: app
; - 通过
sgx_edger8r
工具在Enclave/
目录下生成可信代码(Enclave_t.c
和Enclave_t.h
); - 编译可信动态链接库(
enclave.so
); - 通过
sgx_sing
工具签名可信动态链接库(enclave.signed.so
); - 结束。
编译后的代码目录结构:
HelloWorld
├── app
├── App
│ ├── App.cpp
│ ├── App.h
│ ├── App.o #[generated]
│ ├── Enclave_u.c #[generated]
│ ├── Enclave_u.h #[generated]
│ └── Enclave_u.o #[generated]
├── Enclave
│ ├── Enclave.config.xml
│ ├── Enclave.cpp
│ ├── Enclave.edl
│ ├── Enclave.h
│ ├── Enclave.lds
│ ├── Enclave.o #[generated]
│ ├── Enclave_private.pem
│ ├── Enclave_t.c #[generated]
│ ├── Enclave_t.h #[generated]
│ └── Enclave_t.o #[generated]
├── enclave.signed.so #[generated]
├── enclave.so #[generated]
├── Include
└── Makefile
2.5 总结
即便最简单的 SGX HelloWold
也比较复杂,当然“安全性”和“成本”(技术壁垒门槛、开发成本、维护成本、物料成本等)总是成正比的,和“效率”成反比的。希望这篇文章对那些想入门开发 SGX 应用的用户有所帮助。
三.参考链接
https://developer.aliyun.com/article/740793
Intel SGX入门(一)——背景篇_sgx的psw是什么-CSDN博客
四. 感谢支持
完结撒花!后续将持续输出,形成Intel SGX的系列教程,并结合密码学算法设计更复杂功能。希望看到这里的小伙伴能点个关注,也欢迎志同道合的小伙伴一起广泛交流。
码字实属不易,如果本文对你有10分帮助,就赏个10分把,感谢各位大佬支持!
相关文章:

【SGX系列教程】(二)第一个 SGX 程序: HelloWorld,linux下运行
文章目录 0. SGX基础原理分析一.准备工作1.1 前提条件1.2 SGX IDE1.3 基本原理 二.程序设计2.1 目录结构2.2 源码设计2.2.1 Encalve/Enclave.edl:Enclave Description Language2.2.2 Enclave/Enclave.lds: Enclave linker script2.2.3 Enclave/Enclave.config.xml: Enclave 配置…...

网页报错dns_probe_possible 怎么办?——错误代码有效修复
当你在浏览网页时遇到dns_probe_possible 错误,这通常意味着你的浏览器无法解析域名系统(DNS)地址。这个问题可能是由多种原因引起的,包括网络配置问题、DNS服务问题、或是本地设备的问题。教大家几种修复网页报错dns_probe_possi…...

Vue.js 中属性绑定的详细解析:冒号 `:` 和非冒号的区别
Vue.js 中属性绑定的详细解析:冒号 : 和非冒号的区别 在 Vue.js 中,属性绑定是一个重要的概念,它决定了如何将数据绑定到 DOM 元素的属性上。Vue.js 提供了两种方式来绑定属性:使用冒号 : 进行动态绑定,或直接书写属性…...

使用Java实现智能物流管理系统
使用Java实现智能物流管理系统 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们将探讨如何使用Java语言实现智能物流管理系统,这是一个涉及到…...

深圳技术大学oj C : 生成r子集
Description 输出给定序列按字典序的 � 组合,按照所有 � 个元素出现与否的 01 标记串 ����−1,...,�1 的字典序输出. 此处01串的字典序指:先输入的数字对应低位&#x…...

不同操作系统下的换行符
1. 关键字2. 换行符的比较3. ASCII码4. 修改换行符 4.1. VSCode 5. 参考文档 1. 关键字 CR LF CRLF 换行符 2. 换行符的比较 英文全称英文缩写中文含义转义字符ASCII码值操作系统Carriage ReturnCR回车\r13MacIntosh(早期的Mac)LinefeedLF换行/新行\…...

Transformation(转换)开发-switch/case组件
一、switch/case组件-条件判断 体育老师要做一件非常重要的事情:判断学生是男孩还是女孩、或者是蜘蛛,然后让他们各自到指定的队伍中 体育老师做的事情,我们同样也会在Kettle中会经常用来。在Kettle中,switch/case组件可以来做类似…...

Android Gradle 开发与应用 (二): Android 项目结构与构建配置
目录 1. Android 项目的 Gradle 文件结构 1.1 项目根目录 1.2 模块目录 2. Gradle 构建配置详解 2.1 配置 Android 项目的 build.gradle 2.2 配置模块的 build.gradle 2.3 使用 productFlavors 管理多版本应用 2.4 使用 buildConfigField 注入构建常量 在 Android 开发…...

02:vim的使用和权限管控
vim的使用 1、vim基础使用1.1、vim pathname 2、vim高级用法2.1、查找2.2、设置显示行号2.3、快速切换行2.4、 行删除2.5、行复制粘贴 3、权限管理3.1、普通用户和特权用户3.2、文件权限表示 vim是Linux中的一种编辑器,类似于window中的记事本,可以对创建…...

GNeRF代码复现
https://github.com/quan-meng/gnerf 之前一直去复现这个代码总是文件不存在,我就懒得搞了(实际上是没能力哈哈哈) 最近突然想到这篇论文重新试试复现 一、按步骤创建虚拟环境安装各种依赖等 二、安装好之后下载数据,可以用Blen…...

EXCEL返回未使用数组元素(未使用值)
功能简介: 在我们工作中,需要在EXCEL表列出哪些元素(物品或订单)已经被使用了(或使用了多少次),哪些没有被使用。 当数量过于庞大时人工筛选或许不是好办法,我们可以借助公式&…...

系统调用简单介绍
概述 简单理解就是操作系统给我们提供的函数接口,当我们的程序需要执行一些只有操作系统才能完成的工作的时候,我们就要调用操作系统给我们提供的接口来实现这些功能,这些接口就是系统调用。 那什么样的操作是只有操作系统才能完成呢? 比如…...

Mac可以读取NTFS吗 Mac NTFS软件哪个好 mac ntfs读写工具免费
在跨操作系统环境下使用外部存储设备时,特别是当Windows系统的U盘被连接到Mac电脑时,常常会遇到文件系统兼容性的问题。由于Mac OS原生并不完全支持对NTFS格式磁盘的读写操作,导致用户无法直接在Mac上向NTFS格式的U盘或硬盘写入数据。下面我们…...

AI是否能够做决定
AI是在帮助开发者还是取代他们? 我认为AI功能虽然很强大,但是代替不了人,原因就在于人可以做决定,可以承担责任和后果,但是AI不能够为结果负责...

【Excel操作】Python Pandas判断Excel单元格中数值是否为空
判断Excel单元格中数值是为空,主要有下面两种方法: 1. pandas.isnull 2. pandas.isna判断Excel不为空,也有下面两种方法: 1. pandas.notna 2. pandas.notnull假设有这样一张Excel的表格 我们来识别出为空的单元格 import panda…...

C# Opacity 不透明度
WinForms Opacity以下是一些使用 Opacity 属性的示例:设置窗体的透明度:设置按钮的透明度:动态改变控件的透明度:使用定时器改变透明度:在窗体加载时设置透明度: 请注意另外 WPF Opacity以下是一些使用 Opa…...

推荐三款常用接口测试工具!
接口测试是软件开发中至关重要的一环,通过对应用程序接口进行测试,可以验证其功能、性能和稳定性。随着互联网和移动应用的快速发展,接口测试变得越来越重要。为了提高测试效率和质量,开发人员和测试人员需要使用专业的接口测试工…...

【Qt】Qt多线程编程指南:提升应用性能与用户体验
文章目录 前言1. Qt 多线程概述2. QThread 常用 API3. 使用线程4. 多线的使用场景5. 线程安全问题5.1. 加锁5.2. QReadWriteLocker、QReadLocker、QWriteLocker 6. 条件变量 与 信号量6.1. 条件变量6.2 信号量 总结 前言 在现代软件开发中,多线程编程已成为一个不可…...

PyTorch之nn.Module、nn.Sequential、nn.ModuleList使用详解
文章目录 1. nn.Module1.1 基本使用1.2 常用函数1.2.1 核心函数1.2.2 查看函数1.2.3 设置函数1.2.4 注册函数1.2.5 转换函数1.2.6 加载函数 2. nn.Sequential()2.1 基本定义2.2 Sequential类不同的实现2.3 nn.Sequential()的本质作用 3. nn.ModuleList参考资料 本篇文章主要介绍…...

C++Primer Plus 第十四章代码重用:编程练习,第4题
CPrimer Plus 第十四章代码重用:编程练习,第4题 CPrimer Plus 第十四章代码重用:编程练习,第4题 文章目录 CPrimer Plus 第十四章代码重用:编程练习,第4题前言4.一、定义二、方法 前言 4. Person 类保存人的名和姓。除构造函数外ÿ…...

01 Docker 概述
目录 1.Docker简介 2.传统虚拟机 vs 容器 3.Docker运行速度快的原因 4.Docker基本组成三要素 5.Docker 平台架构 入门版 架构版 1.Docker简介 Docker是基于Go语言实现的云开源项目。 Docker的主要目标是:Build, Ship and Run Any App, Anywhere,…...

c++的const
const在C中是一个非常重要的关键字,用于定义不可变的变量、函数参数、成员函数等。它可以提高代码的可读性、安全性,并帮助编译器进行优化。 定义常量 使用const定义不可变的变量: const int MAX_SIZE 100;常量指针 指向常量的指针和常量…...

Git不想跟踪某个文件
如果你不想跟踪某个文件,可以将该文件路径添加到 .gitignore 文件中。.gitignore 文件用于告诉 Git 哪些文件或目录应该被忽略,不进行版本控制。以下是具体步骤: 编辑 .gitignore 文件:在项目的根目录下找到或创建一个 .gitignore…...

DB-GPT 文档切分报错
感谢阅读 配置完知识库,进行切分报错切分完成后,进行问答时后台日志报错 配置完知识库,进行切分报错 报的错如下 document sync error cryptography>3.1 is required for AES algorithm pip install -U cryptography 之后重新运行程序 …...

#如何使用 Qt 5.6 在 Android 上启用 NFC
如何使用 Qt 5.6 在 Android 上启用 NFC NFC 技术在 Android 应用开发中变得越来越重要。在本文中,我将介绍如何使用 Qt 5.6 来实现 Android 上的 NFC 功能。这个教程基于一个创建于 8 年 8 个月前的问题,并在 7 年 3 个月前进行了修改,讨论…...

合并排序的数组
题目链接 合并排序的数组 题目描述 注意点 A的末端有足够的缓冲空间容纳BA和B都是排序的 解答思路 最初想到的是双指针,从小到大找到合并B时应该A相应位置应该插入的元素,因为在插入的过程中B的元素会替换A原有位置的元素,所以需要先将A…...

js 复制文本带样式
一键复制带样式的html文本到邮件 <div><div idcopy-content><div style{{ fontSize: 16px,fontWeight: 500, lineHeight: 24px, color: #222, marginBottom: 16px }}>邀请您参加腾讯会议网络研讨会(Webinar)</div></div><Button …...

服务器之BIOS基础知识总结
1.BIOS是什么? BIOS全称Basic Input Output System,即基本输入输出系统,是固化在服务器主板的专用ROM上,加载在服务器硬件系统上最基本的运行程序,它位于服务器硬件和OS之间,在服务器启动过程中首先运行&am…...

FFmpeg 实现从摄像头获取流并通过RTMP推流
使用FFmpeg库实现从USB摄像头获取流并通过RTMP推流,FFmpeg版本为4.4.2-0。RTMP服务器使用的是SRS,拉流端使用VLC。 在Linux上查看摄像头信息可使用 v4l2-ctl 工具,查看命令如下: v4l2-ctl --device/dev/video0 --list-formats-e…...

学生管理系统
一、登录 用户类:属性:用户名、密码、身份证号码、手机号码 1、欢迎页面 System.out.println("欢迎来到学生管理系统"); System.out.println("请选择操作1登录 2注册 3忘记密码"); 代码实现: //欢迎页面public static…...