[ 
https://issues.apache.org/jira/browse/NET-408?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18066390#comment-18066390
 ] 

Tim Boeckstaens commented on NET-408:
-------------------------------------

We ran into the same issue.
Because we use java 21 the reflection fix does not work.

However we found a different workaround to make the TLS session reuse work 
without reflection on java internal SSL classes.

Our setup is: 
java client -> HTTP proxy -> FTP server that requires TLS session reuse between 
command and data connection

 
{code:java}
@Test
public void test() throws GeneralSecurityException, IOException {
    SSLContext sslContext = //custom setup with private key and custom 
truststore;
    FTPSClient ftpClient = new PatchedFTPSClient(sslContext);
    Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("x.x.x.x", 
8080));
    ftpClient.setProxy(proxy);
    // use java 1.7+ endpoint validation
    ftpClient.setEndpointCheckingEnabled(true);
    // debug logging
    ftpClient.addProtocolCommandListener(new PrintCommandListener(new 
PrintWriter(System.out), false));
    ftpClient.connect("ftphost");
    ftpClient.enterLocalPassiveMode();
    // use enhanced passive mode
    // this way server returns no IP and only PORT for data connection
    // by using the patched PatchedFTPSClient this results in a data connection 
to the host WITH TLS session reuse
    ftpClient.setUseEPSVwithIPv4(true);
    ftpClient.execPBSZ(0);
    ftpClient.execPROT("P");
    ftpClient.login("username", "");
    // Verify the connection
    if (ftpClient.isConnected()) {
        System.out.println("Connected in Enhanced Passive Mode.");
    }
    
    FTPFile[] files = ftpClient.listFiles();
    for (FTPFile file : files) {
        System.out.printf("File name: %s\n", file.getName());
    }
}
public class PatchedFTPSClient extends FTPSClient {
    public PatchedFTPSClient(SSLContext sslContext) {
        super(sslContext);
    }
    @Override
    protected void _parseExtendedPassiveModeReply(String reply) throws 
MalformedServerReplyException {
        super._parseExtendedPassiveModeReply(reply);
        try {
            // FTPClient::_parseExtendedPassiveModeReply sets the passiveHost 
to:
            // passiveHost = getRemoteAddress().getHostAddress();
            // for connections with a proxy this returns the proxy IP
            // resulting in client connecting to the proxy on the returned data 
connection port
            // and results in FTPClient stuck on:
            // EPSV
            // 229 Entering Extended Passive Mode (|||40001|)
            // LIST
            // To fix this we override the passiveHost field with the peer host 
of the sslsocket
            // this is the correct host and results in TLS session reuse
            Class<?> ftpClientClass = 
getClass().getSuperclass().getSuperclass();
            Field passiveHost = ftpClientClass.getDeclaredField("passiveHost");
            passiveHost.setAccessible(true);
            String peerHost = ((SSLSocket) _socket_).getSession().getPeerHost();
            passiveHost.set(this, peerHost);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}
{code}
 

 

> problem connecting to ProFTPD with FTPES
> ----------------------------------------
>
>                 Key: NET-408
>                 URL: https://issues.apache.org/jira/browse/NET-408
>             Project: Commons Net
>          Issue Type: Bug
>          Components: FTP
>    Affects Versions: 2.2, 3.0
>         Environment: ProFTPD 1.3.3d on SUSE Linux Enterprise Server 10.1 
> 32bit, Kernel 2.6.16.46-0.12-default (config file attached)
> ProFTPD 1.3.3d on OpenSUSE 64bit Linux 2.6.34.8-0.2-desktop
> Java 1.5
>            Reporter: Michael Voigt
>            Priority: Major
>         Attachments: BCFTPSClient.java, FTPSClientWithTLSResumption.zip, 
> PTFTPSClient.java, ftpes.jpg, proftpd.conf
>
>
> I have a problem with the FTPClient connecting to a ProFTPD server.
> If the server uses the configuration option "TLSProtocol TLSv1", I
> cannot connect to it at all. I recieve the following error message:
> - javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection
> On the server side I see in the log:
> unable to accept TLS connection: protocol error:
> -  (1) error:14094416:SSL routines:SSL3_READ_BYTES:sslv3 alert
> certificate unknown
> - TLS/TLS-C negotiation failed on control channel
> If the server uses the configuration option "TLSProtocol SSLv23", I
> can connect to it but I cant transfer any files. In the server log I
> see:
> - starting TLS negotiation on data connection
> - TLSv1/SSLv3 renegotiation accepted, using cipher RC4-MD5 (128 bits)
> - client did not reuse SSL session, rejecting data connection (see
> TLSOption NoSessionReuseRequired)
> - unable to open data connection: TLS negotiation failed
> If I add the NoSessionReuseRequired parameter to the ProFTPD config
> everything works fine.
> Here is my code:
>                FTPClient ftpClient = new FTPClient();
>                ftpClient = new FTPSClient("TLS");
>                // this throws an exception with TLSProtocol TLSv1
>                ftpClient.connect(host, port);
>                int reply = ftpClient.getReplyCode();
>                if (!FTPReply.isPositiveCompletion(reply)) {
>                        ftpClient.disconnect();
>                        log.error("The FTP Server did not return a positive 
> completion reply!");
>                        throw new 
> FtpTransferException(ECCUtils.ERROR_FTP_CONNECTION);
>                }
>                boolean loginSuccessful = ftpClient.login(userName, password);
>                if (!loginSuccessful) {
>                        log.error("Login to the FTP Server failed! The 
> credentials are not valid.");
>                        throw new 
> FtpTransferException(ECCUtils.ERROR_FTP_LOGIN);
>                }
>                ftpClient.execPBSZ(0);
>                ftpClient.execPROT("P");
>                boolean success = ftpClient.storeFile(fileName, fis);
>                if (!success) {
>                        // this is false if "NoSessionReuseRequired" is not set
>                }
> Now my question is if it is generally possible to connect to a server
> with "TLSProtocol TLSv1" or "TLSProtocol SSLv23" without the
> "NoSessionReuseRequired" parameter? Could someone provide a piece of
> example code for this?



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to