Reputation: 2095
I have a .pem certificate which I have to use in my spring boot application. Now, since java does not understand .pem format, I am converting it to .p12 format.
Since, we already have a .pem certificate which is not protected by any password, I am trying to avoid password for .p12 too.
I created two .p12 files, one is with password using below command :
openssl x509 -signkey sslcert.key -in sslcert.csr -req -days 365
-out sslcert.pem
And another without password using below command :
openssl pkcs12 -inkey sslcert.key -in sslcert.pem -export -passout
pass: -nokeys -out sslcert.p12
And I am able to get the results successfully using the one with password using the below properties in spring boot application :
server.port=8443
server.ssl.enabled=true
server.ssl.key-store-type=PKCS12
server.ssl.key-store=keys/sslcert.p12
server.ssl.key-store-password=password
But when I am trying to use the one without password which is my preference, I am getting sslhandshake exception.
And also, I am not able to figure out how to pass this information to spring boot that ssl is not password protected.
SO far I tried many combinations like not passing password property or keeping it empty but it failed in all cases.
server.port=8443
server.ssl.enabled=true
server.ssl.key-store-type=PKCS12
server.ssl.key-store=keys/sslcert.p12
I am getting below exception :
javax.net.ssl.SSLHandshakeException: no cipher suites in common
at sun.security.ssl.Handshaker.checkThrown(Unknown Source)
at sun.security.ssl.SSLEngineImpl.checkTaskThrown(Unknown Source)
at sun.security.ssl.SSLEngineImpl.writeAppRecord(Unknown Source)
at sun.security.ssl.SSLEngineImpl.wrap(Unknown Source)
at javax.net.ssl.SSLEngine.wrap(Unknown Source)
at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.flush(SslConnection.java:864)
at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.fill(SslConnection.java:515)
at org.eclipse.jetty.server.HttpConnection.fillRequestBuffer(HttpConnection.java:331)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:243)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onFillable(SslConnection.java:411)
at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:305)
at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:159)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683)
at java.lang.Thread.run(Unknown Source)
SO, can any one throw some light on how to use non-password protected .p12 certificate in spring boot.
All googles articles seems to be telling about the password propected. SO is it a mandatory thing in java?
Upvotes: 8
Views: 4820
Reputation: 1248
By using a custom implementation of WebServerFactoryCustomizer and the BouncyCastle JCE provider, I was able to use a PKCS12 keystore without a password to serve SSL for a spring boot app.
First I loaded the password-less PKCS12 (in my case, retrieved from Azure Key Vault) into a keystore with the BouncyCastle provider (org.bouncycastle:bcprov-jdk15on):
ByteArrayInputStream keyStoreStream = new ByteArrayInputStream(pfxBytes);
logger.info("Loading server cert keystore from Vault retrieved cert");
KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
keyStore.load(keyStoreStream, "".toCharArray());
Then I put the keyStore into an implementation of org.springframework.boot.web.server.SslStoreProvider:
public class CustomSslStoreProvider implements SslStoreProvider {
private KeyStore keyStore;
private KeyStore trustStore;
public CustomSslStoreProvider(KeyStore keyStore, KeyStore trustStore){
this.keyStore = keyStore;
this.trustStore = trustStore;
}
And then I registered the CustomSslStoreProvider as a bean so it could be injected into my implementation of WebServerFactoryCustomizer so that it will be used by the embedded server:
@Component
public class CustomSSLServletContainer implements
WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Autowired(required = false)
private CustomSslStoreProvider sslStoreProvider;
public void customize(TomcatServletWebServerFactory factory) {
if(sslStoreProvider != null) {
factory.setSslStoreProvider(sslStoreProvider);
}
With this implementation, I still configured the key-alias in application.properties (unrelated I happened to require ssl client auth). However, you will not need to provide any of the server.ssl.key-store properties:
server.ssl.key-alias=panda-asfafa=asfaf
server.ssl.client-auth=need
Upvotes: 1
Reputation: 2095
So after all the research, it seems java key store needs a password. So I had to ignore the .p12 which we had without password. And using the pem certificate, we converted it to .p12 with password. And I am doing this from spring code where I am passing random password to shell script which generates .p12 from .pem using that password.
And then I am passing the same password to ssl properties from the code.
one drawback is I have to regenerate .p12 from .pem every time application is restarted but this is how I prevent static password.
Upvotes: 3