1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.apache.harmony.xnet.provider.jsse; 18 19 import java.io.ByteArrayOutputStream; 20 import java.io.IOException; 21 import java.io.InputStream; 22 import java.io.OutputStream; 23 import java.io.OutputStreamWriter; 24 import java.net.InetAddress; 25 import java.net.InetSocketAddress; 26 import java.net.Socket; 27 import java.net.SocketException; 28 import java.security.PrivateKey; 29 import java.security.cert.CertificateException; 30 import java.security.cert.X509Certificate; 31 import java.security.interfaces.RSAPublicKey; 32 import java.util.ArrayList; 33 import java.util.concurrent.atomic.AtomicInteger; 34 import java.util.logging.Level; 35 import java.util.logging.Logger; 36 37 import javax.net.ssl.HandshakeCompletedEvent; 38 import javax.net.ssl.HandshakeCompletedListener; 39 import javax.net.ssl.SSLException; 40 import javax.net.ssl.SSLHandshakeException; 41 import javax.net.ssl.SSLSession; 42 43 import org.apache.harmony.security.provider.cert.X509CertImpl; 44 import org.bouncycastle.openssl.PEMWriter; 45 46 /** 47 * Implementation of the class OpenSSLSocketImpl 48 * based on OpenSSL. The JNI native interface for some methods 49 * of this this class are defined in the file: 50 * org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl.cpp 51 * 52 * This class only supports SSLv3 and TLSv1. This should be documented elsewhere 53 * later, for example in the package.html or a separate reference document. 54 */ 55 public class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket { 56 private int ssl_ctx; 57 private int ssl; 58 private InputStream is; 59 private OutputStream os; 60 private final Object handshakeLock = new Object(); 61 private Object readLock = new Object(); 62 private Object writeLock = new Object(); 63 private SSLParameters sslParameters; 64 private OpenSSLSessionImpl sslSession; 65 private Socket socket; 66 private boolean autoClose; 67 private boolean handshakeStarted = false; 68 private ArrayList<HandshakeCompletedListener> listeners; 69 private long ssl_op_no = 0x00000000L; 70 private int timeout = 0; 71 // BEGIN android-added 72 private int handshakeTimeout = -1; // -1 = same as timeout; 0 = infinite 73 // END android-added 74 private InetSocketAddress address; 75 76 private static final String[] supportedProtocols = new String[] { 77 "SSLv3", 78 "TLSv1" 79 }; 80 81 private static final AtomicInteger instanceCount = new AtomicInteger(0); 82 83 public static int getInstanceCount() { 84 return instanceCount.get(); 85 } 86 87 private static void updateInstanceCount(int amount) { 88 instanceCount.addAndGet(amount); 89 } 90 91 /** 92 * Initialize OpenSSL library. 93 */ 94 private native static void nativeinitstatic(); 95 96 static { 97 nativeinitstatic(); 98 } 99 100 private native void nativeinit(String privatekey, String certificate, byte[] seed); 101 102 /** 103 * Initialize the SSL socket and set the certificates for the 104 * future handshaking. 105 */ 106 private void init() throws IOException { 107 String alias = sslParameters.getKeyManager().chooseClientAlias(new String[] { "RSA" }, null, null); 108 if (alias != null) { 109 PrivateKey privateKey = sslParameters.getKeyManager().getPrivateKey(alias); 110 X509Certificate[] certificates = sslParameters.getKeyManager().getCertificateChain(alias); 111 112 ByteArrayOutputStream privateKeyOS = new ByteArrayOutputStream(); 113 PEMWriter privateKeyPEMWriter = new PEMWriter(new OutputStreamWriter(privateKeyOS)); 114 privateKeyPEMWriter.writeObject(privateKey); 115 privateKeyPEMWriter.close(); 116 117 ByteArrayOutputStream certificateOS = new ByteArrayOutputStream(); 118 PEMWriter certificateWriter = new PEMWriter(new OutputStreamWriter(certificateOS)); 119 120 for (int i = 0; i < certificates.length; i++) { 121 certificateWriter.writeObject(certificates[i]); 122 } 123 certificateWriter.close(); 124 125 nativeinit(privateKeyOS.toString(), certificateOS.toString(), 126 sslParameters.getSecureRandomMember() != null ? 127 sslParameters.getSecureRandomMember().generateSeed(1024) : null); 128 } else { 129 nativeinit(null, null, 130 sslParameters.getSecureRandomMember() != null ? 131 sslParameters.getSecureRandomMember().generateSeed(1024) : null); 132 } 133 } 134 135 /** 136 * Class constructor with 2 parameters 137 * 138 * @param sslParameters Parameters for the SSL 139 * context 140 * @param ssl_op_no Parameter to set the enabled 141 * protocols 142 * @throws IOException if network fails 143 */ 144 protected OpenSSLSocketImpl(SSLParameters sslParameters, long ssl_op_no) throws IOException { 145 super(); 146 this.sslParameters = sslParameters; 147 this.ssl_op_no = ssl_op_no; 148 updateInstanceCount(1); 149 } 150 151 /** 152 * Class constructor with 1 parameter 153 * 154 * @param sslParameters Parameters for the SSL 155 * context 156 * @throws IOException if network fails 157 */ 158 protected OpenSSLSocketImpl(SSLParameters sslParameters) throws IOException { 159 super(); 160 this.sslParameters = sslParameters; 161 init(); 162 updateInstanceCount(1); 163 } 164 165 /** 166 * Class constructor with 3 parameters 167 * 168 * @throws IOException if network fails 169 * @throws java.net.UnknownHostException host not defined 170 */ 171 protected OpenSSLSocketImpl(String host, int port, 172 SSLParameters sslParameters) 173 throws IOException { 174 super(host, port); 175 this.sslParameters = sslParameters; 176 init(); 177 updateInstanceCount(1); 178 } 179 180 181 /** 182 * Class constructor with 3 parameters: 1st is InetAddress 183 * 184 * @throws IOException if network fails 185 * @throws java.net.UnknownHostException host not defined 186 */ 187 protected OpenSSLSocketImpl(InetAddress address, int port, 188 SSLParameters sslParameters) 189 throws IOException { 190 super(address, port); 191 this.sslParameters = sslParameters; 192 init(); 193 updateInstanceCount(1); 194 } 195 196 197 /** 198 * Class constructor with 5 parameters: 1st is host 199 * 200 * @throws IOException if network fails 201 * @throws java.net.UnknownHostException host not defined 202 */ 203 protected OpenSSLSocketImpl(String host, int port, InetAddress clientAddress, 204 int clientPort, SSLParameters sslParameters) 205 throws IOException { 206 super(host, port, clientAddress, clientPort); 207 this.sslParameters = sslParameters; 208 init(); 209 updateInstanceCount(1); 210 } 211 212 /** 213 * Class constructor with 5 parameters: 1st is InetAddress 214 * 215 * @throws IOException if network fails 216 * @throws java.net.UnknownHostException host not defined 217 */ 218 protected OpenSSLSocketImpl(InetAddress address, int port, 219 InetAddress clientAddress, int clientPort, SSLParameters sslParameters) 220 throws IOException { 221 super(address, port, clientAddress, clientPort); 222 this.sslParameters = sslParameters; 223 init(); 224 updateInstanceCount(1); 225 } 226 227 /** 228 * Constructor with 5 parameters: 1st is socket. Enhances an existing socket 229 * with SSL functionality. 230 * 231 * @throws IOException if network fails 232 */ 233 protected OpenSSLSocketImpl(Socket socket, String host, int port, 234 boolean autoClose, SSLParameters sslParameters) throws IOException { 235 super(); 236 this.socket = socket; 237 this.timeout = socket.getSoTimeout(); 238 this.address = new InetSocketAddress(host, port); 239 this.autoClose = autoClose; 240 this.sslParameters = sslParameters; 241 init(); 242 updateInstanceCount(1); 243 } 244 245 /** 246 * Adds OpenSSL functionality to the existing socket and starts the SSL 247 * handshaking. 248 */ 249 private native boolean nativeconnect(int ctx, Socket sock, boolean client_mode, int sslsession) throws IOException; 250 private native int nativegetsslsession(int ssl); 251 private native String nativecipherauthenticationmethod(); 252 253 /** 254 * Gets the suitable session reference from the session cache container. 255 * 256 * @return OpenSSLSessionImpl 257 */ 258 private OpenSSLSessionImpl getCachedClientSession() { 259 if (super.getInetAddress() == null || 260 super.getInetAddress().getHostAddress() == null || 261 super.getInetAddress().getHostName() == null) { 262 return null; 263 } 264 ClientSessionContext sessionContext 265 = sslParameters.getClientSessionContext(); 266 return (OpenSSLSessionImpl) sessionContext.getSession( 267 super.getInetAddress().getHostName(), 268 super.getPort()); 269 } 270 271 /** 272 * Ensures that logger is lazily loaded. The outer class seems to load 273 * before logging is ready. 274 */ 275 static class LoggerHolder { 276 static final Logger logger = Logger.getLogger( 277 OpenSSLSocketImpl.class.getName()); 278 } 279 280 /** 281 * Starts a TLS/SSL handshake on this connection using some native methods 282 * from the OpenSSL library. It can negotiate new encryption keys, change 283 * cipher suites, or initiate a new session. The certificate chain is 284 * verified if the correspondent property in java.Security is set. All 285 * listensers are notified at the end of the TLS/SSL handshake. 286 * 287 * @throws <code>IOException</code> if network fails 288 */ 289 public synchronized void startHandshake() throws IOException { 290 synchronized (handshakeLock) { 291 if (!handshakeStarted) { 292 handshakeStarted = true; 293 } else { 294 return; 295 } 296 } 297 298 OpenSSLSessionImpl session = getCachedClientSession(); 299 300 // Check if it's allowed to create a new session (default is true) 301 if (session == null && !sslParameters.getEnableSessionCreation()) { 302 throw new SSLHandshakeException("SSL Session may not be created"); 303 } else { 304 // BEGIN android-added 305 // Temporarily use a different timeout for the handshake process 306 int savedTimeout = timeout; 307 if (handshakeTimeout >= 0) { 308 setSoTimeout(handshakeTimeout); 309 } 310 // END android-added 311 312 Socket socket = this.socket != null ? this.socket : this; 313 int sessionId = session != null ? session.session : 0; 314 boolean reusedSession; 315 synchronized (OpenSSLSocketImpl.class) { 316 reusedSession = nativeconnect(ssl_ctx, socket, 317 sslParameters.getUseClientMode(), sessionId); 318 } 319 if (reusedSession) { 320 // nativeconnect shouldn't return true if the session is not 321 // done 322 session.lastAccessedTime = System.currentTimeMillis(); 323 sslSession = session; 324 325 LoggerHolder.logger.fine("Reused cached session for " 326 + getInetAddress().getHostName() + "."); 327 } else { 328 if (session != null) { 329 LoggerHolder.logger.fine("Reuse of cached session for " 330 + getInetAddress().getHostName() + " failed."); 331 } else { 332 LoggerHolder.logger.fine("Created new session for " 333 + getInetAddress().getHostName() + "."); 334 } 335 336 ClientSessionContext sessionContext 337 = sslParameters.getClientSessionContext(); 338 synchronized (OpenSSLSocketImpl.class) { 339 sessionId = nativegetsslsession(ssl); 340 } 341 if (address == null) { 342 sslSession = new OpenSSLSessionImpl( 343 sessionId, sslParameters, 344 super.getInetAddress().getHostName(), 345 super.getPort(), sessionContext); 346 } else { 347 sslSession = new OpenSSLSessionImpl( 348 sessionId, sslParameters, 349 address.getHostName(), address.getPort(), 350 sessionContext); 351 } 352 353 try { 354 X509Certificate[] peerCertificates = (X509Certificate[]) 355 sslSession.getPeerCertificates(); 356 357 if (peerCertificates == null 358 || peerCertificates.length == 0) { 359 throw new SSLException("Server sends no certificate"); 360 } 361 362 String authMethod; 363 synchronized (OpenSSLSocketImpl.class) { 364 authMethod = nativecipherauthenticationmethod(); 365 } 366 sslParameters.getTrustManager().checkServerTrusted( 367 peerCertificates, 368 authMethod); 369 sessionContext.putSession(sslSession); 370 } catch (CertificateException e) { 371 throw new SSLException("Not trusted server certificate", e); 372 } 373 } 374 375 // BEGIN android-added 376 // Restore the original timeout now that the handshake is complete 377 if (handshakeTimeout >= 0) { 378 setSoTimeout(savedTimeout); 379 } 380 // END android-added 381 } 382 383 if (listeners != null) { 384 // notify the listeners 385 HandshakeCompletedEvent event = 386 new HandshakeCompletedEvent(this, sslSession); 387 int size = listeners.size(); 388 for (int i = 0; i < size; i++) { 389 listeners.get(i).handshakeCompleted(event); 390 } 391 } 392 } 393 394 // To be synchronized because of the verify_callback 395 native synchronized void nativeaccept(Socket socketObject, int m_ctx, boolean client_mode); 396 397 /** 398 * Performs the first part of a SSL/TLS handshaking process with a given 399 * 'host' connection and initializes the SSLSession. 400 */ 401 protected void accept(int m_ctx, boolean client_mode) throws IOException { 402 // Must be set because no handshaking is necessary 403 // in this situation 404 handshakeStarted = true; 405 406 nativeaccept(this, m_ctx, client_mode); 407 408 ServerSessionContext sessionContext 409 = sslParameters.getServerSessionContext(); 410 sslSession = new OpenSSLSessionImpl(nativegetsslsession(ssl), 411 sslParameters, super.getInetAddress().getHostName(), 412 super.getPort(), sessionContext); 413 sslSession.lastAccessedTime = System.currentTimeMillis(); 414 sessionContext.putSession(sslSession); 415 } 416 417 /** 418 * Callback methode for the OpenSSL native certificate verification process. 419 * 420 * @param bytes Byte array containing the cert's 421 * information. 422 * @return 0 if the certificate verification fails or 1 if OK 423 */ 424 @SuppressWarnings("unused") 425 private int verify_callback(byte[][] bytes) { 426 try { 427 X509Certificate[] peerCertificateChain 428 = new X509Certificate[bytes.length]; 429 for(int i = 0; i < bytes.length; i++) { 430 peerCertificateChain[i] = 431 new X509CertImpl(javax.security.cert.X509Certificate.getInstance(bytes[i]).getEncoded()); 432 } 433 434 try { 435 // TODO "null" String 436 sslParameters.getTrustManager().checkClientTrusted(peerCertificateChain, "null"); 437 } catch (CertificateException e) { 438 throw new AlertException(AlertProtocol.BAD_CERTIFICATE, 439 new SSLException("Not trusted server certificate", e)); 440 } 441 } catch (javax.security.cert.CertificateException e) { 442 return 0; 443 } catch (IOException e) { 444 return 0; 445 } 446 return 1; 447 } 448 449 /** 450 * Returns an input stream for this SSL socket using native calls to the 451 * OpenSSL library. 452 * 453 * @return: an input stream for reading bytes from this socket. 454 * @throws: <code>IOException</code> if an I/O error occurs when creating 455 * the input stream, the socket is closed, the socket is not 456 * connected, or the socket input has been shutdown. 457 */ 458 public InputStream getInputStream() throws IOException { 459 synchronized(this) { 460 if (is == null) { 461 is = new SSLInputStream(); 462 } 463 464 return is; 465 } 466 } 467 468 /** 469 * Returns an output stream for this SSL socket using native calls to the 470 * OpenSSL library. 471 * 472 * @return an output stream for writing bytes to this socket. 473 * @throws <code>IOException</code> if an I/O error occurs when creating 474 * the output stream, or no connection to the socket exists. 475 */ 476 public OutputStream getOutputStream() throws IOException { 477 synchronized(this) { 478 if (os == null) { 479 os = new SSLOutputStream(); 480 } 481 482 return os; 483 } 484 } 485 486 /** 487 * This method is not supported for this SSLSocket implementation. 488 */ 489 public void shutdownInput() throws IOException { 490 throw new UnsupportedOperationException( 491 "Method shutdownInput() is not supported."); 492 } 493 494 /** 495 * This method is not supported for this SSLSocket implementation. 496 */ 497 public void shutdownOutput() throws IOException { 498 throw new UnsupportedOperationException( 499 "Method shutdownOutput() is not supported."); 500 } 501 502 /** 503 * Reads with the native SSL_read function from the encrypted data stream 504 * @return -1 if error or the end of the stream is reached. 505 */ 506 private native int nativeread(int timeout) throws IOException; 507 private native int nativeread(byte[] b, int off, int len, int timeout) throws IOException; 508 509 /** 510 * This inner class provides input data stream functionality 511 * for the OpenSSL native implementation. It is used to 512 * read data received via SSL protocol. 513 */ 514 private class SSLInputStream extends InputStream { 515 SSLInputStream() throws IOException { 516 /** 517 /* Note: When startHandshake() throws an exception, no 518 * SSLInputStream object will be created. 519 */ 520 OpenSSLSocketImpl.this.startHandshake(); 521 } 522 523 /** 524 * Reads one byte. If there is no data in the underlying buffer, 525 * this operation can block until the data will be 526 * available. 527 * @return read value. 528 * @throws <code>IOException</code> 529 */ 530 public int read() throws IOException { 531 synchronized(readLock) { 532 return OpenSSLSocketImpl.this.nativeread(timeout); 533 } 534 } 535 536 /** 537 * Method acts as described in spec for superclass. 538 * @see java.io.InputStream#read(byte[],int,int) 539 */ 540 public int read(byte[] b, int off, int len) throws IOException { 541 synchronized(readLock) { 542 return OpenSSLSocketImpl.this.nativeread(b, off, len, timeout); 543 } 544 } 545 } 546 547 /** 548 * Writes with the native SSL_write function to the encrypted data stream. 549 */ 550 private native void nativewrite(int b) throws IOException; 551 private native void nativewrite(byte[] b, int off, int len) throws IOException; 552 553 /** 554 * This inner class provides output data stream functionality 555 * for the OpenSSL native implementation. It is used to 556 * write data according to the encryption parameters given in SSL context. 557 */ 558 private class SSLOutputStream extends OutputStream { 559 SSLOutputStream() throws IOException { 560 /** 561 /* Note: When startHandshake() throws an exception, no 562 * SSLInputStream object will be created. 563 */ 564 OpenSSLSocketImpl.this.startHandshake(); 565 } 566 567 /** 568 * Method acts as described in spec for superclass. 569 * @see java.io.OutputStream#write(int) 570 */ 571 public void write(int b) throws IOException { 572 synchronized(writeLock) { 573 OpenSSLSocketImpl.this.nativewrite(b); 574 } 575 } 576 577 /** 578 * Method acts as described in spec for superclass. 579 * @see java.io.OutputStream#write(byte[],int,int) 580 */ 581 public void write(byte[] b, int start, int len) throws IOException { 582 synchronized(writeLock) { 583 OpenSSLSocketImpl.this.nativewrite(b, start, len); 584 } 585 } 586 } 587 588 589 /** 590 * The SSL session used by this connection is returned. The SSL session 591 * determines which cipher suite should be used by all connections within 592 * that session and which identities have the session's client and server. 593 * This method starts the SSL handshake. 594 * @return the SSLSession. 595 * @throws <code>IOException</code> if the handshake fails 596 */ 597 public SSLSession getSession() { 598 try { 599 startHandshake(); 600 } catch (IOException e) { 601 Logger.getLogger(getClass().getName()).log(Level.WARNING, 602 "Error negotiating SSL connection.", e); 603 604 // return an invalid session with 605 // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL" 606 return SSLSessionImpl.NULL_SESSION; 607 } 608 return sslSession; 609 } 610 611 /** 612 * Registers a listener to be notified that a SSL handshake 613 * was successfully completed on this connection. 614 * @throws <code>IllegalArgumentException</code> if listener is null. 615 */ 616 public void addHandshakeCompletedListener( 617 HandshakeCompletedListener listener) { 618 if (listener == null) { 619 throw new IllegalArgumentException("Provided listener is null"); 620 } 621 if (listeners == null) { 622 listeners = new ArrayList(); 623 } 624 listeners.add(listener); 625 } 626 627 /** 628 * The method removes a registered listener. 629 * @throws IllegalArgumentException if listener is null or not registered 630 */ 631 public void removeHandshakeCompletedListener( 632 HandshakeCompletedListener listener) { 633 if (listener == null) { 634 throw new IllegalArgumentException("Provided listener is null"); 635 } 636 if (listeners == null) { 637 throw new IllegalArgumentException( 638 "Provided listener is not registered"); 639 } 640 if (!listeners.remove(listener)) { 641 throw new IllegalArgumentException( 642 "Provided listener is not registered"); 643 } 644 } 645 646 /** 647 * Returns true if new SSL sessions may be established by this socket. 648 * 649 * @return true if the session may be created; false if a session already 650 * exists and must be resumed. 651 */ 652 public boolean getEnableSessionCreation() { 653 return sslParameters.getEnableSessionCreation(); 654 } 655 656 /** 657 * Set a flag for the socket to inhibit or to allow the creation of a new 658 * SSL sessions. If the flag is set to false, and there are no actual 659 * sessions to resume, then there will be no successful handshaking. 660 * 661 * @param flag true if session may be created; false 662 * if a session already exists and must be resumed. 663 */ 664 public void setEnableSessionCreation(boolean flag) { 665 sslParameters.setEnableSessionCreation(flag); 666 } 667 668 /** 669 * Gets all available ciphers from the current OpenSSL library. 670 * Needed by OpenSSLSocketFactory too. 671 */ 672 static native String[] nativegetsupportedciphersuites(); 673 674 /** 675 * The names of the cipher suites which could be used by the SSL connection 676 * are returned. 677 * @return an array of cipher suite names 678 */ 679 public String[] getSupportedCipherSuites() { 680 return nativegetsupportedciphersuites(); 681 } 682 683 static native String[] nativeGetEnabledCipherSuites(int ssl_ctx); 684 685 /** 686 * The names of the cipher suites that are in use in the actual the SSL 687 * connection are returned. 688 * 689 * @return an array of cipher suite names 690 */ 691 public String[] getEnabledCipherSuites() { 692 return nativeGetEnabledCipherSuites(ssl_ctx); 693 } 694 695 /** 696 * Calls the SSL_CTX_set_cipher_list(...) OpenSSL function with the passed 697 * char array. 698 */ 699 static native void nativeSetEnabledCipherSuites(int ssl_ctx, String controlString); 700 701 private static boolean findSuite(String suite) { 702 String[] supportedCipherSuites = nativegetsupportedciphersuites(); 703 for(int i = 0; i < supportedCipherSuites.length; i++) { 704 if (supportedCipherSuites[i].equals(suite)) { 705 return true; 706 } 707 } 708 throw new IllegalArgumentException("Protocol " + suite + " is not supported."); 709 } 710 711 /** 712 * This method enables the cipher suites listed by 713 * getSupportedCipherSuites(). 714 * 715 * @param suites names of all the cipher suites to 716 * put on use 717 * @throws IllegalArgumentException when one or more of the 718 * ciphers in array suites are not supported, or when the array 719 * is null. 720 */ 721 public void setEnabledCipherSuites(String[] suites) { 722 setEnabledCipherSuites(ssl_ctx, suites); 723 } 724 725 static void setEnabledCipherSuites(int ssl_ctx, String[] suites) { 726 if (suites == null) { 727 throw new IllegalArgumentException("Provided parameter is null"); 728 } 729 String controlString = ""; 730 for (int i = 0; i < suites.length; i++) { 731 findSuite(suites[i]); 732 if (i == 0) controlString = suites[i]; 733 else controlString += ":" + suites[i]; 734 } 735 nativeSetEnabledCipherSuites(ssl_ctx, controlString); 736 } 737 738 /** 739 * The names of the protocols' versions that may be used on this SSL 740 * connection. 741 * @return an array of protocols names 742 */ 743 public String[] getSupportedProtocols() { 744 return supportedProtocols.clone(); 745 } 746 747 /** 748 * SSL mode of operation with or without back compatibility. See the OpenSSL 749 * ssl.h header file for more information. 750 */ 751 static private long SSL_OP_NO_SSLv3 = 0x02000000L; 752 static private long SSL_OP_NO_TLSv1 = 0x04000000L; 753 754 /** 755 * The names of the protocols' versions that are in use on this SSL 756 * connection. 757 * 758 * @return an array of protocols names 759 */ 760 @Override 761 public String[] getEnabledProtocols() { 762 ArrayList<String> array = new ArrayList<String>(); 763 764 if ((ssl_op_no & SSL_OP_NO_SSLv3) == 0x00000000L) { 765 array.add(supportedProtocols[1]); 766 } 767 if ((ssl_op_no & SSL_OP_NO_TLSv1) == 0x00000000L) { 768 array.add(supportedProtocols[2]); 769 } 770 return array.toArray(new String[array.size()]); 771 } 772 773 private native void nativesetenabledprotocols(long l); 774 775 /** 776 * This method enables the protocols' versions listed by 777 * getSupportedProtocols(). 778 * 779 * @param protocols The names of all the protocols to put on use 780 * 781 * @throws IllegalArgumentException when one or more of the names in the 782 * array are not supported, or when the array is null. 783 */ 784 @Override 785 public synchronized void setEnabledProtocols(String[] protocols) { 786 787 if (protocols == null) { 788 throw new IllegalArgumentException("Provided parameter is null"); 789 } 790 791 ssl_op_no = SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1; 792 793 for(int i = 0; i < protocols.length; i++) { 794 if (protocols[i].equals("SSLv3")) 795 ssl_op_no ^= SSL_OP_NO_SSLv3; 796 else if (protocols[i].equals("TLSv1")) 797 ssl_op_no ^= SSL_OP_NO_TLSv1; 798 else throw new IllegalArgumentException("Protocol " + protocols[i] + 799 " is not supported."); 800 } 801 802 nativesetenabledprotocols(ssl_op_no); 803 } 804 805 /** 806 * This method gives true back if the SSL socket is set to client mode. 807 * 808 * @return true if the socket should do the handshaking as client. 809 */ 810 public boolean getUseClientMode() { 811 return sslParameters.getUseClientMode(); 812 } 813 814 /** 815 * This method set the actual SSL socket to client mode. 816 * 817 * @param mode true if the socket starts in client 818 * mode 819 * @throws IllegalArgumentException if mode changes during 820 * handshake. 821 */ 822 public synchronized void setUseClientMode(boolean mode) { 823 if (handshakeStarted) { 824 throw new IllegalArgumentException( 825 "Could not change the mode after the initial handshake has begun."); 826 } 827 sslParameters.setUseClientMode(mode); 828 } 829 830 /** 831 * Returns true if the SSL socket requests client's authentication. Relevant 832 * only for server sockets! 833 * 834 * @return true if client authentication is desired, false if not. 835 */ 836 public boolean getWantClientAuth() { 837 return sslParameters.getWantClientAuth(); 838 } 839 840 /** 841 * Returns true if the SSL socket needs client's authentication. Relevant 842 * only for server sockets! 843 * 844 * @return true if client authentication is desired, false if not. 845 */ 846 public boolean getNeedClientAuth() { 847 return sslParameters.getNeedClientAuth(); 848 } 849 850 /** 851 * Sets the SSL socket to use client's authentication. Relevant only for 852 * server sockets! 853 * 854 * @param need true if client authentication is 855 * desired, false if not. 856 */ 857 public void setNeedClientAuth(boolean need) { 858 sslParameters.setNeedClientAuth(need); 859 } 860 861 /** 862 * Sets the SSL socket to use client's authentication. Relevant only for 863 * server sockets! Notice that in contrast to setNeedClientAuth(..) this 864 * method will continue the negotiation if the client decide not to send 865 * authentication credentials. 866 * 867 * @param want true if client authentication is 868 * desired, false if not. 869 */ 870 public void setWantClientAuth(boolean want) { 871 sslParameters.setWantClientAuth(want); 872 } 873 874 /** 875 * This method is not supported for SSLSocket implementation. 876 */ 877 public void sendUrgentData(int data) throws IOException { 878 throw new SocketException( 879 "Method sendUrgentData() is not supported."); 880 } 881 882 /** 883 * This method is not supported for SSLSocket implementation. 884 */ 885 public void setOOBInline(boolean on) throws SocketException { 886 throw new SocketException( 887 "Methods sendUrgentData, setOOBInline are not supported."); 888 } 889 890 /** 891 * Set the read timeout on this socket. The SO_TIMEOUT option, is specified 892 * in milliseconds. The read operation will block indefinitely for a zero 893 * value. 894 * 895 * @param timeout the read timeout value 896 * @throws SocketException if an error occurs setting the option 897 */ 898 public synchronized void setSoTimeout(int timeout) throws SocketException { 899 super.setSoTimeout(timeout); 900 this.timeout = timeout; 901 } 902 903 // BEGIN android-added 904 /** 905 * Set the handshake timeout on this socket. This timeout is specified in 906 * milliseconds and will be used only during the handshake process. 907 * 908 * @param timeout the handshake timeout value 909 */ 910 public synchronized void setHandshakeTimeout(int timeout) throws SocketException { 911 this.handshakeTimeout = timeout; 912 } 913 // END android-added 914 915 private native void nativeinterrupt() throws IOException; 916 private native void nativeclose() throws IOException; 917 918 /** 919 * Closes the SSL socket. Once closed, a socket is not available for further 920 * use anymore under any circumstance. A new socket must be created. 921 * 922 * @throws <code>IOException</code> if an I/O error happens during the 923 * socket's closure. 924 */ 925 public void close() throws IOException { 926 // TODO: Close SSL sockets using a background thread so they close 927 // gracefully. 928 929 synchronized (handshakeLock) { 930 if (!handshakeStarted) { 931 handshakeStarted = true; 932 933 synchronized (this) { 934 nativefree(); 935 936 if (socket != null) { 937 if (autoClose && !socket.isClosed()) socket.close(); 938 } else { 939 if (!super.isClosed()) super.close(); 940 } 941 } 942 943 return; 944 } 945 } 946 947 nativeinterrupt(); 948 949 synchronized (this) { 950 synchronized (writeLock) { 951 synchronized (readLock) { 952 953 IOException pendingException = null; 954 955 // Shut down the SSL connection, per se. 956 try { 957 if (handshakeStarted) { 958 nativeclose(); 959 } 960 } catch (IOException ex) { 961 /* 962 * Note the exception at this point, but try to continue 963 * to clean the rest of this all up before rethrowing. 964 */ 965 pendingException = ex; 966 } 967 968 /* 969 * Even if the above call failed, it is still safe to free 970 * the native structs, and we need to do so lest we leak 971 * memory. 972 */ 973 nativefree(); 974 975 if (socket != null) { 976 if (autoClose && !socket.isClosed()) 977 socket.close(); 978 } else { 979 if (!super.isClosed()) 980 super.close(); 981 } 982 983 if (pendingException != null) { 984 throw pendingException; 985 } 986 } 987 } 988 } 989 } 990 991 private native void nativefree(); 992 993 protected void finalize() throws IOException { 994 /* 995 * Just worry about our own state. Notably we do not try and 996 * close anything. The SocketImpl, either our own 997 * PlainSocketImpl, or the Socket we are wrapping, will do 998 * that. This might mean we do not properly SSL_shutdown, but 999 * if you want to do that, properly close the socket yourself. 1000 * 1001 * The reason why we don't try to SSL_shutdown is that there 1002 * can be a race between finalizers where the PlainSocketImpl 1003 * finalizer runs first and closes the socket. However, in the 1004 * meanwhile, the underlying file descriptor could be reused 1005 * for another purpose. If we call SSL_shutdown after that, the 1006 * underlying socket BIOs still have the older file descriptor 1007 * and will write the close notify to some unsuspecting 1008 * reader. 1009 */ 1010 updateInstanceCount(-1); 1011 if (ssl == 0) { 1012 return; 1013 } 1014 nativefree(); 1015 } 1016 1017 /** 1018 * Verifies an RSA signature. Conceptually, this method doesn't really 1019 * belong here, but due to its native code being closely tied to OpenSSL 1020 * (just like the rest of this class), we put it here for the time being. 1021 * This also solves potential problems with native library initialization. 1022 * 1023 * @param message The message to verify 1024 * @param signature The signature to verify 1025 * @param algorithm The hash/sign algorithm to use, i.e. "RSA-SHA1" 1026 * @param key The RSA public key to use 1027 * @return true if the verification succeeds, false otherwise 1028 */ 1029 public static boolean verifySignature(byte[] message, byte[] signature, String algorithm, RSAPublicKey key) { 1030 byte[] modulus = key.getModulus().toByteArray(); 1031 byte[] exponent = key.getPublicExponent().toByteArray(); 1032 1033 return nativeverifysignature(message, signature, algorithm, modulus, exponent) == 1; 1034 } 1035 1036 private static native int nativeverifysignature(byte[] message, byte[] signature, 1037 String algorithm, byte[] modulus, byte[] exponent); 1038 } 1039