从OpenSSLSocketImpl派生的Android自定义套接字(非SSLSocket)

从OpenSSLSocketImpl派生的Android自定义套接字(非SSLSocket),android,sockets,Android,Sockets,对不起,这是一个很长的问题,但有点牵扯其中。谢谢你的阅读 我有一个定制的套接字工厂和套接字类(Android5.0),我开发了它来执行我在该级别需要执行的一些特定任务。下面是我的套接字工厂和套接字(为了简单起见,我省略了许多方法): 我是这样使用这个工厂的: private void doCustomSocketFactoryWithHttpUrlConnection() { try { String uri = "https://alice.sni.velox.c

对不起,这是一个很长的问题,但有点牵扯其中。谢谢你的阅读

我有一个定制的套接字工厂和套接字类(Android5.0),我开发了它来执行我在该级别需要执行的一些特定任务。下面是我的套接字工厂和套接字(为了简单起见,我省略了许多方法):

我是这样使用这个工厂的:

  private void doCustomSocketFactoryWithHttpUrlConnection() {

    try {
        String uri = "https://alice.sni.velox.ch";

        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, null, null);
        CustomSocketFactory customSocketFactory = new CustomSocketFactory(context.getSocketFactory());
        HttpsURLConnection.setDefaultSSLSocketFactory(customSocketFactory);

        URL url = new URL(uri);
        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();

        Log.d(TAG, "HTTP Response Code: " + conn.getResponseCode());

    } catch (Exception e) {
        Log.d(TAG, e.getLocalizedMessage());
    }

}
这就像预期的一样,除非我访问了一个使用like的站点。在这种情况下,网站抱怨(我向Wireshark确认)我的应用程序没有发送SNI TLS头

取出我的自定义套接字工厂,并发送标头

进一步挖掘,我在Platform.java类中发现了这段代码(在HttpsURLConnection中使用了okhttp类)

openSSLSocketClass的设置方式如下:

Class<?> openSslSocketClass =    Class.forName("com.android.org.conscrypt.OpenSSLSocketImpl");
Class openSslSocketClass=Class.forName(“com.android.org.conscrypt.OpenSSLSocketImpl”);
因此,此代码启用SNI和会话票证,但仅当套接字扩展OpenSSLSocketImpl时才启用

回到我的自定义套接字,在调试器中,我看到传递给构造函数的套接字类是:com.android.org.conscrypt.OpenSSLSocketImplWrapper(它扩展了OpenSSLSocketImpl)

因此,我错过了SNI和会话票证功能,因为我的套接字扩展了java.net.ssl.SSLSocket(而不是OpenSSLSocketImpl)

想到的最好的解决方案是让我的CustomSocket扩展OpenSSLSocketImpl并添加所需的委托方法,但我不知道如何导入OpenSSLSocketImpl。它似乎不在标准Android库中。Android文档只讨论了SSLSocket,没有提到OpenSSLSocketImpl

有没有一种方法可以让我的CustomSocket类从我缺少的OpenSSLSocketImpl进行扩展

我意识到我可以使用反射在CustomSocket类中的“委托”上调用这些方法,但我担心在所有情况下的可靠性以及在何处/何时进行这些调用。此外,如果他们继续使用类似的方法在新的Android版本中向OpenSSLSocketImpl类添加新功能,我也会错过这些功能


感谢您一路阅读

也许我对你没什么用处,但你可以尝试设置一个不同的客户端,比如jersey的客户端或apache http客户端,特别是因为Android自己的http客户端太旧了,应该更换

这取决于您需要在CustomSocket中实现什么功能,但您可以执行以下操作:

  • 使CustomSocket扩展套接字(无SSL)
  • 在套接字工厂中,创建一个普通的自定义套接字,然后使用
    delegate.createSocket(s、主机、端口、自动关闭)
  • 返回委托的结果,它的类型为
    com.android.org.conscrypt.OpenSSLSocketImplWrapper

Android上不推荐使用AndroidHttpClient和Apache HttpClient。HttpURLConnection是我认为最好使用的类。Wel如果他使用的是外部jar(在他的例子中是okhttp),他可以尝试另一个。我不是说他应该使用内置的http客户端。例如,我认为原始android中的apache http客户端甚至还没有完全发布,我也遇到了类似的问题。你能解决这个问题吗?
@Override public void enableTlsExtensions(SSLSocket socket, String uriHost) {
     super.enableTlsExtensions(socket, uriHost);
     if (!openSslSocketClass.isInstance(socket)) return;
     try {
       setUseSessionTickets.invoke(socket, true);
       setHostname.invoke(socket, uriHost);
     } catch (InvocationTargetException e) {
// snip
}
Class<?> openSslSocketClass =    Class.forName("com.android.org.conscrypt.OpenSSLSocketImpl");