Hi
After upgrade to 2.3.6 tomcat ssl keystore password no longer works
server:
port: 10002
ssl:
key-store: xxx.jks
key-password: xxxxx
Caused by: java.io.IOException: Keystore was tampered with, or password was incorrect
at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:785)
at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:56)
at sun.security.provider.KeyStoreDelegator.engineLoad(KeyStoreDelegator.java:224)
at sun.security.provider.JavaKeyStore$DualFormatJKS.engineLoad(JavaKeyStore.java:70)
at java.security.KeyStore.load(KeyStore.java:1445)
at org.apache.tomcat.util.security.KeyStoreUtil.load(KeyStoreUtil.java:69)
at org.apache.tomcat.util.net.SSLUtilBase.getStore(SSLUtilBase.java:216)
at org.apache.tomcat.util.net.SSLHostConfigCertificate.getCertificateKeystore(SSLHostConfigCertificate.java:207)
at org.apache.tomcat.util.net.SSLUtilBase.getKeyManagers(SSLUtilBase.java:282)
at org.apache.tomcat.util.net.SSLUtilBase.createSSLContext(SSLUtilBase.java:246)
at org.apache.tomcat.util.net.AbstractJsseEndpoint.createSSLContext(AbstractJsseEndpoint.java:97)
The configuration for keystore retrieved from a cloud config server, and works fine on 2.3.5 release
Probably related to the following fix in 2.3.6 but from the quick look I do not see an issue there https://github.com/spring-projects/spring-boot/issues/24052
Regards Alex M
Comment From: scottfrederick
java.io.IOException: Keystore was tampered with, or password was incorrect
This error is related to the keystore password, which you are not setting (i.e. with server.ssl.key-store-password
).
When any of the keystore-related properties are set on the Tomcat connection, Tomcat initializes a new certificate object with a default keystore password value. Prior to the change in #24052, Spring Boot would override the Tomcat default keystore password with null
when server.ssl.key-store-password
was not set. After this change the default password value is retained, which doesn't match your keystore's password.
Can you try setting server.ssl.key-store-password
to see if this fixes your problem?
Setting the keystore password seems like a best-practice when setting a keystore, so I'm not sure if there's anything more we should do here, but I'll mark this issue for team attention to discuss whether this new behavior is correct or if there are further changes that should be made in Spring Boot.
Comment From: alexmond
Hi Scott, thanks for a quick response.
Sorry for the delay, I had to test the issue locally. So looks like the issue is mostly affecting JKS format. Up to 2.3.5 version either key-password or key-store-password settings can be used for both store and key password, and It still works the same way in Netty.
Right now, just replacing the key-password with key-store-password (in a couple hundred yaml files) solves our issue.
Since the JKS format is deprecated we will be migrating to p12 where both passwords have to be set and this issue will get resolved, but I think some discussion about backward compatibility will still make sense.
You are welcome to close this issue Alex M
Comment From: scottfrederick
Up to 2.3.5 version either key-password or key-store-password settings can be used for both store and key password, and It still works the same way in Netty.
The Netty connection setup in Spring Boot uses the server.ssl.key-store-password
property as-is, allowing it to be null
if not set. server.ssl.key-password
is not used for the store password. The inverse is true though - if server.ssl.key-password
is not set then server.ssl.key-store-password
is used for the key password.
The difference in 2.3.6 is that a value of null
for server.ssl.key-store-password
will result in the Tomcat code using changeit
for the key store password instead of using null
as the default. After some further team discussion, we believe this is the correct behavior for Spring Boot.
Right now, just replacing the key-password with key-store-password (in a couple hundred yaml files) solves our issue.
Another option is to implement your own TomcatConnectorCustomizer
and set any keystore fields in code, if that's easier than changing yaml files.
@Configuration
public class TomcatConfiguration {
@Bean
public TomcatConnectorCustomizer customizer() {
return connector -> {
AbstractHttp11JsseProtocol<?> protocol = (AbstractHttp11JsseProtocol<?>) connector.getProtocolHandler();
protocol.setKeystorePass(/* password value */);
protocol.setKeyPass(/* password value */);
};
}
}
Comment From: inad9300
It'd be worth including a mention to this breaking change in the release notes!