从0开始写一个 SGX

从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 = 0
    1
    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 
    #include 
    #include 
    #include 
    
    #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  
    #include 
    #include 
    
    #include 
    #include 
    #include 
    #include 
    
    #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.edl

    enclave {
    
        untrusted {
        //ocall generally not add a public-attribut
            void ocall_print_string([in, string] const char *str);
    
        };
    };

    外部应用程序的主程序:
    app.cpp

    #include 
    #include 
    #include 
    
    # include 
    # include 
    
    #include 
    # 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:"<":"<std::endl;
        std::cout<<"enclave file:"<std::endl;
        //std::cout<<<
        ecv.destroy();
    
        return 0;
    }
    

    3.创建enclave应用程序

    在Enclave文件夹中
    创建enclave程序:

    #ifndef _ENCLAVE_H_
    #define _ENCLAVE_H_
    
    #include 
    #include 
    
    #if defined(__cplusplus)
    extern "C" {
    #endif
    
    
    #if defined(__cplusplus)
    }
    #endif
    
    #endif /* !_ENCLAVE_H_ */

    enclave.cpp

    #include 
    #include       /* vsnprintf */
    #include "Enclave.h"
    #include "Enclave_t.h"  /* print_string */
    # include 
    #include 
    
    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.lds

    enclave.so
    {
        global:
            g_global_data_sim;
            g_global_data;
            enclave_entry;
        local:
            *;
    };

    配置文件
    Enclave.config.xml

    
    <EnclaveConfiguration>
      <ProdID>0ProdID>
      <ISVSVN>0ISVSVN>
      <StackMaxSize>0x40000StackMaxSize>
      <HeapMaxSize>0x100000HeapMaxSize>
      <TCSNum>10TCSNum>
      <TCSPolicy>1TCSPolicy>
      <DisableDebug>0DisableDebug>
      <MiscSelect>0MiscSelect>
      <MiscMask>0xFFFFFFFFMiscMask>
    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  -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.*
    

    你可能感兴趣的:(SGX)