[英]SSL Handshake failed Android 5.1
由於三星設備上的 Android 5.0.2 或 5.1.1 在連接舊路由器“FRITZ!Box 7170”的 Web 界面時,我的 Android 應用程序收到錯誤消息。
javax.net.ssl.SSLProtocolException:SSL握手中止:ssl = 0xaecc7e00:SSL庫失敗,通常是協議錯誤錯誤:14082174:SSL例程:SSL3_CHECK_CERT_AND_ALGORITHM:在ccs之前獲得通道ID(外部/openssl/ssl/s3_clnt.c :3632 0xaf0e1679:0x00000000)
如果我用 Firefox 瀏覽器連接相同的界面:
ssl_error_weak_server_ephemeral_dh_key
我認為這是因為不安全的 Diffie-Hellman 密鑰長度? 如何避免這種情況? 我正在使用HTTPClient
建立連接。
我有同樣的問題。
原因是三星安全更新,它改變了 SSLSocketFactory 給出的默認密碼套件數組。 如果您使用帶有 android M 的 nexus 設備,您將看到此錯誤消息
ssl_error_weak_server_ephemeral_dh_key
在三星設備上,它是
SSL3_CHECK_CERT_AND_ALGORITHM
我的解決方案是覆蓋密碼套件數組。 這是我的 SSLSocketFactory,我用它來創建 ssl 套接字。
public class SpeedportSSLSocketFactory extends SSLSocketFactory {
private final static Logger logger = Logger.getLogger(SpeedportSSLSocketFactory.class);
/**
* the order of ciphers in this list is important here e.g. TLS_DHE_* must not stay above TLS_RSA_*
*/
private static final String[] APPROVED_CIPHER_SUITES = new String[]{
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_RSA_WITH_AES_128_GCM_SHA256",
"TLS_RSA_WITH_AES_128_CBC_SHA",
"TLS_RSA_WITH_AES_256_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
};
private SSLSocketFactory factory;
public SpeedportSSLSocketFactory() {
try {
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(null, new TrustManager[]{
// accepts certs with valid but expired key chain (incl. root cert)
new ExpiredSpeedportTrustManager()}, new java.security.SecureRandom());
factory = sslcontext.getSocketFactory();
} catch (Exception ex) {
logger.error("Cannot create SpeedportSSLSocketFactory", ex);
}
}
// dirty
private void injectHostname(InetAddress address, String host) {
try {
Field field = InetAddress.class.getDeclaredField("hostName");
field.setAccessible(true);
field.set(address, host);
} catch (Exception ignored) {
logger.error("Cannot inject hostName");
}
}
public static SocketFactory getDefault() {
return new SpeedportSSLSocketFactory();
}
public Socket createSocket() throws IOException {
return factory.createSocket();
}
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
return factory.createSocket(socket, host, port, autoClose);
}
public Socket createSocket(InetAddress addr, int port, InetAddress localAddr, int localPort) throws IOException {
return factory.createSocket(addr, port, localAddr, localPort);
}
public Socket createSocket(InetAddress inaddr, int i) throws IOException {
return factory.createSocket(inaddr, i);
}
public Socket createSocket(String host, int port, InetAddress localAddr, int localPort) throws IOException {
return factory.createSocket(host, port, localAddr, localPort);
}
public Socket createSocket(String host, int port) throws IOException {
InetAddress addr = InetAddress.getByName(host);
injectHostname(addr, host);
Socket socket = factory.createSocket(addr, port);
((SSLSocket) socket).setEnabledCipherSuites(getSupportedCipherSuites());
return socket;
}
@Override
public String[] getDefaultCipherSuites() {
return APPROVED_CIPHER_SUITES;
}
@Override
public String[] getSupportedCipherSuites() {
return APPROVED_CIPHER_SUITES;
}
}
最后兩種方法覆蓋默認密碼套件。 我不確定,你需要覆蓋兩者。
cipher suites 數組中的順序也很重要
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.