spring-projects / spring-boot

Spring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss.
https://spring.io/projects/spring-boot
Apache License 2.0
75.17k stars 40.68k forks source link

Mixing PEM and JKS certificate material in server.ssl properties does not work #39105

Closed bennypi closed 9 months ago

bennypi commented 10 months ago

Apparently, it is not possible to use PEM files for the certificate and private key and a key store for the trust store together. The WebServerSslBundle wants to create a bundle for the trust store as well, but it ignores the configured server.ssl.trust-store and fails because it cannot find a certificate for the trust store.

Given this example configuration:

server.ssl.certificate=file:config/localhost.crt
server.ssl.certificate-private-key=file:config/localhost.key
server.ssl.trust-store=file:config/truststore.p12
server.ssl.trust-store-password=123456
server.ssl.trust-store-type=PKCS12

Using Spring Boot 3.2.1 with Azul JDK 17.0.6 on Ubuntu 22.04 fails with the following log output:

org.springframework.context.ApplicationContextException: Unable to start web server
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:165) ~[spring-boot-3.2.1.jar:3.2.1]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:619) ~[spring-context-6.1.2.jar:6.1.2]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.2.1.jar:3.2.1]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:762) ~[spring-boot-3.2.1.jar:3.2.1]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:464) ~[spring-boot-3.2.1.jar:3.2.1]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:334) ~[spring-boot-3.2.1.jar:3.2.1]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1358) ~[spring-boot-3.2.1.jar:3.2.1]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1347) ~[spring-boot-3.2.1.jar:3.2.1]
    at de.governikus.dvca.DVCAApplication.main(DVCAApplication.java:28) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50) ~[spring-boot-devtools-3.2.1.jar:3.2.1]
Caused by: java.lang.IllegalStateException: Unable to create trust store: Certificates must not be empty
    at org.springframework.boot.ssl.pem.PemSslStoreBundle.createKeyStore(PemSslStoreBundle.java:122) ~[spring-boot-3.2.1.jar:3.2.1]
    at org.springframework.boot.ssl.pem.PemSslStoreBundle.<init>(PemSslStoreBundle.java:69) ~[spring-boot-3.2.1.jar:3.2.1]
    at org.springframework.boot.ssl.pem.PemSslStoreBundle.<init>(PemSslStoreBundle.java:54) ~[spring-boot-3.2.1.jar:3.2.1]
    at org.springframework.boot.web.server.WebServerSslBundle.createPemStoreBundle(WebServerSslBundle.java:69) ~[spring-boot-3.2.1.jar:3.2.1]
    at org.springframework.boot.web.server.WebServerSslBundle.createStoreBundle(WebServerSslBundle.java:161) ~[spring-boot-3.2.1.jar:3.2.1]
    at org.springframework.boot.web.server.WebServerSslBundle.get(WebServerSslBundle.java:155) ~[spring-boot-3.2.1.jar:3.2.1]
    at org.springframework.boot.web.server.AbstractConfigurableWebServerFactory.getSslBundle(AbstractConfigurableWebServerFactory.java:225) ~[spring-boot-3.2.1.jar:3.2.1]
    at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.customizeSsl(TomcatServletWebServerFactory.java:373) ~[spring-boot-3.2.1.jar:3.2.1]
    at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.customizeConnector(TomcatServletWebServerFactory.java:349) ~[spring-boot-3.2.1.jar:3.2.1]
    at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:210) ~[spring-boot-3.2.1.jar:3.2.1]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:188) ~[spring-boot-3.2.1.jar:3.2.1]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:162) ~[spring-boot-3.2.1.jar:3.2.1]
    ... 13 common frames omitted
Caused by: java.lang.IllegalArgumentException: Certificates must not be empty
    at org.springframework.util.Assert.notEmpty(Assert.java:381) ~[spring-core-6.1.2.jar:6.1.2]
    at org.springframework.boot.ssl.pem.PemSslStoreBundle.createKeyStore(PemSslStoreBundle.java:107) ~[spring-boot-3.2.1.jar:3.2.1]
    ... 24 common frames omitted

I could not find anything in the documentation that the two options cannot be used together, so I guess this is a bug.

bennypi commented 9 months ago

Thanks for the quick fix, looking forward to the releases!