OpenSSLSocketImpl.java revision 0dd7db8b85dfd8ad5d16d239432b9852450dc78f
108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project/*
208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project *
408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * you may not use this file except in compliance with the License.
608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * You may obtain a copy of the License at
708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project *
808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project *
1008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * See the License for the specific language governing permissions and
1408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * limitations under the License.
1508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */
1608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
17860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootpackage org.conscrypt;
1808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
19ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrickimport dalvik.system.BlockGuard;
20fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstromimport dalvik.system.CloseGuard;
210648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkeyimport java.io.FileDescriptor;
2208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.io.IOException;
2308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.io.InputStream;
2408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.io.OutputStream;
2508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.net.InetAddress;
2608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.net.Socket;
2708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.net.SocketException;
281ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Rootimport java.security.InvalidKeyException;
2998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstromimport java.security.PrivateKey;
3098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstromimport java.security.SecureRandom;
311f42e0a4d7d28b8fc20833e0be05ad17dcfa8ea0Brian Carlstromimport java.security.cert.CertificateEncodingException;
3208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.security.cert.CertificateException;
3308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.util.ArrayList;
3497e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughesimport java.util.Arrays;
3508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.HandshakeCompletedEvent;
3608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.HandshakeCompletedListener;
3708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.SSLException;
38edc307bd5a7cf750852b9083ba203ba1c24fcdaeBrian Carlstromimport javax.net.ssl.SSLHandshakeException;
39d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Rootimport javax.net.ssl.SSLParameters;
408765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstromimport javax.net.ssl.SSLProtocolException;
4108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.SSLSession;
42d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Rootimport javax.net.ssl.X509ExtendedTrustManager;
438d63ff1384e46407a7618df2b79b2b455795c396Alex Klyubinimport javax.net.ssl.X509KeyManager;
44fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstromimport javax.net.ssl.X509TrustManager;
4598a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstromimport javax.security.auth.x500.X500Principal;
46fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstromimport libcore.io.ErrnoException;
47fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstromimport libcore.io.Libcore;
485c44d1fc26c081cf85af010b6e751449bde14b80Brian Carlstromimport libcore.io.Streams;
49fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstromimport libcore.io.StructTimeval;
5008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
518db22531f59b33539647ab95bb76354212d3866aNarayan Kamathimport static libcore.io.OsConstants.SOL_SOCKET;
528db22531f59b33539647ab95bb76354212d3866aNarayan Kamathimport static libcore.io.OsConstants.SO_SNDTIMEO;
538db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
5408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project/**
550b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * Implementation of the class OpenSSLSocketImpl based on OpenSSL.
560b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <p>
570b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * Extensions to SSLSocket include:
580b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <ul>
590b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>handshake timeout
600b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>session tickets
610b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>Server Name Indication
620b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * </ul>
6308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */
64f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrompublic class OpenSSLSocketImpl
65f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        extends javax.net.ssl.SSLSocket
663c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        implements NativeCrypto.SSLHandshakeCallbacks, SSLParametersImpl.AliasChooser {
6790ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom
688db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private static final boolean DBG_STATE = false;
698db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
7069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    /**
7169c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom     * Protects handshakeStarted and handshakeCompleted.
7269c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom     */
738db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private final Object stateLock = new Object();
7469c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom
7569c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    /**
768db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * The {@link OpenSSLSocketImpl} object is constructed, but {@link #startHandshake()}
778db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * has not yet been called.
7869c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom     */
798db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private static final int STATE_NEW = 0;
8069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom
8169c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    /**
828db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * {@link #startHandshake()} has been called at least once.
8369c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom     */
848db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private static final int STATE_HANDSHAKE_STARTED = 1;
8569c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom
8669c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    /**
878db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * {@link #handshakeCompleted()} has been called, but {@link #startHandshake()} hasn't
888db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * returned yet.
8969c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom     */
908db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private static final int STATE_HANDSHAKE_COMPLETED = 2;
918db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
928db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    /**
938db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * {@link #startHandshake()} has completed but {@link #handshakeCompleted()} hasn't
948db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * been called. This is expected behaviour in cut-through mode, where SSL_do_handshake
958db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * returns before the handshake is complete. We can now start writing data to the socket.
968db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     */
978db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private static final int STATE_READY_HANDSHAKE_CUT_THROUGH = 3;
9869c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom
9969c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    /**
1008db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * {@link #startHandshake()} has completed and {@link #handshakeCompleted()} has been
1018db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * called.
10269c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom     */
1038db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private static final int STATE_READY = 4;
10469c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom
10569c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    /**
1068db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * {@link #close()} has been called at least once.
10769c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom     */
1088db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private static final int STATE_CLOSED = 5;
1098db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
1108db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    // @GuardedBy("stateLock");
1118db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private int state = STATE_NEW;
11269c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom
11369c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    /**
1148db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * Protected by synchronizing on stateLock. Starts as 0, set by
1158db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * startHandshake, reset to 0 on close.
11669c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom     */
1178db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    // @GuardedBy("stateLock");
1188db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private long sslNativePointer;
11969c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom
12069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    /**
1218db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * Protected by synchronizing on stateLock. Starts as null, set by
1228db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * getInputStream.
12369c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom     */
1248db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    // @GuardedBy("stateLock");
1258db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private SSLInputStream is;
1268db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
1278db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    /**
1288db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * Protected by synchronizing on stateLock. Starts as null, set by
1298db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * getInputStream.
1308db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     */
1318db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    // @GuardedBy("stateLock");
1328db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private SSLOutputStream os;
13369c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom
13469c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    private final Socket socket;
13569c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    private final boolean autoClose;
13657ef6334828dfb4f7f6834ddddf5a0ac61f1a4d0Kenny Root    private String wrappedHost;
13769c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    private final int wrappedPort;
13869c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    private final SSLParametersImpl sslParameters;
13969c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    private final CloseGuard guard = CloseGuard.get();
14069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom
1413c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root    private ArrayList<HandshakeCompletedListener> listeners;
1422828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
1432828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    /**
1443c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root     * Private key for the TLS Channel ID extension. This field is client-side
1453c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root     * only. Set during startHandshake.
1462828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     */
1473c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root    OpenSSLKey channelIdPrivateKey;
14869c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom
14969c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    /** Set during startHandshake. */
15069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    private OpenSSLSessionImpl sslSession;
1512828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
152d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root    /** Used during handshake callbacks. */
153d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root    private OpenSSLSessionImpl handshakeSession;
154d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root
15572721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    /**
15672721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     * Local cache of timeout to avoid getsockopt on every read and
15772721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     * write for non-wrapped sockets. Note that
15872721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     * OpenSSLSocketImplWrapper overrides setSoTimeout and
15972721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     * getSoTimeout to delegate to the wrapped socket.
16072721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     */
161fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    private int readTimeoutMilliseconds = 0;
162fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    private int writeTimeoutMilliseconds = 0;
16372721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom
16472721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    private int handshakeTimeoutMilliseconds = -1;  // -1 = same as timeout; 0 = infinite
16508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
166cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    protected OpenSSLSocketImpl(SSLParametersImpl sslParameters) throws IOException {
16790ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
16869c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.wrappedHost = null;
16969c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.wrappedPort = -1;
17069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.autoClose = false;
17169c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.sslParameters = sslParameters;
17208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
17308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
174cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    protected OpenSSLSocketImpl(SSLParametersImpl sslParameters,
1752828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                                String[] enabledProtocols,
1765ea53c028b903ce252e08c1b67508ce8dafcff34Brian Carlstrom                                String[] enabledCipherSuites) throws IOException {
17790ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
17869c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.wrappedHost = null;
17969c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.wrappedPort = -1;
18069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.autoClose = false;
18169c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.sslParameters = sslParameters;
1823c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        this.sslParameters.openSslEnabledProtocols = enabledProtocols;
1833c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        this.sslParameters.openSslEnabledCipherSuites = enabledCipherSuites;
1842828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    }
1852828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
186cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    protected OpenSSLSocketImpl(String host, int port, SSLParametersImpl sslParameters)
18790ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom            throws IOException {
18808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        super(host, port);
18990ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
19069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.wrappedHost = null;
19169c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.wrappedPort = -1;
19269c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.autoClose = false;
19369c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.sslParameters = sslParameters;
19408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
19508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
196cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    protected OpenSSLSocketImpl(InetAddress address, int port, SSLParametersImpl sslParameters)
19790ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom            throws IOException {
19808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        super(address, port);
19990ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
20069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.wrappedHost = null;
20169c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.wrappedPort = -1;
20269c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.autoClose = false;
20369c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.sslParameters = sslParameters;
20408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
20508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
20608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
207c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom    protected OpenSSLSocketImpl(String host, int port,
208c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom                                InetAddress clientAddress, int clientPort,
2095006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                                SSLParametersImpl sslParameters) throws IOException {
21008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        super(host, port, clientAddress, clientPort);
21190ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
21269c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.wrappedHost = null;
21369c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.wrappedPort = -1;
21469c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.autoClose = false;
21569c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.sslParameters = sslParameters;
21608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
21708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
21808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    protected OpenSSLSocketImpl(InetAddress address, int port,
219c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom                                InetAddress clientAddress, int clientPort,
2205006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                                SSLParametersImpl sslParameters) throws IOException {
22108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        super(address, port, clientAddress, clientPort);
22290ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
22369c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.wrappedHost = null;
22469c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.wrappedPort = -1;
22569c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.autoClose = false;
22669c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.sslParameters = sslParameters;
22708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
22808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
22908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
2305006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson     * Create an SSL socket that wraps another socket. Invoked by
2315006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson     * OpenSSLSocketImplWrapper constructor.
23208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
23308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    protected OpenSSLSocketImpl(Socket socket, String host, int port,
234cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom            boolean autoClose, SSLParametersImpl sslParameters) throws IOException {
23508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        this.socket = socket;
2366e0361de414915ae9929f55f6a8e0266a67506efBrian Carlstrom        this.wrappedHost = host;
2376e0361de414915ae9929f55f6a8e0266a67506efBrian Carlstrom        this.wrappedPort = port;
23808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        this.autoClose = autoClose;
23969c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.sslParameters = sslParameters;
24072721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom
24172721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        // this.timeout is not set intentionally.
24272721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        // OpenSSLSocketImplWrapper.getSoTimeout will delegate timeout
24372721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        // to wrapped socket
244f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    }
245f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
246a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    private void checkOpen() throws SocketException {
247a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        if (isClosed()) {
248a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom            throw new SocketException("Socket is closed");
249a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        }
250a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    }
251a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom
252a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    /**
253d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson     * Starts a TLS/SSL handshake on this connection using some native methods
254d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson     * from the OpenSSL library. It can negotiate new encryption keys, change
255d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson     * cipher suites, or initiate a new session. The certificate chain is
256d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson     * verified if the correspondent property in java.Security is set. All
257d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson     * listeners are notified at the end of the TLS/SSL handshake.
2582828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     */
259f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
260f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void startHandshake() throws IOException {
2618db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        checkOpen();
2628db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
2638db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (state == STATE_NEW) {
2648db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                state = STATE_HANDSHAKE_STARTED;
26508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            } else {
2668db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // We've either started the handshake already or have been closed.
2678db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // Do nothing in both cases.
26808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                return;
26908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
27008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
27108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
27298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        // note that this modifies the global seed, not something specific to the connection
27398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final int seedLengthInBytes = NativeCrypto.RAND_SEED_LENGTH_IN_BYTES;
27498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final SecureRandom secureRandom = sslParameters.getSecureRandomMember();
27598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        if (secureRandom == null) {
27698ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            NativeCrypto.RAND_load_file("/dev/urandom", seedLengthInBytes);
27798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        } else {
27898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            NativeCrypto.RAND_seed(secureRandom.generateSeed(seedLengthInBytes));
27998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        }
28098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
28198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final boolean client = sslParameters.getUseClientMode();
28298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
2838db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        sslNativePointer = 0;
2848db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        boolean releaseResources = true;
285fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        try {
2863c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            final AbstractSessionContext sessionContext = sslParameters.getSessionContext();
2873c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            final long sslCtxNativePointer = sessionContext.sslCtxNativePointer;
288fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer);
289fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            guard.open("close");
29098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
2913c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            boolean enableSessionCreation = getEnableSessionCreation();
292fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (!enableSessionCreation) {
293fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer,
2943c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root                        enableSessionCreation);
2952828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
2962828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
2973c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            final OpenSSLSessionImpl sessionToReuse = sslParameters.getSessionToReuse(
2983c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root                    sslNativePointer, getPeerHostName(), getPeerPort());
2993c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            sslParameters.setSSLParameters(sslCtxNativePointer, sslNativePointer, this,
3003c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root                    getPeerHostName());
3013c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            sslParameters.setCertificateValidation(sslNativePointer);
3023c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            sslParameters.setTlsChannelId(sslNativePointer, channelIdPrivateKey);
303f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
304fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // Temporarily use a different timeout for the handshake process
305fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom            int savedReadTimeoutMilliseconds = getSoTimeout();
306fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom            int savedWriteTimeoutMilliseconds = getSoWriteTimeout();
307fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
308fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                setSoTimeout(handshakeTimeoutMilliseconds);
309fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom                setSoWriteTimeout(handshakeTimeoutMilliseconds);
310fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
3112828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
3128db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            synchronized (stateLock) {
3138db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                if (state == STATE_CLOSED) {
3148db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    return;
3158db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                }
3168db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
3178db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
3187dd8d0b433cf8212538aaaf8726f5222abf035ddMatteo Franchin            long sslSessionNativePointer;
319fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            try {
320a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                sslSessionNativePointer = NativeCrypto.SSL_do_handshake(sslNativePointer,
3213c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root                        socket.getFileDescriptor$(), this, getSoTimeout(), client,
3223c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root                        sslParameters.npnProtocols, client ? null : sslParameters.alpnProtocols);
323fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            } catch (CertificateException e) {
324d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage());
325d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                wrapper.initCause(e);
326d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                throw wrapper;
3278db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            } catch (SSLException e) {
3288db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // Swallow this exception if it's thrown as the result of an interruption.
3298db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                //
3308db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // TODO: SSL_read and SSL_write return -1 when interrupted, but SSL_do_handshake
3318db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // will throw the last sslError that it saw before sslSelect, usually SSL_WANT_READ
3328db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // (or WANT_WRITE). Catching that exception here doesn't seem much worse than
3338db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // changing the native code to return a "special" native pointer value when that
3348db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // happens.
3358db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                synchronized (stateLock) {
3368db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    if (state == STATE_CLOSED) {
3378db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                        return;
3388db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    }
3398db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                }
3408db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
3418db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                throw e;
3422828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
3438db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
3448db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            boolean handshakeCompleted = false;
3458db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            synchronized (stateLock) {
3468db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                if (state == STATE_HANDSHAKE_COMPLETED) {
3478db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    handshakeCompleted = true;
3488db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                } else if (state == STATE_CLOSED) {
3498db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    return;
3508db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                }
3518db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
3528db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
3530dd7db8b85dfd8ad5d16d239432b9852450dc78fKenny Root            sslSession = sslParameters.setupSession(sslSessionNativePointer, sslNativePointer,
3543c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root                    sessionToReuse, getPeerHostName(), getPeerPort(), handshakeCompleted);
355fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom
356fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // Restore the original timeout now that the handshake is complete
357fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
358fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom                setSoTimeout(savedReadTimeoutMilliseconds);
359fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom                setSoWriteTimeout(savedWriteTimeoutMilliseconds);
360331900211d05cd282141a3a50cb1db626f418b2cDan Egnor            }
36108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
362fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback
363fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeCompleted) {
364fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                notifyHandshakeCompletedListeners();
365fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
366f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
3678db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            synchronized (stateLock) {
3688db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                releaseResources = (state == STATE_CLOSED);
3698db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
3708db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                if (state == STATE_HANDSHAKE_STARTED) {
3718db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    state = STATE_READY_HANDSHAKE_CUT_THROUGH;
3728db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                } else if (state == STATE_HANDSHAKE_COMPLETED) {
3738db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    state = STATE_READY;
3748db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                }
3758db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
3768db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                if (!releaseResources) {
3778db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    // Unblock threads that are waiting for our state to transition
3788db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    // into STATE_READY or STATE_READY_HANDSHAKE_CUT_THROUGH.
3798db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    stateLock.notifyAll();
3808db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                }
3818db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
3828765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        } catch (SSLProtocolException e) {
3838765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom            throw new SSLHandshakeException(e);
384fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        } finally {
385aef0b218983e04bc05ffb5746b4f452725f704b7Brian Carlstrom            // on exceptional exit, treat the socket as closed
3868db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (releaseResources) {
3878db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                synchronized (stateLock) {
3888db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    // Mark the socket as closed since we might have reached this as
3898db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    // a result on an exception thrown by the handshake process.
3908db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    //
3918db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    // The state will already be set to closed if we reach this as a result of
3928db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    // an early return or an interruption due to a concurrent call to close().
3938db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    state = STATE_CLOSED;
3948db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    stateLock.notifyAll();
3958db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                }
3968db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
3978db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                try {
3988db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    shutdownAndFreeSslNative();
3998db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                } catch (IOException ignored) {
4008db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
4018db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                }
402fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
40308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
404e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom    }
4053ff2b34d00ea89eec5b895d866fddf05942fd2a7Kenny Root
406bbe7b9241a63a18bebebf38206d0aebb015f1518Geremy Condra    String getPeerHostName() {
4078ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        if (wrappedHost != null) {
4088ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom            return wrappedHost;
4098ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        }
4108ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        InetAddress inetAddress = super.getInetAddress();
4118ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        if (inetAddress != null) {
4128ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom            return inetAddress.getHostName();
4138ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        }
4148ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        return null;
4153967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson    }
4163967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson
417bbe7b9241a63a18bebebf38206d0aebb015f1518Geremy Condra    int getPeerPort() {
4183967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson        return wrappedHost == null ? super.getPort() : wrappedPort;
4193967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson    }
4203967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson
421f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
4225006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / client_cert_cb
42398a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom    public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)
424f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            throws CertificateEncodingException, SSLException {
4253c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        sslParameters.chooseClientCertificate(keyTypeBytes, asn1DerEncodedPrincipals,
4263c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root                sslNativePointer, this);
42798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom    }
42898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
429f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
4305006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / info_callback
431f878e438660d93f8689b864165230492e7a412d4Kenny Root    public void onSSLStateChange(long sslSessionNativePtr, int type, int val) {
432f878e438660d93f8689b864165230492e7a412d4Kenny Root        if (type != NativeCrypto.SSL_CB_HANDSHAKE_DONE) {
433f878e438660d93f8689b864165230492e7a412d4Kenny Root            return;
434f878e438660d93f8689b864165230492e7a412d4Kenny Root        }
435f878e438660d93f8689b864165230492e7a412d4Kenny Root
4368db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
4378db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (state == STATE_HANDSHAKE_STARTED) {
4388db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // If sslSession is null, the handshake was completed during
4398db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // the call to NativeCrypto.SSL_do_handshake and not during a
4408db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // later read operation. That means we do not need to fix up
4418db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // the SSLSession and session cache or notify
4428db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // HandshakeCompletedListeners, it will be done in
4438db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // startHandshake.
4448db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
4458db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                state = STATE_HANDSHAKE_COMPLETED;
4468db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                return;
4478db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            } else if (state == STATE_READY_HANDSHAKE_CUT_THROUGH) {
4488db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // We've returned from startHandshake, which means we've set a sslSession etc.
4498db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // we need to fix them up, which we'll do outside this lock.
4508db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            } else if (state == STATE_CLOSED) {
4518db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // Someone called "close" but the handshake hasn't been interrupted yet.
4528db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                return;
4538db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
4542828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        }
45508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
4562828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // reset session id from the native pointer and update the
4572828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // appropriate cache.
4582828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        sslSession.resetId();
4592828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        AbstractSessionContext sessionContext =
4602828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            (sslParameters.getUseClientMode())
4612828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            ? sslParameters.getClientSessionContext()
4622828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                : sslParameters.getServerSessionContext();
46308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sessionContext.putSession(sslSession);
4642828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
4652828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // let listeners know we are finally done
4662828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        notifyHandshakeCompletedListeners();
4678db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
4688db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
4698db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            // Now that we've fixed up our state, we can tell waiting threads that
4708db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            // we're ready.
4718db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            state = STATE_READY;
4728db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            // Notify all threads waiting for the handshake to complete.
4738db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            stateLock.notifyAll();
4748db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        }
4752828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    }
4762828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
4772828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    private void notifyHandshakeCompletedListeners() {
4782828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        if (listeners != null && !listeners.isEmpty()) {
4792828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            // notify the listeners
4802828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            HandshakeCompletedEvent event =
4812828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                new HandshakeCompletedEvent(this, sslSession);
4822828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            for (HandshakeCompletedListener listener : listeners) {
4832828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                try {
4842828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                    listener.handshakeCompleted(event);
4852828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                } catch (RuntimeException e) {
486371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // The RI runs the handlers in a separate thread,
487371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // which we do not. But we try to preserve their
488371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // behavior of logging a problem and not killing
489371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // the handshaking thread just because a listener
490371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // has a problem.
491371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    Thread thread = Thread.currentThread();
492371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    thread.getUncaughtExceptionHandler().uncaughtException(thread, e);
4932828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                }
4942828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
4952828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        }
49608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
49708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
4985006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks
499f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
500d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root    public void verifyCertificateChain(long sslSessionNativePtr, long[] certRefs, String authMethod)
50198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            throws CertificateException {
50208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        try {
5038d63ff1384e46407a7618df2b79b2b455795c396Alex Klyubin            X509TrustManager x509tm = sslParameters.getX509TrustManager();
5048d63ff1384e46407a7618df2b79b2b455795c396Alex Klyubin            if (x509tm == null) {
5058d63ff1384e46407a7618df2b79b2b455795c396Alex Klyubin                throw new CertificateException("No X.509 TrustManager");
5068d63ff1384e46407a7618df2b79b2b455795c396Alex Klyubin            }
5070e9746b7b132058651155b33f219c7789997985bKenny Root            if (certRefs == null || certRefs.length == 0) {
508371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                throw new SSLException("Peer sent no certificate");
509371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom            }
5100e9746b7b132058651155b33f219c7789997985bKenny Root            OpenSSLX509Certificate[] peerCertChain = new OpenSSLX509Certificate[certRefs.length];
5110e9746b7b132058651155b33f219c7789997985bKenny Root            for (int i = 0; i < certRefs.length; i++) {
5120e9746b7b132058651155b33f219c7789997985bKenny Root                peerCertChain[i] = new OpenSSLX509Certificate(certRefs[i]);
51308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
514d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root
515d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root            // Used for verifyCertificateChain callback
516d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root            handshakeSession = new OpenSSLSessionImpl(sslSessionNativePtr, null, peerCertChain,
517d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root                    getPeerHostName(), getPeerPort(), null);
518d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root
5192828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            boolean client = sslParameters.getUseClientMode();
5202828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            if (client) {
521d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root                if (x509tm instanceof X509ExtendedTrustManager) {
522d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root                    X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) x509tm;
523d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root                    x509etm.checkServerTrusted(peerCertChain, authMethod, this);
524bbe7b9241a63a18bebebf38206d0aebb015f1518Geremy Condra                } else {
5250e9746b7b132058651155b33f219c7789997985bKenny Root                    x509tm.checkServerTrusted(peerCertChain, authMethod);
526bbe7b9241a63a18bebebf38206d0aebb015f1518Geremy Condra                }
5272828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            } else {
5280e9746b7b132058651155b33f219c7789997985bKenny Root                String authType = peerCertChain[0].getPublicKey().getAlgorithm();
529d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root                if (x509tm instanceof X509ExtendedTrustManager) {
530d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root                    X509ExtendedTrustManager x509etm = (X509ExtendedTrustManager) x509tm;
531d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root                    x509etm.checkClientTrusted(peerCertChain, authType, this);
532d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root                } else {
533d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root                    x509tm.checkClientTrusted(peerCertChain, authType);
534d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root                }
53508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
5362828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        } catch (CertificateException e) {
5372828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            throw e;
5382828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        } catch (Exception e) {
5399400b50da5ca8f1e796f5b158063db0aefb58441Brian Carlstrom            throw new CertificateException(e);
540d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root        } finally {
541d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root            // Clear this before notifying handshake completed listeners
542d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root            handshakeSession = null;
54308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
54408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
54508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
546f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
547f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public InputStream getInputStream() throws IOException {
548a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        checkOpen();
5498db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
5508db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        InputStream returnVal;
5518db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
5528db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (state == STATE_CLOSED) {
5538db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                throw new SocketException("Socket is closed.");
5548db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
5558db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
55608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (is == null) {
55708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                is = new SSLInputStream();
55808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
55908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
5608db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            returnVal = is;
56108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
5628db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
5638db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        // Block waiting for a handshake without a lock held. It's possible that the socket
5648db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        // is closed at this point. If that happens, we'll still return the input stream but
5658db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        // all reads on it will throw.
5668db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        waitForHandshake();
5678db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        return returnVal;
56808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
56908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
570f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
571f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public OutputStream getOutputStream() throws IOException {
572a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        checkOpen();
5738db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
5748db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        OutputStream returnVal;
5758db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
5768db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (state == STATE_CLOSED) {
5778db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                throw new SocketException("Socket is closed.");
5788db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
5798db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
58008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (os == null) {
58108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                os = new SSLOutputStream();
58208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
58308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
5848db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            returnVal = os;
5858db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        }
5868db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
5878db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        // Block waiting for a handshake without a lock held. It's possible that the socket
5888db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        // is closed at this point. If that happens, we'll still return the output stream but
5898db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        // all writes on it will throw.
5908db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        waitForHandshake();
5918db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        return returnVal;
5928db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    }
5938db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
5948db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private void assertReadableOrWriteableState() {
5958db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        if (state == STATE_READY || state == STATE_READY_HANDSHAKE_CUT_THROUGH) {
5968db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            return;
5978db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        }
5988db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
5998db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        throw new AssertionError("Invalid state: " + state);
6008db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    }
6018db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6028db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6038db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private void waitForHandshake() throws IOException {
6048db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        startHandshake();
6058db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6068db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
6078db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            while (state != STATE_READY &&
6088db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    state != STATE_READY_HANDSHAKE_CUT_THROUGH &&
6098db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    state != STATE_CLOSED) {
6108db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                try {
6118db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    stateLock.wait();
6128db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                } catch (InterruptedException e) {
6138db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    Thread.currentThread().interrupt();
6148db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    IOException ioe = new IOException("Interrupted waiting for handshake");
6158db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    ioe.initCause(e);
6168db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6178db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    throw ioe;
6188db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                }
6198db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
6208db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6218db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (state == STATE_CLOSED) {
6228db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                throw new SocketException("Socket is closed");
6238db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
62408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
62508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
62608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
6272828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    /**
62808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This inner class provides input data stream functionality
62908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * for the OpenSSL native implementation. It is used to
63008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * read data received via SSL protocol.
63108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
63208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private class SSLInputStream extends InputStream {
6338db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        /**
6348db22531f59b33539647ab95bb76354212d3866aNarayan Kamath         * OpenSSL only lets one thread read at a time, so this is used to
6358db22531f59b33539647ab95bb76354212d3866aNarayan Kamath         * make sure we serialize callers of SSL_read. Thread is already
6368db22531f59b33539647ab95bb76354212d3866aNarayan Kamath         * expected to have completed handshaking.
6378db22531f59b33539647ab95bb76354212d3866aNarayan Kamath         */
6388db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        private final Object readLock = new Object();
6398db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6408db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        SSLInputStream() {
64108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
64208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
64308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
64408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Reads one byte. If there is no data in the underlying buffer,
64508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * this operation can block until the data will be
64608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * available.
64708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @return read value.
6480e9746b7b132058651155b33f219c7789997985bKenny Root         * @throws IOException
64908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
6500b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
65108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        public int read() throws IOException {
6525c44d1fc26c081cf85af010b6e751449bde14b80Brian Carlstrom            return Streams.readSingleByte(this);
65308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
65408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
65508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
65608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
65708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.InputStream#read(byte[],int,int)
65808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
6590b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
66097e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes        public int read(byte[] buf, int offset, int byteCount) throws IOException {
661ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
6628db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6638db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            checkOpen();
6648db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
6658db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (byteCount == 0) {
6668db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                return 0;
6678db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
6688db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
669f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            synchronized (readLock) {
6708db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                synchronized (stateLock) {
6718db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    if (state == STATE_CLOSED) {
6728db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                        throw new SocketException("socket is closed");
6738db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    }
6748db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6758db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    if (DBG_STATE) assertReadableOrWriteableState();
6767b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                }
6778db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
678a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                return NativeCrypto.SSL_read(sslNativePointer, socket.getFileDescriptor$(),
679a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                        OpenSSLSocketImpl.this, buf, offset, byteCount, getSoTimeout());
68008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
68108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
6828db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6838db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        public void awaitPendingOps() {
6848db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (DBG_STATE) {
6858db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                synchronized (stateLock) {
6868db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    if (state != STATE_CLOSED) throw new AssertionError("State is: " + state);
6878db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                }
6888db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
6898db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6908db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            synchronized (readLock) { }
6918db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        }
69208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
69308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
69408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
69508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This inner class provides output data stream functionality
69608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * for the OpenSSL native implementation. It is used to
69708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * write data according to the encryption parameters given in SSL context.
69808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
69908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private class SSLOutputStream extends OutputStream {
7008db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
7018db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        /**
7028db22531f59b33539647ab95bb76354212d3866aNarayan Kamath         * OpenSSL only lets one thread write at a time, so this is used
7038db22531f59b33539647ab95bb76354212d3866aNarayan Kamath         * to make sure we serialize callers of SSL_write. Thread is
7048db22531f59b33539647ab95bb76354212d3866aNarayan Kamath         * already expected to have completed handshaking.
7058db22531f59b33539647ab95bb76354212d3866aNarayan Kamath         */
7068db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        private final Object writeLock = new Object();
7078db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
7088db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        SSLOutputStream() {
70908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
71008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
71108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
71208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
71308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.OutputStream#write(int)
71408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
7150b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
7165c44d1fc26c081cf85af010b6e751449bde14b80Brian Carlstrom        public void write(int oneByte) throws IOException {
7175c44d1fc26c081cf85af010b6e751449bde14b80Brian Carlstrom            Streams.writeSingleByte(this, oneByte);
71808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
71908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
72008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
72108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
72208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.OutputStream#write(byte[],int,int)
72308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
7240b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
72597e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes        public void write(byte[] buf, int offset, int byteCount) throws IOException {
726ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
7278db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            checkOpen();
7288db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
7298db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (byteCount == 0) {
7308db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                return;
7318db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
7328db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
733f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            synchronized (writeLock) {
7348db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                synchronized (stateLock) {
7358db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    if (state == STATE_CLOSED) {
7368db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                        throw new SocketException("socket is closed");
7378db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    }
7388db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
7398db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    if (DBG_STATE) assertReadableOrWriteableState();
7407b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                }
7418db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
742a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                NativeCrypto.SSL_write(sslNativePointer, socket.getFileDescriptor$(),
743fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom                        OpenSSLSocketImpl.this, buf, offset, byteCount, writeTimeoutMilliseconds);
74408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
74508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
7468db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
7478db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
7488db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        public void awaitPendingOps() {
7498db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (DBG_STATE) {
7508db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                synchronized (stateLock) {
7518db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    if (state != STATE_CLOSED) throw new AssertionError("State is: " + state);
7528db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                }
7538db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
7548db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
7558db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            synchronized (writeLock) { }
7568db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        }
75708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
75808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
75908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
760f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
761f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public SSLSession getSession() {
762e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        if (sslSession == null) {
763e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            try {
7648db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                waitForHandshake();
765e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            } catch (IOException e) {
766e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                // return an invalid session with
767e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
768f111f6235d016ce54ab95a2c634a400efe29f24bKenny Root                return SSLNullSession.getNullSession();
769e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            }
77008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
77108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslSession;
77208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
77308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
774f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
775d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root    public SSLSession getHandshakeSession() {
776d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root        return handshakeSession;
777d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root    }
778d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root
779d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root    @Override
780f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void addHandshakeCompletedListener(
78108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            HandshakeCompletedListener listener) {
78208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listener == null) {
78308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
78408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
78508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listeners == null) {
7865006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson            listeners = new ArrayList<HandshakeCompletedListener>();
78708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
78808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        listeners.add(listener);
78908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
79008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
791f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
792f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void removeHandshakeCompletedListener(
79308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            HandshakeCompletedListener listener) {
79408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listener == null) {
79508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
79608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
79708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listeners == null) {
79808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException(
79908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    "Provided listener is not registered");
80008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
80108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (!listeners.remove(listener)) {
80208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException(
80308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    "Provided listener is not registered");
80408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
80508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
80608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
807f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
808f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public boolean getEnableSessionCreation() {
80908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getEnableSessionCreation();
81008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
81108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
812f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
813f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void setEnableSessionCreation(boolean flag) {
81408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setEnableSessionCreation(flag);
81508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
81608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
817f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
818f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public String[] getSupportedCipherSuites() {
819f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        return NativeCrypto.getSupportedCipherSuites();
82008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
82108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
822f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
823f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public String[] getEnabledCipherSuites() {
824f878e438660d93f8689b864165230492e7a412d4Kenny Root        return sslParameters.getEnabledCipherSuites();
82508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
82608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
827f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
828f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void setEnabledCipherSuites(String[] suites) {
829f878e438660d93f8689b864165230492e7a412d4Kenny Root        sslParameters.setEnabledCipherSuites(suites);
83008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
83108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
832f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
833f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public String[] getSupportedProtocols() {
834f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        return NativeCrypto.getSupportedProtocols();
83508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
83608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
837f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
838f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public String[] getEnabledProtocols() {
8393c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        return sslParameters.openSslEnabledProtocols.clone();
84008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
84108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
842f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
843f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void setEnabledProtocols(String[] protocols) {
8443c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        sslParameters.openSslEnabledProtocols = NativeCrypto.checkEnabledProtocols(protocols);
84508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
84608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
84708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
8480b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * This method enables session ticket support.
8490b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
8500b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @param useSessionTickets True to enable session tickets
8510b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8520b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public void setUseSessionTickets(boolean useSessionTickets) {
8533c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        sslParameters.useSessionTickets = useSessionTickets;
8540b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8550b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
8560b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
8570b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * This method enables Server Name Indication
8580b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
8590b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @param hostname the desired SNI hostname, or null to disable
8600b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8610b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public void setHostname(String hostname) {
8623c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        sslParameters.setUseSni(hostname != null);
86357ef6334828dfb4f7f6834ddddf5a0ac61f1a4d0Kenny Root        wrappedHost = hostname;
8640b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8650b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
866577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    /**
867577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * Enables/disables TLS Channel ID for this server socket.
868577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
869577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * <p>This method needs to be invoked before the handshake starts.
870577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
871577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * @throws IllegalStateException if this is a client socket or if the handshake has already
872577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *         started.
873577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin
874577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     */
875577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    public void setChannelIdEnabled(boolean enabled) {
876577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        if (getUseClientMode()) {
877577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin            throw new IllegalStateException("Client mode");
878577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        }
8798db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
8808db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
8818db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (state != STATE_NEW) {
8828db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                throw new IllegalStateException(
8838db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                        "Could not enable/disable Channel ID after the initial handshake has"
8848db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                                + " begun.");
8858db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
886577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        }
8873c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        sslParameters.channelIdEnabled = enabled;
888577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    }
889577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin
890577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    /**
891577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * Gets the TLS Channel ID for this server socket. Channel ID is only available once the
892577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * handshake completes.
893577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
894577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * @return channel ID or {@code null} if not available.
895577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
896577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * @throws IllegalStateException if this is a client socket or if the handshake has not yet
897577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *         completed.
898577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * @throws SSLException if channel ID is available but could not be obtained.
899577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     */
900577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    public byte[] getChannelId() throws SSLException {
901577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        if (getUseClientMode()) {
902577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin            throw new IllegalStateException("Client mode");
903577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        }
9048db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
9058db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
9068db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (state != STATE_READY) {
9078db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                throw new IllegalStateException(
9088db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                        "Channel ID is only available after handshake completes");
9098db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
910577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        }
911577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        return NativeCrypto.SSL_get_tls_channel_id(sslNativePointer);
912577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    }
913577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin
914577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    /**
915577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * Sets the {@link PrivateKey} to be used for TLS Channel ID by this client socket.
916577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
917577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * <p>This method needs to be invoked before the handshake starts.
918577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
919577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key (disables
9204022a5d005758bec373f5b6544fe9be2ef1c0378Alex Klyubin     *        TLS Channel ID). The private key must be an Elliptic Curve (EC) key based on the NIST
921577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *        P-256 curve (aka SECG secp256r1 or ANSI X9.62 prime256v1).
922577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
923577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * @throws IllegalStateException if this is a server socket or if the handshake has already
924577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *         started.
925577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     */
9264022a5d005758bec373f5b6544fe9be2ef1c0378Alex Klyubin    public void setChannelIdPrivateKey(PrivateKey privateKey) {
927577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        if (!getUseClientMode()) {
928577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin            throw new IllegalStateException("Server mode");
929577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        }
9308db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
9318db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
9328db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (state != STATE_NEW) {
9338db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                throw new IllegalStateException(
9348db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                        "Could not change Channel ID private key after the initial handshake has"
9358db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                                + " begun.");
9368db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
937577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        }
9388db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
9391ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root        if (privateKey == null) {
9403c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            sslParameters.channelIdEnabled = false;
9413c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            channelIdPrivateKey = null;
9421ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root        } else {
9433c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            sslParameters.channelIdEnabled = true;
9441ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root            try {
9453c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root                channelIdPrivateKey = OpenSSLKey.fromPrivateKey(privateKey);
9461ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root            } catch (InvalidKeyException e) {
9471ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root                // Will have error in startHandshake
9481ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root            }
9491ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root        }
950577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    }
951577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin
952f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
953f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public boolean getUseClientMode() {
95408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getUseClientMode();
95508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
95608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
957f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
958f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void setUseClientMode(boolean mode) {
9598db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
9608db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (state != STATE_NEW) {
9618db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                throw new IllegalArgumentException(
9628db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                        "Could not change the mode after the initial handshake has begun.");
9638db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
96408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
96508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setUseClientMode(mode);
96608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
96708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
968f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
969f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public boolean getWantClientAuth() {
97008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getWantClientAuth();
97108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
97208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
973f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
974f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public boolean getNeedClientAuth() {
97508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getNeedClientAuth();
97608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
97708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
978f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
979f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void setNeedClientAuth(boolean need) {
98008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setNeedClientAuth(need);
98108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
98208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
983f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
984f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void setWantClientAuth(boolean want) {
98508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setWantClientAuth(want);
98608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
98708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
988f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
989f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void sendUrgentData(int data) throws IOException {
9905006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        throw new SocketException("Method sendUrgentData() is not supported.");
99108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
99208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
993f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
994f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void setOOBInline(boolean on) throws SocketException {
9955006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        throw new SocketException("Methods sendUrgentData, setOOBInline are not supported.");
99608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
99708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
998f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
999f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void setSoTimeout(int readTimeoutMilliseconds) throws SocketException {
1000fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        super.setSoTimeout(readTimeoutMilliseconds);
1001fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        this.readTimeoutMilliseconds = readTimeoutMilliseconds;
100272721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    }
100372721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom
1004f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
1005f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public int getSoTimeout() throws SocketException {
1006fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        return readTimeoutMilliseconds;
1007fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    }
1008fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom
1009fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    /**
1010fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom     * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
1011fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom     */
1012fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    public void setSoWriteTimeout(int writeTimeoutMilliseconds) throws SocketException {
1013fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        this.writeTimeoutMilliseconds = writeTimeoutMilliseconds;
1014fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom
1015fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        StructTimeval tv = StructTimeval.fromMillis(writeTimeoutMilliseconds);
1016fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        try {
1017fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom            Libcore.os.setsockoptTimeval(getFileDescriptor$(), SOL_SOCKET, SO_SNDTIMEO, tv);
1018fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        } catch (ErrnoException errnoException) {
1019fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom            throw errnoException.rethrowAsSocketException();
1020fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        }
1021fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    }
1022fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom
1023fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    /**
1024fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom     * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
1025fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom     */
1026fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    public int getSoWriteTimeout() throws SocketException {
1027fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        return writeTimeoutMilliseconds;
102808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
102908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
1030331900211d05cd282141a3a50cb1db626f418b2cDan Egnor    /**
1031331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     * Set the handshake timeout on this socket.  This timeout is specified in
1032331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     * milliseconds and will be used only during the handshake process.
1033331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     */
1034fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    public void setHandshakeTimeout(int handshakeTimeoutMilliseconds) throws SocketException {
1035fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        this.handshakeTimeoutMilliseconds = handshakeTimeoutMilliseconds;
1036331900211d05cd282141a3a50cb1db626f418b2cDan Egnor    }
1037331900211d05cd282141a3a50cb1db626f418b2cDan Egnor
1038f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
1039f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void close() throws IOException {
10405006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        // TODO: Close SSL sockets using a background thread so they close gracefully.
104108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
10428db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        SSLInputStream sslInputStream = null;
10438db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        SSLOutputStream sslOutputStream = null;
1044f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
10458db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
10468db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (state == STATE_CLOSED) {
10478db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // close() has already been called, so do nothing and return.
10488db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                return;
10498db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
105008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
10518db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            int oldState = state;
10528db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            state = STATE_CLOSED;
10538db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
10548db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (oldState == STATE_NEW) {
10558db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // The handshake hasn't been started yet, so there's no OpenSSL related
10568db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // state to clean up. We still need to close the underlying socket if
10578db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // we're wrapping it and were asked to autoClose.
10588db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                closeUnderlyingSocket();
1059f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
10608db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                stateLock.notifyAll();
106108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                return;
106208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
106308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
10648db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (oldState != STATE_READY && oldState != STATE_READY_HANDSHAKE_CUT_THROUGH) {
10658db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // If we're in these states, we still haven't returned from startHandshake.
10668db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // We call SSL_interrupt so that we can interrupt SSL_do_handshake and then
10678db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // set the state to STATE_CLOSED. startHandshake will handle all cleanup
10688db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // after SSL_do_handshake returns, so we don't have anything to do here.
10698db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                NativeCrypto.SSL_interrupt(sslNativePointer);
107008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
10718db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                stateLock.notifyAll();
10728db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                return;
10738db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
10748db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
10758db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            stateLock.notifyAll();
10768db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            // We've already returned from startHandshake, so we potentially have
10778db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            // input and output streams to clean up.
10788db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            sslInputStream = is;
10798db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            sslOutputStream = os;
10808db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        }
10818db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
10828db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        // Don't bother interrupting unless we have something to interrupt.
10838db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        if (sslInputStream != null || sslOutputStream != null) {
1084fa6657aaf2fadbb1aeb2f869cba82042c1faedeaBrian Carlstrom            NativeCrypto.SSL_interrupt(sslNativePointer);
10858db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        }
10868b352156f879e7b36d223d3f65b8de46b7dc4dcfBrian Carlstrom
10878db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        // Wait for the input and output streams to finish any reads they have in
10888db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        // progress. If there are no reads in progress at this point, future reads will
10898db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        // throw because state == STATE_CLOSED
10908db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        if (sslInputStream != null) {
10918db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            sslInputStream.awaitPendingOps();
10928db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        }
10938db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        if (sslOutputStream != null) {
10948db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            sslOutputStream.awaitPendingOps();
10958db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        }
10968db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
10978db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        shutdownAndFreeSslNative();
10988db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    }
10998db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
11008db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private void shutdownAndFreeSslNative() throws IOException {
11018db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        try {
11028db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            BlockGuard.getThreadPolicy().onNetwork();
11038db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            NativeCrypto.SSL_shutdown(sslNativePointer, socket.getFileDescriptor$(),
11048db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    this);
11058db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        } catch (IOException ignored) {
11068db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            /*
11078db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            * Note that although close() can throw
11088db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            * IOException, the RI does not throw if there
11098db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            * is problem sending a "close notify" which
11108db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            * can happen if the underlying socket is closed.
11118db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            */
11128db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        } finally {
11138db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            free();
11148db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            closeUnderlyingSocket();
11158db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        }
11168db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    }
11178db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
11188db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private void closeUnderlyingSocket() throws IOException {
11198db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        if (socket != this) {
11208db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (autoClose && !socket.isClosed()) {
11218db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                socket.close();
11228db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
11238db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        } else {
11248db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (!super.isClosed()) {
11258db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                super.close();
112608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
112708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
112808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
112908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
1130f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    private void free() {
1131f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        if (sslNativePointer == 0) {
1132f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom            return;
1133f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        }
1134f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        NativeCrypto.SSL_free(sslNativePointer);
1135f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        sslNativePointer = 0;
1136fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        guard.close();
1137f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    }
113808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
1139f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
1140f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    protected void finalize() throws Throwable {
11411990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        try {
11421990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            /*
11431990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * Just worry about our own state. Notably we do not try and
11441990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * close anything. The SocketImpl, either our own
11451990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * PlainSocketImpl, or the Socket we are wrapping, will do
11461990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * that. This might mean we do not properly SSL_shutdown, but
11471990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * if you want to do that, properly close the socket yourself.
11481990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             *
11491990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * The reason why we don't try to SSL_shutdown, is that there
11501990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * can be a race between finalizers where the PlainSocketImpl
11511990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * finalizer runs first and closes the socket. However, in the
11521990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * meanwhile, the underlying file descriptor could be reused
11531990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * for another purpose. If we call SSL_shutdown, the
11541990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * underlying socket BIOs still have the old file descriptor
11551990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * and will write the close notify to some unsuspecting
11561990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * reader.
11571990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             */
1158f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom            if (guard != null) {
1159f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom                guard.warnIfOpen();
1160f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom            }
11611990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            free();
11621990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        } finally {
11631990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            super.finalize();
11641990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        }
116508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
11660648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey
11670648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey    @Override
11680648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey    public FileDescriptor getFileDescriptor$() {
11690648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey        if (socket == this) {
11700648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey            return super.getFileDescriptor$();
11710648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey        } else {
11720648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey            return socket.getFileDescriptor$();
11730648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey        }
11740648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey    }
1175721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson
1176721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    /**
1177721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * Returns the protocol agreed upon by client and server, or null if no
1178721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * protocol was agreed upon.
1179721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     */
1180721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    public byte[] getNpnSelectedProtocol() {
1181263808a68e1538db41196065830107991e9f974aJesse Wilson        return NativeCrypto.SSL_get_npn_negotiated_protocol(sslNativePointer);
1182721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    }
1183721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson
1184721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    /**
11856fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     * Returns the protocol agreed upon by client and server, or {@code null} if
11866fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     * no protocol was agreed upon.
11876fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     */
11886fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root    public byte[] getAlpnSelectedProtocol() {
11896fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root        return NativeCrypto.SSL_get0_alpn_selected(sslNativePointer);
11906fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root    }
11916fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root
11926fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root    /**
1193721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * Sets the list of protocols this peer is interested in. If null no
1194721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * protocols will be used.
1195721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     *
1196d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson     * @param npnProtocols a non-empty array of protocol names. From
1197d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson     *     SSL_select_next_proto, "vector of 8-bit, length prefixed byte
1198d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson     *     strings. The length byte itself is not included in the length. A byte
1199d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson     *     string of length 0 is invalid. No byte string may be truncated.".
1200721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     */
1201721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    public void setNpnProtocols(byte[] npnProtocols) {
1202d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson        if (npnProtocols != null && npnProtocols.length == 0) {
1203d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson            throw new IllegalArgumentException("npnProtocols.length == 0");
1204d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson        }
12053c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        sslParameters.npnProtocols = npnProtocols;
1206721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    }
12076fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root
12086fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root    /**
12096fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     * Sets the list of protocols this peer is interested in. If the list is
12106fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     * {@code null}, no protocols will be used.
12116fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     *
12126fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     * @param alpnProtocols a non-empty array of protocol names. From
12136fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     *            SSL_select_next_proto, "vector of 8-bit, length prefixed byte
12146fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     *            strings. The length byte itself is not included in the length.
12156fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     *            A byte string of length 0 is invalid. No byte string may be
12166fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     *            truncated.".
12176fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     */
12186fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root    public void setAlpnProtocols(byte[] alpnProtocols) {
12196fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root        if (alpnProtocols != null && alpnProtocols.length == 0) {
12206fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root            throw new IllegalArgumentException("alpnProtocols.length == 0");
12216fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root        }
12223c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        sslParameters.alpnProtocols = alpnProtocols;
12232d089e18deae231149737cad6ce00f1e137a7199Alex Klyubin    }
1224d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root
1225d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root    @Override
1226d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root    public SSLParameters getSSLParameters() {
1227d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root        SSLParameters params = super.getSSLParameters();
1228d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root        params.setEndpointIdentificationAlgorithm(
1229d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root                sslParameters.getEndpointIdentificationAlgorithm());
1230d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root        return params;
1231d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root    }
1232d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root
1233d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root    @Override
1234d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root    public void setSSLParameters(SSLParameters p) {
1235d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root        super.setSSLParameters(p);
1236d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root        sslParameters.setEndpointIdentificationAlgorithm(p.getEndpointIdentificationAlgorithm());
1237d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root    }
12383c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root
12393c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root    @Override
12403c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root    public String chooseServerAlias(X509KeyManager keyManager, String keyType) {
12413c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        return keyManager.chooseServerAlias(keyType, null, this);
12423c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root    }
12433c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root
12443c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root    @Override
12453c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root    public String chooseClientAlias(X509KeyManager keyManager, X500Principal[] issuers,
12463c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            String[] keyTypes) {
12473c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        return keyManager.chooseClientAlias(keyTypes, null, this);
12483c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root    }
124908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project}
1250