Java、Apache HttpClient、TLSv1.2和;OpenJDK7

Java、Apache HttpClient、TLSv1.2和;OpenJDK7,java,ssl,apache-httpclient-4.x,openjdk,Java,Ssl,Apache Httpclient 4.x,Openjdk,我们有一小群运行OpenJDK v1.7.0_111的Tomcat服务器。我们计划在今年夏天对它们进行升级和迁移,但我们发现,我们与之交互的客户端API在短期内将需要TLSv1.2。我的最终愿望是找到一个配置更改来实现这一点 托管在那里的应用程序以非常直接的方式创建其SSL上下文: SSLContext sslContext = SSLContexts.createDefault() SSLConnectionSocketFactory sslsf = new SSLConnectionSock

我们有一小群运行OpenJDK v1.7.0_111的Tomcat服务器。我们计划在今年夏天对它们进行升级和迁移,但我们发现,我们与之交互的客户端API在短期内将需要TLSv1.2。我的最终愿望是找到一个配置更改来实现这一点

托管在那里的应用程序以非常直接的方式创建其SSL上下文:

SSLContext sslContext = SSLContexts.createDefault()
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
SSLContexts
来自Apache的httpclient库(版本4.4.1),并且在创建SSL上下文方面也非常直接:

public static SSLContext createDefault() throws SSLInitializationException {
    try {
        SSLContext ex = SSLContext.getInstance("TLS");
        ex.init((KeyManager[])null, (TrustManager[])null, (SecureRandom)null);
        return ex;
    } catch (NoSuchAlgorithmException var1) {
        throw new SSLInitializationException(var1.getMessage(), var1);
    } catch (KeyManagementException var2) {
        throw new SSLInitializationException(var2.getMessage(), var2);
    }
}
通过挖掘
SSLConnectionSocketFactory
类,它似乎只是简单地使用
SSLSocket.getEnabledProtocols()
方法来确定哪些协议可用。请注意,在我的例子中,
this.supportedProtocols
为空

public Socket createLayeredSocket(Socket socket, String target, int port, HttpContext context) throws IOException {
        SSLSocket sslsock = (SSLSocket)this.socketfactory.createSocket(socket, target, port, true);
        if(this.supportedProtocols != null) {
            sslsock.setEnabledProtocols(this.supportedProtocols);
        } else {
            String[] allProtocols = sslsock.getEnabledProtocols();
            ArrayList enabledProtocols = new ArrayList(allProtocols.length);
            String[] arr$ = allProtocols;
            int len$ = allProtocols.length;

            for(int i$ = 0; i$ < len$; ++i$) {
                String protocol = arr$[i$];
                if(!protocol.startsWith("SSL")) {
                    enabledProtocols.add(protocol);
                }
            }

            if(!enabledProtocols.isEmpty()) {
                sslsock.setEnabledProtocols((String[])enabledProtocols.toArray(new String[enabledProtocols.size()]));
            }
        }
除了
-Dhttps.protocols=TLSv1.2
之外,我还毫无运气地尝试了
-Djdk.tls.client.protocols=TLSv1.2
-Ddeployment.security.TLSv1.2=true
JVM参数


有人想过如何在这种配置中启用TLSv1.2而不升级到v8或更改应用程序以专门请求TLSv1.2的实例吗?

jdk.tls.client.protocols
只在您不使用的Java 8(可能是9)上工作

https.protocols
默认情况下仅在httpclient不使用的
HttpsURLConnection
中工作

部署。*
仅适用于您未使用的JNLP和小程序(如果任何浏览器仍允许小程序)

假设您使用
HttpClientBuilder
HttpClientBuilder
(您没有说),您的问题的答案至少是4.5,分别使用
.useSystemProperties()
.createSystem()
;它们确实使用了与
*URLConnection
相同的系统属性,或者至少其中许多属性包括
https.protocols
。您应该检查此集合中包含的其他属性是否配置为执行您不希望执行的操作。这确实需要更改应用程序,但不需要更改它们“以专门请求…”。。。TLSv1.2'


除此之外,您可以配置
SSLConnectionSocketFactory
以指定中允许的确切协议,或
SSLContexts.custom().useProtocol(String.build())
指定上限——这对于您的情况已经足够了,因为向需要1.2的服务器提供“高达1.2”的范围将选择1.2。

以下是配置Apache HttpClient 4.x以使用特定TLS/SSL版本的推荐方法

CloseableHttpClient client = HttpClientBuilder.create()
    .setSSLSocketFactory(new SSLConnectionSocketFactory(SSLContext.getDefault(), new String[] { "TLSv1.2" }, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier()))
    .build();

投票支持dave_thompson_085的答案

您是否尝试过此处显示的参数和测试?此外,您可能希望包含一个简短的测试,以便JDK 7上的其他用户可以复制您正在尝试的内容。您不应该启用所有受支持的协议,因为它们包括不安全的匿名密码套件。@pvg-现在我已经启用了。我已经列出了我在问题中尝试过的所有JVM参数。我还提供了一个简短的示例。为了完整起见,在您的示例中最后一件事可能是一个简单的URLConnection测试,这样您就知道它不是(或是)httpclient特定的问题。
jdk.tls.client.protocols
如果我理解正确,应该在OpenJDK 7u91和更高版本以及6u115和更高版本中提供。
CloseableHttpClient client = HttpClientBuilder.create()
    .setSSLSocketFactory(new SSLConnectionSocketFactory(SSLContext.getDefault(), new String[] { "TLSv1.2" }, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier()))
    .build();