Debian 9 Tomcat 9 Let's Encrypt SSL config

Viewed 495

It drives me nuts now.

I have created sym links to the PEM files. I made the PEM files readable for the tomcat user. I set the server.xml to use SSL. And the connector fails to start.

<Connector port="8443"
               protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="200"
               scheme="https"
               secure="true"
               SSLEnabled="true"
               clientAuth="false"
               sslProtocol="TLS"
               sslImplementationName="org.apache.tomcat.util.net.openssl.OpenSSLImplementation"
               defaultSSLHostConfigName="mydomain.com"
    >
        <SSLHostConfig hostName="mydomain.com" protocols="+TLSv1,+TLSv1.1,+TLSv1.2">
            <Certificate
                certificateKeyFile="conf/privkey.pem"
                certificateFile="conf/cert.pem"
                certificateChainFile="conf/chain.pem"
                type="UNDEFINED"
            />
        </SSLHostConfig>
    </Connector>

I did try to change the type to RSA, to no avail. All I see in the log is:

02-Jan-2021 17:40:54.398 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["https-openssl-nio-8443"]
02-Jan-2021 17:40:54.466 SEVERE [main] org.apache.catalina.util.LifecycleBase.handleSubClassException Failed to initialize component [Connector[HTTP/1.1-8443]]
        org.apache.catalina.LifecycleException: Protocol handler initialization failed
                at org.apache.catalina.connector.Connector.initInternal(Connector.java:1013)
                ... some lines removed
                at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:473)
        Caused by: java.lang.IllegalArgumentException
                at org.apache.tomcat.util.net.AbstractJsseEndpoint.createSSLContext(AbstractJsseEndpoint.java:99)
                ... some lines are removed
                at org.apache.catalina.connector.Connector.initInternal(Connector.java:1010)
                ... 13 more
        Caused by: java.io.IOException
                at org.apache.tomcat.util.net.SSLUtilBase.getKeyManagers(SSLUtilBase.java:302)
                at org.apache.tomcat.util.net.openssl.OpenSSLUtil.getKeyManagers(OpenSSLUtil.java:98)
                at org.apache.tomcat.util.net.SSLUtilBase.createSSLContext(SSLUtilBase.java:247)
                at org.apache.tomcat.util.net.AbstractJsseEndpoint.createSSLContext(AbstractJsseEndpoint.java:97)
                ... 20 more

I've checked the SSLUtilBase.java code (tomcat 9.0.33):

            if (certificate.getCertificateFile() == null) {
                throw new IOException(sm.getString("jsse.noCertFile"));
            }

I did try to copy the files instead of using sym links. No avail. Removed the comments from the cert files. No avail. It seems tomcat cannot find the files I've specified in the server.xml.

What do I miss?

2 Answers

Whenever you use one of the deprecated properties on a connector, Tomcat creates an <SSLHostConfig> element with hostName="_default_" and a <Connector> element inside it. The error is caused by the lack of the certificateFile on this particular element.

Remove the deprecated attributes (clientAuth, sslProtocol) from the <Connector> element and everything should work.

    <Connector port="8443"
               protocol="org.apache.coyote.http11.Http11NioProtocol"
               SSLEnabled="true"
               sslImplementationName="org.apache.tomcat.util.net.openssl.OpenSSLImplementation"
               defaultSSLHostConfigName="mydomain.com">
        <SSLHostConfig hostName="mydomain.com" protocols="TLSv1+TLSv1.1+TLSv1.2">
            <Certificate
                certificateKeyFile="conf/privkey.pem"
                certificateFile="conf/cert.pem"
                certificateChainFile="conf/chain.pem"
                type="UNDEFINED"
            />
        </SSLHostConfig>
    </Connector>

Remark: the sslProtocol attribute is a characteristic of JSSE and should always be left at the default value (TLS).

I had the same issue with Ubuntu 20.04 and Tomcat 9.0.52.

Tomcat - server.xml - certificateKeyFile

<Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol"
           maxThreads="150" SSLEnabled="true" >
    <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
    <SSLHostConfig>
                    <Certificate certificateKeyFile="conf/localhost-rsa-key.pem"
                     certificateFile="conf/localhost-rsa-cert.pem"
                     type="RSA" />
    </SSLHostConfig>
</Connector>

I also tried everything that you described above and I also was not able to make the Tomcat Connector with certificateKeyFile to work.

Note, on RedHat Linux 7/8 it works fine though!!! I only got this issue in Ubuntu 20.04.

The good news is it works fine in Ubuntu 20.04 if you use a keystore instead of the certificateKeyFile.

You will need to create the keystore as the user that runs tomcat, in my case the user named "tomcat", then created the CSR using the keystore, issue the certificate, and imported the certificate into the keystore.

--Create the keystore folder and grant the proper permissions:

su - root
mkdir /rhdata/sslcert
chown -R tomcat:tomcat /rhdata/sslcert
su - tomcat
cd /rhdata/sslcert

--Create the PKCS12 keystore (must do the previous step):

su - tomcat
/usr/lib/jvm/java-11-openjdk-amd64/bin/keytool -genkey -alias tomcat -storetype PKCS12 -keyalg RSA -keystore /rhdata/sslcert/.keystore
$ /usr/lib/jvm/java-11-openjdk-amd64/bin/keytool -genkey -alias tomcat -storetype PKCS12 -keyalg RSA -validity 3600 -keysize 2048 -keystore /rhdata/sslcert/.keystore
Enter keystore password:  key$tom@2021
$ /usr/lib/jvm/java-11-openjdk-amd64/bin/keytool --list --keystore /rhdata/sslcert/.keystore -storepass 'key$tom@2021'

--Create the CSR:

su - tomcat
$ /usr/lib/jvm/java-11-openjdk-amd64/bin/keytool -certreq -keyalg RSA -alias tomcat -file /rhdata/sslcert/keytool_cert/certreq.csr -keystore /rhdata/sslcert/.keystore -storepass 'key$tom@2021'

--Create the new certificate from the certificate authority using the CSR

--Import the new certificate into the keystore:

su - tomcat
$ /usr/lib/jvm/java-11-openjdk-amd64/bin/keytool -import -alias tomcat -keystore /rhdata/sslcert/.keystore -storepass 'key$tom@2021' -file /rhdata/sslcert/keytool_cert/certnew.p7b
$ /usr/lib/jvm/java-11-openjdk-amd64/bin/keytool -import -alias tomcat -keystore /rhdata/sslcert/.keystore -storepass 'key$tom@2021' -file /rhdata/sslcert/keytool_cert/certnew.cer

--This is the new Tomcat connector:

Tomcat - server.xml - keystore

<Connector
       protocol="org.apache.coyote.http11.Http11NioProtocol"
       port="8443" maxThreads="200"
       scheme="https" secure="true" SSLEnabled="true"
       keystoreFile="/rhdata/sslcert/.keystore" keystorePass="key$tom@2021"
       clientAuth="false" sslProtocol="TLS"/>

--Verify the new Tomcat server.xml file

su - tomcat
cd /usr/local/tomcat9/conf
/usr/local/tomcat9/bin/configtest.sh

--Then, stop/start Tomcat.

su - root
systemctl stop tomcat.service
systemctl start tomcat.service
systemctl status tomcat.service
vi /usr/local/tomcat9/logs/catalina.out   <-- shall not have any errors!!!
Related