    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      https://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017
    018package org.apache.commons.net.ftp;
    019
    020import java.io.BufferedReader;
    021import java.io.BufferedWriter;
    022import java.io.IOException;
    023import java.io.InputStreamReader;
    024import java.io.OutputStreamWriter;
    025import java.net.Inet6Address;
    026import java.net.InetAddress;
    027import java.net.InetSocketAddress;
    028import java.net.ServerSocket;
    029import java.net.Socket;
    030import java.util.Base64;
    031
    032import javax.net.ssl.HostnameVerifier;
    033import javax.net.ssl.KeyManager;
    034import javax.net.ssl.SSLContext;
    035import javax.net.ssl.SSLException;
    036import javax.net.ssl.SSLHandshakeException;
    037import javax.net.ssl.SSLSocket;
    038import javax.net.ssl.SSLSocketFactory;
    039import javax.net.ssl.TrustManager;
    040
    041import org.apache.commons.io.IOUtils;
    042import org.apache.commons.net.util.SSLContextUtils;
    043import org.apache.commons.net.util.SSLSocketUtils;
    044import org.apache.commons.net.util.TrustManagerUtils;
    045
    046/**
    047 * FTP over SSL processing. If desired, the JVM property -Djavax.net.debug=all can be used to see wire-level SSL details.
    048 *
    049 * Warning: the hostname is not verified against the certificate by default, use {@link #setHostnameVerifier(HostnameVerifier)} or
    050 * {@link #setEndpointCheckingEnabled(boolean)} (on Java 1.7+) to enable verification. Verification is only performed on client mode connections.
    051 *
    052 * @since 2.0
    053 */
    054public class FTPSClient extends FTPClient {
    055
    056// From http://www.iana.org/assignments/port-numbers
    057
    058//    ftps-data   989/tcp    ftp protocol, data, over TLS/SSL
    059//    ftps-data   989/udp    ftp protocol, data, over TLS/SSL
    060//    ftps        990/tcp    ftp protocol, control, over TLS/SSL
    061//    ftps        990/udp    ftp protocol, control, over TLS/SSL
    062
    063    /** Default FTPS data port. */
    064    public static final int DEFAULT_FTPS_DATA_PORT = 989;
    065
    066    /** Default FTPS port. */
    067    public static final int DEFAULT_FTPS_PORT = 990;
    068
    069    /** The value that I can set in PROT command (C = Clear, P = Protected) */
    070    private static final String[] PROT_COMMAND_VALUE = { "C", "E", "S", "P" };
    071
    072    /** Default PROT Command */
    073    private static final String DEFAULT_PROT = "C";
    074
    075    /** Default secure socket protocol name, i.e. TLS */
    076    private static final String DEFAULT_PROTOCOL = "TLS";
    077
    078    /** The AUTH (Authentication/Security Mechanism) command. */
    079    private static final String CMD_AUTH = "AUTH";
    080
    081    /** The ADAT (Authentication/Security Data) command. */
    082    private static final String CMD_ADAT = "ADAT";
    083
    084    /** The PROT (Data Channel Protection Level) command. */
    085    private static final String CMD_PROT = "PROT";
    086
    087    /** The PBSZ (Protection Buffer Size) command. */
    088    private static final String CMD_PBSZ = "PBSZ";
    089
    090    /** The MIC (Integrity Protected Command) command. */
    091    private static final String CMD_MIC = "MIC";
    092
    093    /** The CONF (Confidentiality Protected Command) command. */
    094    private static final String CMD_CONF = "CONF";
    095
    096    /** The ENC (Privacy Protected Command) command. */
    097    private static final String CMD_ENC = "ENC";
    098
    099    /** The CCC (Clear Command Channel) command. */
    100    private static final String CMD_CCC = "CCC";
    101
    102    /** @deprecated - not used - may be removed in a future release */
    103    @Deprecated
    104    public static String KEYSTORE_ALGORITHM;
    105
    106    /** @deprecated - not used - may be removed in a future release */
    107    @Deprecated
    108    public static String TRUSTSTORE_ALGORITHM;
    109
    110    /** @deprecated - not used - may be removed in a future release */
    111    @Deprecated
    112    public static String PROVIDER;
    113
    114    /** @deprecated - not used - may be removed in a future release */
    115    @Deprecated
    116    public static String STORE_TYPE;
    117
    118    /** The security mode. (True - Implicit Mode / False - Explicit Mode) */
    119    private final boolean isImplicit;
    120
    121    /** The secure socket protocol to be used, e.g. SSL/TLS. */
    122    private final String protocol;
    123
    124    /** The AUTH Command value */
    125    private String auth = DEFAULT_PROTOCOL;
    126
    127    /** The context object. */
    128    private SSLContext context;
    129
    130    /** The socket object. */
    131    private Socket plainSocket;
    132
    133    /** Controls whether a new SSL session may be established by this socket. Default true. */
    134    private boolean isCreation = true;
    135
    136    /** The use client mode flag. */
    137    private boolean isClientMode = true;
    138
    139    /** The need client auth flag. */
    140    private boolean isNeedClientAuth;
    141
    142    /** The want client auth flag. */
    143    private boolean isWantClientAuth;
    144
    145    /** The cipher suites */
    146    private String[] suites;
    147
    148    /** The protocol versions */
    149    private String[] protocols;
    150
    151    /**
    152     * The FTPS {@link TrustManager} implementation, default validate only {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}.
    153     */
    154    private TrustManager trustManager = TrustManagerUtils.getValidateServerCertificateTrustManager();
    155
    156    /** The {@link KeyManager}, default null (i.e. use system default). */
    157    private KeyManager keyManager;
    158
    159    /** The {@link HostnameVerifier} to use post-TLS, default null (i.e. no verification). */
    160    private HostnameVerifier hostnameVerifier;
    161
    162    /** Use Java 1.7+ HTTPS Endpoint Identification Algorithm. */
    163    private boolean tlsEndpointChecking;
    164
    165    /**
    166     * Constructor for FTPSClient, calls {@link #FTPSClient(String, boolean)}.
    167     *
    168     * Sets protocol to {@link #DEFAULT_PROTOCOL} - i.e. TLS - and security mode to explicit (isImplicit = false)
    169     */
    170    public FTPSClient() {
    171        this(DEFAULT_PROTOCOL, false);
    172    }
    173
    174    /**
    175     * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS Calls {@link #FTPSClient(String, boolean)}
    176     *
    177     * @param isImplicit The security mode (Implicit/Explicit).
    178     */
    179    public FTPSClient(final boolean isImplicit) {
    180        this(DEFAULT_PROTOCOL, isImplicit);
    181    }
    182
    183    /**
    184     * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS The default TrustManager is set from
    185     * {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}
    186     *
    187     * @param isImplicit The security mode(Implicit/Explicit).
    188     * @param context    A pre-configured SSL Context
    189     */
    190    public FTPSClient(final boolean isImplicit, final SSLContext context) {
    191        this(DEFAULT_PROTOCOL, isImplicit);
    192        this.context = context;
    193    }
    194
    195    /**
    196     * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS and isImplicit {@code false} Calls {@link #FTPSClient(boolean, SSLContext)}
    197     *
    198     * @param context A pre-configured SSL Context
    199     */
    200    public FTPSClient(final SSLContext context) {
    201        this(false, context);
    202    }
    203
    204    /**
    205     * Constructor for FTPSClient, using explicit mode, calls {@link #FTPSClient(String, boolean)}.
    206     *
    207     * @param protocol the protocol to use
    208     */
    209    public FTPSClient(final String protocol) {
    210        this(protocol, false);
    211    }
    212
    213    /**
    214     * Constructor for FTPSClient allowing specification of protocol and security mode. If isImplicit is true, the port is set to {@link #DEFAULT_FTPS_PORT}
    215     * i.e. 990. The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}
    216     *
    217     * @param protocol   the protocol
    218     * @param isImplicit The security mode(Implicit/Explicit).
    219     */
    220    public FTPSClient(final String protocol, final boolean isImplicit) {
    221        this.protocol = protocol;
    222        this.isImplicit = isImplicit;
    223        if (isImplicit) {
    224            setDefaultPort(DEFAULT_FTPS_PORT);
    225        }
    226    }
    227
    228    /**
    229     * Because there are so many connect() methods, the _connectAction_() method is provided as a means of performing some action immediately after establishing
    230     * a connection, rather than reimplementing all the connect() methods.
    231     *
    232     * @throws IOException If there is any problem with establishing the connection.
    233     * @see org.apache.commons.net.SocketClient#_connectAction_()
    234     */
    235    @Override
    236    protected void _connectAction_() throws IOException {
    237        // Implicit mode.
    238        if (isImplicit) {
    239            applySocketAttributes();
    240            sslNegotiation();
    241        }
    242        super._connectAction_();
    243        // Explicit mode.
    244        if (!isImplicit) {
    245            execAUTH();
    246            sslNegotiation();
    247        }
    248    }
    249
    250    /**
    251     * Returns a socket of the data connection. Wrapped as an {@link SSLSocket}, which carries out handshake processing.
    252     *
    253     * @param command The int representation of the FTP command to send.
    254     * @param arg     The arguments to the FTP command. If this parameter is set to null, then the command is sent with no arguments.
    255     * @return corresponding to the established data connection. Null is returned if an FTP protocol error is reported at any point during the establishment and
    256     *         initialization of the connection.
    257     * @throws IOException If there is any problem with the connection.
    258     * @see FTPClient#_openDataConnection_(int, String)
    259     * @deprecated (3.3) Use {@link FTPClient#_openDataConnection_(FTPCmd, String)} instead
    260     */
    261    @Override
    262    // Strictly speaking this is not needed, but it works round a Clirr bug
    263    // So rather than invoke the parent code, we do it here
    264    @Deprecated
    265    protected Socket _openDataConnection_(final int command, final String arg) throws IOException {
    266        return _openDataConnection_(FTPCommand.getCommand(command), arg);
    267    }
    268
    269    /**
    270     * Returns a socket of the data connection. Wrapped as an {@link SSLSocket}, which carries out handshake processing.
    271     *
    272     * @param command The textual representation of the FTP command to send.
    273     * @param arg     The arguments to the FTP command. If this parameter is set to null, then the command is sent with no arguments.
    274     * @return corresponding to the established data connection. Null is returned if an FTP protocol error is reported at any point during the establishment and
    275     *         initialization of the connection.
    276     * @throws IOException If there is any problem with the connection.
    277     * @see FTPClient#_openDataConnection_(int, String)
    278     * @since 3.2
    279     */
    280    @Override
    281    protected Socket _openDataConnection_(final String command, final String arg) throws IOException {
    282        final Socket socket = openDataSecureConnection(command, arg);
    283        _prepareDataSocket_(socket);
    284        if (socket instanceof SSLSocket) {
    285            final SSLSocket sslSocket = (SSLSocket) socket;
    286
    287            sslSocket.setUseClientMode(isClientMode);
    288            sslSocket.setEnableSessionCreation(isCreation);
    289
    290            // server mode
    291            if (!isClientMode) {
    292                sslSocket.setNeedClientAuth(isNeedClientAuth);
    293                sslSocket.setWantClientAuth(isWantClientAuth);
    294            }
    295            if (suites != null) {
    296                sslSocket.setEnabledCipherSuites(suites);
    297            }
    298            if (protocols != null) {
    299                sslSocket.setEnabledProtocols(protocols);
    300            }
    301            sslSocket.startHandshake();
    302        }
    303
    304        return socket;
    305    }
    306
    307    /**
    308     * Performs any custom initialization for a newly created SSLSocket (before the SSL handshake happens). Called by {@link #_openDataConnection_(int, String)}
    309     * immediately after creating the socket. The default implementation is a no-op
    310     *
    311     * @param socket the socket to set up
    312     * @throws IOException on error
    313     * @since 3.1
    314     */
    315    protected void _prepareDataSocket_(final Socket socket) throws IOException {
    316    }
    317
    318    /**
    319     * Check the value that can be set in PROT Command value.
    320     *
    321     * @param prot Data Channel Protection Level.
    322     * @return True - A set point is right / False - A set point is not right
    323     */
    324    private boolean checkPROTValue(final String prot) {
    325        for (final String element : PROT_COMMAND_VALUE) {
    326            if (element.equals(prot)) {
    327                return true;
    328            }
    329        }
    330        return false;
    331    }
    332
    333    /**
    334     * Closes sockets.
    335     *
    336     * @param socket    main socket for proxy if enabled.
    337     * @param sslSocket SSL socket.
    338     * @throws IOException closing sockets is not successful.
    339     */
    340    private void closeSockets(final Socket socket, final Socket sslSocket) throws IOException {
    341        IOUtils.close(socket, sslSocket);
    342    }
    343
    344    /**
    345     * Create SSL socket from plain socket.
    346     *
    347     * @param socket
    348     * @return SSL Socket
    349     * @throws IOException
    350     */
    351    private SSLSocket createSSLSocket(final Socket socket) throws IOException {
    352        if (socket != null) {
    353            final SSLSocketFactory f = context.getSocketFactory();
    354            return (SSLSocket) f.createSocket(socket, _hostname_, socket.getPort(), false);
    355        }
    356        return null;
    357    }
    358
    359    /**
    360     * Closes the connection to the FTP server and restores connection parameters to the default values.
    361     * <p>
    362     * Calls {@code setSocketFactory(null)} and {@code setServerSocketFactory(null)} to reset the factories that may have been changed during the session, e.g.
    363     * by {@link #execPROT(String)}
    364     *
    365     * @throws IOException If an error occurs while disconnecting.
    366     * @since 3.0
    367     */
    368    @Override
    369    public void disconnect() throws IOException {
    370        super.disconnect();
    371        IOUtils.close(plainSocket);
    372        setSocketFactory(null);
    373        setServerSocketFactory(null);
    374    }
    375
    376    /**
    377     * Sends the ADAT command with the specified authentication data.
    378     *
    379     * @param data The data to send with the command.
    380     * @return server reply.
    381     * @throws IOException If an I/O error occurs while sending the command.
    382     * @since 3.0
    383     */
    384    public int execADAT(final byte[] data) throws IOException {
    385        if (data != null) {
    386            return sendCommand(CMD_ADAT, Base64.getEncoder().encodeToString(data));
    387        }
    388        return sendCommand(CMD_ADAT);
    389    }
    390
    391    /**
    392     * Sends the AUTH command.
    393     *
    394     * @throws SSLException If the server reply code equals neither "234" nor "334".
    395     * @throws IOException  If an I/O error occurs while either sending the command.
    396     */
    397    protected void execAUTH() throws SSLException, IOException {
    398        final int replyCode = sendCommand(CMD_AUTH, auth);
    399        if (FTPReply.SECURITY_MECHANISM_IS_OK == replyCode) {
    400            // replyCode = 334
    401            // I carry out an ADAT command.
    402        } else if (FTPReply.SECURITY_DATA_EXCHANGE_COMPLETE != replyCode) {
    403            throw new SSLException(getReplyString());
    404        }
    405    }
    406
    407    /**
    408     * Sends the AUTH command with the specified mechanism.
    409     *
    410     * @param mechanism The mechanism name to send with the command.
    411     * @return server reply.
    412     * @throws IOException If an I/O error occurs while sending the command.
    413     * @since 3.0
    414     */
    415    public int execAUTH(final String mechanism) throws IOException {
    416        return sendCommand(CMD_AUTH, mechanism);
    417    }
    418
    419    /**
    420     * Sends the CCC command to the server. The CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be assigned to a plain
    421     * {@link Socket} instances
    422     *
    423     * @return server reply.
    424     * @throws IOException If an I/O error occurs while sending the command.
    425     * @since 3.0
    426     */
    427    public int execCCC() throws IOException {
    428
    429// This will be performed by sendCommand(String, String)
    430//        if (FTPReply.isPositiveCompletion(repCode)) {
    431//            _socket_.close();
    432//            _socket_ = plainSocket;
    433//            _controlInput_ = new BufferedReader(
    434//                new InputStreamReader(
    435//                    _socket_.getInputStream(), getControlEncoding()));
    436//            _controlOutput_ = new BufferedWriter(
    437//                new OutputStreamWriter(
    438//                    _socket_.getOutputStream(), getControlEncoding()));
    439//        }
    440        return sendCommand(CMD_CCC);
    441    }
    442
    443    /**
    444     * Sends the CONF command with the specified data.
    445     *
    446     * @param data The data to send with the command.
    447     * @return server reply.
    448     * @throws IOException If an I/O error occurs while sending the command.
    449     * @since 3.0
    450     */
    451    public int execCONF(final byte[] data) throws IOException {
    452        if (data != null) {
    453            return sendCommand(CMD_CONF, Base64.getEncoder().encodeToString(data));
    454        }
    455        return sendCommand(CMD_CONF, ""); // perhaps "=" or just sendCommand(String)?
    456    }
    457
    458    /**
    459     * Sends the ENC command with the specified data.
    460     *
    461     * @param data The data to send with the command.
    462     * @return server reply.
    463     * @throws IOException If an I/O error occurs while sending the command.
    464     * @since 3.0
    465     */
    466    public int execENC(final byte[] data) throws IOException {
    467        if (data != null) {
    468            return sendCommand(CMD_ENC, Base64.getEncoder().encodeToString(data));
    469        }
    470        return sendCommand(CMD_ENC, ""); // perhaps "=" or just sendCommand(String)?
    471    }
    472
    473    /**
    474     * Sends the MIC command with the specified data.
    475     *
    476     * @param data The data to send with the command.
    477     * @return server reply.
    478     * @throws IOException If an I/O error occurs while sending the command.
    479     * @since 3.0
    480     */
    481    public int execMIC(final byte[] data) throws IOException {
    482        if (data != null) {
    483            return sendCommand(CMD_MIC, Base64.getEncoder().encodeToString(data));
    484        }
    485        return sendCommand(CMD_MIC, ""); // perhaps "=" or just sendCommand(String)?
    486    }
    487
    488    /**
    489     * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer.
    490     *
    491     * @param pbsz Protection Buffer Size.
    492     * @throws SSLException If the server reply code does not equal "200".
    493     * @throws IOException  If an I/O error occurs while sending the command.
    494     * @see #parsePBSZ(long)
    495     */
    496    public void execPBSZ(final long pbsz) throws SSLException, IOException {
    497        if (pbsz < 0 || 4294967295L < pbsz) { // 32-bit unsigned number
    498            throw new IllegalArgumentException();
    499        }
    500        final int status = sendCommand(CMD_PBSZ, String.valueOf(pbsz));
    501        if (FTPReply.COMMAND_OK != status) {
    502            throw new SSLException(getReplyString());
    503        }
    504    }
    505
    506    /**
    507     * PROT command.
    508     * <ul>
    509     * <li>C - Clear</li>
    510     * <li>S - Safe(SSL protocol only)</li>
    511     * <li>E - Confidential(SSL protocol only)</li>
    512     * <li>P - Private</li>
    513     * </ul>
    514     * <strong>N.B.</strong> the method calls {@link #setSocketFactory(javax.net.SocketFactory)} and
    515     * {@link #setServerSocketFactory(javax.net.ServerSocketFactory)}
    516     *
    517     * @param prot Data Channel Protection Level, if {@code null}, use {@link #DEFAULT_PROT}.
    518     * @throws SSLException If the server reply code does not equal {@code 200}.
    519     * @throws IOException  If an I/O error occurs while sending the command.
    520     */
    521    public void execPROT(String prot) throws SSLException, IOException {
    522        if (prot == null) {
    523            prot = DEFAULT_PROT;
    524        }
    525        if (!checkPROTValue(prot)) {
    526            throw new IllegalArgumentException();
    527        }
    528        if (FTPReply.COMMAND_OK != sendCommand(CMD_PROT, prot)) {
    529            throw new SSLException(getReplyString());
    530        }
    531        if (DEFAULT_PROT.equals(prot)) {
    532            setSocketFactory(null);
    533            setServerSocketFactory(null);
    534        } else {
    535            setSocketFactory(new FTPSSocketFactory(context));
    536            setServerSocketFactory(new FTPSServerSocketFactory(context));
    537            initSslContext();
    538        }
    539    }
    540
    541    /**
    542     * Extract the data from a reply with a prefix, e.g. PBSZ=1234 => 1234
    543     *
    544     * @param prefix the prefix to find
    545     * @param reply  where to find the prefix
    546     * @return the remainder of the string after the prefix, or null if the prefix was not present.
    547     */
    548    private String extractPrefixedData(final String prefix, final String reply) {
    549        final int idx = reply.indexOf(prefix);
    550        if (idx == -1) {
    551            return null;
    552        }
    553        // Cannot use trim before substring as leading space would affect the offset.
    554        return reply.substring(idx + prefix.length()).trim();
    555    }
    556
    557    /**
    558     * Gets AUTH command use value.
    559     *
    560     * @return AUTH command use value.
    561     */
    562    public String getAuthValue() {
    563        return auth;
    564    }
    565
    566    /**
    567     * Gets the names of the cipher suites which could be enabled for use on this connection. When the underlying {@link Socket} is not an {@link SSLSocket}
    568     * instance, returns null.
    569     *
    570     * @return An array of cipher suite names, or {@code null}
    571     */
    572    public String[] getEnabledCipherSuites() {
    573        if (_socket_ instanceof SSLSocket) {
    574            return ((SSLSocket) _socket_).getEnabledCipherSuites();
    575        }
    576        return null;
    577    }
    578
    579    /**
    580     * Gets the names of the protocol versions which are currently enabled for use on this connection. When the underlying {@link Socket} is not an
    581     * {@link SSLSocket} instance, returns null.
    582     *
    583     * @return An array of protocols, or {@code null}
    584     */
    585    public String[] getEnabledProtocols() {
    586        if (_socket_ instanceof SSLSocket) {
    587            return ((SSLSocket) _socket_).getEnabledProtocols();
    588        }
    589        return null;
    590    }
    591
    592    /**
    593     * Gets true if new SSL sessions may be established by this socket. When the underlying {@link Socket} instance is not SSL-enabled (i.e. an instance of
    594     * {@link SSLSocket} with {@link SSLSocket}{@link #getEnableSessionCreation()}) enabled, this returns False.
    595     *
    596     * @return true - Indicates that sessions may be created; this is the default. false - indicates that an existing session must be resumed.
    597     */
    598    public boolean getEnableSessionCreation() {
    599        if (_socket_ instanceof SSLSocket) {
    600            return ((SSLSocket) _socket_).getEnableSessionCreation();
    601        }
    602        return false;
    603    }
    604
    605    /**
    606     * Gets the currently configured {@link HostnameVerifier}. The verifier is only used on client mode connections.
    607     *
    608     * @return A HostnameVerifier instance.
    609     * @since 3.4
    610     */
    611    public HostnameVerifier getHostnameVerifier() {
    612        return hostnameVerifier;
    613    }
    614
    615    /**
    616     * Gets the {@link KeyManager} instance.
    617     *
    618     * @return The {@link KeyManager} instance
    619     */
    620    private KeyManager getKeyManager() {
    621        return keyManager;
    622    }
    623
    624    /**
    625     * Gets true if the socket will require client authentication. When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false.
    626     *
    627     * @return true - If the server mode socket should request that the client authenticate itself.
    628     */
    629    public boolean getNeedClientAuth() {
    630        if (_socket_ instanceof SSLSocket) {
    631            return ((SSLSocket) _socket_).getNeedClientAuth();
    632        }
    633        return false;
    634    }
    635
    636    /**
    637     * Gets the secure socket protocol to be used, e.g. SSL/TLS.
    638     *
    639     * @return the protocol
    640     * @since 3.11.0
    641     */
    642    protected String getProtocol() {
    643        return protocol;
    644    }
    645
    646    /**
    647     * Gets the protocol versions. The {@link #getEnabledProtocols()} method gets the value from the socket while
    648     * this method gets its value from this instance's config.
    649     *
    650     * @return a clone of the protocols, may be null
    651     * @since 3.11.0
    652     */
    653    protected String[] getProtocols() {
    654        return protocols == null ? null : protocols.clone();
    655    }
    656
    657    /**
    658     * Gets the cipher suites. The {@link #getEnabledCipherSuites()} method gets the value from the socket while
    659     * this method gets its value from this instance's config.
    660     *
    661     * @return a clone of the suites, may be null
    662     * @since 3.11.0
    663     */
    664    protected String[] getSuites() {
    665        return suites == null ? null : suites.clone();
    666    }
    667
    668    /**
    669     * Gets the currently configured {@link TrustManager}.
    670     *
    671     * @return A TrustManager instance.
    672     */
    673    public TrustManager getTrustManager() {
    674        return trustManager;
    675    }
    676
    677    /**
    678     * Gets whether the socket is set to use client mode in its first handshake. When the underlying {@link Socket} is not an {@link SSLSocket} instance,
    679     * returns false.
    680     *
    681     * @return true - If the socket should start its first handshake in "client" mode.
    682     */
    683    public boolean getUseClientMode() {
    684        if (_socket_ instanceof SSLSocket) {
    685            return ((SSLSocket) _socket_).getUseClientMode();
    686        }
    687        return false;
    688    }
    689
    690    /**
    691     * Gets whether the socket will request client authentication. When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false.
    692     *
    693     * @return true - If the server mode socket should request that the client authenticate itself.
    694     */
    695    public boolean getWantClientAuth() {
    696        if (_socket_ instanceof SSLSocket) {
    697            return ((SSLSocket) _socket_).getWantClientAuth();
    698        }
    699        return false;
    700    }
    701
    702    /**
    703     * Performs a lazy init of the SSL context
    704     *
    705     * @throws IOException
    706     */
    707    private void initSslContext() throws IOException {
    708        if (context == null) {
    709            context = SSLContextUtils.createSSLContext(protocol, getKeyManager(), getTrustManager());
    710        }
    711    }
    712
    713    /**
    714     * Tests the use client mode flag. The {@link #getUseClientMode()} method gets the value from the socket while
    715     * this method gets its value from this instance's config.
    716     *
    717     * @return True If the socket should start its first handshake in "client" mode.
    718     * @since 3.11.0
    719     */
    720    protected boolean isClientMode() {
    721        return isClientMode;
    722    }
    723
    724    /**
    725     * Tests whether a new SSL session may be established by this socket. Default true
    726     *
    727     * @return True if session may be established
    728     * @since 3.11.0
    729     */
    730    protected boolean isCreation() {
    731        return isCreation;
    732    }
    733
    734    /**
    735     * Tests whether or not endpoint identification using the HTTPS algorithm on Java 1.7+ is enabled. The default behavior is for this to be disabled.
    736     *
    737     * This check is only performed on client mode connections.
    738     *
    739     * @return True if enabled, false if not.
    740     * @since 3.4
    741     */
    742    public boolean isEndpointCheckingEnabled() {
    743        return tlsEndpointChecking;
    744    }
    745
    746    /**
    747     * Tests the security mode. (True - Implicit Mode / False - Explicit Mode).
    748     *
    749     * @return True if enabled, false if not.
    750     * @since 3.11.0
    751     */
    752    protected boolean isImplicit() {
    753        return isImplicit;
    754    }
    755
    756    /**
    757     * Tests the need client auth flag. The {@link #getNeedClientAuth()} method gets the value from the socket while
    758     * this method gets its value from this instance's config.
    759     *
    760     * @return True if enabled, false if not.
    761     * @since 3.11.0
    762     */
    763    protected boolean isNeedClientAuth() {
    764        return isNeedClientAuth;
    765    }
    766
    767    /**
    768     * Tests the want client auth flag. The {@link #getWantClientAuth()} method gets the value from the socket while
    769     * this method gets its value from this instance's config.
    770     *
    771     * @return True if enabled, false if not.
    772     * @since 3.11.0
    773     */
    774    protected boolean isWantClientAuth() {
    775        return isWantClientAuth;
    776    }
    777
    778    /**
    779     * Establishes a data connection with the FTP server, returning a Socket for the connection if successful. If a restart offset has been set with
    780     * {@link #setRestartOffset(long)}, a REST command is issued to the server with the offset as an argument before establishing the data connection. Active
    781     * mode connections also cause a local PORT command to be issued.
    782     *
    783     * @param command The text representation of the FTP command to send.
    784     * @param arg     The arguments to the FTP command. If this parameter is set to null, then the command is sent with no argument.
    785     * @return A Socket corresponding to the established data connection. Null is returned if an FTP protocol error is reported at any point during the
    786     *         establishment and initialization of the connection.
    787     * @throws IOException If an I/O error occurs while either sending a command to the server or receiving a reply from the server.
    788     * @since 3.1
    789     */
    790    private Socket openDataSecureConnection(final String command, final String arg) throws IOException {
    791        if (getDataConnectionMode() != ACTIVE_LOCAL_DATA_CONNECTION_MODE && getDataConnectionMode() != PASSIVE_LOCAL_DATA_CONNECTION_MODE) {
    792            return null;
    793        }
    794
    795        final boolean isInet6Address = getRemoteAddress() instanceof Inet6Address;
    796
    797        final Socket socket;
    798        Socket sslSocket = null;
    799        final int soTimeoutMillis = DurationUtils.toMillisInt(getDataTimeout());
    800        if (getDataConnectionMode() == ACTIVE_LOCAL_DATA_CONNECTION_MODE) {
    801            // if no activePortRange was set (correctly) -> getActivePort() = 0
    802            // -> new ServerSocket(0) -> bind to any free local port
    803            try (ServerSocket server = _serverSocketFactory_.createServerSocket(getActivePort(), 1, getHostAddress())) {
    804                // Try EPRT only if remote server is over IPv6, if not use PORT,
    805                // because EPRT has no advantage over PORT on IPv4.
    806                // It could even have the disadvantage,
    807                // that EPRT will make the data connection fail, because
    808                // today's intelligent NAT Firewalls are able to
    809                // substitute IP addresses in the PORT command,
    810                // but might not be able to recognize the EPRT command.
    811                if (isInet6Address) {
    812                    if (!FTPReply.isPositiveCompletion(eprt(getReportHostAddress(), server.getLocalPort()))) {
    813                        return null;
    814                    }
    815                } else if (!FTPReply.isPositiveCompletion(port(getReportHostAddress(), server.getLocalPort()))) {
    816                    return null;
    817                }
    818
    819                if (getRestartOffset() > 0 && !restart(getRestartOffset()) || !FTPReply.isPositivePreliminary(sendCommand(command, arg))) {
    820                    return null;
    821                }
    822
    823                // For now, let's just use the data timeout value for waiting for
    824                // the data connection. It may be desirable to let this be a
    825                // separately configurable value. In any case, we really want
    826                // to allow preventing the accept from blocking indefinitely.
    827                if (soTimeoutMillis >= 0) {
    828                    server.setSoTimeout(soTimeoutMillis);
    829                }
    830                socket = server.accept();
    831
    832                // Ensure the timeout is set before any commands are issued on the new socket
    833                if (soTimeoutMillis >= 0) {
    834                    socket.setSoTimeout(soTimeoutMillis);
    835                }
    836                if (getReceiveDataSocketBufferSize() > 0) {
    837                    socket.setReceiveBufferSize(getReceiveDataSocketBufferSize());
    838                }
    839                if (getSendDataSocketBufferSize() > 0) {
    840                    socket.setSendBufferSize(getSendDataSocketBufferSize());
    841                }
    842            }
    843        } else { // We must be in PASSIVE_LOCAL_DATA_CONNECTION_MODE
    844
    845            // Try EPSV command first on IPv6 - and IPv4 if enabled.
    846            // When using IPv4 with NAT it has the advantage
    847            // to work with more rare configurations.
    848            // E.g. if FTP server has a static PASV address (external network)
    849            // and the client is coming from another internal network.
    850            // In that case the data connection after PASV command would fail,
    851            // while EPSV would make the client succeed by taking just the port.
    852            final boolean attemptEPSV = isUseEPSVwithIPv4() || isInet6Address;
    853            if (attemptEPSV && epsv() == FTPReply.ENTERING_EPSV_MODE) {
    854                _parseExtendedPassiveModeReply(_replyLines.get(0));
    855            } else {
    856                // If EPSV failed on IPV4, revert to PASV
    857                if (isInet6Address || pasv() != FTPReply.ENTERING_PASSIVE_MODE) {
    858                    return null;
    859                }
    860                _parsePassiveModeReply(_replyLines.get(0));
    861            }
    862
    863            if (getProxy() != null) {
    864                socket = new Socket(getProxy());
    865            } else {
    866                socket = _socketFactory_.createSocket();
    867            }
    868
    869            if (getReceiveDataSocketBufferSize() > 0) {
    870                socket.setReceiveBufferSize(getReceiveDataSocketBufferSize());
    871            }
    872            if (getSendDataSocketBufferSize() > 0) {
    873                socket.setSendBufferSize(getSendDataSocketBufferSize());
    874            }
    875            if (getPassiveLocalIPAddress() != null) {
    876                socket.bind(new InetSocketAddress(getPassiveLocalIPAddress(), 0));
    877            }
    878
    879            // For now, let's just use the data timeout value for waiting for
    880            // the data connection. It may be desirable to let this be a
    881            // separately configurable value. In any case, we really want
    882            // to allow preventing the accept from blocking indefinitely.
    883            if (soTimeoutMillis >= 0) {
    884                socket.setSoTimeout(soTimeoutMillis);
    885            }
    886
    887            socket.connect(new InetSocketAddress(getPassiveHost(), getPassivePort()), connectTimeout);
    888
    889            if (getProxy() != null) {
    890                sslSocket = context.getSocketFactory().createSocket(socket, getPassiveHost(), getPassivePort(), true);
    891            }
    892
    893            if (getRestartOffset() > 0 && !restart(getRestartOffset()) || !FTPReply.isPositivePreliminary(sendCommand(command, arg))) {
    894                closeSockets(socket, sslSocket);
    895                return null;
    896            }
    897        }
    898
    899        if (isRemoteVerificationEnabled() && !verifyRemote(socket)) {
    900            // Grab the host before we close the socket to avoid NET-663
    901            final InetAddress socketHost = socket.getInetAddress();
    902
    903            closeSockets(socket, sslSocket);
    904
    905            throw new IOException(
    906                    "Host attempting data connection " + socketHost.getHostAddress() + " is not same as server " + getRemoteAddress().getHostAddress());
    907        }
    908
    909        return getProxy() != null ? sslSocket : socket;
    910    }
    911
    912    /**
    913     * Parses the given ADAT response line and base64-decodes the data.
    914     *
    915     * @param reply The ADAT reply to parse.
    916     * @return the data in the reply, base64-decoded.
    917     * @since 3.0
    918     */
    919    public byte[] parseADATReply(final String reply) {
    920        if (reply == null) {
    921            return null;
    922        }
    923        return Base64.getDecoder().decode(extractPrefixedData("ADAT=", reply));
    924    }
    925
    926    /**
    927     * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. Issues the command and parses the response to return the negotiated value.
    928     *
    929     * @param pbsz Protection Buffer Size.
    930     * @throws SSLException If the server reply code does not equal "200".
    931     * @throws IOException  If an I/O error occurs while sending the command.
    932     * @return the negotiated value.
    933     * @see #execPBSZ(long)
    934     * @since 3.0
    935     */
    936    public long parsePBSZ(final long pbsz) throws SSLException, IOException {
    937        execPBSZ(pbsz);
    938        long minvalue = pbsz;
    939        final String remainder = extractPrefixedData("PBSZ=", getReplyString());
    940        if (remainder != null) {
    941            final long replysz = Long.parseLong(remainder);
    942            if (replysz < minvalue) {
    943                minvalue = replysz;
    944            }
    945        }
    946        return minvalue;
    947    }
    948
    949    // DEPRECATED - for API compatibility only - DO NOT USE
    950
    951    /**
    952     * Send an FTP command. A successful CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be assigned to a plain
    953     * {@link Socket}
    954     *
    955     * @param command The FTP command.
    956     * @return server reply.
    957     * @throws IOException  If an I/O error occurs while sending the command.
    958     * @throws SSLException if a CCC command fails
    959     * @see org.apache.commons.net.ftp.FTP#sendCommand(String)
    960     */
    961    // Would like to remove this method, but that will break any existing clients that are using CCC
    962    @Override
    963    public int sendCommand(final String command, final String args) throws IOException {
    964        final int repCode = super.sendCommand(command, args);
    965        /* If CCC is issued, restore socket i/o streams to unsecured versions */
    966        if (CMD_CCC.equals(command)) {
    967            if (FTPReply.COMMAND_OK != repCode) {
    968                throw new SSLException(getReplyString());
    969            }
    970            _socket_.close();
    971            _socket_ = plainSocket;
    972            _controlInput_ = new BufferedReader(new InputStreamReader(_socket_.getInputStream(), getControlEncoding()));
    973            _controlOutput_ = new BufferedWriter(new OutputStreamWriter(_socket_.getOutputStream(), getControlEncoding()));
    974        }
    975        return repCode;
    976    }
    977
    978    /**
    979     * Sets AUTH command use value. This processing is done before connected processing.
    980     *
    981     * @param auth AUTH command use value.
    982     */
    983    public void setAuthValue(final String auth) {
    984        this.auth = auth;
    985    }
    986
    987    /**
    988     * Sets which particular cipher suites are enabled for use on this connection. Called before server negotiation.
    989     *
    990     * @param cipherSuites The cipher suites.
    991     */
    992    public void setEnabledCipherSuites(final String[] cipherSuites) {
    993        suites = cipherSuites.clone();
    994    }
    995
    996    /**
    997     * Sets which particular protocol versions are enabled for use on this connection. I perform setting before a server negotiation.
    998     *
    999     * @param protocolVersions The protocol versions.
    1000     */
    1001    public void setEnabledProtocols(final String[] protocolVersions) {
    1002        protocols = protocolVersions.clone();
    1003    }
    1004
    1005    /**
    1006     * Sets whether a new SSL session may be established by this socket.
    1007     *
    1008     * @param isCreation The established socket flag.
    1009     */
    1010    public void setEnabledSessionCreation(final boolean isCreation) {
    1011        this.isCreation = isCreation;
    1012    }
    1013
    1014    /**
    1015     * Sets automatic endpoint identification checking using the HTTPS algorithm is supported on Java 1.7+. The default behavior is for this to be disabled.
    1016     *
    1017     * This check is only performed on client mode connections.
    1018     *
    1019     * @param enable Enable automatic endpoint identification checking using the HTTPS algorithm on Java 1.7+.
    1020     * @since 3.4
    1021     */
    1022    public void setEndpointCheckingEnabled(final boolean enable) {
    1023        tlsEndpointChecking = enable;
    1024    }
    1025
    1026    /**
    1027     * Sets to override the default {@link HostnameVerifier} to use. The verifier is only used on client mode connections.
    1028     *
    1029     * @param newHostnameVerifier The HostnameVerifier implementation to set or {@code null} to disable.
    1030     * @since 3.4
    1031     */
    1032    public void setHostnameVerifier(final HostnameVerifier newHostnameVerifier) {
    1033        hostnameVerifier = newHostnameVerifier;
    1034    }
    1035
    1036    /**
    1037     * Sets a {@link KeyManager} to use
    1038     *
    1039     * @param keyManager The KeyManager implementation to set.
    1040     * @see org.apache.commons.net.util.KeyManagerUtils
    1041     */
    1042    public void setKeyManager(final KeyManager keyManager) {
    1043        this.keyManager = keyManager;
    1044    }
    1045
    1046    /**
    1047     * Sets the socket to require client authentication.
    1048     *
    1049     * @param isNeedClientAuth The need client auth flag.
    1050     */
    1051    public void setNeedClientAuth(final boolean isNeedClientAuth) {
    1052        this.isNeedClientAuth = isNeedClientAuth;
    1053    }
    1054
    1055    /**
    1056     * Sets to override the default {@link TrustManager} to use; if set to {@code null}, the default TrustManager from the JVM will be used.
    1057     *
    1058     * @param trustManager The TrustManager implementation to set, may be {@code null}
    1059     * @see org.apache.commons.net.util.TrustManagerUtils
    1060     */
    1061    public void setTrustManager(final TrustManager trustManager) {
    1062        this.trustManager = trustManager;
    1063    }
    1064
    1065    /**
    1066     * Sets the socket to use client (or server) mode in its first handshake.
    1067     *
    1068     * @param isClientMode The use client mode flag.
    1069     */
    1070    public void setUseClientMode(final boolean isClientMode) {
    1071        this.isClientMode = isClientMode;
    1072    }
    1073
    1074    /**
    1075     * Sets the socket to request client authentication, but only if such a request is appropriate to the cipher suite negotiated.
    1076     *
    1077     * @param isWantClientAuth The want client auth flag.
    1078     */
    1079    public void setWantClientAuth(final boolean isWantClientAuth) {
    1080        this.isWantClientAuth = isWantClientAuth;
    1081    }
    1082
    1083    /**
    1084     * SSL/TLS negotiation. Acquires an SSL socket of a control connection and carries out handshake processing.
    1085     *
    1086     * @throws IOException If server negotiation fails
    1087     */
    1088    protected void sslNegotiation() throws IOException {
    1089        plainSocket = _socket_;
    1090        initSslContext();
    1091        final SSLSocket socket = createSSLSocket(_socket_);
    1092        socket.setEnableSessionCreation(isCreation);
    1093        socket.setUseClientMode(isClientMode);
    1094
    1095        // client mode
    1096        if (isClientMode) {
    1097            if (tlsEndpointChecking) {
    1098                SSLSocketUtils.enableEndpointNameVerification(socket);
    1099            }
    1100        } else { // server mode
    1101            socket.setNeedClientAuth(isNeedClientAuth);
    1102            socket.setWantClientAuth(isWantClientAuth);
    1103        }
    1104
    1105        if (protocols != null) {
    1106            socket.setEnabledProtocols(protocols);
    1107        }
    1108        if (suites != null) {
    1109            socket.setEnabledCipherSuites(suites);
    1110        }
    1111        socket.startHandshake();
    1112
    1113        // TODO the following setup appears to duplicate that in the super class methods
    1114        _socket_ = socket;
    1115        _controlInput_ = new BufferedReader(new InputStreamReader(socket.getInputStream(), getControlEncoding()));
    1116        _controlOutput_ = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), getControlEncoding()));
    1117
    1118        if (isClientMode && hostnameVerifier != null && !hostnameVerifier.verify(_hostname_, socket.getSession())) {
    1119            throw new SSLHandshakeException("Hostname doesn't match certificate");
    1120        }
    1121    }
    1122}
    1123