Created
February 20, 2018 05:09
-
-
Save riyaz-ali/48fb486f51c258b4e92c2d2be30c35c4 to your computer and use it in GitHub Desktop.
Patching TLS session resumption on Apache Commons Net FTPSClient
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.apache.commons.net.PrintCommandListener; | |
import org.apache.commons.net.ftp.FTP; | |
import org.apache.commons.net.ftp.FTPFile; | |
import org.apache.commons.net.ftp.FTPSClient; | |
import java.io.FileInputStream; | |
import java.io.IOException; | |
import java.nio.file.FileSystems; | |
import java.nio.file.Path; | |
/** | |
* FTPUploadTest class to test FTPS upload using Apache commons net library | |
*/ | |
public class FTPUploadTest { | |
public static void main(String[] args) throws IOException { | |
// file to upload | |
// create a test.jpeg file in your current directory | |
Path path = FileSystems.getDefault().getPath("test.jpeg").toAbsolutePath(); | |
// we will be using https://dlptest.com/ftp-test/ FTP-server to test uploads | |
// thanks guys :D | |
FTPSClient client = new PatchedFTPSClient(); | |
try { | |
// to debug | |
client.addProtocolCommandListener(new PrintCommandListener(System.out)); | |
// connect to the server | |
client.connect("ftp.dlptest.com", 21); | |
// then login | |
client.login("[email protected]", "eiTqR7EMZD5zy7M"); | |
// exec PROT P | |
client.execPBSZ(0); | |
client.execPROT("P"); | |
// enter passive mode | |
client.enterLocalPassiveMode(); | |
// upload | |
client.setFileType(FTP.BINARY_FILE_TYPE); | |
if (client.storeUniqueFile(new FileInputStream(path.toFile()))) { | |
System.out.println("File Saved!"); | |
} else { | |
System.out.println("Failed to save file"); | |
} | |
// list | |
for (FTPFile file : client.listFiles("/")) { | |
System.out.println(file.toFormattedString()); | |
} | |
} finally { | |
client.disconnect(); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.apache.commons.net.ftp.FTPSClient; | |
import javax.net.ssl.*; | |
import java.io.IOException; | |
import java.lang.reflect.Field; | |
import java.lang.reflect.Method; | |
import java.net.Socket; | |
import java.util.Locale; | |
/** | |
* FTPSClient to patch TLS session resumption support in Apache FTPSClient | |
* see also: http://eng.wealthfront.com/2016/06/10/connecting-to-an-ftps-server-with-ssl-session-reuse-in-java-7-and-8/ | |
* see also: https://gist.github.com/lukehansen/cd1931426d1e432d0993005f9976e6fb | |
*/ | |
public class PatchedFTPSClient extends FTPSClient { | |
@Override protected void _prepareDataSocket_(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 new IOException(e); | |
} | |
} | |
} | |
} |
Hi. Thank you. I had to change .getDeclaredMethod("getHost"); for .getDeclaredMethod("getPeerHost"); in JRE8 (openJDK) to make it work. Also, in JRE8, you had to set the protocol in TLS1.2, with TLS1.3 fails (cause 1.8 doesn't support 1.3)
thanks, but I had to use this inside my android application and I wasn't able to access sessionsByHostAndPort key. So, I used RestrictionBypass and it worked!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi. Thank you. I had to change .getDeclaredMethod("getHost"); for .getDeclaredMethod("getPeerHost"); in JRE8 (openJDK) to make it work. Also, in JRE8, you had to set the protocol in TLS1.2, with TLS1.3 fails (cause 1.8 doesn't support 1.3)