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      * Send the ADAT command with the specified authentication data.
384      *
385      * @param data The data to send with the command.
386      * @return server reply.
387      * @throws IOException If an I/O error occurs while sending the command.
388      * @since 3.0
389      */
390     public int execADAT(final byte[] data) throws IOException {
391         if (data != null) {
392             return sendCommand(CMD_ADAT, Base64.getEncoder().encodeToString(data));
393         }
394         return sendCommand(CMD_ADAT);
395     }
396 
397     /**
398      * AUTH command.
399      *
400      * @throws SSLException If the server reply code equals neither "234" nor "334".
401      * @throws IOException  If an I/O error occurs while either sending the command.
402      */
403     protected void execAUTH() throws SSLException, IOException {
404         final int replyCode = sendCommand(CMD_AUTH, auth);
405         if (FTPReply.SECURITY_MECHANISM_IS_OK == replyCode) {
406             // replyCode = 334
407             // I carry out an ADAT command.
408         } else if (FTPReply.SECURITY_DATA_EXCHANGE_COMPLETE != replyCode) {
409             throw new SSLException(getReplyString());
410         }
411     }
412 
413     /**
414      * Send the AUTH command with the specified mechanism.
415      *
416      * @param mechanism The mechanism name to send with the command.
417      * @return server reply.
418      * @throws IOException If an I/O error occurs while sending the command.
419      * @since 3.0
420      */
421     public int execAUTH(final String mechanism) throws IOException {
422         return sendCommand(CMD_AUTH, mechanism);
423     }
424 
425     /**
426      * Send the CCC command to the server. The CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be assigned to a plain
427      * {@link Socket} instances
428      *
429      * @return server reply.
430      * @throws IOException If an I/O error occurs while sending the command.
431      * @since 3.0
432      */
433     public int execCCC() throws IOException {
434         final int repCode = sendCommand(CMD_CCC);
435 // This will be performed by sendCommand(String, String)
436 //        if (FTPReply.isPositiveCompletion(repCode)) {
437 //            _socket_.close();
438 //            _socket_ = plainSocket;
439 //            _controlInput_ = new BufferedReader(
440 //                new InputStreamReader(
441 //                    _socket_.getInputStream(), getControlEncoding()));
442 //            _controlOutput_ = new BufferedWriter(
443 //                new OutputStreamWriter(
444 //                    _socket_.getOutputStream(), getControlEncoding()));
445 //        }
446         return repCode;
447     }
448 
449     /**
450      * Send the CONF command with the specified data.
451      *
452      * @param data The data to send with the command.
453      * @return server reply.
454      * @throws IOException If an I/O error occurs while sending the command.
455      * @since 3.0
456      */
457     public int execCONF(final byte[] data) throws IOException {
458         if (data != null) {
459             return sendCommand(CMD_CONF, Base64.getEncoder().encodeToString(data));
460         }
461         return sendCommand(CMD_CONF, ""); // perhaps "=" or just sendCommand(String)?
462     }
463 
464     /**
465      * Send the ENC command with the specified data.
466      *
467      * @param data The data to send with the command.
468      * @return server reply.
469      * @throws IOException If an I/O error occurs while sending the command.
470      * @since 3.0
471      */
472     public int execENC(final byte[] data) throws IOException {
473         if (data != null) {
474             return sendCommand(CMD_ENC, Base64.getEncoder().encodeToString(data));
475         }
476         return sendCommand(CMD_ENC, ""); // perhaps "=" or just sendCommand(String)?
477     }
478 
479     /**
480      * Send the MIC command with the specified data.
481      *
482      * @param data The data to send with the command.
483      * @return server reply.
484      * @throws IOException If an I/O error occurs while sending the command.
485      * @since 3.0
486      */
487     public int execMIC(final byte[] data) throws IOException {
488         if (data != null) {
489             return sendCommand(CMD_MIC, Base64.getEncoder().encodeToString(data));
490         }
491         return sendCommand(CMD_MIC, ""); // perhaps "=" or just sendCommand(String)?
492     }
493 
494     /**
495      * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer.
496      *
497      * @param pbsz Protection Buffer Size.
498      * @throws SSLException If the server reply code does not equal "200".
499      * @throws IOException  If an I/O error occurs while sending the command.
500      * @see #parsePBSZ(long)
501      */
502     public void execPBSZ(final long pbsz) throws SSLException, IOException {
503         if (pbsz < 0 || 4294967295L < pbsz) { // 32-bit unsigned number
504             throw new IllegalArgumentException();
505         }
506         final int status = sendCommand(CMD_PBSZ, String.valueOf(pbsz));
507         if (FTPReply.COMMAND_OK != status) {
508             throw new SSLException(getReplyString());
509         }
510     }
511 
512     /**
513      * PROT command.
514      * <ul>
515      * <li>C - Clear</li>
516      * <li>S - Safe(SSL protocol only)</li>
517      * <li>E - Confidential(SSL protocol only)</li>
518      * <li>P - Private</li>
519      * </ul>
520      * <b>N.B.</b> the method calls {@link #setSocketFactory(javax.net.SocketFactory)} and {@link #setServerSocketFactory(javax.net.ServerSocketFactory)}
521      *
522      * @param prot Data Channel Protection Level, if {@code null}, use {@link #DEFAULT_PROT}.
523      * @throws SSLException If the server reply code does not equal {@code 200}.
524      * @throws IOException  If an I/O error occurs while sending the command.
525      */
526     public void execPROT(String prot) throws SSLException, IOException {
527         if (prot == null) {
528             prot = DEFAULT_PROT;
529         }
530         if (!checkPROTValue(prot)) {
531             throw new IllegalArgumentException();
532         }
533         if (FTPReply.COMMAND_OK != sendCommand(CMD_PROT, prot)) {
534             throw new SSLException(getReplyString());
535         }
536         if (DEFAULT_PROT.equals(prot)) {
537             setSocketFactory(null);
538             setServerSocketFactory(null);
539         } else {
540             setSocketFactory(new FTPSSocketFactory(context));
541             setServerSocketFactory(new FTPSServerSocketFactory(context));
542             initSslContext();
543         }
544     }
545 
546     /**
547      * Extract the data from a reply with a prefix, e.g. PBSZ=1234 => 1234
548      *
549      * @param prefix the prefix to find
550      * @param reply  where to find the prefix
551      * @return the remainder of the string after the prefix, or null if the prefix was not present.
552      */
553     private String extractPrefixedData(final String prefix, final String reply) {
554         final int idx = reply.indexOf(prefix);
555         if (idx == -1) {
556             return null;
557         }
558         // N.B. Cannot use trim before substring as leading space would affect the offset.
559         return reply.substring(idx + prefix.length()).trim();
560     }
561 
562     /**
563      * Return AUTH command use value.
564      *
565      * @return AUTH command use value.
566      */
567     public String getAuthValue() {
568         return this.auth;
569     }
570 
571     /**
572      * Returns the names of the cipher suites which could be enabled for use on this connection. When the underlying {@link Socket} is not an {@link SSLSocket}
573      * instance, returns null.
574      *
575      * @return An array of cipher suite names, or <code>null</code>
576      */
577     public String[] getEnabledCipherSuites() {
578         if (_socket_ instanceof SSLSocket) {
579             return ((SSLSocket) _socket_).getEnabledCipherSuites();
580         }
581         return null;
582     }
583 
584     /**
585      * Returns the names of the protocol versions which are currently enabled for use on this connection. When the underlying {@link Socket} is not an
586      * {@link SSLSocket} instance, returns null.
587      *
588      * @return An array of protocols, or <code>null</code>
589      */
590     public String[] getEnabledProtocols() {
591         if (_socket_ instanceof SSLSocket) {
592             return ((SSLSocket) _socket_).getEnabledProtocols();
593         }
594         return null;
595     }
596 
597     /**
598      * Returns true if new SSL sessions may be established by this socket. When the underlying {@link Socket} instance is not SSL-enabled (i.e. an instance of
599      * {@link SSLSocket} with {@link SSLSocket}{@link #getEnableSessionCreation()}) enabled, this returns False.
600      *
601      * @return true - Indicates that sessions may be created; this is the default. false - indicates that an existing session must be resumed.
602      */
603     public boolean getEnableSessionCreation() {
604         if (_socket_ instanceof SSLSocket) {
605             return ((SSLSocket) _socket_).getEnableSessionCreation();
606         }
607         return false;
608     }
609 
610     /**
611      * Get the currently configured {@link HostnameVerifier}. The verifier is only used on client mode connections.
612      *
613      * @return A HostnameVerifier instance.
614      * @since 3.4
615      */
616     public HostnameVerifier getHostnameVerifier() {
617         return hostnameVerifier;
618     }
619 
620     /**
621      * Gets the {@link KeyManager} instance.
622      *
623      * @return The {@link KeyManager} instance
624      */
625     private KeyManager getKeyManager() {
626         return keyManager;
627     }
628 
629     /**
630      * Returns true if the socket will require client authentication. When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false.
631      *
632      * @return true - If the server mode socket should request that the client authenticate itself.
633      */
634     public boolean getNeedClientAuth() {
635         if (_socket_ instanceof SSLSocket) {
636             return ((SSLSocket) _socket_).getNeedClientAuth();
637         }
638         return false;
639     }
640 
641     /**
642      * Get the currently configured {@link TrustManager}.
643      *
644      * @return A TrustManager instance.
645      */
646     public TrustManager getTrustManager() {
647         return trustManager;
648     }
649 
650     /**
651      * Returns true if the socket is set to use client mode in its first handshake. When the underlying {@link Socket} is not an {@link SSLSocket} instance,
652      * returns false.
653      *
654      * @return true - If the socket should start its first handshake in "client" mode.
655      */
656     public boolean getUseClientMode() {
657         if (_socket_ instanceof SSLSocket) {
658             return ((SSLSocket) _socket_).getUseClientMode();
659         }
660         return false;
661     }
662 
663     /**
664      * Returns true if the socket will request client authentication. When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false.
665      *
666      * @return true - If the server mode socket should request that the client authenticate itself.
667      */
668     public boolean getWantClientAuth() {
669         if (_socket_ instanceof SSLSocket) {
670             return ((SSLSocket) _socket_).getWantClientAuth();
671         }
672         return false;
673     }
674 
675     /**
676      * Performs a lazy init of the SSL context
677      *
678      * @throws IOException
679      */
680     private void initSslContext() throws IOException {
681         if (context == null) {
682             context = SSLContextUtils.createSSLContext(protocol, getKeyManager(), getTrustManager());
683         }
684     }
685 
686     /**
687      * Return whether or not endpoint identification using the HTTPS algorithm on Java 1.7+ is enabled. The default behavior is for this to be disabled.
688      *
689      * This check is only performed on client mode connections.
690      *
691      * @return True if enabled, false if not.
692      * @since 3.4
693      */
694     public boolean isEndpointCheckingEnabled() {
695         return tlsEndpointChecking;
696     }
697 
698     /**
699      * Establishes a data connection with the FTP server, returning a Socket for the connection if successful. If a restart offset has been set with
700      * {@link #setRestartOffset(long)}, a REST command is issued to the server with the offset as an argument before establishing the data connection. Active
701      * mode connections also cause a local PORT command to be issued.
702      *
703      * @param command The text representation of the FTP command to send.
704      * @param arg     The arguments to the FTP command. If this parameter is set to null, then the command is sent with no argument.
705      * @return A Socket corresponding to the established data connection. Null is returned if an FTP protocol error is reported at any point during the
706      *         establishment and initialization of the connection.
707      * @throws IOException If an I/O error occurs while either sending a command to the server or receiving a reply from the server.
708      * @since 3.1
709      */
710     private Socket openDataSecureConnection(final String command, final String arg) throws IOException {
711         if (getDataConnectionMode() != ACTIVE_LOCAL_DATA_CONNECTION_MODE && getDataConnectionMode() != PASSIVE_LOCAL_DATA_CONNECTION_MODE) {
712             return null;
713         }
714 
715         final boolean isInet6Address = getRemoteAddress() instanceof Inet6Address;
716 
717         final Socket socket;
718         Socket sslSocket = null;
719         final int soTimeoutMillis = DurationUtils.toMillisInt(getDataTimeout());
720         if (getDataConnectionMode() == ACTIVE_LOCAL_DATA_CONNECTION_MODE) {
721             // if no activePortRange was set (correctly) -> getActivePort() = 0
722             // -> new ServerSocket(0) -> bind to any free local port
723             try (final ServerSocket server = _serverSocketFactory_.createServerSocket(getActivePort(), 1, getHostAddress())) {
724                 // Try EPRT only if remote server is over IPv6, if not use PORT,
725                 // because EPRT has no advantage over PORT on IPv4.
726                 // It could even have the disadvantage,
727                 // that EPRT will make the data connection fail, because
728                 // today's intelligent NAT Firewalls are able to
729                 // substitute IP addresses in the PORT command,
730                 // but might not be able to recognize the EPRT command.
731                 if (isInet6Address) {
732                     if (!FTPReply.isPositiveCompletion(eprt(getReportHostAddress(), server.getLocalPort()))) {
733                         return null;
734                     }
735                 } else if (!FTPReply.isPositiveCompletion(port(getReportHostAddress(), server.getLocalPort()))) {
736                     return null;
737                 }
738 
739                 if (getRestartOffset() > 0 && !restart(getRestartOffset())) {
740                     return null;
741                 }
742 
743                 if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) {
744                     return null;
745                 }
746 
747                 // For now, let's just use the data timeout value for waiting for
748                 // the data connection. It may be desirable to let this be a
749                 // separately configurable value. In any case, we really want
750                 // to allow preventing the accept from blocking indefinitely.
751                 if (soTimeoutMillis >= 0) {
752                     server.setSoTimeout(soTimeoutMillis);
753                 }
754                 socket = server.accept();
755 
756                 // Ensure the timeout is set before any commands are issued on the new socket
757                 if (soTimeoutMillis >= 0) {
758                     socket.setSoTimeout(soTimeoutMillis);
759                 }
760                 if (getReceiveDataSocketBufferSize() > 0) {
761                     socket.setReceiveBufferSize(getReceiveDataSocketBufferSize());
762                 }
763                 if (getSendDataSocketBufferSize() > 0) {
764                     socket.setSendBufferSize(getSendDataSocketBufferSize());
765                 }
766             }
767         } else { // We must be in PASSIVE_LOCAL_DATA_CONNECTION_MODE
768 
769             // Try EPSV command first on IPv6 - and IPv4 if enabled.
770             // When using IPv4 with NAT it has the advantage
771             // to work with more rare configurations.
772             // E.g. if FTP server has a static PASV address (external network)
773             // and the client is coming from another internal network.
774             // In that case the data connection after PASV command would fail,
775             // while EPSV would make the client succeed by taking just the port.
776             final boolean attemptEPSV = isUseEPSVwithIPv4() || isInet6Address;
777             if (attemptEPSV && epsv() == FTPReply.ENTERING_EPSV_MODE) {
778                 _parseExtendedPassiveModeReply(_replyLines.get(0));
779             } else {
780                 if (isInet6Address) {
781                     return null; // Must use EPSV for IPV6
782                 }
783                 // If EPSV failed on IPV4, revert to PASV
784                 if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) {
785                     return null;
786                 }
787                 _parsePassiveModeReply(_replyLines.get(0));
788             }
789 
790             if (getProxy() != null) {
791                 socket = new Socket(getProxy());
792             } else {
793                 socket = _socketFactory_.createSocket();
794             }
795 
796             if (getReceiveDataSocketBufferSize() > 0) {
797                 socket.setReceiveBufferSize(getReceiveDataSocketBufferSize());
798             }
799             if (getSendDataSocketBufferSize() > 0) {
800                 socket.setSendBufferSize(getSendDataSocketBufferSize());
801             }
802             if (getPassiveLocalIPAddress() != null) {
803                 socket.bind(new InetSocketAddress(getPassiveLocalIPAddress(), 0));
804             }
805 
806             // For now, let's just use the data timeout value for waiting for
807             // the data connection. It may be desirable to let this be a
808             // separately configurable value. In any case, we really want
809             // to allow preventing the accept from blocking indefinitely.
810             if (soTimeoutMillis >= 0) {
811                 socket.setSoTimeout(soTimeoutMillis);
812             }
813 
814             socket.connect(new InetSocketAddress(getPassiveHost(), getPassivePort()), connectTimeout);
815 
816             if (getProxy() != null) {
817                 sslSocket = context.getSocketFactory().createSocket(socket, getPassiveHost(), getPassivePort(), true);
818             }
819 
820             if (getRestartOffset() > 0 && !restart(getRestartOffset())) {
821                 closeSockets(socket, sslSocket);
822                 return null;
823             }
824 
825             if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) {
826                 closeSockets(socket, sslSocket);
827                 return null;
828             }
829         }
830 
831         if (isRemoteVerificationEnabled() && !verifyRemote(socket)) {
832             // Grab the host before we close the socket to avoid NET-663
833             final InetAddress socketHost = socket.getInetAddress();
834 
835             closeSockets(socket, sslSocket);
836 
837             throw new IOException(
838                     "Host attempting data connection " + socketHost.getHostAddress() + " is not same as server " + getRemoteAddress().getHostAddress());
839         }
840 
841         return getProxy() != null ? sslSocket : socket;
842     }
843 
844     /**
845      * Parses the given ADAT response line and base64-decodes the data.
846      *
847      * @param reply The ADAT reply to parse.
848      * @return the data in the reply, base64-decoded.
849      * @since 3.0
850      */
851     public byte[] parseADATReply(final String reply) {
852         if (reply == null) {
853             return null;
854         }
855         return Base64.getDecoder().decode(extractPrefixedData("ADAT=", reply));
856     }
857 
858     /**
859      * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. Issues the command and parses the response to return the negotiated value.
860      *
861      * @param pbsz Protection Buffer Size.
862      * @throws SSLException If the server reply code does not equal "200".
863      * @throws IOException  If an I/O error occurs while sending the command.
864      * @return the negotiated value.
865      * @see #execPBSZ(long)
866      * @since 3.0
867      */
868     public long parsePBSZ(final long pbsz) throws SSLException, IOException {
869         execPBSZ(pbsz);
870         long minvalue = pbsz;
871         final String remainder = extractPrefixedData("PBSZ=", getReplyString());
872         if (remainder != null) {
873             final long replysz = Long.parseLong(remainder);
874             if (replysz < minvalue) {
875                 minvalue = replysz;
876             }
877         }
878         return minvalue;
879     }
880 
881     /**
882      * Send an FTP command. A successful CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be assigned to a plain
883      * {@link Socket}
884      *
885      * @param command The FTP command.
886      * @return server reply.
887      * @throws IOException  If an I/O error occurs while sending the command.
888      * @throws SSLException if a CCC command fails
889      * @see org.apache.commons.net.ftp.FTP#sendCommand(String)
890      */
891     // Would like to remove this method, but that will break any existing clients that are using CCC
892     @Override
893     public int sendCommand(final String command, final String args) throws IOException {
894         final int repCode = super.sendCommand(command, args);
895         /* If CCC is issued, restore socket i/o streams to unsecured versions */
896         if (CMD_CCC.equals(command)) {
897             if (FTPReply.COMMAND_OK != repCode) {
898                 throw new SSLException(getReplyString());
899             }
900             _socket_.close();
901             _socket_ = plainSocket;
902             _controlInput_ = new BufferedReader(new InputStreamReader(_socket_.getInputStream(), getControlEncoding()));
903             _controlOutput_ = new BufferedWriter(new OutputStreamWriter(_socket_.getOutputStream(), getControlEncoding()));
904         }
905         return repCode;
906     }
907 
908     /**
909      * Set AUTH command use value. This processing is done before connected processing.
910      *
911      * @param auth AUTH command use value.
912      */
913     public void setAuthValue(final String auth) {
914         this.auth = auth;
915     }
916 
917     /**
918      * Controls which particular cipher suites are enabled for use on this connection. Called before server negotiation.
919      *
920      * @param cipherSuites The cipher suites.
921      */
922     public void setEnabledCipherSuites(final String[] cipherSuites) {
923         suites = cipherSuites.clone();
924     }
925 
926     /**
927      * Controls which particular protocol versions are enabled for use on this connection. I perform setting before a server negotiation.
928      *
929      * @param protocolVersions The protocol versions.
930      */
931     public void setEnabledProtocols(final String[] protocolVersions) {
932         protocols = protocolVersions.clone();
933     }
934 
935     /**
936      * Controls whether a new SSL session may be established by this socket.
937      *
938      * @param isCreation The established socket flag.
939      */
940     public void setEnabledSessionCreation(final boolean isCreation) {
941         this.isCreation = isCreation;
942     }
943 
944     /**
945      * Automatic endpoint identification checking using the HTTPS algorithm is supported on Java 1.7+. The default behavior is for this to be disabled.
946      *
947      * This check is only performed on client mode connections.
948      *
949      * @param enable Enable automatic endpoint identification checking using the HTTPS algorithm on Java 1.7+.
950      * @since 3.4
951      */
952     public void setEndpointCheckingEnabled(final boolean enable) {
953         tlsEndpointChecking = enable;
954     }
955 
956     /**
957      * Override the default {@link HostnameVerifier} to use. The verifier is only used on client mode connections.
958      *
959      * @param newHostnameVerifier The HostnameVerifier implementation to set or <code>null</code> to disable.
960      * @since 3.4
961      */
962     public void setHostnameVerifier(final HostnameVerifier newHostnameVerifier) {
963         hostnameVerifier = newHostnameVerifier;
964     }
965 
966     /**
967      * Set a {@link KeyManager} to use
968      *
969      * @param keyManager The KeyManager implementation to set.
970      * @see org.apache.commons.net.util.KeyManagerUtils
971      */
972     public void setKeyManager(final KeyManager keyManager) {
973         this.keyManager = keyManager;
974     }
975 
976     // DEPRECATED - for API compatibility only - DO NOT USE
977 
978     /**
979      * Configures the socket to require client authentication.
980      *
981      * @param isNeedClientAuth The need client auth flag.
982      */
983     public void setNeedClientAuth(final boolean isNeedClientAuth) {
984         this.isNeedClientAuth = isNeedClientAuth;
985     }
986 
987     /**
988      * Override the default {@link TrustManager} to use; if set to {@code null}, the default TrustManager from the JVM will be used.
989      *
990      * @param trustManager The TrustManager implementation to set, may be {@code null}
991      * @see org.apache.commons.net.util.TrustManagerUtils
992      */
993     public void setTrustManager(final TrustManager trustManager) {
994         this.trustManager = trustManager;
995     }
996 
997     /**
998      * Configures the socket to use client (or server) mode in its first handshake.
999      *
1000      * @param isClientMode The use client mode flag.
1001      */
1002     public void setUseClientMode(final boolean isClientMode) {
1003         this.isClientMode = isClientMode;
1004     }
1005 
1006     /**
1007      * Configures the socket to request client authentication, but only if such a request is appropriate to the cipher suite negotiated.
1008      *
1009      * @param isWantClientAuth The want client auth flag.
1010      */
1011     public void setWantClientAuth(final boolean isWantClientAuth) {
1012         this.isWantClientAuth = isWantClientAuth;
1013     }
1014 
1015     /**
1016      * SSL/TLS negotiation. Acquires an SSL socket of a control connection and carries out handshake processing.
1017      *
1018      * @throws IOException If server negotiation fails
1019      */
1020     protected void sslNegotiation() throws IOException {
1021         plainSocket = _socket_;
1022         initSslContext();
1023         final SSLSocket socket = createSSLSocket(_socket_);
1024         socket.setEnableSessionCreation(isCreation);
1025         socket.setUseClientMode(isClientMode);
1026 
1027         // client mode
1028         if (isClientMode) {
1029             if (tlsEndpointChecking) {
1030                 SSLSocketUtils.enableEndpointNameVerification(socket);
1031             }
1032         } else { // server mode
1033             socket.setNeedClientAuth(isNeedClientAuth);
1034             socket.setWantClientAuth(isWantClientAuth);
1035         }
1036 
1037         if (protocols != null) {
1038             socket.setEnabledProtocols(protocols);
1039         }
1040         if (suites != null) {
1041             socket.setEnabledCipherSuites(suites);
1042         }
1043         socket.startHandshake();
1044 
1045         // TODO the following setup appears to duplicate that in the super class methods
1046         _socket_ = socket;
1047         _controlInput_ = new BufferedReader(new InputStreamReader(socket.getInputStream(), getControlEncoding()));
1048         _controlOutput_ = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), getControlEncoding()));
1049 
1050         if (isClientMode && hostnameVerifier != null && !hostnameVerifier.verify(_hostname_, socket.getSession())) {
1051             throw new SSLHandshakeException("Hostname doesn't match certificate");
1052         }
1053     }
1054 
1055 }
1056