OpenSSLSocketImpl.java revision f52b35a5bc22f53b663ea22954135b69f8636bf4
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
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage org.apache.harmony.xnet.provider.jsse;
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
195900e5546059f05d5e58e5732e4d08d83b8b7574Brad Fitzpatrickimport dalvik.system.BlockGuard;
20f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstromimport dalvik.system.CloseGuard;
213267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkeyimport java.io.FileDescriptor;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.OutputStream;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.InetAddress;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.Socket;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.SocketException;
286df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstromimport java.security.PrivateKey;
296df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstromimport java.security.SecureRandom;
3012cd1f00c2fa1a7f37bf644cecdf7588bdc0b0a9Brian Carlstromimport java.security.cert.CertificateEncodingException;
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.cert.CertificateException;
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.cert.X509Certificate;
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.ArrayList;
34a1603838fe9e865575c87982e32c6343740e464cElliott Hughesimport java.util.Arrays;
356c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstromimport java.util.HashSet;
366c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstromimport java.util.Set;
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport javax.net.ssl.HandshakeCompletedEvent;
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport javax.net.ssl.HandshakeCompletedListener;
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport javax.net.ssl.SSLException;
402915378e253f08e47fe5a9bfd026cd1ca7c6c351Brian Carlstromimport javax.net.ssl.SSLHandshakeException;
41aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstromimport javax.net.ssl.SSLProtocolException;
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport javax.net.ssl.SSLSession;
43f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstromimport javax.net.ssl.X509TrustManager;
44059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstromimport javax.security.auth.x500.X500Principal;
45638000042da777f6d628d88dadde957c52597710Brian Carlstromimport libcore.io.Streams;
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.apache.harmony.security.provider.cert.X509CertImpl;
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
494559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * Implementation of the class OpenSSLSocketImpl based on OpenSSL.
504559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <p>
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * This class only supports SSLv3 and TLSv1. This should be documented elsewhere
52ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom * later, for example in the package.html or a separate reference document.
534559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <p>
544559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * Extensions to SSLSocket include:
554559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <ul>
564559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <li>handshake timeout
574559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <li>compression methods
584559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <li>session tickets
594559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <li>Server Name Indication
604559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * </ul>
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
62ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrompublic class OpenSSLSocketImpl
63ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        extends javax.net.ssl.SSLSocket
646df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        implements NativeCrypto.SSLHandshakeCallbacks {
65df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom
66ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    private int sslNativePointer;
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private InputStream is;
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private OutputStream os;
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final Object handshakeLock = new Object();
70ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    private final Object readLock = new Object();
71ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    private final Object writeLock = new Object();
726812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    private SSLParametersImpl sslParameters;
73bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    private String[] enabledProtocols;
74bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    private String[] enabledCipherSuites;
754559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    private String[] enabledCompressionMethods;
764559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    private boolean useSessionTickets;
774559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    private String hostname;
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private OpenSSLSessionImpl sslSession;
79df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom    private final Socket socket;
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private boolean autoClose;
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private boolean handshakeStarted = false;
8212f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom    private final CloseGuard guard = CloseGuard.get();
83bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
84bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    /**
85bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * Not set to true until the update from native that tells us the
86bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * full handshake is complete, since SSL_do_handshake can return
87bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * before the handshake is completely done due to
88bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * handshake_cutthrough support.
89bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     */
90bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    private boolean handshakeCompleted = false;
91bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private ArrayList<HandshakeCompletedListener> listeners;
93a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom
94a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom    /**
95a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom     * Local cache of timeout to avoid getsockopt on every read and
96a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom     * write for non-wrapped sockets. Note that
97a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom     * OpenSSLSocketImplWrapper overrides setSoTimeout and
98a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom     * getSoTimeout to delegate to the wrapped socket.
99a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom     */
100a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom    private int timeoutMilliseconds = 0;
101a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom
102a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom    private int handshakeTimeoutMilliseconds = -1;  // -1 = same as timeout; 0 = infinite
103a653cca054f36de92bbef8498be3f0f01d9d6119Brian Carlstrom    private String wrappedHost;
104a653cca054f36de92bbef8498be3f0f01d9d6119Brian Carlstrom    private int wrappedPort;
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1066812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    protected OpenSSLSocketImpl(SSLParametersImpl sslParameters) throws IOException {
107df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom        this.socket = this;
108ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        init(sslParameters);
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1116812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    protected OpenSSLSocketImpl(SSLParametersImpl sslParameters,
112bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                                String[] enabledProtocols,
1134559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom                                String[] enabledCipherSuites,
1144559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom                                String[] enabledCompressionMethods) throws IOException {
115df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom        this.socket = this;
1164559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        init(sslParameters, enabledProtocols, enabledCipherSuites, enabledCompressionMethods);
117bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    }
118bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
1196812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    protected OpenSSLSocketImpl(String host, int port, SSLParametersImpl sslParameters)
120df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom            throws IOException {
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(host, port);
122df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom        this.socket = this;
123ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        init(sslParameters);
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1266812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    protected OpenSSLSocketImpl(InetAddress address, int port, SSLParametersImpl sslParameters)
127df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom            throws IOException {
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(address, port);
129df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom        this.socket = this;
130ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        init(sslParameters);
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1340c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom    protected OpenSSLSocketImpl(String host, int port,
1350c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                                InetAddress clientAddress, int clientPort,
1360c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson                                SSLParametersImpl sslParameters) throws IOException {
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(host, port, clientAddress, clientPort);
138df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom        this.socket = this;
139ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        init(sslParameters);
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected OpenSSLSocketImpl(InetAddress address, int port,
1430c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                                InetAddress clientAddress, int clientPort,
1440c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson                                SSLParametersImpl sslParameters) throws IOException {
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(address, port, clientAddress, clientPort);
146df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom        this.socket = this;
147ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        init(sslParameters);
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1510c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson     * Create an SSL socket that wraps another socket. Invoked by
1520c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson     * OpenSSLSocketImplWrapper constructor.
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected OpenSSLSocketImpl(Socket socket, String host, int port,
1556812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom            boolean autoClose, SSLParametersImpl sslParameters) throws IOException {
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.socket = socket;
157a653cca054f36de92bbef8498be3f0f01d9d6119Brian Carlstrom        this.wrappedHost = host;
158a653cca054f36de92bbef8498be3f0f01d9d6119Brian Carlstrom        this.wrappedPort = port;
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.autoClose = autoClose;
160ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        init(sslParameters);
161a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom
162a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom        // this.timeout is not set intentionally.
163a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom        // OpenSSLSocketImplWrapper.getSoTimeout will delegate timeout
164a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom        // to wrapped socket
165ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    }
166ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
167ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    /**
168ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom     * Initialize the SSL socket and set the certificates for the
169ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom     * future handshaking.
170ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom     */
1716812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    private void init(SSLParametersImpl sslParameters) throws IOException {
172bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        init(sslParameters,
173bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom             NativeCrypto.getSupportedProtocols(),
1744559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom             NativeCrypto.getDefaultCipherSuites(),
1754559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom             NativeCrypto.getDefaultCompressionMethods());
176ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    }
177ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
178ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    /**
179bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * Initialize the SSL socket and set the certificates for the
180bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * future handshaking.
181ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom     */
1826812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    private void init(SSLParametersImpl sslParameters,
183bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                      String[] enabledProtocols,
1844559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom                      String[] enabledCipherSuites,
1854559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom                      String[] enabledCompressionMethods) throws IOException {
186bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        this.sslParameters = sslParameters;
187bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        this.enabledProtocols = enabledProtocols;
188bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        this.enabledCipherSuites = enabledCipherSuites;
1894559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        this.enabledCompressionMethods = enabledCompressionMethods;
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the suitable session reference from the session cache container.
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
195bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    private OpenSSLSessionImpl getCachedClientSession(ClientSessionContext sessionContext) {
19627c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        String hostName = getPeerHostName();
19727c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        int port = getPeerPort();
19827c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        if (hostName == null) {
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
20127c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        OpenSSLSessionImpl session = (OpenSSLSessionImpl) sessionContext.getSession(hostName, port);
2029acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        if (session == null) {
2039acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            return null;
2049acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2059acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom
2069acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        String protocol = session.getProtocol();
2079acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        boolean protocolFound = false;
2089acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        for (String enabledProtocol : enabledProtocols) {
2099acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            if (protocol.equals(enabledProtocol)) {
2109acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                protocolFound = true;
2119acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                break;
2129acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            }
2139acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2149acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        if (!protocolFound) {
2159acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            return null;
2169acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2179acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom
2189acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        String cipherSuite = session.getCipherSuite();
2199acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        boolean cipherSuiteFound = false;
2209acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        for (String enabledCipherSuite : enabledCipherSuites) {
2219acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            if (cipherSuite.equals(enabledCipherSuite)) {
2229acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                cipherSuiteFound = true;
2239acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                break;
2249acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            }
2259acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2269acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        if (!cipherSuiteFound) {
2279acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            return null;
2289acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2296df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
2304559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        String compressionMethod = session.getCompressionMethod();
23127c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        if (!compressionMethod.equals(NativeCrypto.SUPPORTED_COMPRESSION_METHOD_NULL)) {
23227c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson            boolean compressionMethodFound = false;
23327c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson            for (String enabledCompressionMethod : enabledCompressionMethods) {
23427c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson                if (compressionMethod.equals(enabledCompressionMethod)) {
23527c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson                    compressionMethodFound = true;
23627c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson                    break;
23727c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson                }
23827c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson            }
23927c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson            if (!compressionMethodFound) {
24027c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson                return null;
2414559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom            }
2424559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        }
2434559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom
2449acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        return session;
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Starts a TLS/SSL handshake on this connection using some native methods
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * from the OpenSSL library. It can negotiate new encryption keys, change
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * cipher suites, or initiate a new session. The certificate chain is
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * verified if the correspondent property in java.Security is set. All
252ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom     * listeners are notified at the end of the TLS/SSL handshake.
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
2544559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    @Override
255bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public void startHandshake() throws IOException {
256bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        startHandshake(true);
257bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    }
258bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
2595f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom    private void checkOpen() throws SocketException {
2605f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom        if (isClosed()) {
2615f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom            throw new SocketException("Socket is closed");
2625f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom        }
2635f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom    }
2645f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom
2655f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom    /**
266bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * Perform the handshake
2670c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson     *
268bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * @param full If true, disable handshake cutthrough for a fully synchronous handshake
269bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     */
270bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public synchronized void startHandshake(boolean full) throws IOException {
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (handshakeLock) {
27212e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom            checkOpen();
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!handshakeStarted) {
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                handshakeStarted = true;
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return;
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2806df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        // note that this modifies the global seed, not something specific to the connection
2816df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        final int seedLengthInBytes = NativeCrypto.RAND_SEED_LENGTH_IN_BYTES;
2826df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        final SecureRandom secureRandom = sslParameters.getSecureRandomMember();
2836df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        if (secureRandom == null) {
2846df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            NativeCrypto.RAND_load_file("/dev/urandom", seedLengthInBytes);
2856df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        } else {
2866df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            NativeCrypto.RAND_seed(secureRandom.generateSeed(seedLengthInBytes));
2876df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        }
2886df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
2896df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        final boolean client = sslParameters.getUseClientMode();
2906df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
2916df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        final int sslCtxNativePointer = (client) ?
2926df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            sslParameters.getClientSessionContext().sslCtxNativePointer :
2936df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            sslParameters.getServerSessionContext().sslCtxNativePointer;
2946df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
295f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        this.sslNativePointer = 0;
296f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        boolean exception = true;
297f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        try {
298f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer);
299f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            guard.open("close");
3006df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
301f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // setup server certificates and private keys.
302f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // clients will receive a call back to request certificates.
303f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (!client) {
3046c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                Set<String> keyTypes = new HashSet<String>();
3056c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                for (String enabledCipherSuite : enabledCipherSuites) {
306ffeba5dd766602f6e2be9caa9081744348a53c04Brian Carlstrom                    if (enabledCipherSuite.equals(NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {
307ffeba5dd766602f6e2be9caa9081744348a53c04Brian Carlstrom                        continue;
308ffeba5dd766602f6e2be9caa9081744348a53c04Brian Carlstrom                    }
3094ae3fd787741bfe1b808f447dcb0785250024119Brian Carlstrom                    String keyType = CipherSuite.getByName(enabledCipherSuite).getServerKeyType();
3106c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                    if (keyType != null) {
3116c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                        keyTypes.add(keyType);
3126c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                    }
3136c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                }
3146c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                for (String keyType : keyTypes) {
315f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    try {
316f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        setCertificate(sslParameters.getKeyManager().chooseServerAlias(keyType,
317f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                                                       null,
318f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                                                       this));
319f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    } catch (CertificateEncodingException e) {
320f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        throw new IOException(e);
321f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    }
322ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom                }
3236df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            }
3246df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
325f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            NativeCrypto.setEnabledProtocols(sslNativePointer, enabledProtocols);
326f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            NativeCrypto.setEnabledCipherSuites(sslNativePointer, enabledCipherSuites);
327f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (enabledCompressionMethods.length != 0) {
328f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                NativeCrypto.setEnabledCompressionMethods(sslNativePointer,
329f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                          enabledCompressionMethods);
330f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
331f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (useSessionTickets) {
332f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                NativeCrypto.SSL_clear_options(sslNativePointer, NativeCrypto.SSL_OP_NO_TICKET);
333f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
334f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (hostname != null) {
335f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                NativeCrypto.SSL_set_tlsext_host_name(sslNativePointer, hostname);
336f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
337bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
338f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            boolean enableSessionCreation = sslParameters.getEnableSessionCreation();
339f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (!enableSessionCreation) {
340f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer,
341f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                              enableSessionCreation);
342bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            }
343bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
344f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            AbstractSessionContext sessionContext;
345f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (client) {
346f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // look for client session to reuse
347f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                ClientSessionContext clientSessionContext = sslParameters.getClientSessionContext();
348f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                sessionContext = clientSessionContext;
3490c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson                OpenSSLSessionImpl session = getCachedClientSession(clientSessionContext);
350f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                if (session != null) {
351f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    NativeCrypto.SSL_set_session(sslNativePointer,
352f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                 session.sslSessionNativePointer);
353f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                }
354ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            } else {
355f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                sessionContext = sslParameters.getServerSessionContext();
356ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            }
357059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom
358f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // setup peer certificate verification
359f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (client) {
360f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // TODO support for anonymous cipher would require us to
361f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // conditionally use SSL_VERIFY_NONE
362f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            } else {
363f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // needing client auth takes priority...
3640c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson                boolean certRequested;
365f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                if (sslParameters.getNeedClientAuth()) {
366f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    NativeCrypto.SSL_set_verify(sslNativePointer,
367f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                NativeCrypto.SSL_VERIFY_PEER
368f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
369f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    certRequested = true;
370f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // ... over just wanting it...
371f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                } else if (sslParameters.getWantClientAuth()) {
372f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    NativeCrypto.SSL_set_verify(sslNativePointer,
373f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                NativeCrypto.SSL_VERIFY_PEER);
374f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    certRequested = true;
375f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // ... and it defaults properly so don't call SSL_set_verify in the common case.
376f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                } else {
377f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    certRequested = false;
378f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                }
379f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom
380f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                if (certRequested) {
381f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    X509TrustManager trustManager = sslParameters.getTrustManager();
382f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    X509Certificate[] issuers = trustManager.getAcceptedIssuers();
383f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    if (issuers != null && issuers.length != 0) {
384f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        byte[][] issuersBytes;
385f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        try {
386f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                            issuersBytes = NativeCrypto.encodeIssuerX509Principals(issuers);
387f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        } catch (CertificateEncodingException e) {
388f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                            throw new IOException("Problem encoding principals", e);
389f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        }
390f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        NativeCrypto.SSL_set_client_CA_list(sslNativePointer, issuersBytes);
391ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom                    }
392ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom                }
393ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            }
394ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
395f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (client && full) {
396f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // we want to do a full synchronous handshake, so turn off cutthrough
397f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                NativeCrypto.SSL_clear_mode(sslNativePointer,
398f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                            NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH);
399f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
400ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
401f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // Temporarily use a different timeout for the handshake process
402f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            int savedTimeoutMilliseconds = getSoTimeout();
403f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
404f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                setSoTimeout(handshakeTimeoutMilliseconds);
405f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
406bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
407f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            int sslSessionNativePointer;
408f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            try {
4095d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                sslSessionNativePointer = NativeCrypto.SSL_do_handshake(sslNativePointer,
4105d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                        socket.getFileDescriptor$(), this, getSoTimeout(), client);
411f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            } catch (CertificateException e) {
41254c8a07db3c2d1670c2867ba864d351cb30fecfaBrian Carlstrom                SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage());
41354c8a07db3c2d1670c2867ba864d351cb30fecfaBrian Carlstrom                wrapper.initCause(e);
41454c8a07db3c2d1670c2867ba864d351cb30fecfaBrian Carlstrom                throw wrapper;
415bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            }
416f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            byte[] sessionId = NativeCrypto.SSL_SESSION_session_id(sslSessionNativePointer);
417f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            sslSession = (OpenSSLSessionImpl) sessionContext.getSession(sessionId);
418f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (sslSession != null) {
419f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                sslSession.lastAccessedTime = System.currentTimeMillis();
420f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                NativeCrypto.SSL_SESSION_free(sslSessionNativePointer);
421f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            } else {
422f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                if (!enableSessionCreation) {
423f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    // Should have been prevented by NativeCrypto.SSL_set_session_creation_enabled
424f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    throw new IllegalStateException("SSL Session may not be created");
425f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                }
426f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                X509Certificate[] localCertificates
427f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        = createCertChain(NativeCrypto.SSL_get_certificate(sslNativePointer));
428f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                X509Certificate[] peerCertificates
429f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        = createCertChain(NativeCrypto.SSL_get_peer_cert_chain(sslNativePointer));
43027c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson                sslSession = new OpenSSLSessionImpl(sslSessionNativePointer, localCertificates,
43127c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson                        peerCertificates, getPeerHostName(), getPeerPort(), sessionContext);
432f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // if not, putSession later in handshakeCompleted() callback
433f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                if (handshakeCompleted) {
434f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    sessionContext.putSession(sslSession);
435f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                }
436ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom            }
437f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom
438f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // Restore the original timeout now that the handshake is complete
439f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
440f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                setSoTimeout(savedTimeoutMilliseconds);
4419d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor            }
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
443f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback
444f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (handshakeCompleted) {
445f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                notifyHandshakeCompletedListeners();
446f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
447ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
448f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            exception = false;
449aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        } catch (SSLProtocolException e) {
450aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom            throw new SSLHandshakeException(e);
451f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        } finally {
4528a720cceee7ce319d647738dfeda3f302879f370Brian Carlstrom            // on exceptional exit, treat the socket as closed
453f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (exception) {
4548a720cceee7ce319d647738dfeda3f302879f370Brian Carlstrom                close();
455f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
457df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom    }
458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
45927c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson    private String getPeerHostName() {
460f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        if (wrappedHost != null) {
461f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom            return wrappedHost;
462f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        }
463f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        InetAddress inetAddress = super.getInetAddress();
464f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        if (inetAddress != null) {
465f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom            return inetAddress.getHostName();
466f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        }
467f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        return null;
46827c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson    }
46927c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson
47027c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson    private int getPeerPort() {
47127c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        return wrappedHost == null ? super.getPort() : wrappedPort;
47227c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson    }
47327c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson
474df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom    /**
475df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom     * Return a possibly null array of X509Certificates given the
476df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom     * possibly null array of DER encoded bytes.
477df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom     */
478df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom    private static X509Certificate[] createCertChain(byte[][] certificatesBytes) {
479df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        if (certificatesBytes == null) {
480df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            return null;
481df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        }
482df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        X509Certificate[] certificates = new X509Certificate[certificatesBytes.length];
483df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        for (int i = 0; i < certificatesBytes.length; i++) {
484df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            try {
485df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom                certificates[i] = new X509CertImpl(certificatesBytes[i]);
486df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            } catch (IOException e) {
487df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom                return null;
488df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            }
489df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        }
490df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        return certificates;
491bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    }
492adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
493ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom    private void setCertificate(String alias) throws CertificateEncodingException, SSLException {
4946df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        if (alias == null) {
4956df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            return;
4966df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        }
4976df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        PrivateKey privateKey = sslParameters.getKeyManager().getPrivateKey(alias);
498aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        if (privateKey == null) {
499aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom            return;
500aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        }
5016df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        X509Certificate[] certificates = sslParameters.getKeyManager().getCertificateChain(alias);
502aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        if (certificates == null) {
503aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom            return;
504aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        }
505aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom
506aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        byte[] privateKeyBytes = privateKey.getEncoded();
507ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom        byte[][] certificateBytes = NativeCrypto.encodeCertificates(certificates);
508aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        NativeCrypto.SSL_use_PrivateKey(sslNativePointer, privateKeyBytes);
5096df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        NativeCrypto.SSL_use_certificate(sslNativePointer, certificateBytes);
5106df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
5116df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        // checks the last installed private key and certificate,
5126df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        // so need to do this once per loop iteration
5136df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        NativeCrypto.SSL_check_private_key(sslNativePointer);
5146df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom    }
5156df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
5160c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / client_cert_cb
517059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom    public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)
518ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            throws CertificateEncodingException, SSLException {
519059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom
520059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        String[] keyTypes = new String[keyTypeBytes.length];
521059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        for (int i = 0; i < keyTypeBytes.length; i++) {
5224ae3fd787741bfe1b808f447dcb0785250024119Brian Carlstrom            keyTypes[i] = CipherSuite.getClientKeyType(keyTypeBytes[i]);
523059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        }
524059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom
525059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        X500Principal[] issuers;
526059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        if (asn1DerEncodedPrincipals == null) {
527059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom            issuers = null;
528059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        } else {
529059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom            issuers = new X500Principal[asn1DerEncodedPrincipals.length];
530059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom            for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
531059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom                issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
532059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom            }
533059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        }
534059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        setCertificate(sslParameters.getKeyManager().chooseClientAlias(keyTypes, issuers, this));
5356df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom    }
5366df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
5370c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / info_callback
538bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public void handshakeCompleted() {
539bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        handshakeCompleted = true;
540adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
541bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // If sslSession is null, the handshake was completed during
542bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // the call to NativeCrypto.SSL_do_handshake and not during a
5430c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson        // later read operation. That means we do not need to fix up
544bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // the SSLSession and session cache or notify
545bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // HandshakeCompletedListeners, it will be done in
546bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // startHandshake.
547bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        if (sslSession == null) {
548bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            return;
549bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        }
550adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
551bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // reset session id from the native pointer and update the
552bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // appropriate cache.
553bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        sslSession.resetId();
554bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        AbstractSessionContext sessionContext =
555bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            (sslParameters.getUseClientMode())
556bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            ? sslParameters.getClientSessionContext()
557bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                : sslParameters.getServerSessionContext();
558adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sessionContext.putSession(sslSession);
559bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
560bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // let listeners know we are finally done
561bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        notifyHandshakeCompletedListeners();
562bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    }
563bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
564bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    private void notifyHandshakeCompletedListeners() {
565bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        if (listeners != null && !listeners.isEmpty()) {
566bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            // notify the listeners
567bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            HandshakeCompletedEvent event =
568bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                new HandshakeCompletedEvent(this, sslSession);
569bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            for (HandshakeCompletedListener listener : listeners) {
570bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                try {
571bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                    listener.handshakeCompleted(event);
572bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                } catch (RuntimeException e) {
573e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    // The RI runs the handlers in a separate thread,
574e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    // which we do not. But we try to preserve their
575e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    // behavior of logging a problem and not killing
576e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    // the handshaking thread just because a listener
577e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    // has a problem.
578e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    Thread thread = Thread.currentThread();
579e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    thread.getUncaughtExceptionHandler().uncaughtException(thread, e);
580bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                }
581bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            }
582bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        }
583adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
584adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
5850c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks
5860c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void verifyCertificateChain(byte[][] bytes, String authMethod)
5876df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            throws CertificateException {
588adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
589e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            if (bytes == null || bytes.length == 0) {
590e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                throw new SSLException("Peer sent no certificate");
591e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            }
592bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            X509Certificate[] peerCertificateChain = new X509Certificate[bytes.length];
593bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            for (int i = 0; i < bytes.length; i++) {
594a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                peerCertificateChain[i] = new X509CertImpl(bytes[i]);
595adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
596bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            boolean client = sslParameters.getUseClientMode();
597bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            if (client) {
5986df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom                sslParameters.getTrustManager().checkServerTrusted(peerCertificateChain,
5996df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom                                                                   authMethod);
600bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            } else {
6014ae3fd787741bfe1b808f447dcb0785250024119Brian Carlstrom                String authType = peerCertificateChain[0].getPublicKey().getAlgorithm();
6026df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom                sslParameters.getTrustManager().checkClientTrusted(peerCertificateChain,
6034ae3fd787741bfe1b808f447dcb0785250024119Brian Carlstrom                                                                   authType);
604adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
605bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
606bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        } catch (CertificateException e) {
607bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            throw e;
6081b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom        } catch (RuntimeException e) {
6091b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom            throw e;
610bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        } catch (Exception e) {
611bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            throw new RuntimeException(e);
612adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
613adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
614adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
6150c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public InputStream getInputStream() throws IOException {
6165f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom        checkOpen();
617ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom        synchronized (this) {
618adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (is == null) {
619adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                is = new SSLInputStream();
620adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
621adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
622adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return is;
623adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
624adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
625adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
6260c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public OutputStream getOutputStream() throws IOException {
6275f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom        checkOpen();
628ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom        synchronized (this) {
629adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (os == null) {
630adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                os = new SSLOutputStream();
631adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
632adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
633adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return os;
634adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
635adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
636adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
637bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    /**
638adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This inner class provides input data stream functionality
639adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * for the OpenSSL native implementation. It is used to
640adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * read data received via SSL protocol.
641adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
642adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private class SSLInputStream extends InputStream {
643adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        SSLInputStream() throws IOException {
644adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            /**
645adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            /* Note: When startHandshake() throws an exception, no
646adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * SSLInputStream object will be created.
647adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             */
648bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            OpenSSLSocketImpl.this.startHandshake(false);
649adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
650adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
651adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
652adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Reads one byte. If there is no data in the underlying buffer,
653adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * this operation can block until the data will be
654adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * available.
655adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @return read value.
656adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @throws <code>IOException</code>
657adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
6584559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        @Override
659adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int read() throws IOException {
660638000042da777f6d628d88dadde957c52597710Brian Carlstrom            return Streams.readSingleByte(this);
661adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
662adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
663adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
664adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Method acts as described in spec for superclass.
665adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @see java.io.InputStream#read(byte[],int,int)
666adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
6674559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        @Override
668a1603838fe9e865575c87982e32c6343740e464cElliott Hughes        public int read(byte[] buf, int offset, int byteCount) throws IOException {
6695900e5546059f05d5e58e5732e4d08d83b8b7574Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
670ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            synchronized (readLock) {
67112e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                checkOpen();
672a1603838fe9e865575c87982e32c6343740e464cElliott Hughes                Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
673a1603838fe9e865575c87982e32c6343740e464cElliott Hughes                if (byteCount == 0) {
67412e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                    return 0;
67512e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                }
6765d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                return NativeCrypto.SSL_read(sslNativePointer, socket.getFileDescriptor$(),
6775d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                        OpenSSLSocketImpl.this, buf, offset, byteCount, getSoTimeout());
678adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
679adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
680adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
681adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
682adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
683adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This inner class provides output data stream functionality
684adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * for the OpenSSL native implementation. It is used to
685adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * write data according to the encryption parameters given in SSL context.
686adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
687adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private class SSLOutputStream extends OutputStream {
688adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        SSLOutputStream() throws IOException {
689adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            /**
690adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            /* Note: When startHandshake() throws an exception, no
691ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom             * SSLOutputStream object will be created.
692adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             */
693bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            OpenSSLSocketImpl.this.startHandshake(false);
694adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
695adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
696adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
697adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Method acts as described in spec for superclass.
698adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @see java.io.OutputStream#write(int)
699adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
7004559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        @Override
701638000042da777f6d628d88dadde957c52597710Brian Carlstrom        public void write(int oneByte) throws IOException {
702638000042da777f6d628d88dadde957c52597710Brian Carlstrom            Streams.writeSingleByte(this, oneByte);
703adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
704adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
705adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
706adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Method acts as described in spec for superclass.
707adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @see java.io.OutputStream#write(byte[],int,int)
708adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
7094559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        @Override
710a1603838fe9e865575c87982e32c6343740e464cElliott Hughes        public void write(byte[] buf, int offset, int byteCount) throws IOException {
7115900e5546059f05d5e58e5732e4d08d83b8b7574Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
712ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            synchronized (writeLock) {
71312e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                checkOpen();
714a1603838fe9e865575c87982e32c6343740e464cElliott Hughes                Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
715a1603838fe9e865575c87982e32c6343740e464cElliott Hughes                if (byteCount == 0) {
71612e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                    return;
71712e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                }
7185d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                NativeCrypto.SSL_write(sslNativePointer, socket.getFileDescriptor$(),
7195d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                        OpenSSLSocketImpl.this, buf, offset, byteCount);
720adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
721adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
722adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
723adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
724adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7250c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public SSLSession getSession() {
726df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        if (sslSession == null) {
727df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            try {
728df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom                startHandshake(true);
729df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            } catch (IOException e) {
730df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom                // return an invalid session with
731df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom                // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
732df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom                return SSLSessionImpl.NULL_SESSION;
733df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            }
734adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
735adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sslSession;
736adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
737adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7380c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void addHandshakeCompletedListener(
739adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            HandshakeCompletedListener listener) {
740adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (listener == null) {
741adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
742adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
743adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (listeners == null) {
7440c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson            listeners = new ArrayList<HandshakeCompletedListener>();
745adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
746adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        listeners.add(listener);
747adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
748adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7490c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void removeHandshakeCompletedListener(
750adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            HandshakeCompletedListener listener) {
751adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (listener == null) {
752adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
753adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
754adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (listeners == null) {
755adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException(
756adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    "Provided listener is not registered");
757adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
758adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!listeners.remove(listener)) {
759adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException(
760adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    "Provided listener is not registered");
761adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
762adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
763adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7640c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public boolean getEnableSessionCreation() {
765adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sslParameters.getEnableSessionCreation();
766adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
767adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7680c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setEnableSessionCreation(boolean flag) {
769adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sslParameters.setEnableSessionCreation(flag);
770adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
771adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7720c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public String[] getSupportedCipherSuites() {
773ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        return NativeCrypto.getSupportedCipherSuites();
774adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
775adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7760c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public String[] getEnabledCipherSuites() {
777bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        return enabledCipherSuites.clone();
778adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
779adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7800c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setEnabledCipherSuites(String[] suites) {
781bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(suites);
782adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
783adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7840c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public String[] getSupportedProtocols() {
785ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        return NativeCrypto.getSupportedProtocols();
786adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
787adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7880c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public String[] getEnabledProtocols() {
789bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        return enabledProtocols.clone();
790adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
791adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7920c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setEnabledProtocols(String[] protocols) {
793bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        enabledProtocols = NativeCrypto.checkEnabledProtocols(protocols);
794adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
795adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
796adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
7974559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * The names of the compression methods that may be used on this SSL
7984559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * connection.
7994559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * @return an array of compression methods
8004559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     */
8014559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    public String[] getSupportedCompressionMethods() {
8024559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        return NativeCrypto.getSupportedCompressionMethods();
8034559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    }
8044559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom
8054559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    /**
8064559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * The names of the compression methods versions that are in use
8074559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * on this SSL connection.
8084559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     *
8094559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * @return an array of compression methods
8104559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     */
8114559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    public String[] getEnabledCompressionMethods() {
8124559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        return enabledCompressionMethods.clone();
8134559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    }
8144559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom
8154559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    /**
8160c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson     * Enables compression methods listed by getSupportedCompressionMethods().
8174559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     *
8184559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * @throws IllegalArgumentException when one or more of the names in the
8194559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     *             array are not supported, or when the array is null.
8204559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     */
8210c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    public void setEnabledCompressionMethods(String[] methods) {
8224559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        enabledCompressionMethods = NativeCrypto.checkEnabledCompressionMethods(methods);
8234559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    }
8244559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom
8254559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    /**
8264559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * This method enables session ticket support.
8274559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     *
8284559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * @param useSessionTickets True to enable session tickets
8294559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     */
8304559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    public void setUseSessionTickets(boolean useSessionTickets) {
8314559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        this.useSessionTickets = useSessionTickets;
8324559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    }
8334559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom
8344559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    /**
8354559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * This method enables Server Name Indication
8364559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     *
8374559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * @param hostname the desired SNI hostname, or null to disable
8384559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     */
8394559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    public void setHostname(String hostname) {
8404559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        this.hostname = hostname;
8414559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    }
8424559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom
8430c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public boolean getUseClientMode() {
844adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sslParameters.getUseClientMode();
845adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
846adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8470c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setUseClientMode(boolean mode) {
848adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (handshakeStarted) {
849adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException(
8500c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson                    "Could not change the mode after the initial handshake has begun.");
851adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
852adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sslParameters.setUseClientMode(mode);
853adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
854adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8550c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public boolean getWantClientAuth() {
856adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sslParameters.getWantClientAuth();
857adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
858adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8590c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public boolean getNeedClientAuth() {
860adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sslParameters.getNeedClientAuth();
861adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
862adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8630c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setNeedClientAuth(boolean need) {
864adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sslParameters.setNeedClientAuth(need);
865adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
866adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8670c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setWantClientAuth(boolean want) {
868adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sslParameters.setWantClientAuth(want);
869adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
870adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8710c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void sendUrgentData(int data) throws IOException {
8720c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson        throw new SocketException("Method sendUrgentData() is not supported.");
873adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
874adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8750c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setOOBInline(boolean on) throws SocketException {
8760c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson        throw new SocketException("Methods sendUrgentData, setOOBInline are not supported.");
877adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
878adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8790c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setSoTimeout(int timeoutMilliseconds) throws SocketException {
880a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom        super.setSoTimeout(timeoutMilliseconds);
881a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom        this.timeoutMilliseconds = timeoutMilliseconds;
882a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom    }
883a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom
8840c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public int getSoTimeout() throws SocketException {
885a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom        return timeoutMilliseconds;
886adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
887adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8889d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor    /**
8899d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor     * Set the handshake timeout on this socket.  This timeout is specified in
8909d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor     * milliseconds and will be used only during the handshake process.
8919d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor     */
892a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom    public void setHandshakeTimeout(int timeoutMilliseconds) throws SocketException {
893a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom        this.handshakeTimeoutMilliseconds = timeoutMilliseconds;
8949d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor    }
8959d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor
8960c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void close() throws IOException {
8970c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson        // TODO: Close SSL sockets using a background thread so they close gracefully.
898adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
899adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (handshakeLock) {
900adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!handshakeStarted) {
9010c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson                // prevent further attempts to start handshake
902adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                handshakeStarted = true;
903ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
904adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                synchronized (this) {
905ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom                    free();
906adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
907df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom                    if (socket != this) {
908adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (autoClose && !socket.isClosed()) socket.close();
909adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    } else {
910adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (!super.isClosed()) super.close();
911adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
912adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
913ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
914adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return;
915adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
916adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
917adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
9183e24c53ecc31b840e51869c295785d5a2f8b31ebBrian Carlstrom        NativeCrypto.SSL_interrupt(sslNativePointer);
919adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
920adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (this) {
921adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            synchronized (writeLock) {
922adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                synchronized (readLock) {
923adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
924adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // Shut down the SSL connection, per se.
925adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    try {
926adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (handshakeStarted) {
9275900e5546059f05d5e58e5732e4d08d83b8b7574Brad Fitzpatrick                            BlockGuard.getThreadPolicy().onNetwork();
9285d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                            NativeCrypto.SSL_shutdown(sslNativePointer, socket.getFileDescriptor$(),
9295d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                                    this);
930adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
9311c64b3adb85345659ac60ad82216268acba18764Brian Carlstrom                    } catch (IOException ignored) {
932adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        /*
9331c64b3adb85345659ac60ad82216268acba18764Brian Carlstrom                         * Note that although close() can throw
9341c64b3adb85345659ac60ad82216268acba18764Brian Carlstrom                         * IOException, the RI does not throw if there
9351c64b3adb85345659ac60ad82216268acba18764Brian Carlstrom                         * is problem sending a "close notify" which
9361c64b3adb85345659ac60ad82216268acba18764Brian Carlstrom                         * can happen if the underlying socket is closed.
937adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                         */
938d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                    } finally {
939d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                        /*
940d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                         * Even if the above call failed, it is still safe to free
941d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                         * the native structs, and we need to do so lest we leak
942d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                         * memory.
943d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                         */
944d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                        free();
945d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom
946d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                        if (socket != this) {
947d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                            if (autoClose && !socket.isClosed()) {
948d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                                socket.close();
949d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                            }
950d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                        } else {
951d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                            if (!super.isClosed()) {
952d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                                super.close();
953d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                            }
954d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                        }
955adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
956adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
957adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
958adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
959adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
960adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
961ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    private void free() {
962ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        if (sslNativePointer == 0) {
963ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom            return;
964ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        }
965ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        NativeCrypto.SSL_free(sslNativePointer);
966ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        sslNativePointer = 0;
967f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        guard.close();
968ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    }
969adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
970e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom    @Override protected void finalize() throws Throwable {
971e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        try {
972e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            /*
973e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * Just worry about our own state. Notably we do not try and
974e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * close anything. The SocketImpl, either our own
975e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * PlainSocketImpl, or the Socket we are wrapping, will do
976e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * that. This might mean we do not properly SSL_shutdown, but
977e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * if you want to do that, properly close the socket yourself.
978e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             *
979e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * The reason why we don't try to SSL_shutdown, is that there
980e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * can be a race between finalizers where the PlainSocketImpl
981e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * finalizer runs first and closes the socket. However, in the
982e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * meanwhile, the underlying file descriptor could be reused
983e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * for another purpose. If we call SSL_shutdown, the
984e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * underlying socket BIOs still have the old file descriptor
985e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * and will write the close notify to some unsuspecting
986e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * reader.
987e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             */
98812f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom            if (guard != null) {
98912f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom                guard.warnIfOpen();
99012f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom            }
991e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            free();
992e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        } finally {
993e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            super.finalize();
994e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        }
995adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
9963267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey
9973267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey    @Override
9983267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey    public FileDescriptor getFileDescriptor$() {
9993267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey        if (socket == this) {
10003267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey            return super.getFileDescriptor$();
10013267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey        } else {
10023267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey            return socket.getFileDescriptor$();
10033267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey        }
10043267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey    }
1005adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
1006