2015-10-07 195 views
1

由於三星設備上的Android 5.0.2或5.1.1,當連接舊路由器「FRITZ!Box 7170」的Web界面時,我的Android應用程序會收到錯誤消息。SSL握手失敗Android 5.1

javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xaecc7e00: Failure in SSL library, usually a protocol error error:14082174:SSL routines:SSL3_CHECK_CERT_AND_ALGORITHM:got Channel ID before a ccs (external/openssl/ssl/s3_clnt.c:3632 0xaf0e1679:0x00000000)

如果我連接使用Firefox瀏覽器相同的接口:

ssl_error_weak_server_ephemeral_dh_key

我想這是因爲不安全Deffie - 赫爾曼密鑰長度的? 如何避免這種情況?我正在使用HTTPClient進行連接。

回答

0

我有同樣的問題。

原因是三星安全更新,它已經改變了由SSLSocketFactory給出的默認密碼套件數組。順便問一句,如果你用它的Android米的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; 
} 

}

最後兩個方法覆蓋默認的加密套件。我不確定,你需要覆蓋兩者。

在密碼套件排列順序也非常重要