Android 5.0 SSL连接问题

时间:2015-06-29 07:08:23

标签: java android ssl

我正在尝试与web服务进行交互,这是一个HTTPS调用,在4.0的不同变体上完全正常工作(我没有在4.0以下检查它,所以我不能说它们)并且它完美地工作。我面临的问题是在Android 5.0上,我能够获取的设备是Nexus 5,以下是我在连接时获得的例外

  

javax.net.ssl.SSLPeerUnverifiedException:没有对等证书               在org.apache.harmony.xnet.provider.jsse.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:146)               在org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:93)

经过大量搜索和分析我们的生产服务器SSL证书后,我发现服务器接受TLSv1,它支持的唯一密码套件是TLS_RSA_WITH_3DES_EDE_CBC_SHA。虽然我知道它不安全而且应该升级但是现在我必须找到一些方法让我的Android应用程序与服务器连接。

我尝试了本页建议的方式

https://code.google.com/p/android-developer-preview/issues/attachmentText?id=1200&aid=12000009000&name=CompatSSLSocketFactory.java&token=ABZ6GAcWKpRZhuG6Skof32VtvF0Lzv3Z-A%3A1435550700632

并替换了我所需的算法,即TLS_RSA_WITH_3DES_EDE_CBC_SHA,但现在的问题是我看到了这个异常

  

引起:java.lang.IllegalArgumentException:cipherSuite   不支持TLS_RSA_WITH_3DES_EDE_CBC_SHA。               在com.android.org.conscrypt.NativeCrypto.checkEnabledCipherSuites(NativeCrypto.java:1091)               在com.android.org.conscrypt.SSLParametersImpl.setEnabledCipherSuites(SSLParametersImpl.java:244)               在com.android.org.conscrypt.OpenSSLSocketImpl.setEnabledCipherSuites(OpenSSLSocketImpl.java:822)

因此,根据此例外,Android 5.0不支持我所需的密码套件。但在本页的Android 5.0支持列表中看到它后,我感到困惑

http://developer.android.com/reference/javax/net/ssl/SSLEngine.html

有人知道这个谜吗?

1 个答案:

答案 0 :(得分:0)

我在解决这个问题三天之后最终得到了答案。为将来陷入类似问题的人发布正确的解决方案

首先实现CustomTrustManager

public class CustomX509TrustManager implements X509TrustManager {

    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
    }

    @Override
    public void checkServerTrusted(X509Certificate[] certs,
                                   String authType) throws CertificateException {

        // Here you can verify the servers certificate. (e.g. against one which is stored on mobile device)

        // InputStream inStream = null;
        // try {
        // inStream = MeaApplication.loadCertAsInputStream();
        // CertificateFactory cf = CertificateFactory.getInstance("X.509");
        // X509Certificate ca = (X509Certificate)
        // cf.generateCertificate(inStream);
        // inStream.close();
        //
        // for (X509Certificate cert : certs) {
        // // Verifing by public key
        // cert.verify(ca.getPublicKey());
        // }
        // } catch (Exception e) {
        // throw new IllegalArgumentException("Untrusted Certificate!");
        // } finally {
        // try {
        // inStream.close();
        // } catch (IOException e) {
        // e.printStackTrace();
        // }
        // }
    }

    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }
}

实现自己的套接字工厂

public class CustomSSLSocketFactory extends SSLSocketFactory {

    SSLContext sslContext = SSLContext.getInstance("TLS");

    public CustomSSLSocketFactory(KeyStore truststore)
            throws NoSuchAlgorithmException, KeyManagementException,
            KeyStoreException, UnrecoverableKeyException {
        super(truststore);

        TrustManager tm = new CustomX509TrustManager();

        sslContext.init(null, new TrustManager[] { tm }, null);
    }

    public CustomSSLSocketFactory(SSLContext context)
            throws KeyManagementException, NoSuchAlgorithmException,
            KeyStoreException, UnrecoverableKeyException {
        super(null);
        sslContext = context;
    }

    @Override
    public Socket createSocket(Socket socket, String host, int port,
                               boolean autoClose) throws IOException, UnknownHostException {
        Socket newSocket =  sslContext.getSocketFactory().createSocket(socket, host, port,
                autoClose);
        ((SSLSocket) newSocket).setEnabledCipherSuites(((SSLSocket) newSocket).getSupportedCipherSuites());
        AdjustSocket(newSocket);
        return newSocket;
    }

    @Override
    public Socket createSocket() throws IOException {
        Socket socket = sslContext.getSocketFactory().createSocket();
        ((SSLSocket) socket).setEnabledCipherSuites(((SSLSocket) socket).getSupportedCipherSuites());
        adjustSocket(socket);
        return socket;
    }

    private void adjustSocket(Socket socket)
    {
        String[] cipherSuites = ((SSLSocket) socket).getSSLParameters().getCipherSuites();
        ArrayList<String> cipherSuiteList = new ArrayList<String>(Arrays.asList(cipherSuites));

        cipherSuiteList.add("TLS_RSA_WITH_3DES_EDE_CBC_SHA");
        cipherSuites = cipherSuiteList.toArray(new String[cipherSuiteList.size()]);
        ((SSLSocket) socket).getSSLParameters().setCipherSuites(cipherSuites);

        String[] protocols = ((SSLSocket) socket).getSSLParameters().getProtocols();
        ArrayList<String> protocolList = new ArrayList<String>(Arrays.asList(protocols));

        for (int ii = protocolList.size() - 1; ii >= 0; --ii )
        {
            if ((protocolList.get(ii).contains("SSLv3")) || (protocolList.get(ii).contains("TLSv1.1")) || (protocolList.get(ii).contains("TLSv1.2")))
                protocolList.remove(ii);
        }

        protocols = protocolList.toArray(new String[protocolList.size()]);
        ((SSLSocket)socket).setEnabledProtocols(protocols);
    }
}

现在在类中添加一个函数来创建HttpClient

public HttpClient createHttpClient(){
            try {
                KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
                trustStore.load(null, null);

                CustomSSLSocketFactory sf = new CustomSSLSocketFactory(trustStore);
                sf.setHostnameVerifier(CustomSSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

                HttpParams params = new BasicHttpParams();
                HttpConnectionParams.setConnectionTimeout(params, 15000);
                HttpConnectionParams.setSoTimeout(params, 5000);

                SchemeRegistry registry = new SchemeRegistry();
                registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
                registry.register(new Scheme("https", sf, 443));

                ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

                return new DefaultHttpClient(ccm, params);
            } catch (Exception e) {
                return new DefaultHttpClient();
            }

现在写下面的行来调用server / webservice

HttpClient httpClient = createHttpClient();
HttpPost httpost = new HttpPost(url);
HttpResponse response = null;
try {
    response = httpClient.execute(httpost);
    StatusLine statusLine = response.getStatusLine();
} catch (IOException e) {
    e.printStackTrace();
}