tobi
tobi

Reputation: 863

Use ssl certificate in spring boot application

I followed this tutorial for using a self signed certificate and that worked so far.

Then, I purchased a SSL certificate from my provider and tried to use that one. I get the error:

2019-04-19 17:45:36.385 ERROR 9245 --- [  restartedMain] org.apache.catalina.util.LifecycleBase   : Failed to start component [Connector[HTTP/1.1-8443]]

org.apache.catalina.LifecycleException: Protocol handler start failed
    at org.apache.catalina.connector.Connector.startInternal(Connector.java:1004) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.StandardService.addConnector(StandardService.java:226) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.addPreviouslyRemovedConnectors(TomcatWebServer.java:259) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.start(TomcatWebServer.java:197) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.startWebServer(ServletWebServerApplicationContext.java:311) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:164) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) [spring-context-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
    at de.tki.chinese.ChineseApplication.main(ChineseApplication.java:24) [classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_73]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_73]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_73]
    at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_73]
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-2.1.2.RELEASE.jar:2.1.2.RELEASE]
Caused by: java.lang.IllegalArgumentException: DerInputStream.getLength(): lengthTag=109, too big.
    at org.apache.tomcat.util.net.AbstractJsseEndpoint.createSSLContext(AbstractJsseEndpoint.java:114) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.tomcat.util.net.AbstractJsseEndpoint.initialiseSsl(AbstractJsseEndpoint.java:85) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.tomcat.util.net.NioEndpoint.bind(NioEndpoint.java:224) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.tomcat.util.net.AbstractEndpoint.bindWithCleanup(AbstractEndpoint.java:1085) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.tomcat.util.net.AbstractEndpoint.start(AbstractEndpoint.java:1171) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.coyote.AbstractProtocol.start(AbstractProtocol.java:568) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.connector.Connector.startInternal(Connector.java:1001) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    ... 19 common frames omitted
Caused by: java.io.IOException: DerInputStream.getLength(): lengthTag=109, too big.
    at sun.security.util.DerInputStream.getLength(DerInputStream.java:561) ~[na:1.8.0_73]
    at sun.security.util.DerValue.init(DerValue.java:365) ~[na:1.8.0_73]
    at sun.security.util.DerValue.<init>(DerValue.java:320) ~[na:1.8.0_73]
    at sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:1914) ~[na:1.8.0_73]
    at java.security.KeyStore.load(KeyStore.java:1445) ~[na:1.8.0_73]
    at org.apache.tomcat.util.net.SSLUtilBase.getStore(SSLUtilBase.java:178) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.tomcat.util.net.SSLHostConfigCertificate.getCertificateKeystore(SSLHostConfigCertificate.java:204) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.tomcat.util.net.jsse.JSSEUtil.getKeyManagers(JSSEUtil.java:203) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.tomcat.util.net.AbstractJsseEndpoint.createSSLContext(AbstractJsseEndpoint.java:112) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    ... 25 common frames omitted

2019-04-19 17:45:36.405  INFO 9245 --- [  restartedMain] o.apache.catalina.core.StandardService   : Stopping service [Tomcat]
2019-04-19 17:45:36.414  INFO 9245 --- [  restartedMain] ConditionEvaluationReportLoggingListener : 

I created a keystore like this:

MacBook-Pro:keystore tobias$ keytool -import -alias tomcat -file hanzien_de.key -keystore keystore_hanzien.de.p12 -storepass xxxxx

Then I used that keystore in my application.properties file:

# ==============================================================
# = ssh
# ==============================================================
# Tell Spring Security (if used) to require requests over HTTPS
security.require-ssl=true

# The format used for the keystore 
server.ssl.key-store-type=PKCS12
# The path to the keystore containing the certificate
server.ssl.key-store=classpath:keystore/keystore_hanzien.de.p12
#server.ssl.key-store=classpath:keystore/hanzien_de.pfx
# The password used to generate the certificate
server.ssl.key-store-password=xxxxx
# The alias mapped to the certificate
server.ssl.key-alias=tomcat

What am I doing wrong?

Upvotes: 2

Views: 12811

Answers (4)

Himanshi
Himanshi

Reputation: 112

what about direct running from cmd

java -jar -Djavax.net.ssl.trustStoreType=JKS -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStore=C:\Users\certificates\Cert_name -Dspring.profiles.active=local target\jar_or_war_name_with_dot_extension

Upvotes: 1

kolyaiks
kolyaiks

Reputation: 187

Faced with this error during Spring Boot Application with PCKS12 cert start. Simply rasing Java version from 8 to 11 fixed the error. Keep in mind that all the classes you use have to be in both versions of Java.

Upvotes: 0

dave_thompson_085
dave_thompson_085

Reputation: 38821

First, you appear to be using java 8 (8u73). Through 8 keytool defaults to JKS format, not PKCS12. (9 up does default to PKCS12.) This is why your exception cause is about DerStuff; PKCS12 format is/uses DER but JKS not. Either specify -storetype pkcs12 on the keytool command, or specify ..key-store-type=JKS in your app config (and preferably change the name so it is not actively misleading and confusing to people).

Second, keytool -import on a new keystore (or entry) imports only a certificate as a 'trustedcert' entry only usable to verify other parties. A TLS server (or SSL before it was obsoleted) like Tomcat, or in general any prover, must have a 'privatekey' entry containing a cert AND matching PRIVATEKEY AND usually CHAIN CERT(S). To be exact, the TLS standards require the server to send the/all chain cert(s) needed to verify the entity=server cert, optionally excluding the root or anchor; JSSE normally sends the cert(s) that are in the PrivateKeyEntry, so you must put the needed cert(s) there. For any public CA (like Verisign^WSymantec^WDigicert, GoDaddy, LetsEncrypt/Identrust) since about 1990, at least one chain cert is required, sometimes two and very rarely more. For a private CA this may vary depending on the CA. If the server does not send the required chain cert(s), some clients may still be able to verify some certs; in particular, browsers can often 'fill in' missing chain cert(s) from public CAs. This creates a situation where some connections to your server succeed while other connections to the same server fail, which tends to be very confusing and upsetting to users, and is not recommended.

If your .key file actually contains only a cert, naming it .key is misleading and confusing. If it contains a cert and then key in PEM, Java is able to read and separate the cert part and ignore the key; this allows keytool to run but produces a resulting file that Tomcat cannot use to accept TLS/SSL connections. (Depending on the version and maybe config, it may throw a reasonably specific exception like 'not a key' or 'key not found', or it may simply reject all connection attempts with handshake_failure.) If it contains only a key, or a key then a cert, or not PEM, the keytool command would fail, and yours apparently didn't.

keytool is not able to import a privatekey from anything but a(nother) supported keystore, which doesn't help you much because if it's already in a keystore you don't need to import it. Your choices are:

  • if you have openssl commandline, use it to convert the key + cert(s) to PKCS12. (openssl pkcs12 -export will include chain cert(s) if you provide it/them explicitly, or explicitly specify -chain and provide or default a truststore containing it/them.) There are dozens of existing Stack Qs and As, going back many years, covering this common and popular alternative.

  • use keytool to generate the keypair (already in a Java-supported keystore format) and CSR and get a certificate issued for that CSR, and then use keytool -import to either (1) import CA chain certs as trusted and then the server cert to the existing privatekey entry, which automatically fills in the chain or (2) import the whole CA chain directly to the existing privatekey entry. There are many existing Qs and As on this alternative also, as well as Sun/Oracle's own doc for Java, and tailored versions from every CA (or nearly so).

  • write, or find, and use a program that explicitly loads a privatekey and cert(s) from whatever format(s) you have to a 'privatekey' entry in a supported keystore. This is more work, and there are only a few Qs and As on this.

Upvotes: 2

DEBENDRA DHINDA
DEBENDRA DHINDA

Reputation: 1193

If you use maven, this is probably occurring because of the Maven filtering in your whole resources folder. Maven resource filtering (that let's you include variables in your resource files) can mess up your binaries - and certificates are especially sensitive to modification.

More about maven resource filtering: http://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html

Upvotes: 0

Related Questions