android Retrofit和OkHttpClient使用let加密认证在后端出现SSL handShake错误

时间:2017-05-13 04:22:40

标签: android retrofit retrofit2 lets-encrypt okhttp

我真的不知道如何解决这个问题,这个项目是一个Android和iOs应用程序,在Docker容器服务器上有一个RoR后端API ......

在Android应用程序中,我使用Retrofit Library进行api客户端实现,一切都运行良好......直到在服务器上实现SSL证书。我的合作伙伴使用了Let’s Encrypt,我可以使用curl,postman成功地在api上发出请求...但我的Android应用程序总是说:

D/Error: SSL handshake aborted: ssl=0xXXXXXXXX: I/O error during system call, Connection reset by peer

或有时:

D/Error: SSL handshake timeout

ApiClient来源:

public class ApiClient {

public static final String DOMAIN = "qwerty.xyz"; //not the real url obviously
public static final String BASE_URL = "https://api." + DOMAIN;

private static Retrofit retrofit = null;

private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

private static Gson gson = new GsonBuilder()
        .create();

private static Retrofit.Builder builder =
        new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create(gson));

public static <S> S createService(Class<S> serviceClass) {
    return createService(serviceClass, null, null);
}

public static <S> S createService(Class<S> serviceClass, String username, String password) {
    Retrofit retrofit = builder.client(getUnsafeOkHttpClient())
            .build();
    return retrofit.create(serviceClass);
}

public static OkHttpClient getUnsafeOkHttpClient() {

    try {
        // Create a trust manager that does not validate certificate chains
        final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] chain,
                    String authType) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] chain,
                    String authType) throws CertificateException {
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[0];
            }
        } };

        // Install the all-trusting trust manager
        final SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
        // Create an ssl socket factory with our all-trusting manager
        final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();


        OkHttpClient okHttpClient  = httpClient.sslSocketFactory(sslSocketFactory).hostnameVerifier(new HostnameVerifier() {

                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                                                            return true;
                                                    }
                                                })
                                        .build();

        return okHttpClient;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }

}

观察,sslSocketFactory方法已弃用......但我不知道新方法是怎么做的......

我正在使用&#39; com.squareup.retrofit2:改装:2.2.0&#39; ...

我非常感谢您寻求解决方案的任何帮助。

更新&amp;解

让加密使用TLSv1.2协议而不是自签名,我们需要排除旧版本的TSL。

我创建了一个自定义SSLSocketFactory来执行此操作:

public class TLSSocketFactory extends SSLSocketFactory {

    private SSLSocketFactory internalSSLSocketFactory;

    public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException {
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, null, null);
        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)) {
            ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.2"});
        }
        return socket;
    }
}

然后我们和httpclient中的一个信任管理器:

final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
                @Override
                public void checkClientTrusted(
                        java.security.cert.X509Certificate[] chain,
                        String authType) throws CertificateException {
                }

                @Override
                public void checkServerTrusted(
                        java.security.cert.X509Certificate[] chain,
                        String authType) throws CertificateException {
                }

                @Override
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return new java.security.cert.X509Certificate[0];
                }
            } };
            client = httpClient.sslSocketFactory(new TLSSocketFactory(), (X509TrustManager)trustAllCerts[0])
                    .build();
            Retrofit retrofit = builder.client(client)
                    .build();

瞧!! ​​

1 个答案:

答案 0 :(得分:0)

查看一次certificate pinning