CloudHSM Java PKCS#11 - ECC 密钥生成与自签名 CA 证书签发
本项目演示通过 Java SunPKCS11 Provider 调用 AWS CloudHSM 的 PKCS#11 接口,在HSM 内生成 ECC P-256 密钥对并签发自签名 Root CA 证书。使用底层 PKCS#11API(CGenerateKeyPair)生成密钥以支持设置 CKALABEL,再通过 P11Key 包装为 JCA 对象,结合 BouncyCastle 完成证书签名(签名运算在 HSM 内执行)。私钥始终保存在 HSM 中不可导出,公钥和证书以 PEM 格式导出到本地。
一、背景
AWS CloudHSM 提供了多种 SDK 接口供应用程序调用,包括 JCE Provider、PKCS#11、OpenSSL Dynamic Engine 等。本项目使用 PKCS#11 接口,通过 Java 标准的 SunPKCS11 Provider 加载 CloudHSM 的 PKCS#11 .so 库,实现 ECC P-256 密钥对生成和自签名 CA 证书签发。
与 JCE Provider 方案不同,PKCS#11 方案不依赖 CloudHSM JCE Provider SDK(cloudhsm-jce),而是使用 JDK 内置的 sun.security.pkcs11.SunPKCS11 Provider 直接对接 CloudHSM 的 PKCS#11 共享库(libcloudhsm_pkcs11.so)。这种方式遵循 PKCS#11 标准规范,具有更好的跨 HSM 厂商可移植性。
本项目实现的功能与 cloudhsm-openssl-dynamic-engine 仓库中 java-ecc-demo 目录下的 ECCKeyGenAndExport.java 和 SelfSignedCertGenerator.java 等效,但底层调用方式从 CloudHSM JCE Provider 替换为标准 PKCS#11 接口,而且将原先两个Java文件分两步处理合并为一个Java文件直接处理。
二、实现原理
2.1 架构对比
| 层级 | JCE Provider 方案 | PKCS#11 方案(本项目) |
|---|---|---|
| Java 应用层 | 调用 CloudHsmProvider |
调用 SunPKCS11 Provider |
| SDK 层 | cloudhsm-jce-5.x.jar |
libcloudhsm_pkcs11.so |
| 传输层 | CloudHSM SDK 5 内部通信 | CloudHSM SDK 5 内部通信 |
| HSM 硬件 | CloudHSM | CloudHSM |
2.2 程序执行流程
程序共三个步骤,密钥生成和签名在 HSM 内完成,证书和公钥导出到本地文件:
步骤1: C_GenerateKeyPair(底层 PKCS#11 API)
→ 在 HSM 内生成 ECC P-256 密钥对
→ 生成时直接设置 CKA_LABEL(私钥和公钥使用不同 label)
步骤2: P11Key 包装 handle → 高层 JCA API 生成自签名 Root CA 证书
→ 签名操作通过 PKCS11ContentSigner 转发到 HSM 内执行
步骤3: 导出公钥 PEM 和证书 PEM 到本地文件
2.3 为什么使用底层 PKCS#11 API
SunPKCS11 的高层 KeyPairGenerator API 不支持在生成密钥时设置 CKA_LABEL(配置文件的 attributes 段仅支持布尔/整数类型属性)。同时 CloudHSM 不支持 C_SetAttributeValue(生成后修改属性)。因此必须使用底层 PKCS11 wrapper API 直接调用 C_GenerateKeyPair,在创建时就传入 CKA_LABEL。
2.4 关键技术点
-
SunPKCS11 Provider 加载:通过
cloudhsm-pkcs11.cfg配置文件指定 CloudHSM PKCS#11 库路径(/opt/cloudhsm/lib/libcloudhsm_pkcs11.so),Java 的SunPKCS11Provider 在运行时动态加载该.so库。 -
HSM 认证:CloudHSM PKCS#11 SDK 5 的认证格式为
<CU用户名>:<密码>,通过KeyStore.load(null, pin)触发 PKCS#11 的C_Login函数完成 HSM 登录。 -
底层 API 密钥生成:通过反射获取
sun.security.pkcs11.wrapper.PKCS11实例,直接调用C_GenerateKeyPair,在模板中传入CKA_LABEL、CKA_TOKEN=true等属性。私钥和公钥使用不同的 label 以便在 CloudHSM CLI 中区分。 -
P11Key 包装:通过反射调用
P11Key.publicKey()和P11Key.privateKey()工厂方法,将底层 handle 包装为标准 JCAPublicKey/PrivateKey对象,后续签名等操作使用高层 JCA API。 -
证书签名:自定义
PKCS11ContentSigner实现 BouncyCastle 的ContentSigner接口,将签名操作通过Signature.getInstance(algorithm, provider)转发到 PKCS#11 Provider,确保签名运算在 HSM 内完成。 -
重复检查:运行前通过
C_FindObjects检查 HSM 中是否已存在同 label 的私钥,避免重复生成。
2.5 文件说明
Java示例代码:https://github.com/aobao32/cloudhsm-java-pkcs11
| 文件 | 说明 |
|---|---|
cloudhsm-pkcs11.cfg |
SunPKCS11 Provider 配置文件,指定 PKCS#11 库路径 |
PKCS11CertGenerator.java |
一次性完成密钥生成、证书签发、label 设置、文件导出 |
三、环境准备
以下步骤假设 CloudHSM 集群已初始化完毕并已激活,且已创建 CU(Crypto User)用户。
3.1 安装 CloudHSM PKCS#11 库(SDK 5)
在 Ubuntu 24.04 上安装:
wget wget https://s3.amazonaws.com/cloudhsmv2-software/CloudHsmClient/Noble/cloudhsm-pkcs11_latest_u24.04_amd64.deb
sudo apt install ./cloudhsm-pkcs11_latest_u24.04_amd64.deb
在 Ubuntu 22.04 上安装:
wget https://s3.amazonaws.com/cloudhsmv2-software/CloudHsmClient/Jammy/cloudhsm-pkcs11_latest_u22.04_amd64.deb
sudo apt install ./cloudhsm-pkcs11_latest_u22.04_amd64.deb
安装完成后,PKCS#11 库位于 /opt/cloudhsm/lib/libcloudhsm_pkcs11.so。
3.2 配置 CloudHSM SDK 5 连接
使用 configure-pkcs11 工具配置集群连接信息,这里要替换 <HSM_IP> 为加密机的IP地址:
sudo /opt/cloudhsm/bin/configure-pkcs11 --hsm-ca-cert /opt/cloudhsm/etc/customerCA.crt
sudo /opt/cloudhsm/bin/configure-pkcs11 -a <HSM_IP>
如果是单节点集群,还需要关闭密钥可用性检查:
sudo /opt/cloudhsm/bin/configure-pkcs11 --disable-key-availability-check
3.3 安装 Java 和 Maven
# 安装 Amazon Corretto 8
sudo apt install -y java-1.8.0-amazon-corretto-jdk
# 安装 Maven
sudo apt install -y maven
3.4 设置环境变量
注:本文已经完成CloudHSM的初始化,且已经有创建好密钥使用者user01用户。
export HSM_USER=<CU用户名>
export HSM_PASSWORD=<CU密码>
四、编译 Java 代码并运行
4.1 编译
Java示例代码:https://github.com/aobao32/cloudhsm-java-pkcs11
git clone git@github.com:aobao32/cloudhsm-java-pkcs11.git
cd cloudhsm-java-pkcs11
mvn clean package
编译完成后在 target/ 目录下生成可执行 jar 文件:
pkcs11-cert-generator.jar— ECC 密钥生成 + 自签名 CA 证书签发
4.2 运行
注:本文已经完成CloudHSM的初始化,且已经有创建好密钥使用者user01用户。
java -jar target/pkcs11-cert-generator.jar
执行成功后输出:
已加载 PKCS#11 Provider: SunPKCS11-CloudHSM
已登录 CloudHSM,用户: user01
--- 步骤1:在 HSM 内生成 ECC P-256 密钥对 ---
[HSM] 私钥已生成,label: pkcs11_ec_key_private
[HSM] 公钥已生成,label: pkcs11_ec_key_public
--- 步骤2:生成自签名 Root CA 证书(签名在 HSM 内完成)---
Root CA 证书生成并验证成功
--- 步骤3:导出本地文件 ---
[本地] 公钥 PEM 已导出: pkcs11_ec_pub.pem
[本地] 证书 PEM 已导出: pkcs11_ec_server.crt
✅ 全部完成!摘要如下:
┌─ HSM 内对象(私钥不可导出)────────────────────────────┐
│ 私钥 label: pkcs11_ec_key_private
│ 公钥 label: pkcs11_ec_key_public
└────────────────────────────────────────────────────────┘
┌─ 本地导出文件 ──────────────────────────────────────────┐
│ 公钥 PEM: pkcs11_ec_pub.pem
│ 证书 PEM: pkcs11_ec_server.crt
└────────────────────────────────────────────────────────┘
Subject: EMAILADDRESS=dev_admin@bitipcman.com, CN=dev.bitipcman.com, OU=DEV, O=BITIPCMAN, L=BEIJING, ST=BJ, C=CN
有效期: Thu Apr 16 13:51:27 UTC 2026 ~ Fri Apr 16 13:51:27 UTC 2027
签名算法: SHA256withECDSA
生成的文件:
pkcs11_ec_pub.pem— ECC 公钥 PEM 文件pkcs11_ec_server.crt— 自签名 CA 证书
4.3 验证证书
使用 OpenSSL 查看证书内容:
openssl x509 -in pkcs11_ec_server.crt -text -noout
返回信息如下:
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1776347487545 (0x19d968f9d39)
Signature Algorithm: ecdsa-with-SHA256
Issuer: C = CN, ST = BJ, L = BEIJING, O = BITIPCMAN, OU = DEV, CN = dev.bitipcman.com, emailAddress = dev_admin@bitipcman.com
Validity
Not Before: Apr 16 13:51:27 2026 GMT
Not After : Apr 16 13:51:27 2027 GMT
Subject: C = CN, ST = BJ, L = BEIJING, O = BITIPCMAN, OU = DEV, CN = dev.bitipcman.com, emailAddress = dev_admin@bitipcman.com
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:1b:1c:93:62:58:34:c5:ed:67:3a:99:e2:6a:09:
48:98:a0:64:8a:88:c2:2f:6e:4c:52:60:aa:62:1d:
ae:a0:01:6a:2a:2e:9f:24:e3:d3:c4:69:6c:14:22:
84:5d:8b:59:eb:3f:5f:8e:65:6b:70:92:fd:7a:ba:
a9:f4:ee:88:88
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Key Usage: critical
Digital Signature, Certificate Sign, CRL Sign
Signature Algorithm: ecdsa-with-SHA256
Signature Value:
30:44:02:20:3f:4a:13:89:9a:99:b6:95:18:19:b2:6a:c9:6a:
e5:6c:75:57:f0:cf:e8:ff:01:4d:ad:55:31:21:f5:bd:ae:98:
02:20:28:65:28:99:2f:da:70:26:b9:da:a3:e4:05:87:c7:d8:
70:83:df:a6:66:57:9e:e4:06:40:b6:d4:b7:6f:db:43
4.4 在 CloudHSM CLI 中确认密钥 label
使用CloudHSM CLI登陆到CloudHSM:
/opt/cloudhsm/bin/cloudhsm-cli interactive
以普通加密用户身份登陆(本例为user01):
login --username user01 --role crypto-user
输入命令key list,即可看到返回结果。密钥带有不同的 label,可区分私钥(pkcs11_ec_key_private)和公钥(pkcs11_ec_key_public)。
{
"error_code": 0,
"data": {
"matched_keys": [
{
"key-reference": "0x0000000000001251",
"attributes": {
"label": "pkcs11_ec_key_private"
}
},
{
"key-reference": "0x0000000000001567",
"attributes": {
"label": "pkcs11_ec_key_public"
}
}
],
"total_key_count": 2,
"returned_key_count": 2
}
}
五、参考文档
- Oracle JDK 8 PKCS#11 Reference Guide — 本项目遵循 Appendix B 描述的 KeyStore 标准流程(CKA_ID 关联私钥和证书)
- 安装 CloudHSM PKCS#11 库(SDK 5)
- CloudHSM PKCS#11 库属性表(SDK 5)
- PKCS#11 库认证方式
- PKCS#11 库代码示例
- BouncyCastle 官方文档
- JCE Provider 方案参考实现(java-ecc-demo)
最后修改于 2026-04-16