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

j-verse commented on NET-687:
-----------------------------

The issue is caused by the following commit:
[https://github.com/apache/commons-net/commit/c660afa96016f6cd2de356439b58fa9c4443d467]

This commit moves the SSL socket creation (from a normal socket) to a separate 
function in order to also use it when opening the data connection:
{code:java}
    @Override
    protected Socket _openDataConnection_(String command, String arg)
            throws IOException {
        Socket socket = super._openDataConnection_(command, arg);
        socket = createSSLSocket(socket);
        _prepareDataSocket_(socket);
        if (socket instanceof SSLSocket) {
            SSLSocket sslSocket = (SSLSocket)socket;            
sslSocket.setUseClientMode(isClientMode);
            sslSocket.setEnableSessionCreation(isCreation);            // 
server mode
            if (!isClientMode) {
                sslSocket.setNeedClientAuth(isNeedClientAuth);
                sslSocket.setWantClientAuth(isWantClientAuth);
            }
            if (suites != null) {
                sslSocket.setEnabledCipherSuites(suites);
            }
            if (protocols != null) {
                sslSocket.setEnabledProtocols(protocols);
            }
            sslSocket.startHandshake();
        }        return socket;
    }
{code}
This might seem logical, but it is incorrect. The super call to 
_openDataConnection_ internally uses the socket factory to obtain a new socket. 
When we want the data connection to also use SSL, we execute a PROT P command 
to the server. This is done use the execPROT function:
{code:java}
    public void execPROT(String prot) throws SSLException, IOException {
        if (prot == null) {
            prot = DEFAULT_PROT;
        }
        if (!checkPROTValue(prot)) {
            throw new IllegalArgumentException();
        }
        if (FTPReply.COMMAND_OK != sendCommand(CMD_PROT, prot)) {
            throw new SSLException(getReplyString());
        }
        if (DEFAULT_PROT.equals(prot)) {
            setSocketFactory(null);
            setServerSocketFactory(null);
        } else {
            setSocketFactory(new FTPSSocketFactory(context));
            setServerSocketFactory(new FTPSServerSocketFactory(context));
            initSslContext();
        }
    }
{code}
This function sets the socket factory to be a FTPSSocketFactory when prot is P 
(DEFAULT_PROT is C). The FTPSSocketFactory already returns SSL sockets when 
asked to build a new socket. The line added in the mentioned commit when 
opening the data connection thus builds a SSL socket over what is already a SSL 
socket. This causes the first SSL handshake to trigger another SSL handshake on 
the stacked SSL sockets and this eventually leads to the "Unsupported or 
unrecognized SSL message" exception because one of them tries to interpret 
application data as a handshake message.

Removing the line added in the mentioned commit fixes the issue. I've opened a 
pull request:
[https://github.com/apache/commons-net/pull/59]

 

> FTP data connection error Unsupported or unrecognized SSL message. Probably 
> another ssl_reuse session error ?
> -------------------------------------------------------------------------------------------------------------
>
>                 Key: NET-687
>                 URL: https://issues.apache.org/jira/browse/NET-687
>             Project: Commons Net
>          Issue Type: Bug
>          Components: FTP
>    Affects Versions: 3.7
>         Environment: Tested with JDK 8, 11, 13, 14
>            Reporter: Mikael
>            Priority: Major
>
> After adding the self signed polynesie.cer certificate to JVM security 
> (_jdk-x.x.x/lib/security_) :
> {code:java}
> keytool.exe -import -storepass "changeit" -keystore "./cacerts" -alias 
> polynesie.cer -file ./polynesie.cer -noprompt{code}
>  polynesie.cer obtained by copying certificate part from this command line 
> result :
> {code:java}
> openssl s_client -connect ftp0.gov.pf:21 -starttls ftp{code}
> Trying to retrieve a file with ftpes :
> {code:java}
> java -cp commons-net-examples-3.5.jar;commons-net-3.5.jar 
> examples/ftp/FTPClientExample -A -p TLS,false -e -b ftp0.gov.pf 
> DataVRS/fiche_Station_VRS_VAI1.pdf fiche_Station_VRS_VAI1.pdf{code}
> Produce this exception :
> {code:java}
> javax.net.ssl.SSLException: Unsupported or unrecognized SSL message
>         at 
> java.base/sun.security.ssl.SSLSocketInputRecord.handleUnknownRecord(Unknown 
> Source)
>         at java.base/sun.security.ssl.SSLSocketInputRecord.decode(Unknown 
> Source)
>         at java.base/sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
>         at java.base/sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
>         at 
> java.base/sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown 
> Source)
>         at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(Unknown 
> Source)
>         at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(Unknown 
> Source)
>         at 
> org.apache.commons.net.ftp.FTPSClient._openDataConnection_(FTPSClient.java:642)
>         at 
> org.apache.commons.net.ftp.FTPClient._retrieveFile(FTPClient.java:1907)
>         at 
> org.apache.commons.net.ftp.FTPClient.retrieveFile(FTPClient.java:1893)
>         at testFTP2.FTPClientExample.main(FTPClientExample.java:513)
> {code}
> It is probably the same error of ssl_reuse session as NET-408.
> Same try with ftp4j library reports this error :
> {code:java}
> code=522, message= SSL connection failed; session reuse required: see 
> require_ssl_reuse option in vsftpd.conf man page
> {code}
>  



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to