Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.Locale;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.SSLSocket;
import org.apache.commons.net.ftp.FTPSClient;
import com.google.common.base.Throwables;
public class SSLSessionReuseFTPSClient extends FTPSClient {
// adapted from: https://trac.cyberduck.io/changeset/10760
@Override
protected void _prepareDataSocket_(final Socket socket) throws IOException {
if(socket instanceof SSLSocket) {
final SSLSession session = ((SSLSocket) _socket_).getSession();
final SSLSessionContext context = session.getSessionContext();
try {
final Field sessionHostPortCache = context.getClass().getDeclaredField("sessionHostPortCache");
sessionHostPortCache.setAccessible(true);
final Object cache = sessionHostPortCache.get(context);
final Method putMethod = cache.getClass().getDeclaredMethod("put", Object.class, Object.class);
putMethod.setAccessible(true);
final Method getHostMethod = socket.getClass().getDeclaredMethod("getHost");
getHostMethod.setAccessible(true);
Object host = getHostMethod.invoke(socket);
final String key = String.format("%s:%s", host, String.valueOf(socket.getPort())).toLowerCase(Locale.ROOT);
putMethod.invoke(cache, key, session);
} catch(Exception e) {
throw Throwables.propagate(e);
}
}
}
}
@sreedharputtu
Copy link

sreedharputtu commented Jan 28, 2017

when i call storeFile method in FTPSClient is this _prepareDataSocket method automatically calls or how can i call this class from my class

@Noah1991
Copy link

Noah1991 commented Oct 25, 2017

java.lang.NoSuchFieldException: No field sessionHostPortCache in class Lcom/android/org/conscrypt/ClientSessionContext; (declaration of 'com.android.org.conscrypt.ClientSessionContext' appears in /system/framework/conscrypt.jar)
System.err: at java.lang.Class.getDeclaredField(Native Method)
System.err: at ..*.SSLSessionReuseFTPSClient.prepareDataSocket(SSLSessionReuseFTPSClient.java:35)
System.err: at org.apache.commons.net.ftp.FTPSClient.openDataConnection(FTPSClient.java:628)
System.err: at org.apache.commons.net.ftp.FTPClient.openDataConnection(FTPClient.java:785)
System.err: at org.apache.commons.net.ftp.FTPClient.initiateListParsing(FTPClient.java:3409)
System.err: at org.apache.commons.net.ftp.FTPClient.initiateListParsing(FTPClient.java:3339)
System.err: at org.apache.commons.net.ftp.FTPClient.listFiles(FTPClient.java:3016)
System.err: at org.apache.commons.net.ftp.FTPClient.listFiles(FTPClient.java:3069)
System.err: at com.noah.httpstest.utils.FTPUtils$4.run(FTPUtils.java:265)
System.err: at java.lang.Thread.run(Thread.java:818)

java1.8
android studio 2.3.3
commons-net-3.6.jar
build:
compileSdkVersion 26
buildToolsVersion "26.0.1"

@lgrousset
Copy link

lgrousset commented Mar 6, 2018

Don't know why, but this is working with openjdk version "1.8.0_151" and not working with openjdk version "1.8.0_161"

@lgrousset
Copy link

lgrousset commented Mar 6, 2018

With openJDK 1.8.0_161 :

We must set :

System.setProperty("jdk.tls.useExtendedMasterSecret", "false");

according to
http://www.oracle.com/technetwork/java/javase/8u161-relnotes-4021379.html
Added TLS session hash and extended master secret extension support
In case of compatibility issues, an application may disable negotiation of this extension by setting the System Property jdk.tls.useExtendedMasterSecret to false in the JDK

@51M0Ng
Copy link

51M0Ng commented Mar 14, 2018

I have the same problem too, for retrieving the Field "sessionHostPortCache", basically I view the source code for class "SSLSessionConnecion" there is no "sessionHostPortCache" Fiels, that Field is exist in class call "SSLSessionConnecionImp" from package "sun. security. ssl", but this package is removed from android default SDK, (because some of the function for original SDK package Android doesn't support), also I cannot find that class from jsse.jar library (inside jre1.8u151 folder) , then I tried to build my own from OpenJDK 1.8 source code directly, but it got problem that android studio cannot identify class from the custom-made library. I also tried lgrousset advice, but got no hope, anyone have a ideas?

@farizaghayev
Copy link

farizaghayev commented Jul 4, 2018

Respect :)

@joc7188
Copy link

joc7188 commented May 13, 2020

I implemented the mentioned solution and still getting same error. My java version is 1.8.0_221. This part of code is executed (I saw debugging) and I also added System.setProperty("jdk.tls.useExtendedMasterSecret", "false");

javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:994)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
at org.apache.commons.net.ftp.FTPSClient.openDataConnection(FTPSClient.java:646)
at org.apache.commons.net.ftp.FTPClient._retrieveFile(FTPClient.java:1899)
at org.apache.commons.net.ftp.FTPClient.retrieveFile(FTPClient.java:1885)
at com.motoresocasion.core.utils.ftp.FtpClient.downloadFile(FtpClient.java:72)
Caused by: java.io.EOFException: SSL peer shut down incorrectly
at sun.security.ssl.InputRecord.read(InputRecord.java:505)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:975)
... 26 common frames omitted

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment