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    *      http://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.net.util.SSLContextUtils;
42  import org.apache.commons.net.util.SSLSocketUtils;
43  import org.apache.commons.net.util.TrustManagerUtils;
44  
45  /**
46   * FTP over SSL processing. If desired, the JVM property -Djavax.net.debug=all can be used to see wire-level SSL details.
47   *
48   * Warning: the hostname is not verified against the certificate by default, use {@link #setHostnameVerifier(HostnameVerifier)} or
49   * {@link #setEndpointCheckingEnabled(boolean)} (on Java 1.7+) to enable verification. Verification is only performed on client mode connections.
50   *
51   * @since 2.0
52   */
53  public class FTPSClient extends FTPClient {
54  
55  // From http://www.iana.org/assignments/port-numbers
56  
57  //    ftps-data   989/tcp    ftp protocol, data, over TLS/SSL
58  //    ftps-data   989/udp    ftp protocol, data, over TLS/SSL
59  //    ftps        990/tcp    ftp protocol, control, over TLS/SSL
60  //    ftps        990/udp    ftp protocol, control, over TLS/SSL
61  
62      /** Default FTPS data port. */
63      public static final int DEFAULT_FTPS_DATA_PORT = 989;
64  
65      /** Default FTPS port. */
66      public static final int DEFAULT_FTPS_PORT = 990;
67  
68      /** The value that I can set in PROT command (C = Clear, P = Protected) */
69      private static final String[] PROT_COMMAND_VALUE = { "C", "E", "S", "P" };
70  
71      /** Default PROT Command */
72      private static final String DEFAULT_PROT = "C";
73  
74      /** Default secure socket protocol name, i.e. TLS */
75      private static final String DEFAULT_PROTOCOL = "TLS";
76  
77      /** The AUTH (Authentication/Security Mechanism) command. */
78      private static final String CMD_AUTH = "AUTH";
79  
80      /** The ADAT (Authentication/Security Data) command. */
81      private static final String CMD_ADAT = "ADAT";
82  
83      /** The PROT (Data Channel Protection Level) command. */
84      private static final String CMD_PROT = "PROT";
85  
86      /** The PBSZ (Protection Buffer Size) command. */
87      private static final String CMD_PBSZ = "PBSZ";
88  
89      /** The MIC (Integrity Protected Command) command. */
90      private static final String CMD_MIC = "MIC";
91  
92      /** The CONF (Confidentiality Protected Command) command. */
93      private static final String CMD_CONF = "CONF";
94  
95      /** The ENC (Privacy Protected Command) command. */
96      private static final String CMD_ENC = "ENC";
97  
98      /** The CCC (Clear Command Channel) command. */
99      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