当前位置: 首页 > 工具软件 > EDL > 使用案例 >

SGX中Enclave.edl代码解析

楚嘉
2023-12-01

Enclave.edl文件中主要包括trusted和untrusted两部分。

一、trusted文件内容

(一)trusted中出现的不带返回值的函数如:

public void process_log([in,string] char *str);

它必须得是public类型的,否则在enclave外无法进行ecall的调用。[in]表示数据流将从不可信部分拷贝进入enclave内部。[out]则方向相反。如果是untrusted中的函数[in]和[out]的数据流则刚好跟trusted中的相反。关于[in,string]等的详细讲解在开发指南Page52中。

凡是出现在trusted部分的函数都必须在Enclave.cpp或者Enclave文件夹中的.cpp文件实现。同时上面函数在经过sgx_edger8r工具处理后会在Enclave_u.h中进行声明,成为下面函数:

sgx_status_t process_log(sgx_enclave_id_t eid, char* str);

并在Enclave_u.c文件中实现,如下:

sgx_status_t process_log(sgx_enclave_id_t eid, char* str)

{

sgx_status_t status;

ms_process_log_t ms;

ms.ms_str = str;

ms.ms_str_len = str ? strlen(str) + 1 : 0;

status = sgx_ecall(eid, 0, &ocall_table_Enclave, &ms);  

return status;

}

其中ms_process_log_t也是在enclave_u.c中,其定义为:

typedef struct ms_process_log_t {

char* ms_str;

size_t ms_str_len;

} ms_process_log_t;

因为process_log函数中是有参数的,参数为char *str,所以ms_process_log_t结构中第一个是char* ms_str,第二个是ms_str_len。

思考一下,因为process_log([in,string] char *str)是出现在trusted部分的,那么它应该是要被不可信代码ecall从而在enclave内部执行,所以需要出现在Enclave_u部分里面,从而才能允许不可信代码的调用。它在Enclave_u部分的返回值为sgx_status_t,如果成功则为SGX_SUCCESS(0),否则为别的值。而在Enclave_u部分的代码是通过上面黄色部分sgx_ecall代码与Enclave_c部分进行关联的。因为process_log函数在Enclave.edl文件中的trusted部分是第一个函数,所以它的索引是0。在Enclave_t.h中其声明为void process_log(char* str);,但其实现是在Enclave.cpp中,在Enclave_t.c中有一个与其相关的函数为:

static sgx_status_t SGX_CDECL sgx_process_log(void* pms){……}

 

综上:Enclave.edl中trusted部分中的函数会在:

1Enclave.cpp中定义其实现;2经过sgx_edger8r处理会在Enclave_u.h中声明;3并在Enclave_u.c中实现.h中的声明;4同时还会在Enclave_t.h中进行声明;5并在Enclave_t.c中有一个sgx开头的相关函数。

(二)trusted中出现的带返回值的函数如:

public uint32_t verify_block_messages();

注意该函数不需要参数,同时返回值类型为uint32_t。

1则同样会在Enclave.cpp中定义其实现;

2经过sgx_edger8r处理会在Enclave_u.h中声明,其声明为:

sgx_status_t verify_block_messages(sgx_enclave_id_t eid, uint32_t* retval);

注意其返回值同样为sgx_status_t,成功则为SGX_SUCCESS,否则为别的值。该函数的参数中eid为Enclave的id号,uint32_t* retval用于保存返回的值。

3在Enclave_u.c中实现.h中的声明:

sgx_status_t verify_block_messages(sgx_enclave_id_t eid, uint32_t* retval)

{

sgx_status_t status;

ms_verify_block_messages_t ms;

status = sgx_ecall(eid, 1, &ocall_table_Enclave, &ms);

if (status == SGX_SUCCESS && retval) *retval = ms.ms_retval;

return status;

}

该函数在Enclave.edl中的trusted部分第2个出现,所以索引为1.

typedef struct ms_verify_block_messages_t {

uint32_t ms_retval;

} ms_verify_block_messages_t;

因为verify_block_messages()的原始定义中是没有参数的,所以ms_verify_block_messages_t结构中只有一个是uint32_t ms_retval用来做返回值。

4同时还会在Enclave_t.h中进行声明:

uint32_t verify_block_messages(void);

5在Enclave_t.c中有一个sgx开头的相关函数:

static sgx_status_t SGX_CDECL sgx_verify_block_messages(void* pms)

二、untrusted文件内容

(一)untrusted中出现不带返回值的函数如:

void ocall_print_string([in, string] const char *str);

注意:该函数无返回值,且参数为const char *str类型。

1凡是出现在untrusted部分的函数都必须在不可信代码如App.cpp中实现;

2经过sgx_edger8r工具的处理会在Enclave_t.h中声明为:

sgx_status_t SGX_CDECL ocall_print_string(const char* str);

注意:它的返回值为sgx_status_t,成功则为SGX_SUCCESS,否则为别的值。

3在Enclave_t.c中的实现为:

sgx_status_t SGX_CDECL ocall_print_string(const char* str)

{

sgx_status_t status = SGX_SUCCESS;

size_t _len_str = str ? strlen(str) + 1 : 0;

 

ms_ocall_print_string_t* ms = NULL;

size_t ocalloc_size = sizeof(ms_ocall_print_string_t);

void *__tmp = NULL;

 

CHECK_ENCLAVE_POINTER(str, _len_str);

 

if (ADD_ASSIGN_OVERFLOW(ocalloc_size, (str != NULL) ? _len_str : 0))

return SGX_ERROR_INVALID_PARAMETER;

 

__tmp = sgx_ocalloc(ocalloc_size);

if (__tmp == NULL) {

sgx_ocfree();

return SGX_ERROR_UNEXPECTED;

}

ms = (ms_ocall_print_string_t*)__tmp;

__tmp = (void *)((size_t)__tmp + sizeof(ms_ocall_print_string_t));

ocalloc_size -= sizeof(ms_ocall_print_string_t);

 

if (str != NULL) {

ms->ms_str = (const char*)__tmp;

if (_len_str % sizeof(*str) != 0) {

sgx_ocfree();

return SGX_ERROR_INVALID_PARAMETER;

}

if (memcpy_s(__tmp, ocalloc_size, str, _len_str)) {

sgx_ocfree();

return SGX_ERROR_UNEXPECTED;

}

__tmp = (void *)((size_t)__tmp + _len_str);

ocalloc_size -= _len_str;

} else {

ms->ms_str = NULL;

}

 

status = sgx_ocall(0, ms);

 

if (status == SGX_SUCCESS) {

}

sgx_ocfree();

return status;

}

思考一下:untrusted部分的代码是为了enclave向外部进行ocall的函数,所以它应该是在Enclave内部执行,因此它应该出现在Enclave_t部分,从而才能允许Enclave进行调用。它与不可信部分进行关联是通过sgx_ocall(0,ms)实现的,因为它是untrusted部分的第一个函数,所以它的索引为0。ms的定义为ms_ocall_print_string_t* ms其中ms...结构的定义为:

typedef struct ms_ocall_print_string_t {

const char* ms_str;

} ms_ocall_print_string_t;

结构中只有一个const char* ms_str,不再像trusted部分的函数参数生成的结构中还会有个长度。

4同时还会在Enclave_u.h中进行声明:

void SGX_UBRIDGE(SGX_NOCONVENTION, ocall_print_string, (const char* str));

5在Enclave_u.c中的实现为:

static sgx_status_t SGX_CDECL Enclave_ocall_print_string(void* pms)

{

ms_ocall_print_string_t* ms = SGX_CAST(ms_ocall_print_string_t*, pms);

ocall_print_string(ms->ms_str);

 

return SGX_SUCCESS;

}

(二)untrusted中出现带返回值的函数如:

uint32_t ocall_write_region_data([in, size=bloblen]  uint8_t *blob, uint32_t bloblen);

该函数返回值为uint32_t,也需要有参数。

1在App.cpp中实现;

2经过sgx_edger8r工具的处理会在Enclave_t.h中声明为:

sgx_status_t SGX_CDECL ocall_write_region_data(uint32_t* retval, uint8_t* blob, uint32_t bloblen);

注意:其返回值为sgx_status_t,成功则为SGX_SUCCESS,否则为其它值。参数变为

uint32_t* retval, uint8_t* blob, uint32_t bloblen

比原始函数的参数多了个uint32_t* retval,这个参数用作返回值。

3在Enclave_t.c中的实现为:

sgx_status_t SGX_CDECL ocall_write_region_data(uint32_t* retval, uint8_t* blob, uint32_t bloblen)

{

sgx_status_t status = SGX_SUCCESS;

size_t _len_blob = bloblen;

 

ms_ocall_write_region_data_t* ms = NULL;

size_t ocalloc_size = sizeof(ms_ocall_write_region_data_t);

void *__tmp = NULL;

 

CHECK_ENCLAVE_POINTER(blob, _len_blob);

 

if (ADD_ASSIGN_OVERFLOW(ocalloc_size, (blob != NULL) ? _len_blob : 0))

return SGX_ERROR_INVALID_PARAMETER;

 

__tmp = sgx_ocalloc(ocalloc_size);

if (__tmp == NULL) {

sgx_ocfree();

return SGX_ERROR_UNEXPECTED;

}

ms = (ms_ocall_write_region_data_t*)__tmp;

__tmp = (void *)((size_t)__tmp + sizeof(ms_ocall_write_region_data_t));

ocalloc_size -= sizeof(ms_ocall_write_region_data_t);

 

if (blob != NULL) {

ms->ms_blob = (uint8_t*)__tmp;

if (_len_blob % sizeof(*blob) != 0) {

sgx_ocfree();

return SGX_ERROR_INVALID_PARAMETER;

}

if (memcpy_s(__tmp, ocalloc_size, blob, _len_blob)) {

sgx_ocfree();

return SGX_ERROR_UNEXPECTED;

}

__tmp = (void *)((size_t)__tmp + _len_blob);

ocalloc_size -= _len_blob;

} else {

ms->ms_blob = NULL;

}

 

ms->ms_bloblen = bloblen;

status = sgx_ocall(4, ms);

 

if (status == SGX_SUCCESS) {

if (retval) *retval = ms->ms_retval;

}

sgx_ocfree();

return status;

}

它与不可信部分的关联是通过sgx_ocall(4,ms)实现的,4是这个函数的索引,它在untrusted中是第5个。

ms_ocall_write_region_data_t的定义为:

typedef struct ms_ocall_write_region_data_t {

uint32_t ms_retval;

uint8_t* ms_blob;

uint32_t ms_bloblen;

} ms_ocall_write_region_data_t;

4同时还会在Enclave_u.h中进行声明:

uint32_t SGX_UBRIDGE(SGX_NOCONVENTION, ocall_write_region_data, (uint8_t* blob, uint32_t bloblen));

5在Enclave_u.c中的实现为:

static sgx_status_t SGX_CDECL Enclave_ocall_write_region_data(void* pms)

{

ms_ocall_write_region_data_t* ms = SGX_CAST(ms_ocall_write_region_data_t*, pms);

ms->ms_retval = ocall_write_region_data(ms->ms_blob, ms->ms_bloblen);

 

return SGX_SUCCESS;

}

 

(三)untrusted中出现带allow的函数如:

// This OCALL can make an ECALL to function “verify_block_messages”.

uint32_t ocall_read_sealed_data( [in, string]  char * str) allow(verify_block_messages);

 

 

 类似资料: