PSA Crypto

概述

PSA(Platform Security Architecture)Crypto API 提供了可移植的编程接口,用于在各类硬件上执行加密操作和存储密钥。它的设计易于使用,同时仍然提供现代密码学所必需的底层原语。

它由 Arm 创建并维护。Arm 开发 PSA 是为了提供一个全面的安全框架,以满足联网设备日益增长的安全需求。

在 Zephyr 中,PSA Crypto API 通过 Mbed TLS 实现,后者是一个开源加密库,提供底层的加密函数。

设计目标

该接口适用于种类繁多的设备:从使用内置密钥处理数据的专用加密处理器,到运行自定义应用代码的资源受限设备(如微控制器),再到支持多应用的设备(如服务器)。它遵循密码敏捷性原则。

算法灵活性

PSA Crypto API 支持多种加密算法,允许开发者按需在不同的加密方法之间切换。随着新算法不断涌现、现有算法逐渐过时,这种灵活性对于维持安全性至关重要。

密钥管理

PSA Crypto API 包含强大的密钥管理功能,支持以安全而灵活的方式创建、存储和使用密钥。它使用不透明的密钥标识符,从而可以轻松更换和更新密钥,而不会暴露密钥材料。

实现无关性

PSA Crypto API 对底层加密库进行了抽象,这意味着可以在不影响应用代码的情况下更换具体实现。这种抽象允许按需使用不同的加密库或硬件加速器,从而支持密码敏捷性。

面向未来

通过遵循密码敏捷性,PSA Crypto 确保应用能够快速适应新的加密标准和实践,从而增强长期安全性和合规性。

应用示例

网络安全(TLS)

该 API 提供建立 TLS 连接所需的全部加密原语。

安全存储

该 API 提供与基于块或基于文件的存储加密相关的全部原语,主加密密钥存储在密钥存储中。

网络凭据

该 API 在密钥存储中提供网络凭据管理,例如用于基于 X.509 的身份验证或企业网络中的预共享密钥。

设备配对

该 API 支持密钥协商协议,这类协议常用于通过无线信道安全地配对设备。例如,NFC 令牌或蓝牙设备的配对在首次使用时可能会采用密钥协商协议。

安全启动

该 API 提供的原语可在安全启动或可信启动过程中用于验证固件的完整性和真实性。

证明

该 API 提供证明活动中使用的原语。证明是指设备能够使用设备私钥对字节数组进行签名,并将结果返回给调用方。它有多种用例,从证明设备状态,到生成密钥对并证明该密钥对是在安全密钥存储中生成的。该 API 提供对常用于证明的算法的访问。

出厂配置

大多数 IoT 设备会在出厂配置过程中或部署到现场后获得唯一身份。该 API 提供了将代表该身份的密钥写入设备所需的接口。

使用注意事项

始终检查错误

PSA Crypto API 中的大多数函数都可能返回错误。所有可能失败的函数都返回 psa_status_t 类型。少数函数不会失败,因此返回 void 或其他类型。

如果发生错误,除非另有说明,输出参数的内容是未定义的,不得使用。

一些常见的错误原因包括:

  • 在密钥的存储和处理环境与应用分离的实现中,所有需要访问加密处理环境的函数都可能因两个环境之间的通信错误而失败。

  • 如果算法由硬件加速器实现,而该加速器在逻辑上与应用处理器分离,那么即使应用处理器继续正常运行,加速器也可能发生故障。

  • 大多数函数可能因资源不足而失败。不过,某些实现保证特定函数始终拥有足够的内存。

  • 所有访问持久密钥的函数都可能因存储故障而失败。

  • 所有需要随机性的函数都可能因熵不足而失败。建议实现在执行 psa_crypto_init() 期间为随机数生成器播种足够的熵。不过,某些安全标准要求定期从硬件随机数生成器重新播种,而这一过程可能失败。

共享内存与并发

某些环境允许多线程应用,而另一些环境则不允许。在某些环境中,应用可以与不同的安全上下文共享内存。在具有多线程应用或共享内存的环境中,必须谨慎编写应用,以避免数据损坏或泄漏。本规范要求应用遵守某些约束。

一般而言,PSA Crypto API 允许对任意给定对象要么有一个写入者,要么有任意数量的同时读取者。换句话说,如果两个或更多调用并发访问同一对象,那么只有当所有调用都只读取该对象而不修改它时,行为才是明确定义的。读取访问包括通过输入参数读取内存,以及通过使用密钥读取密钥存储内容。更多详细信息,请参阅 并发调用

如果应用与另一个安全上下文共享内存,它可以将共享内存块作为输入缓冲区或输出缓冲区传递,但不能作为非缓冲区参数传递。更多详细信息,请参阅 参数稳定性。

使用后清理

为了在系统被攻破时尽量减小影响,建议应用在敏感数据不再使用时将其从内存中清除。这样,只有当前正在使用的数据可能泄漏,过去的数据则不会受到危害。

清除敏感数据包括:

  • 清除栈或堆上的临时缓冲区。

  • 如果操作无法完成,则中止操作。

  • 销毁不再使用的密钥。

参考资料