本页提供了更多详细信息和准则,以协助实现 KeyMint 硬件抽象层 (HAL)。HAL 的主要文档是 AIDL 接口规范。
API 滥用
调用方可以使用作为 API 参数有效的授权创建 KeyMint 密钥,但这会导致生成的密钥不安全或无法使用。在这种情况下,KeyMint 实现无需失败或发出诊断。实现不应诊断以下情况:使用过小的密钥、指定不相关的输入参数、重复使用 IV 或 Nonce、生成密钥时未指定目的(因此生成的密钥没有用处),以及类似情况。
应用、框架和 Android 密钥库需负责确保对 KeyMint 模块的调用是合理的,而且是有用的。
addRngEntropy 入口点
addRngEntropy
入口点会将调用方提供的熵添加到 KeyMint 实现生成随机数(用作密钥和 IV)所用的池中。
KeyMint 实现需要将收到的熵安全地混合到所使用的池中,该池中还必须包含由硬件随机数生成器在内部生成的熵。对混合操作的处理应该实现:即使攻击者能够完全控制 addRngEntropy
提供的数位或硬件生成的数位(但不能同时控制这两者),他们在预测从熵池生成的数位方面也不具有明显的优势。
密钥特性
用于创建 KeyMint 密钥的每种机制(generateKey
、importKey
和 importWrappedKey
)都会返回新创建的密钥的特征,并将这些特征适当地划分为强制执行每个特征的安全级别。返回的特性包含为创建密钥而指定的所有参数,但 Tag::APPLICATION_ID
和 Tag::APPLICATION_DATA
除外。如果密钥参数中包含这两个标记,为确保无法通过查看返回的密钥 blob 找到这两个标记的值,系统会将这两个标记从返回的特性中移除。不过,这两个标记以加密形式绑定到密钥 blob,以便在使用相应密钥时,如果未提供正确的值,使用会失败。同样,Tag::ROOT_OF_TRUST
同样会以加密形式绑定到相应密钥,但在生成或导入密钥期间可以不指定此标记,并且在任何情况下都不会返回此标记。
除了提供的标记外,KeyMint 实现还会添加 Tag::ORIGIN
,用于指明密钥的创建方式(KeyOrigin::GENERATED
、KeyOrigin::IMPORTED
或 KeyOrigin::SECURELY_IMPORTED
)。
抗回滚
抗回滚由 Tag::ROLLBACK_RESISTANCE
表示,表示在使用 deleteKey
或 deleteAllKeys
删除密钥后,安全硬件可确保该密钥绝对无法再使用。
KeyMint 实现会将生成或导入的密钥材料作为密钥 Blob(一种经过加密和身份验证的形式)返回给调用程序。当密钥库删除密钥 blob 后,相应密钥将会消失,但之前已设法获取密钥材料的攻击者有可能可以将相应密钥材料恢复到设备上。
如果安全硬件保证被删除的密钥以后无法被恢复,那么相应密钥便可抗回滚。安全硬件通常是通过将额外的密钥元数据存储在攻击者无法操控的可信位置来做到这一点。在移动设备上,用于实现这一点的机制通常为 Replay Protected Memory Block (RPMB)。由于可创建的密钥数量基本上没有限制,而用于抗回滚的可信存储空间的大小则可能有限制,因此,当存储空间已满时,实现可能会使创建抗回滚密钥的请求失败。
begin
begin()
入口点使用指定的密钥和参数(视情况而定)针对指定的目的开始执行加密操作。它会返回一个新的 IKeyMintOperation
Binder 对象,用于完成操作。此外,系统还会返回一个质询值,该值会在经过身份验证的操作中用作身份验证令牌的一部分。
KeyMint 实现支持至少 16 个并行操作。密钥库最多使用 15 个,留一个给 vold
用于对密码进行加密。当密钥库有 15 个操作正在进行(已调用 begin()
,但尚未调用 finish
或 abort
)时,如果密钥库收到开始执行第 16 个操作的请求,它会对最近使用最少的操作调用 abort()
,以便将进行中的操作减少到 14 个,然后再调用 begin()
来开始执行新请求的操作。
如果在生成或导入密钥期间指定了 Tag::APPLICATION_ID
或 Tag::APPLICATION_DATA
,那么调用 begin()
时必须包含这两个标记,标记的值为最初在 params
参数中为此方法指定的值。
错误处理
如果 IKeyMintOperation
上的某个方法返回除 ErrorCode::OK
之外的错误代码,相应操作会被中止,操作 binder 对象也会变为无效。以后再使用该对象时,都会返回 ErrorCode::INVALID_OPERATION_HANDLE
。
密钥授权强制执行
密钥授权强制执行主要在 begin()
中进行。不过,密钥存在以下情况时例外:Tag::USER_SECURE_ID
Tag::AUTH_TIMEOUT
在这种情况下,对于每一项操作,密钥都会要求提供授权,并且 update()
或 finish()
方法会在 authToken
参数中收到一个授权令牌。为了确保令牌有效,KeyMint 实现:
- 验证身份验证令牌上的 HMAC 签名。
- 检查令牌是否包含与密钥关联的安全用户 ID。
- 检查令牌的身份验证类型是否与密钥的
Tag::USER_AUTH_TYPE
一致。 - 检查令牌是否包含质询字段中当前操作的质询值。
如果不符合这些条件,KeyMint 会返回 ErrorCode::KEY_USER_NOT_AUTHENTICATED
。
调用方会在每次调用 update()
和 finish()
时提供身份验证令牌。实现只能对该令牌验证一次。