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