目录
Library Functions and Type Reference
受保护的FS Security Non-Objectives
Enclave Development Basics
(Enclave内)调用Enclave之外的函数
在某些情况下,Enclave内的代码需要调用驻留在不可信(不受保护)内存中的外部函数,以使用Enclave外部的操作系统功能,例如系统调用,I/O操作等。 这种函数被命名为OCALL。
这些函数需要在不可信部分的EDL文件中声明。有关详细信息,请参阅“Enclave Definition Language Syntax”。
Enclave镜像的加载与Linux OS加载共享目标文件的方式非常相似。 应用程序端的函数的地址空间与Enclave共享,因此Enclave代码可以间接调用被链接到(创建Enclave的)应用程序的函数。(Enclave内)不允许直接调用应用程序端的函数,否则在运行时会引发异常。
警告:
- 包装(Wrapper)函数将参数从受保护(Enclave)内存复制到不受保护的内存,因为外部功能无法访问受保护的内存区域。其中最重要的是,OCALL参数被复制到不受信任的堆栈中。考虑参数的数量,OCALL可能会导致不受信任域中的堆栈溢出。 此事件所触发的异常似乎来自于sgx_eder8r基于Enclave EDL文件生成的代码。 但是,可以使用调试程序轻松检测到异常。
警告:
- 仅当在EDL文件中为这些指针指定了特殊属性时,包装函数才可能将缓冲区(由指针指向的内存)进行复制。
警告:
- Intel® Software Guard Extensions SDK发行的某些可信库提供了API,其内部会调用OCALL。当前,libsgx_tstdc.a中的Intel® SGX互斥锁、读/写锁、条件变量和CPUID API(内部)调用了了OCALL。 同样,可信的支持库libsgx_tservice.a也调用了OCALL,该库提供来自Platform ServiceEnclave(PSE-Op)的服务。 使用这些API的开发人员必须先在他的EDL文件中导入所需的OCALL函数,否则,开发人员在构建Enclave时会收到链接器错误。 有关如何从可信库EDL文件中导入OCALL函数的详细信息,请参见“导入EDL库”。
警告:
- 为了有助于定位由于缺少导入产生的问题,Intel® Software Guard Extensions SDK中使用的所有OCALL函数均带有后缀ocall。例如,下面的链接错误说明该Enclave域需要导入insethread_mutex.obj中所需的OCALL sgx_thread_wait_untrusted_event_ocall()和sgx_thread_set_untrusted_event_ocall()函数,这是libsgx_tstdc.a的一部分。
-
libsgx_tstdc.a(sethread_mutex.o): In function `sgx_thread_mutex_lock':sethread_mutex.cpp:109: undefined reference to `sgx_thread_wait_untrusted_event_ocall' libsgx_tstdc.a(sethread_mutex.o): In function `sgx_thread_mutex_unlock':sethread_mutex.cpp:213: undefined reference to `sgx_thread_set_untrusted_event_ocall'
警告:
- 从不受保护的内存访问受保护的内存将导致中止页面语义。 这适用于受保护内存的所有部分,包括堆、栈、代码和数据。
- 中止页面语义:
- 尝试从不存在或不允许的资源中读取将返回全“1”数据(中止页面)。 尝试写入不存在或不允许的物理资源的操作被直接抛弃哦。 此行为与异常类型中止无关(其他类型指“Fault和Trap”)。
OCALL函数有如下限制/规则:
- 所有函数必须是C函数或具有C链接形式的C++函数。
- 在Enclave中指向数据的指针必须在EDL文件中用指针方向属性进行注释。 包装函数将对这些指针进行浅拷贝。有关更多信息,请参见“指针”。
- Enclave内不会捕获异常。因此用户必须在不可信的包装函数中处理这些异常。
- OCALL的原型中不能包含省略号(…)或va_list。
例子1:一个简单的OCALL函数的定义
第一步——在EDL文件中添加foo函数的声明
// foo.edl
enclave {
untrusted {
[cdecl] void foo(int param);
};
};
第二步(可选但是强烈推荐)——写一个可信的、用户友好的包装函数。这个函数是Enclave可信代码的一部分。
包装函数ocall_foo应该长这样:
// enclave's trusted code
#include "foo_t.h"
void ocall_foo(int param)
{
// it is necessary to check the return value of foo()
if (foo(param) != SGX_SUCCESS)
abort();
}
第三步——写一个不可信的foo函数
// untrusted code
void foo(int param)
{
// the implementation of foo
}
sgx_edger8r将生成一个不可信的桥函数,该函数将自动调用不可信的函数foo。 这个不可信的桥和目标不可信函数是应用程序的一部分,而不是Enclave的。
Library Functions and Type Reference
可信库
C标准库
线程同步元语
如果应用程序定义了多个线程上下文,并且不可信加载程序创建了这些线程上下文,那么就有可能出现多个不可信线程同时进入一个Enclave的情况。 一旦多个线程在某个Enclave内并发执行,并且它们试图操作任何一个全局数据结构,那么需要给它们提供某种形式的同步机制。 在某些情况下,线程可能会使用处理器ISA提供的原子操作。 但是,在通常情况下,它们将使用与Enclave外部类似的同步对象和机制。
Intel® Software Guard Extensions SDK可以利用“类型和枚举”章节中定义的以下API和数据类型,以支持互斥和条件变量同步机制。 受信任的线程同步库中包含的某些功能可能会调用Enclave外的函数(OCALL)。 如果要使用以下任何API,则必须先从sgx_tstdc.edl导入所需的OCALL函数。 否则,在构建安全区时会出现链接错误。 有关其他详细信息,请参见在“调用Enclave外部”函数。 下表说明了Intel® SGX线程同步库支持的原语,以及每个API函数所需的OCALL。
Function API | OCall Function | |
Mutex Synchronization | sgx_thread_mutex_init | |
sgx_thread_mutex_destroy | ||
sgx_thread_mutex_lock | sgx_thread_wait_untrusted_event_ocall | |
sgx_thread_mutex_trylock | ||
sgx_thread_mutex_unlock | sgx_thread_set_untrusted_event_ocall | |
Reader/Writer Lock Synchronizations | gx_thread_rwlock_init | |
sgx_thread_rwlock_destroy | ||
sgx_thread_rwlock_rdlock | sgx_thread_wait_untrusted_event_ocall | |
sgx_thread_rwlock_wrlock | sgx_thread_wait_untrusted_event_ocall | |
sgx_thread_rwlock_tryrdlock | ||
sgx_thread_rwlock_trywrlock | ||
sgx_thread_rwlock_unlock | sgx_thread_set_untrusted_event_ocall sgx_thread_set_multiple_untrusted_events_ocall | |
Condition Variable Synchronization | sgx_thread_cond_init | |
sgx_thread_cond_destroy | ||
sgx_thread_cond_wait | sgx_thread_wait_untrusted_event_ocall sgx_thread_wait_untrusted_event_ocall | |
sgx_thread_cond_signal | sgx_thread_set_untrusted_event_ocall | |
sgx_thread_cond_broadcast | sgx_thread_set_multiple_untrusted_events_ocall | |
Thread Management | sgx_thread_self | |
sgx_thread_equal |
注意:
- 需要同步线程时,请使用“POSIX aligned pthread”函数
Reserved Memory Functions
C++语言支持
Intel® Software Guard Extensions SDK在Enclave内部提供了一个可信库用于支持C++。C++开发人员将利用(依赖于C++运行时库)的高级C++功能。
ISO/IEC 14882:C++标准被选为Intel'® Software Guard Extensions SDK可信库的基准。Enclave内部目前支持大多数标准C++特性,其中包括:
- 使用new/delete的动态内存管理
- 支持全局初始化器(通常用于全局对象的构造)
- 运行时类型标识(RTTI)
- Enclave中的C++异常处理
由于销毁Enclave时会回收EPC内存的原因,目前不支持全局析构函数。
注意:
- Enclave接口定义中不支持C++对象。 如果应用程序需要跨越Enclave边界传递C++对象,建议您将C++对象的数据存储到C结构中,然后在Enclave接口中编排(Marshal)这些数据。 然后,您需要使用前面传入到构造函数中的已经编排好的C结构体,去将Enclave内部的C++对象实例化(否则,您也可以使用适当的运算符,去更新现有的实例化对象)。
C++标准库
Intel® Software Guard Extensions SDK包括符合C++11标准的C++标准库(包括STL)的可信版本。不过,根据开发Enclave时所具体使用的Makefile,我们可以链接到该库的其他版本。 较新的Makefile版本默认情况下使用sgx_tcxx.a,它是从libc++移植过来的,并且支持大多数C++11功能。 另一方面,以前的Makefile版本使用sgx_tstdcxx.a,该库是从STLport移植过来的,但是只提供了有限的C++11支持。 如果您更新了一个Enclave项目并且希望接触到所有受支持的C++11功能,那么需要手动添加新的C++可信库。 如果sgx_tstdcxx.a存在,请将其替换为sgx_tcxx.a,不然的话,只需将sgx_tcxx.a添加到Makefile中的链接器的依赖项列表中去。
关于C++标准库,其中大多数函数能够像其不可信部分那样正常工作。如下是Enclave内部所不支持的特性的简要概述:
- 与I/O相关的函数和类,例如<iostream>;
- 取决于语言环境库的函数;
- 需要系统调用的任何其他函数。
不过,只有C函数可以用作可信和不可信接口处的语言。尽管可以使用C++语言开发Enclave,但不应在Enclave边界上传递C++对象。
密码学库
Intel® Software Guard Extensions软件开发工具(Intel® SGX SDK)包含一个名为sgx_tcrypto的受信任的密码学库。 它包含SDK中其他受信任库使用的密码学函数,例如sgx_tservice库。 因此,该库的功能性受到限制。
- sgx_sha256_msg
- sgx_sha256_init
- sgx_sha256_update
- sgx_sha256_get_hash
- sgx_sha256_close
- sgx_rijndael128GCM_encrypt
- sgx_rijndael128GCM_decrypt
- sgx_aes_gcm128_enc_init
- sgx_aes_gcm128_enc_update
- sgx_aes_gcm128_enc_get_mac
- sgx_aes_gcm_close
- sgx_rijndael128_cmac_msg
- sgx_cmac128_init
- sgx_cmac128_update
- sgx_cmac128_final
- sgx_cmac128_close
- sgx_aes_ctr_encrypt
- sgx_aes_ctr_decrypt
- sgx_ecc256_open_context
- sgx_ecc256_close_context
- sgx_ecc256_create_key_pair
- sgx_ecc256_compute_shared_dhkey
- sgx_ecc256_check_point
- sgx_ecdsa_sign
- sgx_ecdsa_verify
- sgx_ecdsa_verify_hash
- sgx_rsa3072_sign
- sgx_rsa3072_verify
- sgx_create_rsa_key_pair
- sgx_create_rsa_priv2_key
- sgx_create_rsa_pub1_key
- sgx_free_rsa_key
- sgx_rsa_priv_decrypt_sha256
- sgx_rsa_pub_encrypt_sha256
- sgx_calculate_ecdsa_priv_key
- sgx_ecc256_calculate_pub_from_priv
- sgx_hmac_sha256_msg
- sgx_hmac256_init
- sgx_hmac256_update
- sgx_hmac256_final
- sgx_hmac256_close
受信任的密码库基于基础通用密码库:Intel®集成性能基元(Intel® IPP)密码库【2018 Update 2.1】或Intel® Software Guard Extensions SSL密码库(Intel® SGX SSL)。
默认版本使用预编译的优化库,其中包括Intel® IPP库。此外,Intel® IPP加密头文件位于[Intel SGX SDK安装路径] include/ipp中。如果要使用Intel® SGX SSL代替Intel® IPP,则应使用未优化的代码实现。请遵循README.md以获得详细说明。
如果需要其他加密功能,则可以使用通用加密库及其对应的头文件。基础的受信任库会被链接到libsgx_tcrypto.a。
在按照Intel® SGX SSL开发人员指南第2.2节中所述的要求更新Enclave EDL和应用程序项目后,可以直接访问Intel® SGX SSL API。使用Intel® SGX SSL库。
Intel® 受保护的文件系统库
Intel® 受保护文件系统库为Intel® SGX Enclave提供了受保护的文件API。 它支持常规C文件API(C语言文件操作相关的API)的基本子集,使您可以创建文件并使用它们,就像通常您在常规应用程序中做的那样。
使用此API,可以在写操作期间对文件进行加密并将其保存在不受信任的磁盘上,并且可以在读操作期间对文件的机密性和完整性进行验证。
要加密文件,你应该提供文件加密密钥。该密钥是一个128位密钥,用作“密钥派生密钥”(key derivation key),以生成多个加密密钥。根据“ NIST Special Publication 800-108-使用伪随机函数进行密钥派生的建议”:“输入到密钥派生函数的密钥称为密钥派生密钥。为了遵循该建议,密钥派生密钥应为密码学密钥(见第3.1节)。可以通过受审批的密码学随机位生成器(例如,[5]中指定类型的确定性随机位生成器)生成“密钥派生密钥”,用作该建议中指定的“密钥派生函数”的输入之一。又或者,通过受审批的自动密钥建立过程,生成“密钥派生密钥”(例如,如[1]和[2]中所定义的)”。有关更多详细信息,请参阅NIST SP 800-108文档。
(要加密文件,)另一个选择是使用从Enclave密封密钥派生的自动密钥(此方法的缺点请参阅“Using the Protected FS Automatic Keys API”章节)
- sgx_fopen
- sgx_fopen_auto_key
- sgx_fclose
- sgx_fread
- sgx_fwrite
- sgx_fflush
- sgx_ftell
- sgx_fseek
- sgx_feof
- sgx_ferror
- sgx_clearerr
- sgx_remove
- sgx_fexport_auto_key
- sgx_fimport_auto_key
- sgx_fclear_cache
受保护的文件系统(FS)的使用限制
由于受保护文件中嵌入了元数据,因此一次只能打开一个文件句柄进行写入,或者可以打开许多文件句柄进行读取。操作系统保护机制被用于防止意外打开多个“写”文件句柄。 如果绕过此保护,则文件将会损坏。 同一Enclave内的许多线程可以使用同一个已经被打开的文件句柄,API包含用于处理此事件(线程对文件句柄的使用)的内部锁,并且这些操作将(一次只能)由一个(线程)执行。
受保护的文件系统(FS)的错误代码
受保护的文件系统(FS)API尝试保留原始的C文件API错误。 根据原始C文件API文档,并且为需要FS错误码的C文件API设置了本地errno(这个错误码处于Enclave内部)。
当受保护的文件系统(FS)API访问OS文件系统时,如果返回错误,该错误将返回给调用者。 此外,如有可能,针对内部错误,它会返回EXXX错误代码(例如,尝试写入一个以只读方式打开的文件时,会返回EACCES错误代码,或者在Enclave内部分配内存失败时,会返回ENOMEM。 )。 对于当前文件名与内部文件名不匹配的情况,添加了一些特殊的错误代码,例如SGX_ERROR_FILE_NAME_MISMATCH。 您可以在sgx_error.h中找到这些错误代码及其说明。
受保护的FS应用程序布局
下图演示了受保护的文件系统(FS)在Intel® SGX应用程序中如何工作:
为了能够使用Intel SGX受保护的文件系统库:
- Enclave必须与libsgx_tprotected_fs.a进行链接
- Application必须与libsgx_uprotected_fs.a进行链接
- Enclave的EDL文件必须要从sgx_tprotected_fs.edl中“import”所有函数
- 源文件需要“include” sgx_tprotected_fs.h
受保护的FS的S3/S4重要说明
(译注:S3/S4指的是CPU Sleeping State/Power State/C-state)
为了提高受保护的文件系统的性能,会使用缓存将用户的数据保存在安全区域内,并且只有在缓存已满时才将其刷新到磁盘。
在S3/S4过渡的情况下,缓存中的数据将丢失(整个Enclave的都将丢失)。 因此,在进入S3/S4之前,必须Flush或关闭所有文件句柄。 如果不采取任何措施,文件完整性不会受到损害,但是最新的未Flush的“写”数据将丢失。
使用受保护的FS自动(Automatic)密钥API
自动密钥是从Enclave密封密钥(With MRSIGNER)派生而来的,因此文件相当于绑定到了该特定机器上的由同一签名人签名的所有Enclave。 要将文件从一台计算机传输到另一台计算机,应遵循如下的密钥导出和导入过程。 在某些情况下,建议不要使用自动密钥。
- 灾难恢复——在其他的计算机上无法成功地打开之前在另一台计算机上创建的文件(除非遵循后续提到的步骤)。 因此,自动化的“灾难恢复”可能无法正常施展。
- VM迁移——目前,Intel® SGX不支持在VM迁移中自动传输Enclave密钥。 因此,在使用了VM迁移的服务器上运行的Enclave不能使用自动密钥API。
使用自动密钥API情况下的文件传输
对于使用sgx_fopen_auto_key创建的文件,要将其从一个Enclave转移到另一个Enclave,或转移到另一台计算机上的Enclave,请按照以下步骤操作:
- 关闭文件对应的所有的已经打开的句柄。
- 调用sgx_fexport_auto_key API。 该API返回用于加密文件的元数据节点的最新加密密钥。
- 将文件传输到目标Enclave,并以安全的方式将密钥交给目标Enclave。
- 调用sgx_fimport_auto_key API。 该API将使用从本地Enclave密封密钥派生出的新加密密钥对元数据节点进行重新加密。
- 像往常一样使用sgx_fopen_auto_key打开文件。
受保护的FS Security Non-Objectives
为了缓解文件交换攻击(两个均为有效文件。译注:针对密封文件的新旧版本可以展开回滚攻击,相关文章如《ROTE: Rollback Protection for Trusted Execution》,与交换攻击存在一些类似性),在文件打开操作期间会检查其文件名(验证当前文件的名称是否与创建文件时的文件名相匹配)。 但是,如果使用相同的文件名创建的两个文件,则(上述做法)无法防止交换攻击。
由于文件保存在常规FS中,因此无法防止恶意删除或修改文件——仅当尝试读取或写入文件中被篡改的部分时,才会检测到这种情况(因为会检测到文件解密失败的现象)
使用受保护的FS API时,有几处不受保护的内容,任何可以访问操作系统的人都可以看到:
- 文件名
- 文件大小(最大4KB粒度)
- 文件修改日期
- 密钥类型(用户自定义的或自动生成的)
- 使用模式
- 读/写偏移
如果上述任何一项可能暴露敏感信息,并给潜在的攻击者提供帮助,则Enclave开发人员应自行添加防御机制,以防止这种情况的发生。 例如,“安全浏览器”的实现中,不应将“ cookies”和与之相关网站的名称一起保存,因为攻击者可以从用户的浏览历史记录中了解到这些。
pthreads
Intel® 软件保护扩展(Intel® SGX)SDK包含pthreads库的可信版本。该库名为sgx_pthread,只能在Enclave内使用。
使用可信的pthreads库,单个Enclave进程可以包含执行同一程序的多个线程。
这些线程在Enclave内部共享相同的全局内存(数据和堆的段),但是每个线程又都有自己的栈和TCS。您需要在Enclave配置文件中配置足够的<TCSNum>;否则pthread_create()会失败。
下面的列表包含Intel® SGX pthread库所支持的API。这些API接口与POSIX标准一致。
-
pthread_create(pthread_t *threadp, const pthread_attr_t *attr, void*(*start_routine)(void*),void*arg)
描述:在调用者进程中创建一个新线程。注意:Enclave内部暂不支持attr,因此将使用PTHREAD_CREATE_JOINABLE创建新线程。
-
pthread_exit(void *retval)
终止调用者线程。
-
pthread_join(pthread_t thread, void **retval)
描述:Join一个被终止的线程。注意:当这个函数在支持Intel® SGX 2.0平台的Enclave的析构函数中调用时,此函数直接返回。 销毁Enclave时,URTS会同步并回收正在运行的线程。
-
pthread_self(void)
描述:获取调用者线程的ID
-
pthread_mutex_init(pthread_mutex_t *mutexp, const pthread_mutexattr_t *attr)
描述:初始化mutex参数指向的互斥锁。注意:Enclave内暂不支持attr这个参数。
-
pthread_mutex_destroy(pthread_mutex_t *mutexp)
描述:销毁互斥锁
-
pthread_mutex_lock(pthread_mutex_t *mutexp)
描述:锁上互斥锁。
-
pthread_mutex_trylock(pthread_mutex_t *mutexp)
描述:锁上互斥锁。如果这个互斥锁当前被其他线程锁上,这个函数立即返回。
-
pthread_mutex_unlock(pthread_mutex_t *mutexp)
描述:解锁这个互斥锁。
-
pthread_rwlock_init(pthread_rwlock_t *rwlockp, constpthread_rwlockattr_t *attr)
描述:初始化rwlockp指向的读写锁。注意:Enclave内暂不支持attr这个参数。
-
pthread_rwlock_destroy(pthread_rwlock_t *rwlockp)
描述:销毁读写锁对象。
-
pthread_rwlock_rdlock(pthread_rwlock_t *rwlockp)
描述:获取一个读者锁。
-
pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlockp)
描述:试图获取一个读者锁。如果相关的写者锁当前被其他线程占用,这个函数立即返回。
-
pthread_rwlock_wrlock(pthread_rwlock_t *rwlockp)
描述:获取一个写者锁。
-
pthread_rwlock_trywrlock(pthread_rwlock_t *rwlockp)
描述:试图获取一个读者锁。如果相关的读者锁或写者锁当前被其他线程占用,这个函数立即返回。
-
pthread_rwlock_unlock(pthread_rwlock_t *rwlockp)
描述:释放当前线程占用的读者或写者锁。
-
pthread_cond_init(pthread_cond_t *condp, const pthread_condattr_t *attr)
描述:初始化一个条件变量。注意:Enclave内暂不支持attr这个参数。
-
pthread_cond_destory(pthread_cond_t *condp)
描述:销毁一个条件变量。
-
pthread_cond_wait(pthread_cond_t *condp, pthread_mutex_t *mutexp)
描述:等待条件。
-
pthread_cond_signal(pthread_cond_t *condp)
描述:向一个条件发信号。
-
pthread_cond_broadcast(pthread_cond_t *condp)
描述:向一个条件发广播。
-
pthread_key_create(pthread_key_t *key, void (*destructor)(void*))
描述:创建一个特定于线程的数据密钥。
-
pthread_key_delete(pthread_key_t key)
描述:删除一个特定于线程的数据密钥。
-
pthread_get_specific(pthread_key_t key)
描述:管理特定于线程的数据。
-
pthread_set_specific(pthread_key_t key, const void *data)
描述:管理特定于线程的数据。
-
pthread_equal(pthread_t t1, pthead_t t2)
描述:比较线程ID。
-
pthread_once(pthread_once_t *once_control, void (*init_routine)(void*))
描述:动态的Package初始化。
-
要在Intel®SGX中启用可信pthread,请在Makefile中的enclave链接选项中添加“ -lsgx_pthread”
函数描述
sgx_create_enclave
使用Enclave名称来加载它。
语法
sgx_status_t sgx_create_enclave(
const char *file_name,
const int debug,
sgx_launch_token_t *launch_token,
int *launch_token_updated,
sgx_enclave_id_t *enclave_id,
sgx_misc_attribute_t *misc_attr
);
参数
file_name [in]
Enclave镜像的名称或完整路径。
debug [in]
有效值为0或1。
0表示在非调试模式下创建Enclave。无法对非调试模式下创建的Enclave进行调试。
1表示在调试模式下创建Enclave。 在调试模式下创建的Enclave内部的代码/数据内存可由该Enclave外部的调试器或其他软件访问,因此与非调试模式下创建的Enclave具有不同的内存访问保护。
Enclave应该在只为了调试目的时以调试模式下创建。提供了一个辅助宏SGX_DEBUG_FLAG以在调试模式下创建一个Enclave。 在发行版本中,SGX_DEBUG_FLAG的值为0。在调试版本和预发行版本中,SGX_DEBUG_FLAG的值默认为1。
launch_token [deprecated]
指向sgx_launch_token_t对象的指针,该对象用于初始化要创建的Enclave(不建议使用)
launch_token_updated [deprecated]
不推荐使用此参数。
enclave_id [out]
指向接收Enclave ID或句柄的sgx_enclave_id_t的指针。 不能为NULL。
misc_attr [out, optional]
指向sgx_misc_attribute_t结构的指针,该结构接收Enclave的杂项选择和属性。 如果不需要信息,则此指针可以为NULL。
返回值
sgx_open
sgx_fopen函数创建并打开一个受保护的文件。
语法
SGX_FILE* sgx_fopen(
const char* filename,
const char* mode,
const sgx_key_128bit_t *key
);
参数
filename [in]
需要被创建或打开的文件名。
mode [in]
文件打开模式字符串。所允许的值为“r”、“w”或“a”,与“+”和“b”的任意组合(目前字符串函数暂不支持,“b”目前没有意义)。
key [in]
文件的加密密钥。这个密钥被用作“密钥导出密钥”,用来导出针对此文件的加密密钥。如果这个文件是用sgx_fopen创建的,那么您应该保护好这个密钥,并且在每次打开这个文件时输入此密钥。
返回值
如果该函数成功执行,它将返回一个有效的文件指针,该文件指针可以被“受保护的FS“API中的其他所有函数使用,否则,返回NULL并使用适当的错误代码设置errno。 有关错误的更多详细信息,请参见受保护的FS错误代码。
描述
sgx_fopen与C(语言的)文件API fopen类似。 它会创建一个新的“受保护的文件”,或打开一个先前sgx_fopen创建的“受保护的文件”。 无法使用此API打开常规文件。
有关此API及其参数的更多详细信息,请参见fopen文档。
要求
Header | sgx_tprotected_fs.h sgx_tprotected_fs.edl |
Library | libsgx_tprotected_fs.a |
sgx_fopen_auto_key
sgx_fopen_auto_key创建或打开一个受保护文件。
语法
SGX_FILE* sgx_fopen_auto_key(
const char* filename,
const char* mode
);
参数
filename [in]
需要被创建或打开的文件名。
mode [in]
文件打开模式字符串。所允许的值为“r”、“w”或“a”,与“+”和“b”的任意组合(目前字符串函数暂不支持,“b”目前没有意义)。
返回值
如果该函数成功执行,它将返回一个有效的文件指针,该文件指针可以被“受保护的FS“API中的其他所有函数使用,否则,返回NULL并使用适当的错误代码设置errno。 有关错误的更多详细信息,请参见受保护的FS错误代码。
描述
sgx_fopen_auto_key与C(语言的)文件API fopen类似。 它会创建一个新的受保护文件,或打开一个先前sgx_fopen_auto_key创建的受保护文件。 无法使用此API打开常规文件。
有关此API及其参数的更多详细信息,请参见fopen文档。
要求
Header | sgx_tprotected_fs.h sgx_tprotected_fs.edl |
Library | libsgx_tprotected_fs.a |
sgx_fclose
sgx_fclose关闭受保护文件的一个句柄。
语法
int32_t sgx_fclose(
SGX_FILE* stream
);
参数
stream [in]
先前sgx_fopen或sgx_fopen_auto_key返回的文件句柄。
返回值
0
文件被成功关闭
1
此操作出现了一些错误
描述
sgx_fclose与C文件API fclose相似。 它会关闭先前sgx_fopen或sgx_fopen_auto_key创建的受保护文件的句柄。调用此函数后,即使返回了错误,该句柄也变得无效了。
有关此API及其参数的更多详细信息,请参照fclose文档。
要求
Header | sgx_tprotected_fs.h sgx_tprotected_fs.edl |
Library | libsgx_tprotected_fs.a |
sgx_fread
sgx_fread函数从文件中读取所要求的数据量,并用该数据量增加文件指针(的偏移量)。
语法
size_t sgx_fread(
void* ptr,
size_t size,
size_t count,
SGX_FILE* stream
);
参数
ptr[out]
指针指向至少size*count字节大小的缓冲区,以接收从文件读取的数据。
size [in]
每个要读取的块的大小。
count [in]
所要读取的块数。
stream [in]
先前sgx_fopen或sgx_fopen_auto_key返回的文件句柄。
返回值
从文件中读取的块数,块的大小为size。
描述
sgx_fread与C文件API的fread类似。 如果发生错误,可以调用sgx_ferror来获取错误代码。
有关此API及其参数的更多详细信息,请查看fread文档。
要求
Header | sgx_tprotected_fs.h sgx_tprotected_fs.edl |
Library | libsgx_tprotected_fs.a |
sgx_fwrite
sgx_fwrite函数向文件中写入所指定的数据量,并用该数据量增加文件指针(的偏移量)。
语法
size_t sgx_fwrite(
const void* ptr,
size_t size,
size_t count,
SGX_FILE* stream
);
参数
ptr[out]
指针指向至少size*count字节大小的缓冲区,缓冲区包含了需要写入文件的数据。
size [in]
每个要写入的块的大小。
count [in]
所要写入的块数。
stream [in]
先前sgx_fopen或sgx_fopen_auto_key返回的文件句柄。
返回值
写入文件的块数,块的大小为size。
描述
sgx_fwrite与C文件API的fwrite类似。 如果发生错误,可以调用sgx_ferror来获取错误代码。
有关此API及其参数的更多详细信息,请查看fwrite文档。
要求
Header | sgx_tprotected_fs.h sgx_tprotected_fs.edl |
Library | libsgx_tprotected_fs.a |
sgx_fflush
sgx_fflush函数强制执行缓存刷新,如果成功返回,则可以确保您所做的更改已提交到磁盘上的文件中。
语法
int32_t sgx_fflush(
SGX_FILE* stream
);
参数
stream [in]
先前sgx_fopen或sgx_fopen_auto_key返回的文件句柄。
返回值
0
此操作成功完成。
1
此操作过程中出现错误。可以调用sgx_ferror获得错误代码。
描述
sgx_fflush与C文件API fflush类似。 此函数从缓存中清除所有修改后的数据,并将其写入磁盘上的文件中。如果发生错误,可以调用sgx_ferror来获取错误代码。 请注意,此功能不会清除缓存,而只会将更改刷新到磁盘上的实际文件。当缓存已满并且需要页面驱逐时,刷新也会自动发生。
有关此API及其参数的更多详细信息,请查看fflush文档。
要求
Header | sgx_tprotected_fs.h sgx_tprotected_fs.edl |
Library | libsgx_tprotected_fs.a |
sgx_ftell
sgx_ftell创建或打开一个受保护文件。
(译注:个人认为官方文档这里写错了。man7:ftell()函数获取stream指向的流的文件位置指示符的当前值)
语法
int64_t sgx_ftell(
SGX_FILE* stream
);
参数
stream [in]
先前sgx_fopen或sgx_fopen_auto_key返回的文件句柄。
返回值
如果函数成功,则返回文件位置指示器的当前值,否则,返回-1并且用适当的错误代码设置errno。 有关错误的更多详细信息,请参见受保护的FS错误代码。
描述
sgx_ftell与C文件API ftell类似。
有关此API及其参数的更多详细信息,请查看ftell文档。
要求
Header | sgx_tprotected_fs.h sgx_tprotected_fs.edl |
Library | libsgx_tprotected_fs.a |
sgx_fseek
sgx_fseek函数设置文件位置指示器的当前值。
语法
int64_t sgx_fseek(
SGX_FILE* stream,
int64_t offset,
int origin
);
参数
stream [in]
先前sgx_fopen或sgx_fopen_auto_key返回的文件句柄。
offset [in]
相对于origin参数的新偏移值。
origin [in]
从origin开始计算偏移量(SEEK_SET,SEEK_CUR或SEEK_END)
返回值
0
此操作成功完成。
1
此操作过程中出现错误。可以调用sgx_ferror获得错误代码。
描述
sgx_fseek与C文件API fseek相似。
有关此API及其参数的更多详细信息,请参阅fseek文档。
要求
Header | sgx_tprotected_fs.h sgx_tprotected_fs.edl |
Library | libsgx_tprotected_fs.a |
sgx_feof
sgx_feof函数告诉调用者,先前的读取操作中文件位置指示器是否命中了文件的末尾。
语法
int32_t sgx_feof(
SGX_FILE* stream
);
参数
stream [in]
先前sgx_fopen或sgx_fopen_auto_key返回的文件句柄。
返回值
0
没有到达文件末尾。
1
到达文件末尾。
描述
sgx_feof与C文件API feof相似。
有关此API及其参数的更多详细信息,请参阅feof文档。
要求
Header | sgx_tprotected_fs.h sgx_tprotected_fs.edl |
Library | libsgx_tprotected_fs.a |
sgx_ferror
sgx_ferror函数返回最新的操作错误码。
语法
int32_t sgx_ferror(
SGX_FILE* stream
);
参数
stream [in]
先前sgx_fopen或sgx_fopen_auto_key返回的文件句柄。
返回值
返回最新的操作错误码。0意味着没有错误。
描述
sgx_ferror与C文件API ferror类似。 如果由于文件处于错误状态而导致最新操作失败,则将返SGX_ERROR_FILE_BAD_STATUS。
有关此API及其参数的更多详细信息,请参阅ferror文档。
要求
Header | sgx_tprotected_fs.h sgx_tprotected_fs.edl |
Library | libsgx_tprotected_fs.a |
sgx_fclearerr
sgx_fclearerr函数试图修复一个坏的文件状态,并且清理end-of-file标志。
语法
void sgx_clearerr(
SGX_FILE* stream
);
参数
stream [in]
先前sgx_fopen或sgx_fopen_auto_key返回的文件句柄。
返回值
None
描述
sgx_clearerr与C文件API clearerr相似。 此函数尝试修复由基础文件系统引起的错误,例如对磁盘的写错误(导致整个缓存无法清空)。 调用此函数后,调用sgx_ferror或sgx_feof以了解它是否成功执行。
有关此API及其参数的更多详细信息,请参阅fclearerr文档。
要求
Header | sgx_tprotected_fs.h sgx_tprotected_fs.edl |
Library | libsgx_tprotected_fs.a |
sgx_remove
sgx_remove函数从文件系统中删除一个文件。
语法
int32_t sgx_remove(
const char* filename,
);
参数
filename [in]
需要被删除的文件的名字。
返回值
0
此操作成功完成。
1
一个错误产生了。检查errno来获得错误代码。
描述
sgx_remove与C文件API remove相似。
有关此API及其参数的更多详细信息,请参阅remove文档。
要求
Header | sgx_tprotected_fs.h sgx_tprotected_fs.edl |
Library | libsgx_tprotected_fs.a |
sgx_fexport_auto_key
sgx_fexport_auto_key函数用于导出最新的用于文件加密的密钥。有关更多详细信息,请参见“使用自动密钥API情况下的文件传输”。
语法
int32_t sgx_fexport_auto_key(
const char* filename,
sgx_key_128bit_t *key
);
参数
filename [in]
要被导出(自动密钥)的文件的名字。这需要是一个sgx_fopen_auto_key API创建的文件的名称。
key [out]
最新的加密密钥。
返回值
0
此操作成功完成。
1
一个错误产生了。检查errno来获得错误代码。
描述
sgx_fexport_auto_key用于导出文件加密中使用的最新密钥。 有了此密钥,您可以将文件导入其他Enclave或系统。
注意:
- 为了使此函数正常运作,不应在任何其他进程中打开此文件。
- 此功能仅适用于使用sgx_fopen_auto_key创建的文件。
有关更多详细信息,请参见“使用自动密钥API情况下的文件传输”。
要求
Header | sgx_tprotected_fs.h sgx_tprotected_fs.edl |
Library | libsgx_tprotected_fs.a |
sgx_fimport_auto_key
sgx_fimport_auto_key函数用于导入另一个Enclave或平台上的受保护FS自动密钥文件。有关更多详细信息,请参见“使用自动密钥API情况下的文件传输”。
语法
int32_t sgx_fimport_auto_key(
const char* filename,
const sgx_key_128bit_t *key
);
参数
filename [in]
要被导入(自动密钥)的文件的名字。这需要是另一个Enclave或平台上的,用sgx_fopen_auto_key API创建的文件的名称。
key [in]
加密密钥。在源Enclave或平台使用sgx_fexport_auto_key导出的。
返回值
0
此操作成功完成。
1
一个错误产生了。检查errno来获得错误代码。
描述
sgx_fimport_auto_key用于导入受保护FS的(自动密钥)文件。函数成功返回后,可以使用sgx_fexport_auto_key正常打开此(由自动密钥加密的)文件。
注意:
- 为了使此函数正常运作,不应在任何其他进程中打开此文件。
- 此功能仅适用于使用sgx_fopen_auto_key创建的文件。
有关更多详细信息,请参见“使用自动密钥API情况下的文件传输”。
要求
Header | sgx_tprotected_fs.h sgx_tprotected_fs.edl |
Library | libsgx_tprotected_fs.a |
sgx_fclear_cache
sgx_fclear_cache函数用于清除内部文件缓存,该函数在缓存中清除所有数据,并释放所有已分配的缓存内存。
语法
int32_t sgx_fclear_cache(
SGX_FILE* stream
);
参数
stream [in]
先前sgx_fopen或sgx_fopen_auto_key返回的文件句柄。
返回值
0
此操作成功完成。
1
一个错误产生了。检查errno来获得错误代码。
描述
sgx_fclear_cache用于从缓存中清除所有数据并释放所有分配的缓存内存。如果在缓存中找到修改后的数据,则在清理之前会将其写入磁盘上的文件中。
如果您不信任自己Enclave的某些部分(例如,链接到的外部库等),并且希望在将控制权转到不可信代码之前确保内存中的敏感数据越少越好,那么这个函数将特别有用。 但是请注意,SGX_FILE结构本身仍保留着敏感数据。 要从内存中完全删除所有与文件相关的数据,那么你应该关闭文件句柄。
要求
Header | sgx_tprotected_fs.h sgx_tprotected_fs.edl |
Library | libsgx_tprotected_fs.a |