OpenSSLSocketImpl.java revision 059dbc04218144f985b20a228bbe98139d400d0c
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 17package org.apache.harmony.xnet.provider.jsse; 18 19import java.io.IOException; 20import java.io.InputStream; 21import java.io.OutputStream; 22import java.net.InetAddress; 23import java.net.Socket; 24import java.net.SocketException; 25import java.security.PrivateKey; 26import java.security.SecureRandom; 27import java.security.cert.CertificateEncodingException; 28import java.security.cert.CertificateException; 29import java.security.cert.X509Certificate; 30import java.util.ArrayList; 31import java.util.concurrent.atomic.AtomicInteger; 32import java.util.logging.Logger; 33import javax.net.ssl.HandshakeCompletedEvent; 34import javax.net.ssl.HandshakeCompletedListener; 35import javax.net.ssl.SSLException; 36import javax.net.ssl.SSLPeerUnverifiedException; 37import javax.net.ssl.SSLSession; 38import javax.security.auth.x500.X500Principal; 39import org.apache.harmony.security.provider.cert.X509CertImpl; 40 41/** 42 * Implementation of the class OpenSSLSocketImpl 43 * based on OpenSSL. 44 * 45 * This class only supports SSLv3 and TLSv1. This should be documented elsewhere 46 * later, for example in the package.html or a separate reference document. 47 */ 48public class OpenSSLSocketImpl 49 extends javax.net.ssl.SSLSocket 50 implements NativeCrypto.SSLHandshakeCallbacks { 51 private int sslNativePointer; 52 private InputStream is; 53 private OutputStream os; 54 private final Object handshakeLock = new Object(); 55 private final Object readLock = new Object(); 56 private final Object writeLock = new Object(); 57 private SSLParameters sslParameters; 58 private String[] enabledProtocols; 59 private String[] enabledCipherSuites; 60 private OpenSSLSessionImpl sslSession; 61 private Socket socket; 62 private boolean autoClose; 63 private boolean handshakeStarted = false; 64 65 /** 66 * Not set to true until the update from native that tells us the 67 * full handshake is complete, since SSL_do_handshake can return 68 * before the handshake is completely done due to 69 * handshake_cutthrough support. 70 */ 71 private boolean handshakeCompleted = false; 72 73 private ArrayList<HandshakeCompletedListener> listeners; 74 private int timeout = 0; 75 // BEGIN android-added 76 private int handshakeTimeout = -1; // -1 = same as timeout; 0 = infinite 77 // END android-added 78 private String wrappedHost; 79 private int wrappedPort; 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 * Class constructor with 1 parameter 93 * 94 * @param sslParameters Parameters for the SSL 95 * context 96 * @throws IOException if network fails 97 */ 98 protected OpenSSLSocketImpl(SSLParameters sslParameters) throws IOException { 99 super(); 100 init(sslParameters); 101 } 102 103 /** 104 * Create an OpenSSLSocketImpl from an OpenSSLServerSocketImpl 105 * 106 * @param sslParameters Parameters for the SSL 107 * context 108 * @throws IOException if network fails 109 */ 110 protected OpenSSLSocketImpl(SSLParameters sslParameters, 111 String[] enabledProtocols, 112 String[] enabledCipherSuites) throws IOException { 113 super(); 114 init(sslParameters, enabledProtocols, enabledCipherSuites); 115 } 116 117 /** 118 * Class constructor with 3 parameters 119 * 120 * @throws IOException if network fails 121 * @throws java.net.UnknownHostException host not defined 122 */ 123 protected OpenSSLSocketImpl(String host, int port, SSLParameters sslParameters) 124 throws IOException { 125 super(host, port); 126 init(sslParameters); 127 } 128 129 /** 130 * Class constructor with 3 parameters: 1st is InetAddress 131 * 132 * @throws IOException if network fails 133 * @throws java.net.UnknownHostException host not defined 134 */ 135 protected OpenSSLSocketImpl(InetAddress address, int port, SSLParameters sslParameters) 136 throws IOException { 137 super(address, port); 138 init(sslParameters); 139 } 140 141 142 /** 143 * Class constructor with 5 parameters: 1st is host 144 * 145 * @throws IOException if network fails 146 * @throws java.net.UnknownHostException host not defined 147 */ 148 protected OpenSSLSocketImpl(String host, int port, 149 InetAddress clientAddress, int clientPort, 150 SSLParameters sslParameters) 151 throws IOException { 152 super(host, port, clientAddress, clientPort); 153 init(sslParameters); 154 } 155 156 /** 157 * Class constructor with 5 parameters: 1st is InetAddress 158 * 159 * @throws IOException if network fails 160 * @throws java.net.UnknownHostException host not defined 161 */ 162 protected OpenSSLSocketImpl(InetAddress address, int port, 163 InetAddress clientAddress, int clientPort, 164 SSLParameters sslParameters) 165 throws IOException { 166 super(address, port, clientAddress, clientPort); 167 init(sslParameters); 168 } 169 170 /** 171 * Constructor with 5 parameters: 1st is socket. Enhances an existing socket 172 * with SSL functionality. Invoked via OpenSSLSocketImplWrapper constructor. 173 * 174 * @throws IOException if network fails 175 */ 176 protected OpenSSLSocketImpl(Socket socket, String host, int port, 177 boolean autoClose, SSLParameters sslParameters) throws IOException { 178 super(); 179 this.socket = socket; 180 this.timeout = socket.getSoTimeout(); 181 this.wrappedHost = host; 182 this.wrappedPort = port; 183 this.autoClose = autoClose; 184 init(sslParameters); 185 } 186 187 /** 188 * Initialize the SSL socket and set the certificates for the 189 * future handshaking. 190 */ 191 private void init(SSLParameters sslParameters) throws IOException { 192 init(sslParameters, 193 NativeCrypto.getSupportedProtocols(), 194 NativeCrypto.getDefaultCipherSuites()); 195 } 196 197 /** 198 * Initialize the SSL socket and set the certificates for the 199 * future handshaking. 200 */ 201 private void init(SSLParameters sslParameters, 202 String[] enabledProtocols, 203 String[] enabledCipherSuites) throws IOException { 204 this.sslParameters = sslParameters; 205 this.enabledProtocols = enabledProtocols; 206 this.enabledCipherSuites = enabledCipherSuites; 207 updateInstanceCount(1); 208 } 209 210 /** 211 * Gets the suitable session reference from the session cache container. 212 * 213 * @return OpenSSLSessionImpl 214 */ 215 private OpenSSLSessionImpl getCachedClientSession(ClientSessionContext sessionContext) { 216 if (super.getInetAddress() == null || 217 super.getInetAddress().getHostAddress() == null || 218 super.getInetAddress().getHostName() == null) { 219 return null; 220 } 221 OpenSSLSessionImpl session = (OpenSSLSessionImpl) sessionContext.getSession( 222 super.getInetAddress().getHostName(), 223 super.getPort()); 224 if (session == null) { 225 return null; 226 } 227 228 String protocol = session.getProtocol(); 229 boolean protocolFound = false; 230 for (String enabledProtocol : enabledProtocols) { 231 if (protocol.equals(enabledProtocol)) { 232 protocolFound = true; 233 break; 234 } 235 } 236 if (!protocolFound) { 237 return null; 238 } 239 240 String cipherSuite = session.getCipherSuite(); 241 boolean cipherSuiteFound = false; 242 for (String enabledCipherSuite : enabledCipherSuites) { 243 if (cipherSuite.equals(enabledCipherSuite)) { 244 cipherSuiteFound = true; 245 break; 246 } 247 } 248 if (!cipherSuiteFound) { 249 return null; 250 } 251 252 return session; 253 } 254 255 /** 256 * Ensures that logger is lazily loaded. The outer class seems to load 257 * before logging is ready. 258 */ 259 static class LoggerHolder { 260 static final Logger logger = Logger.getLogger(OpenSSLSocketImpl.class.getName()); 261 } 262 263 /** 264 * Starts a TLS/SSL handshake on this connection using some native methods 265 * from the OpenSSL library. It can negotiate new encryption keys, change 266 * cipher suites, or initiate a new session. The certificate chain is 267 * verified if the correspondent property in java.Security is set. All 268 * listeners are notified at the end of the TLS/SSL handshake. 269 * 270 * @throws <code>IOException</code> if network fails 271 */ 272 public void startHandshake() throws IOException { 273 startHandshake(true); 274 } 275 276 /** 277 * Perform the handshake 278 * @param full If true, disable handshake cutthrough for a fully synchronous handshake 279 */ 280 public synchronized void startHandshake(boolean full) throws IOException { 281 synchronized (handshakeLock) { 282 if (!handshakeStarted) { 283 handshakeStarted = true; 284 } else { 285 return; 286 } 287 } 288 289 // note that this modifies the global seed, not something specific to the connection 290 final int seedLengthInBytes = NativeCrypto.RAND_SEED_LENGTH_IN_BYTES; 291 final SecureRandom secureRandom = sslParameters.getSecureRandomMember(); 292 if (secureRandom == null) { 293 NativeCrypto.RAND_load_file("/dev/urandom", seedLengthInBytes); 294 } else { 295 NativeCrypto.RAND_seed(secureRandom.generateSeed(seedLengthInBytes)); 296 } 297 298 final boolean client = sslParameters.getUseClientMode(); 299 300 final int sslCtxNativePointer = (client) ? 301 sslParameters.getClientSessionContext().sslCtxNativePointer : 302 sslParameters.getServerSessionContext().sslCtxNativePointer; 303 304 this.sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer); 305 306 // setup server certificates and private keys. 307 // clients will receive a call back to request certificates. 308 if (!client) { 309 for (String keyType : NativeCrypto.KEY_TYPES) { 310 setCertificate(sslParameters.getKeyManager().chooseServerAlias(keyType, 311 null, 312 this)); 313 } 314 } 315 316 NativeCrypto.setEnabledProtocols(sslNativePointer, enabledProtocols); 317 NativeCrypto.setEnabledCipherSuites(sslNativePointer, enabledCipherSuites); 318 319 boolean enableSessionCreation = sslParameters.getEnableSessionCreation(); 320 if (!enableSessionCreation) { 321 NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer, 322 enableSessionCreation); 323 } 324 325 AbstractSessionContext sessionContext; 326 OpenSSLSessionImpl session; 327 if (client) { 328 // look for client session to reuse 329 ClientSessionContext clientSessionContext = sslParameters.getClientSessionContext(); 330 sessionContext = clientSessionContext; 331 session = getCachedClientSession(clientSessionContext); 332 if (session != null) { 333 NativeCrypto.SSL_set_session(sslNativePointer, session.sslSessionNativePointer); 334 } 335 } else { 336 sessionContext = sslParameters.getServerSessionContext(); 337 session = null; 338 } 339 340 // setup peer certificate verification 341 if (client) { 342 // TODO support for anonymous cipher would require us to 343 // conditionally use SSL_VERIFY_NONE 344 } else { 345 // needing client auth takes priority... 346 if (sslParameters.getNeedClientAuth()) { 347 NativeCrypto.SSL_set_verify(sslNativePointer, 348 NativeCrypto.SSL_VERIFY_PEER| 349 NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT| 350 NativeCrypto.SSL_VERIFY_CLIENT_ONCE); 351 // ... over just wanting it... 352 } else if (sslParameters.getWantClientAuth()) { 353 NativeCrypto.SSL_set_verify(sslNativePointer, 354 NativeCrypto.SSL_VERIFY_PEER| 355 NativeCrypto.SSL_VERIFY_CLIENT_ONCE); 356 } 357 // ... and it defaults properly so we don't need call SSL_set_verify in the common case. 358 359 // TODO Need to call SSL_CTX_set_client_CA_list to notify trusted issuers to client 360 // 361 // From SSL_CTX_load_verify_locations(3SSL) 362 // In server mode, when requesting a client 363 // certificate, the server must send the list of CAs 364 // of which it will accept client certificates. This 365 // list is not influenced by the contents of CAfile or 366 // CApath and must explicitly be set using the 367 // SSL_CTX_set_client_CA_list(3) family of functions. 368 // 369 // We can get the list from sslParameters.getTrustManager().getAcceptedIssuers() 370 } 371 372 if (client && full) { 373 // we want to do a full synchronous handshake, so turn off cutthrough 374 NativeCrypto.SSL_clear_mode(sslNativePointer, 375 NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH); 376 } 377 378 // BEGIN android-added 379 // Temporarily use a different timeout for the handshake process 380 int savedTimeout = timeout; 381 if (handshakeTimeout >= 0) { 382 setSoTimeout(handshakeTimeout); 383 } 384 // END android-added 385 386 387 Socket socket = this.socket != null ? this.socket : this; 388 int sslSessionNativePointer; 389 try { 390 sslSessionNativePointer 391 = NativeCrypto.SSL_do_handshake(sslNativePointer, socket, this, timeout, client); 392 } catch (CertificateException e) { 393 throw new SSLPeerUnverifiedException(e.getMessage()); 394 } 395 byte[] sessionId = NativeCrypto.SSL_SESSION_session_id(sslSessionNativePointer); 396 sslSession = (OpenSSLSessionImpl) sessionContext.getSession(sessionId); 397 if (sslSession != null) { 398 sslSession.lastAccessedTime = System.currentTimeMillis(); 399 LoggerHolder.logger.fine("Reused cached session for " 400 + getInetAddress() + "."); 401 NativeCrypto.SSL_SESSION_free(sslSessionNativePointer); 402 } else { 403 if (!enableSessionCreation) { 404 // Should have been prevented by NativeCrypto.SSL_set_session_creation_enabled 405 throw new IllegalStateException("SSL Session may not be created"); 406 } 407 byte[][] localCertificatesBytes = NativeCrypto.SSL_get_certificate(sslNativePointer); 408 X509Certificate[] localCertificates; 409 if (localCertificatesBytes == null) { 410 localCertificates = null; 411 } else { 412 localCertificates = new X509Certificate[localCertificatesBytes.length]; 413 for (int i = 0; i < localCertificatesBytes.length; i++) { 414 localCertificates[i] = new X509CertImpl(localCertificatesBytes[i]); 415 } 416 } 417 418 if (wrappedHost == null) { 419 sslSession = new OpenSSLSessionImpl(sslSessionNativePointer, localCertificates, 420 super.getInetAddress().getHostName(), 421 super.getPort(), sessionContext); 422 } else { 423 sslSession = new OpenSSLSessionImpl(sslSessionNativePointer, localCertificates, 424 wrappedHost, wrappedPort, 425 sessionContext); 426 } 427 // if not, putSession later in handshakeCompleted() callback 428 if (handshakeCompleted) { 429 sessionContext.putSession(sslSession); 430 } 431 LoggerHolder.logger.fine("Created new session for " 432 + getInetAddress().getHostName() + "."); 433 } 434 435 // BEGIN android-added 436 // Restore the original timeout now that the handshake is complete 437 if (handshakeTimeout >= 0) { 438 setSoTimeout(savedTimeout); 439 } 440 // END android-added 441 442 // if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback 443 if (handshakeCompleted) { 444 notifyHandshakeCompletedListeners(); 445 } 446 447 } 448 449 private void setCertificate(String alias) throws IOException { 450 if (alias == null) { 451 return; 452 } 453 454 PrivateKey privateKey = sslParameters.getKeyManager().getPrivateKey(alias); 455 byte[] privateKeyBytes = privateKey.getEncoded(); 456 NativeCrypto.SSL_use_PrivateKey(sslNativePointer, privateKeyBytes); 457 458 X509Certificate[] certificates = sslParameters.getKeyManager().getCertificateChain(alias); 459 byte[][] certificateBytes = new byte[certificates.length][]; 460 for (int i = 0; i < certificates.length; i++) { 461 try { 462 certificateBytes[i] = certificates[i].getEncoded(); 463 } catch (CertificateEncodingException e) { 464 throw new IOException("Problem encoding certificate " + certificates[i], e); 465 } 466 } 467 NativeCrypto.SSL_use_certificate(sslNativePointer, certificateBytes); 468 469 // checks the last installed private key and certificate, 470 // so need to do this once per loop iteration 471 NativeCrypto.SSL_check_private_key(sslNativePointer); 472 } 473 474 /** 475 * Implementation of NativeCrypto.SSLHandshakeCallbacks 476 * invoked via JNI from client_cert_cb 477 */ 478 public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) 479 throws IOException { 480 481 String[] keyTypes = new String[keyTypeBytes.length]; 482 for (int i = 0; i < keyTypeBytes.length; i++) { 483 keyTypes[i] = NativeCrypto.keyType(keyTypeBytes[i]); 484 } 485 486 X500Principal[] issuers; 487 if (asn1DerEncodedPrincipals == null) { 488 issuers = null; 489 } else { 490 issuers = new X500Principal[asn1DerEncodedPrincipals.length]; 491 for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) { 492 issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]); 493 } 494 } 495 496 setCertificate(sslParameters.getKeyManager().chooseClientAlias(keyTypes, issuers, this)); 497 } 498 499 /** 500 * Implementation of NativeCrypto.SSLHandshakeCallbacks 501 * invoked via JNI from info_callback 502 */ 503 public void handshakeCompleted() { 504 handshakeCompleted = true; 505 506 // If sslSession is null, the handshake was completed during 507 // the call to NativeCrypto.SSL_do_handshake and not during a 508 // later read operation. That means we do not need to fixup 509 // the SSLSession and session cache or notify 510 // HandshakeCompletedListeners, it will be done in 511 // startHandshake. 512 if (sslSession == null) { 513 return; 514 } 515 516 // reset session id from the native pointer and update the 517 // appropriate cache. 518 sslSession.resetId(); 519 AbstractSessionContext sessionContext = 520 (sslParameters.getUseClientMode()) 521 ? sslParameters.getClientSessionContext() 522 : sslParameters.getServerSessionContext(); 523 sessionContext.putSession(sslSession); 524 525 // let listeners know we are finally done 526 notifyHandshakeCompletedListeners(); 527 } 528 529 private void notifyHandshakeCompletedListeners() { 530 if (listeners != null && !listeners.isEmpty()) { 531 // notify the listeners 532 HandshakeCompletedEvent event = 533 new HandshakeCompletedEvent(this, sslSession); 534 for (HandshakeCompletedListener listener : listeners) { 535 try { 536 listener.handshakeCompleted(event); 537 } catch (RuntimeException e) { 538 // The RI runs the handlers in a separate thread, 539 // which we do not. But we try to preserve their 540 // behavior of logging a problem and not killing 541 // the handshaking thread just because a listener 542 // has a problem. 543 Thread thread = Thread.currentThread(); 544 thread.getUncaughtExceptionHandler().uncaughtException(thread, e); 545 } 546 } 547 } 548 } 549 550 /** 551 * Implementation of NativeCrypto.SSLHandshakeCallbacks 552 * 553 * @param bytes An array of ASN.1 DER encoded certficates 554 * @param authMethod auth algorithm name 555 * 556 * @throws CertificateException if the certificate is untrusted 557 */ 558 @SuppressWarnings("unused") 559 public void verifyCertificateChain(byte[][] bytes, String authMethod) 560 throws CertificateException { 561 try { 562 if (bytes == null || bytes.length == 0) { 563 throw new SSLException("Peer sent no certificate"); 564 } 565 X509Certificate[] peerCertificateChain = new X509Certificate[bytes.length]; 566 for (int i = 0; i < bytes.length; i++) { 567 peerCertificateChain[i] = 568 new X509CertImpl( 569 javax.security.cert.X509Certificate.getInstance(bytes[i]).getEncoded()); 570 } 571 boolean client = sslParameters.getUseClientMode(); 572 if (client) { 573 sslParameters.getTrustManager().checkServerTrusted(peerCertificateChain, 574 authMethod); 575 } else { 576 sslParameters.getTrustManager().checkClientTrusted(peerCertificateChain, 577 authMethod); 578 } 579 580 } catch (CertificateException e) { 581 throw e; 582 } catch (Exception e) { 583 throw new RuntimeException(e); 584 } 585 } 586 587 /** 588 * Returns an input stream for this SSL socket using native calls to the 589 * OpenSSL library. 590 * 591 * @return: an input stream for reading bytes from this socket. 592 * @throws: <code>IOException</code> if an I/O error occurs when creating 593 * the input stream, the socket is closed, the socket is not 594 * connected, or the socket input has been shutdown. 595 */ 596 public InputStream getInputStream() throws IOException { 597 synchronized(this) { 598 if (is == null) { 599 is = new SSLInputStream(); 600 } 601 602 return is; 603 } 604 } 605 606 /** 607 * Returns an output stream for this SSL socket using native calls to the 608 * OpenSSL library. 609 * 610 * @return an output stream for writing bytes to this socket. 611 * @throws <code>IOException</code> if an I/O error occurs when creating 612 * the output stream, or no connection to the socket exists. 613 */ 614 public OutputStream getOutputStream() throws IOException { 615 synchronized(this) { 616 if (os == null) { 617 os = new SSLOutputStream(); 618 } 619 620 return os; 621 } 622 } 623 624 /** 625 * This method is not supported for this SSLSocket implementation 626 * because reading from an SSLSocket may involve writing to the 627 * network. 628 */ 629 public void shutdownInput() throws IOException { 630 throw new UnsupportedOperationException(); 631 } 632 633 /** 634 * This method is not supported for this SSLSocket implementation 635 * because writing to an SSLSocket may involve reading from the 636 * network. 637 */ 638 public void shutdownOutput() throws IOException { 639 throw new UnsupportedOperationException(); 640 } 641 642 /** 643 * This inner class provides input data stream functionality 644 * for the OpenSSL native implementation. It is used to 645 * read data received via SSL protocol. 646 */ 647 private class SSLInputStream extends InputStream { 648 SSLInputStream() throws IOException { 649 /** 650 /* Note: When startHandshake() throws an exception, no 651 * SSLInputStream object will be created. 652 */ 653 OpenSSLSocketImpl.this.startHandshake(false); 654 } 655 656 /** 657 * Reads one byte. If there is no data in the underlying buffer, 658 * this operation can block until the data will be 659 * available. 660 * @return read value. 661 * @throws <code>IOException</code> 662 */ 663 public int read() throws IOException { 664 synchronized(readLock) { 665 return NativeCrypto.SSL_read_byte(sslNativePointer, timeout); 666 } 667 } 668 669 /** 670 * Method acts as described in spec for superclass. 671 * @see java.io.InputStream#read(byte[],int,int) 672 */ 673 public int read(byte[] b, int off, int len) throws IOException { 674 synchronized(readLock) { 675 return NativeCrypto.SSL_read(sslNativePointer, b, off, len, timeout); 676 } 677 } 678 } 679 680 /** 681 * This inner class provides output data stream functionality 682 * for the OpenSSL native implementation. It is used to 683 * write data according to the encryption parameters given in SSL context. 684 */ 685 private class SSLOutputStream extends OutputStream { 686 SSLOutputStream() throws IOException { 687 /** 688 /* Note: When startHandshake() throws an exception, no 689 * SSLOutputStream object will be created. 690 */ 691 OpenSSLSocketImpl.this.startHandshake(false); 692 } 693 694 /** 695 * Method acts as described in spec for superclass. 696 * @see java.io.OutputStream#write(int) 697 */ 698 public void write(int b) throws IOException { 699 synchronized(writeLock) { 700 NativeCrypto.SSL_write_byte(sslNativePointer, b); 701 } 702 } 703 704 /** 705 * Method acts as described in spec for superclass. 706 * @see java.io.OutputStream#write(byte[],int,int) 707 */ 708 public void write(byte[] b, int start, int len) throws IOException { 709 synchronized(writeLock) { 710 NativeCrypto.SSL_write(sslNativePointer, b, start, len); 711 } 712 } 713 } 714 715 716 /** 717 * The SSL session used by this connection is returned. The SSL session 718 * determines which cipher suite should be used by all connections within 719 * that session and which identities have the session's client and server. 720 * This method starts the SSL handshake. 721 * @return the SSLSession. 722 * @throws <code>IOException</code> if the handshake fails 723 */ 724 public SSLSession getSession() { 725 try { 726 startHandshake(true); 727 } catch (IOException e) { 728 // return an invalid session with 729 // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL" 730 return SSLSessionImpl.NULL_SESSION; 731 } 732 return sslSession; 733 } 734 735 /** 736 * Registers a listener to be notified that a SSL handshake 737 * was successfully completed on this connection. 738 * @throws <code>IllegalArgumentException</code> if listener is null. 739 */ 740 public void addHandshakeCompletedListener( 741 HandshakeCompletedListener listener) { 742 if (listener == null) { 743 throw new IllegalArgumentException("Provided listener is null"); 744 } 745 if (listeners == null) { 746 listeners = new ArrayList(); 747 } 748 listeners.add(listener); 749 } 750 751 /** 752 * The method removes a registered listener. 753 * @throws IllegalArgumentException if listener is null or not registered 754 */ 755 public void removeHandshakeCompletedListener( 756 HandshakeCompletedListener listener) { 757 if (listener == null) { 758 throw new IllegalArgumentException("Provided listener is null"); 759 } 760 if (listeners == null) { 761 throw new IllegalArgumentException( 762 "Provided listener is not registered"); 763 } 764 if (!listeners.remove(listener)) { 765 throw new IllegalArgumentException( 766 "Provided listener is not registered"); 767 } 768 } 769 770 /** 771 * Returns true if new SSL sessions may be established by this socket. 772 * 773 * @return true if the session may be created; false if a session already 774 * exists and must be resumed. 775 */ 776 public boolean getEnableSessionCreation() { 777 return sslParameters.getEnableSessionCreation(); 778 } 779 780 /** 781 * Set a flag for the socket to inhibit or to allow the creation of a new 782 * SSL sessions. If the flag is set to false, and there are no actual 783 * sessions to resume, then there will be no successful handshaking. 784 * 785 * @param flag true if session may be created; false 786 * if a session already exists and must be resumed. 787 */ 788 public void setEnableSessionCreation(boolean flag) { 789 sslParameters.setEnableSessionCreation(flag); 790 } 791 792 /** 793 * The names of the cipher suites which could be used by the SSL connection 794 * are returned. 795 * @return an array of cipher suite names 796 */ 797 public String[] getSupportedCipherSuites() { 798 return NativeCrypto.getSupportedCipherSuites(); 799 } 800 801 /** 802 * The names of the cipher suites that are in use in the actual the SSL 803 * connection are returned. 804 * 805 * @return an array of cipher suite names 806 */ 807 public String[] getEnabledCipherSuites() { 808 return enabledCipherSuites.clone(); 809 } 810 811 /** 812 * This method enables the cipher suites listed by 813 * getSupportedCipherSuites(). 814 * 815 * @param suites names of all the cipher suites to 816 * put on use 817 * @throws IllegalArgumentException when one or more of the 818 * ciphers in array suites are not supported, or when the array 819 * is null. 820 */ 821 public void setEnabledCipherSuites(String[] suites) { 822 enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(suites); 823 } 824 825 /** 826 * The names of the protocols' versions that may be used on this SSL 827 * connection. 828 * @return an array of protocols names 829 */ 830 public String[] getSupportedProtocols() { 831 return NativeCrypto.getSupportedProtocols(); 832 } 833 834 /** 835 * The names of the protocols' versions that are in use on this SSL 836 * connection. 837 * 838 * @return an array of protocols names 839 */ 840 @Override 841 public String[] getEnabledProtocols() { 842 return enabledProtocols.clone(); 843 } 844 845 /** 846 * This method enables the protocols' versions listed by 847 * getSupportedProtocols(). 848 * 849 * @param protocols The names of all the protocols to put on use 850 * 851 * @throws IllegalArgumentException when one or more of the names in the 852 * array are not supported, or when the array is null. 853 */ 854 @Override 855 public synchronized void setEnabledProtocols(String[] protocols) { 856 enabledProtocols = NativeCrypto.checkEnabledProtocols(protocols); 857 } 858 859 /** 860 * This method gives true back if the SSL socket is set to client mode. 861 * 862 * @return true if the socket should do the handshaking as client. 863 */ 864 public boolean getUseClientMode() { 865 return sslParameters.getUseClientMode(); 866 } 867 868 /** 869 * This method set the actual SSL socket to client mode. 870 * 871 * @param mode true if the socket starts in client 872 * mode 873 * @throws IllegalArgumentException if mode changes during 874 * handshake. 875 */ 876 public synchronized void setUseClientMode(boolean mode) { 877 if (handshakeStarted) { 878 throw new IllegalArgumentException( 879 "Could not change the mode after the initial handshake has begun."); 880 } 881 sslParameters.setUseClientMode(mode); 882 } 883 884 /** 885 * Returns true if the SSL socket requests client's authentication. Relevant 886 * only for server sockets! 887 * 888 * @return true if client authentication is desired, false if not. 889 */ 890 public boolean getWantClientAuth() { 891 return sslParameters.getWantClientAuth(); 892 } 893 894 /** 895 * Returns true if the SSL socket needs client's authentication. Relevant 896 * only for server sockets! 897 * 898 * @return true if client authentication is desired, false if not. 899 */ 900 public boolean getNeedClientAuth() { 901 return sslParameters.getNeedClientAuth(); 902 } 903 904 /** 905 * Sets the SSL socket to use client's authentication. Relevant only for 906 * server sockets! 907 * 908 * @param need true if client authentication is 909 * desired, false if not. 910 */ 911 public void setNeedClientAuth(boolean need) { 912 sslParameters.setNeedClientAuth(need); 913 } 914 915 /** 916 * Sets the SSL socket to use client's authentication. Relevant only for 917 * server sockets! Notice that in contrast to setNeedClientAuth(..) this 918 * method will continue the negotiation if the client decide not to send 919 * authentication credentials. 920 * 921 * @param want true if client authentication is 922 * desired, false if not. 923 */ 924 public void setWantClientAuth(boolean want) { 925 sslParameters.setWantClientAuth(want); 926 } 927 928 /** 929 * This method is not supported for SSLSocket implementation. 930 */ 931 public void sendUrgentData(int data) throws IOException { 932 throw new SocketException( 933 "Method sendUrgentData() is not supported."); 934 } 935 936 /** 937 * This method is not supported for SSLSocket implementation. 938 */ 939 public void setOOBInline(boolean on) throws SocketException { 940 throw new SocketException( 941 "Methods sendUrgentData, setOOBInline are not supported."); 942 } 943 944 /** 945 * Set the read timeout on this socket. The SO_TIMEOUT option, is specified 946 * in milliseconds. The read operation will block indefinitely for a zero 947 * value. 948 * 949 * @param timeout the read timeout value 950 * @throws SocketException if an error occurs setting the option 951 */ 952 public synchronized void setSoTimeout(int timeout) throws SocketException { 953 super.setSoTimeout(timeout); 954 this.timeout = timeout; 955 } 956 957 // BEGIN android-added 958 /** 959 * Set the handshake timeout on this socket. This timeout is specified in 960 * milliseconds and will be used only during the handshake process. 961 * 962 * @param timeout the handshake timeout value 963 */ 964 public synchronized void setHandshakeTimeout(int timeout) throws SocketException { 965 this.handshakeTimeout = timeout; 966 } 967 // END android-added 968 969 /** 970 * Closes the SSL socket. Once closed, a socket is not available for further 971 * use anymore under any circumstance. A new socket must be created. 972 * 973 * @throws <code>IOException</code> if an I/O error happens during the 974 * socket's closure. 975 */ 976 public void close() throws IOException { 977 // TODO: Close SSL sockets using a background thread so they close 978 // gracefully. 979 980 synchronized (handshakeLock) { 981 if (!handshakeStarted) { 982 // prevent further attemps to start handshake 983 handshakeStarted = true; 984 985 synchronized (this) { 986 free(); 987 988 if (socket != null) { 989 if (autoClose && !socket.isClosed()) socket.close(); 990 } else { 991 if (!super.isClosed()) super.close(); 992 } 993 } 994 995 return; 996 } 997 } 998 999 NativeCrypto.SSL_interrupt(sslNativePointer); 1000 1001 synchronized (this) { 1002 synchronized (writeLock) { 1003 synchronized (readLock) { 1004 1005 IOException pendingException = null; 1006 1007 // Shut down the SSL connection, per se. 1008 try { 1009 if (handshakeStarted) { 1010 NativeCrypto.SSL_shutdown(sslNativePointer); 1011 } 1012 } catch (IOException ex) { 1013 /* 1014 * Note the exception at this point, but try to continue 1015 * to clean the rest of this all up before rethrowing. 1016 */ 1017 pendingException = ex; 1018 } 1019 1020 /* 1021 * Even if the above call failed, it is still safe to free 1022 * the native structs, and we need to do so lest we leak 1023 * memory. 1024 */ 1025 free(); 1026 1027 if (socket != null) { 1028 if (autoClose && !socket.isClosed()) 1029 socket.close(); 1030 } else { 1031 if (!super.isClosed()) 1032 super.close(); 1033 } 1034 1035 if (pendingException != null) { 1036 throw pendingException; 1037 } 1038 } 1039 } 1040 } 1041 } 1042 1043 private void free() { 1044 if (sslNativePointer == 0) { 1045 return; 1046 } 1047 NativeCrypto.SSL_free(sslNativePointer); 1048 sslNativePointer = 0; 1049 } 1050 1051 protected void finalize() throws IOException { 1052 /* 1053 * Just worry about our own state. Notably we do not try and 1054 * close anything. The SocketImpl, either our own 1055 * PlainSocketImpl, or the Socket we are wrapping, will do 1056 * that. This might mean we do not properly SSL_shutdown, but 1057 * if you want to do that, properly close the socket yourself. 1058 * 1059 * The reason why we don't try to SSL_shutdown, is that there 1060 * can be a race between finalizers where the PlainSocketImpl 1061 * finalizer runs first and closes the socket. However, in the 1062 * meanwhile, the underlying file descriptor could be reused 1063 * for another purpose. If we call SSL_shutdown, the 1064 * underlying socket BIOs still have the old file descriptor 1065 * and will write the close notify to some unsuspecting 1066 * reader. 1067 */ 1068 updateInstanceCount(-1); 1069 free(); 1070 } 1071} 1072