1 /* 2 * Copyright (C) 2017 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.conscrypt; 18 19 import static org.conscrypt.SSLUtils.EngineStates.STATE_CLOSED; 20 import static org.conscrypt.SSLUtils.EngineStates.STATE_HANDSHAKE_STARTED; 21 import static org.conscrypt.SSLUtils.EngineStates.STATE_NEW; 22 import static org.conscrypt.SSLUtils.EngineStates.STATE_READY; 23 import static org.conscrypt.SSLUtils.EngineStates.STATE_READY_HANDSHAKE_CUT_THROUGH; 24 25 import java.io.IOException; 26 import java.io.InputStream; 27 import java.io.OutputStream; 28 import java.net.InetAddress; 29 import java.net.Socket; 30 import java.net.SocketException; 31 import java.security.InvalidKeyException; 32 import java.security.PrivateKey; 33 import java.security.cert.CertificateEncodingException; 34 import java.security.cert.CertificateException; 35 import java.security.cert.X509Certificate; 36 import java.security.interfaces.ECKey; 37 import java.security.spec.ECParameterSpec; 38 import javax.crypto.SecretKey; 39 import javax.net.ssl.SSLException; 40 import javax.net.ssl.SSLHandshakeException; 41 import javax.net.ssl.SSLParameters; 42 import javax.net.ssl.SSLProtocolException; 43 import javax.net.ssl.SSLSession; 44 import javax.net.ssl.X509KeyManager; 45 import javax.net.ssl.X509TrustManager; 46 import javax.security.auth.x500.X500Principal; 47 import org.conscrypt.ExternalSession.Provider; 48 import org.conscrypt.NativeRef.SSL_SESSION; 49 50 /** 51 * Implementation of the class OpenSSLSocketImpl based on OpenSSL. 52 * <p> 53 * Extensions to SSLSocket include: 54 * <ul> 55 * <li>handshake timeout 56 * <li>session tickets 57 * <li>Server Name Indication 58 * </ul> 59 */ 60 class ConscryptFileDescriptorSocket extends OpenSSLSocketImpl 61 implements NativeCrypto.SSLHandshakeCallbacks, SSLParametersImpl.AliasChooser, 62 SSLParametersImpl.PSKCallbacks { 63 private static final boolean DBG_STATE = false; 64 65 // @GuardedBy("ssl"); 66 private int state = STATE_NEW; 67 68 /** 69 * Wrapper around the underlying SSL object. 70 */ 71 private final NativeSsl ssl; 72 73 /** 74 * Protected by synchronizing on ssl. Starts as null, set by 75 * getInputStream. 76 */ 77 // @GuardedBy("ssl"); 78 private SSLInputStream is; 79 80 /** 81 * Protected by synchronizing on ssl. Starts as null, set by 82 * getInputStream. 83 */ 84 // @GuardedBy("ssl"); 85 private SSLOutputStream os; 86 87 private final SSLParametersImpl sslParameters; 88 89 /* 90 * A CloseGuard object on Android. On other platforms, this is nothing. 91 */ 92 private final Object guard = Platform.closeGuardGet(); 93 94 /** 95 * Private key for the TLS Channel ID extension. This field is client-side 96 * only. Set during startHandshake. 97 */ 98 private OpenSSLKey channelIdPrivateKey; 99 100 private final ActiveSession activeSession; 101 /** 102 * A snapshot of the active session when the engine was closed. 103 */ 104 private SessionSnapshot closedSession; 105 /** 106 * The session object exposed externally from this class. 107 */ 108 private final SSLSession externalSession = 109 Platform.wrapSSLSession(new ExternalSession(new Provider() { 110 @Override 111 public ConscryptSession provideSession() { 112 return ConscryptFileDescriptorSocket.this.provideSession(); 113 } 114 })); 115 116 private int writeTimeoutMilliseconds = 0; 117 private int handshakeTimeoutMilliseconds = -1; // -1 = same as timeout; 0 = infinite 118 119 // The constructors should not be called except from the Platform class, because we may 120 // want to construct a subclass instead. 121 ConscryptFileDescriptorSocket(SSLParametersImpl sslParameters) throws IOException { 122 this.sslParameters = sslParameters; 123 this.ssl = newSsl(sslParameters, this); 124 activeSession = new ActiveSession(ssl, sslParameters.getSessionContext()); 125 } 126 127 ConscryptFileDescriptorSocket(String hostname, int port, SSLParametersImpl sslParameters) 128 throws IOException { 129 super(hostname, port); 130 this.sslParameters = sslParameters; 131 this.ssl = newSsl(sslParameters, this); 132 activeSession = new ActiveSession(ssl, sslParameters.getSessionContext()); 133 } 134 135 ConscryptFileDescriptorSocket(InetAddress address, int port, SSLParametersImpl sslParameters) 136 throws IOException { 137 super(address, port); 138 this.sslParameters = sslParameters; 139 this.ssl = newSsl(sslParameters, this); 140 activeSession = new ActiveSession(ssl, sslParameters.getSessionContext()); 141 } 142 143 ConscryptFileDescriptorSocket(String hostname, int port, InetAddress clientAddress, 144 int clientPort, SSLParametersImpl sslParameters) throws IOException { 145 super(hostname, port, clientAddress, clientPort); 146 this.sslParameters = sslParameters; 147 this.ssl = newSsl(sslParameters, this); 148 activeSession = new ActiveSession(ssl, sslParameters.getSessionContext()); 149 } 150 151 ConscryptFileDescriptorSocket(InetAddress address, int port, InetAddress clientAddress, 152 int clientPort, SSLParametersImpl sslParameters) throws IOException { 153 super(address, port, clientAddress, clientPort); 154 this.sslParameters = sslParameters; 155 this.ssl = newSsl(sslParameters, this); 156 activeSession = new ActiveSession(ssl, sslParameters.getSessionContext()); 157 } 158 159 ConscryptFileDescriptorSocket(Socket socket, String hostname, int port, boolean autoClose, 160 SSLParametersImpl sslParameters) throws IOException { 161 super(socket, hostname, port, autoClose); 162 this.sslParameters = sslParameters; 163 this.ssl = newSsl(sslParameters, this); 164 activeSession = new ActiveSession(ssl, sslParameters.getSessionContext()); 165 } 166 167 private static NativeSsl newSsl(SSLParametersImpl sslParameters, 168 ConscryptFileDescriptorSocket engine) throws SSLException { 169 return NativeSsl.newInstance(sslParameters, engine, engine, engine); 170 } 171 172 /** 173 * Starts a TLS/SSL handshake on this connection using some native methods 174 * from the OpenSSL library. It can negotiate new encryption keys, change 175 * cipher suites, or initiate a new session. The certificate chain is 176 * verified if the correspondent property in java.Security is set. All 177 * listeners are notified at the end of the TLS/SSL handshake. 178 */ 179 @Override 180 public final void startHandshake() throws IOException { 181 checkOpen(); 182 synchronized (ssl) { 183 if (state == STATE_NEW) { 184 transitionTo(STATE_HANDSHAKE_STARTED); 185 } else { 186 // We've either started the handshake already or have been closed. 187 // Do nothing in both cases. 188 return; 189 } 190 } 191 192 boolean releaseResources = true; 193 try { 194 Platform.closeGuardOpen(guard, "close"); 195 196 // Prepare the SSL object for the handshake. 197 ssl.initialize(getHostname(), channelIdPrivateKey); 198 199 // For clients, offer to resume a previously cached session to avoid the 200 // full TLS handshake. 201 if (getUseClientMode()) { 202 NativeSslSession cachedSession = clientSessionContext().getCachedSession( 203 getHostnameOrIP(), getPort(), sslParameters); 204 if (cachedSession != null) { 205 cachedSession.offerToResume(ssl); 206 } 207 } 208 209 // Temporarily use a different timeout for the handshake process 210 int savedReadTimeoutMilliseconds = getSoTimeout(); 211 int savedWriteTimeoutMilliseconds = getSoWriteTimeout(); 212 if (handshakeTimeoutMilliseconds >= 0) { 213 setSoTimeout(handshakeTimeoutMilliseconds); 214 setSoWriteTimeout(handshakeTimeoutMilliseconds); 215 } 216 217 synchronized (ssl) { 218 if (state == STATE_CLOSED) { 219 return; 220 } 221 } 222 223 try { 224 ssl.doHandshake(Platform.getFileDescriptor(socket), getSoTimeout()); 225 226 // Update the session from the current state of the SSL object. 227 activeSession.onPeerCertificateAvailable(getHostnameOrIP(), getPort()); 228 } catch (CertificateException e) { 229 SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage()); 230 wrapper.initCause(e); 231 throw wrapper; 232 } catch (SSLException e) { 233 // Swallow this exception if it's thrown as the result of an interruption. 234 // 235 // TODO: SSL_read and SSL_write return -1 when interrupted, but SSL_do_handshake 236 // will throw the last sslError that it saw before sslSelect, usually SSL_WANT_READ 237 // (or WANT_WRITE). Catching that exception here doesn't seem much worse than 238 // changing the native code to return a "special" native pointer value when that 239 // happens. 240 synchronized (ssl) { 241 if (state == STATE_CLOSED) { 242 return; 243 } 244 } 245 246 // Write CCS errors to EventLog 247 String message = e.getMessage(); 248 // Must match error string of SSL_R_UNEXPECTED_CCS 249 if (message.contains("unexpected CCS")) { 250 String logMessage = 251 String.format("ssl_unexpected_ccs: host=%s", getHostnameOrIP()); 252 Platform.logEvent(logMessage); 253 } 254 255 throw e; 256 } 257 258 synchronized (ssl) { 259 if (state == STATE_CLOSED) { 260 return; 261 } 262 } 263 264 // Restore the original timeout now that the handshake is complete 265 if (handshakeTimeoutMilliseconds >= 0) { 266 setSoTimeout(savedReadTimeoutMilliseconds); 267 setSoWriteTimeout(savedWriteTimeoutMilliseconds); 268 } 269 270 synchronized (ssl) { 271 releaseResources = (state == STATE_CLOSED); 272 273 if (state == STATE_HANDSHAKE_STARTED) { 274 transitionTo(STATE_READY_HANDSHAKE_CUT_THROUGH); 275 } else { 276 transitionTo(STATE_READY); 277 } 278 279 if (!releaseResources) { 280 // Unblock threads that are waiting for our state to transition 281 // into STATE_READY or STATE_READY_HANDSHAKE_CUT_THROUGH. 282 ssl.notifyAll(); 283 } 284 } 285 } catch (SSLProtocolException e) { 286 throw(SSLHandshakeException) new SSLHandshakeException("Handshake failed").initCause(e); 287 } finally { 288 // on exceptional exit, treat the socket as closed 289 if (releaseResources) { 290 synchronized (ssl) { 291 // Mark the socket as closed since we might have reached this as 292 // a result on an exception thrown by the handshake process. 293 // 294 // The state will already be set to closed if we reach this as a result of 295 // an early return or an interruption due to a concurrent call to close(). 296 transitionTo(STATE_CLOSED); 297 ssl.notifyAll(); 298 } 299 300 try { 301 shutdownAndFreeSslNative(); 302 } catch (IOException ignored) { 303 // Ignored. 304 } 305 } 306 } 307 } 308 309 @Override 310 @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / client_cert_cb 311 public final void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) 312 throws CertificateEncodingException, SSLException { 313 ssl.chooseClientCertificate(keyTypeBytes, asn1DerEncodedPrincipals); 314 } 315 316 @Override 317 @SuppressWarnings("unused") // used by native psk_client_callback 318 public final int clientPSKKeyRequested(String identityHint, byte[] identity, byte[] key) { 319 return ssl.clientPSKKeyRequested(identityHint, identity, key); 320 } 321 322 @Override 323 @SuppressWarnings("unused") // used by native psk_server_callback 324 public final int serverPSKKeyRequested(String identityHint, String identity, byte[] key) { 325 return ssl.serverPSKKeyRequested(identityHint, identity, key); 326 } 327 328 @Override 329 @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / info_callback 330 public final void onSSLStateChange(int type, int val) { 331 if (type != NativeConstants.SSL_CB_HANDSHAKE_DONE) { 332 // We only care about successful completion. 333 return; 334 } 335 336 // The handshake has completed successfully ... 337 338 // First, update the state. 339 synchronized (ssl) { 340 if (state == STATE_CLOSED) { 341 // Someone called "close" but the handshake hasn't been interrupted yet. 342 return; 343 } 344 345 // Now that we've fixed up our state, we can tell waiting threads that 346 // we're ready. 347 transitionTo(STATE_READY); 348 } 349 350 // Let listeners know we are finally done 351 notifyHandshakeCompletedListeners(); 352 353 synchronized (ssl) { 354 // Notify all threads waiting for the handshake to complete. 355 ssl.notifyAll(); 356 } 357 } 358 359 @Override 360 @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / new_session_callback 361 public final void onNewSessionEstablished(long sslSessionNativePtr) { 362 try { 363 // Increment the reference count to "take ownership" of the session resource. 364 NativeCrypto.SSL_SESSION_up_ref(sslSessionNativePtr); 365 366 // Create a native reference which will release the SSL_SESSION in its finalizer. 367 // This constructor will only throw if the native pointer passed in is NULL, which 368 // BoringSSL guarantees will not happen. 369 NativeRef.SSL_SESSION ref = new SSL_SESSION(sslSessionNativePtr); 370 371 NativeSslSession nativeSession = NativeSslSession.newInstance(ref, activeSession); 372 373 // Cache the newly established session. 374 AbstractSessionContext ctx = sessionContext(); 375 ctx.cacheSession(nativeSession); 376 } catch (Exception ignored) { 377 // Ignore. 378 } 379 } 380 381 @Override 382 public final long serverSessionRequested(byte[] id) { 383 // TODO(nathanmittler): Implement server-side caching for TLS < 1.3 384 return 0; 385 } 386 387 @Override 388 public final void verifyCertificateChain(byte[][] certChain, String authMethod) 389 throws CertificateException { 390 try { 391 if (certChain == null || certChain.length == 0) { 392 throw new CertificateException("Peer sent no certificate"); 393 } 394 X509Certificate[] peerCertChain = SSLUtils.decodeX509CertificateChain(certChain); 395 396 X509TrustManager x509tm = sslParameters.getX509TrustManager(); 397 if (x509tm == null) { 398 throw new CertificateException("No X.509 TrustManager"); 399 } 400 // Update the peer information on the session. 401 activeSession.onPeerCertificatesReceived(getHostnameOrIP(), getPort(), peerCertChain); 402 403 if (getUseClientMode()) { 404 Platform.checkServerTrusted(x509tm, peerCertChain, authMethod, this); 405 } else { 406 String authType = peerCertChain[0].getPublicKey().getAlgorithm(); 407 Platform.checkClientTrusted(x509tm, peerCertChain, authType, this); 408 } 409 } catch (CertificateException e) { 410 throw e; 411 } catch (Exception e) { 412 throw new CertificateException(e); 413 } 414 } 415 416 @Override 417 public final InputStream getInputStream() throws IOException { 418 checkOpen(); 419 420 InputStream returnVal; 421 synchronized (ssl) { 422 if (state == STATE_CLOSED) { 423 throw new SocketException("Socket is closed."); 424 } 425 426 if (is == null) { 427 is = new SSLInputStream(); 428 } 429 430 returnVal = is; 431 } 432 433 // Block waiting for a handshake without a lock held. It's possible that the socket 434 // is closed at this point. If that happens, we'll still return the input stream but 435 // all reads on it will throw. 436 waitForHandshake(); 437 return returnVal; 438 } 439 440 @Override 441 public final OutputStream getOutputStream() throws IOException { 442 checkOpen(); 443 444 OutputStream returnVal; 445 synchronized (ssl) { 446 if (state == STATE_CLOSED) { 447 throw new SocketException("Socket is closed."); 448 } 449 450 if (os == null) { 451 os = new SSLOutputStream(); 452 } 453 454 returnVal = os; 455 } 456 457 // Block waiting for a handshake without a lock held. It's possible that the socket 458 // is closed at this point. If that happens, we'll still return the output stream but 459 // all writes on it will throw. 460 waitForHandshake(); 461 return returnVal; 462 } 463 464 private void assertReadableOrWriteableState() { 465 if (state == STATE_READY || state == STATE_READY_HANDSHAKE_CUT_THROUGH) { 466 return; 467 } 468 469 throw new AssertionError("Invalid state: " + state); 470 } 471 472 private void waitForHandshake() throws IOException { 473 startHandshake(); 474 475 synchronized (ssl) { 476 while (state != STATE_READY && 477 state != STATE_READY_HANDSHAKE_CUT_THROUGH && 478 state != STATE_CLOSED) { 479 try { 480 ssl.wait(); 481 } catch (InterruptedException e) { 482 Thread.currentThread().interrupt(); 483 throw new IOException("Interrupted waiting for handshake", e); 484 } 485 } 486 487 if (state == STATE_CLOSED) { 488 throw new SocketException("Socket is closed"); 489 } 490 } 491 } 492 493 /** 494 * This inner class provides input data stream functionality 495 * for the OpenSSL native implementation. It is used to 496 * read data received via SSL protocol. 497 */ 498 private class SSLInputStream extends InputStream { 499 /** 500 * OpenSSL only lets one thread read at a time, so this is used to 501 * make sure we serialize callers of SSL_read. Thread is already 502 * expected to have completed handshaking. 503 */ 504 private final Object readLock = new Object(); 505 506 SSLInputStream() { 507 } 508 509 /** 510 * Reads one byte. If there is no data in the underlying buffer, 511 * this operation can block until the data will be 512 * available. 513 */ 514 @Override 515 public int read() throws IOException { 516 byte[] buffer = new byte[1]; 517 int result = read(buffer, 0, 1); 518 return (result != -1) ? buffer[0] & 0xff : -1; 519 } 520 521 /** 522 * Method acts as described in spec for superclass. 523 * @see java.io.InputStream#read(byte[],int,int) 524 */ 525 @Override 526 public int read(byte[] buf, int offset, int byteCount) throws IOException { 527 Platform.blockGuardOnNetwork(); 528 529 checkOpen(); 530 ArrayUtils.checkOffsetAndCount(buf.length, offset, byteCount); 531 if (byteCount == 0) { 532 return 0; 533 } 534 535 synchronized (readLock) { 536 synchronized (ssl) { 537 if (state == STATE_CLOSED) { 538 throw new SocketException("socket is closed"); 539 } 540 541 if (DBG_STATE) { 542 assertReadableOrWriteableState(); 543 } 544 } 545 546 int ret = ssl.read( 547 Platform.getFileDescriptor(socket), buf, offset, byteCount, getSoTimeout()); 548 if (ret == -1) { 549 synchronized (ssl) { 550 if (state == STATE_CLOSED) { 551 throw new SocketException("socket is closed"); 552 } 553 } 554 } 555 return ret; 556 } 557 } 558 559 void awaitPendingOps() { 560 if (DBG_STATE) { 561 synchronized (ssl) { 562 if (state != STATE_CLOSED) { 563 throw new AssertionError("State is: " + state); 564 } 565 } 566 } 567 568 synchronized (readLock) {} 569 } 570 } 571 572 /** 573 * This inner class provides output data stream functionality 574 * for the OpenSSL native implementation. It is used to 575 * write data according to the encryption parameters given in SSL context. 576 */ 577 private class SSLOutputStream extends OutputStream { 578 /** 579 * OpenSSL only lets one thread write at a time, so this is used 580 * to make sure we serialize callers of SSL_write. Thread is 581 * already expected to have completed handshaking. 582 */ 583 private final Object writeLock = new Object(); 584 585 SSLOutputStream() { 586 } 587 588 /** 589 * Method acts as described in spec for superclass. 590 * @see java.io.OutputStream#write(int) 591 */ 592 @Override 593 public void write(int oneByte) throws IOException { 594 byte[] buffer = new byte[1]; 595 buffer[0] = (byte) (oneByte & 0xff); 596 write(buffer); 597 } 598 599 /** 600 * Method acts as described in spec for superclass. 601 * @see java.io.OutputStream#write(byte[],int,int) 602 */ 603 @Override 604 public void write(byte[] buf, int offset, int byteCount) throws IOException { 605 Platform.blockGuardOnNetwork(); 606 checkOpen(); 607 ArrayUtils.checkOffsetAndCount(buf.length, offset, byteCount); 608 if (byteCount == 0) { 609 return; 610 } 611 612 synchronized (writeLock) { 613 synchronized (ssl) { 614 if (state == STATE_CLOSED) { 615 throw new SocketException("socket is closed"); 616 } 617 618 if (DBG_STATE) { 619 assertReadableOrWriteableState(); 620 } 621 } 622 623 ssl.write(Platform.getFileDescriptor(socket), buf, offset, byteCount, 624 writeTimeoutMilliseconds); 625 626 synchronized (ssl) { 627 if (state == STATE_CLOSED) { 628 throw new SocketException("socket is closed"); 629 } 630 } 631 } 632 } 633 634 void awaitPendingOps() { 635 if (DBG_STATE) { 636 synchronized (ssl) { 637 if (state != STATE_CLOSED) { 638 throw new AssertionError("State is: " + state); 639 } 640 } 641 } 642 643 synchronized (writeLock) {} 644 } 645 } 646 647 @Override 648 public final SSLSession getSession() { 649 return externalSession; 650 } 651 652 private ConscryptSession provideSession() { 653 boolean handshakeCompleted = false; 654 synchronized (ssl) { 655 if (state == STATE_CLOSED) { 656 return closedSession != null ? closedSession : SSLNullSession.getNullSession(); 657 } 658 659 try { 660 handshakeCompleted = state >= STATE_READY; 661 if (!handshakeCompleted && isConnected()) { 662 waitForHandshake(); 663 handshakeCompleted = true; 664 } 665 } catch (IOException e) { 666 // Fall through. 667 } 668 } 669 670 if (!handshakeCompleted) { 671 // return an invalid session with 672 // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL" 673 return SSLNullSession.getNullSession(); 674 } 675 676 return activeSession; 677 } 678 679 private ConscryptSession provideHandshakeSession() { 680 synchronized (ssl) { 681 return state >= STATE_HANDSHAKE_STARTED && state < STATE_READY ? activeSession 682 : SSLNullSession.getNullSession(); 683 } 684 } 685 686 @Override 687 final SSLSession getActiveSession() { 688 return activeSession; 689 } 690 691 @Override 692 public final SSLSession getHandshakeSession() { 693 synchronized (ssl) { 694 if (state >= STATE_HANDSHAKE_STARTED && state < STATE_READY) { 695 return Platform.wrapSSLSession(new ExternalSession(new Provider() { 696 @Override 697 public ConscryptSession provideSession() { 698 return ConscryptFileDescriptorSocket.this.provideHandshakeSession(); 699 } 700 })); 701 } 702 return null; 703 } 704 } 705 706 @Override 707 public final boolean getEnableSessionCreation() { 708 return sslParameters.getEnableSessionCreation(); 709 } 710 711 @Override 712 public final void setEnableSessionCreation(boolean flag) { 713 sslParameters.setEnableSessionCreation(flag); 714 } 715 716 @Override 717 public final String[] getSupportedCipherSuites() { 718 return NativeCrypto.getSupportedCipherSuites(); 719 } 720 721 @Override 722 public final String[] getEnabledCipherSuites() { 723 return sslParameters.getEnabledCipherSuites(); 724 } 725 726 @Override 727 public final void setEnabledCipherSuites(String[] suites) { 728 sslParameters.setEnabledCipherSuites(suites); 729 } 730 731 @Override 732 public final String[] getSupportedProtocols() { 733 return NativeCrypto.getSupportedProtocols(); 734 } 735 736 @Override 737 public final String[] getEnabledProtocols() { 738 return sslParameters.getEnabledProtocols(); 739 } 740 741 @Override 742 public final void setEnabledProtocols(String[] protocols) { 743 sslParameters.setEnabledProtocols(protocols); 744 } 745 746 /** 747 * This method enables session ticket support. 748 * 749 * @param useSessionTickets True to enable session tickets 750 */ 751 @Override 752 public final void setUseSessionTickets(boolean useSessionTickets) { 753 sslParameters.setUseSessionTickets(useSessionTickets); 754 } 755 756 /** 757 * This method enables Server Name Indication 758 * 759 * @param hostname the desired SNI hostname, or null to disable 760 */ 761 @Override 762 public final void setHostname(String hostname) { 763 sslParameters.setUseSni(hostname != null); 764 super.setHostname(hostname); 765 } 766 767 /** 768 * Enables/disables TLS Channel ID for this server socket. 769 * 770 * <p>This method needs to be invoked before the handshake starts. 771 * 772 * @throws IllegalStateException if this is a client socket or if the handshake has already 773 * started. 774 */ 775 @Override 776 public final void setChannelIdEnabled(boolean enabled) { 777 if (getUseClientMode()) { 778 throw new IllegalStateException("Client mode"); 779 } 780 781 synchronized (ssl) { 782 if (state != STATE_NEW) { 783 throw new IllegalStateException( 784 "Could not enable/disable Channel ID after the initial handshake has" 785 + " begun."); 786 } 787 } 788 sslParameters.channelIdEnabled = enabled; 789 } 790 791 /** 792 * Gets the TLS Channel ID for this server socket. Channel ID is only available once the 793 * handshake completes. 794 * 795 * @return channel ID or {@code null} if not available. 796 * 797 * @throws IllegalStateException if this is a client socket or if the handshake has not yet 798 * completed. 799 * @throws SSLException if channel ID is available but could not be obtained. 800 */ 801 @Override 802 public final byte[] getChannelId() throws SSLException { 803 if (getUseClientMode()) { 804 throw new IllegalStateException("Client mode"); 805 } 806 807 synchronized (ssl) { 808 if (state != STATE_READY) { 809 throw new IllegalStateException( 810 "Channel ID is only available after handshake completes"); 811 } 812 } 813 return ssl.getTlsChannelId(); 814 } 815 816 /** 817 * Sets the {@link PrivateKey} to be used for TLS Channel ID by this client socket. 818 * 819 * <p>This method needs to be invoked before the handshake starts. 820 * 821 * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key (disables 822 * TLS Channel ID). The private key must be an Elliptic Curve (EC) key based on the NIST 823 * P-256 curve (aka SECG secp256r1 or ANSI X9.62 prime256v1). 824 * 825 * @throws IllegalStateException if this is a server socket or if the handshake has already 826 * started. 827 */ 828 @Override 829 public final void setChannelIdPrivateKey(PrivateKey privateKey) { 830 if (!getUseClientMode()) { 831 throw new IllegalStateException("Server mode"); 832 } 833 834 synchronized (ssl) { 835 if (state != STATE_NEW) { 836 throw new IllegalStateException( 837 "Could not change Channel ID private key after the initial handshake has" 838 + " begun."); 839 } 840 } 841 842 if (privateKey == null) { 843 sslParameters.channelIdEnabled = false; 844 channelIdPrivateKey = null; 845 } else { 846 sslParameters.channelIdEnabled = true; 847 try { 848 ECParameterSpec ecParams = null; 849 if (privateKey instanceof ECKey) { 850 ecParams = ((ECKey) privateKey).getParams(); 851 } 852 if (ecParams == null) { 853 // Assume this is a P-256 key, as specified in the contract of this method. 854 ecParams = 855 OpenSSLECGroupContext.getCurveByName("prime256v1").getECParameterSpec(); 856 } 857 channelIdPrivateKey = 858 OpenSSLKey.fromECPrivateKeyForTLSStackOnly(privateKey, ecParams); 859 } catch (InvalidKeyException e) { 860 // Will have error in startHandshake 861 } 862 } 863 } 864 865 @Override 866 byte[] getTlsUnique() { 867 return ssl.getTlsUnique(); 868 } 869 870 @Override 871 public final boolean getUseClientMode() { 872 return sslParameters.getUseClientMode(); 873 } 874 875 @Override 876 public final void setUseClientMode(boolean mode) { 877 synchronized (ssl) { 878 if (state != STATE_NEW) { 879 throw new IllegalArgumentException( 880 "Could not change the mode after the initial handshake has begun."); 881 } 882 } 883 sslParameters.setUseClientMode(mode); 884 } 885 886 @Override 887 public final boolean getWantClientAuth() { 888 return sslParameters.getWantClientAuth(); 889 } 890 891 @Override 892 public final boolean getNeedClientAuth() { 893 return sslParameters.getNeedClientAuth(); 894 } 895 896 @Override 897 public final void setNeedClientAuth(boolean need) { 898 sslParameters.setNeedClientAuth(need); 899 } 900 901 @Override 902 public final void setWantClientAuth(boolean want) { 903 sslParameters.setWantClientAuth(want); 904 } 905 906 /** 907 * Note write timeouts are not part of the javax.net.ssl.SSLSocket API 908 */ 909 @Override 910 public final void setSoWriteTimeout(int writeTimeoutMilliseconds) throws SocketException { 911 this.writeTimeoutMilliseconds = writeTimeoutMilliseconds; 912 913 Platform.setSocketWriteTimeout(this, writeTimeoutMilliseconds); 914 } 915 916 /** 917 * Note write timeouts are not part of the javax.net.ssl.SSLSocket API 918 */ 919 @Override 920 public final int getSoWriteTimeout() throws SocketException { 921 return writeTimeoutMilliseconds; 922 } 923 924 /** 925 * Set the handshake timeout on this socket. This timeout is specified in 926 * milliseconds and will be used only during the handshake process. 927 */ 928 @Override 929 public final void setHandshakeTimeout(int handshakeTimeoutMilliseconds) throws SocketException { 930 this.handshakeTimeoutMilliseconds = handshakeTimeoutMilliseconds; 931 } 932 933 @Override 934 @SuppressWarnings("UnsynchronizedOverridesSynchronized") 935 public final void close() throws IOException { 936 // TODO: Close SSL sockets using a background thread so they close gracefully. 937 938 SSLInputStream sslInputStream; 939 SSLOutputStream sslOutputStream; 940 941 if (ssl == null) { 942 // close() has been called before we've initialized the socket, so just 943 // return. 944 return; 945 } 946 947 synchronized (ssl) { 948 if (state == STATE_CLOSED) { 949 // close() has already been called, so do nothing and return. 950 return; 951 } 952 953 int oldState = state; 954 transitionTo(STATE_CLOSED); 955 956 if (oldState == STATE_NEW) { 957 // The handshake hasn't been started yet, so there's no OpenSSL related 958 // state to clean up. We still need to close the underlying socket if 959 // we're wrapping it and were asked to autoClose. 960 free(); 961 closeUnderlyingSocket(); 962 963 ssl.notifyAll(); 964 return; 965 } 966 967 if (oldState != STATE_READY && oldState != STATE_READY_HANDSHAKE_CUT_THROUGH) { 968 // If we're in these states, we still haven't returned from startHandshake. 969 // We call SSL_interrupt so that we can interrupt SSL_do_handshake and then 970 // set the state to STATE_CLOSED. startHandshake will handle all cleanup 971 // after SSL_do_handshake returns, so we don't have anything to do here. 972 ssl.interrupt(); 973 974 ssl.notifyAll(); 975 return; 976 } 977 978 ssl.notifyAll(); 979 // We've already returned from startHandshake, so we potentially have 980 // input and output streams to clean up. 981 sslInputStream = is; 982 sslOutputStream = os; 983 } 984 985 // Don't bother interrupting unless we have something to interrupt. 986 if (sslInputStream != null || sslOutputStream != null) { 987 ssl.interrupt(); 988 } 989 990 // Wait for the input and output streams to finish any reads they have in 991 // progress. If there are no reads in progress at this point, future reads will 992 // throw because state == STATE_CLOSED 993 if (sslInputStream != null) { 994 sslInputStream.awaitPendingOps(); 995 } 996 if (sslOutputStream != null) { 997 sslOutputStream.awaitPendingOps(); 998 } 999 1000 shutdownAndFreeSslNative(); 1001 } 1002 1003 private void shutdownAndFreeSslNative() throws IOException { 1004 try { 1005 Platform.blockGuardOnNetwork(); 1006 ssl.shutdown(Platform.getFileDescriptor(socket)); 1007 } catch (IOException ignored) { 1008 /* 1009 * Note that although close() can throw 1010 * IOException, the RI does not throw if there 1011 * is problem sending a "close notify" which 1012 * can happen if the underlying socket is closed. 1013 */ 1014 } finally { 1015 free(); 1016 closeUnderlyingSocket(); 1017 } 1018 } 1019 1020 private void closeUnderlyingSocket() throws IOException { 1021 super.close(); 1022 } 1023 1024 private void free() { 1025 if (!ssl.isClosed()) { 1026 ssl.close(); 1027 Platform.closeGuardClose(guard); 1028 } 1029 } 1030 1031 @Override 1032 protected final void finalize() throws Throwable { 1033 try { 1034 /* 1035 * Just worry about our own state. Notably we do not try and 1036 * close anything. The SocketImpl, either our own 1037 * PlainSocketImpl, or the Socket we are wrapping, will do 1038 * that. This might mean we do not properly SSL_shutdown, but 1039 * if you want to do that, properly close the socket yourself. 1040 * 1041 * The reason why we don't try to SSL_shutdown, is that there 1042 * can be a race between finalizers where the PlainSocketImpl 1043 * finalizer runs first and closes the socket. However, in the 1044 * meanwhile, the underlying file descriptor could be reused 1045 * for another purpose. If we call SSL_shutdown, the 1046 * underlying socket BIOs still have the old file descriptor 1047 * and will write the close notify to some unsuspecting 1048 * reader. 1049 */ 1050 if (guard != null) { 1051 Platform.closeGuardWarnIfOpen(guard); 1052 } 1053 synchronized (ssl) { 1054 transitionTo(STATE_CLOSED); 1055 } 1056 } finally { 1057 super.finalize(); 1058 } 1059 1060 } 1061 1062 @Override 1063 public final void setApplicationProtocolSelector(ApplicationProtocolSelector selector) { 1064 setApplicationProtocolSelector( 1065 selector == null ? null : new ApplicationProtocolSelectorAdapter(this, selector)); 1066 } 1067 1068 @Override 1069 final void setApplicationProtocolSelector(ApplicationProtocolSelectorAdapter selector) { 1070 sslParameters.setApplicationProtocolSelector(selector); 1071 } 1072 1073 @Override 1074 final void setApplicationProtocols(String[] protocols) { 1075 sslParameters.setApplicationProtocols(protocols); 1076 } 1077 1078 @Override 1079 final String[] getApplicationProtocols() { 1080 return sslParameters.getApplicationProtocols(); 1081 } 1082 1083 @Override 1084 public final String getApplicationProtocol() { 1085 return SSLUtils.toProtocolString(ssl.getApplicationProtocol()); 1086 } 1087 1088 @Override 1089 public final String getHandshakeApplicationProtocol() { 1090 synchronized (ssl) { 1091 return state >= STATE_HANDSHAKE_STARTED && state < STATE_READY 1092 ? getApplicationProtocol() : null; 1093 } 1094 } 1095 1096 @Override 1097 public final SSLParameters getSSLParameters() { 1098 SSLParameters params = super.getSSLParameters(); 1099 Platform.getSSLParameters(params, sslParameters, this); 1100 return params; 1101 } 1102 1103 @Override 1104 public final void setSSLParameters(SSLParameters p) { 1105 super.setSSLParameters(p); 1106 Platform.setSSLParameters(p, sslParameters, this); 1107 } 1108 1109 @Override 1110 public final String chooseServerAlias(X509KeyManager keyManager, String keyType) { 1111 return keyManager.chooseServerAlias(keyType, null, this); 1112 } 1113 1114 @Override 1115 public final String chooseClientAlias(X509KeyManager keyManager, X500Principal[] issuers, 1116 String[] keyTypes) { 1117 return keyManager.chooseClientAlias(keyTypes, issuers, this); 1118 } 1119 1120 @Override 1121 @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package 1122 public final String chooseServerPSKIdentityHint(PSKKeyManager keyManager) { 1123 return keyManager.chooseServerKeyIdentityHint(this); 1124 } 1125 1126 @Override 1127 @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package 1128 public final String chooseClientPSKIdentity(PSKKeyManager keyManager, String identityHint) { 1129 return keyManager.chooseClientKeyIdentity(identityHint, this); 1130 } 1131 1132 @Override 1133 @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package 1134 public final SecretKey getPSKKey(PSKKeyManager keyManager, String identityHint, String identity) { 1135 return keyManager.getKey(identityHint, identity, this); 1136 } 1137 1138 private ClientSessionContext clientSessionContext() { 1139 return sslParameters.getClientSessionContext(); 1140 } 1141 1142 private AbstractSessionContext sessionContext() { 1143 return sslParameters.getSessionContext(); 1144 } 1145 1146 private void transitionTo(int newState) { 1147 switch (newState) { 1148 case STATE_CLOSED: { 1149 if (!ssl.isClosed() && state >= STATE_HANDSHAKE_STARTED && state < STATE_CLOSED ) { 1150 closedSession = new SessionSnapshot(activeSession); 1151 } 1152 break; 1153 } 1154 default: { 1155 break; 1156 } 1157 } 1158 1159 // Update the state 1160 this.state = newState; 1161 } 1162 } 1163