OpenSSLSocketImpl.java revision 6fcf0cbeec79d1f2491d8d0774fdb314fc419ba3
108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project/*
208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project *
408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * you may not use this file except in compliance with the License.
608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * You may obtain a copy of the License at
708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project *
808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project *
1008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * See the License for the specific language governing permissions and
1408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * limitations under the License.
1508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */
1608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
17860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootpackage org.conscrypt;
1808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
19ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrickimport dalvik.system.BlockGuard;
20fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstromimport dalvik.system.CloseGuard;
210648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkeyimport java.io.FileDescriptor;
2208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.io.IOException;
2308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.io.InputStream;
2408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.io.OutputStream;
2508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.net.InetAddress;
2608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.net.Socket;
2708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.net.SocketException;
281ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Rootimport java.security.InvalidKeyException;
2998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstromimport java.security.PrivateKey;
3098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstromimport java.security.SecureRandom;
311f42e0a4d7d28b8fc20833e0be05ad17dcfa8ea0Brian Carlstromimport java.security.cert.CertificateEncodingException;
3208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.security.cert.CertificateException;
3308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.security.cert.X509Certificate;
3408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.util.ArrayList;
3597e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughesimport java.util.Arrays;
36d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstromimport java.util.HashSet;
37d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstromimport java.util.Set;
3808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.HandshakeCompletedEvent;
3908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.HandshakeCompletedListener;
4008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.SSLException;
41edc307bd5a7cf750852b9083ba203ba1c24fcdaeBrian Carlstromimport javax.net.ssl.SSLHandshakeException;
42a5c365c0867e66e6b5ad8e3e9a1cbd306f35226bBrian Carlstromimport javax.net.ssl.SSLPeerUnverifiedException;
438765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstromimport javax.net.ssl.SSLProtocolException;
4408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.SSLSession;
45fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstromimport javax.net.ssl.X509TrustManager;
4698a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstromimport javax.security.auth.x500.X500Principal;
47fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstromimport static libcore.io.OsConstants.*;
48fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstromimport libcore.io.ErrnoException;
49fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstromimport libcore.io.Libcore;
505c44d1fc26c081cf85af010b6e751449bde14b80Brian Carlstromimport libcore.io.Streams;
51fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstromimport libcore.io.StructTimeval;
5208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
5308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project/**
540b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * Implementation of the class OpenSSLSocketImpl based on OpenSSL.
550b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <p>
560b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * Extensions to SSLSocket include:
570b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <ul>
580b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>handshake timeout
590b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>session tickets
600b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>Server Name Indication
610b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * </ul>
6208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */
63f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrompublic class OpenSSLSocketImpl
64f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        extends javax.net.ssl.SSLSocket
6598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        implements NativeCrypto.SSLHandshakeCallbacks {
6690ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom
6738c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice    private long sslNativePointer;
6808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private InputStream is;
6908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private OutputStream os;
7008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private final Object handshakeLock = new Object();
71f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    private final Object readLock = new Object();
72f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    private final Object writeLock = new Object();
73cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    private SSLParametersImpl sslParameters;
74721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    private byte[] npnProtocols;
756fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root    private byte[] alpnProtocols;
762828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    private String[] enabledProtocols;
772828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    private String[] enabledCipherSuites;
780b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    private boolean useSessionTickets;
790b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    private String hostname;
80577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    /** Whether the TLS Channel ID extension is enabled. This field is server-side only. */
81577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    private boolean channelIdEnabled;
82577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    /** Private key for the TLS Channel ID extension. This field is client-side only. */
831ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root    private OpenSSLKey channelIdPrivateKey;
8408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private OpenSSLSessionImpl sslSession;
8590ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom    private final Socket socket;
8608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private boolean autoClose;
8708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private boolean handshakeStarted = false;
88f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom    private final CloseGuard guard = CloseGuard.get();
892828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
902828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    /**
912828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * Not set to true until the update from native that tells us the
922828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * full handshake is complete, since SSL_do_handshake can return
932828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * before the handshake is completely done due to
942828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * handshake_cutthrough support.
952828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     */
962828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    private boolean handshakeCompleted = false;
972828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
9808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private ArrayList<HandshakeCompletedListener> listeners;
9972721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom
10072721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    /**
10172721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     * Local cache of timeout to avoid getsockopt on every read and
10272721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     * write for non-wrapped sockets. Note that
10372721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     * OpenSSLSocketImplWrapper overrides setSoTimeout and
10472721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     * getSoTimeout to delegate to the wrapped socket.
10572721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     */
106fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    private int readTimeoutMilliseconds = 0;
107fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    private int writeTimeoutMilliseconds = 0;
10872721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom
10972721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    private int handshakeTimeoutMilliseconds = -1;  // -1 = same as timeout; 0 = infinite
1106e0361de414915ae9929f55f6a8e0266a67506efBrian Carlstrom    private String wrappedHost;
1116e0361de414915ae9929f55f6a8e0266a67506efBrian Carlstrom    private int wrappedPort;
11208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
113cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    protected OpenSSLSocketImpl(SSLParametersImpl sslParameters) throws IOException {
11490ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
115f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        init(sslParameters);
11608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
11708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
118cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    protected OpenSSLSocketImpl(SSLParametersImpl sslParameters,
1192828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                                String[] enabledProtocols,
1205ea53c028b903ce252e08c1b67508ce8dafcff34Brian Carlstrom                                String[] enabledCipherSuites) throws IOException {
12190ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
1225ea53c028b903ce252e08c1b67508ce8dafcff34Brian Carlstrom        init(sslParameters, enabledProtocols, enabledCipherSuites);
1232828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    }
1242828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
125cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    protected OpenSSLSocketImpl(String host, int port, SSLParametersImpl sslParameters)
12690ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom            throws IOException {
12708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        super(host, port);
12890ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
129f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        init(sslParameters);
13008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
13108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
132cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    protected OpenSSLSocketImpl(InetAddress address, int port, SSLParametersImpl sslParameters)
13390ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom            throws IOException {
13408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        super(address, port);
13590ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
136f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        init(sslParameters);
13708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
13808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
13908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
140c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom    protected OpenSSLSocketImpl(String host, int port,
141c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom                                InetAddress clientAddress, int clientPort,
1425006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                                SSLParametersImpl sslParameters) throws IOException {
14308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        super(host, port, clientAddress, clientPort);
14490ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
145f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        init(sslParameters);
14608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
14708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
14808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    protected OpenSSLSocketImpl(InetAddress address, int port,
149c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom                                InetAddress clientAddress, int clientPort,
1505006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                                SSLParametersImpl sslParameters) throws IOException {
15108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        super(address, port, clientAddress, clientPort);
15290ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
153f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        init(sslParameters);
15408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
15508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
15608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
1575006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson     * Create an SSL socket that wraps another socket. Invoked by
1585006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson     * OpenSSLSocketImplWrapper constructor.
15908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
16008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    protected OpenSSLSocketImpl(Socket socket, String host, int port,
161cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom            boolean autoClose, SSLParametersImpl sslParameters) throws IOException {
16208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        this.socket = socket;
1636e0361de414915ae9929f55f6a8e0266a67506efBrian Carlstrom        this.wrappedHost = host;
1646e0361de414915ae9929f55f6a8e0266a67506efBrian Carlstrom        this.wrappedPort = port;
16508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        this.autoClose = autoClose;
166f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        init(sslParameters);
16772721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom
16872721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        // this.timeout is not set intentionally.
16972721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        // OpenSSLSocketImplWrapper.getSoTimeout will delegate timeout
17072721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        // to wrapped socket
171f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    }
172f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
173f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    /**
174f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom     * Initialize the SSL socket and set the certificates for the
175f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom     * future handshaking.
176f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom     */
177cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    private void init(SSLParametersImpl sslParameters) throws IOException {
1782828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        init(sslParameters,
1797fce41e05553f8edd1468a68eafb40249a6337cbBrian Carlstrom             NativeCrypto.getDefaultProtocols(),
1805ea53c028b903ce252e08c1b67508ce8dafcff34Brian Carlstrom             NativeCrypto.getDefaultCipherSuites());
181f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    }
182f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
183f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    /**
1842828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * Initialize the SSL socket and set the certificates for the
1852828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * future handshaking.
186f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom     */
187cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    private void init(SSLParametersImpl sslParameters,
1882828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                      String[] enabledProtocols,
1895ea53c028b903ce252e08c1b67508ce8dafcff34Brian Carlstrom                      String[] enabledCipherSuites) throws IOException {
1902828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        this.sslParameters = sslParameters;
1912828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        this.enabledProtocols = enabledProtocols;
1922828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        this.enabledCipherSuites = enabledCipherSuites;
19308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
19408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
19508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
19608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Gets the suitable session reference from the session cache container.
19708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
1982828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    private OpenSSLSessionImpl getCachedClientSession(ClientSessionContext sessionContext) {
1993967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson        String hostName = getPeerHostName();
2003967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson        int port = getPeerPort();
2013967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson        if (hostName == null) {
20208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return null;
20308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
2043967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson        OpenSSLSessionImpl session = (OpenSSLSessionImpl) sessionContext.getSession(hostName, port);
20561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        if (session == null) {
20661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            return null;
20761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
20861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom
20961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        String protocol = session.getProtocol();
21061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        boolean protocolFound = false;
21161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        for (String enabledProtocol : enabledProtocols) {
21261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            if (protocol.equals(enabledProtocol)) {
21361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                protocolFound = true;
21461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                break;
21561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            }
21661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
21761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        if (!protocolFound) {
21861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            return null;
21961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
22061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom
22161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        String cipherSuite = session.getCipherSuite();
22261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        boolean cipherSuiteFound = false;
22361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        for (String enabledCipherSuite : enabledCipherSuites) {
22461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            if (cipherSuite.equals(enabledCipherSuite)) {
22561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                cipherSuiteFound = true;
22661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                break;
22761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            }
22861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
22961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        if (!cipherSuiteFound) {
23061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            return null;
23161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
23298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
23361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        return session;
23408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
23508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
236a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    private void checkOpen() throws SocketException {
237a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        if (isClosed()) {
238a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom            throw new SocketException("Socket is closed");
239a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        }
240a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    }
241a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom
242a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    /**
243d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson     * Starts a TLS/SSL handshake on this connection using some native methods
244d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson     * from the OpenSSL library. It can negotiate new encryption keys, change
245d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson     * cipher suites, or initiate a new session. The certificate chain is
246d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson     * verified if the correspondent property in java.Security is set. All
247d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson     * listeners are notified at the end of the TLS/SSL handshake.
2482828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     */
249d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson    @Override public synchronized void startHandshake() throws IOException {
25008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        synchronized (handshakeLock) {
2517b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom            checkOpen();
25208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (!handshakeStarted) {
25308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                handshakeStarted = true;
25408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            } else {
25508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                return;
25608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
25708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
25808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
25998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        // note that this modifies the global seed, not something specific to the connection
26098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final int seedLengthInBytes = NativeCrypto.RAND_SEED_LENGTH_IN_BYTES;
26198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final SecureRandom secureRandom = sslParameters.getSecureRandomMember();
26298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        if (secureRandom == null) {
26398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            NativeCrypto.RAND_load_file("/dev/urandom", seedLengthInBytes);
26498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        } else {
26598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            NativeCrypto.RAND_seed(secureRandom.generateSeed(seedLengthInBytes));
26698ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        }
26798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
26898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final boolean client = sslParameters.getUseClientMode();
26998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
27038c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice        final long sslCtxNativePointer = (client) ?
27198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            sslParameters.getClientSessionContext().sslCtxNativePointer :
27298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            sslParameters.getServerSessionContext().sslCtxNativePointer;
27398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
274fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        this.sslNativePointer = 0;
275fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        boolean exception = true;
276fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        try {
277fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer);
278fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            guard.open("close");
27998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
280721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson            if (npnProtocols != null) {
281721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson                NativeCrypto.SSL_CTX_enable_npn(sslCtxNativePointer);
282721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson            }
283721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson
2846fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root            if (client && alpnProtocols != null) {
2856fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root                NativeCrypto.SSL_CTX_set_alpn_protos(sslCtxNativePointer, alpnProtocols);
2866fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root            }
2876fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root
288fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // setup server certificates and private keys.
289fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // clients will receive a call back to request certificates.
290fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (!client) {
291d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                Set<String> keyTypes = new HashSet<String>();
292d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                for (String enabledCipherSuite : enabledCipherSuites) {
293aeb3b48a69c2294ca657acd3e8b94c9879d78b61Brian Carlstrom                    if (enabledCipherSuite.equals(NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {
294aeb3b48a69c2294ca657acd3e8b94c9879d78b61Brian Carlstrom                        continue;
295aeb3b48a69c2294ca657acd3e8b94c9879d78b61Brian Carlstrom                    }
296ea8732bc2631141874302bc25ee2795a89f4922fBrian Carlstrom                    String keyType = CipherSuite.getByName(enabledCipherSuite).getServerKeyType();
297d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                    if (keyType != null) {
298d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                        keyTypes.add(keyType);
299d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                    }
300d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                }
301d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                for (String keyType : keyTypes) {
302fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    try {
303fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        setCertificate(sslParameters.getKeyManager().chooseServerAlias(keyType,
304fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                                                       null,
305fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                                                       this));
306fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    } catch (CertificateEncodingException e) {
307fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        throw new IOException(e);
308fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    }
309f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom                }
31098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            }
31198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
312fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            NativeCrypto.setEnabledProtocols(sslNativePointer, enabledProtocols);
313fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            NativeCrypto.setEnabledCipherSuites(sslNativePointer, enabledCipherSuites);
314fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (useSessionTickets) {
315fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_clear_options(sslNativePointer, NativeCrypto.SSL_OP_NO_TICKET);
316fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
317fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (hostname != null) {
318fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_set_tlsext_host_name(sslNativePointer, hostname);
319fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
3202828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
321fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            boolean enableSessionCreation = sslParameters.getEnableSessionCreation();
322fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (!enableSessionCreation) {
323fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer,
324fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                              enableSessionCreation);
3252828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
3262828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
327fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            AbstractSessionContext sessionContext;
328a5c365c0867e66e6b5ad8e3e9a1cbd306f35226bBrian Carlstrom            OpenSSLSessionImpl sessionToReuse;
329fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (client) {
330fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // look for client session to reuse
331fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                ClientSessionContext clientSessionContext = sslParameters.getClientSessionContext();
332fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                sessionContext = clientSessionContext;
333a5c365c0867e66e6b5ad8e3e9a1cbd306f35226bBrian Carlstrom                sessionToReuse = getCachedClientSession(clientSessionContext);
334a5c365c0867e66e6b5ad8e3e9a1cbd306f35226bBrian Carlstrom                if (sessionToReuse != null) {
335fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    NativeCrypto.SSL_set_session(sslNativePointer,
336a5c365c0867e66e6b5ad8e3e9a1cbd306f35226bBrian Carlstrom                                                 sessionToReuse.sslSessionNativePointer);
337fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
338f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            } else {
339fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                sessionContext = sslParameters.getServerSessionContext();
340a5c365c0867e66e6b5ad8e3e9a1cbd306f35226bBrian Carlstrom                sessionToReuse = null;
341f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            }
34298a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom
343fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // setup peer certificate verification
344fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (client) {
345fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // TODO support for anonymous cipher would require us to
346fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // conditionally use SSL_VERIFY_NONE
347fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            } else {
348fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // needing client auth takes priority...
3495006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                boolean certRequested;
350fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (sslParameters.getNeedClientAuth()) {
351fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    NativeCrypto.SSL_set_verify(sslNativePointer,
352fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                NativeCrypto.SSL_VERIFY_PEER
353fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
354fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    certRequested = true;
355fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // ... over just wanting it...
356fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                } else if (sslParameters.getWantClientAuth()) {
357fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    NativeCrypto.SSL_set_verify(sslNativePointer,
358fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                NativeCrypto.SSL_VERIFY_PEER);
359fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    certRequested = true;
360fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // ... and it defaults properly so don't call SSL_set_verify in the common case.
361fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                } else {
362fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    certRequested = false;
363fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
364fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom
365fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (certRequested) {
366fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    X509TrustManager trustManager = sslParameters.getTrustManager();
367fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    X509Certificate[] issuers = trustManager.getAcceptedIssuers();
368fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    if (issuers != null && issuers.length != 0) {
369fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        byte[][] issuersBytes;
370fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        try {
3713ff2b34d00ea89eec5b895d866fddf05942fd2a7Kenny Root                            issuersBytes = encodeIssuerX509Principals(issuers);
372fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        } catch (CertificateEncodingException e) {
373fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                            throw new IOException("Problem encoding principals", e);
374fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        }
375fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        NativeCrypto.SSL_set_client_CA_list(sslNativePointer, issuersBytes);
376f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom                    }
377f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom                }
378f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            }
379f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
380fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // Temporarily use a different timeout for the handshake process
381fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom            int savedReadTimeoutMilliseconds = getSoTimeout();
382fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom            int savedWriteTimeoutMilliseconds = getSoWriteTimeout();
383fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
384fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                setSoTimeout(handshakeTimeoutMilliseconds);
385fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom                setSoWriteTimeout(handshakeTimeoutMilliseconds);
386fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
3872828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
388577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin            // TLS Channel ID
3891ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root            if (channelIdEnabled) {
3901ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root                if (client) {
3911ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root                    // Client-side TLS Channel ID
3921ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root                    if (channelIdPrivateKey == null) {
3931ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root                        throw new SSLHandshakeException("Invalid TLS channel ID key specified");
3941ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root                    }
3951ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root                    NativeCrypto.SSL_set1_tls_channel_id(sslNativePointer,
3961ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root                            channelIdPrivateKey.getPkeyContext());
3971ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root                } else {
3981ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root                    // Server-side TLS Channel ID
399577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin                    NativeCrypto.SSL_enable_tls_channel_id(sslNativePointer);
400577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin                }
401577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin            }
402577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin
403fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            int sslSessionNativePointer;
404fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            try {
405a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                sslSessionNativePointer = NativeCrypto.SSL_do_handshake(sslNativePointer,
4066fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root                        socket.getFileDescriptor$(), this, getSoTimeout(), client, npnProtocols,
4076fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root                        client ? null : alpnProtocols);
408fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            } catch (CertificateException e) {
409d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage());
410d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                wrapper.initCause(e);
411d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                throw wrapper;
4122828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
413fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            byte[] sessionId = NativeCrypto.SSL_SESSION_session_id(sslSessionNativePointer);
414a5c365c0867e66e6b5ad8e3e9a1cbd306f35226bBrian Carlstrom            if (sessionToReuse != null && Arrays.equals(sessionToReuse.getId(), sessionId)) {
415a5c365c0867e66e6b5ad8e3e9a1cbd306f35226bBrian Carlstrom                this.sslSession = sessionToReuse;
416fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                sslSession.lastAccessedTime = System.currentTimeMillis();
417fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_SESSION_free(sslSessionNativePointer);
418fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            } else {
419fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (!enableSessionCreation) {
420fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    // Should have been prevented by NativeCrypto.SSL_set_session_creation_enabled
421fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    throw new IllegalStateException("SSL Session may not be created");
422fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
423fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                X509Certificate[] localCertificates
424fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        = createCertChain(NativeCrypto.SSL_get_certificate(sslNativePointer));
425fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                X509Certificate[] peerCertificates
426fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        = createCertChain(NativeCrypto.SSL_get_peer_cert_chain(sslNativePointer));
427a5c365c0867e66e6b5ad8e3e9a1cbd306f35226bBrian Carlstrom                this.sslSession = new OpenSSLSessionImpl(sslSessionNativePointer, localCertificates,
4283967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson                        peerCertificates, getPeerHostName(), getPeerPort(), sessionContext);
429fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // if not, putSession later in handshakeCompleted() callback
430fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (handshakeCompleted) {
431fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    sessionContext.putSession(sslSession);
432fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
433f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom            }
434fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom
435fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // Restore the original timeout now that the handshake is complete
436fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
437fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom                setSoTimeout(savedReadTimeoutMilliseconds);
438fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom                setSoWriteTimeout(savedWriteTimeoutMilliseconds);
439331900211d05cd282141a3a50cb1db626f418b2cDan Egnor            }
44008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
441fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback
442fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeCompleted) {
443fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                notifyHandshakeCompletedListeners();
444fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
445f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
446fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            exception = false;
4478765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        } catch (SSLProtocolException e) {
4488765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom            throw new SSLHandshakeException(e);
449fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        } finally {
450aef0b218983e04bc05ffb5746b4f452725f704b7Brian Carlstrom            // on exceptional exit, treat the socket as closed
451fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (exception) {
452aef0b218983e04bc05ffb5746b4f452725f704b7Brian Carlstrom                close();
453fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
45408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
455e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom    }
4563ff2b34d00ea89eec5b895d866fddf05942fd2a7Kenny Root
4573ff2b34d00ea89eec5b895d866fddf05942fd2a7Kenny Root    private static byte[][] encodeIssuerX509Principals(X509Certificate[] certificates)
4583ff2b34d00ea89eec5b895d866fddf05942fd2a7Kenny Root            throws CertificateEncodingException {
4593ff2b34d00ea89eec5b895d866fddf05942fd2a7Kenny Root        byte[][] principalBytes = new byte[certificates.length][];
4603ff2b34d00ea89eec5b895d866fddf05942fd2a7Kenny Root        for (int i = 0; i < certificates.length; i++) {
4613ff2b34d00ea89eec5b895d866fddf05942fd2a7Kenny Root            principalBytes[i] = certificates[i].getIssuerX500Principal().getEncoded();
4623ff2b34d00ea89eec5b895d866fddf05942fd2a7Kenny Root        }
4633ff2b34d00ea89eec5b895d866fddf05942fd2a7Kenny Root        return principalBytes;
4643ff2b34d00ea89eec5b895d866fddf05942fd2a7Kenny Root    }
46508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
466bbe7b9241a63a18bebebf38206d0aebb015f1518Geremy Condra    String getPeerHostName() {
4678ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        if (wrappedHost != null) {
4688ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom            return wrappedHost;
4698ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        }
4708ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        InetAddress inetAddress = super.getInetAddress();
4718ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        if (inetAddress != null) {
4728ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom            return inetAddress.getHostName();
4738ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        }
4748ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        return null;
4753967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson    }
4763967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson
477bbe7b9241a63a18bebebf38206d0aebb015f1518Geremy Condra    int getPeerPort() {
4783967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson        return wrappedHost == null ? super.getPort() : wrappedPort;
4793967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson    }
4803967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson
481e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom    /**
482e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom     * Return a possibly null array of X509Certificates given the
483e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom     * possibly null array of DER encoded bytes.
484e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom     */
485a5c365c0867e66e6b5ad8e3e9a1cbd306f35226bBrian Carlstrom    private static X509Certificate[] createCertChain(byte[][] certificatesBytes) throws IOException {
486e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        if (certificatesBytes == null) {
487e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            return null;
488e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        }
489e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        X509Certificate[] certificates = new X509Certificate[certificatesBytes.length];
490e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        for (int i = 0; i < certificatesBytes.length; i++) {
491860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root            certificates[i] = OpenSSLX509Certificate.fromX509Der(certificatesBytes[i]);
492e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        }
493e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        return certificates;
4942828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    }
49508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
496f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom    private void setCertificate(String alias) throws CertificateEncodingException, SSLException {
49798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        if (alias == null) {
49898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            return;
49998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        }
50098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        PrivateKey privateKey = sslParameters.getKeyManager().getPrivateKey(alias);
5018765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        if (privateKey == null) {
5028765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom            return;
5038765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        }
50498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        X509Certificate[] certificates = sslParameters.getKeyManager().getCertificateChain(alias);
5058765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        if (certificates == null) {
5068765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom            return;
5078765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        }
5088765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom
5091ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root        try {
5101ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root            final OpenSSLKey key = OpenSSLKey.fromPrivateKey(privateKey);
5111ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root            NativeCrypto.SSL_use_PrivateKey(sslNativePointer, key.getPkeyContext());
5121ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root        } catch (InvalidKeyException e) {
5131ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root            throw new SSLException(e);
514a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root        }
515a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root
516f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom        byte[][] certificateBytes = NativeCrypto.encodeCertificates(certificates);
51798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        NativeCrypto.SSL_use_certificate(sslNativePointer, certificateBytes);
51898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
51998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        // checks the last installed private key and certificate,
52098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        // so need to do this once per loop iteration
52198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        NativeCrypto.SSL_check_private_key(sslNativePointer);
52298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom    }
52398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
5245006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / client_cert_cb
52598a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom    public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)
526f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            throws CertificateEncodingException, SSLException {
52798a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom
52898a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        String[] keyTypes = new String[keyTypeBytes.length];
52998a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        for (int i = 0; i < keyTypeBytes.length; i++) {
530ea8732bc2631141874302bc25ee2795a89f4922fBrian Carlstrom            keyTypes[i] = CipherSuite.getClientKeyType(keyTypeBytes[i]);
53198a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        }
53298a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom
53398a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        X500Principal[] issuers;
53498a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        if (asn1DerEncodedPrincipals == null) {
53598a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom            issuers = null;
53698a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        } else {
53798a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom            issuers = new X500Principal[asn1DerEncodedPrincipals.length];
53898a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom            for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
53998a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom                issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
54098a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom            }
54198a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        }
54298a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        setCertificate(sslParameters.getKeyManager().chooseClientAlias(keyTypes, issuers, this));
54398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom    }
54498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
5455006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / info_callback
5462828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    public void handshakeCompleted() {
5472828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        handshakeCompleted = true;
54808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
5492828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // If sslSession is null, the handshake was completed during
5502828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // the call to NativeCrypto.SSL_do_handshake and not during a
5515006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        // later read operation. That means we do not need to fix up
5522828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // the SSLSession and session cache or notify
5532828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // HandshakeCompletedListeners, it will be done in
5542828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // startHandshake.
5552828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        if (sslSession == null) {
5562828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            return;
5572828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        }
55808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
5592828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // reset session id from the native pointer and update the
5602828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // appropriate cache.
5612828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        sslSession.resetId();
5622828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        AbstractSessionContext sessionContext =
5632828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            (sslParameters.getUseClientMode())
5642828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            ? sslParameters.getClientSessionContext()
5652828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                : sslParameters.getServerSessionContext();
56608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sessionContext.putSession(sslSession);
5672828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
5682828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // let listeners know we are finally done
5692828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        notifyHandshakeCompletedListeners();
5702828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    }
5712828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
5722828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    private void notifyHandshakeCompletedListeners() {
5732828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        if (listeners != null && !listeners.isEmpty()) {
5742828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            // notify the listeners
5752828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            HandshakeCompletedEvent event =
5762828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                new HandshakeCompletedEvent(this, sslSession);
5772828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            for (HandshakeCompletedListener listener : listeners) {
5782828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                try {
5792828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                    listener.handshakeCompleted(event);
5802828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                } catch (RuntimeException e) {
581371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // The RI runs the handlers in a separate thread,
582371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // which we do not. But we try to preserve their
583371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // behavior of logging a problem and not killing
584371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // the handshaking thread just because a listener
585371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // has a problem.
586371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    Thread thread = Thread.currentThread();
587371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    thread.getUncaughtExceptionHandler().uncaughtException(thread, e);
5882828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                }
5892828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
5902828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        }
59108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
59208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
5935006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks
5945006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void verifyCertificateChain(byte[][] bytes, String authMethod)
59598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            throws CertificateException {
59608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        try {
597371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom            if (bytes == null || bytes.length == 0) {
598371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                throw new SSLException("Peer sent no certificate");
599371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom            }
6002828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            X509Certificate[] peerCertificateChain = new X509Certificate[bytes.length];
6012828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            for (int i = 0; i < bytes.length; i++) {
602860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root                peerCertificateChain[i] = OpenSSLX509Certificate.fromX509Der(bytes[i]);
60308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
6042828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            boolean client = sslParameters.getUseClientMode();
6052828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            if (client) {
606bbe7b9241a63a18bebebf38206d0aebb015f1518Geremy Condra                X509TrustManager x509tm = sslParameters.getTrustManager();
607bbe7b9241a63a18bebebf38206d0aebb015f1518Geremy Condra                if (x509tm instanceof TrustManagerImpl) {
608bbe7b9241a63a18bebebf38206d0aebb015f1518Geremy Condra                    TrustManagerImpl tm = (TrustManagerImpl) x509tm;
609bbe7b9241a63a18bebebf38206d0aebb015f1518Geremy Condra                    tm.checkServerTrusted(peerCertificateChain, authMethod, wrappedHost);
610bbe7b9241a63a18bebebf38206d0aebb015f1518Geremy Condra                } else {
611bbe7b9241a63a18bebebf38206d0aebb015f1518Geremy Condra                    x509tm.checkServerTrusted(peerCertificateChain, authMethod);
612bbe7b9241a63a18bebebf38206d0aebb015f1518Geremy Condra                }
6132828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            } else {
614ea8732bc2631141874302bc25ee2795a89f4922fBrian Carlstrom                String authType = peerCertificateChain[0].getPublicKey().getAlgorithm();
61598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom                sslParameters.getTrustManager().checkClientTrusted(peerCertificateChain,
616ea8732bc2631141874302bc25ee2795a89f4922fBrian Carlstrom                                                                   authType);
61708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
6182828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
6192828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        } catch (CertificateException e) {
6202828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            throw e;
6212828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        } catch (Exception e) {
6229400b50da5ca8f1e796f5b158063db0aefb58441Brian Carlstrom            throw new CertificateException(e);
62308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
62408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
62508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
6265006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public InputStream getInputStream() throws IOException {
627a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        checkOpen();
628f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom        synchronized (this) {
62908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (is == null) {
63008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                is = new SSLInputStream();
63108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
63208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
63308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return is;
63408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
63508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
63608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
6375006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public OutputStream getOutputStream() throws IOException {
638a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        checkOpen();
639f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom        synchronized (this) {
64008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (os == null) {
64108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                os = new SSLOutputStream();
64208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
64308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
64408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return os;
64508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
64608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
64708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
6482828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    /**
64908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This inner class provides input data stream functionality
65008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * for the OpenSSL native implementation. It is used to
65108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * read data received via SSL protocol.
65208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
65308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private class SSLInputStream extends InputStream {
65408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        SSLInputStream() throws IOException {
655d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson            /*
656d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson             * Note: When startHandshake() throws an exception, no
65708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project             * SSLInputStream object will be created.
65808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project             */
659d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson            OpenSSLSocketImpl.this.startHandshake();
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.
66708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @throws <code>IOException</code>
66808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
6690b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
67008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        public int read() throws IOException {
6715c44d1fc26c081cf85af010b6e751449bde14b80Brian Carlstrom            return Streams.readSingleByte(this);
67208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
67308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
67408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
67508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
67608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.InputStream#read(byte[],int,int)
67708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
6780b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
67997e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes        public int read(byte[] buf, int offset, int byteCount) throws IOException {
680ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
681f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            synchronized (readLock) {
6827b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                checkOpen();
68397e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes                Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
68497e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes                if (byteCount == 0) {
6857b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                    return 0;
6867b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                }
687a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                return NativeCrypto.SSL_read(sslNativePointer, socket.getFileDescriptor$(),
688a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                        OpenSSLSocketImpl.this, buf, offset, byteCount, getSoTimeout());
68908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
69008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
69108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
69208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
69308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
69408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This inner class provides output data stream functionality
69508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * for the OpenSSL native implementation. It is used to
69608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * write data according to the encryption parameters given in SSL context.
69708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
69808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private class SSLOutputStream extends OutputStream {
69908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        SSLOutputStream() throws IOException {
700d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson            /*
701d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson             * Note: When startHandshake() throws an exception, no
702f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom             * SSLOutputStream object will be created.
70308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project             */
704d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson            OpenSSLSocketImpl.this.startHandshake();
70508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
70608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
70708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
70808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
70908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.OutputStream#write(int)
71008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
7110b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
7125c44d1fc26c081cf85af010b6e751449bde14b80Brian Carlstrom        public void write(int oneByte) throws IOException {
7135c44d1fc26c081cf85af010b6e751449bde14b80Brian Carlstrom            Streams.writeSingleByte(this, oneByte);
71408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
71508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
71608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
71708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
71808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.OutputStream#write(byte[],int,int)
71908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
7200b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
72197e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes        public void write(byte[] buf, int offset, int byteCount) throws IOException {
722ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
723f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            synchronized (writeLock) {
7247b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                checkOpen();
72597e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes                Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
72697e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes                if (byteCount == 0) {
7277b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                    return;
7287b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                }
729a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                NativeCrypto.SSL_write(sslNativePointer, socket.getFileDescriptor$(),
730fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom                        OpenSSLSocketImpl.this, buf, offset, byteCount, writeTimeoutMilliseconds);
73108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
73208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
73308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
73408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
73508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7365006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public SSLSession getSession() {
737e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        if (sslSession == null) {
738e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            try {
739d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson                startHandshake();
740e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            } catch (IOException e) {
741e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                // return an invalid session with
742e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
743e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                return SSLSessionImpl.NULL_SESSION;
744e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            }
74508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
74608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslSession;
74708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
74808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7495006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void addHandshakeCompletedListener(
75008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            HandshakeCompletedListener listener) {
75108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listener == null) {
75208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
75308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
75408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listeners == null) {
7555006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson            listeners = new ArrayList<HandshakeCompletedListener>();
75608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
75708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        listeners.add(listener);
75808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
75908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7605006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void removeHandshakeCompletedListener(
76108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            HandshakeCompletedListener listener) {
76208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listener == null) {
76308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
76408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
76508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listeners == null) {
76608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException(
76708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    "Provided listener is not registered");
76808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
76908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (!listeners.remove(listener)) {
77008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException(
77108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    "Provided listener is not registered");
77208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
77308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
77408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7755006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public boolean getEnableSessionCreation() {
77608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getEnableSessionCreation();
77708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
77808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7795006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setEnableSessionCreation(boolean flag) {
78008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setEnableSessionCreation(flag);
78108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
78208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7835006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public String[] getSupportedCipherSuites() {
784f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        return NativeCrypto.getSupportedCipherSuites();
78508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
78608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7875006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public String[] getEnabledCipherSuites() {
7882828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        return enabledCipherSuites.clone();
78908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
79008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7915006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setEnabledCipherSuites(String[] suites) {
7922828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(suites);
79308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
79408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7955006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public String[] getSupportedProtocols() {
796f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        return NativeCrypto.getSupportedProtocols();
79708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
79808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7995006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public String[] getEnabledProtocols() {
8002828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        return enabledProtocols.clone();
80108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
80208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8035006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setEnabledProtocols(String[] protocols) {
8042828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        enabledProtocols = NativeCrypto.checkEnabledProtocols(protocols);
80508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
80608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
80708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
8080b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * This method enables session ticket support.
8090b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
8100b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @param useSessionTickets True to enable session tickets
8110b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8120b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public void setUseSessionTickets(boolean useSessionTickets) {
8130b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        this.useSessionTickets = useSessionTickets;
8140b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8150b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
8160b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
8170b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * This method enables Server Name Indication
8180b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
8190b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @param hostname the desired SNI hostname, or null to disable
8200b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8210b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public void setHostname(String hostname) {
8220b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        this.hostname = hostname;
8230b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8240b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
825577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    /**
826577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * Enables/disables TLS Channel ID for this server socket.
827577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
828577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * <p>This method needs to be invoked before the handshake starts.
829577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
830577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * @throws IllegalStateException if this is a client socket or if the handshake has already
831577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *         started.
832577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin
833577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     */
834577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    public void setChannelIdEnabled(boolean enabled) {
835577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        if (getUseClientMode()) {
836577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin            throw new IllegalStateException("Client mode");
837577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        }
838577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        if (handshakeStarted) {
839577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin            throw new IllegalStateException(
840577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin                    "Could not enable/disable Channel ID after the initial handshake has"
841577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin                    + " begun.");
842577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        }
843577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        this.channelIdEnabled = enabled;
844577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    }
845577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin
846577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    /**
847577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * Gets the TLS Channel ID for this server socket. Channel ID is only available once the
848577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * handshake completes.
849577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
850577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * @return channel ID or {@code null} if not available.
851577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
852577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * @throws IllegalStateException if this is a client socket or if the handshake has not yet
853577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *         completed.
854577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * @throws SSLException if channel ID is available but could not be obtained.
855577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     */
856577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    public byte[] getChannelId() throws SSLException {
857577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        if (getUseClientMode()) {
858577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin            throw new IllegalStateException("Client mode");
859577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        }
860577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        if (!handshakeCompleted) {
861577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin            throw new IllegalStateException(
862577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin                    "Channel ID is only available after handshake completes");
863577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        }
864577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        return NativeCrypto.SSL_get_tls_channel_id(sslNativePointer);
865577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    }
866577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin
867577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    /**
868577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * Sets the {@link PrivateKey} to be used for TLS Channel ID by this client socket.
869577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
870577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * <p>This method needs to be invoked before the handshake starts.
871577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
872577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key (disables
8734022a5d005758bec373f5b6544fe9be2ef1c0378Alex Klyubin     *        TLS Channel ID). The private key must be an Elliptic Curve (EC) key based on the NIST
874577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *        P-256 curve (aka SECG secp256r1 or ANSI X9.62 prime256v1).
875577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *
876577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     * @throws IllegalStateException if this is a server socket or if the handshake has already
877577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     *         started.
878577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin     */
8794022a5d005758bec373f5b6544fe9be2ef1c0378Alex Klyubin    public void setChannelIdPrivateKey(PrivateKey privateKey) {
880577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        if (!getUseClientMode()) {
881577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin            throw new IllegalStateException("Server mode");
882577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        }
883577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        if (handshakeStarted) {
884577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin            throw new IllegalStateException(
885577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin                    "Could not change Channel ID private key after the initial handshake has"
886577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin                    + " begun.");
887577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin        }
8881ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root        if (privateKey == null) {
8891ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root            this.channelIdEnabled = false;
8901ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root            this.channelIdPrivateKey = null;
8911ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root        } else {
8921ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root            this.channelIdEnabled = true;
8931ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root            try {
8941ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root                this.channelIdPrivateKey = OpenSSLKey.fromPrivateKey(privateKey);
8951ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root            } catch (InvalidKeyException e) {
8961ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root                // Will have error in startHandshake
8971ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root            }
8981ecc0481f90d32b89b3b051cad70efe07468acd0Kenny Root        }
899577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin    }
900577e146ed2c9c9d166c4d30a495d95d4b171a7e8Alex Klyubin
9015006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public boolean getUseClientMode() {
90208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getUseClientMode();
90308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
90408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
9055006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setUseClientMode(boolean mode) {
90608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (handshakeStarted) {
90708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException(
9085006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                    "Could not change the mode after the initial handshake has begun.");
90908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
91008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setUseClientMode(mode);
91108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
91208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
9135006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public boolean getWantClientAuth() {
91408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getWantClientAuth();
91508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
91608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
9175006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public boolean getNeedClientAuth() {
91808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getNeedClientAuth();
91908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
92008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
9215006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setNeedClientAuth(boolean need) {
92208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setNeedClientAuth(need);
92308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
92408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
9255006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setWantClientAuth(boolean want) {
92608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setWantClientAuth(want);
92708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
92808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
9295006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void sendUrgentData(int data) throws IOException {
9305006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        throw new SocketException("Method sendUrgentData() is not supported.");
93108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
93208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
9335006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setOOBInline(boolean on) throws SocketException {
9345006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        throw new SocketException("Methods sendUrgentData, setOOBInline are not supported.");
93508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
93608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
937fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    @Override public void setSoTimeout(int readTimeoutMilliseconds) throws SocketException {
938fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        super.setSoTimeout(readTimeoutMilliseconds);
939fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        this.readTimeoutMilliseconds = readTimeoutMilliseconds;
94072721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    }
94172721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom
9425006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public int getSoTimeout() throws SocketException {
943fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        return readTimeoutMilliseconds;
944fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    }
945fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom
946fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    /**
947fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom     * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
948fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom     */
949fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    public void setSoWriteTimeout(int writeTimeoutMilliseconds) throws SocketException {
950fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        this.writeTimeoutMilliseconds = writeTimeoutMilliseconds;
951fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom
952fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        StructTimeval tv = StructTimeval.fromMillis(writeTimeoutMilliseconds);
953fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        try {
954fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom            Libcore.os.setsockoptTimeval(getFileDescriptor$(), SOL_SOCKET, SO_SNDTIMEO, tv);
955fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        } catch (ErrnoException errnoException) {
956fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom            throw errnoException.rethrowAsSocketException();
957fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        }
958fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    }
959fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom
960fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    /**
961fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom     * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
962fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom     */
963fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    public int getSoWriteTimeout() throws SocketException {
964fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        return writeTimeoutMilliseconds;
96508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
96608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
967331900211d05cd282141a3a50cb1db626f418b2cDan Egnor    /**
968331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     * Set the handshake timeout on this socket.  This timeout is specified in
969331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     * milliseconds and will be used only during the handshake process.
970331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     */
971fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom    public void setHandshakeTimeout(int handshakeTimeoutMilliseconds) throws SocketException {
972fba8b41283914ec1ba08dabfc23ecc974951a481Brian Carlstrom        this.handshakeTimeoutMilliseconds = handshakeTimeoutMilliseconds;
973331900211d05cd282141a3a50cb1db626f418b2cDan Egnor    }
974331900211d05cd282141a3a50cb1db626f418b2cDan Egnor
9755006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void close() throws IOException {
9765006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        // TODO: Close SSL sockets using a background thread so they close gracefully.
97708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
97808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        synchronized (handshakeLock) {
97908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (!handshakeStarted) {
9805006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                // prevent further attempts to start handshake
98108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                handshakeStarted = true;
982f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
98308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                synchronized (this) {
984f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom                    free();
98508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
98690ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom                    if (socket != this) {
98708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        if (autoClose && !socket.isClosed()) socket.close();
98808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    } else {
98908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        if (!super.isClosed()) super.close();
99008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    }
99108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                }
992f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
99308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                return;
99408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
99508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
99608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
99708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        synchronized (this) {
99808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
999fa6657aaf2fadbb1aeb2f869cba82042c1faedeaBrian Carlstrom            // Interrupt any outstanding reads or writes before taking the writeLock and readLock
1000fa6657aaf2fadbb1aeb2f869cba82042c1faedeaBrian Carlstrom            NativeCrypto.SSL_interrupt(sslNativePointer);
10018b352156f879e7b36d223d3f65b8de46b7dc4dcfBrian Carlstrom
1002fa6657aaf2fadbb1aeb2f869cba82042c1faedeaBrian Carlstrom            synchronized (writeLock) {
1003fa6657aaf2fadbb1aeb2f869cba82042c1faedeaBrian Carlstrom                synchronized (readLock) {
100408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    // Shut down the SSL connection, per se.
100508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    try {
100608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        if (handshakeStarted) {
1007ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick                            BlockGuard.getThreadPolicy().onNetwork();
1008a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                            NativeCrypto.SSL_shutdown(sslNativePointer, socket.getFileDescriptor$(),
1009a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                                    this);
101008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        }
101186c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                    } catch (IOException ignored) {
101208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        /*
101386c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                         * Note that although close() can throw
101486c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                         * IOException, the RI does not throw if there
101586c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                         * is problem sending a "close notify" which
101686c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                         * can happen if the underlying socket is closed.
101708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                         */
101806327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                    } finally {
101906327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                        /*
102006327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                         * Even if the above call failed, it is still safe to free
102106327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                         * the native structs, and we need to do so lest we leak
102206327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                         * memory.
102306327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                         */
102406327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                        free();
102506327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom
102606327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                        if (socket != this) {
102706327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                            if (autoClose && !socket.isClosed()) {
102806327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                                socket.close();
102906327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                            }
103006327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                        } else {
103106327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                            if (!super.isClosed()) {
103206327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                                super.close();
103306327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                            }
103406327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                        }
103508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    }
103608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                }
103708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
103808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
103908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
104008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
1041f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    private void free() {
1042f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        if (sslNativePointer == 0) {
1043f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom            return;
1044f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        }
1045f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        NativeCrypto.SSL_free(sslNativePointer);
1046f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        sslNativePointer = 0;
1047fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        guard.close();
1048f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    }
104908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
10501990574e420184f3ad43400171f624dad44700d8Brian Carlstrom    @Override protected void finalize() throws Throwable {
10511990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        try {
10521990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            /*
10531990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * Just worry about our own state. Notably we do not try and
10541990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * close anything. The SocketImpl, either our own
10551990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * PlainSocketImpl, or the Socket we are wrapping, will do
10561990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * that. This might mean we do not properly SSL_shutdown, but
10571990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * if you want to do that, properly close the socket yourself.
10581990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             *
10591990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * The reason why we don't try to SSL_shutdown, is that there
10601990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * can be a race between finalizers where the PlainSocketImpl
10611990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * finalizer runs first and closes the socket. However, in the
10621990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * meanwhile, the underlying file descriptor could be reused
10631990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * for another purpose. If we call SSL_shutdown, the
10641990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * underlying socket BIOs still have the old file descriptor
10651990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * and will write the close notify to some unsuspecting
10661990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * reader.
10671990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             */
1068f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom            if (guard != null) {
1069f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom                guard.warnIfOpen();
1070f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom            }
10711990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            free();
10721990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        } finally {
10731990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            super.finalize();
10741990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        }
107508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
10760648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey
10770648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey    @Override
10780648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey    public FileDescriptor getFileDescriptor$() {
10790648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey        if (socket == this) {
10800648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey            return super.getFileDescriptor$();
10810648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey        } else {
10820648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey            return socket.getFileDescriptor$();
10830648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey        }
10840648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey    }
1085721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson
1086721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    /**
1087721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * Returns the protocol agreed upon by client and server, or null if no
1088721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * protocol was agreed upon.
1089721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     */
1090721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    public byte[] getNpnSelectedProtocol() {
1091263808a68e1538db41196065830107991e9f974aJesse Wilson        return NativeCrypto.SSL_get_npn_negotiated_protocol(sslNativePointer);
1092721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    }
1093721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson
1094721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    /**
10956fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     * Returns the protocol agreed upon by client and server, or {@code null} if
10966fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     * no protocol was agreed upon.
10976fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     */
10986fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root    public byte[] getAlpnSelectedProtocol() {
10996fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root        return NativeCrypto.SSL_get0_alpn_selected(sslNativePointer);
11006fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root    }
11016fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root
11026fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root    /**
1103721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * Sets the list of protocols this peer is interested in. If null no
1104721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * protocols will be used.
1105721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     *
1106d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson     * @param npnProtocols a non-empty array of protocol names. From
1107d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson     *     SSL_select_next_proto, "vector of 8-bit, length prefixed byte
1108d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson     *     strings. The length byte itself is not included in the length. A byte
1109d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson     *     string of length 0 is invalid. No byte string may be truncated.".
1110721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     */
1111721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    public void setNpnProtocols(byte[] npnProtocols) {
1112d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson        if (npnProtocols != null && npnProtocols.length == 0) {
1113d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson            throw new IllegalArgumentException("npnProtocols.length == 0");
1114d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson        }
1115721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson        this.npnProtocols = npnProtocols;
1116721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    }
11176fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root
11186fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root    /**
11196fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     * Sets the list of protocols this peer is interested in. If the list is
11206fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     * {@code null}, no protocols will be used.
11216fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     *
11226fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     * @param alpnProtocols a non-empty array of protocol names. From
11236fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     *            SSL_select_next_proto, "vector of 8-bit, length prefixed byte
11246fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     *            strings. The length byte itself is not included in the length.
11256fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     *            A byte string of length 0 is invalid. No byte string may be
11266fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     *            truncated.".
11276fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root     */
11286fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root    public void setAlpnProtocols(byte[] alpnProtocols) {
11296fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root        if (alpnProtocols != null && alpnProtocols.length == 0) {
11306fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root            throw new IllegalArgumentException("alpnProtocols.length == 0");
11316fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root        }
11326fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root        this.alpnProtocols = alpnProtocols;
11336fcf0cbeec79d1f2491d8d0774fdb314fc419ba3Kenny Root    }
113408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project}
1135