secGear 开发指南

这里给出使用 secGear 开发一个 C 语言程序 helloworld 的例子,方便用户理解使用 secGear 开发应用程序。

目录结构说明

使用 secGear 开发的应用程序,遵循统一的目录结构如下:

  1. ├── helloworld
  2. ├── CMakeLists.txt
  3. ├── enclave
  4. ├── CMakeLists.txt
  5. ├── Enclave.config.xml
  6. ├── Enclave.lds
  7. ├── hello.c
  8. ├── manifest.txt.in
  9. └── rsa_public_key_cloud.pem
  10. ├── helloworld.edl
  11. └── host
  12. ├── CMakeLists.txt
  13. └── main.c

快速入门

  1. 创建程序工作目录 helloworld,并在 helloworld 目录下新建 enclave 和 host

  2. 编写 EDL(Encalve Definition Language)文件

为了确保开发代码的一致性,secGear 提供了 secgear_urts.h 和 secgear_tstdc.edl 用于屏蔽底层 Intel SGX 和 ARM iTrustee 之间的差异。因此,使用到 C 语言函数库时,EDL 文件默认需要导入 secgear_urts.h 和 secgear_tstdc.edl。helloworld.edl 文件参考如下:

  1. enclave {
  2. include "secgear_urts.h"
  3. from "secgear_tstdc.edl" import *;
  4. trusted {
  5. public int get_string([out, size=32]char *buf);
  6. };
  7. };

说明:EDL 语法详细信息请参见 Intel SGX 开发指南中对应内容。

  1. 编写顶层文件 CMakeLists.txt

编写顶层文件 CMakeLists.txt,置于 helloworld 工作目录下,用于配置编译时的处理器架构、所需的 EDL 文件等信息。

其中,EDL_FILE 是 EDL 文件,需用户指定,例子中为 helloworld.edl。DPATH 是安全侧加载动态库,配置如例子中所示。

  1. cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
  2. project(HelloWorld C)
  3. set(CMAKE_C_STANDARD 99)
  4. set(CURRENT_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
  5. set(EDL_FILE helloworld.edl)
  6. set(LOCAL_ROOT_PATH "$ENV{CC_SDK}")
  7. set(SECGEAR_INSTALL_PATH /lib64/)
  8. if(CC_GP)
  9. set(CODETYPE trustzone)
  10. set(CODEGEN codegen_arm64)
  11. execute_process(COMMAND uuidgen -r OUTPUT_VARIABLE UUID)
  12. string(REPLACE "\n" "" UUID ${UUID})
  13. add_definitions(-DPATH="/data/${UUID}.sec")
  14. endif()
  15. if(CC_SGX)
  16. set(CODETYPE sgx)
  17. set(CODEGEN codegen_x86_64)
  18. add_definitions(-DPATH="${CMAKE_CURRENT_BINARY_DIR}/enclave/enclave.signed.so")
  19. endif()
  20. add_subdirectory(${CURRENT_ROOT_PATH}/enclave)
  21. add_subdirectory(${CURRENT_ROOT_PATH}/host)
  1. 编写非安全侧代码和 CMakeLists.txt

4.1 编写 main.c

编写非安全侧 main.c,置于 host目录。enclave.h 为 secGear 头文件,helloworld_u.h 为辅助代码生成工具生成的头文件。使用 cc_enclave_create 创建安全区 enclave 上下文,cc_enclave_destroy 销毁安全区上下文。 get_string 为 EDL 文件中定义 trusted 的安全侧函数,注意这里与 EDL 中定义的 get_string 有差别,多出两个参数 context 为安全区上下文,retval 为 EDL 中get_string 的返回值。 res 为 get_string 调用成功标志。

  1. #include <stdio.h>
  2. #include "enclave.h"
  3. #include "helloworld_u.h"
  4. #define BUF_LEN 32
  5. int main()
  6. {
  7. int retval = 0;
  8. char *path = PATH;
  9. char buf[BUF_LEN];
  10. cc_enclave_t *context = NULL;
  11. cc_enclave_result_t res;
  12. res = cc_enclave_create(path, AUTO_ENCLAVE_TYPE, 0, SECGEAR_DEBUG_FLAG, NULL, 0, &context);
  13. ...
  14. res = get_string(context, &retval, buf);
  15. if (res != CC_SUCCESS || retval != (int)CC_SUCCESS) {
  16. printf("Ecall enclave error\n");
  17. } else {
  18. printf("%s\n", buf);
  19. }
  20. if (context != NULL) {
  21. res = cc_enclave_destroy(context);
  22. ...
  23. }
  24. return res;
  25. }

4.2 编写非安全侧 CMakeLists.txt

  1. # 设置编译环境变量
  2. #set auto code prefix
  3. set(PREFIX helloworld)
  4. #set host exec name
  5. set(OUTPUT secgear_helloworld)
  6. #set host src code
  7. set(SOURCE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/main.c)
  8. # 使用代码生成工具生成辅助代码。CODEGEN 和 CODETYPE 变量也在顶层 CMakeLists.txt 中定义。--search-path 用于指定 helloword.edl 中导入依赖的其他 EDL 文件路径
  9. #set auto code
  10. if(CC_GP)
  11. set(AUTO_FILES ${CMAKE_CURRENT_BINARY_DIR}/${PREFIX}_u.h ${CMAKE_CURRENT_BINARY_DIR}/${PREFIX}_u.c ${CMAKE_CURRENT_BINARY_DIR}/${PREFIX}_args.h)
  12. add_custom_command(OUTPUT ${AUTO_FILES}
  13. DEPENDS ${CURRENT_ROOT_PATH}/${EDL_FILE}
  14. COMMAND ${CODEGEN} --${CODETYPE} --untrusted ${CURRENT_ROOT_PATH}/${EDL_FILE} --search-path ${LOCAL_ROOT_PATH}/inc/host_inc/gp)
  15. endif()
  16. if(CC_SGX)
  17. set(AUTO_FILES ${CMAKE_CURRENT_BINARY_DIR}/${PREFIX}_u.h ${CMAKE_CURRENT_BINARY_DIR}/${PREFIX}_u.c)
  18. add_custom_command(OUTPUT ${AUTO_FILES}
  19. DEPENDS ${CURRENT_ROOT_PATH}/${EDL_FILE}
  20. COMMAND ${CODEGEN} --${CODETYPE} --untrusted ${CURRENT_ROOT_PATH}/${EDL_FILE} --search-path ${LOCAL_ROOT_PATH}/inc/host_inc/sgx --search-path ${SGXSDK}/include)
  21. endif()
  22. # 设置编译选项和链接选项
  23. set(CMAKE_C_FLAGS "-fstack-protector-all -W -Wall -Werror -Wextra -Werror=array-bounds -D_FORTIFY_SOURCE=2 -O2 -ftrapv -fPIE")
  24. set(CMAKE_EXE_LINKER_FLAGS "-Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack")
  25. # 编译链接引用目录
  26. if(CC_GP)
  27. if(${CMAKE_VERSION} VERSION_LESS "3.13.0")
  28. link_directories(${SECGEAR_INSTALL_PATH})
  29. endif()
  30. add_executable(${OUTPUT} ${SOURCE_FILE} ${AUTO_FILES})
  31. target_include_directories(${OUTPUT} PRIVATE
  32. /usr/include/secGear/host_inc
  33. /usr/include/secGear/host_inc/gp
  34. ${CMAKE_CURRENT_BINARY_DIR})
  35. if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.13.0")
  36. target_link_directories(${OUTPUT} PRIVATE ${SECGEAR_INSTALL_PATH})
  37. endif()
  38. target_link_libraries(${OUTPUT} secgear)
  39. endif()
  40. if(CC_SGX)
  41. if(${CMAKE_VERSION} VERSION_LESS "3.13.0")
  42. link_directories(${SECGEAR_INSTALL_PATH} ${SGXSDK}/lib64)
  43. endif()
  44. set(SGX_MODE HW)
  45. if(${SGX_MODE} STREQUAL HW)
  46. set(Urts_Library_Name sgx_urts)
  47. else()
  48. set(Urts_Library_Name sgx_urts_sim)
  49. endif()
  50. add_executable(${OUTPUT} ${SOURCE_FILE} ${AUTO_FILES} ${LOCAL_ROOT_PATH}/src/host_src/sgx/sgx_log.c)
  51. target_include_directories(${OUTPUT} PRIVATE
  52. /usr/include/secGear/host_inc
  53. /usr/include/secGear/host_inc/sgx
  54. ${CMAKE_CURRENT_BINARY_DIR})
  55. if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.13.0")
  56. target_link_directories(${OUTPUT} PRIVATE ${SECGEAR_INSTALL_PATH} ${SGXSDK}/lib64)
  57. endif()
  58. target_link_libraries(${OUTPUT} secgear ${Urts_Library_Name})
  59. endif()
  60. # 指定二进制安装目录
  61. set_target_properties(${OUTPUT} PROPERTIES SKIP_BUILD_RPATH TRUE)
  62. if(CC_GP)
  63. install(TARGETS ${OUTPUT}
  64. RUNTIME
  65. DESTINATION /vendor/bin/
  66. PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ)
  67. endif()
  68. if(CC_SGX)
  69. install(TARGETS ${OUTPUT}
  70. RUNTIME
  71. DESTINATION ${CMAKE_BINARY_DIR}/bin/
  72. PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ)
  73. endif()
  1. 编写安全侧代码、CMakeLists.txt 和配置文件,放在 enclave 目录

5.1 编写安全侧代码 hello.c

编写安全侧代码 hello.c,置于 enclave 目录。其中,helloworld_t.h 为辅助代码生成工具,通过 EDL 文件生成的安全侧头文件。

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include "helloworld_t.h"
  4. #define TA_HELLO_WORLD "secGear hello world!"
  5. #define BUF_MAX 32
  6. int get_string(char *buf)
  7. {
  8. strncpy(buf, TA_HELLO_WORLD, strlen(TA_HELLO_WORLD) + 1);
  9. return 0;
  10. }

5.2 编写安全侧 CMakeLists.txt

  1. #set auto code prefix
  2. set(PREFIX helloworld)
  3. #set sign key
  4. set(PEM Enclave_private.pem)
  5. #set sign tool
  6. set(SIGN_TOOL ${LOCAL_ROOT_PATH}/tools/sign_tool/sign_tool.sh)
  7. #set enclave src code
  8. set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/hello.c)
  9. #set log level
  10. set(PRINT_LEVEL 3)
  11. add_definitions(-DPRINT_LEVEL=${PRINT_LEVEL})
  12. # WHITE_LIS_X 设置 itrustee 白名单,只有这些路径的主机二进制文件可以调用此安全映像,并且最多可以配置 8 个列表路径。WHITE_LIST_OWNER 设置用户,此用户将应用于所有白名单路径。DEVICEPEM 公钥由itrustee 使用,并用于通过动态生成的 aes 密钥加密安全侧的安全动态库。
  13. if(CC_GP)
  14. #set signed output
  15. set(OUTPUT ${UUID}.sec)
  16. #set itrustee device key
  17. set(DEVICEPEM ${CMAKE_CURRENT_SOURCE_DIR}/rsa_public_key_cloud.pem)
  18. #set whilelist. default: /vendor/bin/teec_hello
  19. set(WHITE_LIST_0 /vendor/bin/helloworld)
  20. set(WHITE_LIST_OWNER root)
  21. set(WHITE_LIST_1 /vendor/bin/secgear_helloworld)
  22. set(WHITELIST WHITE_LIST_0 WHITE_LIST_1)
  23. set(AUTO_FILES ${CMAKE_CURRENT_BINARY_DIR}/${PREFIX}_t.h ${CMAKE_CURRENT_BINARY_DIR}/${PREFIX}_t.c ${CMAKE_CURRENT_BINARY_DIR}/${PREFIX}_args.h)
  24. add_custom_command(OUTPUT ${AUTO_FILES}
  25. DEPENDS ${CURRENT_ROOT_PATH}/${EDL_FILE}
  26. COMMAND ${CODEGEN} --${CODETYPE} --trusted ${CURRENT_ROOT_PATH}/${EDL_FILE} --search-path ${LOCAL_ROOT_PATH}/inc/host_inc/gp)
  27. endif()
  28. # SGX 安全侧动态库签名
  29. if(CC_SGX)
  30. set(OUTPUT enclave.signed.so)
  31. set(AUTO_FILES ${CMAKE_CURRENT_BINARY_DIR}/${PREFIX}_t.h ${CMAKE_CURRENT_BINARY_DIR}/${PREFIX}_t.c)
  32. add_custom_command(OUTPUT ${AUTO_FILES}
  33. DEPENDS ${CURRENT_ROOT_PATH}/${EDL_FILE}
  34. COMMAND ${CODEGEN} --${CODETYPE} --trusted ${CURRENT_ROOT_PATH}/${EDL_FILE} --search-path ${LOCAL_ROOT_PATH}/inc/host_inc/sgx --search-path ${SGXSDK}/include)
  35. endif()
  36. # 设置编译选项
  37. set(COMMON_C_FLAGS "-W -Wall -Werror -fno-short-enums -fno-omit-frame-pointer -fstack-protector \
  38. -Wstack-protector --param ssp-buffer-size=4 -frecord-gcc-switches -Wextra -nostdinc -nodefaultlibs \
  39. -fno-peephole -fno-peephole2 -Wno-main -Wno-error=unused-parameter \
  40. -Wno-error=unused-but-set-variable -Wno-error=format-truncation=")
  41. set(COMMON_C_LINK_FLAGS "-Wl,-z,now -Wl,-z,relro -Wl,-z,noexecstack -Wl,-nostdlib -nodefaultlibs -nostartfiles")
  42. # itrustee 需生成 manifest.txt。指定 itrustee 编译选项和头文件、链接文件的搜索路径
  43. if(CC_GP)
  44. configure_file("${CMAKE_CURRENT_SOURCE_DIR}/manifest.txt.in" "${CMAKE_CURRENT_SOURCE_DIR}/manifest.txt")
  45. set(CMAKE_C_FLAGS "${COMMON_C_FLAGS} -march=armv8-a ")
  46. set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -s -fPIC")
  47. set(CMAKE_SHARED_LINKER_FLAGS "${COMMON_C_LINK_FLAGS} -Wl,-s")
  48. set(ITRUSTEE_TEEDIR ${iTrusteeSDK}/)
  49. set(ITRUSTEE_LIBC ${iTrusteeSDK}/thirdparty/open_source/musl/libc)
  50. if(${CMAKE_VERSION} VERSION_LESS "3.13.0")
  51. link_directories(${CMAKE_BINARY_DIR}/lib/)
  52. endif()
  53. add_library(${PREFIX} SHARED ${SOURCE_FILES} ${AUTO_FILES})
  54. target_include_directories( ${PREFIX} PRIVATE
  55. ${CMAKE_CURRENT_BINARY_DIR}
  56. ${LOCAL_ROOT_PATH}/inc/host_inc
  57. ${LOCAL_ROOT_PATH}/inc/host_inc/gp
  58. ${LOCAL_ROOT_PATH}/inc/enclave_inc
  59. ${LOCAL_ROOT_PATH}/inc/enclave_inc/gp
  60. ${ITRUSTEE_TEEDIR}/include/TA
  61. ${ITRUSTEE_TEEDIR}/include/TA/huawei_ext
  62. ${ITRUSTEE_LIBC}/arch/aarch64
  63. ${ITRUSTEE_LIBC}/
  64. ${ITRUSTEE_LIBC}/arch/arm/bits
  65. ${ITRUSTEE_LIBC}/arch/generic
  66. ${ITRUSTEE_LIBC}/arch/arm
  67. ${LOCAL_ROOT_PATH}/inc/enclave_inc/gp/itrustee)
  68. if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.13.0")
  69. target_link_directories(${PREFIX} PRIVATE
  70. ${CMAKE_BINARY_DIR}/lib/)
  71. endif()
  72. foreach(WHITE_LIST ${WHITELIST})
  73. add_definitions(-D${WHITE_LIST}="${${WHITE_LIST}}")
  74. endforeach(WHITE_LIST)
  75. add_definitions(-DWHITE_LIST_OWNER="${WHITE_LIST_OWNER}")
  76. target_link_libraries(${PREFIX} -lsecgear_tee)
  77. add_custom_command(TARGET ${PREFIX}
  78. POST_BUILD
  79. COMMAND bash ${SIGN_TOOL} -d sign -x trustzone -i ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/lib${PREFIX}.so -m ${CMAKE_CURRENT_SOURCE_DIR}/manifest.txt
  80. -e ${DEVICEPEM} -o ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${OUTPUT})
  81. install(FILES ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${OUTPUT}
  82. DESTINATION /data
  83. PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
  84. endif()
  85. if(CC_SGX)
  86. set(SGX_DIR ${SGXSDK})
  87. set(CMAKE_C_FLAGS "${COMMON_C_FLAGS} -m64 -fvisibility=hidden")
  88. set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -s")
  89. set(LINK_LIBRARY_PATH ${SGX_DIR}/lib64)
  90. if(CC_SIM)
  91. set(Trts_Library_Name sgx_trts_sim)
  92. set(Service_Library_Name sgx_tservice_sim)
  93. else()
  94. set(Trts_Library_Name sgx_trts)
  95. set(Service_Library_Name sgx_tservice)
  96. endif()
  97. set(Crypto_Library_Name sgx_tcrypto)
  98. set(CMAKE_SHARED_LINKER_FLAGS "${COMMON_C_LINK_FLAGS} -Wl,-z,defs -Wl,-pie -Bstatic -Bsymbolic -eenclave_entry \
  99. -Wl,--export-dynamic -Wl,--defsym,__ImageBase=0 -Wl,--gc-sections -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/Enclave.lds")
  100. if(${CMAKE_VERSION} VERSION_LESS "3.13.0")
  101. link_directories(${LINK_LIBRARY_PATH})
  102. endif()
  103. add_library(${PREFIX} SHARED ${SOURCE_FILES} ${AUTO_FILES})
  104. target_include_directories(${PREFIX} PRIVATE
  105. ${CMAKE_CURRENT_BINARY_DIR}
  106. ${SGX_DIR}/include/tlibc
  107. ${SGX_DIR}/include/libcxx
  108. ${SGX_DIR}/include
  109. ${LOCAL_ROOT_PATH}/inc/host_inc
  110. ${LOCAL_ROOT_PATH}/inc/host_inc/sgx)
  111. if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.13.0")
  112. target_link_directories(${PREFIX} PRIVATE
  113. ${LINK_LIBRARY_PATH})
  114. endif()
  115. target_link_libraries(${PREFIX} -Wl,--whole-archive ${Trts_Library_Name} -Wl,--no-whole-archive
  116. -Wl,--start-group -lsgx_tstdc -lsgx_tcxx -l${Crypto_Library_Name} -l${Service_Library_Name} -Wl,--end-group)
  117. add_custom_command(TARGET ${PREFIX}
  118. POST_BUILD
  119. COMMAND umask 0177
  120. COMMAND openssl genrsa -3 -out ${PEM} 3072
  121. COMMAND bash ${SIGN_TOOL} -d sign -x sgx -i ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/lib${PREFIX}.so -k ${PEM} -o ${OUTPUT} -c ${CMAKE_CURRENT_SOURCE_DIR}/Enclave.config.xml)
  122. endif()
  123. set_target_properties(${PREFIX} PROPERTIES SKIP_BUILD_RPATH TRUE)
  1. 编写配置文件

针对使用 Intel SGX 的 x86_64 处理器架构,请编写 Enclave.config.xml 和 Enclave.lds 文件,置于安全侧 enclave 目录。文件的具体配置格式请参见 SGX 官方文档。

Enclave.config.xml 参考:

  1. <EnclaveConfiguration>
  2. <ProdID>0</ProdID>
  3. <ISVSVN>0</ISVSVN>
  4. <StackMaxSize>0x40000</StackMaxSize>
  5. <HeapMaxSize>0x100000</HeapMaxSize>
  6. <TCSNum>10</TCSNum>
  7. <TCSPolicy>1</TCSPolicy>
  8. <!-- Recommend changing 'DisableDebug' to 1 to make the enclave undebuggable for enclave release -->
  9. <DisableDebug>0</DisableDebug>
  10. <MiscSelect>0</MiscSelect>
  11. <MiscMask>0xFFFFFFFF</MiscMask>
  12. </EnclaveConfiguration>

Enclave.lds 参考:

  1. enclave.so
  2. {
  3. global:
  4. g_global_data_sim;
  5. g_global_data;
  6. enclave_entry;
  7. g_peak_heap_used;
  8. local:
  9. *;
  10. };

将设备公钥文件 rsa_public_key_cloud.pem 复制到 enclave 目录。此处的设备公钥用于使用临时生成的 aes 密钥对安全区动态库进行加密。

说明:rsa_public_key_cloud.pem 文件下载路径:https://gitee.com/openeuler/secGear/blob/master/examples/helloworld/enclave/rsa_public_key_cloud.pem

  1. 编译程序

SGX 版本编译命令如下,编译后将生成可执行程序 secgear_helloworld

  1. cmake -DCMAKE_BUILD_TYPE=debug -DCC_SGX=ON -DSGXSDK="PATH" ./ && make
  1. 执行程序

    1. $ ./secgear_helloworld
    2. Create secgear enclave
    3. secgear hello world!