HSM 中使用私钥的 SSL 连接
SSL Connection With Private Keys in HSM
我想实现一个 ssl 连接,RSA 密钥对保存在 Java 的硬件安全模块 (HSM) 中。
通过使用openssl pkcs11引擎,我通过以下引擎配置实现了TLS连接。
[openssl_def]
engines = engine_section
[engine_section]
pkcs11 = pkcs11_section
[pkcs11_section]
engine_id = pkcs11
MODULE_PATH = /home/ubuntu/Desktop/vendorlib.so
PIN = "123456"
init = 0
[req]
distinguished_name = test_name
[req_distinguished_name]
然后我使用此引擎通过以下命令创建证书,其中 ssl_key 保存在 HSM 设备中。
OPENSSL_CONF=engine.conf openssl req -new -x509 -days 365 -subj '/CN=test/' -sha256 -config engine.conf -engine pkcs11 -keyform engine -key slot_2-label_ssl_key -out cert.pem
我可以使用以下 openssl 服务器和客户端命令确认证书和密钥对。
对于服务器:
OPENSSL_CONF=engine.conf openssl s_server -engine pkcs11 -keyform engine -key slot_2-label_ssl_key -cert cert.pem -accept 44330
对于客户:
OPENSSL_CONF=engine.conf openssl s_client -connect localhost:44330 -engine pkcs11
但是,我需要在 Vertx(3.81) Java 8 连接中建立此连接。
当我查看 vertx 的文档时,有一个 OpenSSLEngineOptions 可以设置为 serverOptions 但我不知道在哪里放置参数,如键名、槽号和引擎 ID 等。
事实上,OpenSSLEngineOptions 有一个采用 JsonObject 的构造函数,但我找不到这个 JsonObject 的任何示例。
这是我在实例化 Vertx ssl 选项时截取的代码
HttpServerOptions serverOptions = jerseyServerOptions.getServerOptions();
OpenSSLEngineOptions openSSLOptions = new OpenSSLEngineOptions();
serverOptions.setOpenSslEngineOptions(openSSLOptions);
serverOptions.setPort(1234);
serverOptions.setSsl(true);
String certCopy = "-----BEGIN CERTIFICATE-----
MIICMzCCAZygAwIBAgIJALiPnVsvq8dsMA0GCSqGSIb3DQEBBQUAMFMxCzAJBgNV
BAYTAlVTMQwwCgYDVQQIEwNmb28xDDAKBgNVBAcTA2ZvbzEMMAoGA1UEChMDZm9v
MQwwCgYDVQQLEwNmb28xDDAKBgNVBAMTA2ZvbzAeFw0xMzAzMTkxNTQwMTlaFw0x
ODAzMTgxNTQwMTlaMFMxCzAJBgNVBAYTAlVTMQwwCgYDVQQIEwNmb28xDDAKBgNV
BAcTA2ZvbzEMMAoGA1UEChMDZm9vMQwwCgYDVQQLEwNmb28xDDAKBgNVBAMTA2Zv
bzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzdGfxi9CNbMf1UUcvDQh7MYB
OveIHyc0E0KIbhjK5FkCBU4CiZrbfHagaW7ZEcN0tt3EvpbOMxxc/ZQU2WN/s/wP
xph0pSfsfFsTKM4RhTWD2v4fgk+xZiKd1p0+L4hTtpwnEw0uXRVd0ki6muwV5y/P
+5FHUeldq+pgTcgzuK8CAwEAAaMPMA0wCwYDVR0PBAQDAgLkMA0GCSqGSIb3DQEB
BQUAA4GBAJiDAAtY0mQQeuxWdzLRzXmjvdSuL9GoyT3BF/jSnpxz5/58dba8pWen
v3pj4P3w5DoOso0rzkZy2jEsEitlVM2mLSbQpMM+MUVQCQoiG6W9xuCFuxSrwPIS
pAqEAuV4DNoxQKKWmhVv+J0ptMWD25Pnpxeq5sXzghfJnslJlQND
-----END CERTIFICATE-----";
PemKeyCertOptions pemKeyCertOptions = new PemKeyCertOptions().setCertValue(Buffer.buffer(certValue));
serverOptions.setPemKeyCertOptions(pemKeyCertOptions);
TLDR;
我们如何在 Vertx 中建立 SSL 连接,其中私钥仅存储在 HSM 中且无法提取?
编辑:
我在 OpenSSLEngineOptions here 的构造函数中找到了 jsonObject 的解析器。不幸的是,它只读取 sessionCacheEnabled 选项。
我想出了一个使用安全提供程序和 Java 密钥库的解决方案。这是示例代码:
/*
pkcs11.cfg example:
name=PKCS11
library=vendor provided library absolute path
slot=0
*/
String propertyPath = "/root/IdeaProjects/ssl/pkcs11.cfg;
char[] pin = "1234".toCharArray();
Provider p = new SunPKCS11(propertyPath);
Security.removeProvider("IAIK");
Security.addProvider(p);
KeyStore ks = KeyStore.getInstance("PKCS11",p);
ks.load(null,pin);
KeyStore初始化后,您可以将您的SSLContext指向KeyStore。但是根据Java 8 PKCS11 Documentation,证书的CKA_ID属性和私钥应该是匹配的。如果 pkcs11 引擎匹配证书和密钥对,它应该显示为别名。
//Showing aliases
Enumeration<String> aliases = ks.aliases();
for (; aliases.hasMoreElements(); ){
System.out.println(aliases.nextElement());
}
验证别名后,我们将使用 SSLContext 绑定我们的 KeyManager。
SSLContext ctx = SSLContext.getInstane("TLS");
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(ks,pin);
ctx.init(keyManagerFactory.getKeyManagers(), null, null);
我想实现一个 ssl 连接,RSA 密钥对保存在 Java 的硬件安全模块 (HSM) 中。
通过使用openssl pkcs11引擎,我通过以下引擎配置实现了TLS连接。
[openssl_def]
engines = engine_section
[engine_section]
pkcs11 = pkcs11_section
[pkcs11_section]
engine_id = pkcs11
MODULE_PATH = /home/ubuntu/Desktop/vendorlib.so
PIN = "123456"
init = 0
[req]
distinguished_name = test_name
[req_distinguished_name]
然后我使用此引擎通过以下命令创建证书,其中 ssl_key 保存在 HSM 设备中。
OPENSSL_CONF=engine.conf openssl req -new -x509 -days 365 -subj '/CN=test/' -sha256 -config engine.conf -engine pkcs11 -keyform engine -key slot_2-label_ssl_key -out cert.pem
我可以使用以下 openssl 服务器和客户端命令确认证书和密钥对。
对于服务器:
OPENSSL_CONF=engine.conf openssl s_server -engine pkcs11 -keyform engine -key slot_2-label_ssl_key -cert cert.pem -accept 44330
对于客户:
OPENSSL_CONF=engine.conf openssl s_client -connect localhost:44330 -engine pkcs11
但是,我需要在 Vertx(3.81) Java 8 连接中建立此连接。
当我查看 vertx 的文档时,有一个 OpenSSLEngineOptions 可以设置为 serverOptions 但我不知道在哪里放置参数,如键名、槽号和引擎 ID 等。 事实上,OpenSSLEngineOptions 有一个采用 JsonObject 的构造函数,但我找不到这个 JsonObject 的任何示例。
这是我在实例化 Vertx ssl 选项时截取的代码
HttpServerOptions serverOptions = jerseyServerOptions.getServerOptions();
OpenSSLEngineOptions openSSLOptions = new OpenSSLEngineOptions();
serverOptions.setOpenSslEngineOptions(openSSLOptions);
serverOptions.setPort(1234);
serverOptions.setSsl(true);
String certCopy = "-----BEGIN CERTIFICATE-----
MIICMzCCAZygAwIBAgIJALiPnVsvq8dsMA0GCSqGSIb3DQEBBQUAMFMxCzAJBgNV
BAYTAlVTMQwwCgYDVQQIEwNmb28xDDAKBgNVBAcTA2ZvbzEMMAoGA1UEChMDZm9v
MQwwCgYDVQQLEwNmb28xDDAKBgNVBAMTA2ZvbzAeFw0xMzAzMTkxNTQwMTlaFw0x
ODAzMTgxNTQwMTlaMFMxCzAJBgNVBAYTAlVTMQwwCgYDVQQIEwNmb28xDDAKBgNV
BAcTA2ZvbzEMMAoGA1UEChMDZm9vMQwwCgYDVQQLEwNmb28xDDAKBgNVBAMTA2Zv
bzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzdGfxi9CNbMf1UUcvDQh7MYB
OveIHyc0E0KIbhjK5FkCBU4CiZrbfHagaW7ZEcN0tt3EvpbOMxxc/ZQU2WN/s/wP
xph0pSfsfFsTKM4RhTWD2v4fgk+xZiKd1p0+L4hTtpwnEw0uXRVd0ki6muwV5y/P
+5FHUeldq+pgTcgzuK8CAwEAAaMPMA0wCwYDVR0PBAQDAgLkMA0GCSqGSIb3DQEB
BQUAA4GBAJiDAAtY0mQQeuxWdzLRzXmjvdSuL9GoyT3BF/jSnpxz5/58dba8pWen
v3pj4P3w5DoOso0rzkZy2jEsEitlVM2mLSbQpMM+MUVQCQoiG6W9xuCFuxSrwPIS
pAqEAuV4DNoxQKKWmhVv+J0ptMWD25Pnpxeq5sXzghfJnslJlQND
-----END CERTIFICATE-----";
PemKeyCertOptions pemKeyCertOptions = new PemKeyCertOptions().setCertValue(Buffer.buffer(certValue));
serverOptions.setPemKeyCertOptions(pemKeyCertOptions);
TLDR; 我们如何在 Vertx 中建立 SSL 连接,其中私钥仅存储在 HSM 中且无法提取?
编辑: 我在 OpenSSLEngineOptions here 的构造函数中找到了 jsonObject 的解析器。不幸的是,它只读取 sessionCacheEnabled 选项。
我想出了一个使用安全提供程序和 Java 密钥库的解决方案。这是示例代码:
/*
pkcs11.cfg example:
name=PKCS11
library=vendor provided library absolute path
slot=0
*/
String propertyPath = "/root/IdeaProjects/ssl/pkcs11.cfg;
char[] pin = "1234".toCharArray();
Provider p = new SunPKCS11(propertyPath);
Security.removeProvider("IAIK");
Security.addProvider(p);
KeyStore ks = KeyStore.getInstance("PKCS11",p);
ks.load(null,pin);
KeyStore初始化后,您可以将您的SSLContext指向KeyStore。但是根据Java 8 PKCS11 Documentation,证书的CKA_ID属性和私钥应该是匹配的。如果 pkcs11 引擎匹配证书和密钥对,它应该显示为别名。
//Showing aliases
Enumeration<String> aliases = ks.aliases();
for (; aliases.hasMoreElements(); ){
System.out.println(aliases.nextElement());
}
验证别名后,我们将使用 SSLContext 绑定我们的 KeyManager。
SSLContext ctx = SSLContext.getInstane("TLS");
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(ks,pin);
ctx.init(keyManagerFactory.getKeyManagers(), null, null);