【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 工具
else
    SGX_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  # 调试模式:不进行优化,包含调试信息
else
        SGX_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  # 如果不是硬件模式,使用仿真库
else
    Urts_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
else
        App_C_Flags += -DNDEBUG -UEDEBUG -UDEBUG
endif

App_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 mode
	Enclave_Version_Script = Enclave/Enclave.lds 
endif
endif
endif

# 仿真模式与硬件模式下使用不同的库
ifneq ($(SGX_MODE), HW)
    Trts_Library_Name := sgx_trts_sim      # 仿真模式库
    Service_Library_Name := sgx_tservice_sim # 仿真模式服务库
else
    Trts_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
else
	Build_Mode = HW_RELEASE
endif
else
ifeq ($(SGX_DEBUG), 1)
	Build_Mode = SIM_DEBUG
else ifeq ($(SGX_PRERELEASE), 1)
	Build_Mode = SIM_PRERELEASE
else
	Build_Mode = SIM_RELEASE
endif
endif


.PHONY: all run target
all: .config_$(Build_Mode)_$(SGX_ARCH)
	@$(MAKE) target

ifeq ($(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: clean

clean:
	@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):

  1. 通过 sgx_edger8r 工具在 App/ 目录下生成不可信代码(Enclave_u.cEnclave_u.h),这部分生成代码主要会调用 ECALL (sgx_ecall)
  2. 编译不可信部分 Binary: app
  3. 通过sgx_edger8r 工具在 Enclave/ 目录下生成可信代码(Enclave_t.cEnclave_t.h);
  4. 编译可信动态链接库(enclave.so);
  5. 通过sgx_sing工具签名可信动态链接库(enclave.signed.so);
  6. 结束。

编译后的代码目录结构:

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分把,感谢各位大佬支持!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/758834.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ctfshow-web入门-命令执行(web59-web65)

目录 1、web59 2、web60 3、web61 4、web62 5、web63 6、web64 7、web65 都是使用 highlight_file 或者 show_source 1、web59 直接用上一题的 payload&#xff1a; cshow_source(flag.php); 拿到 flag&#xff1a;ctfshow{9e058a62-f37d-425e-9696-43387b0b3629} 2、w…

MathType7.6专业数学公式编辑器!与Word、PPT等常用软件无缝对接。

MathType&#xff0c;一款专业的数学公式编辑器&#xff0c;以其强大的功能和友好的用户界面&#xff0c;在科研、教学等领域广受欢迎。它支持丰富的数学符号和公式模板&#xff0c;满足不同用户的需求。同时&#xff0c;MathType还提供了多种输出格式&#xff0c;方便与其他文…

3ds Max导出fbx贴图问题简单记录

1.前言 工作中发现3ds Max导出的fbx在其它软件&#xff08;Autodesk viewer&#xff0c;blender&#xff0c;navisworks&#xff0c;FBXReview等&#xff09;中丢失了部分贴图&#xff0c;但导出的fbx用3ds Max打开却正常显示。 fbx格式使用范围较广&#xff0c;很多常见的三…

如何用Go语言,实现基于宏系统的解释器?

目录 一、Go语言介绍二、什么是宏系统三、什么是解释器四、如何用Go语言实现一个基于宏系统的解释器&#xff1f; 一、Go语言介绍 Go语言&#xff0c;又称为Golang&#xff0c;是一种由谷歌公司开发并开源的编程语言。Go语言的设计目标是提高程序员的生产力&#xff0c;同时具…

树莓派开发之文件传输

文章目录 一、简介使用U盘传输文件使用SD卡传输文件使用Xftp 7传输文件 二、 总结 一、简介 在树莓派开发中经常会用到文件传输&#xff0c;下面介绍几种树莓派文件传输的几种方法。 使用U盘传输文件 &#xff08;1&#xff09;复制所需传输文件到U盘 &#xff08;2&#…

详细介绍MySQL的索引(上)

索引 索引概述 索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种方式引用(指向数据&#xff0c;这样就可以在这些数据结构上实现高级查找算法&#xff0c;这种数据结…

【计算机图形学】期末考试知识点汇总(上)

文章目录 视频教程第一章 计算机图形学概述计算机图形学的定义计算机图形学的应用计算机图形学 vs 图像处理 vs模式识别图形显示器的发展及工作原理理解三维渲染管线 第二章 基本图元的扫描转换扫描转换直线的扫描转换DDA算法Bresenham算法中点画线算法圆的扫描转换中点画圆算法…

json文件 增删查改

默认收藏夹 qt操作json格式文件... 这个人的 写的很好 我的demo全是抄他的 抄了就能用 —————————— 下次有空把我的demo 传上来 在E盘的demo文件夹 json什么名字

小迪安全v2023笔记 1-18

小迪安全v2023笔记 1-18 棱角社区 文章目录 1. 基础入门1. 正向shell与反向shell2. web应用3. 抓包&#xff0c;封包&#xff0c;协议&#xff0c;app&#xff0c;小程序&#xff0c;pc应用&#xff0c;web应用 2. 信息打点1. 常见信息获取2. 文件泄露3. 常见阻碍4. CDN绕过&a…

二叉树第二期:堆的实现与应用

若对树与二叉树的相关概念&#xff0c;不太熟悉的同学&#xff0c;可移置上一期博客 链接&#xff1a;二叉树第一期&#xff1a;树与二叉树的概念-CSDN博客 本博客目标&#xff1a;对二叉树的顺序结构&#xff0c;进行深入且具体的讲解&#xff0c;同时学习二叉树顺序结构的应用…

电子电路学习笔记(3)三极管

部分内容参考链接&#xff1a; 电子电路学习笔记&#xff08;5&#xff09;——三极管_三极管 箭头-CSDN博客 模拟电子技术基础笔记&#xff08;4&#xff09;——晶体三极管_集电结的单向导电性-CSDN博客 硬件基本功-36-三极管Ib电流如何控制Ic电流_哔哩哔哩_bilibili 部分…

栈的实现

栈 1.栈的概念及结构 栈是一种特殊的线性表&#xff0c;其只允许在固定的一端插入和删除元素。进行插入和删除的一端称为栈顶&#xff0c;另一端称为栈底。栈中的元素支持先进后出的原则。 2.栈的实现 栈的实现一般使用数组和链表&#xff0c;相对而言使用数组更优一些&…

SpringCloud Alibaba Seata2.0基础入门与安装

官网地址&#xff1a;https://seata.apache.org/zh-cn/ GitHub下载地址&#xff1a;https://github.com/apache/incubator-seata/releases 本文这里下载的是seata2.0.0版本。 【1】概述 ① Seata是什么 Simple Extensible Autonomous Transaction Architecture&#xff0c…

python多继承的3C算法

python多继承的3C算法 有很多地方都说python多继承的继承顺序&#xff0c;是按照深度遍历的方式&#xff0c;其实python多继承顺序的算法&#xff0c;不是严格意义上的深度遍历&#xff0c;而是基于深度遍历基础上优化出一种叫3C算法 python多继承的深度遍历 class C:def ru…

实现Set接口的HashSet

HashSet 的底层实现实际上依赖于 HashMap&#xff0c;而 HashMap 的底层结构确实是 数组链表红黑树 的组合。 存储过程 计算哈希值: 当向 HashSet 添加一个元素时&#xff0c;首先会使用该元素的 hashCode() 方法计算其哈希值。 这个哈希值是一个整数&#xff0c;代表了元素在…

idea乱码问题解决

乱码问题产生的根本原因 数据的编码和解码使用的不是同一个字符集 使用了不支持某个语言文字的字符集 Tomcat控制台乱码 在tomcat10.1.7这个版本中,修改 tomcat/conf/logging.properties中,所有的UTF-8为GBK即可 sout乱码问题,设置JVM加载.class文件时使用UTF-8字符集 设置虚…

我重生了,学会了珂朵莉树

还玩线段树吗&#xff1f; 前言&注明 我好像一万年没更新了&#xff1f; 化学&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff…

深度学习笔记: 最详尽解释逻辑回归 Logistic Regression

欢迎收藏Star我的Machine Learning Blog:https://github.com/purepisces/Wenqing-Machine_Learning_Blog。如果收藏star, 有问题可以随时与我交流, 谢谢大家&#xff01; 逻辑回归概述 逻辑回归类似于线性回归&#xff0c;但预测的是某事物是否为真&#xff0c;而不是像大小这…

数字化那点事:一文读懂数字乡村

一、数字乡村的定义 数字乡村是指利用信息技术和数字化手段&#xff0c;推动乡村社会经济发展和治理模式变革&#xff0c;提升乡村治理能力和公共服务水平&#xff0c;实现乡村全面振兴的一种新型发展模式。它包括农业生产的数字化、乡村治理的智能化、乡村生活的现代化等方面…

【ai】trition:tritonclient.utils.shared_memory 仅支持linux

Can’t find tritonclient.utils.shared_memory on WIN10 #4149yolov4的python客户端 导入以后,windows 的pycharm 就是看不到折腾了很久:SaviorEnv 环境下安装tritonclient[all]也会失败 (base) C:\Users\zhangbin>conda create -n SaviorEnv python=3.8 Collecting pack…
最新文章