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