OpenSGX 安裝編譯教程

介紹:

   英特爾提供的SGX是一個擴展的x86指令集架構,它能讓應用程序在叫做enclave的受保護的容器內運行。爲不信任特權軟件(如:操作系統和虛擬機管理程序)上的應用程序提供隔離的執行和內存保護。通過減少可信計算基(TCB),SGX提供窄攻擊面。掌握了所有的軟件組件和硬件,除CPU包外的敵人不能危害到SGX應用的代碼和數據。SGX不僅保證了程序代碼和數據的完整性,還保證了SGX程序的保密性。

     OpenSGX是基於QEMU的二進制翻譯實現的軟件SGX仿真器,它在指令集水平仿真SGX硬件組件。此外,OpenSGX完全是一個用於SGX開發的平臺,它包含仿真硬件和操作系統組件,enclave程序加載器,一個OpenSGX用戶庫,還支持調試和性能監控。使用OpenSGX能實現調試和評估一個應用程序。

    

     使用QEMU實現SGX指令以及仿真硬件組件。特別的,利用它的二進制翻譯功能,在QEMU的用戶空間仿真模式的頂層實現OpenSGX。Figure 1展示整體設計組件。OpenSGX包含6個一起工作的組件,提供功能齊全的SGX開發環境。6個組件如下:

  1. Intel SGX硬件仿真(Emulated Intel SGX hardware):硬件組件包括SGX指令,SGX數據結構,EPC和它的訪問保護,以及SGX處理鍵內QEMU    軟件。
  2. 操作系統仿真(OS emulation):系統調用仿真enclave程序用於執行SGX操作(如:enclave配置和動態內存分配)。
  3. enclave程序加載(Enclave program loader):一個用於自動處理通過enclave代碼和數據段加載到EPC及適當的提供enclave棧和堆區域的加載器。
  4. OpenSGX用戶庫(libsgx):一個用在enclave內部和外部的方便的庫。它爲所有SGX用戶級指令提供封裝,爲高級應用程序提供接口。
  5. 調試器支持( Debugger support):擴展gbd來映射仿真指令(這裏,,OpenSGX也通過gdb公開SGX數據結構的密鑰)
  6. 性能監視(Performance monitoring):性能計數器/分析器,允許用戶手機enclave程序的性能數據

     需要注意的是OpenSGX不支持英特爾SGX二進制兼容性。現在還沒有具體或標準的二進制級別的互操作。雖然OpenSGX支持大部分的具體的指令,我們並不實現所有的指令。例如,OpenSGX並沒有實現Intel SGX指定的調試指令,但是軟件層能提供豐富的調試環境(例如,熟悉的GBD存根)。OpenSGx是一種軟件仿真器,不提供安全保證。它的安全保證和Intel SGX不是一個層次的。

    首先,下載源碼

   

$git clone https://github.com/sslab-gatech/opensgx.git

    安裝OpenSGX需要的依賴庫: libglib2.0-dev zlib1g-dev libaio-dev autoconf libtool libssl-dev libelf-dev。最好進入root權限安裝,否則可能會導致失敗:

$su     進入root權限
#apt-get install libglib2.0-dev zlib1g-dev libaio-dev autoconf libtool libssl-dev libelf-dev    安裝所需要的庫</span>
     接下來就是編譯QEMU:
    
#cd opensgx/qemu
# ./configure-arch
# make –j $(nproc)</span>

編譯sgxlib和user-level code

# cd ..
# make –C libsgx
# make –C user
如果上述編譯都成功,那麼代碼就可以算是編譯成功了

源代碼組成:

  1. opensgx:用於運行應用程序OpenSGX工具鏈。
  2. qemu:用於SGX指令的硬件仿真 
    qemu/target-i386/sgx-helper.c :ENCLU/ENCLS指令的輔助功能
     qemu/target-i386/sgx.h:EPC, EPCM以及SGX的數據結構
  3. libsgx:OpenSGX庫
    libsgx/musl-libc/:爲OpenSGX程序定製的libc庫
     libsgx/polarssl/:OpenSGX程序輕加密庫
    libsgx/sgx-basic.c:OpenSGX爲封裝ENCLU指令封裝的函數
    libsgx/sgx-entry.c :進入封裝的enclave程序
  4. user:系統仿真,系統調用接口,用戶水平API,OpenSGX測試用例 
    user/sgx-tool.c:用於創建密鑰和數據結構的工具
    user/sgx-runtime.c:啓動enclave的運行庫
    user/sgx-user.c :用戶水平API及系統調用接口
    ser/sgx-kern.c:用於創建enclave的操作系統級封裝
    user/sgx-loader.c:用於執行enclave程序的enclave加載器
    user/sgx-trampoline.c:用於SGX庫支持的Trampoline封裝 
    user/sgx.lds:OpenSGX的鏈接腳本
    user/test/:簡單測試用例
  5. gdb:用於調試EPCM,EPC和SECS的Python腳本

OpenSGX硬件配置

     最初,硬件組件如EPC,EPCM和處理器密鑰實際上是處理器的組成部分。此外,軟件組件,如SIGSTRUCT和EINITTOKEN應駐留在EPC爲受保護的數據結構的一部分。要模擬這些組件,OpenSGX提供了一個名爲“SGX-tool”來指定硬件配置,如EPC的大小和SGX處理器密鑰。它位於user/directory。

配置硬件組件 

    要編譯,構建和執行程序OpenSGX,兩個密鑰必需的。一個是處理器密鑰,而另一個是enclave密鑰。這兩個密鑰可以通過使用sgx-tool -k選項生成。默認情況下,OpenSGX使用處理器的密鑰對爲128位,使用RSA的enclave密鑰對爲3072位。

Generate RSA key with give bits
$ sgx-tool -k [BITS]
Default setting
$ sgx-tool -k 3072 ( For enclave key pair )
$ sgx-tool -k 128 ( For device key pair )
   EPC和EPCM的大小也是可配置的。在qemu/target-i386/directory中,有一個“sgx.h”頭文件。在第26行,定義了NUM_EPC變量(默認,1500)。它是一個enclave開始包含的EPC頁的數量。如果你想改變一個enclave的大小,你可以更改此值,並重新編譯qemu。


配置數據結構
有兩個核心數據結構來驗證enclave和enclave程序員的身份。那是SIGSTRUCT和EINITTOKEN。 SIGSTRUCT從enclave簽名者(OpenSGX程序員)得到enclave信息,並且還具有enclave的散列值。它用來驗證發動encalve時enclave簽名者的身份。 EINITTOKEN在EINIT指令驗證目標enclave是否允許推出時使用。它包含一個通過啓動密鑰(處理器密鑰)計算的加密的MAC,以檢查enclave是否是在運行

SGX啓用的平臺。下面是產生SIGSTRUCT和EINITTOKEN數據結構的具體過程。

Measure binary (生成enclave哈希)
$ sgx-tool -m path/to/binary --begin=STARTADDR --end=ENDADDR --entry=ENTRYADDR
(e.g., sgx-tool -m test/simple --begin=0x426000 --end=0x426018 --entry=0x426000)
Note: 偏移可以通過使用“readelf-S”,找到對應部分的偏移量來獲得。

Sign on sigstruct format with given key (after manually fill the fields)
$ sgx-tool -s path/to/sigstructfile --key=path/to/enclavekeyfile
Note,註冊後用戶需要在sigstruct文件中手動填寫註冊信息 user should manually fill the sign information in the sigstruct file after sign


Generate einittoken format (with reserved fields filled with 0s)
<span style="font-family: Arial, Helvetica, sans-serif;">$ sgx-tool -E</span>
Generate MAC over einittoken format with given key (after manually fill the fields)
$ sgx-tool -M path/to/einittokenfile --key=path/to/devicekeyfile
(e.g., sgx-tool -M sig-einittoken.conf --key=sgx-intel-processor.conf)
Note, 用戶需要手動填寫MAC到einittoken文件.


爲了方便OpenSGX用戶,我們提供一個叫“opensgx”的工具鏈,上述過程是由簡單的命令自動完成。使用opensgx工具鏈的解釋在下面描述。

OpenSGX二進制編譯

    要編譯二進制OpenSGX,它需要多個前提步驟。首先,SGX應用程序開發者創建了他/她自己的簽名密鑰簽名者身份認證。在這之後,你可以編譯OpenSGX程序和使用自己的密鑰進行簽名。在這個階段中,OpenSGX還可以通過計算代碼和數據區域的哈希值計算enclave程序同一性(身份)。然後,你可以運行你自己OpenSGX的應用程序。

生成自己的簽名密鑰
$ ./opensgx –k
(Then, sign.key 文件被創建)
生成hello.sgx (編譯一個OpenSGX應用程序)
$ ./opensgx –c user/demo/hello.c
(Then, hello.sgx創建在user/demo 目錄
生成 hello.conf (註冊並計算出一個OpenSGX應用程序的身份)
$ ./opensgx –s user/demo/hello.sgx --key sign.key
(Then, hello.conf 創建在 user/demo 目錄)
運行OpenSGX程序
$ ./opensgx user/demo/hello.sgx user/demo/hello.conf


實現OpenSGX應用
    實現一個OpenSGX程序類似於正常的C程序。由於對SGX程序的操作系統支持,OpenSGX支持系統調用接口和用戶級的API,用戶只需用他們建立並執行OpenSGX二進制文件。唯一的區別在於,使用enclave_main()而不是主main(),使用sgx_exit(null)代替return。在OpenSGX程序中,在編譯OpenSGX程序時,有可能使用現有的libc庫函數或通過將存檔文件加密的庫函數如polarssl。由於OpenSGX提供它自己的定製鏈接腳本和加載器,所以通過修改,它們用到其他庫中的enclave二進制文件。下面是簡單的Hello World程序的源代碼:
Hello world example

#include “test.h”
void enclave_main()
{
char *hello = "hello sgx!\n";
puts(hello);
sgx_exit(NULL);
}

Trampoline & Stub

    OpenSGX通過使用共享代碼和數據內存提供更嚴格通信協議,分別爲Trampoline & Stub。使用Trampoline & Stub的定義狹窄enclave接口,這使得強制執行相關的安全特性易於處理。圖2示出Trampoline & Stub的示例情況。enclave首先在stub設置輸入參數,然後調用一個預定義的處理程序,trampoline ,通過退出其enclave模式(即,通過調用EEXIT)。


使用libc 庫函數

    在OpenSGX應用程序中使用libc庫,使用trampoline and stub接口是通過修改幾個原glibc庫的代碼。下面是一個包含trampoline and stub接口修改libc函數的源代碼。紅色的是新添加部分。在此,stub的數據結構設置對應的共享區(STUB_ADDR),函數類型(FCODE)和在庫函數輸入/輸出參數。在這裏,輸出參數(out_arg)是函數的輸入變量,輸入參數(in_arg)是函數的返回值。out_arg值被設定之後,它會調用“sgx_exit(stub->蹦牀)”退出enclave模式。

ssize_t read(int fd, void *buf, size_t count)
{
<span style="color:#ff6666;">sgx_stub_info *stub = (sgx_stub_info *)STUB_ADDR;</span>
int tmp_len;
ssize_t rt;
int i;
rt = 0;
for (i = 0; i < count / SGXLIB_MAX_ARG + 1; i++) {
<span style="color:#ff6666;">stub->fcode = FUNC_READ;
stub->out_arg1 = fd;</span>
if (i == count / SGXLIB_MAX_ARG)
tmp_len = (int)count % SGXLIB_MAX_ARG;
else
tmp_len = SGXLIB_MAX_ARG;
<span style="color:#ff6666;">stub->out_arg2 = tmp_len;
sgx_exit(stub->trampoline);</span>
memcpy((uint8_t *)buf + i * SGXLIB_MAX_ARG, stub->in_data1, tmp_len);
<span style="color:#ff6666;">rt += stub->in_arg1;</span>
return rt;
}

一但主機程序或OS處理enclave請求時,它把結果或返回值存儲到stub中,而且通過調用ERESUME.重新進入enclave模式。將程序的控制權交還給已知enclave位置後,enclave最終能得到返回值(e.g,in_arg1 in stub)。

static int sgx_read_tramp(int fd, void *buf, size_t count)
{
return read(fd, buf, count);
}
void sgx_trampoline()
{
switch (stub->fcode) {
case FUNC_PUTS:
…
case FUNC_READ:
stub->in_arg1 = sgx_read_tramp(stub->out_arg1, stub->in_data1, (size_t)stub->out_arg2);
break;
…
}
     要使用enclave程序中的第三方庫,他們的存檔文件(*.a)中或目標文件(*.o)應該被編譯以及連接到SGX程序。目前,OpenSGX支持mbedtls(輕量級SSL庫)和OpenSSL庫。您可以不需要任何修改的使用enclave程序內的庫,在OpenSGX,我們使用mbedtls庫來計算用於mrenclave的SHA256哈希和用於報告數據結構的MAC(消息身份驗證碼Message Authenticate Code)。使用這些庫的唯一事情就是修改Makefile文件;你應該在編譯過程中鏈接歸檔文件或目標文件複製到目標SGX程序(見user/ Makefile中的細節),這是使用enclave內OpenSSL庫函數的示例代碼。

/user/test/openssl/simple-openssl.c

#include "../test.h"
#include <openssl/bn.h>
#include <openssl/rsa.h>
BIGNUM *bn = NULL;
RSA *rsa = NULL;
void enclave_main()
{
// Bignum allocation for global variable
bn = BN_new();
// Bignum allocation for local variable
BIGNUM *bn2 = BN_new();
// RSA allocation for global variable
rsa = RSA_new();
// RSA allocation for local variable
RSA *rsa2 = RSA_new();
printf("%x\n", (unsigned long)rsa2);
}
參數向量
    OpenSGX還支持參數向量指令輸入傳遞給enclave程序。爲了實現這個屬性,OpenSGX提供sgx-entry.S中的彙編代碼傳遞位於libsgx目錄中argc和argv,調用enclave_main之前,sgx-runtime保存參數向量到用戶空間寄存器(RDI,RDX等),並將其傳遞到入口點(enclave_start)。在這裏,“SGX-entry.S”文件定義了enclave_start象徵,它得到的寄存器的值,並把它們進棧。你可以在/user/sgx-runtime.c和/libsgx/sgx-entry.S文件中看到參數向量處理過程的細節。下面是使用參數向量的示例代碼。

/user/test/simple-arg.c

#include "test.h"
void enclave_main(int argc, char **argv)
{
printf("argc = %d\n", argc);
puts(argv[0]);
puts(argv[1]);
puts(argv[2]);
}

上述“test_arg”爲參數簡單的帶參數的程序執行的結果如下。類似的參數向量的一般用法,它可以傳遞參數argc和argv到enclave_main.需要注意的是argv[0] 包括“./../user/sgx-runtime”字符串,因爲test.sh腳本執行sgx-runtime來加載SGX二進制和調用EENTER指令。

smkim@ubuntu:~/src/SGX/opensgx/user$ ./test.sh test/simple-arg test_arg
make: `test/simple-arg' is up to date.
--------------------------------------------
kern in count : 2
kern out count : 2
--------------------------------------------
…
…
…
--------------------------------------------
Pre-allocated EPC SSA region : 0x2000
Pre-allocated EPC Heap region : 0x12c000
Later-Augmented EPC Heap region : 0x0
Total EPC Heap region : 0x12c000
argc = 3                      print argc
./../user/sgx-runtime         print argv[0]
test/simple-arg               print argv[1]
test_arg                      print argv[2]


enclave和non-enclave過程的分離

    要實現SGX程序,最重要的是減少了TCB(可信計算基)。爲了實現這一目標,SGX程序員需要儘量減少SGX程序的大小,例如,如果程序員嘗試實現和執行現有的應用程序,他們需要把核心部分分開(例如,私鑰創建簽名),把他們變成enclave程序。在本教程中我們把在enclave內執行的進程叫做enclave進程,把其他的進程叫做non-enclave進程。在本節中,我們提供了他們如何互相通信,並給他們一個簡單的例子。

    enclave和non-enclave進程通過管道協議進行通信,當nonenclave進程請求核心操作的(例如,要求創建簽名),它發送請求信息給enclave進程,然後,它發送輸入的數據(例如,數據將簽署)到enclave進程。enclave進程接收non-enclave的輸入數據並在enclave執行祕密操作(例如,創建一個簽名)。表明祕密應用程序(例如,私有密鑰)不會被泄露以及在enclave內部被安全保護,安全操作完成後,將結果發送回no-encalve進程。enclave 進程和non-enclave進程位於 user/test/simple-pipe.c和user/non_enclave/simple-pipe.c。

遠程認證

     認證相關的源代碼OpenSGX支持本地/遠程認證。在libsgx目錄有幾個與認證相關函數。您可以通過include ‘sgx-lib.h'使用本地/遠程認證庫函數到enclave程序。下面是相關認證函數原型

Part of /libsgx/include/sgx-lib.h

extern int sgx_enclave_read(void *buf, int len);
extern int sgx_enclave_write(void *buf, int len);

/* SIGSTRUCT parsing function */
extern sigstruct_t *sgx_load_sigstruct(char *conf);

/* Attestation supporting funcitons */
extern int sgx_make_server(int port);
extern int sgx_connect_server(const char *target_ip, int target_port);
extern int sgx_get_report(int fd, report_t *report);
extern int sgx_read_sock(int fd, void *buf, int len);
extern int sgx_write_sock(int fd, void *buf, int len);
extern int sgx_match_mac(unsigned char *report_key, report_t *report);
extern int sgx_make_quote(const char* pers, report_t *report, unsigned char *rsa_N, unsigned char *rsa_E);

/* Intra attestation supporting functions */
extern int sgx_intra_attest_challenger(int target_port, char *conf);
extern int sgx_intra_attest_target(int port);

/* Remote attestation supporing functions */
extern int sgx_remote_attest_challenger(const char *target_ip, int target_port, const char *challenge);
extern int sgx_remote_attest_target(int challenger_port, int quote_port, char *conf);
extern int sgx_remote_attest_quote(int target_port)

內/遠程認證機制

   OpenSGX產生兩種認證特性,一種是本地認證,一種是遠程認證。

    本地認證出現在兩個enclave之間,challenger和target。challenger enclave想要驗證target enclave,使用套接字與target enclave相連。然後challenger enclave從配置文件(.conf)中得到target enclave的身份。challenger enclave通過target enclave的配置文件加載target enclave 的SIGSTRUCT ,然後challenger enclave通過EREPORT指令創建REPORT 並通過套接字寫發送給target enclave,target enclave收到REPORT 然後提取報告密鑰來計算MAC。然後REPORT 驗證MAC的REPORT 並把它的REPORT 發送給challenger enclave。最後,challenger enclave使用target enclave的REPORT相互驗證來反覆驗證這個過程。

    遠程認證比本地部認證更加困難。遠程認證過程需要三個enclave, challenger, target, 和quoting enclave。首先,challenger enclave建立與target enclave的套接字連接,然後向target enclave發送請求。target enclave收到target enclave發送的請求後,就和存在於同一個SGX平臺的quoting enclave開始內認證,兩個enclave完成相互驗證後,target enclave發送認證成功信息給quoting enclave,然後quoting enclave生成QUOTE and RSA 密鑰併發送發送給target enclave。target enclave收到QUOTE and RSA 密鑰後將其轉發給challenger enclave。最後challenger enclave使用RSA密鑰對驗證QUOTE來驗證target enclave。OpenSGX中所有的遠程認證都是基於SGX標準實現的,使用RSA密鑰方案作爲替代EPID。我們使用公共簽名方案(RSA)作爲證明的概念,並留下采用EPID作爲今後的工作。

測試本/遠程認證

OpenSGX支持相關的內部/遠程認證測試代碼,因爲target/quoting enclave配置文件對內/遠程認證是必需的,所以首先需要在demo目錄新建配置文件。可以通過鍵入下面的命令簡單地測試認證碼。

本地認證測試

Terminal #1

$ ./opensgx –k
$ ./opensgx –c user/demo/simple-intra-attest-target.c
$ ./opensgx –s use user/demo/simple-intra-attest-target.sgx --key sign.key
$ ./opensgx user/demo/simple-intra-attest-target.sgx user/demo/simple-intra-attest-target.conf


Terminal  #2

$ cd user
$ ./test.sh test/simple-intra-attest-challenger


遠程認證測試

Terminal #1

$ ./opensgx –k
$ ./opensgx –c user/demo/simple-remote-attest-quote.c
$ ./opensgx –s use user/demo/simple-remote-attest-quote.sgx --key sign.key
$ ./opensgx user/demo/simple-remote-attest-quote.sgx user/demo/simple-remote-attest-quote.conf


Terminal #2

$ cd user
$ ./test.sh test/simple-remote-attest-target

Terminal #3

$ cd user
$ ./test.sh test/simple-remote-attest-challenger
    由於上面的測試在本地計算機環境設計的測試,遠程驗證測試本地使用套接字連接。然而如果你想測試遠程認證在遠程OpenSGX環境,可以簡單的修改測試代碼中的IP地址和端口。

    如果測試成功,會打印出 “Intra/Remote Attestation Success!”,另外,遠程認證測試,您可能需要等待幾秒鐘,因爲生成RSA密鑰和解密QUOTE需要一些時間。

調試支持

由於OpenSGX基於QEMU的用戶模式仿真實現,其二進制轉換使調試更加困難,因爲一個調試器只能觀察轉換後的指令。 從而,
OpenSGX擴展gdb映射仿真的該指令。這下面是一個調試OpenSGX應用程序過程的例子。

用調試操作運行目標應用程序

$ ./opensgx -d 1234 user/demo/hello.sgx user/demo/hello.conf &


連接遠程dbg到目標端口

$ gdb user/sgx-runtime
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
[New Remote target]
Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
[Switching to Remote target]
0x0000004000802190 in ?? () from /lib64/ld-linux-x86-64.so.2
(gdb) b sgx-runtime.c:63
Breakpoint 1 at 0x401a80: file sgx-runtime.c, line 63.
(gdb) c
Continuing.
Breakpoint 1, 0x0000000000401a80 in main ()

Find a text section 

$ readelf -s user/demo/hello.sgx | grep text
[ 2] .text   PROGBITS   0000000050000110 00000110


Add symbol file in gdb by specifying a text section offset

(gdb) add-symbol-file user/demo/hello.sgx 0x0000000050000110
add symbol table from file "user/demo/hello.sgx" at
.text_addr = 0x50000110
(y or n) y
Reading symbols from /home/mingwei/gatech/opensgx_test/user/demo/hello.sgx...done.

Set a breakpoint on the enclave binary and start debugging

(gdb) b enclave_main
Breakpoint 2 at 0x50000110
(gdb) c
Continuing.
Breakpoint 2, 0x0000000050000110 in enclave_main ()
(gdb)

性能監控

OpenSGX還支持性能監視功能。因爲它是一個軟件仿真器,它不能提供精確的性能指標。但是,OpenSGX通過提供類似於性能計數器的模擬性能統計數據的幫助開發人員和研究人員推測潛在性能問題。它公開了一個系統調用來查詢OpenSGX仿真數據。發生上下文切換次數、SGX指令的執行次數等等。此外,opensgx工具鏈提供-i選項(通過使用QEMU的tcg-插件),以計算enclave程序以軟件方式消耗的CPU週期數。

$ cd user
$ ./test.sh –i test/simple-hello


Example:給定的Hello World程序的性能測試

--------------------------------------------
kern in count : 2
kern out count : 2
--------------------------------------------
encls count : 6071
ecreate count : 1
eadd count : 357
eextend count : 5712
einit count : 1
eaug count : 0
--------------------------------------------
enclu count : 2
eenter count : 1
eresume count : 0
eexit count : 1
egetkey count : 0
ereport count : 0
eaccept count : 0
--------------------------------------------
mode switch count : 2tlb flush count
: 2
--------------------------------------------
Pre-allocated EPC SSA region : 0x2000
Pre-allocated EPC Heap region : 0x64000
Later-Augmented EPC Heap region : 0x0
Total EPC Heap region
: 0x64000           Statistics of SGX program
hello sgx!          Result of program
number of executed instructions on CPU #0 = 120950414        Consumed CPU cycles









    




發佈了78 篇原創文章 · 獲贊 28 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章