Linux下SGX的使用(2)-Hello Enclave

来源:互联网 发布:阿里云搭建ss教程 编辑:程序博客网 时间:2024/06/04 01:40

在编写代码之前,我们需要定义可信和不可信的函数,我们首先建立一个文件夹,在文件夹中为了编译方便(仿照上一节的makefile写我们自己的makefie)也仿照sdk给的例子中的文件夹布局建立新的文件夹文件夹的布局如下:这里写图片描述
其中后缀为xml,lds,pem的文件,直接从SDK中SampleEnclave中拷贝即可(在所有的案例中,xml,lds的内容一样,但是名称不一样,也可以自己更该,但是makefile也要更改,pem可以自己生成也可以使用已经存在的pem)一下文件都是参照SampleEnclave中的代码来实现的
首先配置edl文件
我们实现将hello world在enclave中替换成hello enclave!
edl的代码如下:

enclave{    trusted{    public void dck_test([in,out,size=len] char *buf,size_t len);  //in或者out的修饰是必不可少的,否则无法正常读出以及写入    };    untrusted{    };};

之后编写enclave的实现,SGX中是通过enclave.cpp
enclave.cpp的内容如下:

#include "enclave_t.h"                 //包括edl的同名的_t.h文件#include "sgx_trts.h"                 //包括可信的头文件#include <string.h>void dck_test(char *buf,size_t len)   //拷贝函数{    const char *secret="Hello Enclave!";    if(len>=0)    {        memcpy(buf,secret,strlen(secret)+1);    }}

之后是函数的主体也就是test.cpp,首先先看依稀test.h

/* * Copyright (C) 2011-2017 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * *   * Redistributions of source code must retain the above copyright *     notice, this list of conditions and the following disclaimer. *   * Redistributions in binary form must reproduce the above copyright *     notice, this list of conditions and the following disclaimer in *     the documentation and/or other materials provided with the *     distribution. *   * Neither the name of Intel Corporation nor the names of its *     contributors may be used to endorse or promote products derived *     from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */#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_ */

之后定义相关的test.cpp

#include <stdio.h>#include <string.h>#include <assert.h># include <unistd.h># include <pwd.h># define LEN 100            //自己添加的# define MAX_PATH FILENAME_MAX           //这个定义在test.h#include "sgx_urts.h"#include "enclave_u.h"#include "test.h"/* Global EID shared by multiple threads */sgx_enclave_id_t global_eid = 0;    //enclave的IDtypedef struct _sgx_errlist_t {    sgx_status_t err;    const char *msg;    const char *sug; /* Suggestion */} sgx_errlist_t;/* Error code returned by sgx_create_enclave */static sgx_errlist_t sgx_errlist[] = {    {        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    },};/* Check error conditions for loading enclave */void print_error_message(sgx_status_t ret){    size_t idx = 0;    size_t ttl = sizeof sgx_errlist/sizeof sgx_errlist[0];    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");}/* Initialize the enclave: *   Step 1: try to retrieve the launch token saved by last transaction *   Step 2: call sgx_create_enclave to initialize an enclave instance *   Step 3: save the launch token if it is updated */int initialize_enclave(void){    char token_path[MAX_PATH] = {'\0'};    sgx_launch_token_t token = {0};    sgx_status_t ret = SGX_ERROR_UNEXPECTED;    int updated = 0;    /* Step 1: try to retrieve the launch token saved by last transaction      *         if there is no token, then create a new one.     */    /* try to get the token saved in $HOME */    const char *home_dir = getpwuid(getuid())->pw_dir;    if (home_dir != NULL &&         (strlen(home_dir)+strlen("/")+sizeof(TOKEN_FILENAME)+1) <= MAX_PATH) {        /* compose the token path */        strncpy(token_path, home_dir, strlen(home_dir));        strncat(token_path, "/", strlen("/"));        strncat(token_path, TOKEN_FILENAME, sizeof(TOKEN_FILENAME)+1);    } else {        /* if token path is too long or $HOME is NULL */        strncpy(token_path, TOKEN_FILENAME, sizeof(TOKEN_FILENAME));    }    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) {        /* read the token from saved file */        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);        }    }    /* Step 2: call sgx_create_enclave to initialize an enclave instance */    /* Debug Support: set 2nd parameter to 1 */    ret = sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, &token, &updated, &global_eid, NULL);    if (ret != SGX_SUCCESS) {        print_error_message(ret);        if (fp != NULL) fclose(fp);        return -1;    }    /* Step 3: save the launch token if it is updated */    if (updated == FALSE || fp == NULL) {        /* if the token is not updated, or file handler is invalid, do not perform saving */        if (fp != NULL) fclose(fp);        return 0;    }    /* reopen the file with write capablity */    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;}//以上内容都是必须的,都不需要更该/* Application entry */int SGX_CDECL main(int argc, char *argv[]){    (void)(argc);    (void)(argv);    char buffer[LEN]= "Hello world!";    /* Initialize the enclave */    if(initialize_enclave() < 0){        printf("Enter a character before exit ...\n");        getchar();        return -1;     }     dck_test(global_eid,buffer,LEN);    //调用函数,一定要使用enclave的id     printf("%s",buffer);    /* Destroy the enclave */    sgx_destroy_enclave(global_eid);    return 0;}

下面就是重点的makefile了

######## SGX SDK Settings ########不用更改SGX_SDK ?= /opt/intel/sgxsdkSGX_MODE ?= HWSGX_ARCH ?= x64SGX_DEBUG ?= 1ifeq ($(shell getconf LONG_BIT), 32)    SGX_ARCH := x86else ifeq ($(findstring -m32, $(CXXFLAGS)), -m32)    SGX_ARCH := x86endififeq ($(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_edger8relse    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_edger8rendififeq ($(SGX_DEBUG), 1)ifeq ($(SGX_PRERELEASE), 1)$(error Cannot set SGX_DEBUG and SGX_PRERELEASE at the same time!!)endifendififeq ($(SGX_DEBUG), 1)        SGX_COMMON_CFLAGS += -O0 -gelse        SGX_COMMON_CFLAGS += -O2endif######## App Settings ########ifneq ($(SGX_MODE), HW)    Urts_Library_Name := sgx_urts_simelse    Urts_Library_Name := sgx_urtsendifApp_Cpp_Files := App/test.cpp $(wildcard App/Edger8rSyntax/*.cpp) $(wildcard App/TrustedLibrary/*.cpp)      #上述App/。。。更改成我们自己的cpp名称其他的不做更改App_Include_Paths := -IInclude -IApp -I$(SGX_SDK)/includeApp_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 -UEDEBUGelse ifeq ($(SGX_PRERELEASE), 1)        App_C_Flags += -DNDEBUG -DEDEBUG -UDEBUGelse        App_C_Flags += -DNDEBUG -UEDEBUG -UDEBUGendifApp_Cpp_Flags := $(App_C_Flags) -std=c++11App_Link_Flags := $(SGX_COMMON_CFLAGS) -L$(SGX_LIBRARY_PATH) -l$(Urts_Library_Name) -lpthread ifneq ($(SGX_MODE), HW)    App_Link_Flags += -lsgx_uae_service_simelse    App_Link_Flags += -lsgx_uae_serviceendifApp_Cpp_Objects := $(App_Cpp_Files:.cpp=.o)App_Name := test######## Enclave Settings ########ifneq ($(SGX_MODE), HW)    Trts_Library_Name := sgx_trts_sim    Service_Library_Name := sgx_tservice_simelse    Trts_Library_Name := sgx_trts    Service_Library_Name := sgx_tserviceendifCrypto_Library_Name := sgx_tcryptoEnclave_Cpp_Files := Enclave/enclave.cpp $(wildcard Enclave/Edger8rSyntax/*.cpp) $(wildcard Enclave/TrustedLibrary/*.cpp)#更改成我们的cpp文件Enclave_Include_Paths := -IInclude -IEnclave -I$(SGX_SDK)/include -I$(SGX_SDK)/include/tlibc -I$(SGX_SDK)/include/stlportEnclave_C_Flags := $(SGX_COMMON_CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector $(Enclave_Include_Paths)Enclave_Cpp_Flags := $(Enclave_C_Flags) -std=c++03 -nostdinc++# To generate a proper enclave, it is recommended to follow below guideline to link the trusted libraries:#    1. Link sgx_trts with the `--whole-archive' and `--no-whole-archive' options,#       so that the whole content of trts is included in the enclave.#    2. For other libraries, you just need to pull the required symbols.#       Use `--start-group' and `--end-group' to link these libraries.# Do NOT move the libraries linked with `--start-group' and `--end-group' within `--whole-archive' and `--no-whole-archive' options.# Otherwise, you may get some undesirable errors.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  #lds文件的使用Enclave_Cpp_Objects := $(Enclave_Cpp_Files:.cpp=.o)Enclave_Name := enclave.soSigned_Enclave_Name := enclave.signed.soEnclave_Config_File := Enclave/Enclave.config.xmlifeq ($(SGX_MODE), HW)ifeq ($(SGX_DEBUG), 1)    Build_Mode = HW_DEBUGelse ifeq ($(SGX_PRERELEASE), 1)    Build_Mode = HW_PRERELEASEelse    Build_Mode = HW_RELEASEendifelseifeq ($(SGX_DEBUG), 1)    Build_Mode = SIM_DEBUGelse ifeq ($(SGX_PRERELEASE), 1)    Build_Mode = SIM_PRERELEASEelse    Build_Mode = SIM_RELEASEendifendif.PHONY: all runifeq ($(Build_Mode), HW_RELEASE)all: .config_$(Build_Mode)_$(SGX_ARCH) $(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."elseall: .config_$(Build_Mode)_$(SGX_ARCH) $(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."endifendifrun: allifneq ($(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#更改成我们自己的edl文件,此处生成的_t.c要与我们程序中包含的文件_u.h内容以值    @cd App && $(SGX_EDGER8R) --untrusted ../Enclave/enclave.edl --search-path ../Enclave --search-path $(SGX_SDK)/include   #edl要改成我们自己的文件    @echo "GEN  =>  $@"App/enclave_u.o: App/enclave_u.c              #改成上述生成的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)#改成上述步骤生成的_u.o文件    @$(CXX) $^ -o $@ $(App_Link_Flags)    @echo "LINK =>  $@".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)######## Enclave Objects ########Enclave/enclave_t.c: $(SGX_EDGER8R) Enclave/enclave.edl#更改文件内容,这部分是可信的生成文件要与我们文件中include的文件相同    @cd Enclave && $(SGX_EDGER8R) --trusted ../Enclave/enclave.edl --search-path ../Enclave --search-path $(SGX_SDK)/include#更改edl文件    @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)#签名,使用pem进行签名    @echo "SIGN =>  $@".PHONY: cleanclean:    @rm -f .config_* $(App_Name) $(Enclave_Name) $(Signed_Enclave_Name) $(App_Cpp_Objects) App/enclave_u.* $(Enclave_Cpp_Objects) Enclave/enclave_t.*#更改成我们需要的名称

之后使用make,之后运行生成的程序,结果如下:
make
之后运行./test,结果如下:
这里写图片描述
我们的enclave版hello world就完成了!