Search code examples
javaftpfilezillaftpsftp4j

FTP4j fails to use FTPES (TLS session of data connection has not resumed or the session does not match the control connection)


I am trying to use ftp4j lib to get list of files from FileZilla FTP servcer with TLS.

import it.sauronsoftware.ftp4j.FTPClient;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.Arrays;

public class FTP {

    public static void main(String args[]) throws Exception {
        System.setProperty("http.protocols", "TLSv1,TLSv1.1,TLSv1.2"); 
        //tried to avoid closing connection during the handshake

        //load and set certificate
        KeyStore keyStore = KeyStore.getInstance("JKS");
        keyStore.load(new FileInputStream("mykeystore.jks"), "root12".toCharArray());

        FTPClient client = new FTPClient();

        SSLContext sslContext = null;
        try {
            javax.net.ssl.TrustManagerFactory tmf = javax.net.ssl.TrustManagerFactory
                    .getInstance(javax.net.ssl.KeyManagerFactory
                            .getDefaultAlgorithm());
            tmf.init(keyStore);
            sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, tmf.getTrustManagers(), new SecureRandom());
        } catch (Exception e) {
            e.printStackTrace();
        }

        SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

        client.setSSLSocketFactory(sslSocketFactory);
        client.setSecurity(FTPClient.SECURITY_FTPES);

        client.setCharset("UTF-8");
        client.setPassive(true);
        String[] arg = client.connect("localhost", 21);
        System.out.println(Arrays.toString(arg));

        client.login("admin", "pass"); //OK
        client.noop(); // aka Ping is OK
        String s = client.currentDirectory(); //OK
        client.changeDirectory("/"); //OK
        String[] files = client.listNames(); //Exception here
        System.out.println(Arrays.toString(files));
        client.disconnect(true);
    }
}

I got an exception

Exception in thread "main" it.sauronsoftware.ftp4j.FTPException [code=450, message= TLS session of data connection has not resumed or the session does not match the control connection] at it.sauronsoftware.ftp4j.FTPClient.listNames(FTPClient.java:2407) at FTP.main(FTP.java:49)

I tried to use active mode, but it doesn't help also (failed after ping command)

Exception in thread "main" it.sauronsoftware.ftp4j.FTPException [code=421, message= Rejected command, requested IP address does not match control connection IP.]

Could you please answer me what I've done wrong or does ftp4j library actually support FTPES & TLS?

Screenshots with FileZilla server TLS configuration:

FileZilla TLS configuration


Solution

  • ftp4j library does support FTPS/TLS. Were it not, you would not get the error in the first place.

    FileZilla FTP server is one of FTP servers, which require the clients to reuse the TLS/SSL session from FTP control connection for data connections:
    https://svn.filezilla-project.org/filezilla?view=revision&revision=6661

    This increases security by making it a way harder for an attacker to hijack a data connection.

    I do not know, if ftp4j supports the reuse this though.

    Alternative solutions are:

    • Use Java FTP client from Apache Commons Net library. While it does not support the reuse on its own, it's easy to add the support. See How to connect to FTPS server with data connection using same TLS session?
    • As you own the FTP server, you can disable the requirement for reuse. See the Require TLS session resumption on data connection when using PROT P option (on your screenshot). Though as mentioned above, it has some impact of security.