Skip to content

Instantly share code, notes, and snippets.

@lukehansen
Created May 10, 2016 06:10
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lukehansen/cd1931426d1e432d0993005f9976e6fb to your computer and use it in GitHub Desktop.
Save lukehansen/cd1931426d1e432d0993005f9976e6fb to your computer and use it in GitHub Desktop.
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

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

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"

@laurent-grousset
Copy link

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"

@laurent-grousset
Copy link

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

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