1. 程式人生 > >TLS, SSL, and HTTPS 升級

TLS, SSL, and HTTPS 升級

copy 記錄

Diagnosing TLS, SSL, and HTTPS

When building inter-connected applications, developers frequently interact with TLS-enabled protocols like HTTPS. With recent emphasis on encrypted communications, I will cover the way in which the JDK evolves regarding protocols, algorithms, and changes, as well as some advanced diagnostics to better understand TLS connections like HTTPS.

Most developers will not have to do this level of diagnosis in the process of writing or running applications. In the event that you do, the following information should provide enough information to understand what's happening within secure connections.

Stability: The evolution of protocols and algorithms

For the last 15 years (since 1998), the Java platform has evolved through the Java Community Process where companies, organizations, and dedicated individuals develop and vote on specifications to determine what makes up the Java Platform. Much of the efforts are centered on compatibility, like the TCK, ensuring that different implementations are compatible with each-other and that developers can predict how their applications will run. We are not changing critical default options (like TLS protocol) within minor versions.

The following chart depicts the protocols and algorithms supported in each JDK version:

Sample Java code for making an HTTPS connection

Making an HTTPS connection in Java is relatively straight-forward. I will post the code here with the intent focused on tuning and understanding the underlying capabilities.

Sample back-end code for making an SSL connection:

final URL url = new URL("https://example.com");
try(final InputStream in = url.openStream()){
  //…
}

Or the connection can be tuned through a cast:

final HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
//operate on conn
conn.connect();
try(final InputStream in = conn.getInputStream()){
  //…
}

Example: Qualys SSL Labs' "View My Client" Page

Qualys SSL Labs maintains a collection of tools that are helpful in understanding SSL/TLS connections. One in particular is aView My Client page, which will display information about the client connection. By integrating with that page, I was able to control the implementation as I used different Java tuning parameters.

To test parameter tuning, I implemented a small JavaFX application in JavaScript. It displays that page in aWebView, showing information about the underlying Java SSL/TLS client connection. You can find the code in the appendix.

JSSE Tuning Parameters

When diagnosing TLS-related issues, there are a number of helpful system properties. They are generally covered in their relevant sections of JSSE but this single collection may help anyone looking to understand the flexibility of Java’s implementation or diagnose connection details.

javax.net.debug  Prints debugging details for connections made.
Example: -Djavax.net.debug=all or -Djavax.net.debug=ssl:handshake:verbose
https.protocols

Controls the protocol version used by Java clients which obtain https connections through use of the HttpsURLConnection class or via URL.openStream() operations. For older versions, this can update the default in case your Java 7 client wants to use TLS 1.2 as its default.
Example: -Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2

For non-HTTP protocols, this can be controlled through the SocketFactory's SSLContext.

jdk.tls.client.protocols Controls the underlying platform TLS implementation . Additional information is available in theJSSE Reference Guide.
Example: -Djdk.tls.client.protocols=TLSv1.1,TLSv1.2
Available in all JDK 8 releases, or after Java 7 update 95 (January 2016) and Java 6 update 121 (July 2016).
http.agent When initiating connections, Java will apply this as its user-agent string. Modifying this will handle cases where the receiving party responds differently based on the user-agent.
Example: -Dhttp.agent="known agent"
java.net.useSystemProxies java.net.useSystemProxiesUse proxy details from the operating system itself.
Example: -Djava.net.useSystemProxies=true
http.proxyHost
http.proxyPort
The proxy connection to use for HTTP connections.
Example: -Dhttp.proxyHost=proxy.example.com -Dhttp.proxyPort=8080
https.proxyHost
https.proxyPort
The same as above, except that configuration is separate between HTTP and HTTPS.
http.proxyUser
http.proxyPassword
https.proxyUser
https.proxyPassword
Password-based credentials for the above proxies.

Many other protocols and properties can be found within the following areas:

Example of diagnosing a problem

When making an HTTPS connection, let’s assume that the client threw the following exception due to a failed handshake with the server:

 javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure 

SSLHandshakeException is a subclass of the IOException, so you do not need to catch is explicitly. Most developers will not need an explicit catch, but it may help you more easily diagnose the cause of any IOException.

When applying the -Djavax.net.debug=all property from above, the failure associated with this SSLHandshakeException would appear immediately after algorithm negotiation in the logs.

 JDK 7 (fails on unsupported algorithm) JDK 8 (works fine)
Cipher Suites: […Long list of ciphers…]
Compression Methods:  { 0 }
Extension elliptic_curves, curve names: {…}
Extension ec_point_formats, formats: [uncompressed]
Extension server_name, server_name: [host_name: HOST]
***
main, WRITE: TLSv1 Handshake, length = 168
main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1 ALERT:  fatal, handshake_failure
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
Cipher Suites: […Long list of ciphers…]
Compression Methods:  { 0 }
Extension elliptic_curves, curve names: {…}
Extension ec_point_formats, formats: [uncompressed]
Extension signature_algorithms, signature_algorithms: …
Extension server_name, server_name: [type=host_name (0), value=HOST]
***
main, WRITE: TLSv1.2 Handshake, length = 226
main, READ: TLSv1.2 Handshake, length = 89
*** ServerHello, TLSv1.2
RandomCookie:  GMT: -1809079139 bytes = { …}
Session ID:  {…}
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
Compression Method: 0
Extension renegotiation_info, renegotiated_connection: <empty>
Extension ec_point_formats, formats: [uncompressed, ansiX962_compressed_prime, ansiX962_compressed_char2]
***
%% Initialized:  [Session-1, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
** TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
main, READ: TLSv1.2 Handshake, length = 2308

In the case above, the failure occurred during the handshake. The most likely cause for that is algorithm support. The JDK provides a separate package called JCE Unlimited Strength, designed to add stronger algorithm support than what’s available by default. Qualys SSL Labs provides a different server SSL test that will enumerate which algorithms a server supports.

Many TLS error messages are covered in a few pieces of documentation:

Adding stronger algorithms: JCE Unlimited Strength

In a high security environment, one way of strengthening algorithms in the JDK is through the JCE Unlimited Strength policy files. In this particular case, replacing those policy files within JDK 7 allows it to use the stronger variants of existing algorithms and connect successfully.

JCE Unlimited Strength downloads: JDK 8, JDK 7, or JDK 6.

Appendix

The following code will open Qualys SSL Labs’ View My Client page within a Java client. To test configurations, run this like:

jjs -fx viewmyclient.js
jjs -fx -Dhttps.protocols=TLSv1 viewmyclient.js

var Scene = javafx.scene.Scene;
var WebView = javafx.scene.web.WebView;
var browser = new WebView();
browser.getEngine().load("https://ssllabs.com/ssltest/viewMyClient.html");
$STAGE.scene = new Scene(browser);
$STAGE.show();