问题
My HSM (Hardware Security Module) stores (or allows to use) private key, however, it does not support PKCS#11 and similar method. In turn, Apache Tomcat might work with certificate and keys either via JKS, PKCS#11 or programmatically. My goal is to enable HTTPS support on a Web server, but I see no way how to achieve that with changes in configuration files only.
I imagine an option that I could store certificate in JKS, and get private key associated with it via HSM vendor provided API. For that purpose, if I am right, I will need to re-implement JSSEImplementation and corresponding factories. As well, I will need to implement specific Key and Trust Managers.
Is that the only way to solve such problem?
Is it safe to replace JSSEImplementation in a running standalone instance of Apache Tomcat, for instance, right after it started.
回答1:
Finally, I came up only to the solution below based on this example. I add <Connector>
instance to the Tomcat configuration with sslImplementationName
property pointing to the custom JSSEImplementation
class name, and extend JSSEImplementation
with custom JSSESocketFactory
and X509KeyManager
classes.
Tomcat configuration looks like:
<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 is:
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 is:
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 is:
interface CustomSslContext {
KeyManager[] getKeyManagers(JSSESocketFactory factory) throws Exception;
}
HsmKeyManagerImpl
which reference private key in the HSM by an keyAlias
property looks like:
public class HsmKeyManagerImpl implements X509KeyManager {
...
@Override
public PrivateKey getPrivateKey(String alias) {
// HSM Vendor specific API calls
}
}
I didn't show the code how to obtain certificate which corresponds to the private, but the same alias defined by the keyAlias
property of the <Connector>
is used to get it from the JKS.
来源:https://stackoverflow.com/questions/40620939/hsm-usage-with-apache-tomcat-for-https