👹
Carlos's Tech Blog
  • 🧔ECUs
    • ZYNQ_Documents
      • [ZYNQ] 构建ZYNQ的BSP工程
      • [ZYNQ] 启动流程
      • [ZYNQ] Secure Boot Flow
      • [ZYNQ] Provisioning Guideline
      • [ZYNQ] Decrypting Partition by the Decrypt Agent Using PUF key
      • [ZYNQ] enabling the cryptsetup on ramdisk
      • [ZYNQ] Encrypt external files based on file system using PUF key
      • [ZYNQ] Loading an Encrypted Linux kernel at U-Boot with a KUP Key
      • [ZYNQ] cross-compile the cryptsetup on Xilinx ZYNQ aarch64 platform
      • [ZYNQ] Linux Linaro系统镜像制作SD卡启动
    • S32G_Documents
      • [S32G] Going through the s32g hard/soft platform
      • [S32G] S32g247's Secure Boot using HSE firmware
        • S32g2 HSE key config
        • How S32g verify secure boot image
        • S32g secure boot signature generation
        • How to download and build S32g Secure boot image
        • [S32G] OTA with Secure Boot
    • RT117x_Documents
      • [RT-117x]IMX RT1170 Provisioning Guideline
      • [RT-117x] Going through the MX-RT1170 hard/soft platform
      • [RT-117x] i.MX-RT1170's Secure Boot
        • [RT-117x]Signing image with the HSM (SignServer)
    • LS104x_Documents
      • [LS104x] bsp project
      • [LS104x] boot flow
      • [LS104x] secure boot
      • [LS104x] Application Note, Using the PKCS#11 in TCU platform
      • [LS104x] 使用ostree更新rootfs
      • [LS104x] ostree的移植
      • [LS104x] Starting with Yocto
      • [LS104x] 使用FIT的kernel格式和initramfs
    • IMX6/8_Documents
      • [IMX6] Defining A U-Boot Command
      • NXP IMX6 嵌入式板子一些笔记
      • NXP-imx6 initialization
    • Vehicle_Apps
      • [SecOC] Tree
        • [SecOC] SecOC Freshness and MAC Truncation
  • 😾TECH
    • Rust Arm OS
      • ARMv7m_Using_The_RUST_Cross_Compiler
    • ARM
      • ARM-v7-M
        • 01_ARMv7-M_处理器架构技术综述
        • 02_ARMv7-M_编程模型与模式
        • 03_ARMv7-M_存储系统结构
        • 04_ARMv7-M_异常处理及中断处理
      • ARM-v8-A
        • 02_ARMv8_基本概念
        • 03_ARMv8_指令集介绍_加载指令集和存储指令集
        • 04_ARMv8_指令集_运算指令集
        • 05_ARMv8_指令集_跳转_比较与返回指令
        • 06_ARMv8_指令集_一些重要的指令
        • 0X_ARMv8_指令集_基于汇编的UART驱动
        • 07_ARMv8_汇编器Using as
        • 08_ARMv8_链接器和链接脚本
        • 09_ARMv8_内嵌汇编(内联汇编)Inline assembly
        • 10_ARMv8_异常处理(一) - 入口与返回、栈选择、异常向量表
        • 11_ARMv8_异常处理(二)- Legacy 中断处理
        • 12_ARMv8_异常处理(三)- GICv1/v2中断处理
        • 13_ARMv8_内存管理(一)-内存管理要素
        • 14_ARMv8_内存管理(二)-ARM的MMU设计
        • 15_ARMv8_内存管理(三)-MMU恒等映射及Linux实现
        • 16_ARMv8_高速缓存(一)cache要素
        • 17_ARMv8_高速缓存(二)ARM cache设计
        • 18_ARMv8_高速缓存(三)多核与一致性要素
        • 19_ARMv8_TLB管理(Translation Lookaside buffer)
        • 20_ARMv8_barrier(一)流水线和一致性模型
        • 21_ARMv8_barrier(二)内存屏障案例
      • ARM Boot Flow
        • 01_Embedded_ARMv7/v8 non-secure Boot Flow
        • 02_Embedded_ARMv8 ATF Secure Boot Flow (BL1/BL2/BL31)
        • 03_Embedded_ARMv8 BL33 Uboot Booting Flow
      • ARM Compiler
        • Compiler optimization and the volatile keyword
      • ARM Development
        • 在MACBOOK上搭建ARMv8架构的ARM开发环境
        • Starting with JLink debugger or QEMU
    • Linux
      • Kernel
        • 0x01_LinuxKernel_内核的启动(一)之启动前准备
        • 0x02_LinuxKernel_内核的启动(二)SMP多核处理器启动过程分析
        • 0x21_LinuxKernel_内核活动(一)之系统调用
        • 0x22_LinuxKernel_内核活动(二)中断体系结构(中断上文)
        • 0x23_LinuxKernel_内核活动(三)中断体系结构(中断下文)
        • 0x24_LinuxKernel_进程(一)进程的管理(生命周期、进程表示)
        • 0x25_LinuxKernel_进程(二)进程的调度器的实现
        • 0x26_LinuxKernel_设备驱动(一)综述与文件系统关联
        • 0x27_LinuxKernel_设备驱动(二)字符设备操作
        • 0x28_LinuxKernel_设备驱动(三)块设备操作
        • 0x29_LinuxKernel_设备驱动(四)资源与总线系统
        • 0x30_LinuxKernel_设备驱动(五)模块
        • 0x31_LinuxKernel_内存管理(一)物理页面、伙伴系统和slab分配器
        • 0x32_LinuxKernel_内存管理(二)虚拟内存管理、缺页与调试工具
        • 0x33_LinuxKernel_同步管理_原子操作_内存屏障_锁机制等
        • 01_LinuxDebug_调试理论和基础综述
      • Userspace
        • Linux-用户空间-多线程与同步
        • Linux进程之间的通信-管道(上)
        • Linux进程之间的通信-管道(下)
        • Linux进程之间的通信-信号量(System V)
        • Linux进程之间的通信-内存共享(System V)
        • Linux进程之间的通信-消息队列(System V)
        • Linux应用调试(一)方法、技巧和工具 - 综述
        • Linux应用调试(二)工具之coredump
        • Linux应用调试(三)工具之Valgrind
        • Linux机制之内存池
        • Linux机制之对象管理和引用计数(kobject/ktype/kset)
        • Linux机制copy_{to, from}_user
        • Linux设备树 - DTS语法、节点、设备树解析等
        • Linux System : Managing Linux Services - inittab & init.d
        • Linux System : Managing Linux Services - initramfs
      • Kernel Examples
        • Linux Driver - GPIO键盘驱动开发记录_OMAPL138
        • 基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(一)之miscdevice和ioctl
        • 基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(二)之cdev与read、write
        • 基于OMAPL138的字符驱动_GPIO驱动AD9833(三)之中断申请IRQ
        • Linux内核调用SPI驱动_实现OLED显示功能
        • Linux内核调用I2C驱动_驱动嵌套驱动方法MPU6050
    • OPTEE
      • 01_OPTEE-OS_基础之(一)功能综述、简要介绍
      • 02_OPTEE-OS_基础之(二)TrustZone和ATF功能综述、简要介绍
      • 03_OPTEE-OS_系统集成之(一)编译、实例、在QEMU上执行
      • 05_OPTEE-OS_系统集成之(三)ATF启动过程
      • 06_OPTEE-OS_系统集成之(四)OPTEE镜像启动过程
      • 07_OPTEE-OS_系统集成之(五)REE侧上层软件
      • 08_OPTEE-OS_系统集成之(六)TEE的驱动
      • 09_OPTEE-OS_内核之(一)ARM核安全态和非安全态的切换
      • 10_OPTEE-OS_内核之(二)对安全监控模式的调用的处理
      • 11_OPTEE-OS_内核之(三)中断与异常的处理
      • 12_OPTEE-OS_内核之(四)对TA请求的处理
      • 13_OPTEE-OS_内核之(五)内存和cache管理
      • 14_OPTEE-OS_内核之(六)线程管理与并发
      • 15_OPTEE-OS_内核之(七)系统调用及IPC机制
      • 16_OPTEE-OS_应用之(一)TA镜像的签名和加载
      • 17_OPTEE-OS_应用之(二)密码学算法和安全存储
      • 18_OPTEE-OS_应用之(三)可信应用的开发
      • 19_OPTEE-OS_应用之(四)安全驱动开发
      • 20_OPTEE-OS_应用之(五)终端密钥在线下发系统
    • Binary
      • 01_ELF文件_目标文件格式
      • 02_ELF文件结构_浅析内部文件结构
      • 03_ELF文件_静态链接
      • 04_ELF文件_加载进程虚拟地址空间
      • 05_ELF文件_动态链接
      • 06_Linux的动态共享库
      • 07_ELF文件_堆和栈调用惯例以ARMv8为例
      • 08_ELF文件_运行库(入口、库、多线程)
      • 09_ELF文件_基于ARMv7的Linux系统调用原理
      • 10_ELF文件_ARM的镜像文件(.bin/.hex/.s19)
    • Build
      • 01_Script_makefile_summary
    • Rust
      • 02_SYS_RUST_文件IO
    • Security
      • Crypto
        • 1.0_Security_计算机安全概述及安全需求
        • 2.0_Security_随机数(伪随机数)
        • 3.0_Security_对称密钥算法加解密
        • 3.1_Security_对称密钥算法之AES
        • 3.2_Security_对称密钥算法之MAC(CMAC/HMAC)
        • 3.3_Security_对称密钥算法之AEAD
        • 8.0_Security_pkcs7(CMS)_embedded
        • 9.0_Security_pkcs11(HSM)_embedded
      • Tools
        • Openssl EVP to implement RSA and SM2 en/dec sign/verify
        • 基于Mac Silicon M1 的OpenSSL 编译
        • How to compile mbedtls library on Linux/Mac/Windows
    • Embedded
      • eMMC启动介质
  • 😃Design
    • Secure Boot
      • JY Secure Boot Desgin
    • FOTA
      • [FOTA] Module of ECUs' FOTA unit design
        • [FOTA] Tech key point: OSTree Deployment
        • [FOTA] Tech key point: repositories role for onboard
        • [FOTA] Tech key point: metadata management
        • [FOTA] Tech key point: ECU verifying and Decrpting
        • [FOTA] Tech key point: time server
      • [FOTA] Local-OTA for Embedded Linux System
    • Provisioning
      • [X-Shield] Module of the Embedded Boards initialization
    • Report
由 GitBook 提供支持
在本页
  • 1. Overview
  • 2. API
  • 2.1 用户侧API(Cryptoki)
  • 2.2 中间层API (Secure Object Library)
  • 3. Secure Object集成
  • 3.1 Cryptoki
  • 3.2 OpenSSL
  • 4. Example OpenVPN
  • 4.1 启动 tee-supplicant
  • 4.2 在HSM中产生key
  • 4.3 配置OpenVPN
  • 附录:PKCS#11常用操作指南
  • 附录:PKCS#11常用操作指南
  1. ECUs
  2. LS104x_Documents

[LS104x] Application Note, Using the PKCS#11 in TCU platform

上一页[LS104x] secure boot下一页[LS104x] 使用ostree更新rootfs

最后更新于1年前

1. Overview

PKCS#11标准定义了与密码令牌(如硬件安全模块(HSM)和智能卡)的独立于平台的API,并将API本身命名为Cryptoki(来自“加密令牌接口”,发音为“crypto-key” - 但是“PKCS#11”通常用于指代API以及定义它的标准)。 API定义了最常用的加密对像类型(RSA密钥,X.509证书,DES / 三重DES密钥等)以及使用,创建/生成,修改和删除这些对象所需的所有功能。参考:

本文使用NXP LS1046A来对pkcs11进行验证。pkcs11对硬件有所要求,需要智能卡或者HSM。因此,本文会着重整理关于pkcs11如何和HSM进行配置的部分。NXP提供了Virual HSM,其底层使用OPTEE-OS进行实现;中间层使用Secure Object Library,在用户侧使用Cryptoki对其进行封装,用户只需要按照要求调用API即可。总结顺序为:OPTEE-OS-> Secure Object Library(SOL) -> Cryptoki APIs。另外,Secure Object Libray还可以被OpenSSL API作为engine使用。

SOL对HSM要求是:

  • 产生密钥对在HSM内部

  • 导入私钥进入HSM内部

私钥对于用户侧永远不可见。

OPTEE内部实现框图如图所示:

2. API

2.1 用户侧API(Cryptoki)

用户侧的API来源于Cryptoki,这些API的实际实现来源于libpkcs11.so。在NXP的Layerscape中支持的API的列表为:

API

Description

C_Initialize

Initialize Cryptoki library

C_Finalize

Clean up cryptoki related resources

C_GetFunctionList

Obtains entry points of Cryptoki library functions.

C_GetInfo

Obtains general information about Cryptoki

C_GetSlotInfo

Obtains information about a particular slot

C_GetTokenInfo

Obtains information about a particular token

C_GetSlotList

Obtain list of slots in the system.Only a fixed slot with fixed token is supported. Dynamic slot or token addition is not supported.

C_OpenSession/C_CloseSession/C_CloseAllSessions

Opens/Closes a session.* All types of sessions are supported with Token.* Only Token Objects can be created/destroyed, Session Objects are not supported.

C_Login/C_Logout

Logs into a token.Logs out from a token

C_CreateObject

Creates an object (RSA Keys of size up to 2048bits are supported)

C_DestroyObject

Destroys an object

C_FindObjectsInit/C_FindObjects/C_FindObjectsFinal

Objects search operations.RSA Public and Private key objects of size up to 2048bits are supported.ECDSA Public and Private key objects of size 256 & 384 bits are supported.

C_GetAttributeValue

Obtains the value of one or more attributes of the objects.

C_GetMechanismList

Obtains List of mechanism supported by token.

C_GetMechanismInfo

Obtains the information about a mechanism.

C_GenerateKeyPair

Generates a public-key/private-key pair (RSA Keys of size up to 2048bits are supported)

C_SignInit/C_Sign/C_SignUpdate/C_SignFinal

Initialize a signature operation.Signs single-part data.Continues a multiple-part signature operation.Finishes a multiple-part signature operation.Mechanisms supported:* RSA-based Mechanisms* CKM_RSA_PKCS* CKM_MD5_RSA_PKCS* CKM_SHA1_RSA_PKCS* CKM_SHA256_RSA_PKCS* CKM_SHA384_RSA_PKCS* CKM_SHA512_RSA_PKCS* ECDSA-based Mechanisms (Single Part Only)* CKM_ECDSA* CKM_ECDSA_SHA1

C_DigestInit/C_Digest/C_DigestUpdate/C_DigestFinal

Initializes a message-digesting operation.Digests single-part data.Continues a multiple-part digesting operation.Finishes a multiple-part digesting operation.Mechanisms supported:* CKM_MD5* CKM_SHA1* CKM_SHA256* CKM_SHA384* CKM_SHA512

C_DecryptInit/C_Decrypt

Initializes a decryption operation.Decrypts single-part encrypted data.Mechanisms supported:* CKM_RSA_PKCS* CKM_RSA_PKCS_OAEP

2.2 中间层API (Secure Object Library)

这里面规定了如何:

  • Import Keys

  • Generate Key.

  • Erase Object.

  • Manufacturing Key APIs:

    • Get MP Public key.

    • Sign using MP Private Key

    • Get MP Tag.

3. Secure Object集成

3.1 Cryptoki

Cryptoki可以分为两个访问方法

  • 命令行(p11tool, softhsm2-utils)

  • API调用

。如果是ubuntu系统可以通过sudo apt install gnutls-bin来安装p11tool

We have tested this library with p11tool for following operations:

  • Listing tokens: p11tool --list-tokens

  • Initializing token: p11tool --initialize

  • Initializing User pin: p11tool --initialize-pin

  • Initializing SO pin: p11tool --initialize-so-pin

  • Generating RSA Key: p11tool --generate-rsa

  • Importing RSA Key: p11tool --write --load-privkey <rsa_key.pem>

这里涉及了一些具体的签名和验签操作。

3.2 OpenSSL

OpenSSL通过SOL可以实现使用Engine进行加解密,进而可以调用到NXP的CAAM来对加密算法加速运算。有两种方法可以实现使用OpenSSL的API来访问Secure Objects:

  • 使用Secure Object Library 基于 OpenSSL Engine (libeng_secure_obj)

  • 使用PKCS#11基于OpenSSL引擎(第三方的OpenSC/libp11)

3.2.1 使用libeng_secure_obj (非PKCS#11)

如果engine基于SOL,是有限制的,只能是:

  1. RSA Private Encryption.

  2. RSA Private Decryption.

  3. ECDSA Signing Operation.

OpenSSL不能够通过调用接口产生RSA Keys。这个Key需要通过sobj_app预置到HSM中。OpenSSL只能使用HSM中的key。

3.2.1.1 配置openssl

如果使用命令行的openssl,我们需要对openssl进行配置,在openssl.cnf中 (often in /etc/ssl/openssl.cnf) 的最前面:

openssl_conf = conf_section

如果配置RSA相应的配置,Add following section at bottom of file:

[conf_section]
engines = engine_section
[engine_section]
secure_obj = sobj_section
[sobj_section]
engine_id = eng_secure_obj
dynamic_path = <path where lib_eng_secure_obj.so is placed>
default_algorithms = RSA
init = 1

如果配置ECC,配置:default_algorithms = RSA, EC

测试: To verify that the engine is properly operating, you can use the following example:

root@Ubuntu:~#
root@Ubuntu:~# openssl engine
(dynamic) Dynamic engine loading support
(eng_secure_obj) secure object OpenSSL Engine.
root@Ubuntu:~#
root@Ubuntu:~#

you do not update the OpenSSL configuration file, specify the engine configuration explicitly.

$: openssl engine -t dynamic -pre SO_PATH:<path-to-libeng_secure_obj.so> -pre ID:eng_secure_obj -pre LIST_ADD:1 -pre LOAD

root@Ubuntu:~#
root@Ubuntu:~# openssl engine -t dynamic -pre SO_PATH:/usr/lib/aarch64-linux-gnu/openssl-1.0.0/
engines/libeng_secure_obj.so -pre ID:eng_secure_obj -pre LIST_ADD:1 -pre LOAD
(dynamic) Dynamic engine loading support
[Success] : SO_PATH:/usr/lib/aarch64-linux-gnu/openssl-1.0.0/engines/libeng_secure_obj.SO
[Success] : ID:eng_secure_obj
[Success] : LIST_ADD:1
[Success] : LOAD
LOADED: (eng_secure_obj) Secure object OpenSSL Engine.
	[available]
root@Ubuntu:~#

3.2.1.2 使用openssl

RSA

Following commands can be used to generate RSA/ECDSA key-pair and use them in signing any data and verifying the signatures generated.

$: sobj_app -G -m rsa-pair -s 2048 -l "rsa_gen_2048" -i 1 -w rsa_2048.pem ## Generating RSA key-pair ##
$: openssl rsa -in rsa_2048.pem -pubout -out rsa_pub_2048.pem  ## Taking out Public Key for verifying signature ##
$: openssl dgst -sha1 -sign rsa_2048.pem -out sig.data data  ## Generating Signature "sig.data" of "data" ##
$: openssl dgst -sha1 -verify rsa_pub_2048.pem -signature sig.data data  ## Verifying the signature using Public Key ##

注意,这个地方并没有使用PKCS#11,只是普通的签名算法和验签算法。

ECDSA

Same thing can be done for ECDSA keys of prime256v1 by using following commands:

$: sobj_app -G -m ec-pair -c prime256v1 -l "ecc_256" -i 2 -w ec256.pem
$: openssl ec -in ec256.pem -pubout -out ec_pub_256.pem
$: openssl dgst -sha1 -sign ec256.pem -out sig.data data
$: openssl dgst -sha1 -verify ec_pub_256.pem -signature sig.data data

For ECDSA secp384r1 curve us following commands:

$: sobj_app -G -m ec-pair -c secp384r1 -l "ecc_384" -i 3 -w ec384.pem
$: openssl ec -in ec384.pem -pubout -out ec_pub_384.pem
$: openssl dgst -sha1 -sign ec384.pem -out sig.data data
$: openssl dgst -sha1 -verify ec_pub_384.pem -signature sig.data data

x.509

下面描述一下怎么创建一个self-sign的cert。这个key由HSM产生并且无法暴露出来。

As per the following examples, generate a private key in the HSM with sobj_app, This will also create a fake PEM file “dev_key.pem” having information to get the required key from HSM.

Following command is generating RSA key-pair:

$: sobj_app -G -m rsa-pair -s 2048 -l "Test_Key" -i 1 -w dev_key.pem

ECDSA key-pair can also be generated using following command:

$: sobj_app -G -m ec-pair -c prime256v1 -l "ecc_256" -i 30 -w dev_key.pem

产生一个cert用SOL:

// The first command creates a self-signed Certificate for “NXP Semiconductor". The signing is done using the key specified by the fake PEM file.
$ openssl req -new -key dev_key.pem -out req.pem -text -x509 -subj "/CN=NXP Semiconductor"


// creates a self-signed certificate for the request, the private key used to sign the certificate is the same private key used to create the request.
$ openssl x509 -signkey dev_key.pem -in req.pem -out cert.pem

3.2.2 使用OpenSC/libp11

  • 相比于PKCS#11的库更高一层的封装。他的设计主要意图是和使用OpenSSL的应用集成在一起;

  • OpenSSL库的pkcs11 engine插件

对于Ubuntu系统可以sudo apt-get install libengine-pkcs11-openssl。上面的命令可以安装libpkcs11.so (pkcs11 engine) 到/usr/lib/aarch64-linux-gnu/engines-1.1/libpkcs11.so。

同样需要更改openssl的配置文件:

openssl_conf = openssl_init

This should be added to the bottom of the file:

[openssl_init] 
engines=engine_section 

[engine_section] 
pkcs11 = pkcs11_section 

[pkcs11_section] 
engine_id = pkcs11 
dynamic_path = /usr/lib/aarch64-linux-gnu/engines-1.1/libpkcs11.so
MODULE_PATH = /usr/lib/libpkcs11.so
init = 0 		
  • dynamic_path:pkcs11 engine的插件

  • MODULE_PATH: NXP PKCS#11 library

  • engine_id: arbitrary identifier for OpenSSL applications to select the engine by the identifier.

如何测试

To verify that the engine is properly operating you can use the following example.

$ openssl engine pkcs11 -t 
(pkcs11) pkcs11 engine 
[ available ]

使用p11tool

下面的测试用例是使用命令行产生一个自签的cert,这个key产生一个token,并且key不能被导出。sudo apt-get install gnutls-bin

NXP提供的sobj_app也可以查看由p11tool产生的key:

  • NXP: /usr/lib/libpkcs11.so

  • OP engine: /usr/lib/aarch64-linux-gnu/engines-1.1/libpkcs11.so

The following commands utilize p11tool for that.

$ p11tool --provider <path-to-NXP-PKCS-library>/libpkcs11.so --list-privkeys

root@localhost:~# p11tool --provider /root/libpkcs11.so --list-privkeys
Object 0:
	URL: pkcs11:model=;manufacturer=NXP;serial=1;token=TEE_BASED_TOKEN;%01%00%00%00;object=Device_Key3;type=private
	Type: Private Key
	Label: Device Key3
	Flags: CKA_NEVER_EXTRACTABLE; CKA_SENSITIVE;
	ID: 01:00:00:00
Object 1:
	URL: pkcs11:model=;manufacturer=NXP;serial=1;token=TEE_BASED_TOKEN;%01%00%00%00;object=Device_Key2;type=private
	Type: Private Key
	Label: Device Key2
	Flags: CKA_NEVER_EXTRACTABLE; CKA_SENSITIVE;
	ID: 01:00:00:00

Object 0:
	URL: pkcs11:model=;manufacturer=NXP;serial=1;token=TEE_BASED_TOKEN;%01%00%00%00;object=Device_Key3;type=private
	Type: Private Key
	Label: Device Key
	Flags: CKA_NEVER_EXTRACTABLE; CKA_SENSITIVE;
	ID: 01:00:00:00
root@localhost:~#

产生一个在PKCS#11里面的证书:

$ openssl req -engine pkcs11 -new -key 
"pkcs11:model=;manufacturer=NXP;serial=1;token=TEE_BASED_TOKEN;id=%01%00%00%00;object=Device_Key3
;type=private" -keyform engine -out req.pem -text -x509 -subj "/CN=NXP Semiconductor"

4. Example OpenVPN

Here are the steps to use OpenVPN with PKCS#11 in Ubuntu:

  1. Install OpenVPN: Open a terminal window and run the following command to install OpenVPN: sudo apt-get install openvpn

  2. Install PKCS#11 library: Install the PKCS#11 library for your token. The library is usually provided by the manufacturer of the token. You can download the library from the manufacturer's website and install it on your system. For example, if you are using a YubiKey, you can download the YubiKey PKCS#11 library from the Yubico website.

  3. Configure OpenVPN: Create an OpenVPN configuration file and specify the PKCS#11 library path and the certificate and key for your PKCS#11 token. You can use the following sample configuration file as a starting point:

client
dev tun
proto udp
remote vpn.example.com 1194
resolv-retry infinite
nobind
persist-key
persist-tun
pkcs11-providers /usr/local/lib/libykcs11.so
pkcs11-id "pkcs11:object=YubiKey;type=private"
comp-lzo
verb 3

In this example, /usr/local/lib/libykcs11.so is the path to the YubiKey PKCS#11 library, and YubiKey is the name of the object that contains the private key in the token.

  1. Start OpenVPN: Open a terminal window and run the following command to start OpenVPN using the configuration file that you have created: sudo openvpn --config /path/to/config-file.ovpn

Replace /path/to/config-file.ovpn with the path to your OpenVPN configuration file.

That's it! OpenVPN will now use the PKCS#11 token for secure authentication and key management.

4.1 启动 tee-supplicant

由于NXP的layerscape是使用optee模拟的HSM,因此需要在用户侧启动tee服务程序:tee-supplicant &

运行xtest 测试OPTEE 是否可以正常运行。

4.2 在HSM中产生key

产生Key名字叫做com_rsa_2048:sobj_app -G -m rsa-pair -s 2048 -l "comrsa2048" -i 2

查看Key

root@localhost:/# p11tool --provider /usr/lib/libpkcs11.so --list-privkeys

4.3 配置OpenVPN

配置OpenVPN有两种方式:

  • 传统的证书方式

  • PKCS#11方式

OpenVPN开始SSL模式,有个互相challenge的过程。因此,必须提供ca.cert证书,作为client和server之间的互信。

4.3.1 传统的证书方式

客户端需要:

  • /opt/easy-rsa/pki/ca.crt (CA证书)

  • /opt/easy-rsa/pki/issued/client.crt (被CA签过的client公钥证书)

  • /opt/easy-rsa/pki/private/client.key (client端的RSA私钥)

这几个证书的生成过程如图所示:

CSR生成

实际上产生的命令如下:

openssl req -new -SHA256 -newkey rsa:2048 -nodes -keyout mlts.tech.key -out mlts.tech.csr -subj "/C=CN/ST=Guangdong/L=Shenzhen/O=multibeans/OU=ite dept/CN=mlts.tech"

这个命令会生输出:

  • mlts.tech.key (PEM格式的私钥)

  • mlts.tech.csr (发给CA服务器的CSR)

这里生成CSR必须要私钥信息,因为CSR需要签名信息,公钥信息也会被放置到CSR里面。

服务器CA返回CERT

服务器端(CA服务器)会对CSR文件进行校验,签署,这里模拟CA服务器的命令:

openssl x509 -req -days 365 -in mlts.tech.csr -signkey server.key -out client.crt

服务器需要用自己的server.key对csr进行签名和转换,输出client.crt,然后把client.crt转给client端。有的CA可能为了防攻击还需要申请者提供CA.cert以确保自身的身份需要验证。

curl <https://xxx.xxxx.com/cert/sign> \\  
 --request POST \\  
 --cert scripts/CA_Client.crt \\  
--key scripts/CA_Client.key \\  
--cacert <> \\  
--header 'Content-Type: application/json' \\  
--data-raw '{"csr":"'"$str"'"}'

以上是一个CSR请求证书的示例,通过HTTPS做CERT。

4.3.2 PKCS#11

要配置 OpenVPN 客户端使用 PKCS#11 进行身份验证,您需要执行以下步骤:

安装 PKCS#11 库:首先,需要为硬件令牌安装适当的 PKCS#11 库。您可以查看令牌制造商提供的文档以确定要使用哪个库以及如何将其安装到您的系统上。NXP的令牌就在/usr/lib/libpkcs11.so中。

配置 OpenVPN 以使用 PKCS#11:接下来,需要配置 OpenVPN 以使用 PKCS#11 进行身份验证。这涉及修改 OpenVPN 配置文件以包含适当的 PKCS#11 指令。这是一个示例配置:

client
dev tun
proto udp
remote sz.vehicle.vpn.autox.tech 443
pkcs11-providers /usr/lib/libpkcs11.so
pkcs11-id 'doge'
<cert>
-----BEGIN CERTIFICATE-----
MIIDyTCCArGgAwIBAgIUHStvPgFiRK35CwMtbMeXnwqJquswDQYJKoZIhvcNAQEL
BQAwWTEUMBIGA1UEAwwLd2ViU2VydmVyQ0ExETAPBgNVBAsMCFNlY3VyaXR5MQ4w
DAYDVQQKDAVBdXRvWDERMA8GA1UEBwwIU2hlbnpoZW4xCzAJBgNVBAYTAkNOMB4X
DTIzMDQxMDA2MDMwNloXDTI1MDQwOTA2MDMwNVowajELMAkGA1UEBhMCQ04xEjAQ
BgNVBAgMCUd1YW5nZG9uZzERMA8GA1UEBwwIU2hlbnpoZW4xDjAMBgNVBAoMBUFV
VE9YMREwDwYDVQQLDAhzZWN1cml0eTERMA8GA1UEAwwIYXV0b3guYWkwggEiMA0G
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDM/FbyJ804T9WkI+opYq4TrbgvcM09
aDRepkU6QBJlDdcAOl1i1rMki7p5eg429fgvYEgvuw2zDE7YPDdOxxH6Z18RSWyU
9S5HHi8K+P3LzeeFtiC0CyokAsfUsj8VhUrNFKhuZTl0oH9guHi+rTPzE9uq8UPp
WND86+rhL3/OrQvsf84omc3nXunAb93YmaLYJ+J0LpemBHwxUXd/7RvJcaybWC1R
jv1QVd4bYIaIOWqr2i9qIccIHeSxmnKg9Uhjm+TuOo86ztQB7mpVXIAmESgcEH/9
Ae6g3JN28Gy2kJZHQhcWjMtOprkTgthfW67mxsNn7wuA+6dmuDeLGglxAgMBAAGj
eDB2MAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUW3et23Gz9/uPZILFkKlujCQm
CZ8wFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYEFHSTjanaUUEFicn1
HOegxJ8S0GicMA4GA1UdDwEB/wQEAwIF4DANBgkqhkiG9w0BAQsFAAOCAQEAdgH7
LJVxAdurr9wzsC5VLuI3uebm+M7OC/C3ncbvgQmL/gaT0s0mL2wWik73nGNIMYgq
nD8KF2OLp86tnXlm40z1M1aLtE7/CkGDuLuVHwsHAdjLc3iMwGgqS+FPOpo1fea+
FW7/ddK/16TUcaRNeHhjwWwo9SaL/Wmea8c4dGF5lIcrkOAo5EdHI2i13OH1ptI2
p7NbjHI/so4jUxyEBIS3R7dQ4n1K6IlToyP/YK1LZ9010skiJl3konzKd7c0dTju
VtUNutzM7NANvJVkOH9ncYU6INp28KOYXf3OmewcfmKAX9u4Wqjd+7qJ1f5KMBTd
oUdFdaa3Hp3ipWwKxA==
-----END CERTIFICATE-----
</cert>

4.3.2.1 remote

需要在host里面添加:120.78.72.155 sz.vehicle.vpn.autox.tech。这个就是remote地址。

4.3.2.2 pkcs11-providers

这个就是PKCS#11的库,NXP的Layerscape的目录是在:/usr/lib/libpkcs11.so

4.3.2.3 pkcs11-id

PKCS#11驱动目前不支持生成密钥的功能。一个密钥对可以通过sobj_app生成。with the identifier of the object containing the private key and certificate on the hardware token.

sobj_app -G -m rsa-pair -s 2048 -l "rsa_gen_2048" -i 1 -w rsa_2048.pem

通过命令来查看:

pkcs11-tool --module /usr/lib/libpkcs11.so --list-objects

4.3.2.4 pkcs11-pin

存在HSM内部的私钥的password,如果有的话需要指定。with the PIN needed to access the token.

4.3.2.5 cert

OpenVPN配置文件中的<cert>标记指的是将用于身份验证的客户端证书。这通常是由OpenVPN服务器配置为信任的CA(证书颁发机构)签署的用户特定证书。当使用PKCS#11进行身份验证时,客户端证书和私钥存储在硬件令牌上,PKCS#11库提供对它们的访问。在OpenVPN配置中,可以在<cert>标签之间包含证书数据,也可以指定包含证书数据的文件的路径。

生成RSA key在HSM中

按照步骤我们先生成一个RSA 2048的key放入HSM,名字就是doge

sobj_app -G -m rsa-pair -s 2048 -l "doge" -i 1 -w doge_fake.pem

同时也生成一个doge_fake.pem文件,该文件并不是真正的私钥,

读出对应的RSA 2048的公钥:

pkcs11-tool --module /usr/lib/libpkcs11.so --read-object --type pubkey --label doge -o doge_public.key

使用openssl接入engine产生CSR

配置openssl

openssl需要配置,在/etc/ssl/openssl.cnf中在文件头部添加:

openssl_conf = openssl_init

[openssl_init]
engines=engine_section

[engine_section]
pkcs11 = pkcs11_section

[pkcs11_section]
engine_id = pkcs11
dynamic_path = /usr/lib/aarch64-linux-gnu/engines-1.1/libpkcs11.so
MODULE_PATH = /usr/lib/libpkcs11.so
init = 0

在环境变量中使能配置文件路径:export OPENSSL_CONF=/etc/ssl/openssl.cnf

检测之后,代表pkcs11的engine已经在openssl启动:

使用openssl生成CSR

接下来使用openssl生成CSR:

token的名字通过pkcs11-tool --module /usr/lib/libpkcs11.so --list-token查找,object的名字通过pkcs11-tool --module /usr/lib/libpkcs11.so --list-objects查找。

openssl req -engine pkcs11 -keyform engine -key "pkcs11:token=TEE_BASED_TOKEN;object=doge" -new -out doge.csr

接下来就开始输入CSR的一些信息:

生成了doge.csr

向CA请求csr签名获取证书

根据公司的业务不同,CSR的请求接口形式上可能有差异,但最终公司CA进行核查后,CA 会根据 CSR 中的信息创建服务器证书,使用私钥对其进行签名,然后将证书发送给自己。CA 还会向您发送一个根 CA 证书和一个中间 CA 证书(如果适用)。所以一个CSR可以获取:

  • 根CA证书 (从CA网站获取)

  • 中间CA证书(如果有的话)

  • Client证书

本公司的API使用的https的接口,因此需要为https指定HTTPS的cert、key、ca_cert。

本公司的API使用的https的接口,因此需要为https指定HTTPS的cert、key、ca_cert。bash脚本如下:

# !/bin/bash

echo "[INFO] sync time"
# ntpdate cn.pool.ntp.org && hwclock --systohc

OUT_CERT_NAME=doge_client.cert

readonly CA_CERT_URL="https://dev.ca.autox.tech/ejbca/publicweb/webdist/certdist?cmd=cachain&caid=-238079556&format=pem"
readonly CERT=/root/.client_certs/sign_server.crt
readonly KEY=/root/.client_certs/sign_server.key

# get CA cert
echo "[INFO] Get CA root certificate from HTTPS"
CA_FILE="$(mktemp /tmp/tmp.autox-ca-XXXXXX.crt)"
JSON_FILE="$(mktemp /tmp/tmp.sec-gateway-XXXXXX.json)"
curl -sk "$CA_CERT_URL" -o "$CA_FILE"
if [ $? -eq 0 ]; then
    echo "[INFO] get root certificate done!"
else
    echo "[ERR] failed on curl -sk "$CA_CERT_URL" -o "$CA_FILE""
    exit -1
fi

# pass the CSR text
echo "[INFO] POST the CSR via HTTPS"
CSR=`cat doge.csr`
CSR_JSON=`echo "{}" | jq --arg csr "${CSR}" '{"csr": $csr}'`
echo ${CSR_JSON}

echo "request CA sign"
curl https://dev.xsec-gateway.autox.tech/v1/web/server/cert/sign \
        --request POST                                           \
        --cert ${CERT}                                           \
        --key ${KEY}                                             \
        --cacert ${CA_FILE}                                      \
        --header "Content-Type: application/json"                \
        --data-raw "${CSR_JSON}"                                 \
        --output temp.json
if [ $? -eq 0 ]; then
    echo ""
    echo "[INFO] curl client certificate done!"
else
    echo ""
    echo "[ERR] failed on curl client certificate!"
    exit -1
fi

jq ".cert" temp.json | sed -e 's/\\n/\n/g' -e 's/\"//g' > ${OUT_CERT_NAME}
if [ $? -eq 0 ]; then
    echo ""
    echo "[INFO] transform the cert to pem done| out is ${OUT_CERT_NAME}!"
else
    echo ""
    echo "[ERR] failed on transform the cert to pem!"
    exit -1
fi

cat ${OUT_CERT_NAME}

trap 'rm -fr "$JSON_FILE" "$CA_FILE"' EXIT
rm -rf temp.json
echo "[INFO] Done!"

写入CERT到HSM/Token中

如果我们通过配置文件指定client.cert文件,openVPN会报错,当开启--pkcs11-provider的时候,cert不能够被指定。

但是Layerscape无法将CERT写入到HSM中(通用的PKCS# Tool)是有这个接口的,但是NXP的Virtual HSM有这个限制。

证据1 : 在NXP的技术文档中已经表明,只能导入HSM是Private Key和Public Key。

证据2: 查看NXP的这部分源程序的实现,do_CreateObject只支持SKK_RSA和SKK_EC两种类型的object的分支处理。

结论,OpenVPN的PKCS#11需要将Cert写入到HSM中,而Layerscape的virtualHSM没有暴露写入Cert的接口,因此无法使用基于PKCS#11的OpenVPN。

解决方案:

方案二:我们延续NXP的程序,自己开发基于Virtual HSM的cert写入功能。工足量:

  • 工具层(Linux Userspace):pkcs11_app

  • 中间层(secure_obj):增加--write-object --type cert的逻辑和cert读取的逻辑,以及RSA私钥和cert关联的逻辑。

  • 内核层(optee-client):

    • 开发对应的CA,增加--write-object --type cert的逻辑和cert读取访问的逻辑

    • 开发对应的TA,增加--write-object --type cert的逻辑和证书内存管理的逻辑和cert读取访问的逻辑

附录:PKCS#11常用操作指南

显示关于cryptoki版本的信息,以及PKCS#11驱动[1]。

root@localhost:~# pkcs11-tool --module /usr/lib/libpkcs11.so --show-info

关于可用插槽的信息。列出的插槽取决于p11nethsm.conf配置文件中的插槽阵列的配置。

root@localhost:~# pkcs11-tool --module /usr/lib/libpkcs11.so --list-slots

生成密钥,产生一个密钥对并将其存储在VirtualHSM上。

PKCS#11驱动目前不支持这个功能。一个密钥对可以通过nitropy 或REST API请求生成。要了解更多关于如何生成密钥的信息,请参考生成密钥<../operation.html#generate-key>_ 章。

显示NetHSM上Key Store 中的密钥和证书的信息。

root@localhost:~# pkcs11-tool --module /usr/lib/libpkcs11.so --list-objects

从NetHSM上的Key Store 读取密钥和证书。不可能从NetHSM上读取私钥。

一个密钥对的公钥可以读作如下。

$ pkcs11-tool --module /usr/lib/libpkcs11.so --read-object --type pubkey --label comrsa2048 -o comrsa2048_public.key

一个密钥对的证书可以读作以下内容。

$ pkcs11-tool --module /usr/lib/libpkcs11.so --read-object --type cert --label comrsa2048 -o comrsa2048_public.cert

返回的证书或公钥是ASN.1编码的。这些数据可以用dumpasn1 工具进行解码,因为它包含DER格式的数据。DER格式可以用OpenSSL转换为PEM格式。

将密钥和证书写入NetHSM上的Key Store 。

钥匙对的私钥可以写成如下形:

$ pkcs11-tool --module /usr/lib/libpkcs11.so --write-object secret.key --type privkey --label

一个密钥对的公钥可以写成如下。

$ pkcs11-tool --module p11nethsm.so --write-object public.key --type pubkey --label myFirstKey

一个密钥对的证书可以写成以下样子。

$ pkcs11-tool --module p11nethsm.so --write-object cert.pub --type cert --label myFirstKey

NetHSM可以为存储在NetHSM的Key Store中的私钥签署数据。对于使用RSA和ECDSA密钥的签名,必须先计算出摘要。

要计算一个摘要,首先需要数据。一个信息的创建方法如下。

附录:PKCS#11常用操作指南

显示关于cryptoki版本的信息,以及PKCS#11驱动[1]。

root@localhost:~# pkcs11-tool --module /usr/lib/libpkcs11.so --show-info

关于可用插槽的信息。列出的插槽取决于p11nethsm.conf配置文件中的插槽阵列的配置。

root@localhost:~# pkcs11-tool --module /usr/lib/libpkcs11.so --list-slots

生成密钥,产生一个密钥对并将其存储在VirtualHSM上。

PKCS#11驱动目前不支持这个功能。一个密钥对可以通过nitropy 或REST API请求生成。要了解更多关于如何生成密钥的信息,请参考生成密钥<../operation.html#generate-key>_ 章。

显示NetHSM上Key Store 中的密钥和证书的信息。

root@localhost:~# pkcs11-tool --module /usr/lib/libpkcs11.so --list-objects

从NetHSM上的Key Store 读取密钥和证书。不可能从NetHSM上读取私钥。

一个密钥对的公钥可以读作如下。

$ pkcs11-tool --module /usr/lib/libpkcs11.so --read-object --type pubkey --label comrsa2048 -o comrsa2048_public.key

一个密钥对的证书可以读作以下内容。

$ pkcs11-tool --module /usr/lib/libpkcs11.so --read-object --type cert --label comrsa2048 -o comrsa2048_public.cert

返回的证书或公钥是ASN.1编码的。这些数据可以用dumpasn1 工具进行解码,因为它包含DER格式的数据。DER格式可以用OpenSSL转换为PEM格式。

将密钥和证书写入NetHSM上的Key Store 。

钥匙对的私钥可以写成如下形:

$ pkcs11-tool --module /usr/lib/libpkcs11.so --write-object secret.key --type privkey --label

一个密钥对的公钥可以写成如下。

$ pkcs11-tool --module p11nethsm.so --write-object public.key --type pubkey --label myFirstKey

一个密钥对的证书可以写成以下样子。

$ pkcs11-tool --module p11nethsm.so --write-object cert.pub --type cert --label myFirstKey

NetHSM可以为存储在NetHSM的Key Store中的私钥签署数据。对于使用RSA和ECDSA密钥的签名,必须先计算出摘要。

要计算一个摘要,首先需要数据。一个信息的创建方法如下。

$ echo 'NetHSM rulez!' | pkcs11-tool --module p11nethsm.so \
   --sign \
   --mechanism SHA512-RSA-PKCS-PSS \
   --output-file sig.data \
   --label myFirstKey

创建的签名可以用OpenSSL进行验证,方法如下。

$ echo 'NetHSM rulez!' | openssl dgst -keyform PEM \
   -verify public.pem \
   -sha512 \
   -sigopt rsa_padding_mode:pss \
   -sigopt rsa_pss_saltlen:-1 \
   -signature sig.data

中间层的API,请参考:

用户甚至可以直接使用Secure Object Library来操作HSM/Token。NXP提供了sobj_app用来直接访问Secure Object Library:

命令行的p11tool比较常用,该命令行参数在

NXP把p11tool又包装了一层pkcs11_app工具,可以参考:

libp11对PKCS#11 API进行了比较薄的封装,参考。这个仓库提供了:

注意,,一个是NXP的,一个是openssl engine用的:

OpenVPN

ca.crt是需要手动拷贝的,需要从ca.crt的服务器上获取,csr的生成需要:

OpenVPN 中通过修改配置来接入 PKCS#11 认证,分别为 pkcs11-providers 、pkcs11-id 属性赋值。 为HSM提供的 PKCS#11 共享库,pkcs11-id 值在使用过程 中通过调用命令openvpn show-pkcs11-help libhpkcs11.so来动态读取。

OpenVPN在文档中规定,要求clientcert必须写入到HSM中才可以使用(CA cert不需要),参考:

文档地址:

证据3: 在网络上也有人使用LS1088A来做OpenVPN的PKCS#11的方案,但是使用USB外置的产品,而没有使用LS1088A的VirtualHSM。参考:

方案一:相关问题已经提交给NXP官方,地址:,等待NXP的AE进行解答。

方案三:使用外置的HSM,参考:

🧔
https://docs.nxp.com/bundle/GUID-1441E561-3EAD-47FD-A50D-72E1A4E4D69E/page/GUID-81BC632C-6F59-49B1-8573-419306674DD3.html
https://docs.nxp.com/bundle/GUID-1441E561-3EAD-47FD-A50D-72E1A4E4D69E/page/GUID-94DA27FA-ADB5-432E-87A4-0AA3B0BB99B1.html#GUID-94DA27FA-ADB5-432E-87A4-0AA3B0BB99B1
https://www.gnutls.org/manual/html_node/p11tool-Invocation.html
https://docs.nxp.com/bundle/GUID-1441E561-3EAD-47FD-A50D-72E1A4E4D69E/page/GUID-E9CE3DC0-9C77-45C4-BE72-0E86FC5233ED.html#GUID-E9CE3DC0-9C77-45C4-BE72-0E86FC5233ED__UL_DDX_JML_XCB
https://github.com/OpenSC/libp11
有两个libpkcs11.so
https://openvpn.net/vpn-server-resources/support-of-pkcs11-physical-tokens-for-openvpn-connect/
https://myssl.com/csr_create.html
libhpkcs11.so
.
https://openvpn.net/community-resources/how-to/#what-is-pkcs11
https://docs.nxp.com/bundle/GUID-487B2E69-BB19-42CB-AC38-7EF18C0FE3AE/page/GUID-E9CE3DC0-9C77-45C4-BE72-0E86FC5233ED.html
Nitrokey HSM 2
https://support.pervices.com/application-notes/pvan-7/
https://community.nxp.com/t5/Layerscape/LS1046a-Populate-x-509-client-cert-into-the-Virtual-HSM-about/m-p/1630896#M12221
https://support.pervices.com/application-notes/pvan-7/
http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/os/pkcs11-base-v2.40-os.html