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