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