OpenSSLSocketImpl.java revision d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9ae
1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * you may not use this file except in compliance with the License.
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * You may obtain a copy of the License at
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License.
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1738375a4d0b3d34e2babbd2f6a013976c7c439696Kenny Rootpackage org.conscrypt;
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
195900e5546059f05d5e58e5732e4d08d83b8b7574Brad Fitzpatrickimport dalvik.system.BlockGuard;
20f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstromimport dalvik.system.CloseGuard;
213267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkeyimport java.io.FileDescriptor;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.OutputStream;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.InetAddress;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.Socket;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.SocketException;
286df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstromimport java.security.PrivateKey;
296df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstromimport java.security.SecureRandom;
3012cd1f00c2fa1a7f37bf644cecdf7588bdc0b0a9Brian Carlstromimport java.security.cert.CertificateEncodingException;
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.cert.CertificateException;
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.cert.X509Certificate;
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.ArrayList;
34a1603838fe9e865575c87982e32c6343740e464cElliott Hughesimport java.util.Arrays;
356c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstromimport java.util.HashSet;
366c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstromimport java.util.Set;
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport javax.net.ssl.HandshakeCompletedEvent;
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport javax.net.ssl.HandshakeCompletedListener;
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport javax.net.ssl.SSLException;
402915378e253f08e47fe5a9bfd026cd1ca7c6c351Brian Carlstromimport javax.net.ssl.SSLHandshakeException;
41b88ab0efb05475fa9d4e2a06175e95e88f507cffBrian Carlstromimport javax.net.ssl.SSLPeerUnverifiedException;
42aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstromimport javax.net.ssl.SSLProtocolException;
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport javax.net.ssl.SSLSession;
44f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstromimport javax.net.ssl.X509TrustManager;
45059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstromimport javax.security.auth.x500.X500Principal;
46615225a35dbd838210270b282d1196deff643b51Brian Carlstromimport static libcore.io.OsConstants.*;
47615225a35dbd838210270b282d1196deff643b51Brian Carlstromimport libcore.io.ErrnoException;
48615225a35dbd838210270b282d1196deff643b51Brian Carlstromimport libcore.io.Libcore;
49638000042da777f6d628d88dadde957c52597710Brian Carlstromimport libcore.io.Streams;
50615225a35dbd838210270b282d1196deff643b51Brian Carlstromimport libcore.io.StructTimeval;
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
534559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * Implementation of the class OpenSSLSocketImpl based on OpenSSL.
544559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <p>
554559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * Extensions to SSLSocket include:
564559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <ul>
574559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <li>handshake timeout
584559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <li>session tickets
594559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <li>Server Name Indication
604559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * </ul>
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
62ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrompublic class OpenSSLSocketImpl
63ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        extends javax.net.ssl.SSLSocket
646df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        implements NativeCrypto.SSLHandshakeCallbacks {
65df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom
668acd6134dc84b387608746fbf2054c6d7dcd4f52Joel Dice    private long sslNativePointer;
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private InputStream is;
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private OutputStream os;
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final Object handshakeLock = new Object();
70ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    private final Object readLock = new Object();
71ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    private final Object writeLock = new Object();
726812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    private SSLParametersImpl sslParameters;
7325977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    private byte[] npnProtocols;
74bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    private String[] enabledProtocols;
75bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    private String[] enabledCipherSuites;
764559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    private boolean useSessionTickets;
774559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    private String hostname;
78de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    /** Whether the TLS Channel ID extension is enabled. This field is server-side only. */
79de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    private boolean channelIdEnabled;
80de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    /** Private key for the TLS Channel ID extension. This field is client-side only. */
81c17bdfa469de6c48f16e454611caae3aaa82cc9dAlex Klyubin    private PrivateKey channelIdPrivateKey;
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private OpenSSLSessionImpl sslSession;
83df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom    private final Socket socket;
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private boolean autoClose;
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private boolean handshakeStarted = false;
8612f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom    private final CloseGuard guard = CloseGuard.get();
87bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
88bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    /**
89bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * Not set to true until the update from native that tells us the
90bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * full handshake is complete, since SSL_do_handshake can return
91bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * before the handshake is completely done due to
92bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * handshake_cutthrough support.
93bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     */
94bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    private boolean handshakeCompleted = false;
95bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private ArrayList<HandshakeCompletedListener> listeners;
97a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom
98a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom    /**
99a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom     * Local cache of timeout to avoid getsockopt on every read and
100a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom     * write for non-wrapped sockets. Note that
101a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom     * OpenSSLSocketImplWrapper overrides setSoTimeout and
102a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom     * getSoTimeout to delegate to the wrapped socket.
103a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom     */
104615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    private int readTimeoutMilliseconds = 0;
105615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    private int writeTimeoutMilliseconds = 0;
106a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom
107a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom    private int handshakeTimeoutMilliseconds = -1;  // -1 = same as timeout; 0 = infinite
108a653cca054f36de92bbef8498be3f0f01d9d6119Brian Carlstrom    private String wrappedHost;
109a653cca054f36de92bbef8498be3f0f01d9d6119Brian Carlstrom    private int wrappedPort;
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1116812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    protected OpenSSLSocketImpl(SSLParametersImpl sslParameters) throws IOException {
112df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom        this.socket = this;
113ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        init(sslParameters);
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1166812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    protected OpenSSLSocketImpl(SSLParametersImpl sslParameters,
117bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                                String[] enabledProtocols,
1187695a9b3261bfee3a810e0829bd8082fe1fcb6a4Brian Carlstrom                                String[] enabledCipherSuites) throws IOException {
119df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom        this.socket = this;
1207695a9b3261bfee3a810e0829bd8082fe1fcb6a4Brian Carlstrom        init(sslParameters, enabledProtocols, enabledCipherSuites);
121bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    }
122bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
1236812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    protected OpenSSLSocketImpl(String host, int port, SSLParametersImpl sslParameters)
124df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom            throws IOException {
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(host, port);
126df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom        this.socket = this;
127ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        init(sslParameters);
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1306812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    protected OpenSSLSocketImpl(InetAddress address, int port, SSLParametersImpl sslParameters)
131df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom            throws IOException {
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(address, port);
133df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom        this.socket = this;
134ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        init(sslParameters);
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1380c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom    protected OpenSSLSocketImpl(String host, int port,
1390c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                                InetAddress clientAddress, int clientPort,
1400c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson                                SSLParametersImpl sslParameters) throws IOException {
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(host, port, clientAddress, clientPort);
142df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom        this.socket = this;
143ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        init(sslParameters);
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected OpenSSLSocketImpl(InetAddress address, int port,
1470c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                                InetAddress clientAddress, int clientPort,
1480c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson                                SSLParametersImpl sslParameters) throws IOException {
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(address, port, clientAddress, clientPort);
150df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom        this.socket = this;
151ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        init(sslParameters);
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1550c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson     * Create an SSL socket that wraps another socket. Invoked by
1560c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson     * OpenSSLSocketImplWrapper constructor.
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected OpenSSLSocketImpl(Socket socket, String host, int port,
1596812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom            boolean autoClose, SSLParametersImpl sslParameters) throws IOException {
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.socket = socket;
161a653cca054f36de92bbef8498be3f0f01d9d6119Brian Carlstrom        this.wrappedHost = host;
162a653cca054f36de92bbef8498be3f0f01d9d6119Brian Carlstrom        this.wrappedPort = port;
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.autoClose = autoClose;
164ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        init(sslParameters);
165a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom
166a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom        // this.timeout is not set intentionally.
167a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom        // OpenSSLSocketImplWrapper.getSoTimeout will delegate timeout
168a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom        // to wrapped socket
169ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    }
170ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
171ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    /**
172ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom     * Initialize the SSL socket and set the certificates for the
173ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom     * future handshaking.
174ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom     */
1756812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    private void init(SSLParametersImpl sslParameters) throws IOException {
176bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        init(sslParameters,
1773d74b4bec8543e6e3f89eafe3afe0925f3a69f01Brian Carlstrom             NativeCrypto.getDefaultProtocols(),
1787695a9b3261bfee3a810e0829bd8082fe1fcb6a4Brian Carlstrom             NativeCrypto.getDefaultCipherSuites());
179ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    }
180ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
181ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    /**
182bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * Initialize the SSL socket and set the certificates for the
183bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * future handshaking.
184ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom     */
1856812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    private void init(SSLParametersImpl sslParameters,
186bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                      String[] enabledProtocols,
1877695a9b3261bfee3a810e0829bd8082fe1fcb6a4Brian Carlstrom                      String[] enabledCipherSuites) throws IOException {
188bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        this.sslParameters = sslParameters;
189bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        this.enabledProtocols = enabledProtocols;
190bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        this.enabledCipherSuites = enabledCipherSuites;
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the suitable session reference from the session cache container.
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
196bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    private OpenSSLSessionImpl getCachedClientSession(ClientSessionContext sessionContext) {
19727c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        String hostName = getPeerHostName();
19827c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        int port = getPeerPort();
19927c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        if (hostName == null) {
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
20227c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        OpenSSLSessionImpl session = (OpenSSLSessionImpl) sessionContext.getSession(hostName, port);
2039acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        if (session == null) {
2049acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            return null;
2059acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2069acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom
2079acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        String protocol = session.getProtocol();
2089acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        boolean protocolFound = false;
2099acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        for (String enabledProtocol : enabledProtocols) {
2109acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            if (protocol.equals(enabledProtocol)) {
2119acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                protocolFound = true;
2129acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                break;
2139acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            }
2149acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2159acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        if (!protocolFound) {
2169acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            return null;
2179acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2189acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom
2199acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        String cipherSuite = session.getCipherSuite();
2209acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        boolean cipherSuiteFound = false;
2219acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        for (String enabledCipherSuite : enabledCipherSuites) {
2229acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            if (cipherSuite.equals(enabledCipherSuite)) {
2239acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                cipherSuiteFound = true;
2249acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                break;
2259acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            }
2269acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2279acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        if (!cipherSuiteFound) {
2289acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            return null;
2299acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2306df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
2319acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        return session;
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2345f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom    private void checkOpen() throws SocketException {
2355f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom        if (isClosed()) {
2365f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom            throw new SocketException("Socket is closed");
2375f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom        }
2385f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom    }
2395f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom
2405f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom    /**
241679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson     * Starts a TLS/SSL handshake on this connection using some native methods
242679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson     * from the OpenSSL library. It can negotiate new encryption keys, change
243679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson     * cipher suites, or initiate a new session. The certificate chain is
244679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson     * verified if the correspondent property in java.Security is set. All
245679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson     * listeners are notified at the end of the TLS/SSL handshake.
246bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     */
247679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson    @Override public synchronized void startHandshake() throws IOException {
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (handshakeLock) {
24912e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom            checkOpen();
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!handshakeStarted) {
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                handshakeStarted = true;
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return;
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2576df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        // note that this modifies the global seed, not something specific to the connection
2586df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        final int seedLengthInBytes = NativeCrypto.RAND_SEED_LENGTH_IN_BYTES;
2596df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        final SecureRandom secureRandom = sslParameters.getSecureRandomMember();
2606df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        if (secureRandom == null) {
2616df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            NativeCrypto.RAND_load_file("/dev/urandom", seedLengthInBytes);
2626df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        } else {
2636df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            NativeCrypto.RAND_seed(secureRandom.generateSeed(seedLengthInBytes));
2646df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        }
2656df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
2666df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        final boolean client = sslParameters.getUseClientMode();
2676df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
2688acd6134dc84b387608746fbf2054c6d7dcd4f52Joel Dice        final long sslCtxNativePointer = (client) ?
2696df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            sslParameters.getClientSessionContext().sslCtxNativePointer :
2706df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            sslParameters.getServerSessionContext().sslCtxNativePointer;
2716df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
272f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        this.sslNativePointer = 0;
273f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        boolean exception = true;
274f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        try {
275f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer);
276f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            guard.open("close");
2776df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
27825977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson            if (npnProtocols != null) {
27925977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson                NativeCrypto.SSL_CTX_enable_npn(sslCtxNativePointer);
28025977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson            }
28125977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson
282f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // setup server certificates and private keys.
283f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // clients will receive a call back to request certificates.
284f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (!client) {
2856c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                Set<String> keyTypes = new HashSet<String>();
2866c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                for (String enabledCipherSuite : enabledCipherSuites) {
287ffeba5dd766602f6e2be9caa9081744348a53c04Brian Carlstrom                    if (enabledCipherSuite.equals(NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {
288ffeba5dd766602f6e2be9caa9081744348a53c04Brian Carlstrom                        continue;
289ffeba5dd766602f6e2be9caa9081744348a53c04Brian Carlstrom                    }
2904ae3fd787741bfe1b808f447dcb0785250024119Brian Carlstrom                    String keyType = CipherSuite.getByName(enabledCipherSuite).getServerKeyType();
2916c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                    if (keyType != null) {
2926c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                        keyTypes.add(keyType);
2936c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                    }
2946c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                }
2956c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                for (String keyType : keyTypes) {
296f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    try {
297f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        setCertificate(sslParameters.getKeyManager().chooseServerAlias(keyType,
298f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                                                       null,
299f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                                                       this));
300f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    } catch (CertificateEncodingException e) {
301f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        throw new IOException(e);
302f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    }
303ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom                }
3046df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            }
3056df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
306f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            NativeCrypto.setEnabledProtocols(sslNativePointer, enabledProtocols);
307f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            NativeCrypto.setEnabledCipherSuites(sslNativePointer, enabledCipherSuites);
308f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (useSessionTickets) {
309f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                NativeCrypto.SSL_clear_options(sslNativePointer, NativeCrypto.SSL_OP_NO_TICKET);
310f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
311f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (hostname != null) {
312f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                NativeCrypto.SSL_set_tlsext_host_name(sslNativePointer, hostname);
313f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
314bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
315f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            boolean enableSessionCreation = sslParameters.getEnableSessionCreation();
316f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (!enableSessionCreation) {
317f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer,
318f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                              enableSessionCreation);
319bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            }
320bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
321f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            AbstractSessionContext sessionContext;
322b88ab0efb05475fa9d4e2a06175e95e88f507cffBrian Carlstrom            OpenSSLSessionImpl sessionToReuse;
323f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (client) {
324f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // look for client session to reuse
325f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                ClientSessionContext clientSessionContext = sslParameters.getClientSessionContext();
326f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                sessionContext = clientSessionContext;
327b88ab0efb05475fa9d4e2a06175e95e88f507cffBrian Carlstrom                sessionToReuse = getCachedClientSession(clientSessionContext);
328b88ab0efb05475fa9d4e2a06175e95e88f507cffBrian Carlstrom                if (sessionToReuse != null) {
329f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    NativeCrypto.SSL_set_session(sslNativePointer,
330b88ab0efb05475fa9d4e2a06175e95e88f507cffBrian Carlstrom                                                 sessionToReuse.sslSessionNativePointer);
331f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                }
332ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            } else {
333f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                sessionContext = sslParameters.getServerSessionContext();
334b88ab0efb05475fa9d4e2a06175e95e88f507cffBrian Carlstrom                sessionToReuse = null;
335ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            }
336059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom
337f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // setup peer certificate verification
338f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (client) {
339f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // TODO support for anonymous cipher would require us to
340f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // conditionally use SSL_VERIFY_NONE
341f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            } else {
342f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // needing client auth takes priority...
3430c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson                boolean certRequested;
344f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                if (sslParameters.getNeedClientAuth()) {
345f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    NativeCrypto.SSL_set_verify(sslNativePointer,
346f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                NativeCrypto.SSL_VERIFY_PEER
347f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
348f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    certRequested = true;
349f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // ... over just wanting it...
350f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                } else if (sslParameters.getWantClientAuth()) {
351f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    NativeCrypto.SSL_set_verify(sslNativePointer,
352f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                NativeCrypto.SSL_VERIFY_PEER);
353f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    certRequested = true;
354f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // ... and it defaults properly so don't call SSL_set_verify in the common case.
355f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                } else {
356f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    certRequested = false;
357f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                }
358f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom
359f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                if (certRequested) {
360f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    X509TrustManager trustManager = sslParameters.getTrustManager();
361f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    X509Certificate[] issuers = trustManager.getAcceptedIssuers();
362f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    if (issuers != null && issuers.length != 0) {
363f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        byte[][] issuersBytes;
364f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        try {
365d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9aeKenny Root                            issuersBytes = encodeIssuerX509Principals(issuers);
366f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        } catch (CertificateEncodingException e) {
367f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                            throw new IOException("Problem encoding principals", e);
368f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        }
369f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        NativeCrypto.SSL_set_client_CA_list(sslNativePointer, issuersBytes);
370ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom                    }
371ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom                }
372ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            }
373ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
374f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // Temporarily use a different timeout for the handshake process
375615225a35dbd838210270b282d1196deff643b51Brian Carlstrom            int savedReadTimeoutMilliseconds = getSoTimeout();
376615225a35dbd838210270b282d1196deff643b51Brian Carlstrom            int savedWriteTimeoutMilliseconds = getSoWriteTimeout();
377f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
378f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                setSoTimeout(handshakeTimeoutMilliseconds);
379615225a35dbd838210270b282d1196deff643b51Brian Carlstrom                setSoWriteTimeout(handshakeTimeoutMilliseconds);
380f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
381bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
382de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin            // TLS Channel ID
383de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin            if (client) {
384de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin                // Client-side TLS Channel ID
385de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin                if (channelIdPrivateKey != null) {
386de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin                    NativeCrypto.SSL_set1_tls_channel_id(sslNativePointer, channelIdPrivateKey);
387de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin                }
388de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin            } else {
389de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin                // Server-side TLS Channel ID
390de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin                if (channelIdEnabled) {
391de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin                    NativeCrypto.SSL_enable_tls_channel_id(sslNativePointer);
392de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin                }
393de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin            }
394de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin
395f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            int sslSessionNativePointer;
396f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            try {
3975d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                sslSessionNativePointer = NativeCrypto.SSL_do_handshake(sslNativePointer,
39825977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson                        socket.getFileDescriptor$(), this, getSoTimeout(), client, npnProtocols);
399f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            } catch (CertificateException e) {
40054c8a07db3c2d1670c2867ba864d351cb30fecfaBrian Carlstrom                SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage());
40154c8a07db3c2d1670c2867ba864d351cb30fecfaBrian Carlstrom                wrapper.initCause(e);
40254c8a07db3c2d1670c2867ba864d351cb30fecfaBrian Carlstrom                throw wrapper;
403bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            }
404f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            byte[] sessionId = NativeCrypto.SSL_SESSION_session_id(sslSessionNativePointer);
405b88ab0efb05475fa9d4e2a06175e95e88f507cffBrian Carlstrom            if (sessionToReuse != null && Arrays.equals(sessionToReuse.getId(), sessionId)) {
406b88ab0efb05475fa9d4e2a06175e95e88f507cffBrian Carlstrom                this.sslSession = sessionToReuse;
407f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                sslSession.lastAccessedTime = System.currentTimeMillis();
408f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                NativeCrypto.SSL_SESSION_free(sslSessionNativePointer);
409f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            } else {
410f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                if (!enableSessionCreation) {
411f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    // Should have been prevented by NativeCrypto.SSL_set_session_creation_enabled
412f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    throw new IllegalStateException("SSL Session may not be created");
413f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                }
414f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                X509Certificate[] localCertificates
415f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        = createCertChain(NativeCrypto.SSL_get_certificate(sslNativePointer));
416f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                X509Certificate[] peerCertificates
417f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        = createCertChain(NativeCrypto.SSL_get_peer_cert_chain(sslNativePointer));
418b88ab0efb05475fa9d4e2a06175e95e88f507cffBrian Carlstrom                this.sslSession = new OpenSSLSessionImpl(sslSessionNativePointer, localCertificates,
41927c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson                        peerCertificates, getPeerHostName(), getPeerPort(), sessionContext);
420f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // if not, putSession later in handshakeCompleted() callback
421f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                if (handshakeCompleted) {
422f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    sessionContext.putSession(sslSession);
423f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                }
424ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom            }
425f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom
426f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // Restore the original timeout now that the handshake is complete
427f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
428615225a35dbd838210270b282d1196deff643b51Brian Carlstrom                setSoTimeout(savedReadTimeoutMilliseconds);
429615225a35dbd838210270b282d1196deff643b51Brian Carlstrom                setSoWriteTimeout(savedWriteTimeoutMilliseconds);
4309d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor            }
431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
432f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback
433f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (handshakeCompleted) {
434f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                notifyHandshakeCompletedListeners();
435f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
436ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
437f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            exception = false;
438aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        } catch (SSLProtocolException e) {
439aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom            throw new SSLHandshakeException(e);
440f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        } finally {
4418a720cceee7ce319d647738dfeda3f302879f370Brian Carlstrom            // on exceptional exit, treat the socket as closed
442f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (exception) {
4438a720cceee7ce319d647738dfeda3f302879f370Brian Carlstrom                close();
444f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
445adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
446df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom    }
447d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9aeKenny Root
448d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9aeKenny Root    private static byte[][] encodeIssuerX509Principals(X509Certificate[] certificates)
449d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9aeKenny Root            throws CertificateEncodingException {
450d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9aeKenny Root        byte[][] principalBytes = new byte[certificates.length][];
451d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9aeKenny Root        for (int i = 0; i < certificates.length; i++) {
452d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9aeKenny Root            principalBytes[i] = certificates[i].getIssuerX500Principal().getEncoded();
453d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9aeKenny Root        }
454d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9aeKenny Root        return principalBytes;
455d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9aeKenny Root    }
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
4576d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra    String getPeerHostName() {
458f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        if (wrappedHost != null) {
459f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom            return wrappedHost;
460f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        }
461f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        InetAddress inetAddress = super.getInetAddress();
462f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        if (inetAddress != null) {
463f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom            return inetAddress.getHostName();
464f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        }
465f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        return null;
46627c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson    }
46727c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson
4686d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra    int getPeerPort() {
46927c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        return wrappedHost == null ? super.getPort() : wrappedPort;
47027c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson    }
47127c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson
472df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom    /**
473df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom     * Return a possibly null array of X509Certificates given the
474df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom     * possibly null array of DER encoded bytes.
475df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom     */
476b88ab0efb05475fa9d4e2a06175e95e88f507cffBrian Carlstrom    private static X509Certificate[] createCertChain(byte[][] certificatesBytes) throws IOException {
477df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        if (certificatesBytes == null) {
478df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            return null;
479df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        }
480df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        X509Certificate[] certificates = new X509Certificate[certificatesBytes.length];
481df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        for (int i = 0; i < certificatesBytes.length; i++) {
48238375a4d0b3d34e2babbd2f6a013976c7c439696Kenny Root            certificates[i] = OpenSSLX509Certificate.fromX509Der(certificatesBytes[i]);
483df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        }
484df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        return certificates;
485bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    }
486adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
487ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom    private void setCertificate(String alias) throws CertificateEncodingException, SSLException {
4886df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        if (alias == null) {
4896df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            return;
4906df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        }
4916df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        PrivateKey privateKey = sslParameters.getKeyManager().getPrivateKey(alias);
492aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        if (privateKey == null) {
493aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom            return;
494aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        }
4956df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        X509Certificate[] certificates = sslParameters.getKeyManager().getCertificateChain(alias);
496aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        if (certificates == null) {
497aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom            return;
498aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        }
499aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom
5000731d6d00c5e30c05e035d3ae96327029d07a606Kenny Root        if (privateKey instanceof OpenSSLKeyHolder) {
5010731d6d00c5e30c05e035d3ae96327029d07a606Kenny Root            OpenSSLKey key = ((OpenSSLKeyHolder) privateKey).getOpenSSLKey();
502c9acbf1c80d90952f7a4bce83e37c2540e42f6fcKenny Root            NativeCrypto.SSL_use_OpenSSL_PrivateKey(sslNativePointer, key.getPkeyContext());
50341e34229c07e8d05090560ff80558fa222623769Kenny Root        } else if ("PKCS#8".equals(privateKey.getFormat())) {
50441e34229c07e8d05090560ff80558fa222623769Kenny Root            byte[] privateKeyBytes = privateKey.getEncoded();
50541e34229c07e8d05090560ff80558fa222623769Kenny Root            NativeCrypto.SSL_use_PrivateKey(sslNativePointer, privateKeyBytes);
50641e34229c07e8d05090560ff80558fa222623769Kenny Root        } else {
50741e34229c07e8d05090560ff80558fa222623769Kenny Root            throw new SSLException("Unsupported PrivateKey format: " + privateKey.getFormat());
50841e34229c07e8d05090560ff80558fa222623769Kenny Root        }
50941e34229c07e8d05090560ff80558fa222623769Kenny Root
510ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom        byte[][] certificateBytes = NativeCrypto.encodeCertificates(certificates);
5116df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        NativeCrypto.SSL_use_certificate(sslNativePointer, certificateBytes);
5126df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
5136df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        // checks the last installed private key and certificate,
5146df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        // so need to do this once per loop iteration
5156df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        NativeCrypto.SSL_check_private_key(sslNativePointer);
5166df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom    }
5176df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
5180c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / client_cert_cb
519059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom    public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)
520ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            throws CertificateEncodingException, SSLException {
521059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom
522059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        String[] keyTypes = new String[keyTypeBytes.length];
523059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        for (int i = 0; i < keyTypeBytes.length; i++) {
5244ae3fd787741bfe1b808f447dcb0785250024119Brian Carlstrom            keyTypes[i] = CipherSuite.getClientKeyType(keyTypeBytes[i]);
525059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        }
526059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom
527059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        X500Principal[] issuers;
528059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        if (asn1DerEncodedPrincipals == null) {
529059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom            issuers = null;
530059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        } else {
531059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom            issuers = new X500Principal[asn1DerEncodedPrincipals.length];
532059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom            for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
533059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom                issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
534059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom            }
535059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        }
536059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        setCertificate(sslParameters.getKeyManager().chooseClientAlias(keyTypes, issuers, this));
5376df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom    }
5386df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
5390c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / info_callback
540bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public void handshakeCompleted() {
541bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        handshakeCompleted = true;
542adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
543bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // If sslSession is null, the handshake was completed during
544bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // the call to NativeCrypto.SSL_do_handshake and not during a
5450c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson        // later read operation. That means we do not need to fix up
546bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // the SSLSession and session cache or notify
547bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // HandshakeCompletedListeners, it will be done in
548bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // startHandshake.
549bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        if (sslSession == null) {
550bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            return;
551bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        }
552adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
553bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // reset session id from the native pointer and update the
554bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // appropriate cache.
555bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        sslSession.resetId();
556bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        AbstractSessionContext sessionContext =
557bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            (sslParameters.getUseClientMode())
558bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            ? sslParameters.getClientSessionContext()
559bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                : sslParameters.getServerSessionContext();
560adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sessionContext.putSession(sslSession);
561bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
562bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // let listeners know we are finally done
563bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        notifyHandshakeCompletedListeners();
564bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    }
565bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
566bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    private void notifyHandshakeCompletedListeners() {
567bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        if (listeners != null && !listeners.isEmpty()) {
568bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            // notify the listeners
569bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            HandshakeCompletedEvent event =
570bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                new HandshakeCompletedEvent(this, sslSession);
571bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            for (HandshakeCompletedListener listener : listeners) {
572bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                try {
573bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                    listener.handshakeCompleted(event);
574bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                } catch (RuntimeException e) {
575e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    // The RI runs the handlers in a separate thread,
576e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    // which we do not. But we try to preserve their
577e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    // behavior of logging a problem and not killing
578e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    // the handshaking thread just because a listener
579e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    // has a problem.
580e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    Thread thread = Thread.currentThread();
581e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    thread.getUncaughtExceptionHandler().uncaughtException(thread, e);
582bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                }
583bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            }
584bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        }
585adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
586adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
5870c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks
5880c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void verifyCertificateChain(byte[][] bytes, String authMethod)
5896df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            throws CertificateException {
590adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
591e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            if (bytes == null || bytes.length == 0) {
592e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                throw new SSLException("Peer sent no certificate");
593e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            }
594bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            X509Certificate[] peerCertificateChain = new X509Certificate[bytes.length];
595bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            for (int i = 0; i < bytes.length; i++) {
59638375a4d0b3d34e2babbd2f6a013976c7c439696Kenny Root                peerCertificateChain[i] = OpenSSLX509Certificate.fromX509Der(bytes[i]);
597adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
598bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            boolean client = sslParameters.getUseClientMode();
599bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            if (client) {
6006d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                X509TrustManager x509tm = sslParameters.getTrustManager();
6016d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                if (x509tm instanceof TrustManagerImpl) {
6026d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                    TrustManagerImpl tm = (TrustManagerImpl) x509tm;
6036d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                    tm.checkServerTrusted(peerCertificateChain, authMethod, wrappedHost);
6046d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                } else {
6056d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                    x509tm.checkServerTrusted(peerCertificateChain, authMethod);
6066d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                }
607bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            } else {
6084ae3fd787741bfe1b808f447dcb0785250024119Brian Carlstrom                String authType = peerCertificateChain[0].getPublicKey().getAlgorithm();
6096df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom                sslParameters.getTrustManager().checkClientTrusted(peerCertificateChain,
6104ae3fd787741bfe1b808f447dcb0785250024119Brian Carlstrom                                                                   authType);
611adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
612bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
613bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        } catch (CertificateException e) {
614bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            throw e;
615bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        } catch (Exception e) {
6168c4a407e34de1b348316a9175bd1c0577c887181Brian Carlstrom            throw new CertificateException(e);
617adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
618adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
619adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
6200c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public InputStream getInputStream() throws IOException {
6215f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom        checkOpen();
622ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom        synchronized (this) {
623adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (is == null) {
624adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                is = new SSLInputStream();
625adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
626adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
627adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return is;
628adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
629adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
630adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
6310c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public OutputStream getOutputStream() throws IOException {
6325f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom        checkOpen();
633ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom        synchronized (this) {
634adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (os == null) {
635adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                os = new SSLOutputStream();
636adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
637adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
638adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return os;
639adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
640adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
641adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
642bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    /**
643adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This inner class provides input data stream functionality
644adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * for the OpenSSL native implementation. It is used to
645adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * read data received via SSL protocol.
646adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
647adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private class SSLInputStream extends InputStream {
648adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        SSLInputStream() throws IOException {
649679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson            /*
650679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson             * Note: When startHandshake() throws an exception, no
651adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * SSLInputStream object will be created.
652adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             */
653679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson            OpenSSLSocketImpl.this.startHandshake();
654adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
655adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
656adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
657adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Reads one byte. If there is no data in the underlying buffer,
658adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * this operation can block until the data will be
659adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * available.
660adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @return read value.
661adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @throws <code>IOException</code>
662adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
6634559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        @Override
664adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int read() throws IOException {
665638000042da777f6d628d88dadde957c52597710Brian Carlstrom            return Streams.readSingleByte(this);
666adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
667adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
668adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
669adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Method acts as described in spec for superclass.
670adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @see java.io.InputStream#read(byte[],int,int)
671adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
6724559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        @Override
673a1603838fe9e865575c87982e32c6343740e464cElliott Hughes        public int read(byte[] buf, int offset, int byteCount) throws IOException {
6745900e5546059f05d5e58e5732e4d08d83b8b7574Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
675ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            synchronized (readLock) {
67612e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                checkOpen();
677a1603838fe9e865575c87982e32c6343740e464cElliott Hughes                Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
678a1603838fe9e865575c87982e32c6343740e464cElliott Hughes                if (byteCount == 0) {
67912e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                    return 0;
68012e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                }
6815d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                return NativeCrypto.SSL_read(sslNativePointer, socket.getFileDescriptor$(),
6825d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                        OpenSSLSocketImpl.this, buf, offset, byteCount, getSoTimeout());
683adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
684adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
685adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
686adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
687adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
688adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This inner class provides output data stream functionality
689adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * for the OpenSSL native implementation. It is used to
690adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * write data according to the encryption parameters given in SSL context.
691adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
692adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private class SSLOutputStream extends OutputStream {
693adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        SSLOutputStream() throws IOException {
694679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson            /*
695679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson             * Note: When startHandshake() throws an exception, no
696ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom             * SSLOutputStream object will be created.
697adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             */
698679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson            OpenSSLSocketImpl.this.startHandshake();
699adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
700adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
701adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
702adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Method acts as described in spec for superclass.
703adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @see java.io.OutputStream#write(int)
704adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
7054559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        @Override
706638000042da777f6d628d88dadde957c52597710Brian Carlstrom        public void write(int oneByte) throws IOException {
707638000042da777f6d628d88dadde957c52597710Brian Carlstrom            Streams.writeSingleByte(this, oneByte);
708adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
709adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
710adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
711adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Method acts as described in spec for superclass.
712adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @see java.io.OutputStream#write(byte[],int,int)
713adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
7144559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        @Override
715a1603838fe9e865575c87982e32c6343740e464cElliott Hughes        public void write(byte[] buf, int offset, int byteCount) throws IOException {
7165900e5546059f05d5e58e5732e4d08d83b8b7574Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
717ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            synchronized (writeLock) {
71812e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                checkOpen();
719a1603838fe9e865575c87982e32c6343740e464cElliott Hughes                Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
720a1603838fe9e865575c87982e32c6343740e464cElliott Hughes                if (byteCount == 0) {
72112e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                    return;
72212e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                }
7235d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                NativeCrypto.SSL_write(sslNativePointer, socket.getFileDescriptor$(),
724615225a35dbd838210270b282d1196deff643b51Brian Carlstrom                        OpenSSLSocketImpl.this, buf, offset, byteCount, writeTimeoutMilliseconds);
725adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
726adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
727adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
728adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
729adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7300c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public SSLSession getSession() {
731df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        if (sslSession == null) {
732df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            try {
733679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson                startHandshake();
734df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            } catch (IOException e) {
735df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom                // return an invalid session with
736df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom                // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
737df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom                return SSLSessionImpl.NULL_SESSION;
738df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            }
739adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
740adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sslSession;
741adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
742adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7430c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void addHandshakeCompletedListener(
744adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            HandshakeCompletedListener listener) {
745adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (listener == null) {
746adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
747adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
748adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (listeners == null) {
7490c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson            listeners = new ArrayList<HandshakeCompletedListener>();
750adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
751adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        listeners.add(listener);
752adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
753adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7540c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void removeHandshakeCompletedListener(
755adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            HandshakeCompletedListener listener) {
756adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (listener == null) {
757adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
758adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
759adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (listeners == null) {
760adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException(
761adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    "Provided listener is not registered");
762adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
763adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!listeners.remove(listener)) {
764adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException(
765adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    "Provided listener is not registered");
766adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
767adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
768adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7690c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public boolean getEnableSessionCreation() {
770adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sslParameters.getEnableSessionCreation();
771adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
772adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7730c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setEnableSessionCreation(boolean flag) {
774adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sslParameters.setEnableSessionCreation(flag);
775adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
776adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7770c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public String[] getSupportedCipherSuites() {
778ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        return NativeCrypto.getSupportedCipherSuites();
779adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
780adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7810c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public String[] getEnabledCipherSuites() {
782bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        return enabledCipherSuites.clone();
783adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
784adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7850c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setEnabledCipherSuites(String[] suites) {
786bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(suites);
787adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
788adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7890c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public String[] getSupportedProtocols() {
790ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        return NativeCrypto.getSupportedProtocols();
791adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
792adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7930c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public String[] getEnabledProtocols() {
794bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        return enabledProtocols.clone();
795adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
796adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7970c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setEnabledProtocols(String[] protocols) {
798bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        enabledProtocols = NativeCrypto.checkEnabledProtocols(protocols);
799adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
800adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
801adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
8024559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * This method enables session ticket support.
8034559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     *
8044559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * @param useSessionTickets True to enable session tickets
8054559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     */
8064559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    public void setUseSessionTickets(boolean useSessionTickets) {
8074559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        this.useSessionTickets = useSessionTickets;
8084559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    }
8094559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom
8104559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    /**
8114559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * This method enables Server Name Indication
8124559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     *
8134559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * @param hostname the desired SNI hostname, or null to disable
8144559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     */
8154559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    public void setHostname(String hostname) {
8164559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        this.hostname = hostname;
8174559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    }
8184559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom
819de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    /**
820de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * Enables/disables TLS Channel ID for this server socket.
821de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *
822de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * <p>This method needs to be invoked before the handshake starts.
823de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *
824de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * @throws IllegalStateException if this is a client socket or if the handshake has already
825de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *         started.
826de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin
827de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     */
828de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    public void setChannelIdEnabled(boolean enabled) {
829de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        if (getUseClientMode()) {
830de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin            throw new IllegalStateException("Client mode");
831de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        }
832de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        if (handshakeStarted) {
833de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin            throw new IllegalStateException(
834de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin                    "Could not enable/disable Channel ID after the initial handshake has"
835de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin                    + " begun.");
836de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        }
837de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        this.channelIdEnabled = enabled;
838de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    }
839de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin
840de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    /**
841de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * Gets the TLS Channel ID for this server socket. Channel ID is only available once the
842de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * handshake completes.
843de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *
844de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * @return channel ID or {@code null} if not available.
845de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *
846de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * @throws IllegalStateException if this is a client socket or if the handshake has not yet
847de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *         completed.
848de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * @throws SSLException if channel ID is available but could not be obtained.
849de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     */
850de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    public byte[] getChannelId() throws SSLException {
851de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        if (getUseClientMode()) {
852de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin            throw new IllegalStateException("Client mode");
853de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        }
854de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        if (!handshakeCompleted) {
855de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin            throw new IllegalStateException(
856de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin                    "Channel ID is only available after handshake completes");
857de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        }
858de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        return NativeCrypto.SSL_get_tls_channel_id(sslNativePointer);
859de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    }
860de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin
861de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    /**
862de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * Sets the {@link PrivateKey} to be used for TLS Channel ID by this client socket.
863de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *
864de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * <p>This method needs to be invoked before the handshake starts.
865de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *
866de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key (disables
867c17bdfa469de6c48f16e454611caae3aaa82cc9dAlex Klyubin     *        TLS Channel ID). The private key must be an Elliptic Curve (EC) key based on the NIST
868de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *        P-256 curve (aka SECG secp256r1 or ANSI X9.62 prime256v1).
869de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *
870de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * @throws IllegalStateException if this is a server socket or if the handshake has already
871de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *         started.
872de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     */
873c17bdfa469de6c48f16e454611caae3aaa82cc9dAlex Klyubin    public void setChannelIdPrivateKey(PrivateKey privateKey) {
874de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        if (!getUseClientMode()) {
875de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin            throw new IllegalStateException("Server mode");
876de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        }
877de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        if (handshakeStarted) {
878de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin            throw new IllegalStateException(
879de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin                    "Could not change Channel ID private key after the initial handshake has"
880de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin                    + " begun.");
881de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        }
882de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        this.channelIdPrivateKey = privateKey;
883de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    }
884de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin
8850c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public boolean getUseClientMode() {
886adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sslParameters.getUseClientMode();
887adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
888adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8890c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setUseClientMode(boolean mode) {
890adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (handshakeStarted) {
891adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException(
8920c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson                    "Could not change the mode after the initial handshake has begun.");
893adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
894adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sslParameters.setUseClientMode(mode);
895adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
896adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8970c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public boolean getWantClientAuth() {
898adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sslParameters.getWantClientAuth();
899adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
900adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
9010c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public boolean getNeedClientAuth() {
902adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sslParameters.getNeedClientAuth();
903adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
904adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
9050c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setNeedClientAuth(boolean need) {
906adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sslParameters.setNeedClientAuth(need);
907adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
908adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
9090c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setWantClientAuth(boolean want) {
910adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sslParameters.setWantClientAuth(want);
911adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
912adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
9130c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void sendUrgentData(int data) throws IOException {
9140c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson        throw new SocketException("Method sendUrgentData() is not supported.");
915adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
916adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
9170c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setOOBInline(boolean on) throws SocketException {
9180c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson        throw new SocketException("Methods sendUrgentData, setOOBInline are not supported.");
919adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
920adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
921615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    @Override public void setSoTimeout(int readTimeoutMilliseconds) throws SocketException {
922615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        super.setSoTimeout(readTimeoutMilliseconds);
923615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        this.readTimeoutMilliseconds = readTimeoutMilliseconds;
924a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom    }
925a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom
9260c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public int getSoTimeout() throws SocketException {
927615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        return readTimeoutMilliseconds;
928615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    }
929615225a35dbd838210270b282d1196deff643b51Brian Carlstrom
930615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    /**
931615225a35dbd838210270b282d1196deff643b51Brian Carlstrom     * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
932615225a35dbd838210270b282d1196deff643b51Brian Carlstrom     */
933615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    public void setSoWriteTimeout(int writeTimeoutMilliseconds) throws SocketException {
934615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        this.writeTimeoutMilliseconds = writeTimeoutMilliseconds;
935615225a35dbd838210270b282d1196deff643b51Brian Carlstrom
936615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        StructTimeval tv = StructTimeval.fromMillis(writeTimeoutMilliseconds);
937615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        try {
938615225a35dbd838210270b282d1196deff643b51Brian Carlstrom            Libcore.os.setsockoptTimeval(getFileDescriptor$(), SOL_SOCKET, SO_SNDTIMEO, tv);
939615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        } catch (ErrnoException errnoException) {
940615225a35dbd838210270b282d1196deff643b51Brian Carlstrom            throw errnoException.rethrowAsSocketException();
941615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        }
942615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    }
943615225a35dbd838210270b282d1196deff643b51Brian Carlstrom
944615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    /**
945615225a35dbd838210270b282d1196deff643b51Brian Carlstrom     * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
946615225a35dbd838210270b282d1196deff643b51Brian Carlstrom     */
947615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    public int getSoWriteTimeout() throws SocketException {
948615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        return writeTimeoutMilliseconds;
949adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
950adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
9519d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor    /**
9529d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor     * Set the handshake timeout on this socket.  This timeout is specified in
9539d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor     * milliseconds and will be used only during the handshake process.
9549d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor     */
955615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    public void setHandshakeTimeout(int handshakeTimeoutMilliseconds) throws SocketException {
956615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        this.handshakeTimeoutMilliseconds = handshakeTimeoutMilliseconds;
9579d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor    }
9589d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor
9590c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void close() throws IOException {
9600c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson        // TODO: Close SSL sockets using a background thread so they close gracefully.
961adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
962adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (handshakeLock) {
963adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!handshakeStarted) {
9640c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson                // prevent further attempts to start handshake
965adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                handshakeStarted = true;
966ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
967adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                synchronized (this) {
968ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom                    free();
969adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
970df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom                    if (socket != this) {
971adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (autoClose && !socket.isClosed()) socket.close();
972adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    } else {
973adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (!super.isClosed()) super.close();
974adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
975adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
976ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
977adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return;
978adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
979adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
980adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
981adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (this) {
982adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
983783004cceef470884b3ee6946cbbfc4af0f28ae7Brian Carlstrom            // Interrupt any outstanding reads or writes before taking the writeLock and readLock
984783004cceef470884b3ee6946cbbfc4af0f28ae7Brian Carlstrom            NativeCrypto.SSL_interrupt(sslNativePointer);
985df9f5967a3b8dc2f61183d155791393b67980511Brian Carlstrom
986783004cceef470884b3ee6946cbbfc4af0f28ae7Brian Carlstrom            synchronized (writeLock) {
987783004cceef470884b3ee6946cbbfc4af0f28ae7Brian Carlstrom                synchronized (readLock) {
988adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // Shut down the SSL connection, per se.
989adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    try {
990adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (handshakeStarted) {
9915900e5546059f05d5e58e5732e4d08d83b8b7574Brad Fitzpatrick                            BlockGuard.getThreadPolicy().onNetwork();
9925d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                            NativeCrypto.SSL_shutdown(sslNativePointer, socket.getFileDescriptor$(),
9935d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                                    this);
994adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
9951c64b3adb85345659ac60ad82216268acba18764Brian Carlstrom                    } catch (IOException ignored) {
996adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        /*
9971c64b3adb85345659ac60ad82216268acba18764Brian Carlstrom                         * Note that although close() can throw
9981c64b3adb85345659ac60ad82216268acba18764Brian Carlstrom                         * IOException, the RI does not throw if there
9991c64b3adb85345659ac60ad82216268acba18764Brian Carlstrom                         * is problem sending a "close notify" which
10001c64b3adb85345659ac60ad82216268acba18764Brian Carlstrom                         * can happen if the underlying socket is closed.
1001adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                         */
1002d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                    } finally {
1003d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                        /*
1004d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                         * Even if the above call failed, it is still safe to free
1005d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                         * the native structs, and we need to do so lest we leak
1006d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                         * memory.
1007d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                         */
1008d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                        free();
1009d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom
1010d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                        if (socket != this) {
1011d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                            if (autoClose && !socket.isClosed()) {
1012d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                                socket.close();
1013d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                            }
1014d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                        } else {
1015d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                            if (!super.isClosed()) {
1016d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                                super.close();
1017d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                            }
1018d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                        }
1019adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
1020adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
1021adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
1022adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1023adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
1024adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1025ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    private void free() {
1026ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        if (sslNativePointer == 0) {
1027ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom            return;
1028ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        }
1029ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        NativeCrypto.SSL_free(sslNativePointer);
1030ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        sslNativePointer = 0;
1031f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        guard.close();
1032ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    }
1033adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1034e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom    @Override protected void finalize() throws Throwable {
1035e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        try {
1036e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            /*
1037e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * Just worry about our own state. Notably we do not try and
1038e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * close anything. The SocketImpl, either our own
1039e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * PlainSocketImpl, or the Socket we are wrapping, will do
1040e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * that. This might mean we do not properly SSL_shutdown, but
1041e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * if you want to do that, properly close the socket yourself.
1042e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             *
1043e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * The reason why we don't try to SSL_shutdown, is that there
1044e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * can be a race between finalizers where the PlainSocketImpl
1045e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * finalizer runs first and closes the socket. However, in the
1046e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * meanwhile, the underlying file descriptor could be reused
1047e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * for another purpose. If we call SSL_shutdown, the
1048e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * underlying socket BIOs still have the old file descriptor
1049e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * and will write the close notify to some unsuspecting
1050e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * reader.
1051e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             */
105212f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom            if (guard != null) {
105312f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom                guard.warnIfOpen();
105412f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom            }
1055e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            free();
1056e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        } finally {
1057e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            super.finalize();
1058e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        }
1059adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
10603267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey
10613267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey    @Override
10623267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey    public FileDescriptor getFileDescriptor$() {
10633267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey        if (socket == this) {
10643267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey            return super.getFileDescriptor$();
10653267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey        } else {
10663267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey            return socket.getFileDescriptor$();
10673267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey        }
10683267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey    }
106925977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson
107025977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    /**
107125977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     * Returns the protocol agreed upon by client and server, or null if no
107225977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     * protocol was agreed upon.
107325977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     */
107425977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    public byte[] getNpnSelectedProtocol() {
1075600dc4949de6bf5608e5f5a5214cde59299b683aJesse Wilson        return NativeCrypto.SSL_get_npn_negotiated_protocol(sslNativePointer);
107625977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    }
107725977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson
107825977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    /**
107925977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     * Sets the list of protocols this peer is interested in. If null no
108025977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     * protocols will be used.
108125977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     *
10821982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson     * @param npnProtocols a non-empty array of protocol names. From
10831982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson     *     SSL_select_next_proto, "vector of 8-bit, length prefixed byte
10841982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson     *     strings. The length byte itself is not included in the length. A byte
10851982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson     *     string of length 0 is invalid. No byte string may be truncated.".
108625977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     */
108725977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    public void setNpnProtocols(byte[] npnProtocols) {
10881982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson        if (npnProtocols != null && npnProtocols.length == 0) {
10891982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson            throw new IllegalArgumentException("npnProtocols.length == 0");
10901982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson        }
109125977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson        this.npnProtocols = npnProtocols;
109225977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    }
1093adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
1094