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 1125962 2011-05-22 13:34:53Z 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) sslNegotiation(); 201 super._connectAction_(); 202 // Explicit mode. 203 if (!isImplicit) { 204 execAUTH(); 205 sslNegotiation(); 206 } 207 } 208 209 /** 210 * AUTH command. 211 * @throws SSLException If it server reply code not equal "234" and "334". 212 * @throws IOException If an I/O error occurs while either sending 213 * the command. 214 */ 215 protected void execAUTH() throws SSLException, IOException { 216 int replyCode = sendCommand(CMD_AUTH, auth); 217 if (FTPReply.SECURITY_MECHANISM_IS_OK == replyCode) { 218 // replyCode = 334 219 // I carry out an ADAT command. 220 } else if (FTPReply.SECURITY_DATA_EXCHANGE_COMPLETE != replyCode) { 221 throw new SSLException(getReplyString()); 222 } 223 } 224 225 /** 226 * Performs a lazy init of the SSL context 227 * @throws IOException 228 */ 229 private void initSslContext() throws IOException { 230 if(context == null) { 231 context = SSLContextUtils.createSSLContext(protocol, getKeyManager(), getTrustManager()); 232 } 233 } 234 235 /** 236 * SSL/TLS negotiation. Acquires an SSL socket of a control 237 * connection and carries out handshake processing. 238 * @throws IOException If server negotiation fails 239 */ 240 protected void sslNegotiation() throws IOException { 241 plainSocket = _socket_; 242 initSslContext(); 243 244 SSLSocketFactory ssf = context.getSocketFactory(); 245 String ip = _socket_.getInetAddress().getHostAddress(); 246 int port = _socket_.getPort(); 247 SSLSocket socket = 248 (SSLSocket) ssf.createSocket(_socket_, ip, port, false); 249 socket.setEnableSessionCreation(isCreation); 250 socket.setUseClientMode(isClientMode); 251 // server mode 252 if (!isClientMode) { 253 socket.setNeedClientAuth(isNeedClientAuth); 254 socket.setWantClientAuth(isWantClientAuth); 255 } 256 257 if (protocols != null) socket.setEnabledProtocols(protocols); 258 if (suites != null) socket.setEnabledCipherSuites(suites); 259 socket.startHandshake(); 260 261 _socket_ = socket; 262 _controlInput_ = new BufferedReader(new InputStreamReader( 263 socket .getInputStream(), getControlEncoding())); 264 _controlOutput_ = new BufferedWriter(new OutputStreamWriter( 265 socket.getOutputStream(), getControlEncoding())); 266 } 267 268 /** 269 * Get the {@link KeyManager} instance. 270 * @return The {@link KeyManager} instance 271 */ 272 private KeyManager getKeyManager() { 273 return keyManager; 274 } 275 276 /** 277 * Set a {@link KeyManager} to use 278 * 279 * @param keyManager The KeyManager implementation to set. 280 * @see org.apache.commons.net.util.KeyManagerUtils 281 */ 282 public void setKeyManager(KeyManager keyManager) { 283 this.keyManager = keyManager; 284 } 285 286 /** 287 * Controls whether a new SSL session may be established by this socket. 288 * @param isCreation The established socket flag. 289 */ 290 public void setEnabledSessionCreation(boolean isCreation) { 291 this.isCreation = isCreation; 292 } 293 294 /** 295 * Returns true if new SSL sessions may be established by this socket. 296 * When the underlying {@link Socket} instance is not SSL-enabled (i.e. an 297 * instance of {@link SSLSocket} with {@link SSLSocket}{@link #getEnableSessionCreation()}) enabled, 298 * this returns False. 299 * @return true - Indicates that sessions may be created; 300 * this is the default. 301 * false - indicates that an existing session must be resumed. 302 */ 303 public boolean getEnableSessionCreation() { 304 if (_socket_ instanceof SSLSocket) 305 return ((SSLSocket)_socket_).getEnableSessionCreation(); 306 return false; 307 } 308 309 /** 310 * Configures the socket to require client authentication. 311 * @param isNeedClientAuth The need client auth flag. 312 */ 313 public void setNeedClientAuth(boolean isNeedClientAuth) { 314 this.isNeedClientAuth = isNeedClientAuth; 315 } 316 317 /** 318 * Returns true if the socket will require client authentication. 319 * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. 320 * @return true - If the server mode socket should request 321 * that the client authenticate itself. 322 */ 323 public boolean getNeedClientAuth() { 324 if (_socket_ instanceof SSLSocket) 325 return ((SSLSocket)_socket_).getNeedClientAuth(); 326 return false; 327 } 328 329 /** 330 * Configures the socket to request client authentication, 331 * but only if such a request is appropriate to the cipher 332 * suite negotiated. 333 * @param isWantClientAuth The want client auth flag. 334 */ 335 public void setWantClientAuth(boolean isWantClientAuth) { 336 this.isWantClientAuth = isWantClientAuth; 337 } 338 339 /** 340 * Returns true if the socket will request client authentication. 341 * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. 342 * @return true - If the server mode socket should request 343 * that the client authenticate itself. 344 */ 345 public boolean getWantClientAuth() { 346 if (_socket_ instanceof SSLSocket) 347 return ((SSLSocket)_socket_).getWantClientAuth(); 348 return false; 349 } 350 351 /** 352 * Configures the socket to use client (or server) mode in its first 353 * handshake. 354 * @param isClientMode The use client mode flag. 355 */ 356 public void setUseClientMode(boolean isClientMode) { 357 this.isClientMode = isClientMode; 358 } 359 360 /** 361 * Returns true if the socket is set to use client mode 362 * in its first handshake. 363 * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. 364 * @return true - If the socket should start its first handshake 365 * in "client" mode. 366 */ 367 public boolean getUseClientMode() { 368 if (_socket_ instanceof SSLSocket) 369 return ((SSLSocket)_socket_).getUseClientMode(); 370 return false; 371 } 372 373 /** 374 * Controls which particular cipher suites are enabled for use on this 375 * connection. Called before server negotiation. 376 * @param cipherSuites The cipher suites. 377 */ 378 public void setEnabledCipherSuites(String[] cipherSuites) { 379 suites = new String[cipherSuites.length]; 380 System.arraycopy(cipherSuites, 0, suites, 0, cipherSuites.length); 381 } 382 383 /** 384 * Returns the names of the cipher suites which could be enabled 385 * for use on this connection. 386 * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null. 387 * @return An array of cipher suite names, or <code>null</code> 388 */ 389 public String[] getEnabledCipherSuites() { 390 if (_socket_ instanceof SSLSocket) 391 return ((SSLSocket)_socket_).getEnabledCipherSuites(); 392 return null; 393 } 394 395 /** 396 * Controls which particular protocol versions are enabled for use on this 397 * connection. I perform setting before a server negotiation. 398 * @param protocolVersions The protocol versions. 399 */ 400 public void setEnabledProtocols(String[] protocolVersions) { 401 protocols = new String[protocolVersions.length]; 402 System.arraycopy(protocolVersions, 0, protocols, 0, protocolVersions.length); 403 } 404 405 /** 406 * Returns the names of the protocol versions which are currently 407 * enabled for use on this connection. 408 * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null. 409 * @return An array of protocols, or <code>null</code> 410 */ 411 public String[] getEnabledProtocols() { 412 if (_socket_ instanceof SSLSocket) 413 return ((SSLSocket)_socket_).getEnabledProtocols(); 414 return null; 415 } 416 417 /** 418 * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. 419 * @param pbsz Protection Buffer Size. 420 * @throws SSLException If the server reply code does not equal "200". 421 * @throws IOException If an I/O error occurs while sending 422 * the command. 423 * @see #parsePBSZ(long) 424 */ 425 public void execPBSZ(long pbsz) throws SSLException, IOException { 426 if (pbsz < 0 || 4294967295L < pbsz) // 32-bit unsigned number 427 throw new IllegalArgumentException(); 428 int status = sendCommand(CMD_PBSZ, String.valueOf(pbsz)); 429 if (FTPReply.COMMAND_OK != status) { 430 throw new SSLException(getReplyString()); 431 } 432 } 433 434 /** 435 * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. 436 * Issues the command and parses the response to return the negotiated value. 437 * 438 * @param pbsz Protection Buffer Size. 439 * @throws SSLException If the server reply code does not equal "200". 440 * @throws IOException If an I/O error occurs while sending 441 * the command. 442 * @return the negotiated value. 443 * @see #execPBSZ(long) 444 * @since 3.0 445 */ 446 public long parsePBSZ(long pbsz) throws SSLException, IOException { 447 execPBSZ(pbsz); 448 long minvalue = pbsz; 449 String remainder = extractPrefixedData("PBSZ=", getReplyString()); 450 if (remainder != null) { 451 long replysz = Long.parseLong(remainder); 452 if (replysz < minvalue) { 453 minvalue = replysz; 454 } 455 } 456 return minvalue; 457 } 458 459 /** 460 * PROT command.</br> 461 * C - Clear</br> 462 * S - Safe(SSL protocol only)</br> 463 * E - Confidential(SSL protocol only)</br> 464 * P - Private 465 * <p> 466 * <b>N.B.</b> the method calls 467 * {@link #setSocketFactory(javax.net.SocketFactory)} and 468 * {@link #setServerSocketFactory(javax.net.ServerSocketFactory)} 469 * 470 * @param prot Data Channel Protection Level. 471 * @throws SSLException If the server reply code does not equal "200". 472 * @throws IOException If an I/O error occurs while sending 473 * the command. 474 */ 475 public void execPROT(String prot) throws SSLException, IOException { 476 if (prot == null) prot = DEFAULT_PROT; 477 if (!checkPROTValue(prot)) throw new IllegalArgumentException(); 478 if (FTPReply.COMMAND_OK != sendCommand(CMD_PROT, prot)) 479 throw new SSLException(getReplyString()); 480 if (DEFAULT_PROT.equals(prot)) { 481 setSocketFactory(null); 482 setServerSocketFactory(null); 483 } else { 484 setSocketFactory(new FTPSSocketFactory(context)); 485 setServerSocketFactory(new FTPSServerSocketFactory(context)); 486 initSslContext(); 487 } 488 } 489 490 /** 491 * Check the value that can be set in PROT Command value. 492 * @param prot Data Channel Protection Level. 493 * @return True - A set point is right / False - A set point is not right 494 */ 495 private boolean checkPROTValue(String prot) { 496 for (int p = 0; p < PROT_COMMAND_VALUE.length; p++) { 497 if (PROT_COMMAND_VALUE[p].equals(prot)) return true; 498 } 499 return false; 500 } 501 502 /** 503 * Send an FTP command. 504 * A successful CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} 505 * instance to be assigned to a plain {@link Socket} 506 * @param command The FTP command. 507 * @return server reply. 508 * @throws IOException If an I/O error occurs while sending the command. 509 * @throws SSLException if a CCC command fails 510 * @see org.apache.commons.net.ftp.FTP#sendCommand(java.lang.String) 511 */ 512 // Would like to remove this method, but that will break any existing clients that are using CCC 513 @Override 514 public int sendCommand(String command, String args) throws IOException { 515 int repCode = super.sendCommand(command, args); 516 /* If CCC is issued, restore socket i/o streams to unsecured versions */ 517 if (CMD_CCC.equals(command)) { 518 if (FTPReply.COMMAND_OK == repCode) { 519 _socket_.close(); 520 _socket_ = plainSocket; 521 _controlInput_ = new BufferedReader( 522 new InputStreamReader( 523 _socket_ .getInputStream(), getControlEncoding())); 524 _controlOutput_ = new BufferedWriter( 525 new OutputStreamWriter( 526 _socket_.getOutputStream(), getControlEncoding())); 527 } else { 528 throw new SSLException(getReplyString()); 529 } 530 } 531 return repCode; 532 } 533 534 /** 535 * Returns a socket of the data connection. 536 * Wrapped as an {@link SSLSocket}, which carries out handshake processing. 537 * @param command The textual representation of the FTP command to send. 538 * @param arg The arguments to the FTP command. 539 * If this parameter is set to null, then the command is sent with 540 * no arguments. 541 * @return corresponding to the established data connection. 542 * Null is returned if an FTP protocol error is reported at any point 543 * during the establishment and initialization of the connection. 544 * @throws IOException If there is any problem with the connection. 545 * @see FTPClient#_openDataConnection_(int, String) 546 */ 547 @Override 548 protected Socket _openDataConnection_(int command, String arg) 549 throws IOException { 550 Socket socket = super._openDataConnection_(command, arg); 551 if (socket instanceof SSLSocket) { 552 SSLSocket sslSocket = (SSLSocket)socket; 553 554 sslSocket.setUseClientMode(isClientMode); 555 sslSocket.setEnableSessionCreation(isCreation); 556 557 // server mode 558 if (!isClientMode) { 559 sslSocket.setNeedClientAuth(isNeedClientAuth); 560 sslSocket.setWantClientAuth(isWantClientAuth); 561 } 562 if (suites != null) { 563 sslSocket.setEnabledCipherSuites(suites); 564 } 565 if (protocols != null) { 566 sslSocket.setEnabledProtocols(protocols); 567 } 568 sslSocket.startHandshake(); 569 } 570 571 return socket; 572 } 573 574 /** 575 * Get the currently configured {@link TrustManager}. 576 * 577 * @return A TrustManager instance. 578 */ 579 public TrustManager getTrustManager() { 580 return trustManager; 581 } 582 583 /** 584 * Override the default {@link TrustManager} to use. 585 * 586 * @param trustManager The TrustManager implementation to set. 587 * @see org.apache.commons.net.util.TrustManagerUtils 588 */ 589 public void setTrustManager(TrustManager trustManager) { 590 this.trustManager = trustManager; 591 } 592 593 /** 594 * Closes the connection to the FTP server and restores 595 * connection parameters to the default values. 596 * <p> 597 * Calls {@code setSocketFactory(null)} and {@code setServerSocketFactory(null)} 598 * to reset the factories that may have been changed during the session, 599 * e.g. by {@link #execPROT(String)} 600 * @exception IOException If an error occurs while disconnecting. 601 * @since 3.0 602 */ 603 @Override 604 public void disconnect() throws IOException 605 { 606 super.disconnect(); 607 setSocketFactory(null); 608 setServerSocketFactory(null); 609 } 610 611 /** 612 * Send the AUTH command with the specified mechanism. 613 * @param mechanism The mechanism name to send with the command. 614 * @return server reply. 615 * @throws IOException If an I/O error occurs while sending 616 * the command. 617 * @since 3.0 618 */ 619 public int execAUTH(String mechanism) throws IOException 620 { 621 return sendCommand(CMD_AUTH, mechanism); 622 } 623 624 /** 625 * Send the ADAT command with the specified authentication data. 626 * @param data The data to send with the command. 627 * @return server reply. 628 * @throws IOException If an I/O error occurs while sending 629 * the command. 630 * @since 3.0 631 */ 632 public int execADAT(byte[] data) throws IOException 633 { 634 if (data != null) 635 { 636 return sendCommand(CMD_ADAT, new String(Base64.encodeBase64(data))); 637 } 638 else 639 { 640 return sendCommand(CMD_ADAT); 641 } 642 } 643 644 /** 645 * Send the CCC command to the server. 646 * The CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be assigned 647 * to a plain {@link Socket} instances 648 * @return server reply. 649 * @throws IOException If an I/O error occurs while sending 650 * the command. 651 * @since 3.0 652 */ 653 public int execCCC() throws IOException 654 { 655 int repCode = sendCommand(CMD_CCC); 656 // This will be performed by sendCommand(String, String) 657 // if (FTPReply.isPositiveCompletion(repCode)) { 658 // _socket_.close(); 659 // _socket_ = plainSocket; 660 // _controlInput_ = new BufferedReader( 661 // new InputStreamReader( 662 // _socket_.getInputStream(), getControlEncoding())); 663 // _controlOutput_ = new BufferedWriter( 664 // new OutputStreamWriter( 665 // _socket_.getOutputStream(), getControlEncoding())); 666 // } 667 return repCode; 668 } 669 670 /** 671 * Send the MIC command with the specified data. 672 * @param data The data to send with the command. 673 * @return server reply. 674 * @throws IOException If an I/O error occurs while sending 675 * the command. 676 * @since 3.0 677 */ 678 public int execMIC(byte[] data) throws IOException 679 { 680 if (data != null) 681 { 682 return sendCommand(CMD_MIC, new String(Base64.encodeBase64(data))); 683 } 684 else 685 { 686 return sendCommand(CMD_MIC, ""); // perhaps "=" or just sendCommand(String)? 687 } 688 } 689 690 /** 691 * Send the CONF command with the specified data. 692 * @param data The data to send with the command. 693 * @return server reply. 694 * @throws IOException If an I/O error occurs while sending 695 * the command. 696 * @since 3.0 697 */ 698 public int execCONF(byte[] data) throws IOException 699 { 700 if (data != null) 701 { 702 return sendCommand(CMD_CONF, new String(Base64.encodeBase64(data))); 703 } 704 else 705 { 706 return sendCommand(CMD_CONF, ""); // perhaps "=" or just sendCommand(String)? 707 } 708 } 709 710 /** 711 * Send the ENC command with the specified data. 712 * @param data The data to send with the command. 713 * @return server reply. 714 * @throws IOException If an I/O error occurs while sending 715 * the command. 716 * @since 3.0 717 */ 718 public int execENC(byte[] data) throws IOException 719 { 720 if (data != null) 721 { 722 return sendCommand(CMD_ENC, new String(Base64.encodeBase64(data))); 723 } 724 else 725 { 726 return sendCommand(CMD_ENC, ""); // perhaps "=" or just sendCommand(String)? 727 } 728 } 729 730 /** 731 * Parses the given ADAT response line and base64-decodes the data. 732 * @param reply The ADAT reply to parse. 733 * @return the data in the reply, base64-decoded. 734 * @since 3.0 735 */ 736 public byte[] parseADATReply(String reply) 737 { 738 if (reply == null) return null; 739 else { 740 return Base64.decodeBase64(extractPrefixedData("ADAT=", reply)); 741 } 742 } 743 744 /** 745 * Extract the data from a reply with a prefix, e.g. PBSZ=1234 => 1234 746 * @param prefix the prefix to find 747 * @param reply where to find the prefix 748 * @return the remainder of the string after the prefix, or null if the prefix was not present. 749 */ 750 private String extractPrefixedData(String prefix, String reply) { 751 int idx = reply.indexOf(prefix); 752 if (idx == -1) { 753 return null; 754 } 755 // N.B. Cannot use trim before substring as leading space would affect the offset. 756 return reply.substring(idx+prefix.length()).trim(); 757 } 758 759 // DEPRECATED - for API compatibility only - DO NOT USE 760 761 /** @deprecated - not used - may be removed in a future release */ 762 @Deprecated 763 public static String KEYSTORE_ALGORITHM; 764 765 /** @deprecated - not used - may be removed in a future release */ 766 @Deprecated 767 public static String TRUSTSTORE_ALGORITHM; 768 769 /** @deprecated - not used - may be removed in a future release */ 770 @Deprecated 771 public static String PROVIDER; 772 773 /** @deprecated - not used - may be removed in a future release */ 774 @Deprecated 775 public static String STORE_TYPE; 776 777 } 778 /* kate: indent-width 4; replace-tabs on; */