对不起,这是一个很长的问题,但它有点牵扯.谢谢阅读.
我有一个自定义套接字工厂和套接字类(Android 5.0),我已经开发它来执行我需要在该级别执行的一些特定任务.这是我的套接字工厂和套接字(为简洁起见,我省略了许多方法):
public class CustomSocketFactory extends SSLSocketFactory {
private final SSLSocketFactory delegate;
public CustomSocketFactory(SSLSocketFactory delegate) {
this.delegate = delegate;
}
private Socket createCustomSocket(Socket socket) {
if (socket instanceof SSLSocket) {
socket = new CustomSocket((SSLSocket) socket);
}
return socket;
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
return createCustomSocket(delegate.createSocket(s, host, port, autoClose));
}
@Override
public Socket createSocket(String host, int port) throws IOException {
return createCustomSocket(delegate.createSocket(host, port));
}
private class CustomSocket extends SSLSocket {
protected final SSLSocket delegate;
private CustomSocket(SSLSocket delegate) {
this.delegate = delegate;
}
Run Code Online (Sandbox Code Playgroud)
我正在使用这个工厂:
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());
}
}
Run Code Online (Sandbox Code Playgroud)
除非我正在使用像alice.sni.velox.ch这样的服务器名称指示的网站,否则这会按预期工作.在这种情况下,该网站抱怨(我与Wireshark确认)我的应用程序没有发送SNI TLS标头.
取出我的自定义套接字工厂并发送标头.
进一步挖掘,我在okhttp Platform.java类中找到了这个代码(okhttp类在HttpsURLConnection中使用).
@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
}
Run Code Online (Sandbox Code Playgroud)
openSSLSocketClass正在以这种方式设置:
Class<?> openSslSocketClass = Class.forName("com.android.org.conscrypt.OpenSSLSocketImpl");
Run Code Online (Sandbox Code Playgroud)
因此,此代码启用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类添加新功能,我也会错过这些功能.
感谢您一路阅读!
bre*_*ine -1
好吧,也许我对你没那么有用,但你可以尝试设置一个不同的客户端,比如 jersey 的客户端或 apache http 客户端,特别是因为 Android 自己的 http 客户端太旧了,应该更换。