Onki
Onki

Reputation: 2095

how to use non password protected (.p12) ssl certificate in spring boot

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

Answers (3)

webthaumaturge
webthaumaturge

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

Okan
Okan

Reputation: 19

It is not possible wiithout setting password

Upvotes: 0

Onki
Onki

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

Related Questions