可信存储API(GP Internal API)

总体设计

1、每个TA都可以访问由32位存储标识符标识的一组可信存储空间。

  • 本规范为每个TA定义了一个单独的、私有的可信存储空间,此存储空间中的对象仅可由创建它们的TA访问,而其他TA不可见。
  • 其他存储标识符可以在本规范的未来版本中定义,例如,在多个TA之间共享存储空间,或在启动时实体和运行时TA之间进行通信的存储空间。

2、可信存储空间包含持久对象。每个持久对象都由对象标识符标识,对象标识符是从0到64字节的可变长度二进制缓冲区。对象标识符可以包含任何字节,包括对应于不可打印字符的字节。

3、一个持久对象可以是Cryptographic Key对象,Cryptographic Key-Pair对象,或Data对象。

4、每个持久对象都有一个类型,该类型精确定义了对象的内容。例如,AES密钥,RSA密钥对,数据对象等类型。

5、所有持久对象都有一个关联的数据流。持久data对象仅具有数据流,持久key对象(即密钥或密钥对)具有数据流,对象属性和元数据。

  • 数据流完全在TA存储器空间中进行管理,可以在打开对象时将其加载到TA分配的缓冲区中,也可以在创建对象时从TA分配的缓冲区中存储它。它也可以作为流进行访问,因此可以用于存储由小块访问的大量数据。
  • 对象属性用于少量数据(通常为几十或几百个字节)。它们可以存储在与TA实例分离的内存池中,并且某些属性可能对TA本身隐藏。属性用于以结构化方式存储key material 。例如,RSA密钥对具有模数,公共指数,私有指数等属性。创建对象时,必须指定所有的必要对象属性并可以指定可选对象属性。

6、与每个加密对象关联的元数据包括:

  • key size:确切含义取决于密钥算法,例如AES密钥可以是128位、192位和256位;RSA密钥可以是1024位或2048位等。
  • key usage flags:定义了密钥允许的操作以及key material的敏感部分是否可以由TA检索

7、TA也可以分配瞬时对象。

  • 瞬时对象保存在内存中,当它们关闭或TA实例销毁时,它们会自动擦除和回收。
  • 瞬时对象仅包含属性,而没有数据流。
  • 瞬时对象可以是未初始化的,在这种情况下,它是分配了某种对象类型和最大大小但没有属性的对象容器。瞬时对象在填充其属性时将被初始化。请注意,持久对象始终是经初始化创建的,这意味着当TA要生成或派生持久密钥时,它必须首先使用一个瞬时对象,然后将瞬时对象的属性写入持久对象中。
  • 瞬时对象没有标识符,它们只能通过对象句柄进行操作。
  • 当前,瞬时对象用于加密密钥和密钥对。

8、任何访问持久对象句柄的函数都可能返回TEE_ERROR_CORRUPT_OBJECT或TEE_ERROR_CORRUPT_OBJECT_2状态,这表明已检测到对象损坏。在返回此状态之前,TEE实现应删除损坏的对象并关闭关联的句柄;随后使用该句柄发出panic。

9、持久对象和瞬时对象通过不透明的对象句柄进行操作

  • 一些函数接受两种类型的对象句柄,例如可以使用瞬时密钥句柄或持久密钥句柄来启动加密操作
  • 一些函数仅接受瞬时对象的句柄。例如,填充对象的属性仅适用于瞬时对象,因为它需要未初始化的对象,而持久性对象始终被完全初始化
  • 类文件API的函数仅能通过持久对象访问数据流,因为瞬时对象没有数据流。

 

 

可信存储和回滚检测

可信存储必须提供最低级别的保护,以防止对持久对象的回滚攻击。但是,可以接受的是,实际的物理存储可能位于不安全的区域,因此很容易受到TEE外部动作的影响。

TA从可信存储的回滚检测机制中推断出的保护信任级别是由实现定义的,可以通过查询相应属性来获取:gpd.tee.trustedStorage.rollbackDetection.protectionLevel

 

 

 

数据类型

 

 

 

通用对象函数

可以在临时对象句柄和持久对象句柄上调用这些函数。

1、TEE_Result TEE_GetObjectInfo1(TEE_ObjectHandle object, [out] TEE_ObjectInfo* objectInfo);

该函数替代了不推荐使用的TEE_GetObjectInfo函数,该函数返回对象的特征,其填充TEE_ObjectInfo数据结构中的域。

 

2、TEE_Result TEE_RestrictObjectUsage1(TEE_ObjectHandle object, uint32_t objectUsage);

该函数替代了不推荐使用的TEE_RestrictObjectInfo函数,

 

3、TEE_Result TEE_GetObjectBufferAttribute(TEE_ObjectHandle object, uint32_t attributeID, [outbuf] void* buffer, size_t* size);

该函数从一个对象中提取出一个buffer属性,该属性由参数attributeID标识,此参数的确切含义取决于容器的类型和大小。

属性标识符的bit[29]必须设置为0,即必须表示buffer属性。

 

4、TEE_Result TEE_GetObjectValueAttribute(TEE_ObjectHandle object, uint32_t attributeID, [outopt] uint32_t* a, [outopt] uint32_t* b);

该函数从一个对象中提取出一个value属性,该属性由参数attributeID标识,此参数的确切含义取决于容器的类型和大小。

属性标识符的bit[29]必须设置为1,即必须表示value属性。

 

5、void TEE_CloseObject(TEE_ObjectHandle object);

该函数关闭打开的对象句柄,可以是持久对象或瞬时对象。对于瞬时对象,TEE_CloseObject等效于TEE_FreeTransientObject。

即使对象或包含的存储已损坏,此功能也将正常运行。

 

 

瞬时对象函数

1、TEE_Result TEE_AllocateTransientObject(uint32_t objectType, uint32_t maxObjectSize, [out] TEE_ObjectHandle* object);

该函数分配一个未初始化的瞬时对象,即属性容器。瞬时对象用于保存加密对象(密钥或密钥对),必须指定对象类型和最大密钥大小,以便可以预先分配所有资源。

分配后,容器是未初始化的,随后可以通过导入object material,生成对象、派生对象或从可信存储中加载对象来对其进行初始化。

与容器关联的密钥用法的初始值是0xFFFFFFFF,意味着其可以包含所有使用标志。可以使用TEE_RestrictObjectUsage1函数来限制容器的使用。

返回的句柄可用于后续功能,如密钥管理、函数操作等。直到使用函数TEE_FreeTransientObject释放容器,该句柄一直保持有效。

对象类型确定了要传递给TEE_AllocateTransientObject的可能的对象大小,不一定是要分配的对象大小

 

2、void TEE_FreeTransientObject(TEE_ObjectHandle object);

该函数释放TEE_AllocateTransientObject先前分配的瞬时对象。调用此函数后,对象句柄将不再有效,并且必须回收与瞬时对象关联的所有资源。

如果对象已经初始化,则在释放对象之前清除对象属性。如果传入参数为TEE_HANDLE_NULL,该函数不执行任何操作。

 

3、void TEE_ResetTransientObject(TEE_ObjectHandle object);

该函数将瞬时对象重置为其刚分配后的初始状态,如果该对象当前已初始化,则该函数清除该对象的所有材料,对象又变成未初始化状态。

在任何情况下,该函数都会将容器的密钥用法重置为0xFFFFFFFF。如果传入参数为TEE_HANDLE_NULL,该函数不执行任何操作。

 

4、TEE_Result TEE_PopulateTransientObject(TEE_ObjectHandle object, [in] TEE_Attribute* attrs, uint32_t attrCount);

该函数使用参数attrs中传递的对象属性填充未初始化的对象容器。
调用此函数时,对象必须未初始化;如果已经初始化,则需要先调用TEE_ResetTransientObject清楚对象。

请注意,如果对象类型是密钥对,则此函数将设置密钥对的私钥和公钥属性。必须指定所有必填属性,否则程序将出现panic。

 

5、void TEE_InitRefAttribute([out] TEE_Attribute* attr, uint32_t attributeID, [inbuf] void* buffer, size_t length);

void TEE_InitValueAttribute([out] TEE_Attribute* attr, uint32_t attributeID, uint32_t a, uint32_t b);

这两个辅助函数被用来填充属性。

 

6、TEE_Result TEE_CopyObjectAttributes1(TEE_ObjectHandle destObject, TEE_ObjectHandle srcObject);

该函数替代了不推荐使用的TEE_CopyObjectAttributes函数。

该函数使用另一个对象句柄的属性填充未初始化的对象句柄,即使用srcObject的属性填充destObject的属性,可用在下列场合:

  • 从密钥对对象提取公钥属性
  • 将属性从持久对象复制到瞬时对象中

destObject必须是未初始化的对象句柄,因此必须是临时对象。源对象和目标对象必须具有兼容的类型和大小:

  • destObject的类型必须是srcObject的子类型
  • srcObject的大小必须小于或等于destObject的最大大小

 

 

 

7、TEE_Result TEE_GenerateKey(TEE_ObjectHandle object, uint32_t keySize, [in] TEE_Attribute* params, uint32_t paramCount);

该函数生成一个随机密钥或密钥对,并使用生成的密钥材料填充临时密钥对象。所需的密钥大小在keySize参数中传递,并且必须小于或等于创建临时对象时指定的最大密钥大小。

 

 

持久对象函数

1、TEE_Result TEE_OpenPersistentObject(uint32_t storageID, [in(objectIDLength)] void* objectID, size_tobjectIDLen, uint32_t flags, [out] TEE_ObjectHandle* object);

TEE_OpenPersistentObject函数可在现有的持久对象上打开一个句柄。它返回一个可用于访问对象的属性和数据流的句柄。

storageID参数指示要访问哪个可信存储空间。

flags参数是一组标志,用于控制打开对象句柄的访问权限和共享权限,其值由下列标志进行或操作形成:

  • 访问控制标志:TEE_DATA_FLAG_ACCESS_READ(TEE_ReadObjectData)、TEE_DATA_FLAG_ACCESS_WRITE(TEE_WriteObjectData / TEE_TruncateObjectData)、TEE_DATA_FLAG_ACCESS_WRITE_META(TEE_CloseAndDeletePersistentObjec / TEE_RenamePersistentObject)
  • 共享权限控制标志:TEE_DATA_FLAG_SHARE_READ、TEE_DATA_FLAG_SHARE_WRITE
  • 其他标志保留供将来使用,应将其设置为0

可以同时在同一对象上打开多个句柄,但必须明确允许共享。

数据流中的初始数据位置设置为0。

 

2、TEE_Result TEE_CreatePersistentObject(uint32_t storageID, [in(objectIDLength)] void* objectID, size_t objectIDLen, uint32_t flags, TEE_ObjectHandle attributes, [inbuf] void* initialData, size_t initialDataLen, [out] TEE_ObjectHandle* object);

创建具有初始属性和初始数据流内容的持久对象,并有选择地返回所创建对象的句柄或失败时返回TEE_HANDLE_NULL。

 

4、TEE_Result TEE_CloseAndDeletePersistentObject1(TEE_ObjectHandle object);

该函数替代了不推荐使用的TEE_CloseAndDeletePersistentObject函数,其将对象标记为删除并关闭对象句柄。

必须使用写元数据访问权限打开对象句柄,这意味着对该对象的访问是独占的。

删除对象是原子操作。一旦此函数返回,则该对象肯定会被删除,并且不再存在该对象的打开句柄。即使对象或包含该对象的存储已损坏,情况也是如此。

该函数可能失败的唯一原因是,包含对象的存储区变得无法访问,此时将返回TEE_ERROR_STORAGE_NOT_AVAILABLE。

 

5、TEE_Result TEE_RenamePersistentObject(TEE_ObjectHandleobject, [in(newObjectIDLen)] void* newObjectID, size_t newObjectIDLen);

该函数改变一个对象的标识符。必须使用写元数据访问权限打开对象句柄,这意味着对该对象的访问是独占的。

重命名对象是原子操作,对象或者被重命名或者什么也没有发生。

 

 

持久对象枚举函数

1、TEE_Result TEE_AllocatePersistentObjectEnumerator([out] TEE_ObjectEnumHandle* objectEnumerator);

该函数在对象枚举器上分配一个句柄,一旦分配了对象枚举器句柄,就可以将其重新用于多个枚举。

 

2、void TEE_FreePersistentObjectEnumerator(TEE_ObjectEnumHandle objectEnumerator);

该函数释放与对象枚举器句柄关联的所有资源。调用此函数后,该句柄不再有效。

 

3、void TEE_ResetPersistentObjectEnumerator(TEE_ObjectEnumHandle objectEnumerator);

该函数重置一个对象枚举器句柄为它刚分配后的初始状态。如果枚举已经启动,则将停止。

 

4、TEE_Result TEE_StartPersistentObjectEnumerator(TEE_ObjectEnumHandle objectEnumerator, uint32_t storageID);

 

5、TEE_Result TEE_GetNextPersistentObject(TEE_ObjectEnumHandle objectEnumerator, [out] TEE_ObjectInfo* objectInfo, [out(TEE_OBJECT_ID_MAX_LEN)] void* objectID, [out] size_t* objectIDLen);

该函数获取枚举中的下一个对象并返回有关该对象的信息:类型,大小,标识符等。

如果枚举中没有其他对象,或者没有启动任何枚举,则该函数返回TEE_ERROR_ITEM_NOT_FOUND。如果在枚举对象时检测到损坏的对象,则应在objectID中返回其对象ID,应将objectInfo归零,并且函数应返回TEE_ERROR_CORRUPT_OBJECT。

 

 

数据流访问函数

这些函数可用于访问持久对象的数据流,它们像文件API一样工作。

1、TEE_Result TEE_ReadObjectData(TEE_ObjectHandle object, [out] void* buffer, size_t size, [out] uint32_t* count );

尝试从与object对象关联的数据流中读取size个字节到由buffer指向的缓冲区中,实际读取的字节数写入count参数。

2、TEE_Result TEE_WriteObjectData(TEE_ObjectHandle object, [in] void* buffer, size_t size);

尝试将buffer所指向的缓冲区的size个字节写入打开的object对象句柄关联的数据流中。

3、TEE_Result TEE_TruncateObjectData(TEE_ObjectHandle object, uint32_t size);

该函数改变一个数据流的size。如果参数size小于当前数据流的size,则将删除所有超出size的字节;如果参数size大于当前数据流的size,则在数据流末端添加零字节来扩展数据流。

4、TEE_Result TEE_SeekObjectData(TEE_ObjectHandle object, int32_t offset, TEE_Whence whence );

设置与对象句柄关联的数据位置指示符。

 

posted @ 2021-04-26 16:47  hunterDing  阅读(1314)  评论(0编辑  收藏  举报