我们有一小组运行 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()]));
}
}
我遇到的问题是,在运行一些初步测试时,我无法让这些客户端连接到需要 TLSv1.2 的 API。
在下面的例子中我可以得到URLConnection
代码通过包含来完成-Dhttps.protocols=TLSv1.2
参数,但我无法连接 Apache 连接。
public static void main(String[] args) throws Exception{
String testURL = "https://testapi.com";
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(null, null, null);
try {
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslcontext);
CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(socketFactory).build();
HttpGet httpget = new HttpGet(testURL);
CloseableHttpResponse response = client.execute(httpget);
System.out.println("Response Code (Apache): " + response.getStatusLine().getStatusCode());
}
catch (Exception e){
System.err.println("Apache HTTP Client Failed");
e.printStackTrace();
}
try {
HttpsURLConnection urlConnection = (HttpsURLConnection) new URL(testURL).openConnection();
urlConnection.setSSLSocketFactory(sslcontext.getSocketFactory());
urlConnection.connect();
System.out.println("Response Code (URLConnection): " + urlConnection.getResponseCode());
}
catch (Exception e){
System.err.println("HttpsURLConnection Failed");
e.printStackTrace();
}
}
随着-Dhttps.protocols=TLSv1.2
我已经尝试过-Djdk.tls.client.protocols=TLSv1.2
和-Ddeployment.security.TLSv1.2=true
JVM参数没有任何运气。
有谁知道如何在此配置中启用 TLSv1.2,而无需升级到 v8 或更改应用程序以专门请求 TLSv1.2 实例?