I'm running H2 tcp server.
Java (Servlet 3.1 webapp in Tomcat 8.5):
org.h2.tools.Server tcp = Server.createTcpServer("-ifExists", "-tcpSSL", "-tcpPort", "8089", "-tcpAllowOthers").start();
I'm trying to access it on a remote machine via the H2 Shell on command line:
$ java -cp h2-2.1.210.jar org.h2.tools.Shell
After opening port 8089 on router, tcp connections work:
jdbc:h2:tcp://mySite.net:8089/file:/Users/xyz/tomcat/webapps/ROOT/WEB-INF/database/myh2db;IFEXISTS=TRUE;MODE=MySQL;CASE_INSENSITIVE_IDENTIFIERS=TRUE
jdbc:h2:tcp://mySite.net:8089//Users/xyz/tomcat/webapps/ROOT/WEB-INF/database/myh2db;IFEXISTS=TRUE;MODE=MySQL;CASE_INSENSITIVE_IDENTIFIERS=TRUE
But any attempt at using ssl fails with:
SQL Exception: Connection is broken: "javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
At first I thought it was a Tomcat issue with port 8089, but it doesn't look to be. The router routes incoming requests at its port 80 to Tomcat at port 8080. Tomcat redirects any HTTPS requests Tomcat receives to the router's port 443, and the router routes incoming requests it receives at its port 443 to Tomcat's port 8443.
For H2 tcp SSL (running in Tomcat, bound to port 8089), I have set up the router to route incoming requests at port 8089 to port 8089. So now tcp works, but ssl fails with the javax.net.ssl.SSLHandshakeException
.
Tomcat server.xml:
<Connector port="8080"
protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="443">
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
</Connector>
.
.
.
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
sslImplementationName="org.apache.tomcat.util.net.jsse.JSSEImplementation"
scheme="https" secure="true"
maxThreads="150" SSLEnabled="true" >
<SSLHostConfig certificateVerification="none" sslProtocol="TLS">
<Certificate certificateKeystoreFile="conf/tomcat.keystore"
type="RSA"
certificateKeystorePassword="<password>" />
</SSLHostConfig>
</Connector>
Any idea what the problem is? How to fix it?
Thanks.
UPDATE 2022-03-28
Thanks to Evgenij's pointer, I did some more research.
I used openssl (on macOS) to create new self-signed certificate. I have the following files from this process:
- server.key (private key)
- server.crt (the certificate)
- server.pem (concatenation of above 2; used to make keystore.pkcs12; otherwise looks useless)
- keystore.pkcs12
I then set six java system properties (keyStore and trustStore for the TcpServer (for anonymous TLS connection from client side)):
javax.net.ssl.keyStore=/path/to/keystore.pkcs12
javax.net.ssl.keyStorePassword=<password>
javax.net.ssl.keyStoreType=pkcs12
javax.net.ssl.trustStore=/path/to/keystore.pkcs12
javax.net.ssl.trustStorePassword=<password>
javax.net.ssl.trustStoreType=pkcs12
Now when I start up Tomcat, I get:
Error starting H2 server
org.h2.jdbc.JdbcSQLNonTransientException: IO Exception: "java.net.SocketException: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: sun.security.ssl.SSLContextImpl$DefaultSSLContext)"; "port: 8089 ssl: true" [90031-210]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:573)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:496)
at org.h2.message.DbException.get(DbException.java:216)
at org.h2.message.DbException.convertIOException(DbException.java:461)
at org.h2.util.NetUtils.createServerSocketTry(NetUtils.java:214)
at org.h2.util.NetUtils.createServerSocket(NetUtils.java:177)
at org.h2.server.TcpServer.start(TcpServer.java:236)
at org.h2.tools.Server.start(Server.java:521)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4763)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5232)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:753)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:727)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:695)
at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1016)
at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1903)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.net.SocketException: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: sun.security.ssl.SSLContextImpl$DefaultSSLContext)
at java.base/javax.net.ssl.DefaultSSLServerSocketFactory.throwException(SSLServerSocketFactory.java:175)
at java.base/javax.net.ssl.DefaultSSLServerSocketFactory.createServerSocket(SSLServerSocketFactory.java:188)
at org.h2.security.CipherFactory.createServerSocket(CipherFactory.java:152)
at org.h2.util.NetUtils.createServerSocketTry(NetUtils.java:204)
... 17 common frames omitted
Caused by: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: sun.security.ssl.SSLContextImpl$DefaultSSLContext)
at java.base/java.security.Provider$Service.newInstance(Provider.java:1901)
at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:236)
at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:164)
at java.base/javax.net.ssl.SSLContext.getInstance(SSLContext.java:168)
at java.base/javax.net.ssl.SSLContext.getDefault(SSLContext.java:99)
at java.base/javax.net.ssl.SSLServerSocketFactory.getDefault(SSLServerSocketFactory.java:114)
at org.h2.security.CipherFactory.createServerSocket(CipherFactory.java:149)
... 18 common frames omitted
Caused by: java.security.KeyStoreException: problem accessing trust store
at java.base/sun.security.ssl.TrustManagerFactoryImpl.engineInit(TrustManagerFactoryImpl.java:73)
at java.base/javax.net.ssl.TrustManagerFactory.init(TrustManagerFactory.java:278)
at java.base/sun.security.ssl.SSLContextImpl$DefaultManagersHolder.getTrustManagers(SSLContextImpl.java:1053)
at java.base/sun.security.ssl.SSLContextImpl$DefaultManagersHolder.<clinit>(SSLContextImpl.java:1023)
at java.base/sun.security.ssl.SSLContextImpl$DefaultSSLContext.<init>(SSLContextImpl.java:1198)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at java.base/java.security.Provider.newInstanceUtil(Provider.java:154)
at java.base/java.security.Provider$Service.newInstance(Provider.java:1894)
at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:236)
at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:164)
at java.base/javax.net.ssl.SSLContext.getInstance(SSLContext.java:168)
at java.base/javax.net.ssl.SSLContext.getDefault(SSLContext.java:99)
at java.base/javax.net.ssl.SSLServerSocketFactory.getDefault(SSLServerSocketFactory.java:114)
at org.h2.security.CipherFactory.createServerSocket(CipherFactory.java:149)
at org.h2.util.NetUtils.createServerSocketTry(NetUtils.java:204)
at org.h2.util.NetUtils.createServerSocket(NetUtils.java:174)
... 16 common frames omitted
Caused by: java.io.IOException: toDerInputStream rejects tag type 45
at java.base/sun.security.util.DerValue.toDerInputStream(DerValue.java:858)
at java.base/sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:1974)
at java.base/sun.security.util.KeyStoreDelegator.engineLoad(KeyStoreDelegator.java:222)
at java.base/java.security.KeyStore.load(KeyStore.java:1479)
at java.base/sun.security.ssl.TrustStoreManager$TrustAnchorManager.loadKeyStore(TrustStoreManager.java:365)
at java.base/sun.security.ssl.TrustStoreManager$TrustAnchorManager.getTrustedCerts(TrustStoreManager.java:313)
at java.base/sun.security.ssl.TrustStoreManager.getTrustedCerts(TrustStoreManager.java:55)
at java.base/sun.security.ssl.TrustManagerFactoryImpl.engineInit(TrustManagerFactoryImpl.java:49)
... 34 common frames omitted
UPDATE 2022-03-29
@dave_thompson_085, to your comment re toDerInputStream rejects tag type 45
, here are the first few lines of the od -tx1
output on the keystore.pkcs12:
$ od -tx1 keystore.pkcs12
0000000 30 82 09 e9 02 01 03 30 82 09 af 06 09 2a 86 48
0000020 86 f7 0d 01 07 01 a0 82 09 a0 04 82 09 9c 30 82
0000040 09 98 30 82 04 4f 06 09 2a 86 48 86 f7 0d 01 07
0000060 06 a0 82 04 40 30 82 04 3c 02 01 00 30 82 04 35
0000100 06 09 2a 86 48 86 f7 0d 01 07 01 30 1c 06 0a 2a
0000120 86 48 86 f7 0d 01 0c 01 06 30 0e 04 08 7c 2f ef
0000140 9d c7 1d 83 a8 02 02 08 00 80 82 04 08 5a ea 2b
0000160 57 b0 b6 ba 58 4c b5 45 7c 48 28 e0 5c 94 50 aa
0000200 b0 9b 5d 33 b1 94 0b eb 5e 85 0b 58 83 3c f0 86
0000220 24 d7 b9 53 12 fa ab 8b b1 fe b4 2b 5c b7 2c 0a
...
Do I look for 2d
(the hex value for the hyphen character)? I don't see any there. The first time any 2d
appears is at offset 320:
$ od -tx1 keystore.pkcs12 | grep 2d
0000320 76 6c 82 cb b4 2f b2 78 a3 d3 8d 2d 53 36 5e 65
...
Also: I thought I'd try importing the cert (pem file) into $JAVA_HOME/lib/security/cacerts instead of setting those six Java system properties. So I downloaded the pem file via the browser (clicking on the padlock icon in the URL locator box), and I imported it:
$ keytool -importcert -file cert.pem -alias testcert -cacerts
I then listed the cacerts file and confirmed cert.pem was imported into it. But I also noticed that the Keystore type: JKS
:
$ keytool -list -cacerts
Enter keystore password:
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 214 entries
...
Is that JKS
type in conflict with the openssl origin of the cert.pem file, which is pkcs12
? Should the pem file have been converted first into JKS format before importing into cacerts?
I tested the H2 TcpServer over ssl, and it still throws the same exception as before:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
UPDATE 2022-03-29, #2
I did over again the truststore and keystore per the instructions given at Oracle using Java keytool: Creating a Keystore to Use with JSSE. And I reset all six JVM system properties. I started up Tomcat running the TcpServer, then I tried again connecting to the server remotely via tcp over ssl. Getting the same exceptions.
UPDATE 2022-03-30
I give up getting anonymous TLS connection to work. I am able to connect non-anonymously from the client to the server when I have the client also have the six JVM system properties point to the client's own set of truststore and keystore (client's own credential) when starting the H2 Shell:
$ java -Djavax.net.ssl.keyStore=/path/to/keystore -Djavax.net.ssl.keyStorePassword=<password> -Djavax.net.ssl.keyStoreType=PKCS12 -Djavax.net.ssl.trustStore=/path/to/truststore -Djavax.net.ssl.trustStorePassword=<password> -Djavax.net.ssl.trustStoreType=PKCS12 -cp h2-2.1.210.jar org.h2.tools.Shell
What I did learn was that the truststore must have its own file; it cannot share the same file as the keystore even though the files are equivalent to each other. Sharing the same file leads to:
SEVERE [main] org.apache.catalina.core.StandardService.
initInternal Failed to initialize connector [Connector[org.apache.coyote.http11.
Http11Nio2Protocol-8443]]
...
Caused by: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
The latest set of truststore and keystore files were all generated via Java keytool. Since I am using Java 11, all files are PKCS12. I have had no success with the OpenSSL files (also PKCS12) mentioned at the very beginning.
I have not been able to replicate the toDerInputStream rejects tag type 45
exception.