【SGX系列教程】(二)第一个 SGX 程序: HelloWorld,linux下运行

news2024/11/20 1:41:24

文章目录

  • 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.coloradmin.cn/o/1881880.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入理解Java核心技术模块化局部变量类型推断

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

Python计算n的阶乘的多种方法

1 问题 在课上&#xff0c;我们学习了用递归函数去计算一个自然数n的阶乘。但计算一个自然数n的阶乘是否就这一种方法呢&#xff1f; 2 方法 关于计算一个自然数n的阶乘&#xff0c;通过搜索&#xff0c;我们寻找到了除运用递归函数外的其他三种方法&#xff1a; 方法一 通过导…

【PyQt5】一文向您详细介绍 QLineEdit() 的作用

【PyQt5】一文向您详细介绍 QLineEdit() 的作用 下滑即可查看博客内容 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地&#xff01;&#x1f387; &#x1f393; 博主简介&#xff1a;985高校的普通本硕&…

树洞陪聊陪玩交友程序系统源码,解锁交友新体验

在繁忙的都市生活中&#xff0c;你是否渴望找到一片属于自己的秘密花园&#xff0c;倾诉心声、分享快乐&#xff1f;今天&#xff0c;就让我带你走进这片名为“树洞”的神秘之地&#xff0c;感受陪聊陪玩交友的全新魅力&#xff01; &#x1f333;树洞陪聊陪玩交友程序系统 你…

基于CST2024 Python内部环境的双锥天线自动3D建模和仿真

CST Studio Suite 2024版里面的Python相较于之前有了大的变化。 第一&#xff0c; 增加了cst.asymptotic &#xff0c;cst.radar &#xff0c;cst.units 三个包。 第二&#xff0c;之前CST python只能通过外部环境去操作&#xff0c;现在增加了内部环境控制&#xff0c;可以内…

修改element-ui日期下拉框datetimePicker的背景色样式

如图&#xff1a; 1、修改背景色 .el-date-picker.has-sidebar.has-time { background: #04308D; color: #fff; border: 1px solid #326AFF } .el-date-picker__header-label { color: #ffffff; } .el-date-table th { color: #fff; } .el-icon-d-arrow-left:before { color: …

MyBatis操作数据库(入门)

本节目标 使用MyBatis完成简单的增删改查操作&#xff0c;参数传递掌握MyBatis的两种写法&#xff1a;注解和XML方式掌握MyBatis相关的日志配置 前言 在应用分层学习中&#xff0c;我们了解web应用程序一般分为三层&#xff0c;即Controller、Service、Dao。在之前的案例中&a…

使用Nginx反向代理KKFileView遇到问题

使用KKFileView 4.0 以上版本 在KKFileView官网上&#xff0c;关于使用Nginx代理&#xff0c;建议配置如下 一、修改Nacos 在Nginx的conf文件夹中修改 nginx.conf ,新加 红框内的IP地址为代理服务器地址&#xff08;即安装KKFileView的服务器地址&#xff09; 二、修改KKFil…

计算机组成原理——寄存器

文章目录 1. 寄存器 2. 带寄存器的加法器 3. 时钟信号与计算速度 1. 寄存器 上一篇D触发器可以在时钟上沿存储1位数据。如果想存储多个位&#xff08;bit&#xff09;的数据&#xff0c;就需要用多个D触发器并联实现&#xff0c;这种电路称之为寄存器。 寄存器是计算机中央…

MySQL:表的内连接和外连接、索引

文章目录 1.内连接2.外连接2.1 左外连接2.2 右外连接 3.综合练习4.索引4.1见一见索引4.2 硬件理解4.3 MySQL 与磁盘交互基本单位(软件理解)4.4 (MySQL选择的数据结构)索引的理解4.5 聚簇索引 VS 非聚簇索引 5.索引操作5.1 创建索引5.2 查询索引5.3 删除索引 1.内连接 内连接实…

DreamView数据流

DreamView数据流 查看DV中界面启动dag&#xff0c;/apollo/modules/dreamview_plus/conf/hmi_modes/pnc.pb.txt可以看到点击界面的planning按钮&#xff0c;后台其实启动的是/apollo/modules/planning/planning_component/dag/planning.dag和/apollo/modules/external_command…

IT专业入门,高考假期预习指南

七月来临&#xff0c;各省高考分数已揭榜完成。而高考的完结并不意味着学习的结束&#xff0c;而是新旅程的开始。对于有志于踏入IT领域的高考少年们&#xff0c;这个假期是开启探索IT世界的绝佳时机。 一、基础课程预习指南 IT专业是一个广泛的领域&#xff0c;涵盖了从软件开…

Datawhale机器学习day-1

赛题 在当今科技日新月异的时代&#xff0c;人工智能&#xff08;AI&#xff09;技术正以前所未有的深度和广度渗透到科研领域&#xff0c;特别是在化学及药物研发中展现出了巨大潜力。精准预测分子性质有助于高效筛选出具有优异性能的候选药物。以PROTACs为例&#xff0c;它是…

服装分销的系统架构

背景 服装的分销规则&#xff1a;组织结构由总公司代理商专卖店构成。总公司全权负责销售业务&#xff0c;并决定给代理商的份额&#xff1b;代理商再给货到专卖店&#xff0c;整个组织机构呈现树状结构&#xff1b;上级机构对下级机构拥有控制权&#xff0c;主要控制其销售的服…

Entity Framework EF Migration 迁移

针对Code First来说关注的只有实体类。当需求变更时只需要添加新的实体类或者在实体类中添加、删除、修改属性即可。但是修改完成之后要如何将修改同步到数据库中&#xff1f; migration 机制就出现了 ●启用Migrations   ●通过Add-Migration添加Migration   ●Update-D…

WPF/C#:BusinessLayerValidation

BusinessLayerValidation介绍 BusinessLayerValidation&#xff0c;即业务层验证&#xff0c;是指在软件应用程序的业务逻辑层&#xff08;Business Layer&#xff09;中执行的验证过程。业务逻辑层是应用程序架构中的一个关键部分&#xff0c;负责处理与业务规则和逻辑相关的…

初中英语优秀作文分析-006How to Deal with the Exam Stress-如何应对考试压力

更多资源请关注纽扣编程微信公众号 记忆树 1 We students are very busy with schoolwork and in the face of many exams every school day. 翻译 我们学生忙于功课&#xff0c;每个上学日都面临许多考试。 简化记忆 考试 句子结构 We students 主语 我们学生&#xf…

手把手教你入门vue+springboot开发(六)--后端代码解读与优化

文章目录 前言一、Lombok库二、spring-boot-starter-validation库三、ThreadLocalUtil四、全局异常处理总结 前言 前面我们已经把vuespringboot前后端分离开发和打包部署过程全部打通了&#xff0c;通过一个简单的demo来演示整个过程&#xff0c;主要关注在开发工具使用、框架…

CAD使用技巧,图片去边框,直线等分

CAD插入图片之后怎么去除图片边框 有时候我们需要将图片插入到CAD里面&#xff0c;但是发现插入进去之后&#xff0c;图片周围带有白色边框&#xff0c;这样看着就不是很舒服&#xff0c;要去除边框要如何操作呢 命令操作法&#xff1a;在命令栏输入“imageframe”回车&#xf…