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.javaSelfSignedCertGenerator.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 关键技术点

  1. SunPKCS11 Provider 加载:通过 cloudhsm-pkcs11.cfg 配置文件指定 CloudHSM PKCS#11 库路径(/opt/cloudhsm/lib/libcloudhsm_pkcs11.so),Java 的 SunPKCS11 Provider 在运行时动态加载该 .so 库。

  2. HSM 认证:CloudHSM PKCS#11 SDK 5 的认证格式为 <CU用户名>:<密码>,通过 KeyStore.load(null, pin) 触发 PKCS#11 的 C_Login 函数完成 HSM 登录。

  3. 底层 API 密钥生成:通过反射获取 sun.security.pkcs11.wrapper.PKCS11 实例,直接调用 C_GenerateKeyPair,在模板中传入 CKA_LABELCKA_TOKEN=true 等属性。私钥和公钥使用不同的 label 以便在 CloudHSM CLI 中区分。

  4. P11Key 包装:通过反射调用 P11Key.publicKey()P11Key.privateKey() 工厂方法,将底层 handle 包装为标准 JCA PublicKey/PrivateKey 对象,后续签名等操作使用高层 JCA API。

  5. 证书签名:自定义 PKCS11ContentSigner 实现 BouncyCastle 的 ContentSigner 接口,将签名操作通过 Signature.getInstance(algorithm, provider) 转发到 PKCS#11 Provider,确保签名运算在 HSM 内完成。

  6. 重复检查:运行前通过 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
  }
}

五、参考文档


最后修改于 2026-04-16