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.