How to Determine which TLS Version an Application is Using
The TLS version used by your Java application depends on how your application and JDK are configured. The Java Security API offers options for which protocol versions to have TLS use. In the most recent JDK releases, TLSv1.3 and TLSv1.2 are offered by default (via the TLS ClientHello handshake initialization routine)
Check out How to Disable TLS Versions by Default to read more on what the JDK API has to offer in this area.
Determining exactly what TLS protocol version an application is using is easiest done via collection of runtime data. Various tools and logger options are available. This document will discuss some of those options.
Network Analysis
One option is to attach a network protocol analyzer tool to the network
interface where the JDK is communicating and get information on all the
network traffic on that interface. The "ClientHello"
record will
control details of the TLS versions offered to the TLS server for use,
but ultimately it’s the TLS server that decides what TLS version will be
used. Look for the "ServerHello"
record and the accompanying version
value to detemine what TLS version is in use on a particular socket.
JDK Debug Logs
The JDK offers verbose, standard error output if the javax.net.debug
system property is enabled. A value of all
produces verbose output.
For the purpose of detemining a TLS version protocol value, a value of
ssl:handshake
(for example, -Djavax.net.debug=ssl:handshake
) is
sufficient. Here’s an example of a "ServerHello"
capture in a recent
JDK 17 release:
"ServerHello": {
"server version" : "TLSv1.2",
"random" : "3C84EF0BAB49FDD5D179780EEC6C0E8E950AAF5DBCBAE20C8B258D75F2646618",
"session id" : "",
"cipher suite" : "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256(0xC02F)",
"compression methods" : "00",
"extensions" : [
"server_name (0)": {
<empty extension_data field>
},
"renegotiation_info (65,281)": {
"renegotiated connection": [<no renegotiated connection>]
},
"ec_point_formats (11)": {
"formats": [uncompressed, ansiX962_compressed_prime, ansiX962_compressed_char2]
},
"session_ticket (35)": {
<empty>
}
]
}
From above output, we see that TLSv1.2 is in use for this particular connection.
Java Flight Recorder (JFR) Events
A less well-known but quite useful option for capturing such TLS
information is the JFR profiler that ships with the JDK. The
jdk.TLSHandshake
event captures core information on every TLS
handshake performed by the JDK. You can enable it via the JFR options or
edit the default configuration file in the JDK itself. The default JFR
configuration file is located at <JDK_HOME>/lib/jfr/default.jfc
in JDK
11 and later. Simply switch the enabled options to true
.
<event name="jdk.TLSHandshake">
<setting name="enabled">true</setting>
<setting name="stackTrace">true</setting>
</event>
This event is available since the release of Oracle JDK 8u231
(JDK-8148188). For JDK 8u, the event name is java/tls_handshake
.
You can start your JFR recording via application start-up arguments or
attach remotely via jcmd
, Java Mission Control (JMC), or one of your
other favourite tools that supports the JFR attach option. For example,
add (in JDK 11 and later)
-XX:StartFlightRecording=filename=TLSInfo.jfr
to your application
start-up arguments. Use JMC or the $JDK/bin/jfr
tool (avaialable since
JDK 12) to analyze the recording.
Here’s a example dump of the TLSHandshake event data from the jfr tool:
$JDK/bin/jfr print --events "TLS*" /tmp/TLS.jfr
jdk.TLSHandshake {
startTime = 09:03:36.128
peerHost = "myserver.oracle.com"
peerPort = 443
protocolVersion = "TLSv1.2"
cipherSuite = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
certificateId = -1377911018
eventThread = "main" (javaThreadId = 1)
stackTrace = [
sun.security.ssl.Finished.recordEvent(SSLSessionImpl) line: 1164
sun.security.ssl.Finished$T12FinishedConsumer.onConsumeFinished(ClientHandshakeContext, ByteBuffer) line: 567
sun.security.ssl.Finished$T12FinishedConsumer.consume(ConnectionContext, ByteBuffer) line: 538
sun.security.ssl.SSLHandshake.consume(ConnectionContext, ByteBuffer) line: 396
sun.security.ssl.HandshakeContext.dispatch(byte, ByteBuffer) line: 480
...
]
}
As you can see, TLSv1.2 is in use for this particular example.
Last reviewed on Sat Feb 01 2025 00:00:00 GMT+0000 (Coordinated Universal Time)