我的HSM(硬件安全模块)存储(或允许使用)私钥,但是,它不支持PKCS#11和类似方法。反过来,Apache Tomcat可以通过JKS,PKCS#11或以编程方式使用证书和密钥。我的目标是在Web服务器上启用HTTPS支持,但是我看不到如何仅通过更改配置文件来实现这一点。
我想象一个选项,我可以将证书存储在JKS中,并通过HSM供应商提供的API获得与其关联的私钥。为此,如果我是对的,我将需要重新实现JSSEImplementation和相应的工厂。同样,我将需要实现特定的密钥和信任管理器。
那是解决这种问题的唯一方法吗?
例如,在启动后立即在正在运行的Apache Tomcat独立实例中替换JSSEImplementation是否安全?
最后,基于此示例,我仅提出以下解决方案。我将<Connector>实例添加到Tomcat配置中,并带有sslImplementationName指向自定义JSSEImplementation类名称的属性,并JSSEImplementation通过自定义JSSESocketFactory和X509KeyManager类进行扩展。
<Connector>
sslImplementationName
JSSEImplementation
JSSESocketFactory
X509KeyManager
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 类是:
CustomJSSEImplementation
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 类是:
CustomSslContextSocketFactory
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 界面是:
CustomSslContext
interface CustomSslContext { KeyManager[] getKeyManagers(JSSESocketFactory factory) throws Exception; }
HsmKeyManagerImpl通过keyAlias属性在HSM中引用私钥的形式如下:
HsmKeyManagerImpl
keyAlias
public class HsmKeyManagerImpl implements X509KeyManager { ... @Override public PrivateKey getPrivateKey(String alias) { // HSM Vendor specific API calls } }
我没有显示代码如何获取与私有证书相对应的证书,但是使用的keyAlias属性定义的相同别名<Connector>用于从JKS 获取证书。