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;
284f60362bb61f8199f3e97371eff96461fbacba68Kenny Rootimport java.security.InvalidKeyException;
296df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstromimport java.security.PrivateKey;
306df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstromimport java.security.SecureRandom;
3112cd1f00c2fa1a7f37bf644cecdf7588bdc0b0a9Brian Carlstromimport java.security.cert.CertificateEncodingException;
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.cert.CertificateException;
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.cert.X509Certificate;
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.ArrayList;
35a1603838fe9e865575c87982e32c6343740e464cElliott Hughesimport java.util.Arrays;
366c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstromimport java.util.HashSet;
376c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstromimport java.util.Set;
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport javax.net.ssl.HandshakeCompletedEvent;
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport javax.net.ssl.HandshakeCompletedListener;
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport javax.net.ssl.SSLException;
412915378e253f08e47fe5a9bfd026cd1ca7c6c351Brian Carlstromimport javax.net.ssl.SSLHandshakeException;
42b88ab0efb05475fa9d4e2a06175e95e88f507cffBrian Carlstromimport javax.net.ssl.SSLPeerUnverifiedException;
43aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstromimport javax.net.ssl.SSLProtocolException;
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport javax.net.ssl.SSLSession;
45f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstromimport javax.net.ssl.X509TrustManager;
46059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstromimport javax.security.auth.x500.X500Principal;
47615225a35dbd838210270b282d1196deff643b51Brian Carlstromimport static libcore.io.OsConstants.*;
48615225a35dbd838210270b282d1196deff643b51Brian Carlstromimport libcore.io.ErrnoException;
49615225a35dbd838210270b282d1196deff643b51Brian Carlstromimport libcore.io.Libcore;
50638000042da777f6d628d88dadde957c52597710Brian Carlstromimport libcore.io.Streams;
51615225a35dbd838210270b282d1196deff643b51Brian Carlstromimport libcore.io.StructTimeval;
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
544559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * Implementation of the class OpenSSLSocketImpl based on OpenSSL.
554559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <p>
564559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * Extensions to SSLSocket include:
574559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <ul>
584559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <li>handshake timeout
594559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <li>session tickets
604559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <li>Server Name Indication
614559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * </ul>
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
63ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrompublic class OpenSSLSocketImpl
64ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        extends javax.net.ssl.SSLSocket
656df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        implements NativeCrypto.SSLHandshakeCallbacks {
66df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom
678acd6134dc84b387608746fbf2054c6d7dcd4f52Joel Dice    private long sslNativePointer;
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private InputStream is;
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private OutputStream os;
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final Object handshakeLock = new Object();
71ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    private final Object readLock = new Object();
72ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    private final Object writeLock = new Object();
736812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    private SSLParametersImpl sslParameters;
7425977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    private byte[] npnProtocols;
75d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root    private byte[] alpnProtocols;
76bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    private String[] enabledProtocols;
77bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    private String[] enabledCipherSuites;
784559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    private boolean useSessionTickets;
794559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    private String hostname;
80de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    /** Whether the TLS Channel ID extension is enabled. This field is server-side only. */
81de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    private boolean channelIdEnabled;
82de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    /** Private key for the TLS Channel ID extension. This field is client-side only. */
834f60362bb61f8199f3e97371eff96461fbacba68Kenny Root    private OpenSSLKey channelIdPrivateKey;
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private OpenSSLSessionImpl sslSession;
85df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom    private final Socket socket;
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private boolean autoClose;
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private boolean handshakeStarted = false;
8812f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom    private final CloseGuard guard = CloseGuard.get();
89bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
90bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    /**
91bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * Not set to true until the update from native that tells us the
92bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * full handshake is complete, since SSL_do_handshake can return
93bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * before the handshake is completely done due to
94bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * handshake_cutthrough support.
95bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     */
96bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    private boolean handshakeCompleted = false;
97bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private ArrayList<HandshakeCompletedListener> listeners;
99a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom
100a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom    /**
101a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom     * Local cache of timeout to avoid getsockopt on every read and
102a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom     * write for non-wrapped sockets. Note that
103a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom     * OpenSSLSocketImplWrapper overrides setSoTimeout and
104a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom     * getSoTimeout to delegate to the wrapped socket.
105a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom     */
106615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    private int readTimeoutMilliseconds = 0;
107615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    private int writeTimeoutMilliseconds = 0;
108a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom
109a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom    private int handshakeTimeoutMilliseconds = -1;  // -1 = same as timeout; 0 = infinite
110a653cca054f36de92bbef8498be3f0f01d9d6119Brian Carlstrom    private String wrappedHost;
111a653cca054f36de92bbef8498be3f0f01d9d6119Brian Carlstrom    private int wrappedPort;
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1136812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    protected OpenSSLSocketImpl(SSLParametersImpl sslParameters) throws IOException {
114df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom        this.socket = this;
115ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        init(sslParameters);
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1186812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    protected OpenSSLSocketImpl(SSLParametersImpl sslParameters,
119bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                                String[] enabledProtocols,
1207695a9b3261bfee3a810e0829bd8082fe1fcb6a4Brian Carlstrom                                String[] enabledCipherSuites) throws IOException {
121df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom        this.socket = this;
1227695a9b3261bfee3a810e0829bd8082fe1fcb6a4Brian Carlstrom        init(sslParameters, enabledProtocols, enabledCipherSuites);
123bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    }
124bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
1256812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    protected OpenSSLSocketImpl(String host, int port, SSLParametersImpl sslParameters)
126df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom            throws IOException {
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(host, port);
128df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom        this.socket = this;
129ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        init(sslParameters);
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1326812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    protected OpenSSLSocketImpl(InetAddress address, int port, SSLParametersImpl sslParameters)
133df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom            throws IOException {
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(address, port);
135df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom        this.socket = this;
136ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        init(sslParameters);
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1400c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom    protected OpenSSLSocketImpl(String host, int port,
1410c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                                InetAddress clientAddress, int clientPort,
1420c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson                                SSLParametersImpl sslParameters) throws IOException {
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(host, port, clientAddress, clientPort);
144df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom        this.socket = this;
145ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        init(sslParameters);
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected OpenSSLSocketImpl(InetAddress address, int port,
1490c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                                InetAddress clientAddress, int clientPort,
1500c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson                                SSLParametersImpl sslParameters) throws IOException {
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(address, port, clientAddress, clientPort);
152df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom        this.socket = this;
153ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        init(sslParameters);
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1570c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson     * Create an SSL socket that wraps another socket. Invoked by
1580c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson     * OpenSSLSocketImplWrapper constructor.
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected OpenSSLSocketImpl(Socket socket, String host, int port,
1616812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom            boolean autoClose, SSLParametersImpl sslParameters) throws IOException {
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.socket = socket;
163a653cca054f36de92bbef8498be3f0f01d9d6119Brian Carlstrom        this.wrappedHost = host;
164a653cca054f36de92bbef8498be3f0f01d9d6119Brian Carlstrom        this.wrappedPort = port;
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.autoClose = autoClose;
166ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        init(sslParameters);
167a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom
168a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom        // this.timeout is not set intentionally.
169a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom        // OpenSSLSocketImplWrapper.getSoTimeout will delegate timeout
170a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom        // to wrapped socket
171ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    }
172ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
173ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    /**
174ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom     * Initialize the SSL socket and set the certificates for the
175ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom     * future handshaking.
176ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom     */
1776812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    private void init(SSLParametersImpl sslParameters) throws IOException {
178bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        init(sslParameters,
1793d74b4bec8543e6e3f89eafe3afe0925f3a69f01Brian Carlstrom             NativeCrypto.getDefaultProtocols(),
1807695a9b3261bfee3a810e0829bd8082fe1fcb6a4Brian Carlstrom             NativeCrypto.getDefaultCipherSuites());
181ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    }
182ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
183ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    /**
184bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * Initialize the SSL socket and set the certificates for the
185bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * future handshaking.
186ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom     */
1876812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    private void init(SSLParametersImpl sslParameters,
188bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                      String[] enabledProtocols,
1897695a9b3261bfee3a810e0829bd8082fe1fcb6a4Brian Carlstrom                      String[] enabledCipherSuites) throws IOException {
190bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        this.sslParameters = sslParameters;
191bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        this.enabledProtocols = enabledProtocols;
192bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        this.enabledCipherSuites = enabledCipherSuites;
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the suitable session reference from the session cache container.
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
198bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    private OpenSSLSessionImpl getCachedClientSession(ClientSessionContext sessionContext) {
19927c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        String hostName = getPeerHostName();
20027c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        int port = getPeerPort();
20127c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        if (hostName == null) {
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
20427c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        OpenSSLSessionImpl session = (OpenSSLSessionImpl) sessionContext.getSession(hostName, port);
2059acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        if (session == null) {
2069acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            return null;
2079acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2089acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom
2099acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        String protocol = session.getProtocol();
2109acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        boolean protocolFound = false;
2119acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        for (String enabledProtocol : enabledProtocols) {
2129acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            if (protocol.equals(enabledProtocol)) {
2139acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                protocolFound = true;
2149acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                break;
2159acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            }
2169acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2179acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        if (!protocolFound) {
2189acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            return null;
2199acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2209acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom
2219acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        String cipherSuite = session.getCipherSuite();
2229acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        boolean cipherSuiteFound = false;
2239acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        for (String enabledCipherSuite : enabledCipherSuites) {
2249acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            if (cipherSuite.equals(enabledCipherSuite)) {
2259acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                cipherSuiteFound = true;
2269acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                break;
2279acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            }
2289acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2299acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        if (!cipherSuiteFound) {
2309acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            return null;
2319acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2326df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
2339acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        return session;
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2365f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom    private void checkOpen() throws SocketException {
2375f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom        if (isClosed()) {
2385f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom            throw new SocketException("Socket is closed");
2395f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom        }
2405f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom    }
2415f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom
2425f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom    /**
243679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson     * Starts a TLS/SSL handshake on this connection using some native methods
244679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson     * from the OpenSSL library. It can negotiate new encryption keys, change
245679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson     * cipher suites, or initiate a new session. The certificate chain is
246679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson     * verified if the correspondent property in java.Security is set. All
247679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson     * listeners are notified at the end of the TLS/SSL handshake.
248bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     */
249679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson    @Override public synchronized void startHandshake() throws IOException {
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (handshakeLock) {
25112e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom            checkOpen();
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!handshakeStarted) {
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                handshakeStarted = true;
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return;
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2596df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        // note that this modifies the global seed, not something specific to the connection
2606df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        final int seedLengthInBytes = NativeCrypto.RAND_SEED_LENGTH_IN_BYTES;
2616df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        final SecureRandom secureRandom = sslParameters.getSecureRandomMember();
2626df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        if (secureRandom == null) {
2636df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            NativeCrypto.RAND_load_file("/dev/urandom", seedLengthInBytes);
2646df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        } else {
2656df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            NativeCrypto.RAND_seed(secureRandom.generateSeed(seedLengthInBytes));
2666df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        }
2676df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
2686df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        final boolean client = sslParameters.getUseClientMode();
2696df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
2708acd6134dc84b387608746fbf2054c6d7dcd4f52Joel Dice        final long sslCtxNativePointer = (client) ?
2716df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            sslParameters.getClientSessionContext().sslCtxNativePointer :
2726df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            sslParameters.getServerSessionContext().sslCtxNativePointer;
2736df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
274f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        this.sslNativePointer = 0;
275f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        boolean exception = true;
276f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        try {
277f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer);
278f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            guard.open("close");
2796df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
28025977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson            if (npnProtocols != null) {
28125977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson                NativeCrypto.SSL_CTX_enable_npn(sslCtxNativePointer);
28225977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson            }
28325977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson
284d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root            if (client && alpnProtocols != null) {
285d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root                NativeCrypto.SSL_CTX_set_alpn_protos(sslCtxNativePointer, alpnProtocols);
286d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root            }
287d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root
288f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // setup server certificates and private keys.
289f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // clients will receive a call back to request certificates.
290f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (!client) {
2916c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                Set<String> keyTypes = new HashSet<String>();
2926c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                for (String enabledCipherSuite : enabledCipherSuites) {
293ffeba5dd766602f6e2be9caa9081744348a53c04Brian Carlstrom                    if (enabledCipherSuite.equals(NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {
294ffeba5dd766602f6e2be9caa9081744348a53c04Brian Carlstrom                        continue;
295ffeba5dd766602f6e2be9caa9081744348a53c04Brian Carlstrom                    }
2964ae3fd787741bfe1b808f447dcb0785250024119Brian Carlstrom                    String keyType = CipherSuite.getByName(enabledCipherSuite).getServerKeyType();
2976c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                    if (keyType != null) {
2986c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                        keyTypes.add(keyType);
2996c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                    }
3006c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                }
3016c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                for (String keyType : keyTypes) {
302f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    try {
303f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        setCertificate(sslParameters.getKeyManager().chooseServerAlias(keyType,
304f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                                                       null,
305f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                                                       this));
306f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    } catch (CertificateEncodingException e) {
307f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        throw new IOException(e);
308f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    }
309ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom                }
3106df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            }
3116df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
312f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            NativeCrypto.setEnabledProtocols(sslNativePointer, enabledProtocols);
313f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            NativeCrypto.setEnabledCipherSuites(sslNativePointer, enabledCipherSuites);
314f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (useSessionTickets) {
315f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                NativeCrypto.SSL_clear_options(sslNativePointer, NativeCrypto.SSL_OP_NO_TICKET);
316f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
317f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (hostname != null) {
318f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                NativeCrypto.SSL_set_tlsext_host_name(sslNativePointer, hostname);
319f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
320bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
321f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            boolean enableSessionCreation = sslParameters.getEnableSessionCreation();
322f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (!enableSessionCreation) {
323f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer,
324f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                              enableSessionCreation);
325bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            }
326bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
327f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            AbstractSessionContext sessionContext;
328b88ab0efb05475fa9d4e2a06175e95e88f507cffBrian Carlstrom            OpenSSLSessionImpl sessionToReuse;
329f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (client) {
330f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // look for client session to reuse
331f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                ClientSessionContext clientSessionContext = sslParameters.getClientSessionContext();
332f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                sessionContext = clientSessionContext;
333b88ab0efb05475fa9d4e2a06175e95e88f507cffBrian Carlstrom                sessionToReuse = getCachedClientSession(clientSessionContext);
334b88ab0efb05475fa9d4e2a06175e95e88f507cffBrian Carlstrom                if (sessionToReuse != null) {
335f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    NativeCrypto.SSL_set_session(sslNativePointer,
336b88ab0efb05475fa9d4e2a06175e95e88f507cffBrian Carlstrom                                                 sessionToReuse.sslSessionNativePointer);
337f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                }
338ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            } else {
339f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                sessionContext = sslParameters.getServerSessionContext();
340b88ab0efb05475fa9d4e2a06175e95e88f507cffBrian Carlstrom                sessionToReuse = null;
341ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            }
342059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom
343f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // setup peer certificate verification
344f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (client) {
345f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // TODO support for anonymous cipher would require us to
346f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // conditionally use SSL_VERIFY_NONE
347f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            } else {
348f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // needing client auth takes priority...
3490c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson                boolean certRequested;
350f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                if (sslParameters.getNeedClientAuth()) {
351f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    NativeCrypto.SSL_set_verify(sslNativePointer,
352f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                NativeCrypto.SSL_VERIFY_PEER
353f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
354f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    certRequested = true;
355f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // ... over just wanting it...
356f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                } else if (sslParameters.getWantClientAuth()) {
357f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    NativeCrypto.SSL_set_verify(sslNativePointer,
358f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                NativeCrypto.SSL_VERIFY_PEER);
359f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    certRequested = true;
360f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // ... and it defaults properly so don't call SSL_set_verify in the common case.
361f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                } else {
362f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    certRequested = false;
363f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                }
364f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom
365f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                if (certRequested) {
366f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    X509TrustManager trustManager = sslParameters.getTrustManager();
367f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    X509Certificate[] issuers = trustManager.getAcceptedIssuers();
368f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    if (issuers != null && issuers.length != 0) {
369f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        byte[][] issuersBytes;
370f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        try {
371d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9aeKenny Root                            issuersBytes = encodeIssuerX509Principals(issuers);
372f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        } catch (CertificateEncodingException e) {
373f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                            throw new IOException("Problem encoding principals", e);
374f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        }
375f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        NativeCrypto.SSL_set_client_CA_list(sslNativePointer, issuersBytes);
376ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom                    }
377ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom                }
378ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            }
379ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
380f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // Temporarily use a different timeout for the handshake process
381615225a35dbd838210270b282d1196deff643b51Brian Carlstrom            int savedReadTimeoutMilliseconds = getSoTimeout();
382615225a35dbd838210270b282d1196deff643b51Brian Carlstrom            int savedWriteTimeoutMilliseconds = getSoWriteTimeout();
383f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
384f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                setSoTimeout(handshakeTimeoutMilliseconds);
385615225a35dbd838210270b282d1196deff643b51Brian Carlstrom                setSoWriteTimeout(handshakeTimeoutMilliseconds);
386f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
387bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
388de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin            // TLS Channel ID
3894f60362bb61f8199f3e97371eff96461fbacba68Kenny Root            if (channelIdEnabled) {
3904f60362bb61f8199f3e97371eff96461fbacba68Kenny Root                if (client) {
3914f60362bb61f8199f3e97371eff96461fbacba68Kenny Root                    // Client-side TLS Channel ID
3924f60362bb61f8199f3e97371eff96461fbacba68Kenny Root                    if (channelIdPrivateKey == null) {
3934f60362bb61f8199f3e97371eff96461fbacba68Kenny Root                        throw new SSLHandshakeException("Invalid TLS channel ID key specified");
3944f60362bb61f8199f3e97371eff96461fbacba68Kenny Root                    }
3954f60362bb61f8199f3e97371eff96461fbacba68Kenny Root                    NativeCrypto.SSL_set1_tls_channel_id(sslNativePointer,
3964f60362bb61f8199f3e97371eff96461fbacba68Kenny Root                            channelIdPrivateKey.getPkeyContext());
3974f60362bb61f8199f3e97371eff96461fbacba68Kenny Root                } else {
3984f60362bb61f8199f3e97371eff96461fbacba68Kenny Root                    // Server-side TLS Channel ID
399de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin                    NativeCrypto.SSL_enable_tls_channel_id(sslNativePointer);
400de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin                }
401de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin            }
402de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin
403f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            int sslSessionNativePointer;
404f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            try {
4055d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                sslSessionNativePointer = NativeCrypto.SSL_do_handshake(sslNativePointer,
406d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root                        socket.getFileDescriptor$(), this, getSoTimeout(), client, npnProtocols,
407d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root                        client ? null : alpnProtocols);
408f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            } catch (CertificateException e) {
40954c8a07db3c2d1670c2867ba864d351cb30fecfaBrian Carlstrom                SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage());
41054c8a07db3c2d1670c2867ba864d351cb30fecfaBrian Carlstrom                wrapper.initCause(e);
41154c8a07db3c2d1670c2867ba864d351cb30fecfaBrian Carlstrom                throw wrapper;
412bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            }
413f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            byte[] sessionId = NativeCrypto.SSL_SESSION_session_id(sslSessionNativePointer);
414b88ab0efb05475fa9d4e2a06175e95e88f507cffBrian Carlstrom            if (sessionToReuse != null && Arrays.equals(sessionToReuse.getId(), sessionId)) {
415b88ab0efb05475fa9d4e2a06175e95e88f507cffBrian Carlstrom                this.sslSession = sessionToReuse;
416f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                sslSession.lastAccessedTime = System.currentTimeMillis();
417f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                NativeCrypto.SSL_SESSION_free(sslSessionNativePointer);
418f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            } else {
419f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                if (!enableSessionCreation) {
420f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    // Should have been prevented by NativeCrypto.SSL_set_session_creation_enabled
421f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    throw new IllegalStateException("SSL Session may not be created");
422f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                }
423f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                X509Certificate[] localCertificates
424f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        = createCertChain(NativeCrypto.SSL_get_certificate(sslNativePointer));
425f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                X509Certificate[] peerCertificates
426f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        = createCertChain(NativeCrypto.SSL_get_peer_cert_chain(sslNativePointer));
427b88ab0efb05475fa9d4e2a06175e95e88f507cffBrian Carlstrom                this.sslSession = new OpenSSLSessionImpl(sslSessionNativePointer, localCertificates,
42827c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson                        peerCertificates, getPeerHostName(), getPeerPort(), sessionContext);
429f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // if not, putSession later in handshakeCompleted() callback
430f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                if (handshakeCompleted) {
431f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    sessionContext.putSession(sslSession);
432f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                }
433ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom            }
434f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom
435f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // Restore the original timeout now that the handshake is complete
436f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
437615225a35dbd838210270b282d1196deff643b51Brian Carlstrom                setSoTimeout(savedReadTimeoutMilliseconds);
438615225a35dbd838210270b282d1196deff643b51Brian Carlstrom                setSoWriteTimeout(savedWriteTimeoutMilliseconds);
4399d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor            }
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
441f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback
442f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (handshakeCompleted) {
443f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                notifyHandshakeCompletedListeners();
444f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
445ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
446f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            exception = false;
447aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        } catch (SSLProtocolException e) {
448aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom            throw new SSLHandshakeException(e);
449f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        } finally {
4508a720cceee7ce319d647738dfeda3f302879f370Brian Carlstrom            // on exceptional exit, treat the socket as closed
451f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (exception) {
4528a720cceee7ce319d647738dfeda3f302879f370Brian Carlstrom                close();
453f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
455df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom    }
456d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9aeKenny Root
457d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9aeKenny Root    private static byte[][] encodeIssuerX509Principals(X509Certificate[] certificates)
458d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9aeKenny Root            throws CertificateEncodingException {
459d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9aeKenny Root        byte[][] principalBytes = new byte[certificates.length][];
460d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9aeKenny Root        for (int i = 0; i < certificates.length; i++) {
461d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9aeKenny Root            principalBytes[i] = certificates[i].getIssuerX500Principal().getEncoded();
462d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9aeKenny Root        }
463d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9aeKenny Root        return principalBytes;
464d2cbcf1c2e2169d6454ede8ac7d1cfc73860b9aeKenny Root    }
465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
4666d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra    String getPeerHostName() {
467f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        if (wrappedHost != null) {
468f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom            return wrappedHost;
469f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        }
470f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        InetAddress inetAddress = super.getInetAddress();
471f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        if (inetAddress != null) {
472f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom            return inetAddress.getHostName();
473f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        }
474f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        return null;
47527c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson    }
47627c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson
4776d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra    int getPeerPort() {
47827c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        return wrappedHost == null ? super.getPort() : wrappedPort;
47927c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson    }
48027c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson
481df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom    /**
482df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom     * Return a possibly null array of X509Certificates given the
483df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom     * possibly null array of DER encoded bytes.
484df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom     */
485b88ab0efb05475fa9d4e2a06175e95e88f507cffBrian Carlstrom    private static X509Certificate[] createCertChain(byte[][] certificatesBytes) throws IOException {
486df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        if (certificatesBytes == null) {
487df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            return null;
488df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        }
489df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        X509Certificate[] certificates = new X509Certificate[certificatesBytes.length];
490df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        for (int i = 0; i < certificatesBytes.length; i++) {
49138375a4d0b3d34e2babbd2f6a013976c7c439696Kenny Root            certificates[i] = OpenSSLX509Certificate.fromX509Der(certificatesBytes[i]);
492df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        }
493df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        return certificates;
494bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    }
495adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
496ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom    private void setCertificate(String alias) throws CertificateEncodingException, SSLException {
4976df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        if (alias == null) {
4986df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            return;
4996df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        }
5006df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        PrivateKey privateKey = sslParameters.getKeyManager().getPrivateKey(alias);
501aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        if (privateKey == null) {
502aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom            return;
503aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        }
5046df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        X509Certificate[] certificates = sslParameters.getKeyManager().getCertificateChain(alias);
505aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        if (certificates == null) {
506aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom            return;
507aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        }
508aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom
50980546e159b0491667acbfe53ef3ea9b0962f070dBrian Carlstrom        // Note that OpenSSL says to use SSL_use_certificate before SSL_use_PrivateKey.
51080546e159b0491667acbfe53ef3ea9b0962f070dBrian Carlstrom
51180546e159b0491667acbfe53ef3ea9b0962f070dBrian Carlstrom        byte[][] certificateBytes = NativeCrypto.encodeCertificates(certificates);
51280546e159b0491667acbfe53ef3ea9b0962f070dBrian Carlstrom        NativeCrypto.SSL_use_certificate(sslNativePointer, certificateBytes);
51380546e159b0491667acbfe53ef3ea9b0962f070dBrian Carlstrom
5144f60362bb61f8199f3e97371eff96461fbacba68Kenny Root        try {
5154f60362bb61f8199f3e97371eff96461fbacba68Kenny Root            final OpenSSLKey key = OpenSSLKey.fromPrivateKey(privateKey);
5164f60362bb61f8199f3e97371eff96461fbacba68Kenny Root            NativeCrypto.SSL_use_PrivateKey(sslNativePointer, key.getPkeyContext());
5174f60362bb61f8199f3e97371eff96461fbacba68Kenny Root        } catch (InvalidKeyException e) {
5184f60362bb61f8199f3e97371eff96461fbacba68Kenny Root            throw new SSLException(e);
51941e34229c07e8d05090560ff80558fa222623769Kenny Root        }
52041e34229c07e8d05090560ff80558fa222623769Kenny Root
5216df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        // checks the last installed private key and certificate,
5226df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        // so need to do this once per loop iteration
5236df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        NativeCrypto.SSL_check_private_key(sslNativePointer);
5246df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom    }
5256df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
5260c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / client_cert_cb
527059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom    public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)
528ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            throws CertificateEncodingException, SSLException {
529059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom
530059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        String[] keyTypes = new String[keyTypeBytes.length];
531059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        for (int i = 0; i < keyTypeBytes.length; i++) {
5324ae3fd787741bfe1b808f447dcb0785250024119Brian Carlstrom            keyTypes[i] = CipherSuite.getClientKeyType(keyTypeBytes[i]);
533059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        }
534059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom
535059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        X500Principal[] issuers;
536059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        if (asn1DerEncodedPrincipals == null) {
537059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom            issuers = null;
538059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        } else {
539059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom            issuers = new X500Principal[asn1DerEncodedPrincipals.length];
540059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom            for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
541059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom                issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
542059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom            }
543059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        }
544059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        setCertificate(sslParameters.getKeyManager().chooseClientAlias(keyTypes, issuers, this));
5456df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom    }
5466df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
5470c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / info_callback
548bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public void handshakeCompleted() {
549bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        handshakeCompleted = true;
550adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
551bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // If sslSession is null, the handshake was completed during
552bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // the call to NativeCrypto.SSL_do_handshake and not during a
5530c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson        // later read operation. That means we do not need to fix up
554bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // the SSLSession and session cache or notify
555bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // HandshakeCompletedListeners, it will be done in
556bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // startHandshake.
557bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        if (sslSession == null) {
558bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            return;
559bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        }
560adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
561bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // reset session id from the native pointer and update the
562bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // appropriate cache.
563bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        sslSession.resetId();
564bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        AbstractSessionContext sessionContext =
565bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            (sslParameters.getUseClientMode())
566bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            ? sslParameters.getClientSessionContext()
567bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                : sslParameters.getServerSessionContext();
568adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sessionContext.putSession(sslSession);
569bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
570bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // let listeners know we are finally done
571bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        notifyHandshakeCompletedListeners();
572bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    }
573bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
574bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    private void notifyHandshakeCompletedListeners() {
575bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        if (listeners != null && !listeners.isEmpty()) {
576bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            // notify the listeners
577bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            HandshakeCompletedEvent event =
578bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                new HandshakeCompletedEvent(this, sslSession);
579bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            for (HandshakeCompletedListener listener : listeners) {
580bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                try {
581bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                    listener.handshakeCompleted(event);
582bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                } catch (RuntimeException e) {
583e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    // The RI runs the handlers in a separate thread,
584e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    // which we do not. But we try to preserve their
585e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    // behavior of logging a problem and not killing
586e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    // the handshaking thread just because a listener
587e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    // has a problem.
588e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    Thread thread = Thread.currentThread();
589e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    thread.getUncaughtExceptionHandler().uncaughtException(thread, e);
590bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                }
591bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            }
592bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        }
593adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
594adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
5950c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks
5960c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void verifyCertificateChain(byte[][] bytes, String authMethod)
5976df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            throws CertificateException {
598adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
599e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            if (bytes == null || bytes.length == 0) {
600e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                throw new SSLException("Peer sent no certificate");
601e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            }
602bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            X509Certificate[] peerCertificateChain = new X509Certificate[bytes.length];
603bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            for (int i = 0; i < bytes.length; i++) {
60438375a4d0b3d34e2babbd2f6a013976c7c439696Kenny Root                peerCertificateChain[i] = OpenSSLX509Certificate.fromX509Der(bytes[i]);
605adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
606bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            boolean client = sslParameters.getUseClientMode();
607bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            if (client) {
6086d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                X509TrustManager x509tm = sslParameters.getTrustManager();
6096d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                if (x509tm instanceof TrustManagerImpl) {
6106d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                    TrustManagerImpl tm = (TrustManagerImpl) x509tm;
6116d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                    tm.checkServerTrusted(peerCertificateChain, authMethod, wrappedHost);
6126d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                } else {
6136d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                    x509tm.checkServerTrusted(peerCertificateChain, authMethod);
6146d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                }
615bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            } else {
6164ae3fd787741bfe1b808f447dcb0785250024119Brian Carlstrom                String authType = peerCertificateChain[0].getPublicKey().getAlgorithm();
6176df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom                sslParameters.getTrustManager().checkClientTrusted(peerCertificateChain,
6184ae3fd787741bfe1b808f447dcb0785250024119Brian Carlstrom                                                                   authType);
619adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
620bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
621bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        } catch (CertificateException e) {
622bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            throw e;
623bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        } catch (Exception e) {
6248c4a407e34de1b348316a9175bd1c0577c887181Brian Carlstrom            throw new CertificateException(e);
625adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
626adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
627adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
6280c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public InputStream getInputStream() throws IOException {
6295f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom        checkOpen();
630ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom        synchronized (this) {
631adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (is == null) {
632adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                is = new SSLInputStream();
633adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
634adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
635adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return is;
636adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
637adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
638adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
6390c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public OutputStream getOutputStream() throws IOException {
6405f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom        checkOpen();
641ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom        synchronized (this) {
642adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (os == null) {
643adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                os = new SSLOutputStream();
644adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
645adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
646adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return os;
647adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
648adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
649adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
650bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    /**
651adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This inner class provides input data stream functionality
652adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * for the OpenSSL native implementation. It is used to
653adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * read data received via SSL protocol.
654adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
655adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private class SSLInputStream extends InputStream {
656adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        SSLInputStream() throws IOException {
657679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson            /*
658679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson             * Note: When startHandshake() throws an exception, no
659adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * SSLInputStream object will be created.
660adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             */
661679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson            OpenSSLSocketImpl.this.startHandshake();
662adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
663adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
664adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
665adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Reads one byte. If there is no data in the underlying buffer,
666adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * this operation can block until the data will be
667adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * available.
668adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @return read value.
669adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @throws <code>IOException</code>
670adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
6714559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        @Override
672adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int read() throws IOException {
673638000042da777f6d628d88dadde957c52597710Brian Carlstrom            return Streams.readSingleByte(this);
674adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
675adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
676adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
677adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Method acts as described in spec for superclass.
678adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @see java.io.InputStream#read(byte[],int,int)
679adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
6804559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        @Override
681a1603838fe9e865575c87982e32c6343740e464cElliott Hughes        public int read(byte[] buf, int offset, int byteCount) throws IOException {
6825900e5546059f05d5e58e5732e4d08d83b8b7574Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
683ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            synchronized (readLock) {
68412e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                checkOpen();
685a1603838fe9e865575c87982e32c6343740e464cElliott Hughes                Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
686a1603838fe9e865575c87982e32c6343740e464cElliott Hughes                if (byteCount == 0) {
68712e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                    return 0;
68812e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                }
6895d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                return NativeCrypto.SSL_read(sslNativePointer, socket.getFileDescriptor$(),
6905d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                        OpenSSLSocketImpl.this, buf, offset, byteCount, getSoTimeout());
691adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
692adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
693adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
694adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
695adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
696adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This inner class provides output data stream functionality
697adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * for the OpenSSL native implementation. It is used to
698adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * write data according to the encryption parameters given in SSL context.
699adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
700adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private class SSLOutputStream extends OutputStream {
701adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        SSLOutputStream() throws IOException {
702679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson            /*
703679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson             * Note: When startHandshake() throws an exception, no
704ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom             * SSLOutputStream object will be created.
705adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             */
706679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson            OpenSSLSocketImpl.this.startHandshake();
707adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
708adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
709adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
710adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Method acts as described in spec for superclass.
711adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @see java.io.OutputStream#write(int)
712adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
7134559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        @Override
714638000042da777f6d628d88dadde957c52597710Brian Carlstrom        public void write(int oneByte) throws IOException {
715638000042da777f6d628d88dadde957c52597710Brian Carlstrom            Streams.writeSingleByte(this, oneByte);
716adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
717adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
718adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
719adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Method acts as described in spec for superclass.
720adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @see java.io.OutputStream#write(byte[],int,int)
721adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
7224559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        @Override
723a1603838fe9e865575c87982e32c6343740e464cElliott Hughes        public void write(byte[] buf, int offset, int byteCount) throws IOException {
7245900e5546059f05d5e58e5732e4d08d83b8b7574Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
725ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            synchronized (writeLock) {
72612e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                checkOpen();
727a1603838fe9e865575c87982e32c6343740e464cElliott Hughes                Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
728a1603838fe9e865575c87982e32c6343740e464cElliott Hughes                if (byteCount == 0) {
72912e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                    return;
73012e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                }
7315d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                NativeCrypto.SSL_write(sslNativePointer, socket.getFileDescriptor$(),
732615225a35dbd838210270b282d1196deff643b51Brian Carlstrom                        OpenSSLSocketImpl.this, buf, offset, byteCount, writeTimeoutMilliseconds);
733adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
734adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
735adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
736adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
737adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7380c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public SSLSession getSession() {
739df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        if (sslSession == null) {
740df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            try {
741679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson                startHandshake();
742df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            } catch (IOException e) {
743df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom                // return an invalid session with
744df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom                // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
745da5b7116b58795b169961cbd63c2b21bac741d9aKenny Root                return SSLSessionImpl.getNullSession();
746df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            }
747adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
748adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sslSession;
749adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
750adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7510c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void addHandshakeCompletedListener(
752adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            HandshakeCompletedListener listener) {
753adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (listener == null) {
754adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
755adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
756adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (listeners == null) {
7570c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson            listeners = new ArrayList<HandshakeCompletedListener>();
758adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
759adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        listeners.add(listener);
760adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
761adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7620c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void removeHandshakeCompletedListener(
763adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            HandshakeCompletedListener listener) {
764adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (listener == null) {
765adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
766adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
767adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (listeners == null) {
768adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException(
769adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    "Provided listener is not registered");
770adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
771adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!listeners.remove(listener)) {
772adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException(
773adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    "Provided listener is not registered");
774adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
775adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
776adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7770c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public boolean getEnableSessionCreation() {
778adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sslParameters.getEnableSessionCreation();
779adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
780adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7810c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setEnableSessionCreation(boolean flag) {
782adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sslParameters.setEnableSessionCreation(flag);
783adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
784adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7850c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public String[] getSupportedCipherSuites() {
786ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        return NativeCrypto.getSupportedCipherSuites();
787adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
788adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7890c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public String[] getEnabledCipherSuites() {
790bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        return enabledCipherSuites.clone();
791adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
792adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7930c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setEnabledCipherSuites(String[] suites) {
794bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(suites);
795adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
796adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7970c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public String[] getSupportedProtocols() {
798ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        return NativeCrypto.getSupportedProtocols();
799adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
800adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8010c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public String[] getEnabledProtocols() {
802bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        return enabledProtocols.clone();
803adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
804adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8050c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setEnabledProtocols(String[] protocols) {
806bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        enabledProtocols = NativeCrypto.checkEnabledProtocols(protocols);
807adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
808adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
809adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
8104559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * This method enables session ticket support.
8114559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     *
8124559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * @param useSessionTickets True to enable session tickets
8134559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     */
8144559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    public void setUseSessionTickets(boolean useSessionTickets) {
8154559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        this.useSessionTickets = useSessionTickets;
8164559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    }
8174559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom
8184559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    /**
8194559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * This method enables Server Name Indication
8204559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     *
8214559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * @param hostname the desired SNI hostname, or null to disable
8224559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     */
8234559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    public void setHostname(String hostname) {
8244559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        this.hostname = hostname;
8254559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    }
8264559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom
827de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    /**
828de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * Enables/disables TLS Channel ID for this server socket.
829de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *
830de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * <p>This method needs to be invoked before the handshake starts.
831de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *
832de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * @throws IllegalStateException if this is a client socket or if the handshake has already
833de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *         started.
834de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin
835de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     */
836de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    public void setChannelIdEnabled(boolean enabled) {
837de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        if (getUseClientMode()) {
838de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin            throw new IllegalStateException("Client mode");
839de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        }
840de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        if (handshakeStarted) {
841de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin            throw new IllegalStateException(
842de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin                    "Could not enable/disable Channel ID after the initial handshake has"
843de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin                    + " begun.");
844de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        }
845de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        this.channelIdEnabled = enabled;
846de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    }
847de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin
848de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    /**
849de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * Gets the TLS Channel ID for this server socket. Channel ID is only available once the
850de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * handshake completes.
851de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *
852de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * @return channel ID or {@code null} if not available.
853de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *
854de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * @throws IllegalStateException if this is a client socket or if the handshake has not yet
855de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *         completed.
856de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * @throws SSLException if channel ID is available but could not be obtained.
857de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     */
858de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    public byte[] getChannelId() throws SSLException {
859de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        if (getUseClientMode()) {
860de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin            throw new IllegalStateException("Client mode");
861de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        }
862de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        if (!handshakeCompleted) {
863de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin            throw new IllegalStateException(
864de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin                    "Channel ID is only available after handshake completes");
865de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        }
866de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        return NativeCrypto.SSL_get_tls_channel_id(sslNativePointer);
867de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    }
868de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin
869de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    /**
870de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * Sets the {@link PrivateKey} to be used for TLS Channel ID by this client socket.
871de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *
872de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * <p>This method needs to be invoked before the handshake starts.
873de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *
874de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key (disables
875c17bdfa469de6c48f16e454611caae3aaa82cc9dAlex Klyubin     *        TLS Channel ID). The private key must be an Elliptic Curve (EC) key based on the NIST
876de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *        P-256 curve (aka SECG secp256r1 or ANSI X9.62 prime256v1).
877de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *
878de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     * @throws IllegalStateException if this is a server socket or if the handshake has already
879de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     *         started.
880de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin     */
881c17bdfa469de6c48f16e454611caae3aaa82cc9dAlex Klyubin    public void setChannelIdPrivateKey(PrivateKey privateKey) {
882de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        if (!getUseClientMode()) {
883de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin            throw new IllegalStateException("Server mode");
884de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        }
885de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        if (handshakeStarted) {
886de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin            throw new IllegalStateException(
887de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin                    "Could not change Channel ID private key after the initial handshake has"
888de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin                    + " begun.");
889de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin        }
8904f60362bb61f8199f3e97371eff96461fbacba68Kenny Root        if (privateKey == null) {
8914f60362bb61f8199f3e97371eff96461fbacba68Kenny Root            this.channelIdEnabled = false;
8924f60362bb61f8199f3e97371eff96461fbacba68Kenny Root            this.channelIdPrivateKey = null;
8934f60362bb61f8199f3e97371eff96461fbacba68Kenny Root        } else {
8944f60362bb61f8199f3e97371eff96461fbacba68Kenny Root            this.channelIdEnabled = true;
8954f60362bb61f8199f3e97371eff96461fbacba68Kenny Root            try {
8964f60362bb61f8199f3e97371eff96461fbacba68Kenny Root                this.channelIdPrivateKey = OpenSSLKey.fromPrivateKey(privateKey);
8974f60362bb61f8199f3e97371eff96461fbacba68Kenny Root            } catch (InvalidKeyException e) {
8984f60362bb61f8199f3e97371eff96461fbacba68Kenny Root                // Will have error in startHandshake
8994f60362bb61f8199f3e97371eff96461fbacba68Kenny Root            }
9004f60362bb61f8199f3e97371eff96461fbacba68Kenny Root        }
901de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin    }
902de30700ecd96af43e2f3ee2e03f398896f5bb1e9Alex Klyubin
9030c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public boolean getUseClientMode() {
904adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sslParameters.getUseClientMode();
905adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
906adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
9070c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setUseClientMode(boolean mode) {
908adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (handshakeStarted) {
909adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException(
9100c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson                    "Could not change the mode after the initial handshake has begun.");
911adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
912adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sslParameters.setUseClientMode(mode);
913adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
914adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
9150c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public boolean getWantClientAuth() {
916adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sslParameters.getWantClientAuth();
917adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
918adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
9190c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public boolean getNeedClientAuth() {
920adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sslParameters.getNeedClientAuth();
921adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
922adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
9230c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setNeedClientAuth(boolean need) {
924adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sslParameters.setNeedClientAuth(need);
925adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
926adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
9270c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setWantClientAuth(boolean want) {
928adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sslParameters.setWantClientAuth(want);
929adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
930adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
9310c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void sendUrgentData(int data) throws IOException {
9320c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson        throw new SocketException("Method sendUrgentData() is not supported.");
933adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
934adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
9350c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setOOBInline(boolean on) throws SocketException {
9360c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson        throw new SocketException("Methods sendUrgentData, setOOBInline are not supported.");
937adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
938adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
939615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    @Override public void setSoTimeout(int readTimeoutMilliseconds) throws SocketException {
940615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        super.setSoTimeout(readTimeoutMilliseconds);
941615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        this.readTimeoutMilliseconds = readTimeoutMilliseconds;
942a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom    }
943a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom
9440c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public int getSoTimeout() throws SocketException {
945615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        return readTimeoutMilliseconds;
946615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    }
947615225a35dbd838210270b282d1196deff643b51Brian Carlstrom
948615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    /**
949615225a35dbd838210270b282d1196deff643b51Brian Carlstrom     * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
950615225a35dbd838210270b282d1196deff643b51Brian Carlstrom     */
951615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    public void setSoWriteTimeout(int writeTimeoutMilliseconds) throws SocketException {
952615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        this.writeTimeoutMilliseconds = writeTimeoutMilliseconds;
953615225a35dbd838210270b282d1196deff643b51Brian Carlstrom
954615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        StructTimeval tv = StructTimeval.fromMillis(writeTimeoutMilliseconds);
955615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        try {
956615225a35dbd838210270b282d1196deff643b51Brian Carlstrom            Libcore.os.setsockoptTimeval(getFileDescriptor$(), SOL_SOCKET, SO_SNDTIMEO, tv);
957615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        } catch (ErrnoException errnoException) {
958615225a35dbd838210270b282d1196deff643b51Brian Carlstrom            throw errnoException.rethrowAsSocketException();
959615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        }
960615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    }
961615225a35dbd838210270b282d1196deff643b51Brian Carlstrom
962615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    /**
963615225a35dbd838210270b282d1196deff643b51Brian Carlstrom     * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
964615225a35dbd838210270b282d1196deff643b51Brian Carlstrom     */
965615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    public int getSoWriteTimeout() throws SocketException {
966615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        return writeTimeoutMilliseconds;
967adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
968adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
9699d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor    /**
9709d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor     * Set the handshake timeout on this socket.  This timeout is specified in
9719d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor     * milliseconds and will be used only during the handshake process.
9729d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor     */
973615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    public void setHandshakeTimeout(int handshakeTimeoutMilliseconds) throws SocketException {
974615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        this.handshakeTimeoutMilliseconds = handshakeTimeoutMilliseconds;
9759d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor    }
9769d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor
9770c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void close() throws IOException {
9780c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson        // TODO: Close SSL sockets using a background thread so they close gracefully.
979adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
980adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (handshakeLock) {
981adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!handshakeStarted) {
9820c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson                // prevent further attempts to start handshake
983adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                handshakeStarted = true;
984ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
985adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                synchronized (this) {
986ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom                    free();
987adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
988df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom                    if (socket != this) {
989adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (autoClose && !socket.isClosed()) socket.close();
990adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    } else {
991adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (!super.isClosed()) super.close();
992adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
993adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
994ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
995adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return;
996adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
997adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
998adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
999adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (this) {
1000adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1001783004cceef470884b3ee6946cbbfc4af0f28ae7Brian Carlstrom            // Interrupt any outstanding reads or writes before taking the writeLock and readLock
1002783004cceef470884b3ee6946cbbfc4af0f28ae7Brian Carlstrom            NativeCrypto.SSL_interrupt(sslNativePointer);
1003df9f5967a3b8dc2f61183d155791393b67980511Brian Carlstrom
1004783004cceef470884b3ee6946cbbfc4af0f28ae7Brian Carlstrom            synchronized (writeLock) {
1005783004cceef470884b3ee6946cbbfc4af0f28ae7Brian Carlstrom                synchronized (readLock) {
1006adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // Shut down the SSL connection, per se.
1007adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    try {
1008adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (handshakeStarted) {
10095900e5546059f05d5e58e5732e4d08d83b8b7574Brad Fitzpatrick                            BlockGuard.getThreadPolicy().onNetwork();
10105d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                            NativeCrypto.SSL_shutdown(sslNativePointer, socket.getFileDescriptor$(),
10115d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                                    this);
1012adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
10131c64b3adb85345659ac60ad82216268acba18764Brian Carlstrom                    } catch (IOException ignored) {
1014adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        /*
10151c64b3adb85345659ac60ad82216268acba18764Brian Carlstrom                         * Note that although close() can throw
10161c64b3adb85345659ac60ad82216268acba18764Brian Carlstrom                         * IOException, the RI does not throw if there
10171c64b3adb85345659ac60ad82216268acba18764Brian Carlstrom                         * is problem sending a "close notify" which
10181c64b3adb85345659ac60ad82216268acba18764Brian Carlstrom                         * can happen if the underlying socket is closed.
1019adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                         */
1020d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                    } finally {
1021d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                        /*
1022d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                         * Even if the above call failed, it is still safe to free
1023d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                         * the native structs, and we need to do so lest we leak
1024d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                         * memory.
1025d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                         */
1026d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                        free();
1027d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom
1028d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                        if (socket != this) {
1029d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                            if (autoClose && !socket.isClosed()) {
1030d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                                socket.close();
1031d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                            }
1032d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                        } else {
1033d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                            if (!super.isClosed()) {
1034d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                                super.close();
1035d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                            }
1036d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                        }
1037adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
1038adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
1039adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
1040adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1041adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
1042adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1043ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    private void free() {
1044ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        if (sslNativePointer == 0) {
1045ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom            return;
1046ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        }
1047ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        NativeCrypto.SSL_free(sslNativePointer);
1048ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        sslNativePointer = 0;
1049f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        guard.close();
1050ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    }
1051adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1052e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom    @Override protected void finalize() throws Throwable {
1053e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        try {
1054e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            /*
1055e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * Just worry about our own state. Notably we do not try and
1056e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * close anything. The SocketImpl, either our own
1057e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * PlainSocketImpl, or the Socket we are wrapping, will do
1058e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * that. This might mean we do not properly SSL_shutdown, but
1059e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * if you want to do that, properly close the socket yourself.
1060e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             *
1061e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * The reason why we don't try to SSL_shutdown, is that there
1062e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * can be a race between finalizers where the PlainSocketImpl
1063e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * finalizer runs first and closes the socket. However, in the
1064e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * meanwhile, the underlying file descriptor could be reused
1065e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * for another purpose. If we call SSL_shutdown, the
1066e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * underlying socket BIOs still have the old file descriptor
1067e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * and will write the close notify to some unsuspecting
1068e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * reader.
1069e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             */
107012f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom            if (guard != null) {
107112f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom                guard.warnIfOpen();
107212f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom            }
1073e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            free();
1074e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        } finally {
1075e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            super.finalize();
1076e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        }
1077adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
10783267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey
10793267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey    @Override
10803267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey    public FileDescriptor getFileDescriptor$() {
10813267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey        if (socket == this) {
10823267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey            return super.getFileDescriptor$();
10833267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey        } else {
10843267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey            return socket.getFileDescriptor$();
10853267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey        }
10863267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey    }
108725977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson
108825977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    /**
108925977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     * Returns the protocol agreed upon by client and server, or null if no
109025977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     * protocol was agreed upon.
109125977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     */
109225977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    public byte[] getNpnSelectedProtocol() {
1093600dc4949de6bf5608e5f5a5214cde59299b683aJesse Wilson        return NativeCrypto.SSL_get_npn_negotiated_protocol(sslNativePointer);
109425977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    }
109525977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson
109625977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    /**
1097d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root     * Returns the protocol agreed upon by client and server, or {@code null} if
1098d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root     * no protocol was agreed upon.
1099d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root     */
1100d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root    public byte[] getAlpnSelectedProtocol() {
1101d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root        return NativeCrypto.SSL_get0_alpn_selected(sslNativePointer);
1102d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root    }
1103d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root
1104d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root    /**
110525977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     * Sets the list of protocols this peer is interested in. If null no
110625977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     * protocols will be used.
110725977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     *
11081982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson     * @param npnProtocols a non-empty array of protocol names. From
11091982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson     *     SSL_select_next_proto, "vector of 8-bit, length prefixed byte
11101982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson     *     strings. The length byte itself is not included in the length. A byte
11111982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson     *     string of length 0 is invalid. No byte string may be truncated.".
111225977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     */
111325977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    public void setNpnProtocols(byte[] npnProtocols) {
11141982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson        if (npnProtocols != null && npnProtocols.length == 0) {
11151982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson            throw new IllegalArgumentException("npnProtocols.length == 0");
11161982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson        }
111725977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson        this.npnProtocols = npnProtocols;
111825977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    }
1119d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root
1120d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root    /**
1121d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root     * Sets the list of protocols this peer is interested in. If the list is
1122d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root     * {@code null}, no protocols will be used.
1123d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root     *
1124d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root     * @param alpnProtocols a non-empty array of protocol names. From
1125d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root     *            SSL_select_next_proto, "vector of 8-bit, length prefixed byte
1126d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root     *            strings. The length byte itself is not included in the length.
1127d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root     *            A byte string of length 0 is invalid. No byte string may be
1128d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root     *            truncated.".
1129d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root     */
1130d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root    public void setAlpnProtocols(byte[] alpnProtocols) {
1131d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root        if (alpnProtocols != null && alpnProtocols.length == 0) {
1132d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root            throw new IllegalArgumentException("alpnProtocols.length == 0");
1133d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root        }
1134d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root        this.alpnProtocols = alpnProtocols;
1135d10b61eeabd2bace2deac2d2352c0de29c3c6bf6Kenny Root    }
1136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
1137