corePKCS11 管理和随机数演示
简介
本演示是 corePKCS11 演示系列中的第一个。它涵盖了 PKCS #11 API 的管理 PKCS #11堆栈章节,并介绍了如何使用 PKCS #11 生成随机数。PKCS #11 标准可在
此处获取。
这些演示及其相关网页使用 PKCS #11 定义的术语可与 PKCS #11
API、堆栈、标准等术语替换使用。对标准中定义的术语稍作总结:"Cryptoki" 是指定义在 PKCS #11 标准中的加密
令牌接口,即 PKCS #11 API 或函数。Cryptoki 的实现
是指“Cryptoki 库”,等同于“PKCS #11 实现”或
“PKCS #11 堆栈”。
PKCS #11 规范分为三个头文件:
- pkcs11.h
- 这是主头文件,是应用程序唯一需要包含的文件。它需要在被包含之前
定义一些宏,这些定义位于 "core_pkcs11.h" 文件中(请参阅
<freertos>/libraries/freertos_plus/source/corepkcs11/include/core_pkcs11.h
)。因此,包含
PKCS #11 库时,要先包含 "core_pkcs11.h",然后再包含 "pkcs11.h"。
- pkcs11f.h
- 这包含了函数原型。
- pkcs11t.h
- 这包含了 PKCS #11 规范中定义的各种类型。
PKCS #11 演示项目使用
FreeRTOSWindows 移植,因此可以在 Windows 上使用 Visual Studio 免费社区版进行构建和评估,无需
任何特定的 MCU 硬件。
此演示中展示的函数集可分为:
-
- 通用函数
- 插槽和令牌管理函数
- 会话管理函数
- 随机数生成函数
源代码组织
基于 PKCS #11 的双向验证演示的 Visual Studio 解决方案名为
pkcs11_demo.sln
,位于
FreeRTOS 主下载文件的 FreeRTOS\FreeRTOS-Plus\Demo\corePKCS11_Windows_Simulator\
目录中。
点击放大
配置演示项目
要配置演示项目,请将 configPKCS11_MANAGEMENT_AND_RNG_DEMO
(位于 pkcs11_demo_config.h
中)设置为 1。
构建演示项目
演示项目使用 Visual Studio 的免费社区版本。
- 在Visual Studio IDE 中,打开 Visual Studio 解决方案文件
FreeRTOS\FreeRTOS-Plus\Demo\corePKCS11_Windows_Simulator\pkcs11_demos.sln
。
- 在 IDE 的 build 菜单中选择 build solution。
功能
此演示的入口点是 vPKCS11ManagementAndRNGDemo。此函数大致描述了如何启动
PKCS #11 会话并用它生成一个随机数的基本流程。
第一步是获取包含指向PKCS #11 堆栈所实现函数的函数指针。
结构体。未实现的函数始终为 NULL。这一点很有用,因为一些 PKCS #11
实现可能并不定义每个函数。演示将断言未实现的函数。考虑到
这种情况,它在真正的应用程序中会很有用,使得库在不同的
PKCS #11 实现之间兼容。
获取 PKCS #11 函数列表:
CK_FUNCTION_LIST_PTR pxFunctionList = NULL;
xResult = C_GetFunctionList( &pxFunctionList );
configASSERT( xResult == CKR_OK );
configASSERT( pxFunctionList != NULL );
configASSERT( pxFunctionList->C_Initialize != NULL );
configASSERT( pxFunctionList->C_GetSlotList != NULL );
configASSERT( pxFunctionList->C_OpenSession != NULL );
configASSERT( pxFunctionList->C_Login != NULL );
configASSERT( pxFunctionList->C_GenerateRandom != NULL );
configASSERT( pxFunctionList->C_CloseSession != NULL );
configASSERT( pxFunctionList->C_Finalize != NULL );
从 PKCS #11 实现中获取函数后,PKCS #11 实现可以通过
调用 C_Initialize
进行初始化。此函数不保证线程安全,在进行此调用时
应谨慎考虑并发问题。演示使用的 PKCS #11 堆栈未实现规范中的
线程安全机制。因此,在使用不同的 PKCS #11 堆栈时,可能需要重新审视调用 C_Initialize
的
任何代码,以确保正确处理并发。
初始化 PKCS #11 栈:
CK_C_INITIALIZE_ARGS xInitArgs = { 0 };
xResult = pxFunctionList->C_Initialize( &xInitArgs );
configASSERT( xResult == CKR_OK );
初始化后,我们会查询应用程序可以使用的插槽。插槽由 PKCS #11 定义为
"可能包含令牌的逻辑读取器"。演示将始终使用第一个
由 C_GetSlotList
返回的插槽,因为它要写入的实现只有一个插槽。
该插槽是应用程序可以指定要使用的令牌。许多实现在插槽到令牌的关系上
有所不同。要点是 SlotID 将指定我们要用于应用程序会话的
令牌。
选择一个插槽:
CK_SLOT_ID * pxSlotId = NULL;
CK_ULONG xSlotCount = 0;
xResult = pxFunctionList->C_GetSlotList( CK_TRUE,
NULL,
&xSlotCount );
configASSERT( xResult == CKR_OK );
pxSlotId = pvPortMalloc( sizeof( CK_SLOT_ID ) * ( xSlotCount ) );
configASSERT( pxSlotId != NULL );
xResult = pxFunctionList->C_GetSlotList( CK_TRUE,
pxSlotId,
&xSlotCount );
configASSERT( xResult == CKR_OK );
下一步是创建一个会话,将应用程序连接到由 PKCS #11 堆栈返回的插槽。规范
将会话定义为“应用程序与令牌之间的逻辑连接”。同样,
源代码和 PKCS #11 规范中会进一步对此进行解释。会话通过调用
C_OpenSession
建立,并指定应用程序要使用的插槽。
开启 PKCS #11 会话:
CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
xResult = pxFunctionList->C_OpenSession( pxSlotId[0],
CKF_SERIAL_SESSION | CKF_RW_SESSION,
NULL, /* Application defined pointer. */
NULL, /* Callback function. */
&hSession );
configASSERT( xResult == CKR_OK );
既然会话已经建立,我们可以使用它来生成一个随机数。在加密运算中经常使用
随机数,加密中使用的许多算法都依赖于随机数生成器的“随机性”,
以确保密码不会被破解。
生成随机数缓冲区:
CK_BYTE xRandomData[ 10 ] = { 0 };
xResult = pxFunctionList->C_GenerateRandom( hSession,
xRandomData,
sizeof( xRandomData ) );
configASSERT( xResult == CKR_OK );
for( ulIndex = 0; ulIndex < sizeof( xRandomData ); ulIndex++ )
{
configPRINTF( ( "Generated random number: %x\r\n", xRandomData[ ulIndex ] ) );
}
由于加密操作已完成,演示使用以下步骤清理资源:
- 关闭活动会话,
- 调用
C_Finalize
以取消初始化 PKCS #11 堆栈。
清理:
xResult = pxFunctionList->C_CloseSession( hSession );
configASSERT( xResult == CKR_OK );
xResult = pxFunctionList->C_Finalize( NULL );
configASSERT( xResult == CKR_OK );
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.