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
193e46e4ee56c8e37158f46941dedd5b436d724baaKenny Rootimport org.conscrypt.util.Arrays;
20ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrickimport dalvik.system.BlockGuard;
21fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstromimport dalvik.system.CloseGuard;
220648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkeyimport java.io.FileDescriptor;
2308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.io.IOException;
2408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.io.InputStream;
2508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.io.OutputStream;
2608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.net.InetAddress;
2708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.net.Socket;
2808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.net.SocketException;
291ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Rootimport java.security.InvalidKeyException;
3098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstromimport java.security.PrivateKey;
3198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstromimport java.security.SecureRandom;
321f42e0a4d7d28b8fc20833e0be05ad17dcfa8ea0Brian Carlstromimport java.security.cert.CertificateEncodingException;
3308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.security.cert.CertificateException;
3408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.util.ArrayList;
3501cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubinimport javax.crypto.SecretKey;
3608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.HandshakeCompletedEvent;
3708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.HandshakeCompletedListener;
3808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.SSLException;
39edc307bd5a7cf750852b9083ba203ba1c24fcdaeBrian Carlstromimport javax.net.ssl.SSLHandshakeException;
40d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Rootimport javax.net.ssl.SSLParameters;
418765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstromimport javax.net.ssl.SSLProtocolException;
4208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.SSLSession;
438d63ff1384e46407a7618df2b79b2b455795c396Alex Klyubinimport javax.net.ssl.X509KeyManager;
44fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstromimport javax.net.ssl.X509TrustManager;
4598a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstromimport javax.security.auth.x500.X500Principal;
468db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
4708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project/**
480b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * Implementation of the class OpenSSLSocketImpl based on OpenSSL.
490b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <p>
500b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * Extensions to SSLSocket include:
510b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <ul>
520b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>handshake timeout
530b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>session tickets
540b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>Server Name Indication
550b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * </ul>
5608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */
57f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrompublic class OpenSSLSocketImpl
58f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        extends javax.net.ssl.SSLSocket
5901cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin        implements NativeCrypto.SSLHandshakeCallbacks, SSLParametersImpl.AliasChooser,
6001cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin        SSLParametersImpl.PSKCallbacks {
6190ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom
628db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private static final boolean DBG_STATE = false;
638db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6469c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    /**
6569c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom     * Protects handshakeStarted and handshakeCompleted.
6669c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom     */
678db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private final Object stateLock = new Object();
6869c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom
6969c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    /**
708db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * The {@link OpenSSLSocketImpl} object is constructed, but {@link #startHandshake()}
718db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * has not yet been called.
7269c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom     */
738db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private static final int STATE_NEW = 0;
7469c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom
7569c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    /**
768db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * {@link #startHandshake()} has been called at least once.
7769c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom     */
788db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private static final int STATE_HANDSHAKE_STARTED = 1;
7969c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom
8069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    /**
818db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * {@link #handshakeCompleted()} has been called, but {@link #startHandshake()} hasn't
828db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * returned yet.
8369c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom     */
848db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private static final int STATE_HANDSHAKE_COMPLETED = 2;
858db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
868db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    /**
878db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * {@link #startHandshake()} has completed but {@link #handshakeCompleted()} hasn't
888db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * been called. This is expected behaviour in cut-through mode, where SSL_do_handshake
898db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * returns before the handshake is complete. We can now start writing data to the socket.
908db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     */
918db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private static final int STATE_READY_HANDSHAKE_CUT_THROUGH = 3;
9269c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom
9369c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    /**
948db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * {@link #startHandshake()} has completed and {@link #handshakeCompleted()} has been
958db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * called.
9669c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom     */
978db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private static final int STATE_READY = 4;
9869c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom
9969c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    /**
1008db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * {@link #close()} has been called at least once.
10169c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom     */
1028db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private static final int STATE_CLOSED = 5;
1038db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
1048db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    // @GuardedBy("stateLock");
1058db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private int state = STATE_NEW;
10669c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom
10769c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    /**
1088db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * Protected by synchronizing on stateLock. Starts as 0, set by
1098db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * startHandshake, reset to 0 on close.
11069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom     */
1118db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    // @GuardedBy("stateLock");
1128db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private long sslNativePointer;
11369c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom
11469c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    /**
1158db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * Protected by synchronizing on stateLock. Starts as null, set by
1168db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * getInputStream.
11769c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom     */
1188db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    // @GuardedBy("stateLock");
1198db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private SSLInputStream is;
1208db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
1218db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    /**
1228db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * Protected by synchronizing on stateLock. Starts as null, set by
1238db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     * getInputStream.
1248db22531f59b33539647ab95bb76354212d3866aNarayan Kamath     */
1258db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    // @GuardedBy("stateLock");
1268db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private SSLOutputStream os;
12769c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom
12869c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    private final Socket socket;
12969c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    private final boolean autoClose;
130dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root
131dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root    /**
132dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root     * The peer's DNS hostname if it was supplied during creation.
133dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root     */
134dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root    private String peerHostname;
135dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root
136dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root    /**
137dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root     * The DNS hostname from reverse lookup on the socket. Should never be used
138dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root     * for Server Name Indication (SNI).
139dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root     */
140dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root    private String resolvedHostname;
141dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root
142dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root    /**
143dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root     * The peer's port if it was supplied during creation. Should only be set if
144dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root     * {@link #peerHostname} is also set.
145dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root     */
146dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root    private final int peerPort;
147dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root
14869c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    private final SSLParametersImpl sslParameters;
14969c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    private final CloseGuard guard = CloseGuard.get();
15069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom
1513c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root    private ArrayList<HandshakeCompletedListener> listeners;
1522828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
1532828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    /**
1543c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root     * Private key for the TLS Channel ID extension. This field is client-side
1553c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root     * only. Set during startHandshake.
1562828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     */
1573c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root    OpenSSLKey channelIdPrivateKey;
15869c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom
15969c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    /** Set during startHandshake. */
16069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom    private OpenSSLSessionImpl sslSession;
1612828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
162d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root    /** Used during handshake callbacks. */
163d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root    private OpenSSLSessionImpl handshakeSession;
164d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root
16572721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    /**
16672721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     * Local cache of timeout to avoid getsockopt on every read and
16772721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     * write for non-wrapped sockets. Note that
16872721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     * OpenSSLSocketImplWrapper overrides setSoTimeout and
16972721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     * getSoTimeout to delegate to the wrapped socket.
17072721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     */
171fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    private int readTimeoutMilliseconds = 0;
172fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    private int writeTimeoutMilliseconds = 0;
17372721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom
17472721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    private int handshakeTimeoutMilliseconds = -1;  // -1 = same as timeout; 0 = infinite
17508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
176cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    protected OpenSSLSocketImpl(SSLParametersImpl sslParameters) throws IOException {
17790ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
178dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root        this.peerHostname = null;
179dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root        this.peerPort = -1;
18069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.autoClose = false;
18169c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.sslParameters = sslParameters;
18208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
18308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
184dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root    protected OpenSSLSocketImpl(String hostname, int port, SSLParametersImpl sslParameters)
18590ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom            throws IOException {
186dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root        super(hostname, port);
18790ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
188dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root        this.peerHostname = hostname;
189dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root        this.peerPort = port;
19069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.autoClose = false;
19169c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.sslParameters = sslParameters;
19208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
19308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
194cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    protected OpenSSLSocketImpl(InetAddress address, int port, SSLParametersImpl sslParameters)
19590ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom            throws IOException {
19608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        super(address, port);
19790ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
198dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root        this.peerHostname = null;
199dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root        this.peerPort = -1;
20069c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.autoClose = false;
20169c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.sslParameters = sslParameters;
20208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
20308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
20408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
205dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root    protected OpenSSLSocketImpl(String hostname, int port,
206c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom                                InetAddress clientAddress, int clientPort,
2075006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                                SSLParametersImpl sslParameters) throws IOException {
208dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root        super(hostname, port, clientAddress, clientPort);
20990ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
210dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root        this.peerHostname = hostname;
211dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root        this.peerPort = port;
21269c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.autoClose = false;
21369c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.sslParameters = sslParameters;
21408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
21508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
21608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    protected OpenSSLSocketImpl(InetAddress address, int port,
217c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom                                InetAddress clientAddress, int clientPort,
2185006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                                SSLParametersImpl sslParameters) throws IOException {
21908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        super(address, port, clientAddress, clientPort);
22090ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
221dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root        this.peerHostname = null;
222dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root        this.peerPort = -1;
22369c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.autoClose = false;
22469c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.sslParameters = sslParameters;
22508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
22608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
22708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
2285006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson     * Create an SSL socket that wraps another socket. Invoked by
2295006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson     * OpenSSLSocketImplWrapper constructor.
23008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
231dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root    protected OpenSSLSocketImpl(Socket socket, String hostname, int port,
232cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom            boolean autoClose, SSLParametersImpl sslParameters) throws IOException {
23308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        this.socket = socket;
234dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root        this.peerHostname = hostname;
235dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root        this.peerPort = port;
23608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        this.autoClose = autoClose;
23769c9293abd67eee175870a81f9ee24d7bd6acb50Brian Carlstrom        this.sslParameters = sslParameters;
23872721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom
23972721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        // this.timeout is not set intentionally.
24072721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        // OpenSSLSocketImplWrapper.getSoTimeout will delegate timeout
24172721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        // to wrapped socket
242f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    }
243f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
244a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    private void checkOpen() throws SocketException {
245a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        if (isClosed()) {
246a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom            throw new SocketException("Socket is closed");
247a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        }
248a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    }
249a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom
250a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    /**
251d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson     * Starts a TLS/SSL handshake on this connection using some native methods
252d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson     * from the OpenSSL library. It can negotiate new encryption keys, change
253d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson     * cipher suites, or initiate a new session. The certificate chain is
254d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson     * verified if the correspondent property in java.Security is set. All
255d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson     * listeners are notified at the end of the TLS/SSL handshake.
2562828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     */
257f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
258f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void startHandshake() throws IOException {
2598db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        checkOpen();
2608db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
2618db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (state == STATE_NEW) {
2628db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                state = STATE_HANDSHAKE_STARTED;
26308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            } else {
2648db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // We've either started the handshake already or have been closed.
2658db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // Do nothing in both cases.
26608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                return;
26708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
26808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
26908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
27098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        // note that this modifies the global seed, not something specific to the connection
27198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final int seedLengthInBytes = NativeCrypto.RAND_SEED_LENGTH_IN_BYTES;
27298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final SecureRandom secureRandom = sslParameters.getSecureRandomMember();
27398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        if (secureRandom == null) {
27498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            NativeCrypto.RAND_load_file("/dev/urandom", seedLengthInBytes);
27598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        } else {
27698ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            NativeCrypto.RAND_seed(secureRandom.generateSeed(seedLengthInBytes));
27798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        }
27898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
27998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final boolean client = sslParameters.getUseClientMode();
28098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
2818db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        sslNativePointer = 0;
2828db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        boolean releaseResources = true;
283fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        try {
2843c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            final AbstractSessionContext sessionContext = sslParameters.getSessionContext();
2853c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            final long sslCtxNativePointer = sessionContext.sslCtxNativePointer;
286fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer);
287fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            guard.open("close");
28898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
2893c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            boolean enableSessionCreation = getEnableSessionCreation();
290fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (!enableSessionCreation) {
291fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer,
2923c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root                        enableSessionCreation);
2932828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
2942828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
2953c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            final OpenSSLSessionImpl sessionToReuse = sslParameters.getSessionToReuse(
296dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root                    sslNativePointer, getHostname(), getPort());
29701cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin            sslParameters.setSSLParameters(sslCtxNativePointer, sslNativePointer, this, this,
298dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root                    peerHostname);
2993c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            sslParameters.setCertificateValidation(sslNativePointer);
3003c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            sslParameters.setTlsChannelId(sslNativePointer, channelIdPrivateKey);
301f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
302fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // Temporarily use a different timeout for the handshake process
303fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom            int savedReadTimeoutMilliseconds = getSoTimeout();
304fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom            int savedWriteTimeoutMilliseconds = getSoWriteTimeout();
305fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
306fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                setSoTimeout(handshakeTimeoutMilliseconds);
307fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom                setSoWriteTimeout(handshakeTimeoutMilliseconds);
308fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
3092828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
3108db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            synchronized (stateLock) {
3118db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                if (state == STATE_CLOSED) {
3128db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    return;
3138db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                }
3148db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
3158db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
3167dd8d0b433cf8212538aaaf8726f5222abf035ddMatteo Franchin            long sslSessionNativePointer;
317fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            try {
318a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                sslSessionNativePointer = NativeCrypto.SSL_do_handshake(sslNativePointer,
3193e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root                        Platform.getFileDescriptor(socket), this, getSoTimeout(), client,
3203c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root                        sslParameters.npnProtocols, client ? null : sslParameters.alpnProtocols);
321fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            } catch (CertificateException e) {
322d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage());
323d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                wrapper.initCause(e);
324d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                throw wrapper;
3258db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            } catch (SSLException e) {
3268db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // Swallow this exception if it's thrown as the result of an interruption.
3278db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                //
3288db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // TODO: SSL_read and SSL_write return -1 when interrupted, but SSL_do_handshake
3298db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // will throw the last sslError that it saw before sslSelect, usually SSL_WANT_READ
3308db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // (or WANT_WRITE). Catching that exception here doesn't seem much worse than
3318db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // changing the native code to return a "special" native pointer value when that
3328db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // happens.
3338db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                synchronized (stateLock) {
3348db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    if (state == STATE_CLOSED) {
3358db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                        return;
3368db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    }
3378db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                }
3388db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
3392e1be9d876e8c5554f91afee914641f323eebd4crich cannings                // Write CCS errors to EventLog
3402e1be9d876e8c5554f91afee914641f323eebd4crich cannings                String message = e.getMessage();
3412e1be9d876e8c5554f91afee914641f323eebd4crich cannings                // Must match error string of SSL_R_UNEXPECTED_CCS
3422e1be9d876e8c5554f91afee914641f323eebd4crich cannings                if (message.contains("unexpected CCS")) {
3432e1be9d876e8c5554f91afee914641f323eebd4crich cannings                    String logMessage = String.format("ssl_unexpected_ccs: host=%s",
344dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root                            getHostname());
3452e1be9d876e8c5554f91afee914641f323eebd4crich cannings                    Platform.logEvent(logMessage);
3462e1be9d876e8c5554f91afee914641f323eebd4crich cannings                }
3472e1be9d876e8c5554f91afee914641f323eebd4crich cannings
3488db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                throw e;
3492828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
3508db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
3518db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            boolean handshakeCompleted = false;
3528db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            synchronized (stateLock) {
3538db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                if (state == STATE_HANDSHAKE_COMPLETED) {
3548db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    handshakeCompleted = true;
3558db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                } else if (state == STATE_CLOSED) {
3568db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    return;
3578db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                }
3588db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
3598db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
3600dd7db8b85dfd8ad5d16d239432b9852450dc78fKenny Root            sslSession = sslParameters.setupSession(sslSessionNativePointer, sslNativePointer,
361dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root                    sessionToReuse, getHostname(), getPort(), handshakeCompleted);
362fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom
363fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // Restore the original timeout now that the handshake is complete
364fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
365fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom                setSoTimeout(savedReadTimeoutMilliseconds);
366fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom                setSoWriteTimeout(savedWriteTimeoutMilliseconds);
367331900211d05cd282141a3a50cb1db626f418b2cDan Egnor            }
36808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
369fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback
370fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeCompleted) {
371fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                notifyHandshakeCompletedListeners();
372fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
373f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
3748db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            synchronized (stateLock) {
3758db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                releaseResources = (state == STATE_CLOSED);
3768db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
3778db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                if (state == STATE_HANDSHAKE_STARTED) {
3788db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    state = STATE_READY_HANDSHAKE_CUT_THROUGH;
3798db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                } else if (state == STATE_HANDSHAKE_COMPLETED) {
3808db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    state = STATE_READY;
3818db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                }
3828db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
3838db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                if (!releaseResources) {
3848db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    // Unblock threads that are waiting for our state to transition
3858db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    // into STATE_READY or STATE_READY_HANDSHAKE_CUT_THROUGH.
3868db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    stateLock.notifyAll();
3878db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                }
3888db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
3898765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        } catch (SSLProtocolException e) {
3903e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root            throw (SSLHandshakeException) new SSLHandshakeException("Handshake failed")
3913e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root                    .initCause(e);
392fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        } finally {
393aef0b218983e04bc05ffb5746b4f452725f704b7Brian Carlstrom            // on exceptional exit, treat the socket as closed
3948db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (releaseResources) {
3958db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                synchronized (stateLock) {
3968db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    // Mark the socket as closed since we might have reached this as
3978db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    // a result on an exception thrown by the handshake process.
3988db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    //
3998db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    // The state will already be set to closed if we reach this as a result of
4008db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    // an early return or an interruption due to a concurrent call to close().
4018db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    state = STATE_CLOSED;
4028db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    stateLock.notifyAll();
4038db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                }
4048db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
4058db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                try {
4068db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    shutdownAndFreeSslNative();
4078db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                } catch (IOException ignored) {
4088db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
4098db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                }
410fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
41108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
412e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom    }
4133ff2b34d00ea89eec5b895d866fddf05942fd2a7Kenny Root
414dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root    /**
415dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root     * Returns the hostname that was supplied during socket creation or tries to
416dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root     * look up the hostname via the supplied socket address if possible. This
417dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root     * may result in the return of a IP address and should not be used for
418dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root     * Server Name Indication (SNI).
419dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root     */
420dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root    private String getHostname() {
421dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root        if (peerHostname != null) {
422dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root            return peerHostname;
4238ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        }
424dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root        if (resolvedHostname == null) {
425dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root            InetAddress inetAddress = super.getInetAddress();
426dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root            if (inetAddress != null) {
427dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root                resolvedHostname = inetAddress.getHostName();
428dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root            }
4298ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        }
430dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root        return resolvedHostname;
4313967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson    }
4323967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson
433dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root    @Override
434dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root    public int getPort() {
435131640979c0ba3f18581cee9bf5c925ec8a7372bNarayan Kamath        return peerPort == -1 ? super.getPort() : peerPort;
4363967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson    }
4373967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson
438f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
4395006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / client_cert_cb
44098a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom    public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)
441f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            throws CertificateEncodingException, SSLException {
4423c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        sslParameters.chooseClientCertificate(keyTypeBytes, asn1DerEncodedPrincipals,
4433c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root                sslNativePointer, this);
44498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom    }
44598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
446f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
44701cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin    @SuppressWarnings("unused") // used by native psk_client_callback
44801cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin    public int clientPSKKeyRequested(String identityHint, byte[] identity, byte[] key) {
44901cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin        return sslParameters.clientPSKKeyRequested(identityHint, identity, key, this);
45001cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin    }
45101cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin
45201cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin    @Override
45301cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin    @SuppressWarnings("unused") // used by native psk_server_callback
45401cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin    public int serverPSKKeyRequested(String identityHint, String identity, byte[] key) {
45501cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin        return sslParameters.serverPSKKeyRequested(identityHint, identity, key, this);
45601cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin    }
45701cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin
45801cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin    @Override
4595006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / info_callback
460f878e438660d93f8689b864165230492e7a412d4Kenny Root    public void onSSLStateChange(long sslSessionNativePtr, int type, int val) {
461f878e438660d93f8689b864165230492e7a412d4Kenny Root        if (type != NativeCrypto.SSL_CB_HANDSHAKE_DONE) {
462f878e438660d93f8689b864165230492e7a412d4Kenny Root            return;
463f878e438660d93f8689b864165230492e7a412d4Kenny Root        }
464f878e438660d93f8689b864165230492e7a412d4Kenny Root
4658db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
4668db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (state == STATE_HANDSHAKE_STARTED) {
4678db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // If sslSession is null, the handshake was completed during
4688db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // the call to NativeCrypto.SSL_do_handshake and not during a
4698db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // later read operation. That means we do not need to fix up
4708db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // the SSLSession and session cache or notify
4718db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // HandshakeCompletedListeners, it will be done in
4728db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // startHandshake.
4738db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
4748db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                state = STATE_HANDSHAKE_COMPLETED;
4758db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                return;
4768db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            } else if (state == STATE_READY_HANDSHAKE_CUT_THROUGH) {
4778db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // We've returned from startHandshake, which means we've set a sslSession etc.
4788db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // we need to fix them up, which we'll do outside this lock.
4798db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            } else if (state == STATE_CLOSED) {
4808db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // Someone called "close" but the handshake hasn't been interrupted yet.
4818db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                return;
4828db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
4832828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        }
48408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
4852828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // reset session id from the native pointer and update the
4862828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // appropriate cache.
4872828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        sslSession.resetId();
4882828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        AbstractSessionContext sessionContext =
4892828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            (sslParameters.getUseClientMode())
4902828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            ? sslParameters.getClientSessionContext()
4912828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                : sslParameters.getServerSessionContext();
49208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sessionContext.putSession(sslSession);
4932828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
4942828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // let listeners know we are finally done
4952828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        notifyHandshakeCompletedListeners();
4968db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
4978db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
4988db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            // Now that we've fixed up our state, we can tell waiting threads that
4998db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            // we're ready.
5008db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            state = STATE_READY;
5018db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            // Notify all threads waiting for the handshake to complete.
5028db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            stateLock.notifyAll();
5038db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        }
5042828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    }
5052828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
5062828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    private void notifyHandshakeCompletedListeners() {
5072828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        if (listeners != null && !listeners.isEmpty()) {
5082828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            // notify the listeners
5092828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            HandshakeCompletedEvent event =
5102828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                new HandshakeCompletedEvent(this, sslSession);
5112828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            for (HandshakeCompletedListener listener : listeners) {
5122828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                try {
5132828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                    listener.handshakeCompleted(event);
5142828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                } catch (RuntimeException e) {
515371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // The RI runs the handlers in a separate thread,
516371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // which we do not. But we try to preserve their
517371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // behavior of logging a problem and not killing
518371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // the handshaking thread just because a listener
519371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // has a problem.
520371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    Thread thread = Thread.currentThread();
521371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    thread.getUncaughtExceptionHandler().uncaughtException(thread, e);
5222828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                }
5232828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
5242828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        }
52508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
52608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
5275006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks
528f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
529d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root    public void verifyCertificateChain(long sslSessionNativePtr, long[] certRefs, String authMethod)
53098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            throws CertificateException {
53108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        try {
5328d63ff1384e46407a7618df2b79b2b455795c396Alex Klyubin            X509TrustManager x509tm = sslParameters.getX509TrustManager();
5338d63ff1384e46407a7618df2b79b2b455795c396Alex Klyubin            if (x509tm == null) {
5348d63ff1384e46407a7618df2b79b2b455795c396Alex Klyubin                throw new CertificateException("No X.509 TrustManager");
5358d63ff1384e46407a7618df2b79b2b455795c396Alex Klyubin            }
5360e9746b7b132058651155b33f219c7789997985bKenny Root            if (certRefs == null || certRefs.length == 0) {
537371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                throw new SSLException("Peer sent no certificate");
538371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom            }
5390e9746b7b132058651155b33f219c7789997985bKenny Root            OpenSSLX509Certificate[] peerCertChain = new OpenSSLX509Certificate[certRefs.length];
5400e9746b7b132058651155b33f219c7789997985bKenny Root            for (int i = 0; i < certRefs.length; i++) {
5410e9746b7b132058651155b33f219c7789997985bKenny Root                peerCertChain[i] = new OpenSSLX509Certificate(certRefs[i]);
54208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
543d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root
544d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root            // Used for verifyCertificateChain callback
545d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root            handshakeSession = new OpenSSLSessionImpl(sslSessionNativePtr, null, peerCertChain,
546dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root                    getHostname(), getPort(), null);
547d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root
5482828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            boolean client = sslParameters.getUseClientMode();
5492828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            if (client) {
550dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root                Platform.checkServerTrusted(x509tm, peerCertChain, authMethod, getHostname());
5512828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            } else {
5520e9746b7b132058651155b33f219c7789997985bKenny Root                String authType = peerCertChain[0].getPublicKey().getAlgorithm();
553b860016f415dfc5655dcee45f70e8871a2e3edfeBrian Carlstrom                x509tm.checkClientTrusted(peerCertChain, authType);
55408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
5552828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        } catch (CertificateException e) {
5562828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            throw e;
5572828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        } catch (Exception e) {
5589400b50da5ca8f1e796f5b158063db0aefb58441Brian Carlstrom            throw new CertificateException(e);
559d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root        } finally {
560d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root            // Clear this before notifying handshake completed listeners
561d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root            handshakeSession = null;
56208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
56308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
56408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
565f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
566f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public InputStream getInputStream() throws IOException {
567a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        checkOpen();
5688db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
5698db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        InputStream returnVal;
5708db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
5718db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (state == STATE_CLOSED) {
5728db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                throw new SocketException("Socket is closed.");
5738db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
5748db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
57508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (is == null) {
57608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                is = new SSLInputStream();
57708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
57808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
5798db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            returnVal = is;
58008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
5818db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
5828db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        // Block waiting for a handshake without a lock held. It's possible that the socket
5838db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        // is closed at this point. If that happens, we'll still return the input stream but
5848db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        // all reads on it will throw.
5858db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        waitForHandshake();
5868db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        return returnVal;
58708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
58808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
589f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
590f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public OutputStream getOutputStream() throws IOException {
591a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        checkOpen();
5928db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
5938db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        OutputStream returnVal;
5948db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
5958db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (state == STATE_CLOSED) {
5968db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                throw new SocketException("Socket is closed.");
5978db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
5988db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
59908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (os == null) {
60008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                os = new SSLOutputStream();
60108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
60208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
6038db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            returnVal = os;
6048db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        }
6058db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6068db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        // Block waiting for a handshake without a lock held. It's possible that the socket
6078db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        // is closed at this point. If that happens, we'll still return the output stream but
6088db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        // all writes on it will throw.
6098db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        waitForHandshake();
6108db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        return returnVal;
6118db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    }
6128db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6138db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private void assertReadableOrWriteableState() {
6148db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        if (state == STATE_READY || state == STATE_READY_HANDSHAKE_CUT_THROUGH) {
6158db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            return;
6168db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        }
6178db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6188db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        throw new AssertionError("Invalid state: " + state);
6198db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    }
6208db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6218db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6228db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private void waitForHandshake() throws IOException {
6238db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        startHandshake();
6248db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6258db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
6268db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            while (state != STATE_READY &&
6278db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    state != STATE_READY_HANDSHAKE_CUT_THROUGH &&
6288db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    state != STATE_CLOSED) {
6298db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                try {
6308db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    stateLock.wait();
6318db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                } catch (InterruptedException e) {
6328db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    Thread.currentThread().interrupt();
6338db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    IOException ioe = new IOException("Interrupted waiting for handshake");
6348db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    ioe.initCause(e);
6358db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6368db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    throw ioe;
6378db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                }
6388db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
6398db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6408db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (state == STATE_CLOSED) {
6418db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                throw new SocketException("Socket is closed");
6428db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
64308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
64408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
64508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
6462828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    /**
64708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This inner class provides input data stream functionality
64808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * for the OpenSSL native implementation. It is used to
64908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * read data received via SSL protocol.
65008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
65108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private class SSLInputStream extends InputStream {
6528db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        /**
6538db22531f59b33539647ab95bb76354212d3866aNarayan Kamath         * OpenSSL only lets one thread read at a time, so this is used to
6548db22531f59b33539647ab95bb76354212d3866aNarayan Kamath         * make sure we serialize callers of SSL_read. Thread is already
6558db22531f59b33539647ab95bb76354212d3866aNarayan Kamath         * expected to have completed handshaking.
6568db22531f59b33539647ab95bb76354212d3866aNarayan Kamath         */
6578db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        private final Object readLock = new Object();
6588db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6598db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        SSLInputStream() {
66008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
66108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
66208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
66308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Reads one byte. If there is no data in the underlying buffer,
66408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * this operation can block until the data will be
66508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * available.
66608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @return read value.
6670e9746b7b132058651155b33f219c7789997985bKenny Root         * @throws IOException
66808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
6690b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
67008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        public int read() throws IOException {
6713e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root            byte[] buffer = new byte[1];
6723e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root            int result = read(buffer, 0, 1);
6733e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root            return (result != -1) ? buffer[0] & 0xff : -1;
67408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
67508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
67608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
67708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
67808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.InputStream#read(byte[],int,int)
67908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
6800b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
68197e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes        public int read(byte[] buf, int offset, int byteCount) throws IOException {
682ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
6838db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6848db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            checkOpen();
6858db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
6868db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (byteCount == 0) {
6878db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                return 0;
6888db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
6898db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
690f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            synchronized (readLock) {
6918db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                synchronized (stateLock) {
6928db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    if (state == STATE_CLOSED) {
6938db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                        throw new SocketException("socket is closed");
6948db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    }
6958db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6968db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    if (DBG_STATE) assertReadableOrWriteableState();
6977b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                }
6988db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
6993e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root                return NativeCrypto.SSL_read(sslNativePointer, Platform.getFileDescriptor(socket),
700a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                        OpenSSLSocketImpl.this, buf, offset, byteCount, getSoTimeout());
70108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
70208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
7038db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
7048db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        public void awaitPendingOps() {
7058db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (DBG_STATE) {
7068db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                synchronized (stateLock) {
7078db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    if (state != STATE_CLOSED) throw new AssertionError("State is: " + state);
7088db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                }
7098db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
7108db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
7118db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            synchronized (readLock) { }
7128db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        }
71308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
71408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
71508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
71608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This inner class provides output data stream functionality
71708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * for the OpenSSL native implementation. It is used to
71808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * write data according to the encryption parameters given in SSL context.
71908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
72008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private class SSLOutputStream extends OutputStream {
7218db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
7228db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        /**
7238db22531f59b33539647ab95bb76354212d3866aNarayan Kamath         * OpenSSL only lets one thread write at a time, so this is used
7248db22531f59b33539647ab95bb76354212d3866aNarayan Kamath         * to make sure we serialize callers of SSL_write. Thread is
7258db22531f59b33539647ab95bb76354212d3866aNarayan Kamath         * already expected to have completed handshaking.
7268db22531f59b33539647ab95bb76354212d3866aNarayan Kamath         */
7278db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        private final Object writeLock = new Object();
7288db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
7298db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        SSLOutputStream() {
73008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
73108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
73208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
73308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
73408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.OutputStream#write(int)
73508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
7360b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
7375c44d1fc26c081cf85af010b6e751449bde14b80Brian Carlstrom        public void write(int oneByte) throws IOException {
7383e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root            byte[] buffer = new byte[1];
7393e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root            buffer[0] = (byte) (oneByte & 0xff);
7403e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root            write(buffer);
74108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
74208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
74308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
74408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
74508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.OutputStream#write(byte[],int,int)
74608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
7470b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
74897e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes        public void write(byte[] buf, int offset, int byteCount) throws IOException {
749ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
7508db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            checkOpen();
7518db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
7528db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (byteCount == 0) {
7538db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                return;
7548db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
7558db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
756f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            synchronized (writeLock) {
7578db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                synchronized (stateLock) {
7588db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    if (state == STATE_CLOSED) {
7598db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                        throw new SocketException("socket is closed");
7608db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    }
7618db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
7628db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    if (DBG_STATE) assertReadableOrWriteableState();
7637b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                }
7648db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
7653e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root                NativeCrypto.SSL_write(sslNativePointer, Platform.getFileDescriptor(socket),
766fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom                        OpenSSLSocketImpl.this, buf, offset, byteCount, writeTimeoutMilliseconds);
76708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
76808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
7698db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
7708db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
7718db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        public void awaitPendingOps() {
7728db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (DBG_STATE) {
7738db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                synchronized (stateLock) {
7748db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    if (state != STATE_CLOSED) throw new AssertionError("State is: " + state);
7758db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                }
7768db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
7778db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
7788db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            synchronized (writeLock) { }
7798db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        }
78008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
78108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
78208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
783f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
784f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public SSLSession getSession() {
785e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        if (sslSession == null) {
786e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            try {
7878db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                waitForHandshake();
788e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            } catch (IOException e) {
789e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                // return an invalid session with
790e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
791f111f6235d016ce54ab95a2c634a400efe29f24bKenny Root                return SSLNullSession.getNullSession();
792e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            }
79308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
79408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslSession;
79508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
79608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
797d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root    @Override
798f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void addHandshakeCompletedListener(
79908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            HandshakeCompletedListener listener) {
80008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listener == null) {
80108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
80208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
80308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listeners == null) {
8045006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson            listeners = new ArrayList<HandshakeCompletedListener>();
80508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
80608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        listeners.add(listener);
80708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
80808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
809f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
810f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void removeHandshakeCompletedListener(
81108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            HandshakeCompletedListener listener) {
81208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listener == null) {
81308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
81408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
81508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listeners == null) {
81608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException(
81708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    "Provided listener is not registered");
81808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
81908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (!listeners.remove(listener)) {
82008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException(
82108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    "Provided listener is not registered");
82208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
82308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
82408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
825f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
826f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public boolean getEnableSessionCreation() {
82708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getEnableSessionCreation();
82808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
82908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
830f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
831f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void setEnableSessionCreation(boolean flag) {
83208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setEnableSessionCreation(flag);
83308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
83408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
835f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
836f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public String[] getSupportedCipherSuites() {
837f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        return NativeCrypto.getSupportedCipherSuites();
83808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
83908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
840f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
841f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public String[] getEnabledCipherSuites() {
842f878e438660d93f8689b864165230492e7a412d4Kenny Root        return sslParameters.getEnabledCipherSuites();
84308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
84408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
845f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
846f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void setEnabledCipherSuites(String[] suites) {
847f878e438660d93f8689b864165230492e7a412d4Kenny Root        sslParameters.setEnabledCipherSuites(suites);
84808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
84908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
850f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
851f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public String[] getSupportedProtocols() {
852f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        return NativeCrypto.getSupportedProtocols();
85308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
85408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
855f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
856f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public String[] getEnabledProtocols() {
857ae2ecac00779167b0381c48da7c612567d1c646fAlex Klyubin        return sslParameters.getEnabledProtocols();
85808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
85908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
860f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
861f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void setEnabledProtocols(String[] protocols) {
862ae2ecac00779167b0381c48da7c612567d1c646fAlex Klyubin        sslParameters.setEnabledProtocols(protocols);
86308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
86408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
86508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
8660b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * This method enables session ticket support.
8670b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
8680b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @param useSessionTickets True to enable session tickets
8690b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8700b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public void setUseSessionTickets(boolean useSessionTickets) {
8713c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        sslParameters.useSessionTickets = useSessionTickets;
8720b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8730b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
8740b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
8750b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * This method enables Server Name Indication
8760b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
8770b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @param hostname the desired SNI hostname, or null to disable
8780b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8790b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public void setHostname(String hostname) {
8803c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        sslParameters.setUseSni(hostname != null);
881dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root        peerHostname = hostname;
8820b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8830b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
884577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    /**
885577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * Enables/disables TLS Channel ID for this server socket.
886577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
887577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * <p>This method needs to be invoked before the handshake starts.
888577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
889577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * @throws IllegalStateException if this is a client socket or if the handshake has already
890577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *         started.
891577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin
892577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     */
893577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    public void setChannelIdEnabled(boolean enabled) {
894577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        if (getUseClientMode()) {
895577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin            throw new IllegalStateException("Client mode");
896577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        }
8978db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
8988db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
8998db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (state != STATE_NEW) {
9008db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                throw new IllegalStateException(
9018db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                        "Could not enable/disable Channel ID after the initial handshake has"
9028db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                                + " begun.");
9038db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
904577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        }
9053c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        sslParameters.channelIdEnabled = enabled;
906577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    }
907577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin
908577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    /**
909577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * Gets the TLS Channel ID for this server socket. Channel ID is only available once the
910577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * handshake completes.
911577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
912577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * @return channel ID or {@code null} if not available.
913577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
914577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * @throws IllegalStateException if this is a client socket or if the handshake has not yet
915577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *         completed.
916577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * @throws SSLException if channel ID is available but could not be obtained.
917577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     */
918577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    public byte[] getChannelId() throws SSLException {
919577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        if (getUseClientMode()) {
920577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin            throw new IllegalStateException("Client mode");
921577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        }
9228db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
9238db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
9248db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (state != STATE_READY) {
9258db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                throw new IllegalStateException(
9268db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                        "Channel ID is only available after handshake completes");
9278db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
928577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        }
929577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        return NativeCrypto.SSL_get_tls_channel_id(sslNativePointer);
930577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    }
931577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin
932577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    /**
933577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * Sets the {@link PrivateKey} to be used for TLS Channel ID by this client socket.
934577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
935577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * <p>This method needs to be invoked before the handshake starts.
936577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
937577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key (disables
9384022a5d005758bec373f5b6544fe9be2ef1c0378Alex Klyubin     *        TLS Channel ID). The private key must be an Elliptic Curve (EC) key based on the NIST
939577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *        P-256 curve (aka SECG secp256r1 or ANSI X9.62 prime256v1).
940577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
941577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * @throws IllegalStateException if this is a server socket or if the handshake has already
942577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *         started.
943577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     */
9444022a5d005758bec373f5b6544fe9be2ef1c0378Alex Klyubin    public void setChannelIdPrivateKey(PrivateKey privateKey) {
945577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        if (!getUseClientMode()) {
946577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin            throw new IllegalStateException("Server mode");
947577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        }
9488db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
9498db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
9508db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (state != STATE_NEW) {
9518db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                throw new IllegalStateException(
9528db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                        "Could not change Channel ID private key after the initial handshake has"
9538db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                                + " begun.");
9548db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
955577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        }
9568db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
9571ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root        if (privateKey == null) {
9583c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            sslParameters.channelIdEnabled = false;
9593c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            channelIdPrivateKey = null;
9601ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root        } else {
9613c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            sslParameters.channelIdEnabled = true;
9621ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root            try {
9633c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root                channelIdPrivateKey = OpenSSLKey.fromPrivateKey(privateKey);
9641ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root            } catch (InvalidKeyException e) {
9651ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root                // Will have error in startHandshake
9661ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root            }
9671ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root        }
968577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    }
969577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin
970f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
971f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public boolean getUseClientMode() {
97208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getUseClientMode();
97308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
97408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
975f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
976f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void setUseClientMode(boolean mode) {
9778db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
9788db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (state != STATE_NEW) {
9798db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                throw new IllegalArgumentException(
9808db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                        "Could not change the mode after the initial handshake has begun.");
9818db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
98208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
98308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setUseClientMode(mode);
98408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
98508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
986f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
987f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public boolean getWantClientAuth() {
98808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getWantClientAuth();
98908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
99008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
991f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
992f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public boolean getNeedClientAuth() {
99308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getNeedClientAuth();
99408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
99508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
996f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
997f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void setNeedClientAuth(boolean need) {
99808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setNeedClientAuth(need);
99908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
100008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
1001f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
1002f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void setWantClientAuth(boolean want) {
100308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setWantClientAuth(want);
100408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
100508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
1006f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
1007f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void sendUrgentData(int data) throws IOException {
10085006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        throw new SocketException("Method sendUrgentData() is not supported.");
100908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
101008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
1011f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
1012f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void setOOBInline(boolean on) throws SocketException {
10135006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        throw new SocketException("Methods sendUrgentData, setOOBInline are not supported.");
101408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
101508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
1016f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
1017f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void setSoTimeout(int readTimeoutMilliseconds) throws SocketException {
1018fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        super.setSoTimeout(readTimeoutMilliseconds);
1019fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        this.readTimeoutMilliseconds = readTimeoutMilliseconds;
102072721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    }
102172721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom
1022f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
1023f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public int getSoTimeout() throws SocketException {
1024fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        return readTimeoutMilliseconds;
1025fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    }
1026fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom
1027fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    /**
1028fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom     * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
1029fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom     */
1030fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    public void setSoWriteTimeout(int writeTimeoutMilliseconds) throws SocketException {
1031fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        this.writeTimeoutMilliseconds = writeTimeoutMilliseconds;
1032fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom
1033dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root        Platform.setSocketWriteTimeout(this, writeTimeoutMilliseconds);
1034fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    }
1035fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom
1036fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    /**
1037fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom     * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
1038fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom     */
1039fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    public int getSoWriteTimeout() throws SocketException {
1040fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        return writeTimeoutMilliseconds;
104108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
104208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
1043331900211d05cd282141a3a50cb1db626f418b2cDan Egnor    /**
1044331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     * Set the handshake timeout on this socket.  This timeout is specified in
1045331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     * milliseconds and will be used only during the handshake process.
1046331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     */
1047fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    public void setHandshakeTimeout(int handshakeTimeoutMilliseconds) throws SocketException {
1048fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        this.handshakeTimeoutMilliseconds = handshakeTimeoutMilliseconds;
1049331900211d05cd282141a3a50cb1db626f418b2cDan Egnor    }
1050331900211d05cd282141a3a50cb1db626f418b2cDan Egnor
1051f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
1052f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    public void close() throws IOException {
10535006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        // TODO: Close SSL sockets using a background thread so they close gracefully.
105408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
10558db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        SSLInputStream sslInputStream = null;
10568db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        SSLOutputStream sslOutputStream = null;
1057f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
10588db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        synchronized (stateLock) {
10598db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (state == STATE_CLOSED) {
10608db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // close() has already been called, so do nothing and return.
10618db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                return;
10628db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
106308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
10648db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            int oldState = state;
10658db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            state = STATE_CLOSED;
10668db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
10678db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (oldState == STATE_NEW) {
10688db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // The handshake hasn't been started yet, so there's no OpenSSL related
10698db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // state to clean up. We still need to close the underlying socket if
10708db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // we're wrapping it and were asked to autoClose.
10718db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                closeUnderlyingSocket();
1072f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
10738db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                stateLock.notifyAll();
107408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                return;
107508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
107608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
10778db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (oldState != STATE_READY && oldState != STATE_READY_HANDSHAKE_CUT_THROUGH) {
10788db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // If we're in these states, we still haven't returned from startHandshake.
10798db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // We call SSL_interrupt so that we can interrupt SSL_do_handshake and then
10808db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // set the state to STATE_CLOSED. startHandshake will handle all cleanup
10818db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                // after SSL_do_handshake returns, so we don't have anything to do here.
10828db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                NativeCrypto.SSL_interrupt(sslNativePointer);
108308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
10848db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                stateLock.notifyAll();
10858db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                return;
10868db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
10878db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
10888db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            stateLock.notifyAll();
10898db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            // We've already returned from startHandshake, so we potentially have
10908db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            // input and output streams to clean up.
10918db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            sslInputStream = is;
10928db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            sslOutputStream = os;
10938db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        }
10948db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
10958db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        // Don't bother interrupting unless we have something to interrupt.
10968db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        if (sslInputStream != null || sslOutputStream != null) {
1097fa6657aaf2fadbb1aeb2f869cba82042c1faedeaBrian Carlstrom            NativeCrypto.SSL_interrupt(sslNativePointer);
10988db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        }
10998b352156f879e7b36d223d3f65b8de46b7dc4dcfBrian Carlstrom
11008db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        // Wait for the input and output streams to finish any reads they have in
11018db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        // progress. If there are no reads in progress at this point, future reads will
11028db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        // throw because state == STATE_CLOSED
11038db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        if (sslInputStream != null) {
11048db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            sslInputStream.awaitPendingOps();
11058db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        }
11068db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        if (sslOutputStream != null) {
11078db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            sslOutputStream.awaitPendingOps();
11088db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        }
11098db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
11108db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        shutdownAndFreeSslNative();
11118db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    }
11128db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
11138db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private void shutdownAndFreeSslNative() throws IOException {
11148db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        try {
11158db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            BlockGuard.getThreadPolicy().onNetwork();
11163e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root            NativeCrypto.SSL_shutdown(sslNativePointer, Platform.getFileDescriptor(socket),
11178db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                    this);
11188db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        } catch (IOException ignored) {
11198db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            /*
11208db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            * Note that although close() can throw
11218db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            * IOException, the RI does not throw if there
11228db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            * is problem sending a "close notify" which
11238db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            * can happen if the underlying socket is closed.
11248db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            */
11258db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        } finally {
11268db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            free();
11278db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            closeUnderlyingSocket();
11288db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        }
11298db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    }
11308db22531f59b33539647ab95bb76354212d3866aNarayan Kamath
11318db22531f59b33539647ab95bb76354212d3866aNarayan Kamath    private void closeUnderlyingSocket() throws IOException {
11328db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        if (socket != this) {
11338db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (autoClose && !socket.isClosed()) {
11348db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                socket.close();
11358db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            }
11368db22531f59b33539647ab95bb76354212d3866aNarayan Kamath        } else {
11378db22531f59b33539647ab95bb76354212d3866aNarayan Kamath            if (!super.isClosed()) {
11388db22531f59b33539647ab95bb76354212d3866aNarayan Kamath                super.close();
113908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
114008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
114108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
114208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
1143f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    private void free() {
1144f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        if (sslNativePointer == 0) {
1145f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom            return;
1146f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        }
1147f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        NativeCrypto.SSL_free(sslNativePointer);
1148f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        sslNativePointer = 0;
1149fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        guard.close();
1150f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    }
115108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
1152f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    @Override
1153f06338c01394610174fe2b3532beac56d61d9e26Kenny Root    protected void finalize() throws Throwable {
11541990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        try {
11551990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            /*
11561990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * Just worry about our own state. Notably we do not try and
11571990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * close anything. The SocketImpl, either our own
11581990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * PlainSocketImpl, or the Socket we are wrapping, will do
11591990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * that. This might mean we do not properly SSL_shutdown, but
11601990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * if you want to do that, properly close the socket yourself.
11611990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             *
11621990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * The reason why we don't try to SSL_shutdown, is that there
11631990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * can be a race between finalizers where the PlainSocketImpl
11641990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * finalizer runs first and closes the socket. However, in the
11651990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * meanwhile, the underlying file descriptor could be reused
11661990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * for another purpose. If we call SSL_shutdown, the
11671990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * underlying socket BIOs still have the old file descriptor
11681990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * and will write the close notify to some unsuspecting
11691990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * reader.
11701990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             */
1171f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom            if (guard != null) {
1172f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom                guard.warnIfOpen();
1173f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom            }
11741990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            free();
11751990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        } finally {
11761990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            super.finalize();
11771990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        }
117808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
11790648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey
11803e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root    /* @Override */
11810648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey    public FileDescriptor getFileDescriptor$() {
11820648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey        if (socket == this) {
11833e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root            return Platform.getFileDescriptorFromSSLSocket(this);
11840648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey        } else {
11853e46e4ee56c8e37158f46941dedd5b436d724baaKenny Root            return Platform.getFileDescriptor(socket);
11860648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey        }
11870648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey    }
1188721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson
1189721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    /**
1190721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * Returns the protocol agreed upon by client and server, or null if no
1191721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * protocol was agreed upon.
1192721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     */
1193721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    public byte[] getNpnSelectedProtocol() {
1194263808a68e1538db41196065830107991e9f974aJesse Wilson        return NativeCrypto.SSL_get_npn_negotiated_protocol(sslNativePointer);
1195721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    }
1196721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson
1197721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    /**
11986fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     * Returns the protocol agreed upon by client and server, or {@code null} if
11996fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     * no protocol was agreed upon.
12006fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     */
12016fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root    public byte[] getAlpnSelectedProtocol() {
12026fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root        return NativeCrypto.SSL_get0_alpn_selected(sslNativePointer);
12036fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root    }
12046fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root
12056fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root    /**
1206721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * Sets the list of protocols this peer is interested in. If null no
1207721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * protocols will be used.
1208721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     *
1209d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson     * @param npnProtocols a non-empty array of protocol names. From
1210d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson     *     SSL_select_next_proto, "vector of 8-bit, length prefixed byte
1211d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson     *     strings. The length byte itself is not included in the length. A byte
1212d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson     *     string of length 0 is invalid. No byte string may be truncated.".
1213721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     */
1214721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    public void setNpnProtocols(byte[] npnProtocols) {
1215d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson        if (npnProtocols != null && npnProtocols.length == 0) {
1216d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson            throw new IllegalArgumentException("npnProtocols.length == 0");
1217d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson        }
12183c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        sslParameters.npnProtocols = npnProtocols;
1219721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    }
12206fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root
12216fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root    /**
12226fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     * Sets the list of protocols this peer is interested in. If the list is
12236fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     * {@code null}, no protocols will be used.
12246fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     *
12256fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     * @param alpnProtocols a non-empty array of protocol names. From
12266fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     *            SSL_select_next_proto, "vector of 8-bit, length prefixed byte
12276fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     *            strings. The length byte itself is not included in the length.
12286fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     *            A byte string of length 0 is invalid. No byte string may be
12296fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     *            truncated.".
12306fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     */
12316fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root    public void setAlpnProtocols(byte[] alpnProtocols) {
12326fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root        if (alpnProtocols != null && alpnProtocols.length == 0) {
12336fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root            throw new IllegalArgumentException("alpnProtocols.length == 0");
12346fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root        }
12353c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        sslParameters.alpnProtocols = alpnProtocols;
12362d089e18deae231149737cad6ce00f1e137a7199Alex Klyubin    }
1237d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root
1238d2cced8b10f5e4f600a5eb9464eba0da7c8f09deKenny Root    @Override
12393c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root    public String chooseServerAlias(X509KeyManager keyManager, String keyType) {
12403c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        return keyManager.chooseServerAlias(keyType, null, this);
12413c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root    }
12423c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root
12433c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root    @Override
12443c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root    public String chooseClientAlias(X509KeyManager keyManager, X500Principal[] issuers,
12453c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root            String[] keyTypes) {
12463c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root        return keyManager.chooseClientAlias(keyTypes, null, this);
12473c072fb087eaa1a363fc673c60f5ef65390e356fKenny Root    }
124801cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin
124901cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin    @Override
125001cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin    public String chooseServerPSKIdentityHint(PSKKeyManager keyManager) {
125101cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin        return keyManager.chooseServerKeyIdentityHint(this);
125201cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin    }
125301cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin
125401cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin    @Override
125501cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin    public String chooseClientPSKIdentity(PSKKeyManager keyManager, String identityHint) {
125601cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin        return keyManager.chooseClientKeyIdentity(identityHint, this);
125701cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin    }
125801cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin
125901cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin    @Override
126001cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin    public SecretKey getPSKKey(PSKKeyManager keyManager, String identityHint, String identity) {
126101cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin        return keyManager.getKey(identityHint, identity, this);
126201cce891dd313a0fb9d4694283f2a13fb5c43afeAlex Klyubin    }
126308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project}
1264