

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

# 移植核心PKCS11 库
<a name="afr-porting-pkcs"></a>

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

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


**应用场景**  

| 使用场景 | 必需的 PKCS \$111 API 系列 | 
| --- | --- | 
| 全部 | 初始化、完成、 Open/Close 会话 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 内核 PKCS11
<a name="using-pkcs"></a>

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

## 移植核心 PKCS11
<a name="porting-core-pkcs"></a>

您必须有实现才能读取加密对象并将其写入非易失性存储器 (NVM)，例如板载闪存。加密对象必须存储在设备重新编程时未初始化且未擦除的 NVM 部分。核心PKCS11 库的用户将为设备提供凭据，然后使用通过核心PKCS11 接口访问这些凭据的新应用程序对设备进行重新编程。核心 PKCS11 PAL 端口必须提供存储以下内容的位置：
+ 设备客户端证书
+ 设备客户端私有密钥
+ 设备客户端公有密钥
+ 受信任的根 CA
+ 用于安全启动加载器和 (OTA) 更新的代码验证公钥（或包含代码验证公钥的证书） over-the-air
+  Just-In-Time供应证书

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


**PAL APIs**  

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

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

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

本节还介绍如何通过资格测试在本地运行 F PKCS11 reeRTOS 测试。

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

要设置 FreeRTO PKCS11 S 测试，必须实现以下内容。
+ 支持的端口 PKCS11 APIs。
+ FreeRTOS 资格认证测试平台功能的实现，其中包括：
  + `FRTest_ThreadCreate`
  + `FRTest_ThreadTimedJoin`
  + `FRTest_MemoryAlloc`
  + `FRTest_MemoryFree`

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

### 移植测试
<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\$1测试\$1导入\$1私钥\$1支持 |  移植支持导入私有密钥。如果已启用支持密钥功能，则将在测试中验证 RSA 和 EC 密钥导入。  | 
| PKCS11\$1测试\$1生成\$1密钥对\$1支持 |  移植支持生成密钥对。如果已启用支持密钥功能，则将在测试中验证 EC 密钥对生成。  | 
| PKCS11\$1测试\$1预配置\$1支持 |  移植具有预置凭证。`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 TL |  测试中使用的私有密钥的标签。  | 
| PKCS11\$1TEST\$1LABEL\$1DEVICE\$1PUBLIC\$1KEY\$1FOR TLS |  测试中使用的公有密钥的标签。  | 
| PKCS11\$1TEST\$1LABEL\$1DEVICE\$1CERTIFACE\$1FOR TLS |  测试中使用的证书的标签。  | 
| PKCS11\$1TEST\$1JITP\$1CODEVERIFY\$1ROOT\$1CERT\$1支持 |  该移植支持 JITP 的存储。将其设置为 1 可启用 JITP `codeverify` 测试。  | 
| PKCS11\$1TEST\$1LABEL\$1CODE\$1VERIFICATION\$1KEY |  JITP `codeverify` 测试中使用的代码验证密钥的标签。  | 
| PKCS11\$1TEST\$1LABEL\$1JITP\$1CERTIFICATE |  JITP `codeverify` 测试中使用的 JITP 证书的标签。  | 
| PKCS11\$1TEST\$1LABEL\$1根证书 |  JITP `codeverify` 测试中使用的根证书的标签。  | 

FreeRTOS 库和参考集成必须支持至少一种按键功能配置，例如 RSA 或 Elliptic 曲线键，以及支持的一种密钥配置机制。 PKCS11 APIs该测试必须启用以下配置：
+ 至少启用以下密钥功能配置之一：
  + PKCS11\$1TEST\$1RSA\$1KEY\$1SUPPORT
  + PKCS11\$1TEST\$1EC\$1KEY\$1SUPPORT
+ 至少启用以下密钥预置配置之一：
  + PKCS11\$1测试\$1导入\$1私钥\$1支持
  + PKCS11\$1测试\$1生成\$1密钥对\$1支持
  + PKCS11\$1测试\$1预配置\$1支持 

预先配置的设备凭证测试必须在以下条件下运行：
+ 必须启用 `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\$1 PKCS11 \$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 用户指南》中的 “用 AWS IoT Device Tester 于](https://docs.aws.amazon.com/freertos/latest/userguide/device-tester-for-freertos-ug.html) FreeRTOS” 中的说明进行端口验证设置。 AWS IoT Device Tester 要测试特定库的端口，必须在 AWS IoT Device Tester `configs`文件夹`device.json`的文件中启用正确的测试组。