Home | History | Annotate | Download | only in conscrypt
      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