HSM 与 Apache Tomcat 的 HTTPS 用法
HSM usage with Apache Tomcat for HTTPS
我的 HSM(硬件安全模块)存储(或允许使用)私钥,但是,它不支持 PKCS#11 和类似的方法。反过来,Apache Tomcat 可以通过 JKS、PKCS#11 或以编程方式使用证书和密钥。我的目标是在 Web 服务器上启用 HTTPS 支持,但我看不出如何仅通过更改配置文件来实现。
我设想了一个选项,我可以将证书存储在 JKS 中,并通过 HSM 供应商提供的 API 获取与其关联的私钥。为此,如果我是对的,我将需要重新实现 JSSEImplementation 和相应的工厂。同样,我需要实施特定的密钥和信任管理器。
这是解决此类问题的唯一方法吗?
在 Apache Tomcat 的 运行 独立实例中替换 JSSEImplementation 是否安全,例如,在它启动后立即替换。
最后,我仅根据this示例得出了以下解决方案。我将 <Connector>
实例添加到 Tomcat 配置,sslImplementationName
属性 指向自定义 JSSEImplementation
class 名称,并扩展 JSSEImplementation
使用自定义 JSSESocketFactory
和 X509KeyManager
classes.
Tomcat 配置如下:
<Connector
protocol="org.apache.coyote.http11.Http11Protocol"
port="8443" maxThreads="200"
scheme="https" secure="true" SSLEnabled="true"
clientAuth="true" sslProtocol="TLS" SSLEnabled="true"
sslImplementationName="x.y.z.CustomJSSEImplementation"
keyAlias="alias_of_key_in_HSM_and_cert_in_JKS"
/>
CustomJSSEImplementation
class 是:
public class CustomJSSEImplementation extends JSSEImplementation {
@Override
public ServerSocketFactory getServerSocketFactory(AbstractEndpoint endpoint) {
return new CustomSslContextSocketFactory(endpoint);
}
@Override
public SSLUtil getSSLUtil(AbstractEndpoint endpoint) {
return new CustomSslContextSocketFactory(endpoint);
}
}
CustomSslContextSocketFactory
class 是:
public class CustomSslContextSocketFactory extends JSSESocketFactory {
public static final AtomicReference<CustomSslContext> customSslContext =
new AtomicReference<CustomSslContext>();
public CustomSslContextSocketFactory(AbstractEndpoint endpoint) {
super(endpoint);
}
@Override
public KeyManager[] getKeyManagers() throws Exception {
return (customSslContext.get() == null ? super.getKeyManagers() : customSslContext.get().getKeyManagers(this));
}
}
CustomSslContext
界面为:
interface CustomSslContext {
KeyManager[] getKeyManagers(JSSESocketFactory factory) throws Exception;
}
HsmKeyManagerImpl
通过 keyAlias
属性 引用 HSM 中的私钥,如下所示:
public class HsmKeyManagerImpl implements X509KeyManager {
...
@Override
public PrivateKey getPrivateKey(String alias) {
// HSM Vendor specific API calls
}
}
我没有显示代码如何获取对应于私有的证书,但是使用 <Connector>
的 keyAlias
属性 定义的相同别名来获取来自 JKS.
我的 HSM(硬件安全模块)存储(或允许使用)私钥,但是,它不支持 PKCS#11 和类似的方法。反过来,Apache Tomcat 可以通过 JKS、PKCS#11 或以编程方式使用证书和密钥。我的目标是在 Web 服务器上启用 HTTPS 支持,但我看不出如何仅通过更改配置文件来实现。
我设想了一个选项,我可以将证书存储在 JKS 中,并通过 HSM 供应商提供的 API 获取与其关联的私钥。为此,如果我是对的,我将需要重新实现 JSSEImplementation 和相应的工厂。同样,我需要实施特定的密钥和信任管理器。
这是解决此类问题的唯一方法吗?
在 Apache Tomcat 的 运行 独立实例中替换 JSSEImplementation 是否安全,例如,在它启动后立即替换。
最后,我仅根据this示例得出了以下解决方案。我将 <Connector>
实例添加到 Tomcat 配置,sslImplementationName
属性 指向自定义 JSSEImplementation
class 名称,并扩展 JSSEImplementation
使用自定义 JSSESocketFactory
和 X509KeyManager
classes.
Tomcat 配置如下:
<Connector
protocol="org.apache.coyote.http11.Http11Protocol"
port="8443" maxThreads="200"
scheme="https" secure="true" SSLEnabled="true"
clientAuth="true" sslProtocol="TLS" SSLEnabled="true"
sslImplementationName="x.y.z.CustomJSSEImplementation"
keyAlias="alias_of_key_in_HSM_and_cert_in_JKS"
/>
CustomJSSEImplementation
class 是:
public class CustomJSSEImplementation extends JSSEImplementation {
@Override
public ServerSocketFactory getServerSocketFactory(AbstractEndpoint endpoint) {
return new CustomSslContextSocketFactory(endpoint);
}
@Override
public SSLUtil getSSLUtil(AbstractEndpoint endpoint) {
return new CustomSslContextSocketFactory(endpoint);
}
}
CustomSslContextSocketFactory
class 是:
public class CustomSslContextSocketFactory extends JSSESocketFactory {
public static final AtomicReference<CustomSslContext> customSslContext =
new AtomicReference<CustomSslContext>();
public CustomSslContextSocketFactory(AbstractEndpoint endpoint) {
super(endpoint);
}
@Override
public KeyManager[] getKeyManagers() throws Exception {
return (customSslContext.get() == null ? super.getKeyManagers() : customSslContext.get().getKeyManagers(this));
}
}
CustomSslContext
界面为:
interface CustomSslContext {
KeyManager[] getKeyManagers(JSSESocketFactory factory) throws Exception;
}
HsmKeyManagerImpl
通过 keyAlias
属性 引用 HSM 中的私钥,如下所示:
public class HsmKeyManagerImpl implements X509KeyManager {
...
@Override
public PrivateKey getPrivateKey(String alias) {
// HSM Vendor specific API calls
}
}
我没有显示代码如何获取对应于私有的证书,但是使用 <Connector>
的 keyAlias
属性 定义的相同别名来获取来自 JKS.