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