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     * Sends 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     * Sends the 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     * Sends 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     * 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
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
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 sendCommand(CMD_CCC);
447    }
448
449    /**
450     * Sends 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     * Sends 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     * Sends 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}
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}
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     * Gets 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     * Gets the secure socket protocol to be used, e.g. SSL/TLS.
643     * @since 3.11.0
644     * @return the protocol
645     */
646    protected String getProtocol() {
647        return protocol;
648    }
649
650    /**
651     * Gets the protocol versions. The {@link #getEnabledProtocols()} method gets the value from the socket while
652     * this method gets its value from this instance's config.
653     * @since 3.11.0
654     * @return a clone of the protocols, may be null
655     */
656    protected String[] getProtocols() {
657        return protocols == null ? null : protocols.clone();
658    }
659
660    /**
661     * Gets the cipher suites. The {@link #getEnabledCipherSuites()} method gets the value from the socket while
662     * this method gets its value from this instance's config.
663     * @since 3.11.0
664     * @return a clone of the suites, may be null
665     */
666    protected String[] getSuites() {
667        return suites == null ? null : suites.clone();
668    }
669
670    /**
671     * Gets the currently configured {@link TrustManager}.
672     *
673     * @return A TrustManager instance.
674     */
675    public TrustManager getTrustManager() {
676        return trustManager;
677    }
678
679    /**
680     * 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,
681     * returns false.
682     *
683     * @return true - If the socket should start its first handshake in "client" mode.
684     */
685    public boolean getUseClientMode() {
686        if (_socket_ instanceof SSLSocket) {
687            return ((SSLSocket) _socket_).getUseClientMode();
688        }
689        return false;
690    }
691
692    /**
693     * Returns true if the socket will request client authentication. When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false.
694     *
695     * @return true - If the server mode socket should request that the client authenticate itself.
696     */
697    public boolean getWantClientAuth() {
698        if (_socket_ instanceof SSLSocket) {
699            return ((SSLSocket) _socket_).getWantClientAuth();
700        }
701        return false;
702    }
703
704    /**
705     * Performs a lazy init of the SSL context
706     *
707     * @throws IOException
708     */
709    private void initSslContext() throws IOException {
710        if (context == null) {
711            context = SSLContextUtils.createSSLContext(protocol, getKeyManager(), getTrustManager());
712        }
713    }
714
715    /**
716     * Gets the use client mode flag. The {@link #getUseClientMode()} method gets the value from the socket while
717     * this method gets its value from this instance's config.
718     * @since 3.11.0
719     * @return True If the socket should start its first handshake in "client" mode.
720     */
721    protected boolean isClientMode() {
722        return isClientMode;
723    }
724
725    /**
726     * Gets whether a new SSL session may be established by this socket. Default true
727     * @since 3.11.0
728     * @return True if session may be established
729     */
730    protected boolean isCreation() {
731        return isCreation;
732    }
733
734    /**
735     * 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.
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     * Gets the security mode. (True - Implicit Mode / False - Explicit Mode)
748     * @since 3.11.0
749     * @return True if enabled, false if not.
750     */
751    protected boolean isImplicit() {
752        return isImplicit;
753    }
754
755    /**
756     * Gets the need client auth flag. The {@link #getNeedClientAuth()} method gets the value from the socket while
757     * this method gets its value from this instance's config.
758     * @since 3.11.0
759     * @return True if enabled, false if not.
760     */
761    protected boolean isNeedClientAuth() {
762        return isNeedClientAuth;
763    }
764
765    /**
766     * Gets the want client auth flag. The {@link #getWantClientAuth()} method gets the value from the socket while
767     * this method gets its value from this instance's config.
768     * @since 3.11.0
769     * @return True if enabled, false if not.
770     */
771    protected boolean isWantClientAuth() {
772        return isWantClientAuth;
773    }
774
775    /**
776     * Establishes a data connection with the FTP server, returning a Socket for the connection if successful. If a restart offset has been set with
777     * {@link #setRestartOffset(long)}, a REST command is issued to the server with the offset as an argument before establishing the data connection. Active
778     * mode connections also cause a local PORT command to be issued.
779     *
780     * @param command The text representation of the FTP command to send.
781     * @param arg     The arguments to the FTP command. If this parameter is set to null, then the command is sent with no argument.
782     * @return A Socket corresponding to the established data connection. Null is returned if an FTP protocol error is reported at any point during the
783     *         establishment and initialization of the connection.
784     * @throws IOException If an I/O error occurs while either sending a command to the server or receiving a reply from the server.
785     * @since 3.1
786     */
787    private Socket openDataSecureConnection(final String command, final String arg) throws IOException {
788        if (getDataConnectionMode() != ACTIVE_LOCAL_DATA_CONNECTION_MODE && getDataConnectionMode() != PASSIVE_LOCAL_DATA_CONNECTION_MODE) {
789            return null;
790        }
791
792        final boolean isInet6Address = getRemoteAddress() instanceof Inet6Address;
793
794        final Socket socket;
795        Socket sslSocket = null;
796        final int soTimeoutMillis = DurationUtils.toMillisInt(getDataTimeout());
797        if (getDataConnectionMode() == ACTIVE_LOCAL_DATA_CONNECTION_MODE) {
798            // if no activePortRange was set (correctly) -> getActivePort() = 0
799            // -> new ServerSocket(0) -> bind to any free local port
800            try (final ServerSocket server = _serverSocketFactory_.createServerSocket(getActivePort(), 1, getHostAddress())) {
801                // Try EPRT only if remote server is over IPv6, if not use PORT,
802                // because EPRT has no advantage over PORT on IPv4.
803                // It could even have the disadvantage,
804                // that EPRT will make the data connection fail, because
805                // today's intelligent NAT Firewalls are able to
806                // substitute IP addresses in the PORT command,
807                // but might not be able to recognize the EPRT command.
808                if (isInet6Address) {
809                    if (!FTPReply.isPositiveCompletion(eprt(getReportHostAddress(), server.getLocalPort()))) {
810                        return null;
811                    }
812                } else if (!FTPReply.isPositiveCompletion(port(getReportHostAddress(), server.getLocalPort()))) {
813                    return null;
814                }
815
816                if (getRestartOffset() > 0 && !restart(getRestartOffset())) {
817                    return null;
818                }
819
820                if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) {
821                    return null;
822                }
823
824                // For now, let's just use the data timeout value for waiting for
825                // the data connection. It may be desirable to let this be a
826                // separately configurable value. In any case, we really want
827                // to allow preventing the accept from blocking indefinitely.
828                if (soTimeoutMillis >= 0) {
829                    server.setSoTimeout(soTimeoutMillis);
830                }
831                socket = server.accept();
832
833                // Ensure the timeout is set before any commands are issued on the new socket
834                if (soTimeoutMillis >= 0) {
835                    socket.setSoTimeout(soTimeoutMillis);
836                }
837                if (getReceiveDataSocketBufferSize() > 0) {
838                    socket.setReceiveBufferSize(getReceiveDataSocketBufferSize());
839                }
840                if (getSendDataSocketBufferSize() > 0) {
841                    socket.setSendBufferSize(getSendDataSocketBufferSize());
842                }
843            }
844        } else { // We must be in PASSIVE_LOCAL_DATA_CONNECTION_MODE
845
846            // Try EPSV command first on IPv6 - and IPv4 if enabled.
847            // When using IPv4 with NAT it has the advantage
848            // to work with more rare configurations.
849            // E.g. if FTP server has a static PASV address (external network)
850            // and the client is coming from another internal network.
851            // In that case the data connection after PASV command would fail,
852            // while EPSV would make the client succeed by taking just the port.
853            final boolean attemptEPSV = isUseEPSVwithIPv4() || isInet6Address;
854            if (attemptEPSV && epsv() == FTPReply.ENTERING_EPSV_MODE) {
855                _parseExtendedPassiveModeReply(_replyLines.get(0));
856            } else {
857                if (isInet6Address) {
858                    return null; // Must use EPSV for IPV6
859                }
860                // If EPSV failed on IPV4, revert to PASV
861                if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) {
862                    return null;
863                }
864                _parsePassiveModeReply(_replyLines.get(0));
865            }
866
867            if (getProxy() != null) {
868                socket = new Socket(getProxy());
869            } else {
870                socket = _socketFactory_.createSocket();
871            }
872
873            if (getReceiveDataSocketBufferSize() > 0) {
874                socket.setReceiveBufferSize(getReceiveDataSocketBufferSize());
875            }
876            if (getSendDataSocketBufferSize() > 0) {
877                socket.setSendBufferSize(getSendDataSocketBufferSize());
878            }
879            if (getPassiveLocalIPAddress() != null) {
880                socket.bind(new InetSocketAddress(getPassiveLocalIPAddress(), 0));
881            }
882
883            // For now, let's just use the data timeout value for waiting for
884            // the data connection. It may be desirable to let this be a
885            // separately configurable value. In any case, we really want
886            // to allow preventing the accept from blocking indefinitely.
887            if (soTimeoutMillis >= 0) {
888                socket.setSoTimeout(soTimeoutMillis);
889            }
890
891            socket.connect(new InetSocketAddress(getPassiveHost(), getPassivePort()), connectTimeout);
892
893            if (getProxy() != null) {
894                sslSocket = context.getSocketFactory().createSocket(socket, getPassiveHost(), getPassivePort(), true);
895            }
896
897            if (getRestartOffset() > 0 && !restart(getRestartOffset())) {
898                closeSockets(socket, sslSocket);
899                return null;
900            }
901
902            if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) {
903                closeSockets(socket, sslSocket);
904                return null;
905            }
906        }
907
908        if (isRemoteVerificationEnabled() && !verifyRemote(socket)) {
909            // Grab the host before we close the socket to avoid NET-663
910            final InetAddress socketHost = socket.getInetAddress();
911
912            closeSockets(socket, sslSocket);
913
914            throw new IOException(
915                    "Host attempting data connection " + socketHost.getHostAddress() + " is not same as server " + getRemoteAddress().getHostAddress());
916        }
917
918        return getProxy() != null ? sslSocket : socket;
919    }
920
921    /**
922     * Parses the given ADAT response line and base64-decodes the data.
923     *
924     * @param reply The ADAT reply to parse.
925     * @return the data in the reply, base64-decoded.
926     * @since 3.0
927     */
928    public byte[] parseADATReply(final String reply) {
929        if (reply == null) {
930            return null;
931        }
932        return Base64.getDecoder().decode(extractPrefixedData("ADAT=", reply));
933    }
934
935    /**
936     * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. Issues the command and parses the response to return the negotiated value.
937     *
938     * @param pbsz Protection Buffer Size.
939     * @throws SSLException If the server reply code does not equal "200".
940     * @throws IOException  If an I/O error occurs while sending the command.
941     * @return the negotiated value.
942     * @see #execPBSZ(long)
943     * @since 3.0
944     */
945    public long parsePBSZ(final long pbsz) throws SSLException, IOException {
946        execPBSZ(pbsz);
947        long minvalue = pbsz;
948        final String remainder = extractPrefixedData("PBSZ=", getReplyString());
949        if (remainder != null) {
950            final long replysz = Long.parseLong(remainder);
951            if (replysz < minvalue) {
952                minvalue = replysz;
953            }
954        }
955        return minvalue;
956    }
957
958    // DEPRECATED - for API compatibility only - DO NOT USE
959
960    /**
961     * Send an FTP command. A successful CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be assigned to a plain
962     * {@link Socket}
963     *
964     * @param command The FTP command.
965     * @return server reply.
966     * @throws IOException  If an I/O error occurs while sending the command.
967     * @throws SSLException if a CCC command fails
968     * @see org.apache.commons.net.ftp.FTP#sendCommand(String)
969     */
970    // Would like to remove this method, but that will break any existing clients that are using CCC
971    @Override
972    public int sendCommand(final String command, final String args) throws IOException {
973        final int repCode = super.sendCommand(command, args);
974        /* If CCC is issued, restore socket i/o streams to unsecured versions */
975        if (CMD_CCC.equals(command)) {
976            if (FTPReply.COMMAND_OK != repCode) {
977                throw new SSLException(getReplyString());
978            }
979            _socket_.close();
980            _socket_ = plainSocket;
981            _controlInput_ = new BufferedReader(new InputStreamReader(_socket_.getInputStream(), getControlEncoding()));
982            _controlOutput_ = new BufferedWriter(new OutputStreamWriter(_socket_.getOutputStream(), getControlEncoding()));
983        }
984        return repCode;
985    }
986
987    /**
988     * Sets AUTH command use value. This processing is done before connected processing.
989     *
990     * @param auth AUTH command use value.
991     */
992    public void setAuthValue(final String auth) {
993        this.auth = auth;
994    }
995
996    /**
997     * Controls which particular cipher suites are enabled for use on this connection. Called before server negotiation.
998     *
999     * @param cipherSuites The cipher suites.
1000     */
1001    public void setEnabledCipherSuites(final String[] cipherSuites) {
1002        suites = cipherSuites.clone();
1003    }
1004
1005    /**
1006     * Controls which particular protocol versions are enabled for use on this connection. I perform setting before a server negotiation.
1007     *
1008     * @param protocolVersions The protocol versions.
1009     */
1010    public void setEnabledProtocols(final String[] protocolVersions) {
1011        protocols = protocolVersions.clone();
1012    }
1013
1014    /**
1015     * Controls whether a new SSL session may be established by this socket.
1016     *
1017     * @param isCreation The established socket flag.
1018     */
1019    public void setEnabledSessionCreation(final boolean isCreation) {
1020        this.isCreation = isCreation;
1021    }
1022
1023    /**
1024     * Automatic endpoint identification checking using the HTTPS algorithm is supported on Java 1.7+. The default behavior is for this to be disabled.
1025     *
1026     * This check is only performed on client mode connections.
1027     *
1028     * @param enable Enable automatic endpoint identification checking using the HTTPS algorithm on Java 1.7+.
1029     * @since 3.4
1030     */
1031    public void setEndpointCheckingEnabled(final boolean enable) {
1032        tlsEndpointChecking = enable;
1033    }
1034
1035    /**
1036     * Override the default {@link HostnameVerifier} to use. The verifier is only used on client mode connections.
1037     *
1038     * @param newHostnameVerifier The HostnameVerifier implementation to set or {@code null} to disable.
1039     * @since 3.4
1040     */
1041    public void setHostnameVerifier(final HostnameVerifier newHostnameVerifier) {
1042        hostnameVerifier = newHostnameVerifier;
1043    }
1044
1045    /**
1046     * Sets a {@link KeyManager} to use
1047     *
1048     * @param keyManager The KeyManager implementation to set.
1049     * @see org.apache.commons.net.util.KeyManagerUtils
1050     */
1051    public void setKeyManager(final KeyManager keyManager) {
1052        this.keyManager = keyManager;
1053    }
1054
1055    /**
1056     * Configures the socket to require client authentication.
1057     *
1058     * @param isNeedClientAuth The need client auth flag.
1059     */
1060    public void setNeedClientAuth(final boolean isNeedClientAuth) {
1061        this.isNeedClientAuth = isNeedClientAuth;
1062    }
1063
1064    /**
1065     * Override the default {@link TrustManager} to use; if set to {@code null}, the default TrustManager from the JVM will be used.
1066     *
1067     * @param trustManager The TrustManager implementation to set, may be {@code null}
1068     * @see org.apache.commons.net.util.TrustManagerUtils
1069     */
1070    public void setTrustManager(final TrustManager trustManager) {
1071        this.trustManager = trustManager;
1072    }
1073
1074    /**
1075     * Configures the socket to use client (or server) mode in its first handshake.
1076     *
1077     * @param isClientMode The use client mode flag.
1078     */
1079    public void setUseClientMode(final boolean isClientMode) {
1080        this.isClientMode = isClientMode;
1081    }
1082
1083    /**
1084     * Configures the socket to request client authentication, but only if such a request is appropriate to the cipher suite negotiated.
1085     *
1086     * @param isWantClientAuth The want client auth flag.
1087     */
1088    public void setWantClientAuth(final boolean isWantClientAuth) {
1089        this.isWantClientAuth = isWantClientAuth;
1090    }
1091
1092    /**
1093     * SSL/TLS negotiation. Acquires an SSL socket of a control connection and carries out handshake processing.
1094     *
1095     * @throws IOException If server negotiation fails
1096     */
1097    protected void sslNegotiation() throws IOException {
1098        plainSocket = _socket_;
1099        initSslContext();
1100        final SSLSocket socket = createSSLSocket(_socket_);
1101        socket.setEnableSessionCreation(isCreation);
1102        socket.setUseClientMode(isClientMode);
1103
1104        // client mode
1105        if (isClientMode) {
1106            if (tlsEndpointChecking) {
1107                SSLSocketUtils.enableEndpointNameVerification(socket);
1108            }
1109        } else { // server mode
1110            socket.setNeedClientAuth(isNeedClientAuth);
1111            socket.setWantClientAuth(isWantClientAuth);
1112        }
1113
1114        if (protocols != null) {
1115            socket.setEnabledProtocols(protocols);
1116        }
1117        if (suites != null) {
1118            socket.setEnabledCipherSuites(suites);
1119        }
1120        socket.startHandshake();
1121
1122        // TODO the following setup appears to duplicate that in the super class methods
1123        _socket_ = socket;
1124        _controlInput_ = new BufferedReader(new InputStreamReader(socket.getInputStream(), getControlEncoding()));
1125        _controlOutput_ = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), getControlEncoding()));
1126
1127        if (isClientMode && hostnameVerifier != null && !hostnameVerifier.verify(_hostname_, socket.getSession())) {
1128            throw new SSLHandshakeException("Hostname doesn't match certificate");
1129        }
1130    }
1131}
1132