I’m running a local TCP server in C++ on Windows via OpenSSL and Windows sockets. I’m running the client in Java using SSL sockets. For most users this setup is working, however, some users run into the following Java exception upon attempting the SSL handshake:
javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake
at sun.security.ssl.SSLSocketImpl.handleEOF(Unknown Source) ~[?:1.8.0_321]
at sun.security.ssl.SSLSocketImpl.decode(Unknown Source) ~[?:1.8.0_321]
at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(Unknown Source) ~[?:1.8.0_321]
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source) ~[?:1.8.0_321]
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source) ~[?:1.8.0_321]
...
Caused by: java.io.EOFException: SSL peer shut down incorrectly
at sun.security.ssl.SSLSocketInputRecord.read(Unknown Source) ~[?:1.8.0_321]
at sun.security.ssl.SSLSocketInputRecord.readHeader(Unknown Source) ~[?:1.8.0_321]
at sun.security.ssl.SSLSocketInputRecord.decode(Unknown Source) ~[?:1.8.0_321]
at sun.security.ssl.SSLTransport.decode(Unknown Source) ~[?:1.8.0_321]
... 10 more
My client socket code in Java looks like this:
public static Socket getClientSocket() throws Exception
{
InetSocketAddress socketAddress = new InetSocketAddress("localhost", 54321);
SSLSocketFactory socketFactory = getSSLSocketFactory();
Socket clientSocket = socketFactory.createSocket();
clientSocket.connect(socketAddress, 1_000);
((SSLSocket) clientSocket).startHandshake(); // <-- Exception here for some users
return clientSocket;
}
private static SSLSocketFactory getSSLSocketFactory() throws Exception
{
// Create a trust manager that does not validate certificate chains
X509TrustManager trustManager = new X509TrustManager()
{
@Override
public X509Certificate[] getAcceptedIssuers()
{
// TODO Returning null is not allowed but it still works
return null;
}
@Override
public void checkClientTrusted(final X509Certificate[] certificates, final String authType)
{
}
@Override
public void checkServerTrusted(final X509Certificate[] certificates, final String authType)
{
for (X509Certificate certificate : certificates)
{
String certificateString = certificate.toString();
if (!certificateString.contains("blablabla"))
{
throw new SSLException("Certificate not trusted");
}
}
}
};
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]{trustManager}, new SecureRandom());
return sslContext.getSocketFactory();
}
Attempted solutions:
- Calling
System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2")
before connecting did not work (reference) - I do not want to tell users to import any SSL certificates into their truststore (unless I can automate this easily)
Where does the inconsistent behavior come from and how to fix it cleanly for everyone who gets the exception? I have access to the server source code and certificates. Also any critical questions or suggestions are welcome. I can provide more information if necessary.
Not an answer yet, but too much for a comment. This is clearly not a server cert problem; the symptoms of that are quite different. From your system’s POV, the server appears to be closing during the handshake. There are two possibilities:
The server really is closing, which is a SSL/TLS protocol violation though a fairly minor one; there are quite a few reasons a server might fail to handshake with you but it should send a fatal alert first, which your JSSE or the
weblogic equivalent should indicate. In this case there may well be some useful information in the server log, if you are able (and permitted) to communicate with knowledgeable server admin(s). Or you can try putting a network monitor on your client machine, or one close enough it sees all your traffic; personally I like www.wireshark.org. But this usually shows only that the close came immediately after the ClientHello, which doesn’t narrow it down much. You don’t say if you are supposed to and
have configured a «client cert» (actually key&cert, in the form of a Java privateKeyEntry) for this server; if that is required by the server and not correct, some servers may perceive that as an attack and knowingly violate protocol by closing even though officially they should send an alert.
Or, some middlebox in the network, most often a firewall or purportedly-transparent proxy, is deciding it doesn’t like your connection and forcing a close. The Proxy you use is an
obvious suspect; when you say the «same code» works to other hosts, confirm if you mean through the same proxy (not just a proxy) and using HTTPS (not clear HTTP). If that isn’t so, try testing to other hosts with HTTPS through the proxy (you needn’t send a full SOAP request, just a GET / if enough). If you can, try connecting without the proxy, or possibly a different proxy, and connecting HTTP (not S) through the proxy to the host (if both support clear) and see if those work.
If
you don’t mind publishing the actual host (but definitely not any authentication credentials) others can try it. Or you can go to www.ssllabs.com and request they test the server (without publishing the results); this will try several common variations on SSL/TLS connection and report any errors it sees, as well as any security weaknesses.
With Java 11, I can’t connect to an LDAPS server using Jenkins LTS v2.164.3.
It works correctly with Java 8.
I tried with Java 11.0.3 and Java 11.0.4 (Azul JDK for Alpine).
I don’t know if the bug is directly related to Jenkins or if an upstream component is involved.
The only workaround I found it’s to disable TLS1.2 and TLS1.3 (-Djdk.tls.client.protocols=TLSv1.1,TLSv1 -Dhttps.protocols=TLSv1.1,TLSv1).
Unable to connect to ldaps:java.io.EOFException: SSL peer shut down incorrectly at java.base/sun.security.ssl.SSLSocketInputRecord.decode(SSLSocketInputRecord.java:167) at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:108) at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1152) Caused: javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake at java.base/sun.security.ssl.SSLSocketImpl.handleEOF(SSLSocketImpl.java:1322) at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1160) at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1063) at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:402) at java.base/sun.security.ssl.SSLSocketImpl.ensureNegotiated(SSLSocketImpl.java:716) at java.base/sun.security.ssl.SSLSocketImpl$AppOutputStream.write(SSLSocketImpl.java:970) at java.base/java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:81) at java.base/java.io.BufferedOutputStream.flush(BufferedOutputStream.java:142) at java.naming/com.sun.jndi.ldap.Connection.writeRequest(Connection.java:398) at java.naming/com.sun.jndi.ldap.Connection.writeRequest(Connection.java:371) at java.naming/com.sun.jndi.ldap.LdapClient.ldapBind(LdapClient.java:359) at java.naming/com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:192) Caused: javax.naming.CommunicationException: anonymous bind failed: myserver.com:636 [Root exception is javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake] at java.naming/com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:198) at java.naming/com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2795) at java.naming/com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:320) at java.naming/com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:192) at java.naming/com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:210) at java.naming/com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:153) at java.naming/com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:83) at java.naming/javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:730) at java.naming/javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:305) at java.naming/javax.naming.InitialContext.init(InitialContext.java:236) at java.naming/javax.naming.InitialContext.<init>(InitialContext.java:208) at java.naming/javax.naming.directory.InitialDirContext.<init>(InitialDirContext.java:101) at jenkins.security.plugins.ldap.LDAPConfiguration$LDAPConfigurationDescriptor.doCheckServer(LDAPConfiguration.java:400) at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:710) at org.kohsuke.stapler.Function$MethodFunction.invoke(Function.java:396) at org.kohsuke.stapler.Function$InstanceFunction.invoke(Function.java:408) at org.kohsuke.stapler.Function.bindAndInvoke(Function.java:212) at org.kohsuke.stapler.Function.bindAndInvokeAndServeResponse(Function.java:145) at org.kohsuke.stapler.MetaClass$11.doDispatch(MetaClass.java:537) at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:58) at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:739) at org.kohsuke.stapler.Stapler.invoke(Stapler.java:870) at org.kohsuke.stapler.MetaClass$4.doDispatch(MetaClass.java:282) at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:58) at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:739) at org.kohsuke.stapler.Stapler.invoke(Stapler.java:870) at org.kohsuke.stapler.Stapler.invoke(Stapler.java:668) at org.kohsuke.stapler.Stapler.service(Stapler.java:238) at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:865) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1655) at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:154) at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:239) at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:215) at net.bull.javamelody.PluginMonitoringFilter.doFilter(PluginMonitoringFilter.java:88) at org.jvnet.hudson.plugins.monitoring.HudsonMonitoringFilter.doFilter(HudsonMonitoringFilter.java:114) at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:151) at jenkins.metrics.impl.MetricsFilter.doFilter(MetricsFilter.java:125) at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:151) at hudson.plugins.audit_trail.AuditTrailFilter.doFilter(AuditTrailFilter.java:92) at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:151) at jenkins.telemetry.impl.UserLanguages$AcceptLanguageFilter.doFilter(UserLanguages.java:128) at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:151) at hudson.util.PluginServletFilter.doFilter(PluginServletFilter.java:157) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642) at hudson.security.csrf.CrumbFilter.doFilter(CrumbFilter.java:64) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642) at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:84) at hudson.security.ChainedServletFilter.doFilter(ChainedServletFilter.java:90) at hudson.security.HudsonFilter.doFilter(HudsonFilter.java:171) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642) at org.kohsuke.stapler.compression.CompressionFilter.doFilter(CompressionFilter.java:49) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642) at hudson.util.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:82) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642) at org.kohsuke.stapler.DiagnosticThreadNameFilter.doFilter(DiagnosticThreadNameFilter.java:30) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642) at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146) at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:524) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132) at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257) at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595) at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255) at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1340) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203) at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473) at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1564) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201) at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1242) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132) at org.eclipse.jetty.server.Server.handle(Server.java:503) at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:364) at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260) at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305) at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:333) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:310) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126) at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366) at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765) at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683) at java.base/java.lang.Thread.run(Thread.java:834)
Running from: /opt/deploy-box/jenkins/ear/jenkins.war webroot: System.getProperty("JENKINS_HOME") Jul 22, 2019 3:40:17 PM org.eclipse.jetty.util.log.Log initialized INFO: Logging initialized @1194ms to org.eclipse.jetty.util.log.JavaUtilLog Jul 22, 2019 3:40:17 PM winstone.Logger logInternal INFO: Beginning extraction from war file Jul 22, 2019 3:40:23 PM org.eclipse.jetty.server.handler.ContextHandler setContextPath WARNING: Empty contextPath Jul 22, 2019 3:40:23 PM org.eclipse.jetty.server.Server doStart INFO: jetty-9.4.z-SNAPSHOT; built: 2018-08-30T13:59:14.071Z; git: 27208684755d94a92186989f695db2d7b21ebc51; jvm 11.0.4+11-LTS Jul 22, 2019 3:40:24 PM org.eclipse.jetty.webapp.StandardDescriptorProcessor visitServlet INFO: NO JSP Support for /, did not find org.eclipse.jetty.jsp.JettyJspServlet Jul 22, 2019 3:40:25 PM org.eclipse.jetty.server.session.DefaultSessionIdManager doStart INFO: DefaultSessionIdManager workerName=node0 Jul 22, 2019 3:40:25 PM org.eclipse.jetty.server.session.DefaultSessionIdManager doStart INFO: No SessionScavenger set, using defaults Jul 22, 2019 3:40:25 PM org.eclipse.jetty.server.session.HouseKeeper startScavenging INFO: node0 Scavenging every 660000ms WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by com.thoughtworks.xstream.core.util.Fields (file:/opt/deploy-box/jenkins/war/WEB-INF/lib/xstream-1.4.7-jenkins-1.jar) to field java.util.TreeMap.comparator WARNING: Please consider reporting this to the maintainers of com.thoughtworks.xstream.core.util.Fields WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release Jenkins home directory: /opt/deploy-box/jenkins found at: SystemProperties.getProperty("JENKINS_HOME") Jul 22, 2019 3:40:26 PM org.eclipse.jetty.server.handler.ContextHandler doStart INFO: Started w.@713064e8{Jenkins v2.164.3,/,file:Jul 22, 2019 3:40:26 PM org.eclipse.jetty.server.AbstractConnector doStart INFO: Started ServerConnector@6ae3fb94{HTTP/1.1,[http/1.1]}{0.0.0.0:8080} Jul 22, 2019 3:40:26 PM org.eclipse.jetty.server.Server doStart INFO: Started @10315ms Jul 22, 2019 3:40:26 PM winstone.Logger logInternal INFO: Winstone Servlet Engine v4.0 running: controlPort=disabled Jul 22, 2019 3:40:27 PM jenkins.security.ClassFilterImpl register WARNING: All class filtering suppressed. Your Jenkins installation is at risk from known attacks. See https:Jul 22, 2019 3:40:27 PM jenkins.InitReactorRunner$1 onAttained INFO: Started initialization Jul 22, 2019 3:40:35 PM hudson.ClassicPluginStrategy createClassJarFromWebInfClasses WARNING: Created /opt/deploy-box/jenkins/plugins/built-on-column/WEB-INF/lib/classes.jar; update plugin to a version created with a newer harness Jul 22, 2019 3:40:36 PM hudson.ClassicPluginStrategy createClassJarFromWebInfClasses WARNING: Created /opt/deploy-box/jenkins/plugins/countjobs-viewstabbar/WEB-INF/lib/classes.jar; update plugin to a version created with a newer harness Jul 22, 2019 3:40:37 PM hudson.ClassicPluginStrategy createClassJarFromWebInfClasses WARNING: Created /opt/deploy-box/jenkins/plugins/discard-old-build/WEB-INF/lib/classes.jar; update plugin to a version created with a newer harness Jul 22, 2019 3:40:38 PM hudson.ClassicPluginStrategy createClassJarFromWebInfClasses WARNING: Created /opt/deploy-box/jenkins/plugins/dynamicparameter/WEB-INF/lib/classes.jar; update plugin to a version created with a newer harness Jul 22, 2019 3:40:40 PM hudson.ClassicPluginStrategy createClassJarFromWebInfClasses WARNING: Created /opt/deploy-box/jenkins/plugins/flexible-publish/WEB-INF/lib/classes.jar; update plugin to a version created with a newer harness Jul 22, 2019 3:40:41 PM hudson.ClassicPluginStrategy createClassJarFromWebInfClasses WARNING: Created /opt/deploy-box/jenkins/plugins/gradle/WEB-INF/lib/classes.jar; update plugin to a version created with a newer harness Jul 22, 2019 3:40:43 PM hudson.ClassicPluginStrategy createClassJarFromWebInfClasses WARNING: Created /opt/deploy-box/jenkins/plugins/ivy/WEB-INF/lib/classes.jar; update plugin to a version created with a newer harness Jul 22, 2019 3:40:45 PM hudson.ClassicPluginStrategy createClassJarFromWebInfClasses WARNING: Created /opt/deploy-box/jenkins/plugins/job-dsl/WEB-INF/lib/classes.jar; update plugin to a version created with a newer harness Jul 22, 2019 3:40:49 PM hudson.ClassicPluginStrategy createClassJarFromWebInfClasses WARNING: Created /opt/deploy-box/jenkins/plugins/page-markup/WEB-INF/lib/classes.jar; update plugin to a version created with a newer harness Jul 22, 2019 3:40:49 PM hudson.ClassicPluginStrategy createClassJarFromWebInfClasses WARNING: Created /opt/deploy-box/jenkins/plugins/permissive-script-security/WEB-INF/lib/classes.jar; update plugin to a version created with a newer harness Jul 22, 2019 3:40:49 PM hudson.ClassicPluginStrategy createClassJarFromWebInfClasses WARNING: Created /opt/deploy-box/jenkins/plugins/pipeline-aggregator-view/WEB-INF/lib/classes.jar; update plugin to a version created with a newer harness Jul 22, 2019 3:40:51 PM hudson.ClassicPluginStrategy createClassJarFromWebInfClasses WARNING: Created /opt/deploy-box/jenkins/plugins/postbuild-task/WEB-INF/lib/classes.jar; update plugin to a version created with a newer harness Jul 22, 2019 3:40:53 PM hudson.ClassicPluginStrategy createClassJarFromWebInfClasses WARNING: Created /opt/deploy-box/jenkins/plugins/slave-setup/WEB-INF/lib/classes.jar; update plugin to a version created with a newer harness Jul 22, 2019 3:40:54 PM hudson.ClassicPluginStrategy createClassJarFromWebInfClasses WARNING: Created /opt/deploy-box/jenkins/plugins/text-finder/WEB-INF/lib/classes.jar; update plugin to a version created with a newer harness Jul 22, 2019 3:40:58 PM jenkins.InitReactorRunner$1 onAttained INFO: Listed all plugins Jul 22, 2019 3:40:59 PM hudson.plugins.ansicolor.PluginImpl start INFO: AnsiColor: eliminating boring output (https:Jul 22, 2019 3:40:59 PM org.jenkinsci.plugins.scriptler.ScriptlerPluginImpl synchronizeConfig INFO: initialize scriptler Jul 22, 2019 3:41:14 PM org.jenkinsci.remoting.util.AnonymousClassWarnings warn WARNING: Attempt to (de-)serialize anonymous class hudson.plugins.disk_usage.DiskUsageProjectActionFactory$DescriptorImpl$1 in file:/opt/deploy-box/jenkins/plugins/disk-usage/WEB-INF/lib/disk-usage.jar; see: https:Jul 22, 2019 3:41:14 PM org.jenkinsci.remoting.util.AnonymousClassWarnings warn WARNING: Attempt to (de-)serialize anonymous class hudson.plugins.disk_usage.DiskUsageOvearallGraphGenerator$DiskUsageRecord$1 in file:/opt/deploy-box/jenkins/plugins/disk-usage/WEB-INF/lib/disk-usage.jar; see: https:Jul 22, 2019 3:41:15 PM jenkins.InitReactorRunner$1 onAttained INFO: Prepared all plugins Jul 22, 2019 3:41:15 PM jenkins.InitReactorRunner$1 onAttained INFO: Started all plugins Jul 22, 2019 3:41:20 PM jenkins.InitReactorRunner$1 onAttained INFO: Augmented all extensions Jul 22, 2019 3:41:20 PM hudson.ExtensionFinder$GuiceFinder$FaultTolerantScope$1 error WARNING: Failed to instantiate Key[type=jenkins.metrics.impl.VMMetricProviderImpl, annotation=[none]]; skipping this component com.google.inject.ProvisionException: Unable to provision, see the following errors: 1) Error injecting constructor, java.lang.reflect.InaccessibleObjectException: Unable to make public long com.sun.management.internal.OperatingSystemImpl.getProcessCpuTime() accessible: module jdk.management does not "opens com.sun.management.internal" to unnamed module @62dbb0e9 at jenkins.metrics.impl.VMMetricProviderImpl.<init>(VMMetricProviderImpl.java:61) 1 error at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:52) at com.google.inject.internal.SingletonScope$1.get(SingletonScope.java:145) at hudson.ExtensionFinder$GuiceFinder$FaultTolerantScope$1.get(ExtensionFinder.java:440) at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:41) at com.google.inject.internal.InjectorImpl$2$1.call(InjectorImpl.java:1016) at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1092) at com.google.inject.internal.InjectorImpl$2.get(InjectorImpl.java:1012) at hudson.ExtensionFinder$GuiceFinder._find(ExtensionFinder.java:402) at hudson.ExtensionFinder$GuiceFinder.find(ExtensionFinder.java:393) at hudson.ClassicPluginStrategy.findComponents(ClassicPluginStrategy.java:335) at hudson.ExtensionList.load(ExtensionList.java:380) at hudson.ExtensionList.ensureLoaded(ExtensionList.java:318) at hudson.ExtensionList.iterator(ExtensionList.java:172) at jenkins.metrics.api.Metrics.afterExtensionsAugmented(Metrics.java:335) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at hudson.init.TaskMethodFinder.invoke(TaskMethodFinder.java:104) at hudson.init.TaskMethodFinder$TaskImpl.run(TaskMethodFinder.java:175) at org.jvnet.hudson.reactor.Reactor.runTask(Reactor.java:296) at jenkins.model.Jenkins$5.runTask(Jenkins.java:1096) at org.jvnet.hudson.reactor.Reactor$2.run(Reactor.java:214) at org.jvnet.hudson.reactor.Reactor$Node.run(Reactor.java:117) 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:834) Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make public long com.sun.management.internal.OperatingSystemImpl.getProcessCpuTime() accessible: module jdk.management does not "opens com.sun.management.internal" to unnamed module @62dbb0e9 at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:340) at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:280) at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:198) at java.base/java.lang.reflect.Method.setAccessible(Method.java:192) at jenkins.metrics.impl.VMMetricProviderImpl$CpuUsageGauge.<init>(VMMetricProviderImpl.java:226) at jenkins.metrics.impl.VMMetricProviderImpl.<init>(VMMetricProviderImpl.java:71) at jenkins.metrics.impl.VMMetricProviderImpl$$FastClassByGuice$$bd4f8b03.newInstance(<generated>) at com.google.inject.internal.cglib.reflect.$FastConstructor.newInstance(FastConstructor.java:40) at com.google.inject.internal.DefaultConstructionProxyFactory$1.newInstance(DefaultConstructionProxyFactory.java:61) at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:105) at com.google.inject.internal.ConstructorInjector.access$000(ConstructorInjector.java:32) at com.google.inject.internal.ConstructorInjector$1.call(ConstructorInjector.java:89) at com.google.inject.internal.ProvisionListenerStackCallback$Provision.provision(ProvisionListenerStackCallback.java:115) at hudson.ExtensionFinder$GuiceFinder$SezpozModule.onProvision(ExtensionFinder.java:567) at com.google.inject.internal.ProvisionListenerStackCallback$Provision.provision(ProvisionListenerStackCallback.java:126) at com.google.inject.internal.ProvisionListenerStackCallback.provision(ProvisionListenerStackCallback.java:68) at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:87) at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:267) at com.google.inject.internal.ProviderToInternalFactoryAdapter$1.call(ProviderToInternalFactoryAdapter.java:46) at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1103) at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:40) ... 26 more Jul 22, 2019 3:41:21 PM jenkins.model.Jenkins setBuildsAndWorkspacesDir INFO: Using non default workspaces directories: ${JENKINS_HOME}/workspace/${ITEM_FULLNAME}. Jul 22, 2019 3:41:22 PM jenkins.InitReactorRunner$1 onAttained INFO: Loaded all jobs Jul 22, 2019 3:41:22 PM hudson.model.AsyncPeriodicWork$1 run INFO: Started Download metadata Jul 22, 2019 3:41:22 PM jenkins.util.groovy.GroovyHookScript execute INFO: Executing /opt/deploy-box/jenkins/init.groovy.d/approve_scripts.groovy Jul 22, 2019 3:41:22 PM hudson.model.AllView migrateLegacyPrimaryAllViewLocalizedName INFO: JENKINS-38606 detected for AllView in hudson.model.Hudson@4ac99ffa; renaming view from All to all Jul 22, 2019 3:41:22 PM jenkins.install.UpgradeWizard applyForcedChanges INFO: New API token system configured with insecure options to keep legacy behavior Jul 22, 2019 3:41:22 PM hudson.model.DownloadService$Downloadable load INFO: Obtained the updated data file for hudson.tasks.Maven.MavenInstaller Jul 22, 2019 3:41:22 PM hudson.model.DownloadService$Downloadable load INFO: Obtained the updated data file for hudson.tasks.Ant.AntInstaller Jul 22, 2019 3:41:23 PM hudson.model.DownloadService$Downloadable load INFO: Obtained the updated data file for hudson.plugins.gradle.GradleInstaller Jul 22, 2019 3:41:23 PM hudson.model.DownloadService$Downloadable load INFO: Obtained the updated data file for hudson.plugins.groovy.GroovyInstaller Jul 22, 2019 3:41:24 PM hudson.model.DownloadService$Downloadable load INFO: Obtained the updated data file for hudson.tools.JDKInstaller Jul 22, 2019 3:41:24 PM hudson.model.DownloadService$Downloadable load INFO: Obtained the updated data file for org.jenkinsci.plugins.scriptler.CentralScriptJsonCatalog Jul 22, 2019 3:41:24 PM hudson.model.AsyncPeriodicWork$1 run INFO: Finished Download metadata. 2,309 ms Script Approval approve all Set permissive-script-security.enabled=true and set level log for this plugin Jul 22, 2019 3:41:24 PM jenkins.util.groovy.GroovyHookScript execute INFO: Executing /opt/deploy-box/jenkins/init.groovy.d/set_global_variables.groovy Jul 22, 2019 3:41:25 PM jenkins.InitReactorRunner$1 onAttained INFO: Completed initialization Jul 22, 2019 3:41:25 PM jenkins.plugins.mattermost.MattermostNotifier$Migrator onLoaded INFO: Starting Settings Migration Process Jul 22, 2019 3:41:25 PM hudson.WebAppMain$3 run INFO: Jenkins is fully up and running Jul 22, 2019 3:41:32 PM hudson.model.AsyncAperiodicWork$1 run INFO: Started Update IdP Metadata from URL PeriodicWork Jul 22, 2019 3:41:32 PM hudson.model.AsyncAperiodicWork$1 run INFO: Finished Update IdP Metadata from URL PeriodicWork. 3 ms javax.net.ssl|DEBUG|12|Handling GET / from 10.255.0.2 : qtp1256440269-18 View/index.jelly AdministrativeMonitorsDecorator/footer.jelly|2019-07-22 15:42:52.244 CEST|SSLCipher.java:437|jdk.tls.keyLimits: entry = AES/GCM/NoPadding KeyUpdate 2^37. AES/GCM/NOPADDING:KEYUPDATE = 137438953472 javax.net.ssl|WARNING|6A|Thread-22|2019-07-22 15:44:05.793 CEST|SignatureScheme.java:282|Signature algorithm, ed25519, is not supported by the underlying providers javax.net.ssl|WARNING|6A|Thread-22|2019-07-22 15:44:05.794 CEST|SignatureScheme.java:282|Signature algorithm, ed448, is not supported by the underlying providers javax.net.ssl|INFO|6A|Thread-22|2019-07-22 15:44:05.800 CEST|AlpnExtension.java:161|No available application protocols javax.net.ssl|DEBUG|6A|Thread-22|2019-07-22 15:44:05.800 CEST|SSLExtensions.java:257|Ignore, context unavailable extension: application_layer_protocol_negotiation javax.net.ssl|DEBUG|6A|Thread-22|2019-07-22 15:44:05.801 CEST|SSLExtensions.java:257|Ignore, context unavailable extension: cookie javax.net.ssl|DEBUG|6A|Thread-22|2019-07-22 15:44:05.827 CEST|SSLExtensions.java:257|Ignore, context unavailable extension: renegotiation_info javax.net.ssl|DEBUG|6A|Thread-22|2019-07-22 15:44:05.827 CEST|PreSharedKeyExtension.java:633|No session to resume. javax.net.ssl|DEBUG|6A|Thread-22|2019-07-22 15:44:05.827 CEST|SSLExtensions.java:257|Ignore, context unavailable extension: pre_shared_key javax.net.ssl|DEBUG|6A|Thread-22|2019-07-22 15:44:05.831 CEST|ClientHello.java:653|Produced ClientHello handshake message ( "ClientHello": { "client version" : "TLSv1.2", "random" : "5C 46 C8 E6 96 5A 9E DD E6 2A 17 06 8D A3 1E 36 48 22 51 6A 86 E8 28 D9 04 5B A7 69 77 91 52 8C", "session id" : "04 1E 46 4F 3E EF 62 E6 76 B8 1D A4 CA C1 37 F9 43 09 66 D8 90 8F 84 96 AE FF B5 BA F4 4D E3 22", "cipher suites" : "[TLS_AES_128_GCM_SHA256(0x1301), TLS_AES_256_GCM_SHA384(0x1302), TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384(0xC02C), TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256(0xC02B), TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384(0xC030), TLS_RSA_WITH_AES_256_GCM_SHA384(0x009D), TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384(0xC02E), TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384(0xC032), TLS_DHE_RSA_WITH_AES_256_GCM_SHA384(0x009F), TLS_DHE_DSS_WITH_AES_256_GCM_SHA384(0x00A3), TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256(0xC02F), TLS_RSA_WITH_AES_128_GCM_SHA256(0x009C), TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256(0xC02D), TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256(0xC031), TLS_DHE_RSA_WITH_AES_128_GCM_SHA256(0x009E), TLS_DHE_DSS_WITH_AES_128_GCM_SHA256(0x00A2), TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384(0xC024), TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384(0xC028), TLS_RSA_WITH_AES_256_CBC_SHA256(0x003D), TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384(0xC026), TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384(0xC02A), TLS_DHE_RSA_WITH_AES_256_CBC_SHA256(0x006B), TLS_DHE_DSS_WITH_AES_256_CBC_SHA256(0x006A), TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA(0xC00A), TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA(0xC014), TLS_RSA_WITH_AES_256_CBC_SHA(0x0035), TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA(0xC005), TLS_ECDH_RSA_WITH_AES_256_CBC_SHA(0xC00F), TLS_DHE_RSA_WITH_AES_256_CBC_SHA(0x0039), TLS_DHE_DSS_WITH_AES_256_CBC_SHA(0x0038), TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256(0xC023), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256(0xC027), TLS_RSA_WITH_AES_128_CBC_SHA256(0x003C), TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256(0xC025), TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256(0xC029), TLS_DHE_RSA_WITH_AES_128_CBC_SHA256(0x0067), TLS_DHE_DSS_WITH_AES_128_CBC_SHA256(0x0040), TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA(0xC009), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA(0xC013), TLS_RSA_WITH_AES_128_CBC_SHA(0x002F), TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA(0xC004), TLS_ECDH_RSA_WITH_AES_128_CBC_SHA(0xC00E), TLS_DHE_RSA_WITH_AES_128_CBC_SHA(0x0033), TLS_DHE_DSS_WITH_AES_128_CBC_SHA(0x0032), TLS_EMPTY_RENEGOTIATION_INFO_SCSV(0x00FF)]", "compression methods" : "00", "extensions" : [ "status_request (5)": { "certificate status type": ocsp "OCSP status request": { "responder_id": <empty> "request extensions": { <empty> } } }, "supported_groups (10)": { "versions": [secp256r1, secp384r1, secp521r1, sect283k1, sect283r1, sect409k1, sect409r1, sect571k1, sect571r1, secp256k1, ffdhe2048, ffdhe3072, ffdhe4096, ffdhe6144, ffdhe8192] }, "ec_point_formats (11)": { "formats": [uncompressed] }, "signature_algorithms (13)": { "signature schemes": [ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384, ecdsa_secp512r1_sha512, rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512, rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512, dsa_sha256, ecdsa_sha224, rsa_sha224, dsa_sha224, ecdsa_sha1, rsa_pkcs1_sha1, dsa_sha1] }, "signature_algorithms_cert (50)": { "signature schemes": [ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384, ecdsa_secp512r1_sha512, rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512, rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512, dsa_sha256, ecdsa_sha224, rsa_sha224, dsa_sha224, ecdsa_sha1, rsa_pkcs1_sha1, dsa_sha1] }, "status_request_v2 (17)": { "cert status request": { "certificate status type": ocsp_multi "OCSP status request": { "responder_id": <empty> "request extensions": { <empty> } } } }, "extended_master_secret (23)": { <empty> }, "supported_versions (43)": { "versions": [TLSv1.3, TLSv1.2, TLSv1.1, TLSv1] }, "psk_key_exchange_modes (45)": { "ke_modes": [psk_dhe_ke] }, "key_share (51)": { "client_shares": [ { "named group": secp256r1 "key_exchange": { 0000: 04 83 84 8A F6 9C 23 D6 E0 D7 04 F6 AB 5E EA 3A ......#......^.: 0010: 4A F5 68 3A EF 01 1B D1 C8 4C 98 E2 FE 38 91 3A J.h:.....L...8.: 0020: FB 35 61 9D 0A 8B F9 6D A5 78 52 77 26 A6 4D A1 .5a....m.xRw&.M. 0030: F8 1A 8F C8 68 0E 18 FF B1 AC 4B 5F A6 DD A7 73 ....h.....K_...s 0040: 4E } }, ] } ] } ) javax.net.ssl|ERROR|6A|Thread-22|2019-07-22 15:44:05.836 CEST|TransportContext.java:312|Fatal (HANDSHAKE_FAILURE): Couldn't kickstart handshaking ( "throwable" : { javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake at java.base/sun.security.ssl.SSLSocketImpl.handleEOF(SSLSocketImpl.java:1322) at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1160) at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1063) at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:402) at java.base/sun.security.ssl.SSLSocketImpl.ensureNegotiated(SSLSocketImpl.java:716) at java.base/sun.security.ssl.SSLSocketImpl$AppInputStream.read(SSLSocketImpl.java:799) at java.base/java.io.BufferedInputStream.fill(BufferedInputStream.java:252) at java.base/java.io.BufferedInputStream.read1(BufferedInputStream.java:292) at java.base/java.io.BufferedInputStream.read(BufferedInputStream.java:351) at java.naming/com.sun.jndi.ldap.Connection.run(Connection.java:832) at java.base/java.lang.Thread.run(Thread.java:834) Caused by: java.io.EOFException: SSL peer shut down incorrectly at java.base/sun.security.ssl.SSLSocketInputRecord.decode(SSLSocketInputRecord.java:167) at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:108) at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1152) ... 9 more} ) javax.net.ssl|DEBUG|6A|Thread-22|2019-07-22 15:44:05.837 CEST|SSLSocketImpl.java:1362|close the underlying socket javax.net.ssl|DEBUG|6A|Thread-22|2019-07-22 15:44:05.837 CEST|SSLSocketImpl.java:1381|close the SSL connection (initiative)
#java #rest #ssl #jersey #jersey-client
#java #rest #ssl #джерси #джерси-клиент
Вопрос:
Я использую Jersey-client-2.27, через который вызывается вызов https get, как показано ниже:
Client client = ClientBuilder.newClient();
return client.target(url)
.request(MediaType.APPLICATION_JSON)
.header("authorization", token)
.get(String.class);
Получение исключения ниже один раз при каждых 10-15 обращениях к методу клиента get():
"status":500,
"reason":"Internal Server Error",
"code":0,
"message":
javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake
javax.ws.rs.ProcessingException: javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake
at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:284)
at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:278)
at org.glassfish.jersey.client.JerseyInvocation.lambda$invoke$1(JerseyInvocation.java:767)
at org.glassfish.jersey.internal.Errors.process(Errors.java:316)
at org.glassfish.jersey.internal.Errors.process(Errors.java:298)
at org.glassfish.jersey.internal.Errors.process(Errors.java:229)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:414)
at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:765)
at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:428)
at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:324)
Что может быть причиной частого сбоя вызова API, особенно во время нагрузочного тестирования, и как я могу это устранить? Я уже пробовал игнорировать SSL-сертификат и добавлять сертификат x509 при отправке запроса
Комментарии:
1. Не похоже, что ваш клиент делает что-то не так. Вам нужно будет просмотреть журналы на сервере, чтобы выяснить, почему он прерывает соединение.
2. Я не видел никаких ошибок в журналах сервера. Похоже, что сам клиент потерпел неудачу при общении.
If you are working with Docker containers and facing the error javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake
, don’t worry! This article will guide you through the steps to fix this error.
Understanding the Error
Before we dive into the solution, let’s try to understand what this error means. The javax.net.ssl.SSLHandshakeException
error occurs when a secure connection fails during an SSL handshake. The Remote host terminated the handshake
message indicates that the other end of the connection closed the connection unexpectedly, leading to the SSL handshake failure.
Possible Causes
There are several reasons why this error might occur. Here are some of the most common causes:
-
Invalid SSL/TLS Certificate: If the SSL/TLS Certificate used by the remote host is not valid or expired, the SSL handshake will fail.
-
Firewall Restrictions: Sometimes, firewall restrictions can block SSL/TLS connections.
-
Client and Server Time Sync Issue: If the time on the client and server machines are not in sync, the SSL handshake might fail.
-
Outdated Java Version: Older versions of Java might not be compatible with the TLS/SSL version used by the remote host.
Solution
Now that we have identified the possible causes, here are some steps you can follow to fix the error:
Step 1: Check SSL/TLS Certificate
The first step is to check the SSL/TLS certificate of the remote host. Make sure that the certificate is valid and not expired. You can check the certificate details by using the openssl
command.
openssl s_client -connect <remote_host>:<port>
Replace <remote_host>
and <port>
with the hostname and port number of the remote host, respectively. If the certificate is not valid, you need to get a new one.
Step 2: Check Firewall Restrictions
Make sure that your firewall is not blocking the SSL/TLS connection. You can temporarily disable the firewall and check if the error still persists. If the error goes away, then you need to allow SSL/TLS traffic through the firewall.
Step 3: Check Time Sync
Make sure that the time on both the client and server machines are in sync. You can synchronize the time by using the ntpdate
command.
sudo ntpdate <ntp_server>
Replace <ntp_server>
with the NTP server of your choice.
Step 4: Update Java
If you are using an older version of Java, update it to the latest version. The latest version of Java should be compatible with the TLS/SSL version used by the remote host.
Conclusion
In conclusion, the javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake
error can be fixed by checking the SSL/TLS certificate, firewall restrictions, time sync, and updating Java. Follow these steps, and you should be able to resolve the error and continue working with Docker containers without any issues!
I’m running a local TCP server in C++ on Windows via OpenSSL and Windows sockets. I’m running the client in Java using SSL sockets. For most users this setup is working, however, some users run into the following Java exception upon attempting the SSL handshake:
javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake
at sun.security.ssl.SSLSocketImpl.handleEOF(Unknown Source) ~[?:1.8.0_321]
at sun.security.ssl.SSLSocketImpl.decode(Unknown Source) ~[?:1.8.0_321]
at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(Unknown Source) ~[?:1.8.0_321]
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source) ~[?:1.8.0_321]
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source) ~[?:1.8.0_321]
...
Caused by: java.io.EOFException: SSL peer shut down incorrectly
at sun.security.ssl.SSLSocketInputRecord.read(Unknown Source) ~[?:1.8.0_321]
at sun.security.ssl.SSLSocketInputRecord.readHeader(Unknown Source) ~[?:1.8.0_321]
at sun.security.ssl.SSLSocketInputRecord.decode(Unknown Source) ~[?:1.8.0_321]
at sun.security.ssl.SSLTransport.decode(Unknown Source) ~[?:1.8.0_321]
... 10 more
My client socket code in Java looks like this:
public static Socket getClientSocket() throws Exception
{
InetSocketAddress socketAddress = new InetSocketAddress("localhost", 54321);
SSLSocketFactory socketFactory = getSSLSocketFactory();
Socket clientSocket = socketFactory.createSocket();
clientSocket.connect(socketAddress, 1_000);
((SSLSocket) clientSocket).startHandshake(); // <-- Exception here for some users
return clientSocket;
}
private static SSLSocketFactory getSSLSocketFactory() throws Exception
{
// Create a trust manager that does not validate certificate chains
X509TrustManager trustManager = new X509TrustManager()
{
@Override
public X509Certificate[] getAcceptedIssuers()
{
// TODO Returning null is not allowed but it still works
return null;
}
@Override
public void checkClientTrusted(final X509Certificate[] certificates, final String authType)
{
}
@Override
public void checkServerTrusted(final X509Certificate[] certificates, final String authType)
{
for (X509Certificate certificate : certificates)
{
String certificateString = certificate.toString();
if (!certificateString.contains("blablabla"))
{
throw new SSLException("Certificate not trusted");
}
}
}
};
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]{trustManager}, new SecureRandom());
return sslContext.getSocketFactory();
}
Attempted solutions:
- Calling
System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2")
before connecting did not work (reference) - I do not want to tell users to import any SSL certificates into their truststore (unless I can automate this easily)
Where does the inconsistent behavior come from and how to fix it cleanly for everyone who gets the exception? I have access to the server source code and certificates. Also any critical questions or suggestions are welcome. I can provide more information if necessary.
javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake
at java.base/sun.security.ssl.SSLSocketImpl.handleEOF(SSLSocketImpl.java:1616)
at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1434)
at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1336)
at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:450)
at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:421)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:436)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:384)
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:376)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
at com.tabnine.logging.TabnineLogDispatcher$dispatchLog$1.run(TabnineLogDispatcher.kt:40)
at com.intellij.openapi.application.impl.ApplicationImpl$1.run(ApplicationImpl.java:263)
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.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:668)
at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:665)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(Executors.java:665)
at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.io.EOFException: SSL peer shut down incorrectly
at java.base/sun.security.ssl.SSLSocketInputRecord.read(SSLSocketInputRecord.java:483)
at java.base/sun.security.ssl.SSLSocketInputRecord.readHeader(SSLSocketInputRecord.java:472)
at java.base/sun.security.ssl.SSLSocketInputRecord.decode(SSLSocketInputRecord.java:160)
at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:111)
at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1426)
... 26 more
When I perform a load testing to my website over HTTPS, I received multiples errors related with SSL Handshake when I simulate a high amount of concurrent users (>500 / sec).
Here are the errors that I received:
Error #1
javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake
Error #2
javax.net.ssl.SSLException: Socket closed
Error #3
javax.net.ssl.SSLException: Read timed out
The thing is, everything is managed by the GCP, especially with the Load Balancer where my front-end is HTTPS associated with a valid certificate.
Also, the capacity of my back-end seems high enough to support everything. It is like the bottleneck is my Load Balancer.
The tests are made directly from my computer using JMeter.
So, what cause this problem and how can I fix it?
SSLHandshakeException
appear in logs when there is some error occurred while validating the certificate installed in the client machine with a certificate on the server machine. In this post, we will learn about fixing this if you are using the Apache HttpClient library to create HttpClient to connect to SSL/TLS-secured URLs.
1. Problem
The exception logs will look like this.
Caused by: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:980) ... ... Caused by: java.io.EOFException: SSL peer shut down incorrectly at sun.security.ssl.InputRecord.read(InputRecord.java:505) ... ...
I have already posted a code fix to bypass SSL matching in an earlier post.
Unfortunately, that fix works in TLS
and TLS 1.1
protocols. It doesn’t work in TLS 1.2
protocol. So ultimately, you need to fix the certificate issue anyway. There is a ‘no code only’ fix for this.
2. Solution
Now there are two ways, you can utilize the imported certificate from the server. Either add the certificate to the JDK cacerts store; or pass certificate information in JVM arguments.
2.1. Import certificate to JDK cacert Store
Import the certificate from the server.
Use the given command to add the certificate to JDK store. (Remove new line characters).
keytool -import
-noprompt
-trustcacerts
-alias MAVEN-ROOT
-file C:/Users/Lokesh/keys/cert/maven.cer
-keystore "C:/Program Files (x86)/Java/jdk8/jre/lib/security/cacerts"
-storepass changeit
Now create the HttpClient as given:
public HttpClient createTlsV2HttpClient() throws KeyManagementException,
UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
SSLConnectionSocketFactory f = new SSLConnectionSocketFactory(sslContext, new String[] { "TLSv1.2" }, null,
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", f)
.build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
CloseableHttpClient client = HttpClients
.custom()
.setSSLSocketFactory(f)
.setConnectionManager(cm)
.build();
return client;
}
Notice the code : SSLContext.getInstance("TLSv1.2")
. This code picks up the certificates added to JDK cacert store
. So make a note of it.
2.2. Pass certificate information in JVM aruguments
Import the certificate from the server.
Add JVM arguments while starting the server. Change the parameter values as per your application.
-Djavax.net.ssl.keyStore="C:/Users/Lokeshkeysmaven.jks"
-Djavax.net.ssl.keyStorePassword="test"
-Djavax.net.ssl.trustStore="C:/Users/Lokeshkeysmaven.jks"
-Djavax.net.ssl.trustStorePassword="test"
Now create an HTTP client as given:
public HttpClient createTlsV2HttpClient() throws KeyManagementException,
UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {
SSLContext sslContext = SSLContexts.createSystemDefault();
SSLConnectionSocketFactory f = new SSLConnectionSocketFactory(sslContext, new String[] { "TLSv1.2" }, null,
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", f)
.build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
CloseableHttpClient client = HttpClients
.custom()
.setSSLSocketFactory(f)
.setConnectionManager(cm)
.build();
return client;
}
Notice the code : SSLContext.createSystemDefault()
. This code picks up the certificates passed as JVM arguments. Again, make a note of it.
3. Conclusion
- Use
SSLContext.getInstance("TLSv1.2")
when the certificate is added to JDK cacert store. - Use
SSLContext.createSystemDefault()
when SSL info is passed as JVM argument.
Drop me your questions in the comments section.
Happy Learning !!
[WEBINAR] Clean Code Principles and Practices — JUNE 21ST
Register Now