3

I have a very simple Java 8 project (FTP server), which uses Apache FTPS (Mina) server library (v. 1.1.1). It is as simple as the following code:

    ListenerFactory factory = new ListenerFactory();
    factory.setPort(2221);
    
    // SSL config
    SslConfigurationFactory ssl = new SslConfigurationFactory();
    ssl.setKeystoreFile(new File("keystore.jks"));
    ssl.setKeystorePassword("password");
    // set the SSL configuration for the listener
    factory.setSslConfiguration(ssl.createSslConfiguration());
    factory.setImplicitSsl(true);

    FtpServerFactory serverFactory = new FtpServerFactory();
    // replace the default listener
    serverFactory.addListener("default", factory.createListener());
    
    //Configure user manager and set admin user
    PropertiesUserManagerFactory userManagerFactory = new PropertiesUserManagerFactory();
    userManagerFactory.setFile(new File("users.properties"));
    UserManager userManager = userManagerFactory.createUserManager();
    if (!userManager.doesExist("admin")) {
        BaseUser user = new BaseUser();
        user.setName("admin");
        user.setPassword("password");
        user.setEnabled(true);
        user.setHomeDirectory(USER_HOME_DIR);
        user.setAuthorities(Collections.<Authority>singletonList(new WritePermission()));
        userManager.save(user);
    }
    serverFactory.setUserManager(userManager);

   // start the server
   FtpServer server = serverFactory.createServer(); 
   server.start();

Needed maven dependencies:

    <dependency>
        <groupId>org.apache.ftpserver</groupId>
        <artifactId>ftpserver-core</artifactId>
        <version>1.1.1</version>
    </dependency>

to simply create a self-signed Keystore:

keytool -genkey -keyalg RSA -alias self-signed -keystore keystore.jks -validity 360 -keysize 2048

I followed the official guide to write this code: https://mina.apache.org/ftpserver-project/embedding_ftpserver.html

If I compile and run this code with Java 8, my FTPS server works perfectly fine, I can reach this server through localhost:2221 and with username "admin" and password "password". From my FTP client (I use Filezilla), I can see that the TLS connection was successfully established.

If I compile and run the same code with Java 11+ (I tried with 11 and 15), I see the following message in my FTP client, and the directory listing fails:

Status:         Connecting to 127.0.0.1:2223...
Status:         Connection established, initializing TLS...
Status:         Verifying certificate...
Status:         TLS connection established, waiting for welcome message...
Status:         Logged in
Status:         Retrieving directory listing...
Command:    PWD
Response:   257 "/" is current directory.
Command:    TYPE I
Response:   200 Command TYPE okay.
Command:    PASV
Response:   227 Entering Passive Mode (127,0,0,1,225,229)
Command:    MLSD
Response:   150 File status okay; about to open data connection.
Error:          Received TLS alert from the server: User canceled (90)
Error:          Could not read from transfer socket: ECONNABORTED - Connection aborted
Response:   226 Closing data connection.
Error:          Failed to retrieve directory listing

And this is the full application log (with VM parameter ):

2021-03-30 22:59:09.304  INFO 10557 --- [           main] com.example.ftp.demo.DemoApplication     : Starting DemoApplication using Java 11.0.7 on Kara's-MBP with PID 10557 (...)
2021-03-30 22:59:09.306  INFO 10557 --- [           main] com.example.ftp.demo.DemoApplication     : No active profile set, falling back to default profiles: default
2021-03-30 22:59:09.601  INFO 10557 --- [           main] com.example.ftp.demo.DemoApplication     : Started DemoApplication in 0.487 seconds (JVM running for 1.046)
javax.net.ssl|DEBUG|01|main|2021-03-30 22:59:09.886 CEST|SSLCipher.java:438|jdk.tls.keyLimits:  entry = AES/GCM/NoPadding KeyUpdate 2^37. AES/GCM/NOPADDING:KEYUPDATE = 137438953472
2021-03-30 22:59:09.966  INFO 10557 --- [           main] o.a.ftpserver.impl.DefaultFtpServer      : FTP server started
2021-03-30 22:59:24.393  INFO 10557 --- [ NioProcessor-3] o.a.f.listener.nio.FtpLoggingFilter      : CREATED
2021-03-30 22:59:24.395  INFO 10557 --- [pool-3-thread-1] o.a.f.listener.nio.FtpLoggingFilter      : OPENED
javax.net.ssl|DEBUG|1B|NioProcessor-3|2021-03-30 22:59:24.443 CEST|SSLCipher.java:1840|KeyLimit read side: algorithm = AES/GCM/NOPADDING:KEYUPDATE-countdown value = 137438953472
javax.net.ssl|DEBUG|1B|NioProcessor-3|2021-03-30 22:59:24.444 CEST|SSLCipher.java:1994|KeyLimit write side: algorithm = AES/GCM/NOPADDING:KEYUPDATE-countdown value = 137438953472
javax.net.ssl|DEBUG|1B|NioProcessor-3|2021-03-30 22:59:24.472 CEST|SSLCipher.java:1994|KeyLimit write side: algorithm = AES/GCM/NOPADDING:KEYUPDATE-countdown value = 137438953472
javax.net.ssl|DEBUG|1B|NioProcessor-3|2021-03-30 22:59:24.490 CEST|SSLCipher.java:1840|KeyLimit read side: algorithm = AES/GCM/NOPADDING:KEYUPDATE-countdown value = 137438953472
2021-03-30 22:59:24.493  INFO 10557 --- [pool-3-thread-1] o.a.f.listener.nio.FtpLoggingFilter      : SENT: 220 Service ready for new user.

2021-03-30 22:59:24.501  INFO 10557 --- [pool-3-thread-1] o.a.f.listener.nio.FtpLoggingFilter      : RECEIVED: USER admin
2021-03-30 22:59:24.503  INFO 10557 --- [pool-3-thread-1] o.a.f.listener.nio.FtpLoggingFilter      : SENT: 331 User name okay, need password for admin.

2021-03-30 22:59:24.503  INFO 10557 --- [pool-3-thread-1] o.a.f.listener.nio.FtpLoggingFilter      : RECEIVED: PASS *****
2021-03-30 22:59:24.505  INFO 10557 --- [pool-3-thread-1] org.apache.ftpserver.command.impl.PASS   : Login success - admin
2021-03-30 22:59:24.505  INFO 10557 --- [pool-3-thread-1] o.a.f.listener.nio.FtpLoggingFilter      : SENT: 230 User logged in, proceed.

2021-03-30 22:59:24.505  INFO 10557 --- [pool-3-thread-2] o.a.f.listener.nio.FtpLoggingFilter      : RECEIVED: OPTS UTF8 ON
2021-03-30 22:59:24.506  INFO 10557 --- [pool-3-thread-2] o.a.f.listener.nio.FtpLoggingFilter      : SENT: 200 Command OPTS okay.

2021-03-30 22:59:24.506  INFO 10557 --- [pool-3-thread-1] o.a.f.listener.nio.FtpLoggingFilter      : RECEIVED: PBSZ 0
2021-03-30 22:59:24.506  INFO 10557 --- [pool-3-thread-1] o.a.f.listener.nio.FtpLoggingFilter      : SENT: 200 Command PBSZ okay.

2021-03-30 22:59:24.507  INFO 10557 --- [pool-3-thread-2] o.a.f.listener.nio.FtpLoggingFilter      : RECEIVED: PROT P
2021-03-30 22:59:24.508  INFO 10557 --- [pool-3-thread-2] o.a.f.listener.nio.FtpLoggingFilter      : SENT: 200 Command PROT okay.

2021-03-30 22:59:24.508  INFO 10557 --- [pool-3-thread-1] o.a.f.listener.nio.FtpLoggingFilter      : RECEIVED: OPTS MLST size;modify;type;
2021-03-30 22:59:24.509  INFO 10557 --- [pool-3-thread-1] o.a.f.listener.nio.FtpLoggingFilter      : SENT: 200 Command OPTS okay.

2021-03-30 22:59:24.509  INFO 10557 --- [pool-3-thread-2] o.a.f.listener.nio.FtpLoggingFilter      : RECEIVED: CWD /
2021-03-30 22:59:24.511  INFO 10557 --- [pool-3-thread-2] o.a.f.listener.nio.FtpLoggingFilter      : SENT: 250 Directory changed to /

2021-03-30 22:59:24.511  INFO 10557 --- [pool-3-thread-2] o.a.f.listener.nio.FtpLoggingFilter      : RECEIVED: TYPE I
2021-03-30 22:59:24.512  INFO 10557 --- [pool-3-thread-2] o.a.f.listener.nio.FtpLoggingFilter      : SENT: 200 Command TYPE okay.

2021-03-30 22:59:24.512  INFO 10557 --- [pool-3-thread-1] o.a.f.listener.nio.FtpLoggingFilter      : RECEIVED: PASV
2021-03-30 22:59:24.513  INFO 10557 --- [pool-3-thread-1] o.a.f.listener.nio.FtpLoggingFilter      : SENT: 227 Entering Passive Mode (127,0,0,1,226,235)

2021-03-30 22:59:24.513  INFO 10557 --- [pool-3-thread-2] o.a.f.listener.nio.FtpLoggingFilter      : RECEIVED: MLSD
javax.net.ssl|DEBUG|1D|pool-3-thread-2|2021-03-30 22:59:24.526 CEST|SSLCipher.java:1840|KeyLimit read side: algorithm = AES/GCM/NOPADDING:KEYUPDATE-countdown value = 137438953472
javax.net.ssl|DEBUG|1D|pool-3-thread-2|2021-03-30 22:59:24.527 CEST|SSLCipher.java:1994|KeyLimit write side: algorithm = AES/GCM/NOPADDING:KEYUPDATE-countdown value = 137438953472
javax.net.ssl|DEBUG|1D|pool-3-thread-2|2021-03-30 22:59:24.528 CEST|SSLCipher.java:1994|KeyLimit write side: algorithm = AES/GCM/NOPADDING:KEYUPDATE-countdown value = 137438953472
javax.net.ssl|DEBUG|1D|pool-3-thread-2|2021-03-30 22:59:24.529 CEST|SSLCipher.java:1840|KeyLimit read side: algorithm = AES/GCM/NOPADDING:KEYUPDATE-countdown value = 137438953472
javax.net.ssl|ALL|1D|pool-3-thread-2|2021-03-30 22:59:24.533 CEST|SSLSocketImpl.java:994|Closing output stream
javax.net.ssl|DEBUG|1D|pool-3-thread-2|2021-03-30 22:59:24.533 CEST|SSLSocketImpl.java:466|duplex close of SSLSocket
javax.net.ssl|DEBUG|1D|pool-3-thread-2|2021-03-30 22:59:24.534 CEST|SSLSocketImpl.java:1372|close the SSL connection (passive)
2021-03-30 22:59:24.535  WARN 10557 --- [pool-3-thread-2] org.apache.ftpserver.impl.PassivePorts   : Releasing unreserved passive port: 58091
2021-03-30 22:59:24.535  INFO 10557 --- [pool-3-thread-2] o.a.f.listener.nio.FtpLoggingFilter      : SENT: 150 File status okay; about to open data connection.

2021-03-30 22:59:24.535  INFO 10557 --- [pool-3-thread-2] o.a.f.listener.nio.FtpLoggingFilter      : SENT: 226 Closing data connection.

Additionally, if I remove SSL support from the code, my FTP server works perfectly fine even with Java 11+.

Is anybody of you guys experienced similar issues with Apache FTPS and Java 11+? If yes how did you find a solution?

Sam Joshua
  • 310
  • 6
  • 17
gubak
  • 31
  • 3

2 Answers2

2

I can reproduce the problem only when using FileZilla. When I use lftp, for example, I can connect successfully to the server (after trusting the self signed certificate).

FileZilla seems to have a problem with the jdk's implementation of TLSv1.3. There is a closed (rejected) ticket about this in Filezilla's bugtracker [1].

Also, I can reproduce the problem when using jdk 8. TLSv1.3 was added and enabled in jdk 8 since 8u261-b12 [2].

As a workaround, you can disable TLSv1.3 by using a security property jdk.tls.disabledAlgorithms [3] which will force the jvm to choose another algorithm for the security handshake (hopefully it'll be TLSv1.2).(As this is a security setting it's best to discuss it with your security team if you have one in your company).

The security property can be set or updated in jdk's configuration file java.security. Its path depends on the jdk and OS you're using.

Usually it is under $JAVA_HOME/jre/lib/security or $JAVA_HOME/lib/security.

If you can't find it, you can print its path by launching the jvm with -Djava.security.debug=all. You should see the path printed in the startup logs (there may be several files). Look for something similar to the following lines :

properties: reading security properties file: /usr/lib/jvm/java-11-openjdk-11.0.11.0.9-4.fc34.x86_64/conf/security/java.security
...
properties: reading system security properties file /etc/crypto-policies/back-ends/java.config

You can also update jdk.tls.disabledAlgorithms programmatically by adding the two following lines before ssl.createSslConfiguration():

String disabledAlgorithms = Security.getProperty("jdk.tls.disabledAlgorithms") + ", TLSv1.3";
Security.setProperty("jdk.tls.disabledAlgorithms", disabledAlgorithms);

Here is the complete program with the added two lines:

import org.apache.ftpserver.FtpServer;
import org.apache.ftpserver.FtpServerFactory;
import org.apache.ftpserver.ftplet.Authority;
import org.apache.ftpserver.ftplet.FtpException;
import org.apache.ftpserver.ftplet.UserManager;
import org.apache.ftpserver.listener.ListenerFactory;
import org.apache.ftpserver.ssl.SslConfigurationFactory;
import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory;
import org.apache.ftpserver.usermanager.impl.BaseUser;
import org.apache.ftpserver.usermanager.impl.WritePermission;

import java.io.File;
import java.security.Security;
import java.util.Collections;

public class Main {
    public static void main(String[] args) throws FtpException {
        String disabledAlgorithms = Security.getProperty("jdk.tls.disabledAlgorithms") + ", TLSv1.3";
        Security.setProperty("jdk.tls.disabledAlgorithms", disabledAlgorithms);

        ListenerFactory factory = new ListenerFactory();
        factory.setPort(2221);

        // SSL config
        SslConfigurationFactory ssl = new SslConfigurationFactory();
        ssl.setKeystoreFile(new File("keystore.jks"));
        ssl.setKeystorePassword("password");
        // set the SSL configuration for the listener
        factory.setSslConfiguration(ssl.createSslConfiguration());
        factory.setImplicitSsl(true);

        FtpServerFactory serverFactory = new FtpServerFactory();
        // replace the default listener
        serverFactory.addListener("default", factory.createListener());

        //Configure user manager and set admin user
        PropertiesUserManagerFactory userManagerFactory = new PropertiesUserManagerFactory();
        userManagerFactory.setFile(new File("users.properties"));
        UserManager userManager = userManagerFactory.createUserManager();
        if (!userManager.doesExist("admin")) {
            BaseUser user = new BaseUser();
            user.setName("admin");
            user.setPassword("password");
            user.setEnabled(true);
            user.setHomeDirectory("/tmp/admin");
            user.setAuthorities(Collections.<Authority>singletonList(new WritePermission()));
            userManager.save(user);
        }
        serverFactory.setUserManager(userManager);

        // start the server
        FtpServer server = serverFactory.createServer();
        server.start();
    }
}

[1] : https://trac.filezilla-project.org/ticket/12099

[2] : https://www.oracle.com/java/technologies/javase/8u261-relnotes.html

[3] : https://docs.oracle.com/en/java/javase/11/security/java-secure-socket-extension-jsse-reference-guide.html#GUID-0A438179-32A7-4900-A81C-29E3073E1E90

Mohamed AMAZIRH
  • 1,159
  • 7
  • 26
1

Thanks for the detailed information from @Mohamed.

I just met this issue recently, would like to share the recent testing result. I can reproduce this issue with JDK 16.0.1_64 with FileZilla pro 3.57.1; and JDK 16.0.1_64 with winscp 5.15.5 works fine; and JDK 17.0.1_64 with FileZilla pro 3.57.1 works fine;

Which means using JDK 17.0.1_64 can be a solution.

LingYan Meng
  • 699
  • 4
  • 12