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