Skip to content

TLS v1.3 Fallback for JDK bug#1149

Merged
SylvainJuge merged 10 commits intoelastic:masterfrom
SylvainJuge:tls13-fallback
Apr 23, 2020
Merged

TLS v1.3 Fallback for JDK bug#1149
SylvainJuge merged 10 commits intoelastic:masterfrom
SylvainJuge:tls13-fallback

Conversation

@SylvainJuge
Copy link
Member

@SylvainJuge SylvainJuge commented Apr 21, 2020

What does this PR do?

This PR implements a fallback for #1080

TLS 1.3 has been added in JDK 11, but due to a JDK bug (JDK-8236039), it can't be used in affected versions.

By default, there is no fallback on other versions of the protocol, even if those are both available and supported by the remote server.

This PR implements the following fallback:

  • applied only when SSL socket handshake fails with a known error type & message pattern and TLS v1.3 protocol is enabled.
  • creates a new socket without TLS v1.3 and restarts handshake.

When applied, the following warning is present in agent log:

WARN co.elastic.apm.agent.report.ssl.TLSFallbackSSLSocket - Workaround for JDK Bug JDK-8236039 applied, will connect without TLS v1.3

Checklist

  • My code follows the style guidelines of this project
  • I have rebased my changes on top of the latest master branch
  • I have made corresponding changes to the documentation
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have updated CHANGELOG.asciidoc
  • I have updated supported-technologies.asciidoc
  • Added an API method or config option? Document in which version this will be introduced
  • Added an instrumentation plugin? How did you make sure that old, non-supported versions are not instrumented by accident?

Author's Checklist

  • manual testing with affected JDK (11.0.5)
  • manual testing with unaffected JDK (8.0.x)

Related issues

@SylvainJuge SylvainJuge requested a review from felixbarny April 21, 2020 13:07
Set<String> enabledProtocols = new HashSet<>(Arrays.asList(socket.getEnabledProtocols()));
if (enabledProtocols.contains(TLS_v_1_3) && e.getMessage().contains("should not be presented in")) {

logger.warn("Workaround for JDK Bug JDK-8236039 applied, will connect without TLS v1.3");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like we're re-triggering this exception for every request to APM Server, right? Could we exclude TLSv1.3 if we know it triggers the bug on the current JVM?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe also suggest the user what to do when the exception occurs, like updating the JDK, or removing 1.3 for the server's setting (https://www.elastic.co/guide/en/apm/server/current/agent-server-ssl.html#_supported_protocols_2).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with both comments, having a single warning is better, and an actionable message is definitely better than having to deal with that in an FAQ somewhere :-).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, there would be the option to disable TLS 1.3 client side, but that would impact the whole JVM, or provide a configuration for agent, which implies some extra complexity for documentation/support.

}

private static void tlsFallback(HttpsURLConnection connection) {
SSLSocketFactory newFactory = SslUtils.getTLSFallbackSocketFactory(connection.getSSLSocketFactory());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we create our own SSLSocketFactory from scratch?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean, why do we wrap the default SSLSocketFactory where we could just have created a new one ?

For me that's just a way to make sure that our implementation does not introduce obvious security bugs or unexpected behaviors here. Also, the default implementation is not public thus we can't inherit from it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SylvainJuge and others added 2 commits April 22, 2020 14:03
…LSFallbackSSLSocket.java

Co-Authored-By: Felix Barnsteiner <felixbarny@users.noreply.github.com>
@SylvainJuge SylvainJuge self-assigned this Apr 23, 2020
@SylvainJuge SylvainJuge merged commit 3c4f6e0 into elastic:master Apr 23, 2020
@SylvainJuge SylvainJuge deleted the tls13-fallback branch April 23, 2020 12:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants