从0开始写一个 SGX
1.sgx project结构
参考sgxsdk的samplecode中的sampleEnclave
包含文件夹: App,Enclave,Include
包含文件:Makefile,Readme.txt
1.App:
外部程序,在enclave外部运行的代码
外部应用程序源码
2.Enclave:
- Enclave.config.xml:enclave 配置文件
-
tag description defaule value ProdID ISV assigned Product ID 0 ISVSVN ISV assigned ISV 0 TCSNum Number of TCS 1 TCSPolicy TCS bound to untrusted thread = 1
TCS not bound to untrusted thread = 01 StackMaxSize the max stack size per thread(4kb aligned) 0x40000 HeapMaxSize the max heap size for the process(4kb aligned) 0x100000 DisableDebug whether can debug enclave 0/1 yes/no MiscSelect the desired MISC feature 0 MiscMask mask bits for the Misc feature 0xFFFFFFFF 配置enclave的堆栈大小,链接数,
- Enclave_private.pem:用来给动态链接库签名的私钥
- Enclave.lds:encalve link script
-
enclave_entry entry point to enclave g_global_data_sim link to tRTS simulathion for running enclave g_peak_heap_used the size of enclave heap 详细链接参数请参考sgx开发手册
- Enclave.edl:enclave defined language file,用来声明enclave内部的trusted函数和app中的untrusted函数
-
- 如果app中要调用enclave中的函数,那么该函数必须在edl的trusted 中声明;
- 如果enclave中要调用app中的函数,那么该函数必须在edl的untrusted中声明;
- 其他:enclave 内部程序源码
-
3.Include:
外部应用程序和enclave程序共享的头文件,大多是公用的数据类型的定义
4.Makefile
构建项目
2.创建外部应用程序
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_ */
简单封装一下enclave操作
创建一个文件夹enclave
进入
enclave.h#ifndef ENCLAVE_H_ #define ENCLAVE_H_ #include <string> #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <time.h> #include <unistd.h> #include <pwd.h> #define MAX_PATH FILENAME_MAX #include "sgx_urts.h" #include "App.h" #include "Enclave_u.h" #define errlist_len 15 using namespace std; typedef struct _sgx_errlist_t { sgx_status_t err; const char *msg; const char *sug; /* Suggestion */ } sgx_errlist_t; class enclave { private: sgx_errlist_t sgx_errlist[errlist_len] = { { SGX_ERROR_UNEXPECTED, "Unexpected error occurred.", NULL }, { SGX_ERROR_INVALID_PARAMETER, "Invalid parameter.", NULL }, { SGX_ERROR_OUT_OF_MEMORY, "Out of memory.", NULL }, { SGX_ERROR_ENCLAVE_LOST, "Power transition occurred.", "Please refer to the sample \"PowerTransition\" for details." }, { SGX_ERROR_INVALID_ENCLAVE, "Invalid enclave image.", NULL }, { SGX_ERROR_INVALID_ENCLAVE_ID, "Invalid enclave identification.", NULL }, { SGX_ERROR_INVALID_SIGNATURE, "Invalid enclave signature.", NULL }, { SGX_ERROR_OUT_OF_EPC, "Out of EPC memory.", NULL }, { SGX_ERROR_NO_DEVICE, "Invalid SGX device.", "Please make sure SGX module is enabled in the BIOS, and install SGX driver afterwards." }, { SGX_ERROR_MEMORY_MAP_CONFLICT, "Memory map conflicted.", NULL }, { SGX_ERROR_INVALID_METADATA, "Invalid enclave metadata.", NULL }, { SGX_ERROR_DEVICE_BUSY, "SGX device was busy.", NULL }, { SGX_ERROR_INVALID_VERSION, "Enclave version was invalid.", NULL }, { SGX_ERROR_INVALID_ATTRIBUTE, "Enclave was not authorized.", NULL }, { SGX_ERROR_ENCLAVE_FILE_ACCESS, "Can't open enclave file.", NULL } }; public: enclave(string tfn,string efn); sgx_enclave_id_t enclave_id; string token_filename; string p_token_path; string enclave_filename; void print_error_message(sgx_status_t ret); int init(char* token_path); int destroy(void); }; #endif
encalve.cpp
#include "enclave.h" enclave::enclave(string tfn,string efn) { token_filename=tfn; enclave_filename=efn; //enclave_id=global_eid; } int enclave::destroy() { sgx_status_t ret; ret = sgx_destroy_enclave(enclave_id); if(SGX_SUCCESS==ret){ printf("Enclave %d destroy success\n",enclave_id); }else{ print_error_message(ret); printf("Enclave %d destroy failure\n",enclave_id); } return 0; } void enclave::print_error_message(sgx_status_t ret) { size_t idx = 0; size_t ttl = errlist_len; for (idx = 0; idx < ttl; idx++) { if(ret == sgx_errlist[idx].err) { if(NULL != sgx_errlist[idx].sug) printf("Info: %s\n", sgx_errlist[idx].sug); printf("Error: %s\n", sgx_errlist[idx].msg); break; } } if (idx == ttl) printf("Error: Unexpected error occurred.\n"); } int enclave::init(char* token_path) { //char token_path[MAX_PATH] = {'\0'}; sgx_launch_token_t token = {0}; sgx_status_t ret = SGX_ERROR_UNEXPECTED; int updated = 0; const char *home_dir = getpwuid(getuid())->pw_dir; //set token if(token_path==NULL){ token_path=(char*)malloc(MAX_PATH); memset(token_path,0, MAX_PATH); if (home_dir != NULL && (strlen(home_dir)+strlen("/")+sizeof(token_filename)+1) <= MAX_PATH) { strncpy(token_path, home_dir, strlen(home_dir)); strncat(token_path, "/", strlen("/")); strncat(token_path, token_filename.c_str(), sizeof(token_filename)+1); } else { /* if token path is too long or $HOME is NULL */ strncpy(token_path, token_filename.c_str(), sizeof(token_filename)); } } //load token p_token_path=token_path; FILE *fp = fopen(token_path, "rb"); if (fp == NULL && (fp = fopen(token_path, "wb")) == NULL) { printf("Warning: Failed to create/open the launch token file \"%s\".\n", token_path); } if (fp != NULL) { size_t read_num = fread(token, 1, sizeof(sgx_launch_token_t), fp); if (read_num != 0 && read_num != sizeof(sgx_launch_token_t)) { /* if token is invalid, clear the buffer */ memset(&token, 0x0, sizeof(sgx_launch_token_t)); printf("Warning: Invalid launch token read from \"%s\".\n", token_path); } } //create ret = sgx_create_enclave(enclave_filename.c_str(), SGX_DEBUG_FLAG, &token, &updated, &global_eid, NULL); if (ret != SGX_SUCCESS) { enclave_id=0; print_error_message(ret); if (fp != NULL) fclose(fp); return -1; } enclave_id=global_eid; if (updated == FALSE || fp == NULL) { if (fp != NULL) fclose(fp); return 0; } fp = freopen(token_path, "wb", fp); if (fp == NULL) return 0; size_t write_num = fwrite(token, 1, sizeof(sgx_launch_token_t), fp); if (write_num != sizeof(sgx_launch_token_t)) printf("Warning: Failed to save launch token to \"%s\".\n", token_path); fclose(fp); return 0; }
写一个简单的程序模块
创建文件夹function
进入
print.cpp#include "../App.h" #include "Enclave_u.h" /* OCall functions */ void ocall_print_string(const char *str) { printf("==in ocall_print:%s", str); }
因为该模块要给enclave调用,所以要定义edl接口
print.edlenclave { untrusted { //ocall generally not add a public-attribut void ocall_print_string([in, string] const char *str); }; };
外部应用程序的主程序:
app.cpp#include <stdio.h> #include <string.h> #include <assert.h> # include <unistd.h> # include <pwd.h> #include <iostream> # define MAX_PATH FILENAME_MAX #include "sgx_urts.h" #include "App.h" #include "Enclave_u.h" #include "enclave.h" sgx_enclave_id_t global_eid = 0; /* Application entry */ int SGX_CDECL main(int argc, char *argv[]) { (void)(argc); (void)(argv); enclave ecv=enclave(TOKEN_FILENAME,ENCLAVE_FILENAME); /* Initialize the enclave */ if(ecv.init(NULL) < 0){ printf("init failed and exit ...\n"); getchar(); return -1; } //-1 char* start[3]; start[0]="start\n"; start[1]="in\n"; start[2]="app\n"; encall_print(global_eid,start); printf("global eid:%d\n",global_eid); std::cout<<"enclave id:"<< ecv.enclave_id<<std::endl; std::cout<<"token:"<<ecv.p_token_path<<":"<<ecv.token_filename<<std::endl; std::cout<<"enclave file:"<<ecv.enclave_filename<<std::endl; //std::cout<<<<std::endl ecv.destroy(); return 0; }
3.创建enclave应用程序
在Enclave文件夹中
创建enclave程序:#ifndef _ENCLAVE_H_ #define _ENCLAVE_H_ #include <stdlib.h> #include <assert.h> #if defined(__cplusplus) extern "C" { #endif #if defined(__cplusplus) } #endif #endif /* !_ENCLAVE_H_ */
enclave.cpp
#include <stdarg.h> #include <stdio.h> /* vsnprintf */ #include "Enclave.h" #include "Enclave_t.h" /* print_string */ # include <unistd.h> #include <string.h> void encall_print(char **fmt) { char buf[BUFSIZ] = {'\0'}; char* a="\tnow is in encall\n"; strncat(buf,fmt[0],100); strncat(buf,(fmt[1]),100); strncat(buf,(fmt[2]),100); strncat(buf,a,100); ocall_print_string(buf); }
创建给外部程序的接口:
Encalve.edl/* Enclave.edl - Top EDL file. */ enclave { include "user_types.h" /* buffer_t */ from "../App/function/print.edl" import *; trusted{ public void encall_print([user_check] char** fmt); }; };
链接文件
Enclave.ldsenclave.so { global: g_global_data_sim; g_global_data; enclave_entry; local: *; };
配置文件
Enclave.config.xml<!-- Please refer to User's Guide for the explanation of each field --> <EnclaveConfiguration> <ProdID>0</ProdID> <ISVSVN>0</ISVSVN> <StackMaxSize>0x40000</StackMaxSize> <HeapMaxSize>0x100000</HeapMaxSize> <TCSNum>10</TCSNum> <TCSPolicy>1</TCSPolicy> <DisableDebug>0</DisableDebug> <MiscSelect>0</MiscSelect> <MiscMask>0xFFFFFFFF</MiscMask> </EnclaveConfiguration>
4.创建共享的头文件
进入Include文件夹
user_types.h/* User defined types */ #define LOOPS_PER_THREAD 500 typedef void *buffer_t; typedef int array_t[10];
5.创建makefile
Makefile
######## SGX SDK Settings ######## SGX_SDK ?= /opt/intel/sgxsdk SGX_MODE ?= SIM SGX_ARCH ?= x64 ifeq ($(shell getconf LONG_BIT), 32) SGX_ARCH := x86 else ifeq ($(findstring -m32, $(CXXFLAGS)), -m32) SGX_ARCH := x86 endif ifeq ($(SGX_ARCH), x86) SGX_COMMON_CFLAGS := -m32 SGX_LIBRARY_PATH := $(SGX_SDK)/lib SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x86/sgx_sign SGX_EDGER8R := $(SGX_SDK)/bin/x86/sgx_edger8r else SGX_COMMON_CFLAGS := -m64 SGX_LIBRARY_PATH := $(SGX_SDK)/lib64 SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x64/sgx_sign SGX_EDGER8R := $(SGX_SDK)/bin/x64/sgx_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_CFLAGS += -O0 -g else SGX_COMMON_CFLAGS += -O2 endif ######## 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/enclave/*.cpp) $(wildcard App/function/*.cpp) #add more dir in APP: $(wildcard App/dir_name/*.cpp) App_Include_Paths := -IInclude -IApp -I$(SGX_SDK)/include -IApp/enclave App_C_Flags := $(SGX_COMMON_CFLAGS) -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) -std=c++11 App_Link_Flags := $(SGX_COMMON_CFLAGS) -L$(SGX_LIBRARY_PATH) -l$(Urts_Library_Name) -lpthread ifneq ($(SGX_MODE), HW) App_Link_Flags += -lsgx_uae_service_sim else App_Link_Flags += -lsgx_uae_service endif App_Cpp_Objects := $(App_Cpp_Files:.cpp=.o) App_Name := app ######## Enclave Settings ######## 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 #add more Enclave dir $(wildcard Enclave/dir_name/*.cpp) Enclave_Include_Paths := -IInclude -IEnclave -I$(SGX_SDK)/include -I$(SGX_SDK)/include/tlibc -I$(SGX_SDK)/include/stlport Enclave_C_Flags := $(SGX_COMMON_CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector $(Enclave_Include_Paths) Enclave_Cpp_Flags := $(Enclave_C_Flags) -std=c++03 -nostdinc++ Enclave_Link_Flags := $(SGX_COMMON_CFLAGS) -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_tstdcxx -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/Enclave.lds 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 ifeq ($(SGX_MODE), HW) ifneq ($(SGX_DEBUG), 1) ifneq ($(SGX_PRERELEASE), 1) Build_Mode = HW_RELEASE endif endif endif .PHONY: all run ifeq ($(Build_Mode), HW_RELEASE) all: $(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. See User's Guide for more details." @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 all: $(App_Name) $(Signed_Enclave_Name) endif run: all ifneq ($(Build_Mode), HW_RELEASE) @$(CURDIR)/$(App_Name) @echo "RUN => $(App_Name) [$(SGX_MODE)|$(SGX_ARCH), OK]" endif ######## App Objects ######## App/Enclave_u.c: $(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.o: App/Enclave_u.c @$(CC) $(App_C_Flags) -c $< -o $@ @echo "CC <= $<" App/%.o: App/%.cpp @$(CXX) $(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/Enclave_t.c: $(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.o: Enclave/Enclave_t.c @$(CC) $(Enclave_C_Flags) -c $< -o $@ @echo "CC <= $<" Enclave/%.o: Enclave/%.cpp @$(CXX) $(Enclave_Cpp_Flags) -c $< -o $@ @echo "CXX <= $<" $(Enclave_Name): Enclave/Enclave_t.o $(Enclave_Cpp_Objects) @$(CXX) $^ -o $@ $(Enclave_Link_Flags) @echo "LINK => $@" $(Signed_Enclave_Name): $(Enclave_Name) @$(SGX_ENCLAVE_SIGNER) sign -key Enclave/Enclave_private.pem -enclave $(Enclave_Name) -out $@ -config $(Enclave_Config_File) @echo "SIGN => $@" .PHONY: clean clean: @rm -f $(App_Name) $(Enclave_Name) $(Signed_Enclave_Name) $(App_Cpp_Objects) App/Enclave_u.* $(Enclave_Cpp_Objects) Enclave/Enclave_t.*