【发布时间】:2015-05-28 18:25:21
【问题描述】:
我正在为我的项目使用 OKHttp。我想为我的服务调用启用 TLSv1.2。任何人都可以告诉我如何启用它。
【问题讨论】:
-
它对您有什么作用?请告诉我我不能在 stackoverflow 上提问
-
这个解决方案解决了我的问题:stackoverflow.com/a/45853669/3448003
我正在为我的项目使用 OKHttp。我想为我的服务调用启用 TLSv1.2。任何人都可以告诉我如何启用它。
【问题讨论】:
见 OkHttp 的HTTPS documentation。
ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.cipherSuites(
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256)
.build();
OkHttpClient client = ...
client.setConnectionSpecs(Collections.singletonList(spec));
【讨论】:
ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) .allEnabledCipherSuites() .allEnabledTlsVersions() .build();我仍然有错误:Retrofit: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
据我所知,OKHttp 不包含自己的 SSL/TLS 库,因此它只使用 Android 提供的标准 SSLSocket。
支持(和启用)哪些 TLS 版本取决于使用的 Android 版本。
在某些手机上支持 TLS 1.2,但默认情况下不启用(据我所知,这会影响 Android 4.1/4.2/4.4 的手机)。在这种情况下,您可以通过实现自定义包装器 SSLSocketFactory 来启用它,该包装器在内部使用默认 SSLSocketFactory 并在创建的每个 Socket 上调用 setEnabledProtocols(new String[]{"TLS1.2"})。
在安装了 Google 服务的设备上,在旧的 Android 4.x 设备上启用 TLS 1.2 的首选方法是使用ProviderInstaller。
【讨论】:
ve combined it with https://stackoverflow.com/a/38962842/5251437. If the ProviderInstaller` 失败(或抛出异常)我正在尝试使用自定义 SSLSoketFactory 来设置启用的协议...
检查我的代码!!完美运行!
private void checkTls() {
if (android.os.Build.VERSION.SDK_INT < 21) {
try {
ProviderInstaller.installIfNeededAsync(this, new ProviderInstaller.ProviderInstallListener() {
@Override
public void onProviderInstalled() {
}
@Override
public void onProviderInstallFailed(int i, Intent intent) {
}
});
} catch (Exception e) {
finish();
e.printStackTrace();
}
}
}
【讨论】:
原来我的解决方案与 Ken 的解决方案非常相似(Java 除外)。我发现它here 虽然必须做一些小改动才能让它工作。希望这对其他人“开箱即用”有效。
public class TLSSocketFactoryCompat extends SSLSocketFactory {
private SSLSocketFactory internalSSLSocketFactory;
public TLSSocketFactoryCompat() throws KeyManagementException, NoSuchAlgorithmException {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, null, null);
internalSSLSocketFactory = context.getSocketFactory();
}
public TLSSocketFactoryCompat(TrustManager[] tm) throws KeyManagementException, NoSuchAlgorithmException {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tm, new java.security.SecureRandom());
internalSSLSocketFactory = context.getSocketFactory();
}
@Override
public String[] getDefaultCipherSuites() {
return internalSSLSocketFactory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return internalSSLSocketFactory.getSupportedCipherSuites();
}
@Override
public Socket createSocket() throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket());
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
}
private Socket enableTLSOnSocket(Socket socket) {
if(socket != null && (socket instanceof SSLSocket)) {
//Create list of supported protocols
ArrayList<String> supportedProtocols = new ArrayList<>();
for (String protocol : ((SSLSocket)socket).getEnabledProtocols()) {
//Log.d("TLSSocketFactory", "Supported protocol:" + protocol);
//Only add TLS protocols (don't want ot support older SSL versions)
if (protocol.toUpperCase().contains("TLS")) {
supportedProtocols.add(protocol);
}
}
//Force add TLSv1.1 and 1.2 if not already added
if (!supportedProtocols.contains("TLSv1.1")) {
supportedProtocols.add("TLSv1.1");
}
if (!supportedProtocols.contains("TLSv1.2")) {
supportedProtocols.add("TLSv1.2");
}
String[] protocolArray = supportedProtocols.toArray(new String[supportedProtocols.size()]);
/*for (int i = 0; i < protocolArray.length; i++) {
Log.d("TLSSocketFactory", "protocolArray[" + i + "]" + protocolArray[i]);
}*/
//enable protocols in our list
((SSLSocket)socket).setEnabledProtocols(protocolArray);
}
return socket;
}
}
用法:
OkHttpClient httpClient = new OkHttpClient();
//Add Custom SSL Socket Factory which adds TLS 1.1 and 1.2 support for Android 4.1-4.4
try {
httpClient.setSslSocketFactory(new TLSSocketFactoryCompat());
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
【讨论】:
Enabling TLS 1.2 Enabling TLS 1.2 Enabling TLS 1.2 Enabling TLS 1.2 Enabling TLS 1.2 Enabling TLS 1.2 Enabling TLS 1.2 Enabling TLS 1.2 javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake terminated: ssl=0x5ff7f518: Failure in SSL library, usually a protocol error error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure (external/openssl/ssl/s3_pkt.c:1256 0x5fe90e28:0x00000003) at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:568)
这与答案above 基本相同,但我觉得代码示例对于其他任何登陆这里并且在导航 java ssl 环境方面没有跟上速度的人都是有用的。
最终对我有用的是基于此处报告的问题:https://github.com/mattleibow/square-bindings/issues/1
从这个要点https://gist.github.com/mattleibow/c8abfa323db094b820cc
请注意,这些代码示例在 C#/Xamarin 中,但可以相当容易地转换为 java。
internal class CompleteSSLSocketFactory : SSLSocketFactory
{
private readonly SSLSocketFactory innerFactory;
public CompleteSSLSocketFactory (SSLSocketFactory innerFactory)
{
this.innerFactory = innerFactory;
}
public override string[] GetDefaultCipherSuites ()
{
return innerFactory.GetDefaultCipherSuites ();
}
public override string[] GetSupportedCipherSuites ()
{
return innerFactory.GetSupportedCipherSuites ();
}
public override Socket CreateSocket ()
{
return MakeSocketSafe (innerFactory.CreateSocket ());
}
public override Socket CreateSocket (Socket s, string host, int port, bool autoClose)
{
return MakeSocketSafe (innerFactory.CreateSocket (s, host, port, autoClose));
}
public override Socket CreateSocket (string host, int port)
{
return MakeSocketSafe (innerFactory.CreateSocket (host, port));
}
public override Socket CreateSocket (string host, int port, InetAddress localHost, int localPort)
{
return MakeSocketSafe (innerFactory.CreateSocket (host, port, localHost, localPort));
}
public override Socket CreateSocket (InetAddress host, int port)
{
return MakeSocketSafe (innerFactory.CreateSocket (host, port));
}
public override Socket CreateSocket (InetAddress address, int port, InetAddress localAddress, int localPort)
{
return MakeSocketSafe (innerFactory.CreateSocket (address, port, localAddress, localPort));
}
private Socket MakeSocketSafe (Socket socket)
{
var sslSocket = socket as SSLSocket;
if (sslSocket != null) {
// enable all supported protocols for this socket
sslSocket.SetEnabledProtocols (sslSocket.GetSupportedProtocols ());
sslSocket.SetEnabledCipherSuites (sslSocket.GetSupportedCipherSuites ());
}
return socket;
}
}
然后这样称呼它:
// this.client is an OkHttpClient
if (Android.OS.Build.VERSION.SdkInt < BuildVersionCodes.Lollipop) {
this.client.SetSslSocketFactory(new CompleteSSLSocketFactory(HttpsURLConnection.DefaultSSLSocketFactory));
}
这对我有用,在 API 19 上测试。
【讨论】: