001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.commons.net.ftp;
019
020 import java.io.BufferedReader;
021 import java.io.BufferedWriter;
022 import java.io.IOException;
023 import java.io.InputStreamReader;
024 import java.io.OutputStreamWriter;
025 import java.net.Socket;
026 import javax.net.ssl.KeyManager;
027 import javax.net.ssl.SSLContext;
028 import javax.net.ssl.SSLException;
029 import javax.net.ssl.SSLSocket;
030 import javax.net.ssl.SSLSocketFactory;
031 import javax.net.ssl.TrustManager;
032
033 import org.apache.commons.net.util.Base64;
034 import org.apache.commons.net.util.SSLContextUtils;
035 import org.apache.commons.net.util.TrustManagerUtils;
036
037 /**
038 * FTP over SSL processing. If desired, the JVM property -Djavax.net.debug=all can be used to
039 * see wire-level SSL details.
040 *
041 * @version $Id: FTPSClient.java 1230368 2012-01-12 02:00:49Z sebb $
042 * @since 2.0
043 */
044 public class FTPSClient extends FTPClient {
045
046 // From http://www.iana.org/assignments/port-numbers
047
048 // ftps-data 989/tcp ftp protocol, data, over TLS/SSL
049 // ftps-data 989/udp ftp protocol, data, over TLS/SSL
050 // ftps 990/tcp ftp protocol, control, over TLS/SSL
051 // ftps 990/udp ftp protocol, control, over TLS/SSL
052
053 public static final int DEFAULT_FTPS_DATA_PORT = 989;
054 public static final int DEFAULT_FTPS_PORT = 990;
055
056 /** The value that I can set in PROT command (C = Clear, P = Protected) */
057 private static final String[] PROT_COMMAND_VALUE = {"C","E","S","P"};
058 /** Default PROT Command */
059 private static final String DEFAULT_PROT = "C";
060 /** Default secure socket protocol name, i.e. TLS */
061 private static final String DEFAULT_PROTOCOL = "TLS";
062
063 /** The AUTH (Authentication/Security Mechanism) command. */
064 private static final String CMD_AUTH = "AUTH";
065 /** The ADAT (Authentication/Security Data) command. */
066 private static final String CMD_ADAT = "ADAT";
067 /** The PROT (Data Channel Protection Level) command. */
068 private static final String CMD_PROT = "PROT";
069 /** The PBSZ (Protection Buffer Size) command. */
070 private static final String CMD_PBSZ = "PBSZ";
071 /** The MIC (Integrity Protected Command) command. */
072 private static final String CMD_MIC = "MIC";
073 /** The CONF (Confidentiality Protected Command) command. */
074 private static final String CMD_CONF = "CONF";
075 /** The ENC (Privacy Protected Command) command. */
076 private static final String CMD_ENC = "ENC";
077 /** The CCC (Clear Command Channel) command. */
078 private static final String CMD_CCC = "CCC";
079
080 /** The security mode. (True - Implicit Mode / False - Explicit Mode) */
081 private final boolean isImplicit;
082 /** The secure socket protocol to be used, e.g. SSL/TLS. */
083 private final String protocol;
084 /** The AUTH Command value */
085 private String auth = DEFAULT_PROTOCOL;
086 /** The context object. */
087 private SSLContext context;
088 /** The socket object. */
089 private Socket plainSocket;
090 /** Controls whether a new SSL session may be established by this socket. Default true. */
091 private boolean isCreation = true;
092 /** The use client mode flag. */
093 private boolean isClientMode = true;
094 /** The need client auth flag. */
095 private boolean isNeedClientAuth = false;
096 /** The want client auth flag. */
097 private boolean isWantClientAuth = false;
098 /** The cipher suites */
099 private String[] suites = null;
100 /** The protocol versions */
101 private String[] protocols = null;
102
103 /** The FTPS {@link TrustManager} implementation, default validate only: {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}. */
104 private TrustManager trustManager = TrustManagerUtils.getValidateServerCertificateTrustManager();
105
106 /** The {@link KeyManager}, default null (i.e. use system default). */
107 private KeyManager keyManager = null;
108
109 /**
110 * Constructor for FTPSClient.
111 * Sets protocol to {@link #DEFAULT_PROTOCOL} - i.e. TLS - and security mode to explicit (isImplicit = false)
112 */
113 public FTPSClient() {
114 this(DEFAULT_PROTOCOL, false);
115 }
116
117 /**
118 * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS
119 * @param isImplicit The security mode (Implicit/Explicit).
120 */
121 public FTPSClient(boolean isImplicit) {
122 this(DEFAULT_PROTOCOL, isImplicit);
123 }
124
125 /**
126 * Constructor for FTPSClient, using explict mode
127 * @param protocol the protocol to use
128 */
129 public FTPSClient(String protocol) {
130 this(protocol, false);
131 }
132
133 /**
134 * Constructor for FTPSClient allowing specification of protocol
135 * and security mode. If isImplicit is true, the port is set to
136 * {@link #DEFAULT_FTPS_PORT} i.e. 990.
137 *
138 * @param protocol the protocol
139 * @param isImplicit The security mode(Implicit/Explicit).
140 */
141 public FTPSClient(String protocol, boolean isImplicit) {
142 super();
143 this.protocol = protocol;
144 this.isImplicit = isImplicit;
145 if (isImplicit) {
146 setDefaultPort(DEFAULT_FTPS_PORT);
147 }
148 }
149
150 /**
151 * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS
152 * @param isImplicit The security mode(Implicit/Explicit).
153 * @param context A pre-configured SSL Context
154 */
155 public FTPSClient(boolean isImplicit, SSLContext context) {
156 this(DEFAULT_PROTOCOL, isImplicit);
157 this.context = context;
158 }
159
160 /**
161 * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS
162 * and isImplicit {@code false}
163 *
164 * @param context A pre-configured SSL Context
165 */
166 public FTPSClient(SSLContext context) {
167 this(false, context);
168 }
169
170
171 /**
172 * Set AUTH command use value.
173 * This processing is done before connected processing.
174 * @param auth AUTH command use value.
175 */
176 public void setAuthValue(String auth) {
177 this.auth = auth;
178 }
179
180 /**
181 * Return AUTH command use value.
182 * @return AUTH command use value.
183 */
184 public String getAuthValue() {
185 return this.auth;
186 }
187
188
189 /**
190 * Because there are so many connect() methods,
191 * the _connectAction_() method is provided as a means of performing
192 * some action immediately after establishing a connection,
193 * rather than reimplementing all of the connect() methods.
194 * @throws IOException If it throw by _connectAction_.
195 * @see org.apache.commons.net.SocketClient#_connectAction_()
196 */
197 @Override
198 protected void _connectAction_() throws IOException {
199 // Implicit mode.
200 if (isImplicit) {
201 sslNegotiation();
202 }
203 super._connectAction_();
204 // Explicit mode.
205 if (!isImplicit) {
206 execAUTH();
207 sslNegotiation();
208 }
209 }
210
211 /**
212 * AUTH command.
213 * @throws SSLException If it server reply code not equal "234" and "334".
214 * @throws IOException If an I/O error occurs while either sending
215 * the command.
216 */
217 protected void execAUTH() throws SSLException, IOException {
218 int replyCode = sendCommand(CMD_AUTH, auth);
219 if (FTPReply.SECURITY_MECHANISM_IS_OK == replyCode) {
220 // replyCode = 334
221 // I carry out an ADAT command.
222 } else if (FTPReply.SECURITY_DATA_EXCHANGE_COMPLETE != replyCode) {
223 throw new SSLException(getReplyString());
224 }
225 }
226
227 /**
228 * Performs a lazy init of the SSL context
229 * @throws IOException
230 */
231 private void initSslContext() throws IOException {
232 if (context == null) {
233 context = SSLContextUtils.createSSLContext(protocol, getKeyManager(), getTrustManager());
234 }
235 }
236
237 /**
238 * SSL/TLS negotiation. Acquires an SSL socket of a control
239 * connection and carries out handshake processing.
240 * @throws IOException If server negotiation fails
241 */
242 protected void sslNegotiation() throws IOException {
243 plainSocket = _socket_;
244 initSslContext();
245
246 SSLSocketFactory ssf = context.getSocketFactory();
247 String ip = _socket_.getInetAddress().getHostAddress();
248 int port = _socket_.getPort();
249 SSLSocket socket =
250 (SSLSocket) ssf.createSocket(_socket_, ip, port, false);
251 socket.setEnableSessionCreation(isCreation);
252 socket.setUseClientMode(isClientMode);
253 // server mode
254 if (!isClientMode) {
255 socket.setNeedClientAuth(isNeedClientAuth);
256 socket.setWantClientAuth(isWantClientAuth);
257 }
258
259 if (protocols != null) {
260 socket.setEnabledProtocols(protocols);
261 }
262 if (suites != null) {
263 socket.setEnabledCipherSuites(suites);
264 }
265 socket.startHandshake();
266
267 _socket_ = socket;
268 _controlInput_ = new BufferedReader(new InputStreamReader(
269 socket .getInputStream(), getControlEncoding()));
270 _controlOutput_ = new BufferedWriter(new OutputStreamWriter(
271 socket.getOutputStream(), getControlEncoding()));
272 }
273
274 /**
275 * Get the {@link KeyManager} instance.
276 * @return The {@link KeyManager} instance
277 */
278 private KeyManager getKeyManager() {
279 return keyManager;
280 }
281
282 /**
283 * Set a {@link KeyManager} to use
284 *
285 * @param keyManager The KeyManager implementation to set.
286 * @see org.apache.commons.net.util.KeyManagerUtils
287 */
288 public void setKeyManager(KeyManager keyManager) {
289 this.keyManager = keyManager;
290 }
291
292 /**
293 * Controls whether a new SSL session may be established by this socket.
294 * @param isCreation The established socket flag.
295 */
296 public void setEnabledSessionCreation(boolean isCreation) {
297 this.isCreation = isCreation;
298 }
299
300 /**
301 * Returns true if new SSL sessions may be established by this socket.
302 * When the underlying {@link Socket} instance is not SSL-enabled (i.e. an
303 * instance of {@link SSLSocket} with {@link SSLSocket}{@link #getEnableSessionCreation()}) enabled,
304 * this returns False.
305 * @return true - Indicates that sessions may be created;
306 * this is the default.
307 * false - indicates that an existing session must be resumed.
308 */
309 public boolean getEnableSessionCreation() {
310 if (_socket_ instanceof SSLSocket) {
311 return ((SSLSocket)_socket_).getEnableSessionCreation();
312 }
313 return false;
314 }
315
316 /**
317 * Configures the socket to require client authentication.
318 * @param isNeedClientAuth The need client auth flag.
319 */
320 public void setNeedClientAuth(boolean isNeedClientAuth) {
321 this.isNeedClientAuth = isNeedClientAuth;
322 }
323
324 /**
325 * Returns true if the socket will require client authentication.
326 * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false.
327 * @return true - If the server mode socket should request
328 * that the client authenticate itself.
329 */
330 public boolean getNeedClientAuth() {
331 if (_socket_ instanceof SSLSocket) {
332 return ((SSLSocket)_socket_).getNeedClientAuth();
333 }
334 return false;
335 }
336
337 /**
338 * Configures the socket to request client authentication,
339 * but only if such a request is appropriate to the cipher
340 * suite negotiated.
341 * @param isWantClientAuth The want client auth flag.
342 */
343 public void setWantClientAuth(boolean isWantClientAuth) {
344 this.isWantClientAuth = isWantClientAuth;
345 }
346
347 /**
348 * Returns true if the socket will request client authentication.
349 * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false.
350 * @return true - If the server mode socket should request
351 * that the client authenticate itself.
352 */
353 public boolean getWantClientAuth() {
354 if (_socket_ instanceof SSLSocket) {
355 return ((SSLSocket)_socket_).getWantClientAuth();
356 }
357 return false;
358 }
359
360 /**
361 * Configures the socket to use client (or server) mode in its first
362 * handshake.
363 * @param isClientMode The use client mode flag.
364 */
365 public void setUseClientMode(boolean isClientMode) {
366 this.isClientMode = isClientMode;
367 }
368
369 /**
370 * Returns true if the socket is set to use client mode
371 * in its first handshake.
372 * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false.
373 * @return true - If the socket should start its first handshake
374 * in "client" mode.
375 */
376 public boolean getUseClientMode() {
377 if (_socket_ instanceof SSLSocket) {
378 return ((SSLSocket)_socket_).getUseClientMode();
379 }
380 return false;
381 }
382
383 /**
384 * Controls which particular cipher suites are enabled for use on this
385 * connection. Called before server negotiation.
386 * @param cipherSuites The cipher suites.
387 */
388 public void setEnabledCipherSuites(String[] cipherSuites) {
389 suites = new String[cipherSuites.length];
390 System.arraycopy(cipherSuites, 0, suites, 0, cipherSuites.length);
391 }
392
393 /**
394 * Returns the names of the cipher suites which could be enabled
395 * for use on this connection.
396 * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null.
397 * @return An array of cipher suite names, or <code>null</code>
398 */
399 public String[] getEnabledCipherSuites() {
400 if (_socket_ instanceof SSLSocket) {
401 return ((SSLSocket)_socket_).getEnabledCipherSuites();
402 }
403 return null;
404 }
405
406 /**
407 * Controls which particular protocol versions are enabled for use on this
408 * connection. I perform setting before a server negotiation.
409 * @param protocolVersions The protocol versions.
410 */
411 public void setEnabledProtocols(String[] protocolVersions) {
412 protocols = new String[protocolVersions.length];
413 System.arraycopy(protocolVersions, 0, protocols, 0, protocolVersions.length);
414 }
415
416 /**
417 * Returns the names of the protocol versions which are currently
418 * enabled for use on this connection.
419 * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null.
420 * @return An array of protocols, or <code>null</code>
421 */
422 public String[] getEnabledProtocols() {
423 if (_socket_ instanceof SSLSocket) {
424 return ((SSLSocket)_socket_).getEnabledProtocols();
425 }
426 return null;
427 }
428
429 /**
430 * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer.
431 * @param pbsz Protection Buffer Size.
432 * @throws SSLException If the server reply code does not equal "200".
433 * @throws IOException If an I/O error occurs while sending
434 * the command.
435 * @see #parsePBSZ(long)
436 */
437 public void execPBSZ(long pbsz) throws SSLException, IOException {
438 if (pbsz < 0 || 4294967295L < pbsz) { // 32-bit unsigned number
439 throw new IllegalArgumentException();
440 }
441 int status = sendCommand(CMD_PBSZ, String.valueOf(pbsz));
442 if (FTPReply.COMMAND_OK != status) {
443 throw new SSLException(getReplyString());
444 }
445 }
446
447 /**
448 * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer.
449 * Issues the command and parses the response to return the negotiated value.
450 *
451 * @param pbsz Protection Buffer Size.
452 * @throws SSLException If the server reply code does not equal "200".
453 * @throws IOException If an I/O error occurs while sending
454 * the command.
455 * @return the negotiated value.
456 * @see #execPBSZ(long)
457 * @since 3.0
458 */
459 public long parsePBSZ(long pbsz) throws SSLException, IOException {
460 execPBSZ(pbsz);
461 long minvalue = pbsz;
462 String remainder = extractPrefixedData("PBSZ=", getReplyString());
463 if (remainder != null) {
464 long replysz = Long.parseLong(remainder);
465 if (replysz < minvalue) {
466 minvalue = replysz;
467 }
468 }
469 return minvalue;
470 }
471
472 /**
473 * PROT command.<br/>
474 * C - Clear<br/>
475 * S - Safe(SSL protocol only)<br/>
476 * E - Confidential(SSL protocol only)<br/>
477 * P - Private
478 * <p>
479 * <b>N.B.</b> the method calls
480 * {@link #setSocketFactory(javax.net.SocketFactory)} and
481 * {@link #setServerSocketFactory(javax.net.ServerSocketFactory)}
482 *
483 * @param prot Data Channel Protection Level.
484 * @throws SSLException If the server reply code does not equal "200".
485 * @throws IOException If an I/O error occurs while sending
486 * the command.
487 */
488 public void execPROT(String prot) throws SSLException, IOException {
489 if (prot == null) {
490 prot = DEFAULT_PROT;
491 }
492 if (!checkPROTValue(prot)) {
493 throw new IllegalArgumentException();
494 }
495 if (FTPReply.COMMAND_OK != sendCommand(CMD_PROT, prot)) {
496 throw new SSLException(getReplyString());
497 }
498 if (DEFAULT_PROT.equals(prot)) {
499 setSocketFactory(null);
500 setServerSocketFactory(null);
501 } else {
502 setSocketFactory(new FTPSSocketFactory(context));
503 setServerSocketFactory(new FTPSServerSocketFactory(context));
504 initSslContext();
505 }
506 }
507
508 /**
509 * Check the value that can be set in PROT Command value.
510 * @param prot Data Channel Protection Level.
511 * @return True - A set point is right / False - A set point is not right
512 */
513 private boolean checkPROTValue(String prot) {
514 for (int p = 0; p < PROT_COMMAND_VALUE.length; p++) {
515 if (PROT_COMMAND_VALUE[p].equals(prot)) {
516 return true;
517 }
518 }
519 return false;
520 }
521
522 /**
523 * Send an FTP command.
524 * A successful CCC (Clear Command Channel) command causes the underlying {@link SSLSocket}
525 * instance to be assigned to a plain {@link Socket}
526 * @param command The FTP command.
527 * @return server reply.
528 * @throws IOException If an I/O error occurs while sending the command.
529 * @throws SSLException if a CCC command fails
530 * @see org.apache.commons.net.ftp.FTP#sendCommand(java.lang.String)
531 */
532 // Would like to remove this method, but that will break any existing clients that are using CCC
533 @Override
534 public int sendCommand(String command, String args) throws IOException {
535 int repCode = super.sendCommand(command, args);
536 /* If CCC is issued, restore socket i/o streams to unsecured versions */
537 if (CMD_CCC.equals(command)) {
538 if (FTPReply.COMMAND_OK == repCode) {
539 _socket_.close();
540 _socket_ = plainSocket;
541 _controlInput_ = new BufferedReader(
542 new InputStreamReader(
543 _socket_ .getInputStream(), getControlEncoding()));
544 _controlOutput_ = new BufferedWriter(
545 new OutputStreamWriter(
546 _socket_.getOutputStream(), getControlEncoding()));
547 } else {
548 throw new SSLException(getReplyString());
549 }
550 }
551 return repCode;
552 }
553
554 /**
555 * Returns a socket of the data connection.
556 * Wrapped as an {@link SSLSocket}, which carries out handshake processing.
557 * @param command The textual representation of the FTP command to send.
558 * @param arg The arguments to the FTP command.
559 * If this parameter is set to null, then the command is sent with
560 * no arguments.
561 * @return corresponding to the established data connection.
562 * Null is returned if an FTP protocol error is reported at any point
563 * during the establishment and initialization of the connection.
564 * @throws IOException If there is any problem with the connection.
565 * @see FTPClient#_openDataConnection_(int, String)
566 */
567 @Override
568 protected Socket _openDataConnection_(int command, String arg)
569 throws IOException {
570 Socket socket = super._openDataConnection_(command, arg);
571 _prepareDataSocket_(socket);
572 if (socket instanceof SSLSocket) {
573 SSLSocket sslSocket = (SSLSocket)socket;
574
575 sslSocket.setUseClientMode(isClientMode);
576 sslSocket.setEnableSessionCreation(isCreation);
577
578 // server mode
579 if (!isClientMode) {
580 sslSocket.setNeedClientAuth(isNeedClientAuth);
581 sslSocket.setWantClientAuth(isWantClientAuth);
582 }
583 if (suites != null) {
584 sslSocket.setEnabledCipherSuites(suites);
585 }
586 if (protocols != null) {
587 sslSocket.setEnabledProtocols(protocols);
588 }
589 sslSocket.startHandshake();
590 }
591
592 return socket;
593 }
594
595 /**
596 * Performs any custom initialization for a newly created SSLSocket (before
597 * the SSL handshake happens).
598 * Called by {@link #_openDataConnection_(int, String)} immediately
599 * after creating the socket.
600 * The default implementation is a no-op
601 * @throws IOException
602 */
603 protected void _prepareDataSocket_(Socket socket)
604 throws IOException {
605 }
606
607 /**
608 * Get the currently configured {@link TrustManager}.
609 *
610 * @return A TrustManager instance.
611 */
612 public TrustManager getTrustManager() {
613 return trustManager;
614 }
615
616 /**
617 * Override the default {@link TrustManager} to use.
618 *
619 * @param trustManager The TrustManager implementation to set.
620 * @see org.apache.commons.net.util.TrustManagerUtils
621 */
622 public void setTrustManager(TrustManager trustManager) {
623 this.trustManager = trustManager;
624 }
625
626 /**
627 * Closes the connection to the FTP server and restores
628 * connection parameters to the default values.
629 * <p>
630 * Calls {@code setSocketFactory(null)} and {@code setServerSocketFactory(null)}
631 * to reset the factories that may have been changed during the session,
632 * e.g. by {@link #execPROT(String)}
633 * @exception IOException If an error occurs while disconnecting.
634 * @since 3.0
635 */
636 @Override
637 public void disconnect() throws IOException
638 {
639 super.disconnect();
640 setSocketFactory(null);
641 setServerSocketFactory(null);
642 }
643
644 /**
645 * Send the AUTH command with the specified mechanism.
646 * @param mechanism The mechanism name to send with the command.
647 * @return server reply.
648 * @throws IOException If an I/O error occurs while sending
649 * the command.
650 * @since 3.0
651 */
652 public int execAUTH(String mechanism) throws IOException
653 {
654 return sendCommand(CMD_AUTH, mechanism);
655 }
656
657 /**
658 * Send the ADAT command with the specified authentication data.
659 * @param data The data to send with the command.
660 * @return server reply.
661 * @throws IOException If an I/O error occurs while sending
662 * the command.
663 * @since 3.0
664 */
665 public int execADAT(byte[] data) throws IOException
666 {
667 if (data != null)
668 {
669 return sendCommand(CMD_ADAT, new String(Base64.encodeBase64(data)));
670 }
671 else
672 {
673 return sendCommand(CMD_ADAT);
674 }
675 }
676
677 /**
678 * Send the CCC command to the server.
679 * The CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be assigned
680 * to a plain {@link Socket} instances
681 * @return server reply.
682 * @throws IOException If an I/O error occurs while sending
683 * the command.
684 * @since 3.0
685 */
686 public int execCCC() throws IOException
687 {
688 int repCode = sendCommand(CMD_CCC);
689 // This will be performed by sendCommand(String, String)
690 // if (FTPReply.isPositiveCompletion(repCode)) {
691 // _socket_.close();
692 // _socket_ = plainSocket;
693 // _controlInput_ = new BufferedReader(
694 // new InputStreamReader(
695 // _socket_.getInputStream(), getControlEncoding()));
696 // _controlOutput_ = new BufferedWriter(
697 // new OutputStreamWriter(
698 // _socket_.getOutputStream(), getControlEncoding()));
699 // }
700 return repCode;
701 }
702
703 /**
704 * Send the MIC command with the specified data.
705 * @param data The data to send with the command.
706 * @return server reply.
707 * @throws IOException If an I/O error occurs while sending
708 * the command.
709 * @since 3.0
710 */
711 public int execMIC(byte[] data) throws IOException
712 {
713 if (data != null)
714 {
715 return sendCommand(CMD_MIC, new String(Base64.encodeBase64(data)));
716 }
717 else
718 {
719 return sendCommand(CMD_MIC, ""); // perhaps "=" or just sendCommand(String)?
720 }
721 }
722
723 /**
724 * Send the CONF command with the specified data.
725 * @param data The data to send with the command.
726 * @return server reply.
727 * @throws IOException If an I/O error occurs while sending
728 * the command.
729 * @since 3.0
730 */
731 public int execCONF(byte[] data) throws IOException
732 {
733 if (data != null)
734 {
735 return sendCommand(CMD_CONF, new String(Base64.encodeBase64(data)));
736 }
737 else
738 {
739 return sendCommand(CMD_CONF, ""); // perhaps "=" or just sendCommand(String)?
740 }
741 }
742
743 /**
744 * Send the ENC command with the specified data.
745 * @param data The data to send with the command.
746 * @return server reply.
747 * @throws IOException If an I/O error occurs while sending
748 * the command.
749 * @since 3.0
750 */
751 public int execENC(byte[] data) throws IOException
752 {
753 if (data != null)
754 {
755 return sendCommand(CMD_ENC, new String(Base64.encodeBase64(data)));
756 }
757 else
758 {
759 return sendCommand(CMD_ENC, ""); // perhaps "=" or just sendCommand(String)?
760 }
761 }
762
763 /**
764 * Parses the given ADAT response line and base64-decodes the data.
765 * @param reply The ADAT reply to parse.
766 * @return the data in the reply, base64-decoded.
767 * @since 3.0
768 */
769 public byte[] parseADATReply(String reply)
770 {
771 if (reply == null) {
772 return null;
773 } else {
774 return Base64.decodeBase64(extractPrefixedData("ADAT=", reply));
775 }
776 }
777
778 /**
779 * Extract the data from a reply with a prefix, e.g. PBSZ=1234 => 1234
780 * @param prefix the prefix to find
781 * @param reply where to find the prefix
782 * @return the remainder of the string after the prefix, or null if the prefix was not present.
783 */
784 private String extractPrefixedData(String prefix, String reply) {
785 int idx = reply.indexOf(prefix);
786 if (idx == -1) {
787 return null;
788 }
789 // N.B. Cannot use trim before substring as leading space would affect the offset.
790 return reply.substring(idx+prefix.length()).trim();
791 }
792
793 // DEPRECATED - for API compatibility only - DO NOT USE
794
795 /** @deprecated - not used - may be removed in a future release */
796 @Deprecated
797 public static String KEYSTORE_ALGORITHM;
798
799 /** @deprecated - not used - may be removed in a future release */
800 @Deprecated
801 public static String TRUSTSTORE_ALGORITHM;
802
803 /** @deprecated - not used - may be removed in a future release */
804 @Deprecated
805 public static String PROVIDER;
806
807 /** @deprecated - not used - may be removed in a future release */
808 @Deprecated
809 public static String STORE_TYPE;
810
811 }
812 /* kate: indent-width 4; replace-tabs on; */