2

I'm in the process of upgrading a java application. Originally, the application was built with jdk 8 and the server was jetty 9. Since upgrading to jetty 10 and jdk 11, I'm running into an issue when trying to make requests to our sql datasource. When the application attempts to query the database, it fails with the error:

java.sql.SQLException: Cannot create PoolableConnectionFactory 
(The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption. Error: "PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target". ClientConnectionId:redacted)
        at org.apache.commons.dbcp2.BasicDataSource.createPoolableConnectionFactory(BasicDataSource.java:653)
        at org.apache.commons.dbcp2.BasicDataSource.createDataSource(BasicDataSource.java:531)
        at org.apache.commons.dbcp2.BasicDataSource.getConnection(BasicDataSource.java:731)
        at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122)
        at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:181)

I understand that either the jetty server or the sql server are missing a security certificate, but I'm not sure what to do about it. I read through the documentation here: https://www.eclipse.org/jetty/documentation/jetty-10/operations-guide/index.html#og-keystore but the sql server is a remote server that I don't have admin access to, so I'm not sure I can even do what they describe. Do I need to get the certificate and key from the sql server somehow? What am I missing here?

jarlh
  • 42,561
  • 8
  • 45
  • 63
pbuchheit
  • 1,371
  • 1
  • 20
  • 47
  • 1
    You need to retrieve SQL Server Public Certificate. Maybe this will help: https://stackoverflow.com/questions/34981859/openssl-fetching-sql-server-public-certificate. Then you should install the certificate in Jetty trusted keystore (cacerts), as it appears to be indicated in the Link you post. – pringi Mar 28 '22 at 16:35
  • What happens if the application needs to connect to multiple databases? Do i need to install a certificate for each? – pbuchheit Mar 28 '22 at 17:11
  • I usually run into this when getting some self signed certificates or people set up their own CA. As @pringi mentions, you need to get the public certificate from the server and add it to cacerts. If i remember correctly its just appending the public key to the file. It can take some experimeting, main thing is to get the whole certificate chain into cacerts so Java can verifiy it. Its really no fun when running into that, i usually do some trial and error until it works. What you need in your cacerts will depend on how the certificate chain looks like. Could be OK when you append the root CA. – jausen brett Mar 28 '22 at 23:19
  • 1
    On second thought: take a look at the old cacert file from the jdk 8, the cert should be there somewhere. – jausen brett Mar 28 '22 at 23:20
  • Either Java 8 runtime contained a trusted root certificate (in the cacerts file) that is now no longer delivered with Java 11, or the validity time range has run out in the meantime, or you previously imported a custom root certificate (to the cacerts file) that you now would have to re-import to the Java 11 runtime. Without more information about the signing root cert from the SQL server and the contents of the old and new cacerts file no better guesses seem to be possible. – cyberbrain Apr 03 '22 at 15:01

1 Answers1

1

Your program is failing because it is trying to connect to an "unsecure" location, you have to connect to the destination manually, get the certificate/or certificates, install them into your local keystore, and restart your program.

Some instructions on how to do that can be gound here. https://www.thesslstore.com/knowledgebase/ssl-install/jetty-java-http-servlet-webserver-ssl-installation/

If you connect to multiple locations, yes, you need to have an entry for each, unless that they have a wildcard certificate (a certificate that applies for all of them).

Alternatively! (not sure but handy) you can start the connection without enforcing certificate validation, in this case the connection will happen no matter is the destination is actually false, this is a security issue, but there are cases when this is needed, in fact, this happens a lot when you run balancers where they validate the certs for you and you connect in http to them, automatically the validation is getting dropped since most of those balancers won't fail to connect even if the validation fails, but this is a different topic!

Cheers.

Marco
  • 1,172
  • 9
  • 24