1

I'm using the YouTube Data API v3 to query some search results from YouTube and present them in a WebApp. The WebApp runs on a Tomcat 9 server with Java 14 (server host is a Raspberry Pi 3 with Raspian).

The thing is, that on my development-system (with Tomcat managed by IntelliJ) everything works fine. But on the server I get a SSLHandshakeException every time I execute a query (to be more specific a YouTube.Search.List).

Does anyone know how to fix this. The only thing I can come up, is to install a custom TrustStrategy which bypasses certificate validation for each request to a googleapi domain. But this would be my last resort because bypassing certificate validation is never a good way to fix a problem.

Thanks for every helpful answer.

Stacktrace of exception

javax.net.ssl.java SSLHandshakeException: Invalid CertificateVerify signatureSSLHandshakeException: Invalid CertificateVerify signature
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:312)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:268)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:259)
    at java.base/sun.security.ssl.CertificateVerify$T13CertificateVerifyMessage.<init>(CertificateVerify.java:1009)
    at java.base/sun.security.ssl.CertificateVerify$T13CertificateVerifyConsumer.consume(CertificateVerify.java:1160)
    at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:396)
    at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:445)
    at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:423)
    at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:182)
    at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:167)
    at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1462)
    at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1370)
    at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:437)
    at java.base/sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:567)
    at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:171)
    at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:142)
    at com.google.api.client.http.javanet.NetHttpRequest.execute(NetHttpRequest.java:148)
    at com.google.api.client.http.javanet.NetHttpRequest.execute(NetHttpRequest.java:84)
    at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1012)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:541)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:474)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:591)
    at apps.chocolatecakecodes.you_java_tube.youtube.YT.performSearch(YT.java:143)
    at apps.chocolatecakecodes.you_java_tube.servlets.Search$1.handleRequest(Search.java:63)
    at apps.chocolatecakecodes.you_java_tube.servlets.ApiServlet.callHandler(ApiServlet.java:97)
    at apps.chocolatecakecodes.you_java_tube.servlets.ApiServlet.doGet(ApiServlet.java:28)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:607)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:678)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:836)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1839)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:832)

UPDATE: even with a TrustManager which ignores all certificates, the save exception occurs.

UPDATE: With a attached debugger I stepped through the handshake process and could circumscribe the cause of the exception: this five lines in sun.security.ssl.CertificateVerify:

Signature signer = this.signatureScheme.getVerifier(x509Credentials.popPublicKey);
signer.update(contentCovered);
if (!signer.verify(this.signature)) {
   throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE, "Invalid CertificateVerify signature");
}

It seems that the signature does not fit the data of the certificate. I do not know why this happens only on the raspian system.

Max.-F.
  • 303
  • 4
  • 11

2 Answers2

1

According to this TLS checker, the YouTube Data API base server (URL: https://www.googleapis.com) is working with TLS v1.3 and v1.2.

Please verify on your site that your JVM enabled this protocols. You may find helpful the SO thread How to find what SSL/TLS version is used in Java.

Do read the official doc Additional information on Oracle's JDK and JRE Cryptographic Algorithms on how to configure your JVM -- specifically the section Changing default TLS protocol version for client end points: TLS 1.0 to TLS 1.2. The doc How do I change the default SSL protocol my Java Client Application will use? might also be useful.


Update

Do have a thorough look at Oracle's official doc Java Secure Socket Extension (JSSE) Reference Guide -- specifically the sections Troubleshooting SSE: Configuration Problems and Troubleshooting SSE: Debugging Utilities.

Afterwards, do enable the following option on the JVM running your app: -Djavax.net.debug=ssl:handshake. Note that the error message you have obtained -- Invalid CertificateVerify signature -- originates from CertificateVerify.java:1010.

Subsequently, you may consider to post here your findings.

stvar
  • 6,551
  • 2
  • 13
  • 28
  • The server JVM supports following protocols: TLSv1.3, TLSv1.2, TLSv1.1, TLSv1, SSLv3, SSLv2Hello. I can not determine which protocol is used for the google APIs, because the exceptions prevents me from connecting. So I tested with other domains: www.youtube.com: same error; duckduckgo.com: success, TLSv1.3. – Max.-F. Jul 16 '20 at 15:31
  • As per [the doc](https://www.java.com/en/configure_crypto.html#enableTLSv1_2) I quoted above, could you try to run your app by a command like: `$ java ‑Djdk.tls.client.protocols="TLSv1.3,TLSv1.2" yourApp`? – stvar Jul 16 '20 at 18:03
  • I added the suggested option to the JAVA_OPTS but still the same exception. – Max.-F. Jul 17 '20 at 09:00
  • I did corrected my updated answer above. Have a look at it once again. – stvar Jul 17 '20 at 12:42
  • I edited my answer. Let me know it if you want the log of the hanshake-debug-output (but I could not find any suspicious). – Max.-F. Jul 17 '20 at 14:47
0

OK, now I know why it was so difficult to find any solution: there was no (application) error. After I updated the JDK the WebApp works just as it should.

Case closed.

Max.-F.
  • 303
  • 4
  • 11