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 018package org.apache.commons.net.ftp; 019 020import java.io.BufferedReader; 021import java.io.BufferedWriter; 022import java.io.IOException; 023import java.io.InputStreamReader; 024import java.io.OutputStreamWriter; 025import java.net.Socket; 026import javax.net.ssl.KeyManager; 027import javax.net.ssl.SSLContext; 028import javax.net.ssl.SSLException; 029import javax.net.ssl.SSLSocket; 030import javax.net.ssl.SSLSocketFactory; 031import javax.net.ssl.TrustManager; 032 033import org.apache.commons.net.util.Base64; 034import org.apache.commons.net.util.SSLContextUtils; 035import 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 */ 044public 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; */