

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 移植 corePKCS11 库
<a name="afr-porting-pkcs"></a>

公有密钥加密标准 \$111 定义了一个独立于平台的 API，可用于管理和使用加密令牌。[PKCS 11](https://en.wikipedia.org/wiki/PKCS_11) 是指它定义的标准和 API。PKCS \$111 加密 API 用于提取密钥存储、加密对象的 get/set 属性以及会话语义。该标准在操纵常见加密对象时应用广泛。它的功能允许应用程序软件使用、创建、修改和删除加密对象，而无需将这些对象暴露在应用程序的内存中。

FreeRTOS 库和参考集成使用 PCKS \$111 接口标准的子集，重点是涉及非对称密钥、随机数生成和哈希的操作。下表列出了使用案例和需要支持的 PKCS \$111 API。


**应用场景**  

| 用例 | 必需的 PKCS \$111 API 系列 | 
| --- | --- | 
| 全部 | 初始化、最终确定、打开/关闭会话、GetsLotList、登录 | 
| 预置 | GenerateKeyPair、CreateObject、DestroyObject、InitToken、GetTokenInfo | 
| TLS | 随机、签名、FindObject、GetAttributeValue | 
| FreeRTOS\$1TCP | 随机，摘要 | 
| OTA | 验证、摘要、FindObject、GetAttributeValue | 

## 何时实现完整的 PKCS \$111 模块
<a name="implemeting-pkcs"></a>

在通用闪存中存储私有密钥对于评估和快速原型设计场景非常方便。在生产场景中，为了减少数据窃取和设备复制的威胁，我们建议您使用专用加密硬件。加密硬件包含具有防止导出加密密钥功能的组件。为了支持这一点，您必须实现使用上表中定义的 FreeRTOS 库所需的 PKCS \$111 子集。

## 何时使用 FreeRTOS corePKCS11
<a name="using-pkcs"></a>

corePKCS11 库包含 PKCS \$111 接口 (API) 的基于软件的实现，该接口使用 [Mbed TLS](https://tls.mbed.org/) 提供的加密功能。这是在没有专用加密硬件的情况下，为硬件的快速原型设计和评估场景提供的。在这种情况下，您只需要实现 corePKCS11 PAL 即可让基于 corePKCS11 软件的实现与您的硬件平台配合使用。

## 移植 corePKCS11
<a name="porting-core-pkcs"></a>

您必须有实现才能读取加密对象并将其写入非易失性存储器 (NVM)，例如板载闪存。加密对象必须存储在设备重新编程时未初始化且未擦除的 NVM 部分。corePKCS11 库的用户将使用凭证预置设备，然后使用可通过 corePKCS11 接口访问这些凭证的新应用程序重新编程设备。corePKCS11 PAL 移植必须提供一个位置来存储：
+ 设备客户端证书
+ 设备客户端私有密钥
+ 设备客户端公有密钥
+ 受信任的根 CA
+ 代码验证公有密钥（或包含代码验证公有密钥的证书），用于安全引导加载程序和空中下载 (OTA) 更新
+ 即时预置证书。

包含[头文件](https://github.com/FreeRTOS/corePKCS11/blob/main/source/include/core_pkcs11_pal.h)并实现定义的 PAL API。


**PAL API**  

| 函数 | 描述 | 
| --- | --- | 
| PKCS11\$1PAL\$1Initialize |  初始化 PAL 层。由 corePKCS11 库在其初始化序列开始时调用。  | 
| PKCS11\$1PAL\$1SaveObject |  将数据写入非易失性存储。  | 
| PKCS11\$1PAL\$1FindObject |  使用 PKCS \$111 `CKA_LABEL` 来在非易失性存储中搜索相应的 PKCS \$111 对象，并返回该对象的句柄（如果存在）。  | 
| PKCS11\$1PAL\$1GetObjectValue |  检索对象的值，给定句柄。  | 
| PKCS11\$1PAL\$1GetObjectValueCleanup |  `PKCS11_PAL_GetObjectValue` 调用的清除。可用于释放 `PKCS11_PAL_GetObjectValue` 调用中分配的内存。  | 

## 测试
<a name="porting-testing-pkcs"></a>

如果您使用 FreeRTOS corePKCS11 库或实现所需的 PKCS11 API 子集，则必须通过 FreeRTOS PKCS11 测试。这些测试用于验证 FreeRTOS 库所需的函数能否按预期执行。

本节还介绍了如何使用资格认证测试在本地运行 FreeRTOS PKCS11 测试。

### 先决条件
<a name="porting-testing-prereqs"></a>

要设置 FreeRTOS PKCS11 测试，必须实现以下几点。
+ PKCS11 API 支持的移植。
+ FreeRTOS 资格认证测试平台功能的实现，其中包括：
  + `FRTest_ThreadCreate`
  + `FRTest_ThreadTimedJoin`
  + `FRTest_MemoryAlloc`
  + `FRTest_MemoryFree`

（参阅 GitHub 上有关 PKCS \$111 的 FreeRTOS 库集成测试的 [README.md](https://github.com/FreeRTOS/FreeRTOS-Libraries-Integration-Tests/tree/main/src/pkcs11) 文件。）

### 移植测试
<a name="porting-tests-pkcs11"></a>
+ 将 [FreeRTOS-Libraries-Integration-Tests](https://github.com/FreeRTOS/FreeRTOS-Libraries-Integration-Tests/tree/main/src/pkcs11) 作为子模块添加到您的项目中。只要可以构建子模块，就可以将其放在项目的任何目录中。
+ 将 `config_template/test_execution_config_template.h` 和 `config_template/test_param_config_template.h` 复制到构建路径中的项目位置，然后将其重命名为`test_execution_config.h`和`test_param_config.h`。
+ 将相关文件包含到构建系统中。如果使用 `CMake`，则可以使用 `qualification_test.cmake` 和 `src/pkcs11_tests.cmake` 来包含相关文件。
+ 实现 `UNITY_OUTPUT_CHAR`，这样，测试输出日志就不会与设备日志交错。
+ 集成 MbedTLS，用于验证 cryptoki 的操作结果。
+ 从应用程序调用 `RunQualificationTest()`。

### 配置测试
<a name="configure-pkcs11-tests"></a>

PKCS11 测试套件必须根据 PKCS11 实现进行配置。下表在 `test_param_config.h` 头文件中列出了 PKCS11 测试所需的配置。


**PKSC11 测试配置**  

| 配置 | 描述 | 
| --- | --- | 
| PKCS11\$1TEST\$1RSA\$1KEY\$1SUPPORT |  该移植支持 RSA 密钥功能。  | 
| PKCS11\$1TEST\$1EC\$1KEY\$1SUPPORT |  该移植支持 EC 密钥功能。  | 
| PKCS11\$1TEST\$1IMPORT\$1PRIVATE\$1KEY\$1SUPPORT |  移植支持导入私有密钥。如果已启用支持密钥功能，则将在测试中验证 RSA 和 EC 密钥导入。  | 
| PKCS11\$1TEST\$1GENERATE\$1KEYPAIR\$1SUPPORT |  移植支持生成密钥对。如果已启用支持密钥功能，则将在测试中验证 EC 密钥对生成。  | 
| PKCS11\$1TEST\$1PREPROVISIONED\$1SUPPORT |  移植具有预置凭证。`PKCS11_TEST_LABEL_DEVICE_PRIVATE_KEY_FOR_TLS`、`PKCS11_TEST_LABEL_DEVICE_PUBLIC_KEY_FOR_TLS` 和 `PKCS11_TEST_LABEL_DEVICE_CERTIFICATE_FOR_TLS` 是证书的示例。  | 
| PKCS11\$1TEST\$1LABEL\$1DEVICE\$1PRIVATE\$1KEY\$1FOR\$1TLS |  测试中使用的私有密钥的标签。  | 
| PKCS11\$1TEST\$1LABEL\$1DEVICE\$1PUBLIC\$1KEY\$1FOR\$1TLS |  测试中使用的公有密钥的标签。  | 
| PKCS11\$1TEST\$1LABEL\$1DEVICE\$1CERTIFICATE\$1FOR\$1TLS |  测试中使用的证书的标签。  | 
| PKCS11\$1TEST\$1JITP\$1CODEVERIFY\$1ROOT\$1CERT\$1SUPPORTED |  该移植支持 JITP 的存储。将其设置为 1 可启用 JITP `codeverify` 测试。  | 
| PKCS11\$1TEST\$1LABEL\$1CODE\$1VERIFICATION\$1KEY |  JITP `codeverify` 测试中使用的代码验证密钥的标签。  | 
| PKCS11\$1TEST\$1LABEL\$1JITP\$1CERTIFICATION |  JITP `codeverify` 测试中使用的 JITP 证书的标签。  | 
| PKCS11\$1TEST\$1LABEL\$1ROOT\$1CERTIFICATE |  JITP `codeverify` 测试中使用的根证书的标签。  | 

FreeRTOS 库和参考集成必须支持至少一种密钥功能配置，例如 RSA 或 Elliptic 曲线密钥，以及 PKCS11 API 支持的一种密钥预置机制。该测试必须启用以下配置：
+ 至少启用以下密钥功能配置之一：
  + PKCS11\$1TEST\$1RSA\$1KEY\$1SUPPORT
  + PKCS11\$1TEST\$1EC\$1KEY\$1SUPPORT
+ 至少启用以下密钥预置配置之一：
  + PKCS11\$1TEST\$1IMPORT\$1PRIVATE\$1KEY\$1SUPPORT
  + PKCS11\$1TEST\$1GENERATE\$1KEYPAIR\$1SUPPORT
  + PKCS11\$1TEST\$1PREPROVISIONED\$1SUPPORT 

预先配置的设备凭证测试必须在以下条件下运行：
+ 必须启用 `PKCS11_TEST_PREPROVISIONED_SUPPORT` 并禁用其他配置机制。
+ 只有一个密钥功能（`PKCS11_TEST_RSA_KEY_SUPPORT` 或 `PKCS11_TEST_EC_KEY_SUPPORT`）处于启用状态。
+ 根据您的密钥功能设置预先配置的密钥标签，包括 `PKCS11_TEST_LABEL_DEVICE_PRIVATE_KEY_FOR_TLS`、`PKCS11_TEST_LABEL_DEVICE_PUBLIC_KEY_FOR_TLS` 和 `PKCS11_TEST_LABEL_DEVICE_CERTIFICATE_FOR_TLS`。在运行测试之前，这些凭证必须存在。

如果实现支持预先配置的凭证和其他配置机制，则测试可能需要使用不同的配置运行多次。

**注意**  
如果启用 `PKCS11_TEST_GENERATE_KEYPAIR_SUPPORT` 或 `PKCS11_TEST_GENERATE_KEYPAIR_SUPPORT`，则会在测试期间销毁带有标签 `PKCS11_TEST_LABEL_DEVICE_PRIVATE_KEY_FOR_TLS`、`PKCS11_TEST_LABEL_DEVICE_PUBLIC_KEY_FOR_TLS` 和 `PKCS11_TEST_LABEL_DEVICE_CERTIFICATE_FOR_TLS` 的对象。

### 运行测试
<a name="running-tests"></a>

本节介绍如何通过资格认证测试在本地测试 PKCS11 接口。或者，您也可以使用 IDT 自动执行。有关详细信息，请参阅《FreeRTOS 用户指南》中 [适用于 FreeRTOS 的 AWS IoT Device Tester](https://docs.aws.amazon.com/freertos/latest/userguide/device-tester-for-freertos-ug.html)。**

以下说明介绍了如何运行测试：
+ 打开 `test_execution_config.h` 并将 **CORE\$1PKCS11\$1TEST\$1ENABLED** 定义为 1。
+ 构建应用程序并将其刷写到您的设备上，以便运行。测试结果会输出到串行端口。

下面是输出测试结果的一个示例。

```
TEST(Full_PKCS11_StartFinish, PKCS11_StartFinish_FirstTest) PASS
TEST(Full_PKCS11_StartFinish, PKCS11_GetFunctionList) PASS
TEST(Full_PKCS11_StartFinish, PKCS11_InitializeFinalize) PASS
TEST(Full_PKCS11_StartFinish, PKCS11_GetSlotList) PASS
TEST(Full_PKCS11_StartFinish, PKCS11_OpenSessionCloseSession) PASS
TEST(Full_PKCS11_Capabilities, PKCS11_Capabilities) PASS
TEST(Full_PKCS11_NoObject, PKCS11_Digest) PASS
TEST(Full_PKCS11_NoObject, PKCS11_Digest_ErrorConditions) PASS
TEST(Full_PKCS11_NoObject, PKCS11_GenerateRandom) PASS
TEST(Full_PKCS11_NoObject, PKCS11_GenerateRandomMultiThread) PASS
TEST(Full_PKCS11_RSA, PKCS11_RSA_CreateObject) PASS
TEST(Full_PKCS11_RSA, PKCS11_RSA_FindObject) PASS
TEST(Full_PKCS11_RSA, PKCS11_RSA_GetAttributeValue) PASS
TEST(Full_PKCS11_RSA, PKCS11_RSA_Sign) PASS
TEST(Full_PKCS11_RSA, PKCS11_RSA_FindObjectMultiThread) PASS
TEST(Full_PKCS11_RSA, PKCS11_RSA_GetAttributeValueMultiThread) PASS
TEST(Full_PKCS11_RSA, PKCS11_RSA_DestroyObject) PASS
TEST(Full_PKCS11_EC, PKCS11_EC_GenerateKeyPair) PASS
TEST(Full_PKCS11_EC, PKCS11_EC_CreateObject) PASS
TEST(Full_PKCS11_EC, PKCS11_EC_FindObject) PASS
TEST(Full_PKCS11_EC, PKCS11_EC_GetAttributeValue) PASS
TEST(Full_PKCS11_EC, PKCS11_EC_Sign) PASS
TEST(Full_PKCS11_EC, PKCS11_EC_Verify) PASS
TEST(Full_PKCS11_EC, PKCS11_EC_FindObjectMultiThread) PASS
TEST(Full_PKCS11_EC, PKCS11_EC_GetAttributeValueMultiThread) PASS
TEST(Full_PKCS11_EC, PKCS11_EC_SignVerifyMultiThread) PASS
TEST(Full_PKCS11_EC, PKCS11_EC_DestroyObject) PASS

-----------------------
27 Tests 0 Failures 0 Ignored
OK
```

 当所有测试均已通过后，测试完成。

**注意**  
要正式对设备进行 FreeRTOS 资格认证，您必须使用 AWS IoT Device Tester 验证设备的移植源代码。按照《FreeRTOS 用户指南》中[使用适用于 FreeRTOS 的 AWS IoT Device Tester](https://docs.aws.amazon.com/freertos/latest/userguide/device-tester-for-freertos-ug.html)中的说明为移植验证设置 AWS IoT Device Tester。要测试特定库的移植，必须在 AWS IoT Device Tester `configs` 文件夹下面的 `device.json` 文件中启用正确的测试组。