AWS Open Source Blog

TLS 1.0/1.1 changes in OpenJDK and Amazon Corretto

Starting on April 20, 2021, quarterly update releases of OpenJDK are disabling TLS1.0 and TLS1.1 availability by default in all versions of OpenJDK. Amazon Corretto will be keeping TLS1.0 and TLS1.1 available by default for a while longer. Feedback from customers and industry partners suggests that this deprecation has the potential to cause outages, so Amazon will be giving Corretto users a chance to audit their usage of TLS and take necessary measures before disabling these older protocols. This post describes the situation in more detail, explains how to re-enable older TLS versions on non-Corretto distributions if necessary, and provides ideas for auditing traffic.

What is the change in OpenJDK?

OpenJDK will be disabling TLS 1.0 and 1.1 availability by default in the security.properties file. Java applications using TLS to communicate will need to use TLS 1.2 or above to establish a connection. The change will apply to at least OpenJDK 8u292 onward, OpenJDK 11.0.11 onward, and all versions of OpenJDK 16, following the JRE and JDK Crypto Roadmap published by Oracle.

Affected OpenJDK versions:

Version Release number
OpenJDK 8 8u292 and newer
OpenJDK 11 11.0.11 and newer
OpenJDK 16 and above All versions

Applications that update to a JDK with this change may see outages if they are currently using TLS 1.0/1.1, either to connect to endpoints that don’t support at least TLS 1.2 (client scenario) or serving traffic to clients that don’t support TLS 1.2 (server scenario). Affected apps can re-enable these versions of TLS because they aren’t being removed from the JDK. Only their availability by default is changing.

What is happening in AWS?

As explained by AWS VP/Distinguished Engineer Colm MacCárthaigh in his blog post Java, Scala, Kotlin and TLS1.0 / TLS1.1, at AWS “every service has long supported at least TLS1.2 and this change won’t impact communication to or from those services.” We believe that applications serving traffic to web browsers will also be covered because all popular browsers support TLS1.2 and are themselves working to deprecate TLS1.0 and TLS1.1. However, according to MacCárthaigh, this change has the potential to cause outages in “non-cloud networks like co-lo and on-premises datacenters, or on industrial and home networks, where it’s not uncommon to encounter legacy appliances and applications that haven’t been, or can’t be updated to support TLS1.2.”

We will be postponing this change in Corretto to give users time to audit their systems and decide whether they need to take action in their own installations. After researching the matter, we believe that the risk of outages is not negligible, and we are calling out the risk to our Corretto users to let them evaluate their situations and decide on next steps.

We suggest a couple of ways for auditing traffic below and we will continue to work on a better way that we will publish here soon.

Amazon Linux, AWS Lambda, and AWS CodeBuild will also continue to support TLS1.0 and TLS1.1 in OpenJDK.

What is Amazon’s position on TLS1.0 and TLS1.1?

We agree that TLS1.0 and TLS1.1 should continue to be removed from the ecosystem. As MacCárthaigh says, “TLS1.2 and TLS1.3 are unambiguously better than TLS1.0 and TLS1.1.”

The IETF (Internet Engineering Task Force) has released a draft document officially deprecating these versions, which is expected to publish during 2021. As mentioned previously, browsers are also working to deprecate them.

Allowing TLS1.0 and TLS1.1 connections to be established, however, doesn’t currently present a realistic security threat, so we believe this temporary measure to prioritize application stability is the right decision. MacCárthaigh’s post goes into detail about the security aspects of running TLS1.0 and 1.1.

These decisions are subject to change if and when new information comes to light.

How do I re-enable TLS1.0 and TLS1.1 in JDK distributions other than Corretto?

The good news is that re-enabling these versions is straightforward. First, locate your java.security configuration file located in the jre/lib/security folder for OpenJDK 8 or conf/security for OpenJDK 11 and higher. If you are unfamiliar with this file, you can take a look at the current version in Corretto 11 on GitHub. From here are two options.

Option 1 (preferred): First, ensure the security.overridePropertiesFile value in the java.security file is set to true (this is usually the default value). Then, take the following steps:

  • Create a file named enableLegacyTLS.security.
  • In that file, add an entry for jdk.tls.disabledAlgorithms with the same contents as the jdk.tls.disabledAlgorithms property in the java.security file.
  • Remove TLSv1 and/or TLSv1.1 from the list on the enableLegacyTLS.security. (You can see this line in the Corretto GitHub).
  • Start your application with -Djava.security.properties=path/to/enableLegacyTLS.security.

Alternatively, you can edit this value in the java.security file directly. Search for the property jdk.tls.disabledAlgorithms. For OpenJDK 11, its contents will be similar to:

jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA, \
 DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \
 include jdk.disabled.namedCurves

By removing the TLSv1.1 and/or TLSv1 entries (in bold above), you can re-establish those versions back to the list of usable versions within the JDK.

To make your Corretto configuration more restrictive, perform similar steps adding “TLSv1, TLSv1.1″ to the jdk.tls.disabledAlgorithms property.

How do I audit my systems?

We can suggest two imperfect methods that will help get information on what applications are doing. They both impact system performance, so you may want to do them on a single server in your fleet to get an idea of percentages rather than count each connection.

Option 1: Using JDK SSL debug logging

The JDK has the ability to log detailed information about the TLS connection. This log will contain the exact version of TLS that is negotiated among all the data it generates. This method requires restarting your server and turning on logging by passing the following parameter to the Java command:

-Djavax.net.debug=ssl,handshake

The log lines identifying the TLS version used look like the following.

If you are using OpenJDK/Corretto 11:

javax.net.ssl|DEBUG|01|main|2021-04-13 12:20:08.055 PDT|ServerHello.java:968|Negotiated protocol version: TLSv1
javax.net.ssl|DEBUG|01|main|2021-04-13 12:20:27.061 PDT|ServerHello.java:968|Negotiated protocol version: TLSv1.1
javax.net.ssl|DEBUG|01|main|2021-04-13 12:20:47.574 PDT|ServerHello.java:968|Negotiated protocol version: TLSv1.2

If you are using OpenJDK/Corretto 8:

javax.net.ssl|FINE|01|main|2021-04-13 12:27:59.841 PDT|Logger.java:765|Negotiated protocol version: TLSv1
javax.net.ssl|FINE|01|main|2021-04-13 12:28:29.046 PDT|Logger.java:765|Negotiated protocol version: TLSv1.1
javax.net.ssl|FINE|01|main|2021-04-13 12:28:34.479 PDT|Logger.java:765|Negotiated protocol version: TLSv1.2

If you capture this log to a file for a given period of time, you can get a summary using a command like the following (on Linux/Mac):

-> cat example.log| grep "Negotiated protocol" | cut -d"|" -f7- | sort | uniq -c
     37 Negotiated protocol version: TLSv1
      6 Negotiated protocol version: TLSv1.1
     87 Negotiated protocol version: TLSv1.2

On Windows, you can use the following PowerShell command:

gc example.log | ?{$_ -like "*Negotiated Protocol*"} | %{$_.split(":")[4]} | sort | group | select Name, Count

Option 2 (on Linux): Using tcpdump

tcpdump allows you to get information from an already running server, without needing to restart. The drawback is that it will put your NIC in a non-performant mode and won’t be able to distinguish which connections are from your JVM, so you may end up with incorrect data if other services are running on that machine.

We will capture all TLS handshakes and be able to count how many of those are TLS 1.0 and 1.1 using the following command:

sudo tcpdump -C 100 -W 5  "tcp[((tcp[12] & 0xf0) >> 2)] = 0x16 && tcp[((tcp[12] & 0xf0) >> 2) + 1] = 0x03 && tcp[((tcp[12] & 0xf0) >> 2) + 5] = 0x02" -w output.pcap

Here is the breakdown of what that command is doing:

  • sudo tcpdump: Privileged permissions are required for capturing traffic.
  • -C 100: Limit the file size to 100 MB; after that size is reached, rotate to a new file.
  • -W 5: Limit the number of rotated files to 5; after that, start overwriting old files. These two options will ensure no more than 500 MB are used.
  • tcp[((tcp[12] & 0xf0) >> 2)] = 0x16: Capture only packets for which the first byte after the TCP header is 0x16. This will ensure only TLS handshake packets are captured.
  • tcp[((tcp[12] & 0xf0) >> 2) + 1] = 0x03: Capture only packets for which the second byte after the TCP header is 0x03. This should be true for all TLS versions from 1.0 to 1.3.
  • tcp[((tcp[12] & 0xf0) >> 2) + 5] = 0x02: Capture only packets for which the sixth byte after the TCP header is 0x02. This ensures we only capture Server Hello messages.
  • -w output.pcap: Store the results in output.pcap.

Once we have let this run from the desired time, we can stop tcpdump with Ctrl + C. We will then have several files named output.pcap with a number at the end.

We can use tcpdump again to check how many connections of each TLS type we have detected. The total number of TLS connections recorded in the file is available with:

tcpdump -r output.pcap0 | wc -l

To get the total number of TLS 1.0 connections recorded in the file:

tcpdump -r output.pcap0 "tcp[((tcp[12] & 0xf0) >> 2) + 2] = 0x01" | wc -l

To get the total number of TLS 1.1 connections recorded in the file:

tcpdump -r output.pcap0 "tcp[((tcp[12] & 0xf0) >> 2) + 2] = 0x02" | wc -l

The total number of TLS 1.2 and TLS 1.3 connections recorded in the file is available with:

tcpdump -r output.pcap0 "tcp[((tcp[12] & 0xf0) >> 2) + 2] = 0x03" | wc -l

The captured files can also be opened with Wireshark. This allows us to see the source and destination IP. We can apply the following filter to Wireshark to limit the connections to TLS 1.0 or 1.1:

tls.handshake.type == 2 && (tls.handshake.version == 0x0301 || tls.handshake.version == 0x0302)

Conclusion

To learn more, read Java, Scala, Kotlin and TLS1.0 / TLS1.1 by Colm MacCárthaigh. Check back here for updates.

Dave Currie

Dave Currie

Dave Currie is a Software Development Manager at Amazon Web Services, working on bringing Corretto to the masses. @davidcurrie on Twitter.