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